一.什么是透视变换
透视变换就是透视变换(Perspective Transformation)是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换。简单的来说就是把一张斜着看的二维图形变为俯瞰的二维图像,透视变换再计算机视觉中相当常用,因为计算机采集的图形并非规整的图像,比如再使用自动倒车,赛道识别等方面都需要使用透视变换来改变计算机所采集的的信息,比如:
二.代码演示:
目标是把这张图片:
变为:
首先是打开图片
frame = imread("test3.jpg", 1);
frame1 = frame.clone();
这里先定义两张一样的图片,一张用于用户输入,一张用于数据处理
然后调整一下图片的大小,这里我测试了一下,把图片都变成正方形可以使变换的更加准确
Size a = frame.size();
resize(frame, frame, Size(max(a.height,a.width), max(a.height ,a.width)));
resize(frame1, frame1, Size(max(a.height, a.width), max(a.height, a.width)));
然后使确定矩形的四个点,这里我们让用户自己再图片上进行点击,我们可以使用openCV自带的函数setmousecallback,用法如下:
这里共有三个参数:
第一个:窗口名称
第二个:鼠标的响应函数和回调函数
第三个:回调函数的参数
我们在第二个参数中写一个返回值void的函数On_mouse,其中识别鼠标按下的回调的参数是:EVENT_LBUTTONDOWN
setMouseCallback("test", On_mouse, 0);
然后我们期望用户点击后在用户点击的地方显示一个点,我们可以使用circle函数,所以On_mouse函数如下:
int num_point = 0, out_size = 0;
void On_mouse(int event, int x, int y, int flags, void*) {
if (event == EVENT_LBUTTONDOWN) {
in_point[num_point] = Point(x, y);
cout << x << ' ' << y << endl;
circle(frame1, in_point[num_point], 6, Scalar(0, 255, 0), -1);
imshow("test", frame1);
num_point++;
}
}
然后我们把输入的四个点的坐标存在in_point这个数组里
最后我们使用getPerspectiveTransform和warpPerspective函数进行透视变换:
temp = getPerspectiveTransform(in_point, out_point);
warpPerspective(frame, result, temp, frame.size());
这里注意我们输入点的顺序是:左上,右上,左下,右下。
完整代码:
#include
#include
using namespace std;
using namespace cv;
Mat frame,frame1;
Point2f in_point[4];
Point2f out_point[4];
int num_point = 0, out_size = 0;
void On_mouse(int event, int x, int y, int flags, void*) {
if (event == EVENT_LBUTTONDOWN) {
in_point[num_point] = Point(x, y);
cout << x << ' ' << y << endl;
circle(frame1, in_point[num_point], 6, Scalar(0, 255, 0), -1);
imshow("test", frame1);
num_point++;
}
}
int main(){
cout << "请依次点击需要变换的四边形的左上角,右上角,左下角,右下角" << endl;
cout << "点选取好后单击Enter" << endl;
frame = imread("test3.jpg", 1); //test3.jpg是我自己在这个目录下的文件,也可以替换为图片的绝对路径,但是要注意使用双斜杠
frame1 = frame.clone();
Size a = frame.size();
resize(frame, frame, Size(max(a.height,a.width), max(a.height ,a.width)));
resize(frame1, frame1, Size(max(a.height, a.width), max(a.height, a.width)));
imshow("test", frame);
setMouseCallback("test", On_mouse, 0);
while (1) {
if (waitKey(10) == 13) {
out_size = std::max(in_point[1].x - in_point[0].x, in_point[3].x - in_point[2].x);
out_point[0] = Point2f(0.0, 0.0);
out_point[1] = Point2f(out_size * 1.0, 0.0);
out_point[2] = Point2f(0.0, out_size * 1.0);
out_point[3] = Point2f(out_size * 1.0, out_size * 1.0);
Mat temp, result;
temp = getPerspectiveTransform(in_point, out_point);
warpPerspective(frame, result, temp, frame.size());
imshow("result", result);
cout << "转换完成" << endl;
waitKey(0);
}
}
return 0;
}