透视变换是3D转换,透视变换的本质是将图像投影到一个新的视平面;
据此,我们可以使用透视变化来实现鸟瞰图和图形贴图的效果;
一、鸟瞰图
实现前:
实现效果:
1.准备一个空的mat对象 用于保存转换后的图
Mat image=imread("road.jpg");
imshow("image",image);
Mat result=Mat::zeros(500,600,CV_8UC1);
//存储转换后的图像坐标 按顺时针 左上、右上、右下、左下(可自己定顺序)
vector<Point2f> obj;
obj.push_back(Point2f(0,0));
obj.push_back(Point2f(600,0));
obj.push_back(Point2f(600,500));
obj.push_back(Point2f(0,500));
2.在原图窗口里做鼠标操作,通过setMouseCallback鼠标回调函数,获取原图四个坐标
在原图中点击四个点获取四个坐标,顺序与上述1中设置的坐标对应,如果1中是顺时针,按选择坐标时也应该按顺时针操作,并且按照左上、右上、右下、左下顺序;
//2.在原图窗口里做鼠标操作,通过鼠标回调函数,获取原图四个坐标
struct imagedata data;
data.img=image;//将原图传入
setMouseCallback("image",mouseHundle,&data);//鼠标回调函数
waitKey(0);//键盘输入 向下执行
//点击按键之后结束鼠标操作,得到原图四个坐标和转换后的坐标
//用到的结构体和鼠标处理函数
struct imagedata
{
Mat img;
vector<Point2f>points;
//该points是test1原图需要做转换的坐标
//在test2中是原图转换后的坐标
};
void mouseHundle(int event,int x,int y,int flag,void *arg)
{
struct imagedata* ind=(struct imagedata *)arg;
if(event==EVENT_LBUTTONDOWN)//鼠标左键按下
{
//画圆
circle(ind->img,Point(x,y),3,Scalar(0,0,255),3,CV_AA);
imshow("image",ind->img);//test1鸟瞰图显示原图带圆点
//imshow("dst",ind->img);//test2贴图显示city图带圆点
if(ind->points.size()<4)
{
ind->points.push_back(Point2f(x,y));//转换的坐标只需要收集四个
}
}
}
3.开始计算坐标映射矩阵
Mat res=findHomography(data.points,obj,CV_RANSAC);
4.进行透视转换
将原图转变为效果图进行显示
warpPerspective(image,result,res,result.size());
imshow("result",result);
waitKey(0);
二、贴图
city图实现前:
贴图实现后:
左边大屏幕更改
贴图与鸟瞰图有些不同,鸟瞰图是将一张原图,通过选择四个点转换成鸟瞰图;
转换后的坐标固定的,转换前的4个坐标由鼠标选择;
而贴图的话,是将原图通过选择的点进行转换,再贴到city图中;
转换前的坐标固定的,就是普通的图片,转换后的坐标由鼠标选择;
1.准备原图要贴上去的图,即1.jpg
Mat image1=imread("1.jpg");//原图
Mat image2=imread("city.jpg");//city图
Mat dst=image2.clone();//克隆一份城市图
//1.准备原图要贴上去的图,即1.jpg
//Mat result=Mat::zeros(image1.rows,image1.cols,CV_8UC1);
//存储转换前的图像坐标
vector<Point2f> obj;
obj.push_back(Point2f(0,0));
obj.push_back(Point2f(image1.cols,0));
obj.push_back(Point2f(image1.cols,image1.rows));
obj.push_back(Point2f(0,image1.rows));
imshow("dst",image2);
2.在city窗口里做鼠标操作,通过鼠标回调函数,获取转换后的四个坐标
struct imagedata data;
data.img=dst;//将city图传入
setMouseCallback("dst",mouseHundle,&data);//鼠标回调函数
waitKey(0);
3.开始计算坐标映射矩阵
//点击按键之后结束鼠标操作,得到原图四个坐标和转换后的坐标
Mat res=findHomography(obj,data.points,CV_RANSAC);
4.透视转换
warpPerspective(image1,dst,res,dst.size());
imshow("image1",dst);
做到这一步,将原图变成这样子
5. 获取四个坐标,将city图中选择的位置填充成黑色,防止两个图片颜色冲突
最后通过image2+=dst把图片贴到city图上,这样就完成了
Point pts[4];
for(int i=0;i<4;i++)
{
pts[i]=data.points[i];
}
//在city图中选择的位置填充成黑色,防止两图颜色冲突
fillConvexPoly(image2,pts,4,Scalar(0),CV_AA);
image2+=dst;//把图片贴到city图上
imshow("final",image2);
waitKey(0);
完整源码
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
struct imagedata
{
Mat img;
vector<Point2f>points;
//该points是test1原图需要做转换的坐标
//在test2中是原图转换后的坐标
};
void mouseHundle(int event,int x,int y,int flag,void *arg)
{
struct imagedata* ind=(struct imagedata *)arg;
if(event==EVENT_LBUTTONDOWN)//鼠标左键按下
{
//画圆
circle(ind->img,Point(x,y),3,Scalar(0,0,255),3,CV_AA);
//imshow("image",ind->img);//test1显示原图带圆点
imshow("dst",ind->img);//test2显示city图带圆点
if(ind->points.size()<4)
{
ind->points.push_back(Point2f(x,y));//转换的坐标只需要收集四个
}
}
}
void test1()
{
Mat image=imread("road.jpg");
imshow("image",image);
//1.准备空的mat对象 用于保存转换后的图
Mat result=Mat::zeros(500,600,CV_8UC1);
//存储转换后的图像坐标 按顺时针 左上、右上、右下、做下(可自己定顺序)
vector<Point2f> obj;
obj.push_back(Point2f(0,0));
obj.push_back(Point2f(600,0));
obj.push_back(Point2f(600,500));
obj.push_back(Point2f(0,500));
//2.在原图窗口里做鼠标操作,通过鼠标回调函数,获取原图四个坐标
struct imagedata data;
data.img=image;//将原图传入
setMouseCallback("image",mouseHundle,&data);//鼠标回调函数
waitKey(0);
//点击按键之后结束鼠标操作,得到原图四个坐标和转换后的坐标
//3.开始计算坐标映射矩阵
Mat res=findHomography(data.points,obj,CV_RANSAC);
//4.透视转换
warpPerspective(image,result,res,result.size());
imshow("result",result);
waitKey(0);
}
void test2()
{
Mat image1=imread("1.jpg");
Mat image2=imread("city.jpg");
Mat dst=image2.clone();//克隆一份城市图
//1.准备原图要贴上去的图,即1.jpg
//Mat result=Mat::zeros(image1.rows,image1.cols,CV_8UC1);
//存储转换前的图像坐标
vector<Point2f> obj;
obj.push_back(Point2f(0,0));
obj.push_back(Point2f(image1.cols,0));
obj.push_back(Point2f(image1.cols,image1.rows));
obj.push_back(Point2f(0,image1.rows));
imshow("dst",image2);
//2.在city窗口里做鼠标操作,通过鼠标回调函数,获取需要四个坐标
struct imagedata data;
data.img=dst;//将city图传入
setMouseCallback("dst",mouseHundle,&data);//鼠标回调函数
waitKey(0);
//点击按键之后结束鼠标操作,得到原图四个坐标和转换后的坐标
//3.开始计算坐标映射矩阵
Mat res=findHomography(obj,data.points,CV_RANSAC);
//4.透视转换
warpPerspective(image1,dst,res,dst.size());
imshow("image1",dst);
Point pts[4];
for(int i=0;i<4;i++)
{
pts[i]=data.points[i];
}
//在city图中选择的位置填充成黑色,防止两图颜色冲突
fillConvexPoly(image2,pts,4,Scalar(0),CV_AA);
image2+=dst;//把图片贴到city图上
imshow("final",image2);
waitKey(0);
}
int main()
{
//test1();
test2();
return 0;
}
感谢观看!!!!
以上就是全部内容,如果对您有帮助,欢迎点赞评论,或者发现有哪里写错的,欢迎指正!