第二章:图像采集与预处理——摄像头选型、标定与滤波增强

各位同学,大家好。今天我们进入一个非常实战的环节——图像采集与预处理。说白了,就是解决“怎么把物理世界的光信号,变成算法能啃的数字矩阵”。

我做了这么多年视觉项目,发现一个规律:80%的跟踪失败,根源不在算法,而在前端的图像质量。你想想看,如果摄像头选错了,或者图像全是噪声,再牛的卡尔曼滤波也救不回来。所以这一章,咱们把地基打牢。

2.1 摄像头选型:别让硬件拖后腿

选摄像头,不是参数越高越好。我见过有人用工业相机拍传送带上的药瓶,结果帧率太高,数据量把工控机直接干死机了。嗯,这里要注意:选型要匹配你的应用场景

我个人习惯,先问自己三个问题:

  • 目标运动多快?——决定帧率(FPS)。一般动态追踪建议≥60fps,高速场景(如机械臂抓取)需要≥120fps。
  • 环境光线如何?——决定传感器类型。CCD适合低噪声、稳定光源;CMOS性价比高,但卷帘快门容易产生果冻效应。
  • 需要什么颜色信息?——决定彩色/黑白。很多追踪任务其实用灰度图就够了,彩色反而增加数据量。

核心参数速查表:

参数低速场景高速场景我的建议
帧率30 FPS≥120 FPS留20%余量
分辨率640×4801280×720够用就行,别贪高
快门类型卷帘快门全局快门高速必选全局
接口USB 3.0GigE / Camera LinkUSB容易掉线,工业场景慎用

💡 我曾经在一个AGV项目中,选了USB接口的摄像头。结果车子一震动,连接就松了。后来换成GigE接口,带锁紧螺丝,再也没出过问题。所以,工业环境,接口的可靠性比速度更重要

2.2 摄像头标定:把镜头畸变算回来

摄像头标定,说白了就是给镜头做“视力矫正”。任何镜头都有畸变,尤其是广角镜头。如果不标定,你测出来的目标位置全是歪的。

我常用的方法是张正友标定法。你只需要打印一张棋盘格,拍十几张不同角度的照片,就能算出内参和畸变系数。

为什么会这样?因为棋盘格的角点坐标是已知的(物理世界),而图像上的坐标是观测到的。通过两者的映射关系,就能反推出镜头的数学模型。

下面是我常用的标定代码片段(基于OpenCV):

import cv2
import numpy as np

# 准备棋盘格尺寸
chessboard_size = (9, 6)  # 内角点数量
objp = np.zeros((chessboard_size[0]*chessboard_size[1], 3), np.float32)
objp[:,:2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1,2)

# 存储所有图像的点
objpoints = []  # 3D点
imgpoints = []  # 2D点

images = [...]  # 你的标定图片列表

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)
    if ret:
        objpoints.append(objp)
        imgpoints.append(corners)

# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
    objpoints, imgpoints, gray.shape[::-1], None, None)

# 去畸变
undistorted = cv2.undistort(img, mtx, dist, None, mtx)

⚠️ 避坑指南:我曾经因为标定板没贴平,导致标定结果偏差很大。后来发现,标定板必须完全平整,哪怕有一点点弯曲,算出来的畸变系数都是错的。建议用玻璃板或铝板做底板,别用纸板。

2.3 图像滤波:去噪是预处理的第一步

图像滤波,说白了就是把图像里的“脏东西”擦掉。传感器噪声、环境干扰,都会让图像变得不干净。我常用的两种滤波:高斯滤波和中值滤波。

2.3.1 高斯滤波——平滑噪声

高斯滤波适合处理高斯噪声(比如传感器热噪声)。它的原理是用一个高斯核去卷积图像,相当于给每个像素做加权平均。

我个人习惯,核大小选3×3或5×5。太大容易把边缘也模糊掉,太小又去不掉噪声。你想想看,如果核是9×9,那一个边缘像素会被周围一大片区域平均,边缘就没了。

# 高斯滤波
blurred = cv2.GaussianBlur(image, (5, 5), 1.5)

2.3.2 中值滤波——对付椒盐噪声

中值滤波是对付椒盐噪声的利器。什么是椒盐噪声?就是图像上随机出现的白点或黑点,像撒了盐和胡椒一样。

中值滤波的原理很简单:把像素值排序,取中间值。这样,一个孤立的噪声点(极大或极小值)就会被直接剔除。我在项目中遇到过,用高斯滤波去椒盐噪声效果很差,换成中值滤波,一下就干净了。

# 中值滤波
median = cv2.medianBlur(image, 5)  # 核大小必须是奇数

经验总结:

  • 高斯噪声 → 高斯滤波
  • 椒盐噪声 → 中值滤波
  • 两者都有 → 先中值后高斯,或者用双边滤波(后面会讲)

2.4 图像增强:让目标“跳”出来

图像增强,说白了就是把对比度拉开,让目标更明显。最经典的方法就是直方图均衡化。

2.4.1 直方图均衡化

直方图均衡化,就是把图像的灰度分布“拉平”。如果一张图整体偏暗(灰度值集中在低区域),均衡化后会扩展到整个0-255范围。

为什么会这样?因为算法会重新映射灰度值,让每个灰度级的像素数量尽量相等。效果就是暗的地方变亮,亮的地方变暗,细节就出来了。

# 全局直方图均衡化
equ = cv2.equalizeHist(gray_image)

# 自适应直方图均衡化(CLAHE)——我推荐这个
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
clahe_result = clahe.apply(gray_image)

💡 我个人强烈推荐用CLAHE(自适应直方图均衡化),而不是全局均衡化。全局均衡化容易把噪声也放大,而CLAHE只在局部区域做均衡,效果更自然。我在一个夜间追踪项目中,用了CLAHE后,目标识别率从60%提升到了92%。

2.5 本章知识体系

下面这张图,是我梳理的本章核心逻辑。你可以把它当作一个检查清单:

图像采集与预处理流程 ① 摄像头选型 帧率 | 分辨率 | 接口 | 传感器类型 ② 摄像头标定 内参 | 畸变系数 | 去畸变 ③ 图像滤波 高斯滤波(高斯噪声) | 中值滤波(椒盐噪声) ④ 图像增强 直方图均衡化 | CLAHE(推荐) 关键原则 1. 选型匹配场景 2. 标定必须精准 3. 滤波先于增强 4. 增强适度即可 ⚠️ 常见错误: • 标定板不平 • 滤波核太大 • 全局均衡化 放大噪声 顺序不可颠倒:先标定 → 再滤波 → 最后增强

嗯,这一章的内容就到这里。记住一句话:预处理做得好,追踪算法事半功倍。下一章我们会讲特征提取,但前提是你得先把图像整干净了。


专注资料整理