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

四路鱼眼相机环绕鸟瞰系统:从标定到拼接的完整实现 车载环视系统(AVM)已成为高级驾驶辅助的核心功能,其背后的“上帝视角”依赖于多路鱼眼相机的协同工作。鱼眼镜头虽能提供超广视场,但成像畸变显著,需通过内参标定与逆透视映射(IPM)将斜视画面转换为统一的俯视鸟瞰图。多路图像的拼接并非简单叠加,重叠区域需要采用多频带融合策略消除接缝与重影,同时配合时间同步与亮度校正。本文从工程实践出发,完整解析四路鱼眼相机的环视系统搭建流程,涵盖相机模型选择、标定板布置、单应矩阵计算、融合参数调优及性能优化等关键环节,为视觉感知、车载影像及多相机融合场景提供一套可复用的技术路 阅读详情
AI摘要

本文深入探讨了AVM环视算法的基本原理及其在实际应用中的实现过程。通过详细的数学公式推导,介绍了如何利用逆透视变换(IPM)生成鸟瞰图,并提供了示例代码来展示具体步骤。此外,还讨论了工程实践中如何优化计算效率。

一、前言

最近想实现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;
    dis_pt[2] = 1;
    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
自动驾驶中的逆投影变换IPM @[TOC]动态IPM(Adaptive Inverse Projective Mapping) 动态逆投影变换(IPM) IPM简介 动态逆变换主要用于自动驾驶中,安装在车辆上的相机在采集车道线图片时,原本平行的车道线将呈现出一定角度,将图片中具有一定角度的车道线恢复平行的过程,就称为动态逆投影变换。如下图所示。 基于无穷远点(VP,Vanishing Point)的动态逆投射变换 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能, 阅读详情

相关推荐

AVM环视:系统搭建整体流程

文章目录前言一、畸变矫正鱼眼相机二、透视变换三、图像拼接四、图像融合总结 前言 由于正在做AVM环视,所以记录一下整个过程,归纳为一个系列文章,并对期间遇到的错误进行归纳整理。本文主要概括了AVM环视的大致流程和逻辑,不涉及代码部分,仅供思路参考,其中涉及的具体技术会在后期整理为小章节进行分析。 一、畸变矫正 鱼眼相机 做环视基本上使用到的是鱼眼照片,因为鱼眼相机的视角范围可以达到220°到230°,所以一个相机就可以采集到一个面的全部信息,例如汽车具有四个面,那么在汽车的前后左右分别安装一个鱼眼相机.

qq_34468890的博客 6534

AVM 环视拼接 鱼眼相机

本节描述了环视系统的成像过程,即如何从车辆周围安装的摄像头捕获的图像中生成环视图。为了合成环视图像,需要建立一个点在原始鱼眼图像上的像素坐标与鸟瞰图上的像素坐标之间的映射关系。由于这种关系相对复杂,我们将其分为两部分:从**鱼眼图像上的像素坐标到地面坐标的映射关系,以及从3D地面坐标到鸟瞰图上的像素坐标的映射关系。给定地面坐标系OGO_GOG​和四摄像头环视系统(摄像头表示为C1C_1C1​C2C_2C2​C3C_3C3​和C。

智能机器人产学研基地 1335

从内外参推导到numpy实现:IPM逆透视变换与AVM环视拼接实战

在计算机视觉与自动驾驶领域,相机标定与透视变换是构建环境感知系统的基础能力。普通前视相机拍摄的画面存在近大远小的透视效应,使得地面平行线在图像中交汇,难以直接用于距离判断与全景显示。逆透视变换(IPM)利用相机内外参构建单应矩阵,将图像像素映射到统一的地面坐标系,从而获得符合人类直觉的俯视视角。其核心原理在于借助地平面约束,将三维投影退化为二维平面单应,而畸变校正则保障了大视角镜头下的映射精度。该技术广泛应用于车载环视系统(AVM),通过四路鱼眼相机的IPM输出与软掩码融合,实现车身周围360°无缝全景拼接

weixin_30558697的博客 189

鱼眼环视拼接(AVM)(持续更新)

后面有时间可以学习下: https://github.com/neozhaoliang/surround-view-system-introduction

gyqJulius_Caesar的博客 2279

360环视全景拼接C++实战:从鱼眼标定到鸟瞰融合的AVM入门

环绕影像技术正加速落地于自动驾驶与智能座舱,其核心是将多路鱼眼相机画面实时拼接为鸟瞰全景。鱼眼镜头因大视场引入强烈畸变,需通过相机标定获得内参与畸变系数,再利用逆透视映射将透视图像转为俯视视角。多路图像在重叠区域进行加权融合,消除接缝与亮度断层,最终形成无缝的360°环视画面。该技术在自动泊车、狭窄路段通过性辅助等场景中广泛应用。本文基于一个轻量级C++与OpenCV实现的开源Demo,完整拆解相机标定、鸟瞰变换、多路融合及工程目录架构,帮助开发者快速掌握AVM系统的代码组织方式与核心算法流程,为二次开发奠

weixin_32025789的博客 148

360环视全景拼接:C++实现AVM四路鱼眼到鸟瞰图完整链路

自动驾驶与智能座舱的普及,让环视系统成为低速泊车和窄道会车场景下最可靠的视觉方案。该技术通过四路鱼眼相机采集车身周围画面,利用畸变校正、逆透视变换与重叠区融合,生成一张以车辆为中心的鸟瞰俯视图。全景拼接的核心在于将鱼眼模型转换为针孔模型,并借助查找表与权重图实现高效实时处理,最终在嵌入式平台完成可运行的C++实现。这项技术不仅能帮助开发者理解自动驾驶感知前端的图像转换逻辑,也为工程化落地提供了低成本参考。本文从OpenCV基础模块入手,结合标定参数外置的设计,拆解一个最小AVM全景拼接demo的完整数据流与

weixin_28285943的博客 216

PYNQ-Z2 开发板从镜像烧录到 Jupyter 交互全流程指南

本文详细介绍了PYNQ-Z2开发板从镜像烧录到Jupyter交互的全流程指南,包括硬件解析、镜像烧录技巧、设备启动与网络配置、Jupyter Notebook深度使用以及实战案例分享。通过具体步骤和实用技巧,帮助开发者快速上手PYNQ-Z2开发板,实现高效的FPGA开发和智能家居控制应用。

weixin_28736355的博客 437

企业微信微盘API权限避坑指南:为什么你的Python脚本无法获取文件列表?

本文深入解析了企业微信微盘API的权限模型,解释了为何即使使用超级管理员账号,Python脚本也可能因权限不足而无法获取文件列表。核心在于微盘API基于“应用身份”而非“用户身份”进行校验,应用只能访问自身创建的空间。文章提供了构建文件上传代理、利用事件回调等合规的替代方案,帮助企业实现高效数据同步。

weixin_29322553的博客 523

VS Code+ESP-IDF开发避坑指南:头文件标红报错的5种解决方法(附CMakeLists.txt配置)

本文详细解析了在VS Code中使用ESP-IDF开发ESP32时头文件标红报错的5种解决方法,包括环境配置检查、CMakeLists.txt规范配置、路径解析策略、缓存清理技巧和高级调试手段。特别提供了CMakeLists.txt的实战配置示例,帮助开发者彻底解决头文件路径问题,提升开发效率。

weixin_33670786的博客 559

ENVI5.6 批量处理GF-2/GF-6/GF-7:从安装到融合的完整自动化流程

本文详细介绍了ENVI5.6环境下批量处理GF-2/GF-6/GF-7卫星数据的完整自动化流程,包括环境配置、工具安装、正射校正、图像融合等关键步骤。通过实战案例和优化技巧,帮助用户高效完成高分卫星影像处理,提升工作效率。特别针对GF-6和GF-7的特殊处理要点进行了深入解析。

weixin_42546392的博客 179

Oracle11g下载与安装(windows)

一、Oracle11g下载 二、安装准备 三、执行安装步骤 四、测试连接 附:Oracle11g服务说明

欢迎订阅我的“JAVA全栈开发笔记(全)”专栏,价格优惠,仅需19.9元。 2万+

Vue+OpenLayers6一本通,OpenLayers6完整教程大全,OpenLayers6全知全解,OpenLayers6入门、实战、扩展进阶三合一专栏目录汇总

Gis开发入门,OpenLayers、Leaflet、Maplibre-gl和Cesiumjs地图引擎介绍以及几种地图服务vms、vmts介绍OpenLayers介绍,相比较其他地图引擎有什么优点OpenLayers7.x版本和6.x版本有什么区别,是否需要升级到OpenLayers7版本?OpenLayers6实战:OpenLayers创建自定义控件,以创建一个地图复位控件为例OpenLayers6实战,OpenLayers创建自定义鹰眼控件,自定义鹰眼控件样式,调整鹰眼控件位置、大小、文字和按钮等样式。

GIS技术方向,GIS地图技术分享(GIS入门、Openlayers教程、Leaflet教程),做最好的GIS地图开发教程。关注博主公众号:eguid 2196

PCL 基于强度的双边滤波【2026最新版】

基于强度信息的双边滤波代码实现、滤波前后点云未出现变化的原因以及获取带有强度pcd点云的方法。本文由优快云点云侠原创,博客长期更新,本文最近一次更新时间为:2026年5月24日。

点云侠的博客 29万+

Unity的粒子系统使用shadergraph(内置管线)制作的一个顶点偏移shader,但是粒子模型移动时,顶点也会偏移?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 1174

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

上一篇: C++用boost实现带返回值、输入参数的异步线程池
文锦渡
博客等级 码龄11年 122粉丝 28原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文锦渡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值