这次比opencv快⑥倍!!!
共 1751字,需浏览 4分钟
·
2022-05-20 09:06
上回书说道,我用汇编+neon实现去畸变算法比opencv快3倍,这都不算啥,这次新增了透视变换算法,二者加起来比opencv快6倍!拭目以待吧。
啥玩意是透视变换?
相信你们都开过高级亿点的车吧,(姑且认为你们都开过)现在车上都有360全景倒车影像。你难道没有奇怪过吗?我车顶上又没装摄像头,怎么来的鸟瞰图?效果是这样式的:
数学基础
我们假使知道像素平面上的一点,那么我们根据透视变换矩阵就可以得到透视变换后的一点。
其中(x,y)是像素平面内的原始点,(X,Y,Z)是透视变换后的一点。那么如何求透视变换矩阵A呢?
上式是一个从二维空间到三维空间的转换,因此我们将上式展开并将(X,Y,Z)除以Z坐标得:
其中(X’,Y’)是透视变换后像素坐标系下的点。令a33=1(a33表示缩放,这里我们不缩放),然后展开得:
我们从图像上找到4对点,如图1.2-1所示,透视变换即将原图上某一坐标点的像素移动到我们想要的坐标上去。比方说A点移动到A’点,BCD点同理。那么我们就将一张一般视角的图片转换为了鸟瞰图。
图1.2-1 透视变换坐标点选取
根据上面选择出来的4对点,代入公式1.2-3中可以得到8个方程,如式1.2-4所示。其中有8个未知量,那么刚好可以求解。
对非齐次线性方程组的求解,也即对系数矩阵求逆,然后用系数矩阵的逆乘以常数项即可得未知数a11-a32,也即求得转换矩阵A。
式1.2-1是已知原图上的一点求透视变换图上的一点。但是我们在编码过程中往往都是对目标图像,这里即透视变换图像进行坐标遍历,然后将原图上对应的像素拷贝过来。那么我们只需将转换矩阵求逆。然后用转换矩阵的逆乘以目的图像的坐标,即可得原图的坐标。矩阵展开可得方程式,方便编程。
OPENCV透视变换实现
opencv透视变换比较简单,只需给定原点和目标点,使用函数getPerspectiveTransform()即可获取转换矩阵。然后再调用warpPerspective()函数即可进行透视变换的操作。关键点在于4对点的选择。
图2-1 opencv透视变换
透视变换的C代码实现
图3-1 C语言实现透视变换
C语言实现透视变换中,主要涉及矩阵的求逆和矩阵的乘法运算。获取映射表的过程和去畸变算法中类似,利用公式将透视变换图像中的坐标点对应的原图坐标点保存下来。最后就是查表remap的过程,查表和去畸变算法中完全相同。
透视变换和去畸变相结合
在opencv中,去畸变和透视变换是相互独立的函数,需要先做去畸变再做透视变换,程序流程如下:
图4-1 opencv去畸变、透视变换流程
在C语言实现去畸变时,我们注意到,去畸变和透视变换最后一步查表的过程完全相同,只是表中的数据不同,那么我们能否将两张表合二为一,这样在查表时还是只需一步。
图4-2 去畸变和透视变换合并计算演示
如图4-2所示,我们假定非畸变图像像素(3,2)对应畸变图像像素坐标(3,3),那么在去畸变映射表中坐标(3,2)保存数据就是(3,3)。同理,透视变换映射表中坐标(1,1)保存的是非畸变图像坐标(3,2)。那么可得,透视变换映射表中(1,1)保存的是畸变图像坐标(3,3)。这样我们只需在计算完非畸变图像映射表后再利用其值计算透视变换映射表即可。代码如下:
其中mapping_table中存储的是计算好的去畸变映射表,mapping_table_warp是透视变换映射表,也即从畸变图像到鸟瞰图的映射表。最后将mapping_table_warp拷贝到输出。
图4-3 利用去畸变映射表生成透视变换映射表
opencv和自写算法速度对比
图5-1 opencv和自写算法速度对比
如图5-1所示,img_process为opencv和自写C语言算法对比。两者均处理1000张640×480图片,opencv耗时42秒,自写C语言算法耗时76秒。img_process_neon为neon加速结果。可以看到加速后的算法,速度相对自身提升了1000%以上,相对opencv提升600%以上。