透视投影变换用于图像几何校正

在日常生活中经常有这样的问题:当我们参加讲座之类的课堂活动的时候,我们想把讲师的演示的PPT之类的东西用手机拍下来,对于两边的同学,拍的图片由于不是正面的,看上去就有点偏,就比如下图(手机随便拍的,有点渣)。

而这里我们就可以通过透视投影变换得到正面图像。

那么什么是透视投影呢?简单的说,就是三维物体投影到二维物体上。这一系列的变换对应了一个透视投影矩阵,这里先不细说了,还是先回归到上面的问题。在opencv里面提供函数,根据4个点就可以得到矩阵。

我采用的方法很简单,通过手动鼠标点击4个点(先左上角,然后顺时针方向),对应变换后的图像的4个顶点,然后采用opencv的方法解决就可以了。附上代码(opencv 2.44测试通过):

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "stdafx.h"
#include "opencv.hpp"
#include "highgui.h"

void mouse_callback(int event, int x, int y, int flags, void* param);

int _tmain(int argc, _TCHAR* argv[])
{
cv::Mat img = cv::imread("E:\\113.jpg");
cv::Size imgSize = img.size();

cv::vector<cv::Point2f> corners;
cv::namedWindow("View", CV_WINDOW_NORMAL);
cv::resizeWindow("View", 600, 1000);

//手动点坐标,从左上角开始顺时针
cv::setMouseCallback("View", mouse_callback, (void*)&corners);

cv::imshow("View", img);
cvWaitKey(0);

/*
for(int i=0; i<corners.size(); i++)
{
std::cout << corners[i].x << " " << corners[i].y << std::endl;
}*/


cv::Point2f src[4];
cv::Point2f dst[4];

for(int i=0; i<4; i++)
{
src[i] = corners[i];
}

//dst赋值,从零点开始顺时针
dst[0].x = 0;
dst[0].y = 0;
dst[1].x = imgSize.width-1;
dst[1].y = 0;
dst[2].x = imgSize.width-1;
dst[2].y = imgSize.height-1;
dst[3].x = 0;
dst[3].y = imgSize.height-1;

cv::Mat dstImg = img;

//通过4个点得到变换矩阵,然后进行变换
cv::Mat warpMat = cv::getPerspectiveTransform(src, dst);
cv::warpPerspective(img, dstImg, warpMat, imgSize);

cv::namedWindow("Viewdst", CV_WINDOW_NORMAL);
//cv::resizeWindow("Viewdst", 800, 600);

cv::imshow("Viewdst", dstImg);
cvWaitKey(0);

cv::destroyAllWindows();
return 0;
}

void mouse_callback(int event, int x, int y, int flags, void* param)
{

cv::vector<cv::Point2f> *corners = (cv::vector<cv::Point2f>*) param;

//int ev = event;

switch(event)
{
case CV_EVENT_LBUTTONDOWN:
{
if(corners->size() == 4)
break;
corners->push_back(cv::Point(x, y));
break;
}
}
}

程序测试采用上面的那张图,结果如下

至于前面提到的透视投影的理论部分,书上和网上已经写的很明白了,大家可以参考这篇文
http://blog.csdn.net/goncely/article/details/5397729,我就不“反复造轮子了”。
最后,Merry Christmas!!