在嵌入式视觉和机器人领域,测距是一个绕不开的核心需求。无论是避障、定位,还是简单的物体检测,视觉传感器都能通过图像信息直接或间接地计算出距离。很多人以为视觉测距必须依赖昂贵的深度相机或激光雷达,但其实只要掌握了几种核心的视觉测距代码逻辑,普通的单目或双目摄像头同样能实现厘米级的测距精度。
我们从最基础的代码实现开始,一步步拆解视觉传感器测距的底层原理与实战技巧。
我们要明确视觉测距的两种主流方式:单目测距和双目测距。单目测距通常依赖于已知的物体尺寸或地面平面假设,通过小孔成像模型和相似三角形原理来计算距离。如果你知道一个目标物体的实际高度(例如一个0.5米高的交通锥),那么在图像中检测到它的像素高度后,就可以通过相机的焦距和像素尺寸反推出距离。下面是一段简化的单目测距Python代码示例,基于OpenCV:
``python
import cv2
import numpy as np
假设相机内参(焦距f,单位像素)
focal_length = 800 示例值,需实际标定
known_height = 0.5 物体实际高度(米)
def estimate_distance(object_pixel_height):
distance = (known_height focal_length) / object_pixel_height
return distance
在图像中检测物体并获取其像素高度(此处为示意)
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
假设通过YOLO或颜色检测找到物体,并得到其像素高度为200像素
pixel_height = 200 示例值
dist = estimate_distance(pixel_height)
print(f"估计距离: {dist:.2f} 米")
cv2.imshow('Frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
`
这段代码看似简单,但实际部署时核心难点在于相机内参的精确标定,以及物体检测的鲁棒性。如果使用一个固定尺寸的标定板(如棋盘格),通过OpenCV的cv2.calibrateCamera()函数可以获取更准确的焦距和畸变参数。
接下来是双目视觉测距。双目测距的优势在于不需要知道物体先验尺寸,完全依靠左右相机图像的视差来计算深度。其核心代码逻辑基于立体匹配算法,例如SGBM(半全局块匹配)。以下是双目测距的一个基础实现:
`python
import cv2
import numpy as np
加载左右图像
img_left = cv2.imread('left.jpg', 0)
img_right = cv2.imread('right.jpg', 0)
设置SGBM参数
stereo = cv2.StereoSGBM_create(minDisparity=0, numDisparities=165, blockSize=11)
disparity = stereo.compute(img_left, img_right).astype(np.float32) / 16.0
视差转深度:深度 = (基线长度 焦距) / 视差
baseline = 0.1 相机基线(米)
focal_length_px = 800 像素焦距
depth_map = np.where(disparity > 0, (baseline focal_length_px) / disparity, 0)
print("深度图生成成功,单位:米")
此处可进一步对深度图进行滤波、可视化等操作
`
但要注意,直接使用OpenCV的默认参数往往会导致深度图噪声极大。优化方向包括:调整numDisparities和blockSize,对左右图像进行极线校正,以及对输出视差图进行WLS滤波(加权最小二乘滤波)。实际项目中,我推荐使用cv2.ximgproc.createDisparityWLSFilter`来平滑结果,能显著提升测距精度。
我们要讨论一个容易忽略的点:视觉传感器的选型与场景适配。对于室内短距离测距(0.3-5米),双目视觉效果极佳;对于户外远距离(10米以上),单目结合已知尺寸的标定物反而更稳定。光线变化、纹理缺失都会影响匹配效果,因此在实际代码中一定要加入图像预处理(如直方图均衡化、高斯模糊)来增强鲁棒性。
总结一下视觉传感器测距代码的关键:先标定相机,再选择合适的测