Qt-在图片中绘制透视网格等距线,实现粗略测距

背景

在实际的生活中,我们有时需要测量某个物体相对我们的距离,但是由于缺少专业的仪器或者物体难以抵达,而难以实现,因此研究如何使用生活中常见的单目相机进行粗略的测距是很有必要的。如果应用在汽车中,它可以辅助驾驶员或者在无人车中,进行前后方车辆距离的估算;如果结合目标检测的技术,我们可以对更多感兴趣的目标进行自动测距…本文介绍在图片中绘制透视网格等距线的方法,实现对实际场景的粗略测量。

建模与分析

Qt-在图片中绘制透视网格等距线,实现粗略测距_第1张图片
如上图所示,我们可以将实际的拍摄场景抽象出来简化表示,其中点B是相机位置,它必须与地面有一定的夹角,且具有高度。O点是相机投影在地面上的点,AC是拍摄到的地面,其中C点对应图片的最下端,A点对应图片的水平中心线。从图中我们还可以得知,∠ABC是相机视角的一半,地面AC处于相机的近平面和远平面之间。
如果在地面AC之间预设若干等距线,间距为step米,可以看出它在近平面上的投影是越向上越密集的,这符合人的近大远小视觉现象。

解决方法

在提出解决方法之前,我们需要清楚需要获取哪些数据:相机的高度,与地面的角度,视角,焦距,此外还有需要自己设置的等距线间隔多少米。
在Qt中进行透视网格线的绘制,我们可以想到三种方法:

  1. 相似三角形
  2. Qt3D
  3. 矩阵QMatrix4x4

我们首先想到的是第一个方法,并且进行了尝试,在绘制出水平线之后,我们发现绘制竖直方向的线是一个很难的问题,而且以后还会遇到更难解决的问题,比如相机很可能不只有与地面的角度变化,还会有更多的姿态。因此我们需要考虑其他的方法。

后来我们想到用Qt3D绘制网格线,但是查看了一些资料之后,感觉可行性较差,存在很多问题。首先我们需要在低版本的Qt中使用网格线,需要自己配置Qt3D,其次,网格线是很简单的图形,因此使用Qt3D进行场景绘制有一种杀鸡用牛刀的感觉。此外,Qt3D显示场景的Window如何叠加到图片上,性能、效果如何都不得而知,如何绘制网格线也是一个问题。

在查看Qt3D的example时,我们注意到了QMatrix4x4这个类,我意识到Qt3D进行3维显示和操作时是使用到了这个类,目的是用矩阵对图形的点位进行计算。使用矩阵可以大大简化绘制透视网格线的难度,我们只需要关注坐标系如何变化即可,我们设定的正方形网格线经过矩阵运算,就可以得到透视网格线的坐标。

矩阵QMatrix4x4

在绘制之前,需要设置QMatrix4x4矩阵,还需要知道的是,x、y坐标系和二维的一致,增加垂直于屏幕向外的z轴。
坐标系的移动与旋转与相机的姿态变化一致,只需要注意,z轴位置的改变要在旋转之后进行,透视在最后一步进行,在z=0平面上的位移什么时候进行都可以。例如以下的代码:

QMatrix4x4 mat;      
mat.translate(200, 200, 0);     
mat.rotate(30, 1, 0, 0);    
mat.rotate(5, 0, 1, 0);     
mat.rotate(0, 0, 0, 1);     
mat.translate(0, 0, -h);    
mat.perspective(30, 16.0/9, 0.1, 1000);

经过一系列变换后,QMatrix4x4中就会产生相应的矩阵,我们用这个矩阵与原来的正方形网格点位进行计算,得到新的3D点位,最后转换到2D点位绘制即可。绘制出的网格图如果位置不正确,移动一下绘制的坐标系即可。

最后我们可以得到以下的图:
Qt-在图片中绘制透视网格等距线,实现粗略测距_第2张图片
Qt-在图片中绘制透视网格等距线,实现粗略测距_第3张图片
把它放到图片中可以得到下图,感觉很好看。
Qt-在图片中绘制透视网格等距线,实现粗略测距_第4张图片
完整的代码可以在我的github仓库中找到,欢迎学习与交流,喜欢的话可以star或者fork一下。

你可能感兴趣的:(Qt)