上一节我们学习了如何对一幅图像进行放大与缩小(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 <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
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;
}
实验结果
原图仿射变换、仿射旋转变换、图像旋转90度
(二)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算法
image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png实验结果
好了,今天的学习到这里就结束了,希望大家可以认真学习学习每一节知识,加油,相信大家可以的!喜欢的朋友也可以给我点个赞哦!!
网友评论