【OpenCV】透视变换应用——实现鸟瞰图与贴图

news2024/9/29 17:23:21

透视变换是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;
}

感谢观看!!!!

以上就是全部内容,如果对您有帮助,欢迎点赞评论,或者发现有哪里写错的,欢迎指正!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/96538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

asp.net mvc+elementUI 实现增删改查

最开始心想着一直都是前端玩这些玩意&#xff0c;个人虽然不是纯前端。好歹做为一个.net全栈开发多年&#xff0c;我就不太想用node去搭建&#xff0c;那么试试吧&#xff0c;总归不是那么几个css和js的文件引用&#xff0c;如果对vue.js不太熟悉&#xff0c;最好先去看看。 那…

智能家居创意DIY之智能触摸面板开关

触摸开关&#xff0c;即通过触摸方式控制的墙壁开关&#xff0c;其感官场景如同我们的触屏手机&#xff0c;只需手指轻轻一点即可达到控制电器的目的&#xff0c;随着人们生活品质的提高&#xff0c;触摸开关将逐渐将换代传统机械按键开关。 触摸开关控制原理 触摸开关我们把…

springboot入门案例

今天写一个springboot入门案例&#xff0c;接下来我将带大家走进springboot第一课的案例。如果有问题&#xff0c;望大家指正。 目录 1. 简介 2. 开发示例 2.1 创建springboot工程 3. 启动类 4. 常用注解 5. springboot配置文件 6. 开发一个controller 1. 简介 Spring …

大一学生WEB前端静态网页——旅游网页设计与实现(15页面)

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

Git GitHub入门

目录Git1. 安装Git1. 下载Git2. 安装Git2. Git常用命令1. 设置用户签名2. 初始化本体库3. 查看本地库状态4. 添加暂存区5. 提交本地库6. 查看历史记录7. 修改文件8. 版本穿梭3. Git分支操作1. 查看分支2. 创建分支3. 切换分支4. 合并分支GitHub操作1. 创建远程仓库2. 远程仓库操…

【sciter】历经一个月封装的Web组件库使用说明文档

Web 组件库 1、组件库总体架构 2、目录结构及组件库引入 使用时,只需要引入 CSS 样式文件及组件入口文件即可。 3、组件注意事项 1、当组件支持绑定事件时,事件名称命名规则为 Sc + DOM事件名称且首字母大写,即点击事件(click)对应(ScClick) 在 sciter 中,通过原生 D…

0127 排序 Day16

剑指 Offer 45. 把数组排成最小的数 输入一个非负整数数组&#xff0c;把数组里所有数字拼接起来排成一个数&#xff0c;打印能拼接出的所有数字中最小的一个。 示例 1: 输入: [10,2] 输出: "102" 示例 2: 输入: [3,30,34,5,9] 输出: "3033459" class…

浅谈 Flink 窗口

本次只记录最近对于窗口的新认知 关于窗口的详细知识可以参考如下链接: https://blog.csdn.net/mynameisgt/article/details/124223193 窗口的作用是为了在无限流上进行统计计算,数据到来时,则为此条数据开辟窗口。当 Flink 的时间大于等于窗口的结束时间时,触发这个窗口…

线程池的设计与原理解析(四)之---runWorker()方法

在调用start()方法&#xff0c;调用的就是worker的run方法&#xff0c;实际上调用的是runWorker()方法 public void run() {// 这个是核心方法&#xff0c;worker启动后的逻辑从这里进入runWorker(this);}简单的梳理runWorker的流程 如果构造worker的时候&#xff0c;指定了fi…

LinuxOS-IO-动静态库

文章目录AMC的了解动静态库1.理论理解2.如何制作一个库&#xff1f;&#xff1f;了解实验&#xff1a;制作库交给别人使用生成静态库生成文件 删除文件 发布文件使用静态库?生成动态库使用动态库AMC的了解 Access:文件最近被访问的时间。 我们发现实际操作下来&#xff0c;文…

谁在「元宇宙」里卖咖啡?

作者 | 曾响铃 文 | 响铃说 全球首个全场景数实融合的「世界杯元宇宙」音乐盛典&#xff0c;已经落下了帷幕。 在14日与16日举办的两场动感地带世界杯音乐盛典中&#xff0c;既能看到周杰伦、李宇春、G.E.M。邓紫棋、周深等乐坛大咖&#xff0c;又能看到动感地带数智代言人橙…

字节跳动首发485道Java岗面试题(含答案)

就目前国内的面试模式来讲&#xff0c;在面试前积极的准备面试&#xff0c;复习整个 Java 知识体系将变得非常重要&#xff0c;可以很负责任地说一句&#xff0c;复习准备的是否充分&#xff0c;将直接影响你入职的成功率。 但很多小伙伴却苦于没有合适的资料来回顾整个 Java …

docker搭建gitlab 服务器

1、搜索gitlab镜像 # 查找Gitlab镜像 docker search gitlab # 拉取Gitlab镜像 docker pull gitlab/gitlab-ce:latest 2、启动Gitlab容器 docker run \-itd \-p 9000:80 \-p 9022:22 \-v /home/gitlab/etc:/etc/gitlab \-v /home/gitlab/logs:/var/log/gitlab \-v /home/gi…

drupal远程代码执行 (CVE-2018-7600)漏洞学习与复现

文章目录一、漏洞描述二、POC&EXP一、漏洞描述 drupal是一个开源PHP管理系统&#xff0c;架构使用的是php环境mysql数据库的环境配置。在Drupal 6.x&#xff0c;7.x&#xff0c;8.x系列的版本中&#xff0c;均存在远程代码执行漏洞。该漏洞产生的原因在于Drupal对表单渲染…

ADI Blackfin DSP处理器-BF533的开发详解58:DSP控制ADXL345三轴加速度传感器的应用(含源码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 MEMS三轴加速度传感器 我做了一个三轴加速度传感器的子卡&#xff0c;插在这个板子上&#xff0c;然后写了一些有意思的应用程序。 硬件实现原理…

Nacos2.2版本发布了,我为其贡献了几行代码并适配了PostgreSQL插件

目录 一、背景 二、个人贡献 三、Nacos使用适配的PostgreSQL插件 3.1、插件源码工程项目结构&#xff1a; 3.2、打包加载插件 3.3、修改配置文件为PostgreSQL连接字符串 3.4、导入数据库脚本文件 四、总结 一、背景 Nacos 是 Dynamic Naming and Configuration-Servic…

计算机毕设Python+Vue心灵治愈服务平台(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

C++那些事之高效率开发C++/C

1.神器 目前开发C/C用的比较多的当属Vim、VS code、CLion。 Vim配上插件编写C/C效率高的不少。 VSCode配上自定义配置及快捷键、vim插件效率跟vim旗鼓相当。 CLion因其独特的CMakeLists.txt管理方式及强大的代码补全等功能&#xff0c;编写本地代码绝对好于前两者。 但是对…

什么是数据指标体系?

定义 对当前业务有参考价值的统计数据 作用 监控业务情况 通过拆解指标寻找当前业务问题 评估业务可改进的地方&#xff0c;找出下一步工作的方向 常用数据指标 谁&#xff1a;用户数据 干了什么&#xff1a;行为数据 结果怎样&#xff1a;业务数据 选好数据指标的通用…

大数据学习:学生排序

文章目录一、提出任务二、任务过程&#xff08;一&#xff09;准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录&#xff08;二&#xff09;实现步骤1、创建Maven项目2、添加相关依赖3、创建日志属性文件4、创建学生实体类5、创建学生映射器类5、创建学生归并器类6…