深度图转点云(2)—再略微优化了下
最近回过头优化以前写的代码,还是不少地方能好好捯饬捯饬加快点速度
这段之前写成博客的深度图转点云的代码就是其中一个

由于B站文章投稿只能修改三次,而之前那篇已经因为改错字用光了次数
所以新开一篇写写
新代码:
修改的是初始化的时候会用到的get_depth_vector()这个函数

用jyupyter notebook来测试的话,之前的函数用时将近7秒 而新函数用时0.5秒
校验两个函数的得到的数据是否一致


旧算法
整体的流程并没有改变,这里只重新简单地说一下
已知一个像素点(u,v)的深度值depth的情况下
点从画面坐标系到相机坐标系可以用[u,v,depth]乘以相机内参矩阵的逆矩阵

然后为了更快连续地计算多张深度图,我们假设有一张深度图,所有像素的深度值都为1
用循环计算其中所有像素的结果, 也就是遍历图片的像素坐标(u,v),反复用[u,v,1]乘以相机的逆矩阵 保存得到的三维坐标[x,y,1]
这时得到的[x,y,1]可以看成是一个方向向量
因为两点确定一条直线
光心以及像素点两点确定了一个方向,所以无论depth值为多少,点都应该在这个方向上
有了所有像素点的方向向量数组以后,只需要将新来的深度图的depth乘以数组,便可以得到点云数组
而旧的get_depth_vector()函数就遍历所有像素点的方式在计算方向向量

新算法
代码中为了计算方便和速度,一直用了矩阵来计算变换
而画面坐标到相机坐标系的变换也可以写成以下形式,其中cx cy为光心坐标,fx fy为焦距,这些都包含在相机内参矩阵中
z = depth
x = (u - cx) * z / fx
y = (v - cy) * z / fy
以x为例,在计算图像中所有像素点的时候 式子右边cx fx是固定值 u和z是变量
但由于我们计算假设所有像素点的深度值都为1,所以这时变量只剩下了 u
u图像分辨率的宽,以代码中的分辨率(960,720)的情况
那么 变量u 就是 0-959 的960个整数
那么可知 相应的结果 x 也应该只有 960种 ,对应着960个u
同理 y应该只有720种 结果 对应着 720个v的量
所以我们并不需要遍历一张图像上的所有像素坐标,只需要计算出0~959 的u以及0~719的v的结果 然后将他们按照顺序组合起来,便可以得到同之前一样的结果
当然,具体的实现为了计算速度 还是采用了矩阵计算的形式
首先根据图像的分辨率我们构建代表长宽的竖数组和横横数组
为了保存结果[x,y,1] ,第三个维度为3
注意这里两个数组的长度都暂时为 u,因为u>v 为了下一步计算的方便暂且都设置成大的这个数
接着遍历0~959 ,通过[u,v,1]乘以相机逆矩阵得到对应的 x 和y ,存入刚才的两个数组的对应位置中
为了计算方便我们一并计算了960个y值,但是实际上只有720个 所以队v_vector进行切片取前720
接着对竖数组,此时为 720*1*3的v_vector,竖着复制960列
对横数组,1*960*3的u_vector, 横着复制720行
复制之后两者的shape都为 720*960*3
接着只要直接将两组数据相乘,便可得到和旧函数一样的结果
此时 对应每个像素点上都会 [x,1,1] * [1,y,1] = [x,y,1]
如此一来 ,从之前遍历所有点 (720*960个点) 进行[u,v,1]乘以相机矩阵逆计算的步骤
变成了现在只计算960次再通过numpy的复制 ,乘法融合 得到相同的结果