在知乎上看到了开源ADAS-360环视拼接c++版本的代码,我改写成了cuda加速版本,实测在我一万五的笔记本上未加速前c++版本12fps,cuda加速后10000fps以上,时间基本可以忽略不计。
ADAS-360环视拼接原理地址:https://zhuanlan.zhihu.com/p/644427203
环视拼接原理详细版本:https://github.com/neozhaoliang/surround-view-system-introduction/blob/master/doc/doc.md
使用文章中的AdasSourrondView c++开源项目:https://github.com/JokerEyeAdas/AdasSourrondView/tree/main
我加速后的github地址:https://github.com/zhangyeyan/360-Surround-View-CUDA-Project
AdasSourrondView代码中是c++版本的360环视拼接,源代码有个小bug,修改下运行后可到如下图,4张原始图像环视拼接成最后一张图的效果。
front | back | left | right |
![]() | ![]() | ![]() | ![]() |
采用查表的方法对代码进行cuda加速,首先需要找到原图和输出后的图,这两张图的坐标映射关系,把这个关系存储下来,有了这个映射关系,每次做拼接时,直接将原图的坐标点搬运到输出图像中具体的位置,使用cuda去做这个查找搬运的过程速度非常快。
通过观察AdasSourrondView c++代码可以发现,代码主要是把去畸变后的四张图直接映射到四块区域,拼接处的重影断代现象使用权重文件进行加权求和,去掉重影部分。具体的原理可以参考原作者的知乎。
环视测试图片有前后左右四张图,以左图为例子,会经过如下a,b,c,d的变换,我们要找到d图到a图,每个坐标变换的关系。
我们的目标是输出4张(1600,1200,10)大小的表,每个像素点需要10个元素记录下坐标变化关系。以其中一张图为例子:
#创建一个网格坐标系
ys, xs = torch.meshgrid(torch.arange(h), torch.arange(w))
#齐次坐标
xy = torch.stack([xs + 0.5, ys + 0.5, torch.ones_like(xs)], dim=-1).float()
xy = xy @ torch.from_numpy(proj @ param.project).float().inverse().T
xy[..., :2] /= xy[..., [2]]
#将坐标值从原始图像的坐标空间映射到 -1 到 1 的范围内
xy = ((xy[..., :2] - 0.5) / torch.tensor([IW, IH]))[None] * 2 - 1
remapxy = torch.stack([torch.from_numpy(x) + 0.5, torch.from_numpy(y) + 0.5], dim=-1)
#将remapxy张量转换为形状为(1, C, H, W)的张量
output = F.grid_sample(remapxy.permute(2, 0, 1)[None], xy.float(), "bilinear", align_corners=False)[0].permute(1, 2, 0)
#将去畸变后的4张图根据M矩阵,投影到输出图的对应区域
output_coord = cv2.warpAffine(output.data.numpy(), M, dsize=(SW, SH), flags=cv2.INTER_NEAREST)
未完待续