问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

AVM全景环视系统(360°影像)代码阅读

创作时间:
2025-01-22 08:58:09
作者:
@小白创作中心

AVM全景环视系统(360°影像)代码阅读

代码借鉴来源:neozhaoliang/surround-view-system-introduction: A full Python implementation for real car surround view system (github.com)

背景

在360°全景视图泊车辅助系统中,通过安装在车辆前、后、左、右 4 个方位的广角摄像头采集车辆四周的视频影像,利用图像融合和拼接技术合成一幅车身周围的全景视图,最后在中控台的屏幕上显示,以扩大驾驶员视野。借助360°全景视图泊车辅助系统,驾驶员坐在车中即可直观地看到车辆周围是否存在障碍物以及障碍物的相对方位与距离,以便在狭窄拥堵的停车场从容操控车辆泊车入位或通过复杂的路面,可有效防止刮蹭、碰撞、陷落等事故的发生。同时,全景视图也可以为自动驾驶系统中识别、检测、跟踪等算法提供支持。

效果图

拼接前:

拼接后:

实现原理

相机透视变换

由于汽车环视相机安装一般是斜向下的角度,因此原始相机输出的图像并不是俯视图(这里我们假定相机输入环视拼接模块的图像是已经经过去畸变矫正的图像)。因此要达到鸟瞰图的效果,相机输出的图像必须需要经过投影到新的俯视视角,如下图所示:

比如使用手机拍摄身份证时会发生一些畸变,利用证件照修复工具会修正成正常的形状,这个过程就是透视变换的典型应用,如下图所示:

透视变换重要的一点是找出原坐标系与新坐标系的转换矩阵,以上图为例,我们知道原图的四个顶点坐标以及转换后的顶点坐标,然后带入转换方程求解便可以求解出转换矩阵。

进行相机标定和透视变换

联合标定

单个相机可以通过透视变换完成视角的转换,需要做的工作是:

①确定转换后的坐标
②将四个相机投影到一个坐标系
标定chart的摆放位置需要保证相邻的两个chart都可以看到斜对角,典型的摆放位置如下图所示:

已知要输出拼接后鸟瞰图大小,并且已经预设好标定板对应斜对角的(Xm, Ym)在鸟瞰图中的位置,那么对应的四个环视相机看到的两个chart投影后的位置便已经知道了,然后又知道棋盘格斜对角的原始坐标在图像中的位置,我们就可以求出投影矩阵。以前环视为例,其标定示例如下图所示,上面是相机输出的去畸变图像,下图是预设好的的鸟瞰图坐标系:

同理,其余三个相机的投影矩阵也可以这样求出。然后再将变换后的图像投影到鸟瞰图中即可。

图像投影拼接问题

在四个环视投影矩阵求解完毕之后,我们便可以将四个环视相机的图像进行投影输出,但在不同相机投影到同一个平面时就会出现两个问题:

①由于校正和投影的误差,在拼接后会有明显的重影现象。(白色是重叠区域,灰色是单个不重叠区域)

解决方法:提取投影图中的重叠部分
灰度化并二值化
用形态学操作去掉噪点,得到了重叠区域的一个完整 mask
将front, left 图像各自位于重叠区域外部的边界检测出来,把 front 相机减去重叠区域后的轮廓记作 polyA (左上图中蓝色边界),left 相机减去重叠区域后的轮廓记作 polyB (右上图中绿色边界)。
对重叠区域中的每个像素,计算其到这两个多边形的距离,即如果这个像素落在 front 画面内,则它与 polyB 的距离就更远,从而权值更大。
对不在重叠区域内的像素,若其属于 front 相机的范围则其权值为 1,否则权值为 0。于是我们得到了一个连续变化的,取值范围在 0~1 之间的矩阵 G,其灰度图如下:

将 G 作为权值可得融合后的图像为

front * G + (1- G) * left

由于重叠区域中的像素值是来自两幅图像的加权平均,所以出现在这个区域内的物体会不可避免出现虚影的现象,所以我们需要尽量压缩重叠区域的范围,尽可能只对拼接缝周围的像素计算权值,拼接缝上方的像素尽量使用来自
front
的原像素,拼接缝下方的像素尽量使用来自
back
的原像素。这一步可以通过控制 dB 的值得到。

②由于不同相机处于不同的环境中,亮度、色温、灯光等环境也有差异,四个环视相机在不同的区域会出现亮度以及颜色的差异,视觉效果看起来亮度不一致。我们需要分区调整每个区域的亮度,使得整个拼接图像的亮度趋于一致。

代码:awb_and_lum_banlance() 进行自动白平衡和亮度均衡处理:

做法:分别对4路相机图像进行处理,对于图像中的每个像素,对其蓝、绿、红三个通道的像素值分别应用增益调整,对每个通道进行加权和求平均来计算亮度来进行色彩平衡。

过亮的通道要调暗一些所以乘的系数小于 1,过暗的通道要调亮一些所以乘的系数大于 1(权重可以根据效果调节)。


class MultiBufferManager(object):
    ...
    def sync(self, device_id):
        # only perform sync if enabled for specified device/stream
        self.mutex.lock()
        if device_id in self.sync_devices:
            # increment arrived count
            self.arrived += 1
            # we are the last to arrive: wake all waiting threads
            if self.do_sync and self.arrived == len(self.sync_devices):
                self.wc.wakeAll()
            # still waiting for other streams to arrive: wait
            else:
                self.wc.wait(self.mutex)
            # decrement arrived count
            self.arrived -= 1
        self.mutex.unlock()  

相机输出的图像对应存储数组的顺序:

合并图像:

由于相邻相机之间有重叠的区域,所以这部分的融合很关键。如果直接采取两幅图像加权平均 (权重各自为 1/2) 的方式融合的话,相邻相机在重合区域的投影结果并不能完全吻合,拼接的结果出现乱码和重影。

根据摄像头名称把去畸变后的图像的特定区域 复制到输出图像的目标区域。(分别对每路摄像头进行处理)对于前面的摄像头,把它放到输出图像的上半区域,对于右边的摄像头,放到图像的右侧区域.....

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号