文章目录
一、仿射变换
仿射变换可以理解为矩阵乘法(线性变换)和向量加法(平移)的变换。本质上,一个仿射变换代表了两个图像之间的关系,可以分别表示为:
1.旋转(线性变换)
2.平移(向量加法)
3.缩放操作(线性变换)
仿射变换通常使用2×3矩阵表示:
将M乘于一个二维向量[x, y],例如图像像素坐标,最终可表示为:
二、求解仿射变换
仿射变换基本上是两个图像之间的关系。这种关系的信息可以通过两种方式获得:
1.已知X和T,那我们的任务就是求M
2.已知M和X,应用T=M⋅X,得到T。
如下图:点1、2和3(在图1中形成一个三角形)被映射到图2中,仍然形成一个三角形,但现在它们已经发生了变化。如果我们找到了这3个点的仿射变换,那么我们就可以将找到的关系应用到图像中的所有像素上。
三、opencv 函数支持
1.getAffineTransform()函数
计算仿射变化矩阵
CV_EXPORTS_W Mat getAffineTransform( InputArray src, InputArray dst );
2.getRotationMatrix2D()函数
计算二维旋转的仿射矩阵
CV_EXPORTS_W Mat getRotationMatrix2D(Point2f center, double angle, double scale);
3.warpAffine()函数
将仿射变换应用于图像。
CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst,
InputArray M, Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
四、测试代码
cv::Mat src;
src = cv::imread("D:\\QtProject\\Opencv_Example\\Affine\\Affine.png", cv::IMREAD_COLOR);
if (src.empty()) {
cout << "matTemplate Cannot load image" << endl;
return;
}
cv::imshow("src", src);
Point2f srcTri[3];
srcTri[0] = Point2f( 0.f, 0.f );
srcTri[1] = Point2f( src.cols - 1.f, 0.f );
srcTri[2] = Point2f( 0.f, src.rows - 1.f );
Point2f dstTri[3];
dstTri[0] = Point2f( 0.f, src.rows*0.33f );
dstTri[1] = Point2f( src.cols*0.85f, src.rows*0.25f );
dstTri[2] = Point2f( src.cols*0.15f, src.rows*0.7f );
Mat warp_mat = getAffineTransform( srcTri, dstTri );
Mat warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
cv::imshow("warp_dst", warp_dst);
Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
double angle = -50.0;
double scale = 0.6;
Mat rot_mat = getRotationMatrix2D( center, angle, scale );
Mat warp_rotate_dst;
warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
cv::imshow("warp_rotate_dst", warp_rotate_dst);
程序运行效果: