使用通用摄像头和低功率激光拍摄的照片计算距离
项目描述
# laser-range-finder 使用通用摄像头和低功率激光拍摄的照片计算距离
# 概述
此包实现了一个Python类,该类根据相机拍摄的两个图像计算距离,其中一张图像包含与相机焦平面平行的激光线投影,另一张图像则没有激光投影。
此方法与[此处](https://sites.google.com/site/todddanko/home/webcam_laser_ranger)中描述的方法非常相似,尽管它已被扩展到应用于一条线而不是单个点。
# 安装
推荐通过pip安装(最好在虚拟环境中进行)
pip install 激光测距仪
# 使用
在使用此类之前,您需要校准您的相机。计算您的相机的
垂直视场角度(以度为单位)
水平视场角度(以度为单位)
相机中心和激光中心之间的距离(以毫米为单位)
弧度偏移量
然后,在实例化类时传递这些值
from laser_range_finder import LaserRangeFinder lrf = LaserRangeFinder(vert_fov_deg=50, horz_fov_deg=40, ro=0.01, h=30)
该包对图像的捕获方式无特定要求,但假设您可以将它们作为文件名或PIL Image实例提供
distances = lrf.get_distance(off_img='~/laser-off.png', on_img='~/laser-on.png')
由get_distance()返回的值将是一个长度与源图像像素宽度相等的列表,每个元素都是从相机到估计距离的毫米值。值为-1表示无法在相关列中获取可靠的距离测量值。
如果您不需要每像素距离测量的精确度,而只是想要对图像中N个块的距离进行更一般的估计,那么您可以将这些距离传递给函数 compress_list(lst, bins)
from laser_range_finder.utils import compress_list distances = lrf.get_distance(off_img=’~/laser-off.png’, on_img=’~/laser-on.png’) distances = compress_list(distances, bins=10)
# 方法
该方法假设我们有两个图像,一个是已知不包含激光线的参考图像A,另一个是肯定包含激光线但可能变形的图像B。我们可能只需使用包含激光线的单个图像,但具有负图像可以帮助我们去除噪声。因此,我们开始以下样本图像
 
注意两张图像之间的亮度差异很大。稍后,我们想要通过找到两张图像之间的差异来隔离激光线,但这种整体亮度的差异将干扰这一点。因此,我们使用 utils.normalize() 来解决这个问题,得到
 
由于这些图像是RGB格式,但激光是红色的,我们通过使用 utils.only_red() 移除蓝色和绿色通道来去除一些噪声,得到
 
现在我们计算图像之间的差异。如果图像之间的唯一变化是激光线,那么结果图像应该是完全黑色的,激光线以亮白色出现。在实践中,仍然会有相当多的噪声,但差异将消除大部分噪声,得到

最后,我们对激光线的位置做出“最佳猜测”。由于我们知道线将大致水平,并且激光线现在应对应于图像中最亮的像素,我们扫描每一列,找到最亮的像素所在的行,得到

注意估计非常接近,但仍有噪声,主要在图像的左侧,激光线被亚光黑色表面吸收的地方。我们通过计算线的平均亮度和标准差亮度来解决此问题,忽略任何小于 mean - stddev 的内容,得到

这消除了很多噪声,但请注意,图像的左上角仍有少量噪声。对于这种设置,激光位于相机下方,这意味着线永远不会出现在中间行以上。因此,我们可以假设任何在中间行以上的激光线像素都是噪声。这给我们最终的图像,几乎完美地检测到激光投影

然后我们可以使用一点三角学将白色像素相对于中间行的偏移量转换为激光投影的物理距离。
作为参考,本例中使用的源图像是用5MP无红外相机捕获的,该相机连接到Raspberry Pi 2和一个1mW 3V红色激光二极管,该二极管从相机距离22.5mm,并直接从Raspberry Pi GPIO引脚控制。
# 测试
要运行测试
tox
或
py.test -s