第一章 双目视觉基础
各位同学好,我是老张。在无人机领域摸爬滚打了十来年,今天咱们来聊聊双目视觉在定高中的应用。说实话,双目视觉这东西,刚接触时觉得挺玄乎,但说白了就是给无人机装上一双「眼睛」,让它能感知深度。
1.1 双目视觉原理
双目视觉的原理,其实跟人眼差不多。你想想看,我们为什么能判断距离?因为两只眼睛看到的画面有细微差别,大脑通过这个差别算出深度。无人机也是一样——左右两个摄像头同时拍摄,通过计算两幅图像中对应点的位置差异,就能得到深度信息。
我刚开始做这个项目时,总觉得原理简单,但实际落地时坑不少。比如两个摄像头的光轴必须严格平行,否则算出来的深度全是错的。嗯,这里要注意,硬件安装的精度直接影响后续算法效果。
核心公式:深度 Z = (f × B) / d
其中 f 是焦距,B 是基线距离(两个摄像头中心距离),d 是视差。
1.2 视差与深度关系
视差,说白了就是同一个物体在左右两张图像上的像素位置差。物体越近,视差越大;物体越远,视差越小。这个关系是反比,不是线性的。
我记得有一次在户外测试,无人机飞到10米高度时,视差变化非常敏感,稍微抖动一下,深度值就跳得厉害。后来我加了个中值滤波,才把数据稳住。
| 物体距离(米) | 视差(像素) | 深度误差(米) |
|---|---|---|
| 1 | 120 | 0.02 |
| 5 | 24 | 0.15 |
| 10 | 12 | 0.60 |
| 20 | 6 | 2.40 |
从表格能看出来,距离越远,深度误差越大。所以双目视觉在近距定高(10米以内)效果很好,再远就得靠其他传感器辅助了。
1.3 相机模型与标定基础
相机模型,我用的是经典的针孔模型。说白了就是三维空间中的点,通过小孔成像映射到二维图像平面上。这里面涉及内参(焦距、主点坐标)和外参(旋转、平移矩阵)。
标定这一步,我建议你认真做。我曾经偷懒用出厂参数,结果飞起来高度偏差半米多,差点炸机。标定的核心就是拍棋盘格,用OpenCV的calibrateCamera函数算参数。
import cv2
import numpy as np
# 准备棋盘格角点
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
objp = np.zeros((6*9, 3), np.float32)
objp[:,:2] = np.mgrid[0:9, 0:6].T.reshape(-1, 2)
# 收集图像
objpoints = [] # 世界坐标系中的点
imgpoints = [] # 图像坐标系中的点
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)
if ret:
objpoints.append(objp)
corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)
imgpoints.append(corners2)
# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print("内参矩阵:\n", mtx)
个人经验:标定时要拍20-30张不同角度的棋盘格,覆盖整个视野。我习惯在自然光下拍,避免反光。标定完一定要验证——用标定好的参数去矫正一张图,看看直线是不是真的直了。
1.4 知识体系总览
下面这张图,是我自己总结的双目视觉定高知识框架。你把它存下来,后面每章都会用到。
避坑指南:我曾经在强光环境下测试,结果图像过曝导致匹配失败。后来加了自动曝光控制,才解决这个问题。另外,两个摄像头的增益必须一致,否则左右图像亮度不同,匹配精度会下降。
好了,第一章的内容就到这里。双目视觉的基础打牢了,后面讲立体匹配和深度计算时你才能跟得上。记住,标定是第一步,也是最重要的一步——标定做不好,后面全是白费功夫。