OpenCvt图像仿射变换、透视变换,详细解读

1、图像仿射变换

仿射变换就是图像的旋转、平移和缩放操作的统称,可以表示为线性变换和平移变换的叠加。

OpenCv4 中没有专门的图像旋转函数,而是通过图像的仿射 变换实现图像的旋转。首先需要确定旋转角度和旋转中心,之后确定旋转矩阵,最终通过仿射变换实现图像旋转。由getRotationMatrix2D() 函数用于计算旋转矩阵,提供了warpAffine() 函数用于实现图像的仿射变换。

getRotationMatrix2D()函数原型

Mat cv::getRotationMatrix2D( Point2f center, double angle, double scale )

其中,center : 图像旋转的中心位置

angle : 图像旋转的角度,单位为度,正值为逆时针旋转

scale :两个轴的比例因子,可以实现旋转过程中的图像缩放,不缩放则为1

该函数返回图像旋转矩阵,返回值的数据类型时Mat 类,是一个2×3 的矩阵(具体不展开了)。

在确定了旋转矩阵后,通过warpAffine() 函数进行仿射变换,就可以实现图像的旋转。

warpAffine() 函数原型

void cv::warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, 
                     int flags = INTER_LINEAR,  int borderMode = BORDER_CONSTANT , 
                     const Scalar& borderValue = Scalar())

其中,src:输入图像

dst:仿射变换后输出图像,与src 数据类型相同,尺寸与·dsize 相同

M:2×3 的变换矩阵

dsize:输出图像的尺寸。

flags:插值方法标志,可选参数及含义见下表

borderMode: 像素边界外推方法的标志

borderValue: 填充边界使用的数值,默认情况下为0。

该函数第三个参数为前面求取的图像旋转矩阵。

图像仿射变换插值方法标志 作用
INTER_NEARES 最近邻插值
INTER_LINEAR 双线性插值法
INTER_CUBIC 双三次插值
INTER_AREA

使用像素区域关系重新采样,首选用图像缩小,

图像放大时效果与INTER_NEAREST 相似

INTER_LANCZOS4 Lanczos插值法
INTER_LINEAR_EXACT 位精确双线性插值法
INTER_MAX 用掩码进行插值
WARP_FILL_OUTLIERS 填充所有输出图像的像素,如果部分像素落在输入图像的边界外,则它们的值设定为 fillval
WARP_INVERSE_MAP 设置为M输出图像到输入图像的反变换

像素边界外推方法的标志 作用
BORDER_CONSTANT 用特定值填充,入如iiiiiii|abcdefg|iiiiiiii
BORDER_REPLICATE 两端复制填充,如aaaaaa|abcdefgh|hhhhhh
BORDER_REFLECT 倒序填充,如fedcba|abcdefgh|hgfedcb
BORDER_WRAP 正序填充,如cdefgh|abcdefgh|abcdefg
BORDER_REFLECT_101

不包含边界值的倒序填充,如

gfedcb|abcdefgh|gfedcba

BORDER_TRANSPARENT 随机填充,uvwxyz|abcdefgh|ijklmno
BORDER_REFLECT101 与BORDER_REFLECT_101 相同
BORDER_DEFAULT 与BORDER_REFLECT_101 相同
BORDER_ISOLATED 不关心感兴趣区域之外的部分

仿射变换的数学表示是先乘以一个线性变换矩阵再加上平移向量,其中线性变换矩阵式2 × 2 的矩阵,平移向量为 2 × 1 的向量。设线性变换矩阵 A 和一个平移向量 B,两者与输入矩阵M的关系:

OpenCvt图像仿射变换、透视变换,详细解读_第1张图片 仿射变换又称为 三点变换,如果知道变换前后两幅图像中 3 个像素点坐标的对应关系,就可以求得仿射变换中的变换矩阵 M 。OpenCv中提供了利用 3 个对应像素点来确定变换矩阵 M 的函数。

getAffineTransform() 函数原型

Mat cv::getAffineTransform( const Point2f src[], const Point2f dst[] )

src[] : 源图像中的3个图像坐标

dst[] : 目标图像中的3个图像坐标

该函数两个输入量都是存放浮点坐标的数组,函数的返回值式一个2×3 的变换矩阵。

示例:

#include 
#include 
#include 

using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("D:\\dijia.png");// 464*668
	if (img.empty())
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}

	Mat rotation0, rotation1, img_warp0, img_warp1;
	double angle = 30;  //设置图像旋转的角度
	Size dst_size(img.rows, img.cols);  //设置输出图像的尺寸
	Point2f center(img.rows / 2.0, img.cols / 2.0);  //设置图像的旋转中心
 	rotation0 = getRotationMatrix2D(center, angle, 1);  //计算仿射变换矩阵
	warpAffine(img, img_warp0, rotation0, dst_size);  //进行仿射变换
	namedWindow("img_warp0", WINDOW_NORMAL);	imshow("img_warp0", img_warp0);
	//根据定义的三个点进行仿射变换
	Point2f src_points[3];
	Point2f dst_points[3];
	src_points[0] = Point2f(0, 0);  //原始图像中的三个点
	src_points[1] = Point2f(0, (float)(img.cols - 1));//(0,667)
	src_points[2] = Point2f((float)(img.rows - 1), (float)(img.cols - 1));//(463,667)
	dst_points[0] = Point2f((float)(img.rows)*0.11, (float)(img.cols)*0.20);  //放射变换后图像中的三个点
	dst_points[1] = Point2f((float)(img.rows)*0.15, (float)(img.cols)*0.70);
	dst_points[2] = Point2f((float)(img.rows)*0.81, (float)(img.cols)*0.85);
	rotation1 = getAffineTransform(src_points, dst_points);  //根据对应点求取仿射变换矩阵
	warpAffine(img, img_warp1, rotation1, dst_size);  //进行仿射变换
	imshow("img_warp1", img_warp1);
 	waitKey(0);
	return 0;
}

 结果:

OpenCvt图像仿射变换、透视变换,详细解读_第2张图片

 2、图像透视变换

透视变换是按照物体成像投影规律进行变换,即将物体重新投影到新的成像平面。在透视变换中,透视前的图像和透视后的图像之间变换关系可以用一个 3×3 的变换矩阵表示,该矩阵可以通过两幅图像中 4 个对应点的坐标求取,因此透视变换又称为“四点变换”。OpenCv4 提供了根据四个对应点的坐标求取变换矩阵的 getPerspectiveTransform()  函数和进行透视变换的 warpPerspective()函数

getPerspectiveTransform()  函数原型

Mat cv::getPerspectiveTransform(const Point2f src[], const Point2f dst[], 
                                   int solveMethod = DECOMP_LU )

src[] :原图像中的4个像素坐标

dst[] : 目标图像中的4个像素坐标

solveMethod : 选择计算透视变换矩阵方法的标志(见下表)。

该函数两个输入量都是存放浮点坐标的数组,函数的返回值是一个 3× 3 的变换矩阵,算透视变换矩阵方法的标志默认情况下选择的是最佳主轴元素的高斯消元法 DECOMP_LU。

标志参数 作用
DECOMP_LU 最佳主轴元素的高斯消元法
DECOMP_SVD 奇异值分解(SVD)方法
DECOMP_EIG 特征值分解法
DECOMP_CHOLESKY Cholesky 分解法
DECOMP_QR QR分解法
DECOMP_NORMAL 使用正规方程公式,可以与其它的标志一起使用

 warpPerspective()函数原型


void cv::warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, 
               int flags  = INTER_LINEAR , int borderMode = BORDER_CONSTANT , 
               const Scalar& borderValue  = Scalar())

其中,src:输入图像

dst:透视变换后输出图像,与src 数据类型相同,尺寸与·dsize 相同

M:2×3 的变换矩阵

dsize:输出图像的尺寸。

flags:插值方法标志,可选参数及含义

borderMode: 像素边界外推方法的标志

borderValue: 填充边界使用的数值,默认情况下为0。

该函数所有参数与上述warpAffine() 函数定义相同。

示例:

#include 
#include 

using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("D:\\book1.png");
	if (img.empty())
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}

	Point2f src_points[4];
	Point2f dst_points[4];
	//通过Image Watch查看的二维码四个角点坐标
	src_points[0] = Point2f(97.0, 99.0);
	src_points[1] = Point2f(291.0, 17.0);
	src_points[2] = Point2f(293.0, 342.0);
	src_points[3] = Point2f(518.0, 226.0);
	//期望透视变换后二维码四个角点的坐标
	dst_points[0] = Point2f(0.0, 0.0);
	dst_points[1] = Point2f(300.0, 0.0);
	dst_points[2] = Point2f(0.0, 450.0);
	dst_points[3] = Point2f(300.0, 450.0);
	Mat rotation, img_warp;
	rotation = getPerspectiveTransform(src_points, dst_points);  //计算透视变换矩阵
	warpPerspective(img, img_warp, rotation, img.size());  //透视变换投影
	imshow("img", img);
	namedWindow("img_warp", WINDOW_AUTOSIZE);
	imshow("img_warp", img_warp);
	waitKey(0);
	return 0;
}

运行结果:

OpenCvt图像仿射变换、透视变换,详细解读_第3张图片

 

你可能感兴趣的:(计算机视觉,计算机视觉,opencv,图像处理,人工智能,c++)