4. 相机模型与图像预处理
视觉感知链路的第一道“关口”不是检测网络,而是相机模型与预处理。无人机上的相机把三维世界投影成二维像素,后续所有定位、测距、避障、跟踪都建立在这个投影关系之上。如果模型参数不准、畸变未校正、颜色空间选错或滤波过度,后面的算法再强也会被系统性误差拖垮。本节围绕针孔模型、内参外参、去畸变、颜色空间、滤波增强以及实时预处理策略展开,目标是让读者能独立完成一次可复现的相机标定与预处理配置。
针孔模型:三维到二维的投影约定
针孔模型把相机简化为一个光心和一个成像平面。设相机坐标系下一点 P_c = (X_c, Y_c, Z_c),归一化平面坐标为 x = X_c / Z_c、y = Y_c / Z_c,再经内参矩阵 K 映射到像素坐标:
u = fx * (X_c / Z_c) + cx
v = fy * (Y_c / Z_c) + cy
K = [ fx 0 cx
0 fy cy
0 0 1 ]
其中 fx、fy 是以像素为单位的焦距,cx、cy 是主点。这里必须明确坐标系约定:本文统一采用“相机坐标系 Z 轴指向相机前方、X 向右、Y 向下”的右手系,像素坐标原点在图像左上角。若使用其他约定(如 Y 向上),内参和外参的符号会变化,全文与图示必须保持一致。
针孔模型是理想线性模型,实际镜头存在径向畸变和切向畸变。径向畸变由 k1、k2、k3 描述,切向畸变由 p1、p2 描述。去畸变就是把观测到的畸变像素 (u_d, v_d) 还原为理想像素 (u, v),常用迭代法或查表法实现。
内参与外参:标定与坐标变换
内参描述相机自身属性,外参描述相机在世界坐标系中的位姿。世界点 P_w 到像素的完整投影为:
s * [u, v, 1]^T = K * [R | t] * [X_w, Y_w, Z_w, 1]^T
其中 R 为 3×3 旋转矩阵,t 为 3×1 平移向量,s 为尺度因子。标定内参通常使用棋盘格,采集 15~25 张不同角度图像,用张正友标定法求解。教学示例中,某 640×480 相机标定结果可假设为 fx = 520.3、fy = 519.8、cx = 318.6、cy = 241.2,畸变系数 k1 = -0.28、k2 = 0.09、p1 = 0.001、p2 = -0.002。这些数值仅为示例,实际应以标定输出为准。
判断标定质量看重投影误差,一般要求平均误差小于 0.5 像素,最大误差小于 1.0 像素。若误差偏大,优先检查棋盘格是否平整、图像是否模糊、角点是否被遮挡,而不是盲目增加图片数量。
去畸变:从畸变像素到理想像素
去畸变的本质是建立一张映射表。对输出图像每个理想像素 (u, v),先归一化得到 x = (u - cx) / fx、y = (v - cy) / fy,再计算畸变后的归一化坐标:
r² = x² + y²
x_d = x * (1 + k1*r² + k2*r⁴ + k3*r⁶) + 2*p1*x*y + p2*(r² + 2*x²)
y_d = y * (1 + k1*r² + k2*r⁴ + k3*r⁶) + p1*(r² + 2*y²) + 2*p2*x*y
u_d = fx * x_d + cx
v_d = fy * y_d + cy
由于 (u_d, v_d) 通常不是整数,需要用双线性插值从原始图像取值。工程上更常用 cv2.initUndistortRectifyMap 预计算映射表,再用 cv2.remap 逐帧查表,避免每帧重复计算畸变模型。对于 640×480 图像,预计算映射表约 1.2 MB,查表耗时通常低于 2 ms,适合机载实时运行。
颜色空间:按任务选择而不是凭习惯
OpenCV 默认读取为 BGR,而多数深度学习模型期望 RGB。颜色空间选择直接影响检测稳定性:
- RGB/BGR:适合深度学习输入、颜色还原要求高的场景。
- 灰度:适合光流、边缘、特征点提取,数据量降为 1/3,速度提升明显。
- HSV:适合颜色阈值分割,如红色目标检测。H 分量对光照变化更鲁棒,但需注意 OpenCV 中 H 范围为 0~179。
- YUV/YCbCr:适合硬件编码与低功耗传输,Y 通道可直接用于灰度处理。
教学示例:检测橙色降落标志时,可先转 HSV,再取 H ∈ [10, 25]、S ∈ [100, 255]、V ∈ [100, 255] 做掩膜。若直接对 BGR 做阈值,光照变化下误检率会明显上升。
滤波与增强:抑制噪声但保留结构
飞行视觉的噪声来源包括传感器热噪声、低照度增益噪声、运动模糊和压缩伪影。滤波策略要按噪声类型选择:
- 高斯滤波:抑制高斯噪声,但会模糊边缘,适合预处理降噪。
- 中值滤波:抑制椒盐噪声,保留边缘,适合低照度图像。
- 双边滤波:保边降噪,但计算量大,机载需谨慎使用。
- 直方图均衡/CLAHE:提升低对比度图像,CLAHE 限制对比度避免噪声放大。
- 锐化:增强边缘,但会放大噪声,通常在降噪后使用。
一个可复现的示例配置:对 640×480 灰度图先做 cv2.medianBlur(img, 3),再做 cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)),最后用 cv2.GaussianBlur(img, (3,3), 0)。该组合在低照度下能明显提升特征点数量,同时控制噪声。
面向飞行视觉的实时预处理策略
机载算力有限,预处理必须做“减法”。建议按以下优先级组织:
- 分辨率降采样:将 1080p 降为 640×480 或 320×240,帧率可提升 2~4 倍。
- ROI 裁剪:只处理图像下半部或目标可能出现的区域,减少 50% 以上计算量。
- 灰度化优先:光流、特征点、边缘任务直接使用灰度,避免不必要的颜色转换。
- 映射表预计算:去畸变映射表在初始化时生成,运行时只做 remap。
- 流水线并行:采集、去畸变、颜色转换、滤波分线程或分流水级,隐藏延迟。
- 按需增强:仅在图像质量指标(如平均梯度、特征点数量)低于阈值时启用 CLAHE 或锐化。
把上述环节串起来,一次完整的飞行视觉预处理流程可以概括为:采集原始 BGR 图像 → 预计算映射表去畸变 → 按任务转灰度或 HSV → 中值/高斯降噪 → 按需 CLAHE 增强 → 降采样或 ROI 裁剪 → 送入感知算法。每一步都应有明确的输入输出和耗时预算,才能保证在振动、光照变化和算力受限的飞行环境中稳定运行。