使用opencv对图像进行透视变换

一.什么是透视变换

透视变换就是透视变换(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<opencv2/opencv.hpp>
#include<iostream>
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;
}

 


 

 

 

  • 11
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值