3. 图像采集与预处理
图像采集,是整个视觉检测流程的起点。说白了,你算法再牛,如果源头数据就出了问题,后面全是白搭。我见过太多项目,花了大把时间调模型,最后发现是相机没配好,或者图像格式搞错了。
这一节,我们就来聊聊从相机SDK调用到图像预处理的完整链路。嗯,都是实战中绕不开的硬骨头。
3.1 相机SDK调用:与硬件对话的第一步
工业相机不像手机摄像头,插上就能用。你得通过厂商提供的SDK(软件开发工具包)来跟它通信。国内用得最多的就是海康威视和大华的相机。
我个人习惯,先把SDK的初始化流程理清楚。不管哪家,核心步骤都差不多:
- 枚举设备:找到所有连接的相机。
- 创建句柄:建立与相机的连接通道。
- 打开设备:激活相机。
- 设置参数:曝光、增益、帧率等。
- 开始采集:启动图像流。
- 获取图像:从缓冲区取一帧数据。
- 停止采集 & 关闭设备:释放资源。
下面是一个海康SDK调用的简化示例,我把它封装成了一个类,方便复用:
#include "MvCameraControl.h"
class HikCamera {
public:
bool Init() {
// 枚举设备
MV_CC_DEVICE_INFO_LIST stDeviceList;
MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
if (stDeviceList.nDeviceNum == 0) {
printf("没有找到相机!\n");
return false;
}
// 创建句柄并打开设备
MV_CC_CreateHandle(&handle_, stDeviceList.pDeviceInfo[0]);
MV_CC_OpenDevice(handle_);
return true;
}
bool GrabImage(cv::Mat &img) {
unsigned char *pData = nullptr;
MV_FRAME_OUT_INFO_EX stInfo;
// 获取一帧图像数据
MV_CC_GetOneFrameTimeout(handle_, pData, &stInfo, 1000);
// 转换为OpenCV Mat格式
img = cv::Mat(stInfo.nHeight, stInfo.nWidth, CV_8UC3, pData).clone();
return true;
}
void Close() {
MV_CC_StopGrabbing(handle_);
MV_CC_CloseDevice(handle_);
MV_CC_DestroyHandle(handle_);
}
private:
void *handle_ = nullptr;
};
MV_CC_StartGrabbing(),结果一直拿不到图像,排查了半天。另外,记得在程序退出前释放所有资源,否则下次可能无法打开相机。
3.2 图像格式转换:BGR、RGB与Gray
相机采集到的原始数据,通常是Bayer格式(拜耳阵列),需要经过ISP(图像信号处理)转换成我们熟悉的RGB或BGR。而OpenCV默认使用BGR顺序,这一点跟很多其他库(比如PIL、matplotlib)不一样。
为什么会这样? 历史原因。早期Windows的BMP格式就是BGR,OpenCV沿用了这个习惯。所以你在用OpenCV显示图像时,如果发现颜色不对,十有八九是通道顺序搞反了。
转换其实很简单,用OpenCV的 cvtColor 函数就行:
cv::Mat bgr_img, rgb_img, gray_img;
// BGR 转 RGB
cv::cvtColor(bgr_img, rgb_img, cv::COLOR_BGR2RGB);
// BGR 转 灰度图
cv::cvtColor(bgr_img, gray_img, cv::COLOR_BGR2GRAY);
// RGB 转 BGR
cv::cvtColor(rgb_img, bgr_img, cv::COLOR_RGB2BGR);
你想想看,如果模型训练时用的是RGB数据,而你推理时喂进去的是BGR,那结果肯定一塌糊涂。所以,务必确认你的数据流中通道顺序的一致性。
3.3 图像滤波:去噪与保边
工业现场环境复杂,图像难免会有噪声。滤波的目的就是去除这些噪声,同时尽量保留图像的边缘和细节。常用的有三种:高斯滤波、中值滤波和双边滤波。
| 滤波类型 | 原理 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 高斯滤波 | 用高斯核的加权平均 | 高斯噪声(传感器热噪声) | 平滑效果好,速度快 | 会模糊边缘 |
| 中值滤波 | 用邻域像素的中值代替 | 椒盐噪声(脉冲噪声) | 保边效果好,对椒盐噪声极佳 | 对高斯噪声效果一般 |
| 双边滤波 | 同时考虑空间距离和像素值差异 | 需要保边去噪的场景 | 保边效果最好 | 计算量大,速度慢 |
代码实现也很直接:
cv::Mat src, dst;
// 高斯滤波,核大小5x5,sigma=1.5
cv::GaussianBlur(src, dst, cv::Size(5, 5), 1.5);
// 中值滤波,核大小5x5
cv::medianBlur(src, dst, 5);
// 双边滤波,d=9,sigmaColor=75,sigmaSpace=75
cv::bilateralFilter(src, dst, 9, 75, 75);
3.4 知识体系总览
下面这张图,把图像采集与预处理的核心流程串起来了。你可以把它当作一个检查清单,每次搭建视觉系统时,对照着走一遍。
嗯,到这里,图像采集与预处理的核心内容就讲完了。从相机SDK的调用,到格式转换,再到滤波去噪,每一步都有坑,但也都有对应的解法。记住,好的开始是成功的一半,把源头数据处理好,后面的算法工作会轻松很多。