一、话说透视变换
透视变换是将图像从一个视平面投影到另外一个视平面的过程,所以透视变换也被称为投影映射(Projection Mapping)。我们知道在图像的仿射变换中需要变换矩阵是一个2x3的两维平面变换矩阵,而透视变换本质上空间立体三维变换,根据其次坐标方差,要把三维坐标投影到另外一个视平面,就需要一个完全不同的变换矩阵M,所以这个是透视变换跟OpenCV中几何仿射变换最大的不同。
OpenCV中透视变换的又分为两种:
- 稀疏透视变换
- 密集透视变换
我们经常提到的对图像的透视变换都是指密集透视变换,而稀疏透视变换在OpenCV的特征点匹配之后的特征对象区域标识中经常用到。一般情况下密集透视变换warpPerspective函数常与函数getPerspectiveTransform一起使用实现对图像的透视校正。而稀疏透视变换perspectiveTransform经常与findhomography一起使用。
二、原理公式
u,v是原始图片左边,对应得到变换后的图片坐标x,y,其中。
变换矩阵可以分作四部分来理解,
表示线性变换,
表示平移,
产生透视,
所以可以理解成仿射等是透视变换的特殊形式。经过透视变换之后的图片通常不是平行四边形(除非映射视平面和原来平面平行的情况)。
重写之前的变换公式可以得到:
所以,已知变换对应的几个点就可以求取变换公式。反之,特定的变换公式也能新的变换后的图片。简单的看一个正方形到四边形的变换:
根据变换公式得到:
定义几个辅助变量:
都为0时变换平面与原来是平行的,可以得到:
不为0时,得到
求解出的变换矩阵就可以将一个正方形变换到四边形。反之,四边形变换到正方形也是一样的。于是,我们通过两次变换:四边形变换到正方形+正方形变换到四边形就可以将任意一个四边形变换到另一个四边形。
三、实验
透视变换的一般过程:读入图片,获取边界点,定义目标边界点,获取转换矩阵,执行转换。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
Mat src = imread("100.jpg");
vector<Point2f>src_coners(4);
src_coners[0] = Point2f(74, 144);
src_coners[1] = Point2f(306, 54);
src_coners[2] = Point2f(120, 277);
src_coners[3] = Point2f(379, 187);
//对四个点画圆点标记
circle(src, src_coners[0], 3, Scalar(0, 0, 255), 3, 8);
circle(src, src_coners[1], 3, Scalar(0, 0, 255), 3, 8);
circle(src, src_coners[2], 3, Scalar(0, 0, 255), 3, 8);
circle(src, src_coners[3], 3, Scalar(0, 0, 255), 3, 8);
vector<Point2f>dst_coners(4);
dst_coners[0] = Point2f(0, 0);
dst_coners[1] = Point2f(400, 0);
dst_coners[2] = Point2f(0, 300);
dst_coners[3] = Point2f(400, 300);
Mat warpMatrix = getPerspectiveTransform(src_coners, dst_coners);
Mat dst;
warpPerspective(src, dst, warpMatrix, dst.size(), INTER_LINEAR, BORDER_CONSTANT);
imshow("原图", src);
imshow("输出结果", dst);
waitKey();
return 0;
}