上一节我们学习了如何对一幅图像进行放大与缩小(resize函数)以及对插值算的原理进行了分析,相信大家对图像如何进行放大与缩小已经有了清晰的理解,那么我们这节学习OpenCV中比较重要的内容,即仿射变换(warpAffine),仿射变换可以实现对稍微倾斜的图片进行矫正哦!!那么接下来我们就正式进入仿射变换的学习吧!
一、原理
仿射变换的功能是从二维坐标到二维坐标之间的线性变换,且保持二维图形的“平直性”和“平行性”。仿射变换可以通过一系列的原子变换的复合来实现,包括平移,缩放,翻转,旋转和剪切。
这类变换可以用一个3*3的矩阵M来表示,其最后一行为(0,0,1)。该变换矩阵将原坐标为(x,y)变换为新坐标(x',y')
典型的仿射变换
1、平移
将每一点移到到(x+t , y+t),变换矩阵为
2、缩放变换
将每一点的横坐标放大或缩小s_x倍,纵坐标放大(缩小)到s_y倍,变换矩阵为
3、旋转变换原点
目标图形围绕原点顺时针旋转Θ 弧度,变换矩阵为
4、旋转变换
目标图形以(x , y )为轴心顺时针旋转θ弧度,变换矩阵为
二、OpenCV中warpAffine()相关函数详解
(一)warpAffine()函数
1、函数原型
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar& borderValue = Scalar());
2、函数功能
对图像进行仿射变换,当函数的参数flags设置为 WARP_INVERSE_MAP时,函数使用下面的矩阵进行仿射变换:
否则,函数将首先使用逆仿射变换的转置,然后用上面的公式代替M,并且该函数不支持就地操作。
3、参数详解
- 第一个参数,InputArray src,原图像;
- 第二个参数,OutputArray dst,目标图像,并且该图像与原图像的尺寸和类型都是一样的;
- 第三个参数,InputArray M,2 x 3的变换矩阵;
- 第四个参数,Size dsize,目标图像的大小;
- 第五个参数,int flags = INTER_LINEAR,插值算法的标识符,默认为线性插值(INTER_LINEAR),如果插值算法为WARP_INVERSE_MAP,则函数使用下面的上面的公式[放射变换]进行图像转换;
- 第六个参数,int borderMode = BORDER_CONSTANT,边界像素的模式,默认值为BORDER_CONSTANT;
- 第七个参数,const Scalar& borderValue = Scalar(),边界取值,默认值为Scalar()。
4、实例
#include #include #include #include using namespace std;using namespace cv;//全局变量String src_windowName = "原图像";String warp_windowName = "仿射变换";String warp_rotate_windowName = "仿射旋转变换";String rotate_windowName = "图像旋转";int main(){ Point2f srcTri[3]; Point2f dstTri[3]; Mat rot_mat(2, 3, CV_32FC1); Mat warp_mat(2, 3, CV_32FC1); Mat srcImage, warp_dstImage, warp_rotate_dstImage, rotate_dstImage; //加载图像 srcImage = imread("lena.png"); //判断文件是否加载成功 if (srcImage.empty()) { cout << "图像加载失败!" << endl; return -1; } else cout << "图像加载成功!" << endl << endl; //创建仿射变换目标图像与原图像尺寸类型相同 warp_dstImage = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type()); //设置三个点来计算仿射变换 srcTri[0] = Point2f(0, 0); srcTri[1] = Point2f(srcImage.cols - 1, 0); srcTri[2] = Point2f(0, srcImage.rows - 1); dstTri[0] = Point2f(srcImage.cols*0.0, srcImage.rows*0.33); dstTri[1] = Point2f(srcImage.cols*0.85, srcImage.rows*0.25); dstTri[2] = Point2f(srcImage.cols*0.15, srcImage.rows*0.7); //计算仿射变换矩阵 warp_mat = getAffineTransform(srcTri, dstTri); //对加载图形进行仿射变换操作 warpAffine(srcImage, warp_dstImage, warp_mat, warp_dstImage.size()); //计算图像中点顺时针旋转90度,缩放因子为0.6的旋转矩阵 Point center = Point(warp_dstImage.cols / 2, warp_dstImage.rows / 2); double angle = -90.0; double scale = 0.6; //计算旋转矩阵 rot_mat = getRotationMatrix2D(center, angle, scale); //旋转已扭曲图像 warpAffine(warp_dstImage, warp_rotate_dstImage, rot_mat, warp_dstImage.size()); //将原图像旋转 warpAffine(srcImage, rotate_dstImage, rot_mat, srcImage.size()); //显示变换结果 namedWindow(src_windowName, WINDOW_AUTOSIZE); imshow(src_windowName, srcImage); namedWindow(warp_windowName, WINDOW_AUTOSIZE); imshow(warp_windowName, warp_dstImage); namedWindow(warp_rotate_windowName, WINDOW_AUTOSIZE); imshow(warp_rotate_windowName, warp_rotate_dstImage); namedWindow(rotate_windowName, WINDOW_AUTOSIZE); imshow(rotate_windowName, rotate_dstImage); waitKey(0); return 0;}
实验结果
(二)getAffineTransform()函数
1、函数原型
Mat getAffineTransform(const Point2f src[], const Point2f dst[]);
2、函数功能
从三对相对应的点计算图像的仿射变换。
3、参数详解
- 第一个参数,const Point2f src[],坐标系中,原图像中三角形的坐标;
- 第二个参数,const Point2f dst[],坐标系中,目标图像中相应的(相对于原图像)三角型的坐标;
- 返回值为Mat类型的图像。
(三)getRotationMatrix2D()函数
1、函数原型
Mat getRotationMatrix2D(Point2f center, double angle, double scale);
2、函数功能
计算二维图像旋转的放射变换。
3、参数详解
- 第一个参数,Point2f center,原图像的旋转中心坐标;
- 第二个参数,double angle,旋转的角度,假定坐标原点为左上角,角度为正值的话,按逆时针的方向进行旋转,角度为负值的话,按顺时针的角度进行旋转;
- 第三个参数,double scale,图像的缩放因子;
- 返回值为Mat类型的图像。
三、综合实例
使用findTransformECC()函数实现图像对齐ECC算法
实验结果
好了,今天的学习到这里就结束了,希望大家可以认真学习学习每一节知识,加油,相信大家可以的!喜欢的朋友也可以给我点个赞哦!!