图像仿射变换函数
图像仿射变换getRotationMatrix2D()
OpenCV4提供了getRotationMatrix2D()函数用于计算旋转矩阵,提供warpAffine()函数用于实现图像的仿射变换
getRotationMatrix2D()函数原型:
Mat getRotationMatrix2D(Point2f center,
double angle,
double scale
)
- center:图像旋转的中心位置
- angle:图像旋转的角度,单位为都,正值逆时针旋转
- scale,两个轴的比例因子,可以实现旋转过程中的图像缩放,不缩放则输入1
该函数输入旋转角度和旋转中心,返回图像旋转矩阵,返回值的数据类型为Mat类,是一个2x3的矩阵,例如:

确定旋转矩阵后,通过warpAffine()函数进行仿射变换,就可以实现图像的旋转
warpAffine()函数原型:
void 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:2x3的变换矩阵
- dsize:输出图像的尺寸
- flags:插值方法标志
- borderMode:像素边界外推方法的标志
- borderValue:填充边界使用的数值,默认情况下为0
该函数第三个参数为前面求取的旋转矩阵,第四个参数是输出图像的尺寸,第五个参数是仿射变换插值方法的标志
第六个参数为像素边界外推方法标志,第七个参数把BORDER_CONSTANT作为定值,默认情况下为0
图像仿射变换插值方法标志
| 方法标志 | 简记 | 作用 |
|---|---|---|
| WARP_FILL_OUTLIERS | 8 | 填充所有输出图像的像素,如果部分像素落在输入图像的边界外,则它们的值设定为fillval |
| WARP_INVERSE_MAP | 16 | 设置为M输出图像到输入图像的反变换 |
边界外推方法标志
| 方法标志 | 简记 | 作用 | ||
|---|---|---|---|---|
| BORDER_CONSTANT | 0 | 用特定值填充,如iiiiii\ | abcdefgh\ | iiiiii |
| BORDER_REPLICATE | 1 | 两端复制填充,如aaaaaa\ | abcdefgh\ | bbbbbb |
| BORDER_REFLECT | 2 | 倒序填充,如fedcba\ | abcdefgh\ | hgfedcb |
| BORDER_WRAP | 3 | 正序填充,如cdefgh\ | abcdefgh\ | abcdefg |
| BORDER_REFLECT_101 | 4 | 不含边界值的倒序填充,如gfedcb\ | abcdefgh\ | gfedcba |
| BORDER_TRANSPARENT | 5 | 随机填充,uvwxyz\ | abcdefgh\ | ijklmno |
| BORDER_REFLECT101 | 4 | 与 BORDER_REFLECT_101 相同 | ||
| BORDER_DEFAULT | 4 | 与 BORDER_REFLECT_101 相同 | ||
| BORDER_ISOLATED | 16 | 不关心感兴趣区域之外的部分 |
仿射变换又称三点变换,如果知道前后两幅图像中3个像素点的对应关系,就可以求得仿射变换中的变换矩阵M
OpenCV4提供了getAffineTransform()函数来确定变换矩阵
Mat getAffineTransform(const Point2f src[],
const Point2f dst[]
)
- src[]:源图像中的3个像素坐标
- dst[]:目标图像中的3个像素坐标
示例:
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("E:\\CLion\\opencv_xin\\SG\\SG_1.jpg");
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,0,0,Scalar(255,255,255)); //进行仿射变换(白色)
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));
src_points[2] = Point2f((float)(img.rows - 1), (float)(img.cols - 1));
//放射变换后图像中的三个点
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;
}
图像透视变换getPerspectiveTransform()
透视变换是按照物体成像投影的规律进行变换,将物体重新投影到新的成像平面

透视变换常用于机器人视觉巡航研究中,由于相机视场于地面存在倾斜角使得物体成像产生畸变,通常通过透视变换实现图像的矫正
在透视变换中,透视前后的图像之间的变换关系可以用一个3x3的矩阵表示,该矩阵可以通过两幅图像4个对应点的坐标求取
透视变换又称“四点变换”,OpenCV4提供了getPerspectiveTransform()函数和进行透视变换的warpPerspective()函数
getPerspectiveTransform()函数原型:
Mat getPerspectiveTransform(const Point2f src[],
const Point2f dst[],
int solveMethod = DECOMP_LU
)
- src[]:原图像的4个像素坐标
- dst[]:目标图像的4给像素坐标
- solveMethod:选择计算透视变换矩阵方法的标志
getPerspectiveTransform()函数计算方法标志
| 标志参数 | 简记 | 作用 |
|---|---|---|
| DECOMP_LU | 0 | 最佳主轴元素的高斯消元法 |
| DECOMP_SVD | 1 | 奇异值分解(SVD)方法 |
| DECOMP_EIG | 2 | 特征值分解法 |
| DECOMP_CHOLESKY | 3 | Cholesky分解法 |
| DECOMP_QR | 4 | QR分解法 |
| DECOMP_NORMAL | 16 | 使用正规方程公式,可以与其他标志一起使用 |
warpPerspective()函数原型:
void 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:3x3的变换矩阵
- dsize:输出图像的尺寸
- flags:插值方法标志
- borderMode:像素边界外推方法的标志
- borderValue:填充边界使用的数值,默认情况下为0
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("E:\\CLion\\opencv_xin\\SG\\ewm_0.png");
if (img.empty()) {
cout << "Error" << endl;
return -1;
}
Point2f src_points[4];
Point2f dst_points[4];
//通过Opencv Image viewer查看二维码的4个角
//137 187 | 478 44 | 127 375 | 515 510
//0 0 | 643 0 | 0 586 | 643 586
src_points[0] = Point2f(137.0,187.0);
src_points[1] = Point2f(478.0,44.0);
src_points[2] = Point2f(127.0,375.0);
src_points[3] = Point2f(515.0,510.0);
//期望透视后二维码4给角点的坐标
dst_points[0] = Point2f(0.0,0.0);
dst_points[1] = Point2f(643.0,0.0);
dst_points[2] = Point2f(0.0,586.0);
dst_points[3] = Point2f(643.0,586.0);
Mat rotation,img_warp;
rotation = getPerspectiveTransform(src_points,dst_points); //计算透视变换矩阵
warpPerspective(img,img_warp,rotation,img.size()); //透视变换投影
imshow("img",img);
imshow("img_warp",img_warp);
waitKey(0);
return 0;
}
极坐标变换

极点和极轴,极点就相当于平面直角坐标系中的原点,极轴就是一根由极点引出的射线(射线,只有一边)
类似于平面直角坐标系中的x轴
平面直角坐标系中的点用(x,y)表示,而极坐标系中的点通常用(ρ,θ)表示
A在B的北偏东45度50米处, C在B的西偏南75度150米处
这种其实就是极坐标的思想,在航海过程中,由于横纵坐标通常难以确定,所以通常以极坐标的方式判断其他东西的位置
极坐标与直角坐标的变换在数学上是可逆的,但实际变换时存在误差,角度计算精度约为 0.3度
直角坐标系以变换中心为圆心的同一个圆上的点,在极坐标系中显示为一条直线。因此,用极坐标变换可以实现圆形物体的图像修正

极坐标变换warpPolar()
极坐标变换就是将图像在直角坐标系与极坐标系中相互变换,可以将一个圆形矩阵变换成一个矩阵图像
常用于处理钟表,圆盘等图像,圆形边缘上的文字经过极坐标变换后可以垂直地排列在新图像的边缘,便于对文字进行识别和检测
OpenCV4提供了warpPolar()函数用于图像的极坐标变换
warpPolar()函数原型:
void warpPolar(InputArray src,
OutputArray dst,
Size dsize,
Point2f center,
double maxRadius,
int flags
)
- src:源图像,可以是灰度图像或彩色图像
- dst:极坐标变换后输出图像,与源图像jiyou相同的数据类型和通道数
- dsize:目标图像大小
- center:极坐标变换时极坐标的原点坐标
- maxRadius:变换时边界圆的半径,它也决定了逆变换时的比例参数
- flags:插值方法与极坐标映射方法标志,两个方法之间通过“+”或者“|”号连接
该函数实现了图像极坐标变换和半对数极坐标变换,第一个参数是需要进行极坐标变换的图像(灰度图像和彩色图像均可)
第二个参数是变换后的输出图像,与输入图像具有相同的数据类型和通道数,第三个参数是变换后图像大小
第四个参数是极坐标变换时极坐标原点在原始图像中的位置,该参数同样适用于逆变换中,第五个参数是变换时边界圆的半径
决定了逆变换时的比例参数,最后一个参数是变换方法的选择参数
warpPolar()函数极坐标映射方法标志
| 标志参数 | 作用 |
|---|---|
| WARP_POLAR_LINEAR | 极坐标变换 |
| WARP_POLAR_LOG | 半对数极坐标变换 |
| WARP_INVERSE_MAP | 逆变换 |
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("E:\\CLion\\opencv_xin\\SG\\yuanxin_0.png");
if (img.empty()) {
cout << "Error" << endl;
return -1;
}
Mat img1,img2;
Point2f center = Point2f(img.cols/2,img.rows/2); //极坐标在图像种的原点
//正极坐标变换
warpPolar(img,img1,Size(300,600),center,center.x,INTER_LINEAR + WARP_POLAR_LINEAR);
//逆极坐标变换
warpPolar(img1,img2,Size(img.cols,img.rows),center,center.x,INTER_LINEAR + WARP_INVERSE_MAP);
imshow("img",img);
imshow("img1",img1);
imshow("img2",img2);
waitKey(0);
return 0;
}