从内外参推导IPM变换方程及代码实现(生成AVM环视拼接图)

一、前言

最近想实现AVM拼接,看了不少博客和论文,不过比较愚钝,一直没能很好理解原理,尤其是怎么在实现时把下文式1与式2中Z1和Z2消除的,所以严谨的推导了一下对应的公式,如有不对,水平有限,烦请指出~

IPM变换(逆透视变换),顾名思义,即将正常透视效应消除的变换,变换结果为鸟瞰图BEV(俯视图);AVM环视拼接一般是将车身前后左右的四个鱼眼相机拼接成环视图(也是俯视),其使用的单应矩阵将四个相机转到同一个俯视坐标系。

投影变换的通俗理解就是:假设同一个相机分别在A、B两个不同位置,以不同的位姿拍摄同一个平面(重点是拍摄平面,例如桌面、墙面、地平面),生成了两张图象,这两张图象之间的关系就叫做投影变换。

二、公式推导

公式太难打了,全用word存了,在这直接截图

这也就解释了:为什么有的AVM算法是需要标定相机的内外参,而有的只提供单应矩阵H。

 三、示例代码

#include <Eigen/Core>
#include <Eigen/Dense>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/core/eigen.hpp>
#include <opencv2/opencv.hpp>
#include <vector>void DistortEigenPoints(const Eigen::Vector3d &undis_pt, Eigen::Vector3d &dis_pt, double k1, double k2, double p1,double p2) {double x2 = undis_pt[0] * undis_pt[0];double y2 = undis_pt[1] * undis_pt[1];double r2 = x2 + y2;if (r2 == 0) return;double r4 = r2 * r2;double r6 = r2 * r4;double xy = undis_pt[0] * undis_pt[1];dis_pt[0] = undis_pt[0] * (1 + k1 * r2 + k2 * r4) + 2 * p1 * xy + p2 * (r2 + 2 * x2);dis_pt[1] = undis_pt[1] * (1 + k1 * r2 + k2 * r4) + p1 * (r2 + 2 * y2) + 2 * p2 * xy;return;
}float interp(const cv::Mat &img, float x, float y) {int ix = x;int iy = y;float dx = x - ix;float dy = y - iy;float ddx = 1.0f - dx;float ddy = 1.0f - dy;return ddx * ddy * img.data[iy * img.cols + ix] + ddx * dy * img.data[(iy + 1) * img.cols + ix] +dx * ddy * img.data[iy * img.cols + ix + 1] + dx * dy * img.data[(iy + 1) * img.cols + ix + 1];
}int main() {std::string img_path = "Mynt/00001772.jpg";Eigen::Matrix3d K_c;K_c << 1037.536376953125, 0, 600.182861328125, 0, 1038.532958984375, 358.40493774414062500, 0, 0, 1;double k1 = 0.03784750;double k2 = -0.051872;double p1 = -0.000938;double p2 = 0.000157;Eigen::Matrix3d R_gc;R_gc << 0.9962626012012678, -0.08634899803974432, -0.00216332734845117, -0.005878375212093168, -0.04279258802138065,-0.9990666840182884, 0.08617583276389137, 0.9953454902434454, -0.0431402468639808;Eigen::Vector3d t_gc;t_gc << 0.283289952815021, 1.136073800639606, -2.129837994618606;// 鸟瞰图设置为长宽20m,分辨率0.2mdouble W_m = 20;double H_m = 20;double dx = 0.02;double dy = 0.02;Eigen::Matrix3d K_g;K_g << 1.0 / dx, 0, W_m / (2 * dx), 0, -1.0 / dy, H_m / (2 * dy), 0, 0, 1;Eigen::Matrix3d J_gc;J_gc.block<3, 2>(0, 0) = R_gc.block<3, 2>(0, 0);J_gc.block<3, 1>(0, 2) = t_gc;//一定要带上图像类型,比如IMREAD_GRAYSCALE,默认的是IMREAD_COLORcv::Mat img = cv::imread(img_path, cv::IMREAD_GRAYSCALE);//一、未去畸变鸟瞰图Eigen::Matrix3d H = K_c * J_gc * K_g.inverse();cv::Mat trans_mat;cv::eigen2cv(H, trans_mat);cv::Mat bev_img(H_m / dy, W_m / dx, CV_8UC1);// warpPerspective是透视变换,所有trans_mat需要取逆cv::warpPerspective(img, bev_img, trans_mat.inv(), bev_img.size());//二、去畸变鸟瞰图Eigen::Matrix3d H_gc = J_gc * K_g.inverse();cv::Mat bev_img2(H_m / dy, W_m / dx, CV_8UC1);for (int row = 0; row < bev_img2.rows; row++) {for (int col = 0; col < bev_img2.cols; col++) {Eigen::Vector3d p_g(col, row, 1);Eigen::Vector3d P_c = H_gc * p_g;// 去掉在相机后面的点if (P_c[2] < 0) continue;P_c /= P_c[2];Eigen::Vector3d P_c_dis;DistortEigenPoints(P_c, P_c_dis, k1, k2, p1, p2);Eigen::Vector3d p_c = K_c * P_c_dis;// 在原图范围内的才能映射if (p_c[0] >= 0 && p_c[1] >= 0 && p_c[0] < img.cols - 1 && p_c[1] < img.rows - 1) {bev_img2.at<uchar>(row, col) = interp(img, p_c[0], p_c[1]);}}}cv::imshow("img", img);cv::imshow("bev_img", bev_img);cv::imshow("bev_img2", bev_img2);cv::waitKey(0);return 0;
}

 效果展示

ps.

    // 1. 读取图像cv::Mat img = cv::imread(img_path, cv::IMREAD_GRAYSCALE);

使用时一定要记得加对应图像类型 ,比如灰度的为cv::IMREAD_GRAYSCALE,否则读取的会为三通道的IMREAD_COLOR,导致整个转换出问题,查了个半死。。。

参考文献:

自动驾驶AVM环视算法--3D碗型投影模式的算法原理和代码实现_3d avm算法原理-CSDN博客

Fisheye Calibration Basics- MATLAB & Simulink- MathWorks 中国

AVM 环视拼接方法介绍

IPM 鸟瞰图公式转换与推导 - 古月居

https://blog.51cto.com/u_16099267/10196291

逆透视变换详解 及 代码实现(二)_uvlimitsp-CSDN博客

Online Camera Pose Optimization for the Surround-view System

IPM原理_ipm转换-CSDN博客

https://zhuanlan.zhihu.com/p/636990989

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

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

相关文章

Qt Group与华为合作开发OpenHarmony版本,打造无缝跨设备操作系统

在华为开发者大会2024上&#xff0c;跨平台软件开发和质量保证工具的领先供应商 Qt Group&#xff08;Nasdaq, Helsinki: QTCOM&#xff09;荣幸地宣布成为OpenHarmony生态系统合作伙伴。这是继近几年华为采用Qt开发框架和自动化测试工具Squish的商业许可后&#xff0c;Qt Grou…

Elasticsearch集群部署(下)

目录 上篇&#xff1a;Elasticsearch集群部署&#xff08;上&#xff09;-CSDN博客 七. Filebeat 部署 八. 部署Kafka 九. 集群测试 链接&#xff1a;https://pan.baidu.com/s/1AFXSmDdY5xBb7g35ipKoaw?pwdfa9m 提取码&#xff1a;fa9m 七. Filebeat 部署 为什么用 F…

搭建基础库~

前言 项目中会用到工具库、函数库以及一些跟框架绑定的组件&#xff0c;如果这些基础模块每个项目都实现一套&#xff0c;维护起来那真的头大&#xff0c;你说呢&#x1f609; 搭建流程 准备工作 创建文件夹myLib、安装Git以及pnpm 目录大概就系这样子&#xff1a; myLib ├…

Vue跨域获取ip和ip位置城市等归属地信息

由于端口设置与查询服务器不一致&#xff0c;所以不能直接从ip138网上抓取&#xff0c;只能跨域查询。实现跨域查询&#xff0c;简单的方法是使用jsonp方式&#xff0c;只支持get请求&#xff0c;同时也需要查询的服务器支持jsonp。这时找到了腾讯位置服务。参考文章&#xff0…

Appium Inspector介绍和使用

一、什么是Appium Inspector 官方介绍&#xff1a;Overview - Appium Inspector 检查器的主要目的是提供应用程序页面源代码的检查功能。它主要用于测试自动化开发&#xff0c;但也可用于应用程序开发 - 或者如果只是想查看应用程序的页面源代码&#xff01; 从本质上讲&…

API Object设计模式

API测试面临的问题 API测试由于编写简单&#xff0c;以及较高的稳定性&#xff0c;许多公司都以不同工具和框架维护API自动化测试。我们基于seldom框架也积累了几千条自动化用例。 •简单的用例 import seldomclass TestRequest(seldom.TestCase):def test_post_method(self…

vue3项目图片压缩+rem+自动重启等plugin使用与打包配置

一、Svg配置 每次引入一张 SVG 图片都需要写一次相对路径&#xff0c;并且对 SVG 图片进行压缩优化也不够方便。 vite-svg-loader插件加载SVG文件作为Vue组件&#xff0c;使用SVGO进行优化。 插件网站https://www.npmjs.com/package/vite-svg-loader 1. 安装 pnpm i vite-svg…

步进电机(STM32+28BYJ-48)

一、简介 步进电动机&#xff08;stepping motor&#xff09;把电脉冲信号变换成角位移以控制转子转动的执行机构。在自动控制装置中作为执行器。每输入一个脉冲信号&#xff0c;步进电动机前进一步&#xff0c;故又称脉冲电动机。步进电动机多用于数字式计算机的外部设备&…

DOM 中包含哪些重要方法

1. alert 带有指定消息的警告框 alert("hello world"); 2. confirm 带有确定和取消的对话框&#xff0c;点击确定返回 true&#xff0c;点击取消返回 false confirm("你好吗"); 3. prompt 显示一个提示框&#xff0c;允许用户输入文本&#xff0c;点击…

CST电磁仿真创建独特的天线

在日益无线化的世界中&#xff0c;一切都取决于天线&#xff0c;从我们用于医疗保健、工作和娱乐的智能设备到将我们从一个地方带到另一个地方的车辆。它们如此融入我们的日常生活&#xff0c;以至于我们大多数人甚至没有想到它们——即使想到了&#xff0c;我们也会想象屋顶上…

ubnutu20.04-vscode安装leetcode插件流程

1.在vscode插件商城选择安装leetcode 2.安装node.js 官网下载一个版本安装流程&#xff1a; ①tar -xvf node-v14.18.0-linux-x64.tar.xz ①sudo ln -s /app/software/nodejs/bin/npm /usr/local/bin/ ②ln -s /app/software/nodejs/bin/node /usr/local/bin/ 查看版本&…

nginx的LNMP构建+discuz论坛

一、LNMP&#xff1a; L&#xff1a;linux 操作系统 N&#xff1a;nginx前端页面的web服务 P&#xff1a;PHP&#xff0c;是一种开发动态页面的编程语言&#xff0c;解析动态页面&#xff0c;起到中间件的作用&#xff08;在nginx和数据库的中间&#xff09;&#xff0c;在中…

横截面数据回归

横截面数据回归 一些笔记 观测值一定要比参数值多 p值<0.05,拒绝H0. 参数显著&#xff0c;不能说明模型对 AIC与BIC准则&#xff0c;越小越好的指标值AIC 回归分析一定要进行残差的正态性检验。所有的残差都大于0&#xff0c;小于0&#xff0c;都不正常。残差正常应该是分…

小学校园“闲书”交易平台的设计与实现-计算机毕业设计源码04282

小学校园“闲书”交易平台的设计与实现 摘 要 小学校园“闲书”交易平台是为了解决小学生之间的书籍交流和阅读兴趣培养而设计的。该平台通过使用现代技术手段&#xff0c;如移动应用开发和互联网技术&#xff0c;构建了一个功能齐全的交易平台。平台支持用户注册与登录&#x…

应用于空气和液体抑菌的静态UVC LED抑菌模组-WH-UVC001-VO

WH-UVC001-VO是一款用于空气和液体抑菌的静态UVC LED抑菌模组。适用于带水箱、密闭的腔体结构。可安装于顶部、侧壁及底部&#xff0c;出光面符合IP65的防水要求&#xff0c;即使安装于水箱底部也不用担心漏水。 使用的UVC LED的波长范围为260-280nm&#xff0c;具有优良高效的…

JavaScrip——switch类型

目录 任务描述 相关知识 严格相等 switch语句 编程要求 任务描述 北美五大湖的名称和面积如下&#xff1a; 名称面积(平方公里)Superior82414Huron59600Michigan58016Erie25744Ontario19554 本关任务&#xff1a;根据面积判断湖泊的名字。 相关知识 上一关讲解的是拥…

Java项目:基于SSM框架实现的网上医院预约挂号系统【ssm+B/S架构+源码+数据库+毕业论文】

一、项目简介 本项目是一套基于SSM框架实现的网上医院预约挂号系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

Linux静态库的制作

Linux操作系统支持的函数库分为&#xff1a; 静态库&#xff0c;libxxx.a&#xff0c;在编译时就将库编译进可执行程序中。 优点&#xff1a;程序的运行环境中不需要外部的函数库。 缺点&#xff1a;可执行程序大 动态库&#xff0c;又称共享库&#xff0c;libxxx.so&a…

解决Python爬虫开发中的数据输出问题:确保正确生成CSV文件

引言 在大数据时代&#xff0c;爬虫技术成为获取和分析网络数据的重要工具。然而&#xff0c;许多开发者在使用Python编写爬虫时&#xff0c;常常遇到数据输出问题&#xff0c;尤其是在生成CSV文件时出错。本文将详细介绍如何解决这些问题&#xff0c;并提供使用代理IP和多线程…

【网络安全的神秘世界】SQL注入(下)

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 3.7 二次注入 不好挖这个漏洞&#xff0c;需要搞懂业务逻辑关系 二次注入通常是指在存入数据库时做了过滤&#xff0c;但是取…