OpenCV4入门系列教程44:透视变换

入门系列索引:系列教程索引地址

上一篇:OpenCV4入门系列教程43:距离变换

透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。如下图所示。

1

通用变换公式为:

[xyw][uvw][a11a12a13a21a22a23a31a32a33]\begin{aligned} \begin{bmatrix} x' & y' & w' \end{bmatrix} \begin{bmatrix} u & v & w \end{bmatrix} * \begin{bmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \end{bmatrix} \end{aligned}

(u,v)为原始图像像素坐标,(x=x’/w’,y=y’/w’)为变换之后的图像像素坐标。透视变换矩阵图解如下:

Transform=[a11a12a13a21a22a23a31a32a33]=[T1T2T3a33]T1=[a11a12a21a22](表示图像线性变换)T2=[a13a23]T(用于产生图像透视变换)T3=[a31a32](用于产生图像平移)Transform = \begin{bmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \end{bmatrix} = \begin{bmatrix} T_1 & T_2 \\ T_3 & a_{33} \end{bmatrix} \\ T_1=\begin{bmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{bmatrix} \text{(表示图像线性变换)}\\ T_2=\begin{bmatrix} a_{13} & a_{23} \end{bmatrix}^T \text{(用于产生图像透视变换)}\\ T_3=\begin{bmatrix} a_{31} & a_{32} \end{bmatrix} \text{(用于产生图像平移)}

仿射变换(Affine Transformation)可以理解为透视变换的特殊形式。透视变换的数学表达式为:

x=xw=a11u+a21v+a31a13u+a23v+a33y=yw=a12u+a22v+a32a13u+a23v+a33\begin{aligned} x=\frac{x'}{w'}=\frac{a_{11}u+a_{21}v+a_{31}}{a_{13}u+a_{23}v+a_{33}}\\ y=\frac{y'}{w'}=\frac{a_{12}u+a_{22}v+a_{32}}{a_{13}u+a_{23}v+a_{33}} \end{aligned}

所以,给定透视变换对应的四对像素点坐标,即可求得透视变换矩阵;反之,给定透视变换矩阵,即可对图像或像素点坐标完成透视变换,如下图所示:

3

函数说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Mat getPerspectiveTransform(const Point2f* src, const Point2f* dst)
// 从四对对应的点计算一个透视变换。
// src – 源图像中的四边形顶点的坐标。
// dst – 目标图像中相应的四边形顶点的坐标。

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大小、类型相同的目标图像。
// M – 3*3 变换矩阵
// dsize – 目标图像的尺寸
// flags – 插值方法和可选的标志WARP_INVERSE_MAP的组合,这意味着M是逆变换(dst src)。
// borderMode – 像素填充方法。当borderMode=BORDER_TRANSPARENT时,这意味着目标图像中对应于源图像中的“异常值”的像素不会被该函数修改。
// borderValue – 需要常量边框时使用的值,默认为0

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "opencv2/opencv.hpp"

using namespace cv;

int main( int argc, char** argv )
{
// Read the source file
Mat src;
src = imread(argv[1]);

Mat dst;
Point2f src_verts[4];
src_verts[2] = Point(195, 140);
src_verts[3] = Point(410, 120);
src_verts[1] = Point(220, 750);
src_verts[0] = Point(400, 750);
Point2f dst_verts[4];
dst_verts[2] = Point(160, 100);
dst_verts[3] = Point(530, 120);
dst_verts[1] = Point(220, 750);
dst_verts[0] = Point(400, 750);

// Obtain and Apply the perspective transformation
Mat M = getPerspectiveTransform(src_verts,dst_verts);
warpPerspective(src,dst,M,src.size());

// Show the results
namedWindow( " ORIGINAL ", WINDOW_AUTOSIZE );
imshow( " ORIGINAL ", src );
namedWindow( " PERSPECTIVE ", WINDOW_AUTOSIZE );
imshow( " PERSPECTIVE ", dst );

waitKey();
return 0;
}

测试结果:

perspective

下一篇:OpenCV4入门系列教程测试5:旋转文本图像矫正