2、计算机视觉基础:图像表示、颜色空间、图像滤波与边缘检测

各位同学,欢迎来到第二讲。今天我们要聊的,是计算机视觉最底层的三块基石:图像怎么存、颜色怎么算、特征怎么提。

说实话,我刚开始接触CV时,觉得这些基础概念太枯燥了。直到有一次做工业检测项目,摄像头拍出来的零件边缘总是模糊,我折腾了三天才发现是颜色空间转换出了问题。嗯,从那以后我再也不敢小看这些基础了。

2.1 图像的数字表示

一张图像在计算机眼里是什么?说白了,就是一个巨大的数字矩阵。

我们平时看到的彩色照片,在计算机内存里就是三个二维数组叠在一起。每个数组代表一个颜色通道,每个格子里的数字就是像素值,范围从0到255。

举个例子,一张640×480的彩色图像,它的形状就是(480, 640, 3)。480行,640列,3个通道。每个像素点需要8位来存储,也就是1个字节。所以这张图占用的内存大约是:

480 × 640 × 3 = 921,600 字节 ≈ 0.88 MB

你想想看,一张普通照片就快1MB了。要是做视频实时检测,每秒30帧,那数据量可就大了去了。这也是为什么我们做目标检测时,经常要先做图像压缩和降采样。

关键概念:图像分辨率 = 宽度 × 高度 × 通道数。通道数决定了图像是灰度图(1通道)还是彩色图(3通道)。

2.2 颜色空间

颜色空间,说白了就是描述颜色的数学方法。不同的场景用不同的颜色空间,效果天差地别。

2.2.1 RGB 颜色空间

这是最常用的,也是摄像头直接输出的格式。红绿蓝三原色,每个通道0-255。但我在项目中遇到过一个问题:RGB对光照变化特别敏感。同一个物体,换个灯光,RGB值就全变了。做目标检测时,这很要命。

2.2.2 HSV 颜色空间

我个人习惯在做颜色分割时用HSV。它把颜色拆成色调(H)、饱和度(S)、明度(V)。

为什么要用HSV?举个例子,你想检测画面中的红色物体。在RGB空间里,红色可能是(200,30,30),也可能是(180,20,20)。光照一变,阈值就不好设了。但在HSV空间里,红色的H值基本稳定在0-10度之间,你只需要固定H的范围,S和V稍微放宽点就行。

颜色空间 适用场景 我的经验
RGB 图像显示、存储 直接拿来用,但别做颜色分析
HSV 颜色分割、目标跟踪 做交通灯检测时特别好用
灰度 边缘检测、特征提取 减少计算量,保留形状信息

小技巧:用OpenCV做颜色空间转换时,注意H的范围是0-179,不是0-359。我刚开始就踩过这个坑,调了半天阈值都不对。

2.3 图像滤波

滤波,说白了就是去噪。摄像头拍出来的图像,多少都有点噪点。直接做边缘检测,结果会惨不忍睹。

2.3.1 均值滤波

最简单的滤波方式。取一个3×3的窗口,把9个像素的平均值赋给中心点。效果嘛,平滑了,但也模糊了。

# 均值滤波示例
kernel = np.ones((3,3), np.float32) / 9
filtered = cv2.filter2D(img, -1, kernel)

2.3.2 高斯滤波

这个我用的最多。它给窗口内的像素分配不同的权重,离中心越近权重越大。效果比均值滤波好很多,能保留更多边缘信息。

我记得有一次做车牌识别,图像噪点很多。用均值滤波后,车牌字符边缘都糊了。换成高斯滤波,效果立竿见影。

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

2.3.3 中值滤波

对付椒盐噪声的神器。它取窗口内所有像素的中位数,而不是平均值。这样那些孤立的噪点就被直接干掉了。

避坑指南:我曾经在工业检测项目里,直接用高斯滤波处理有大量椒盐噪声的图像,结果边缘检测出来全是假边缘。后来换成中值滤波,问题就解决了。记住:噪声类型决定滤波方式。

2.4 边缘检测

边缘,是图像中像素值发生剧烈变化的地方。说白了,就是物体的轮廓。做目标检测,边缘信息是第一步。

2.4.1 梯度与导数

边缘检测的核心思想,就是计算图像的一阶导数。导数大的地方,就是边缘。数学上,我们用Sobel算子来计算x方向和y方向的梯度。

# Sobel边缘检测
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
magnitude = np.sqrt(sobelx**2 + sobely**2)

2.4.2 Canny边缘检测

这是目前最经典的边缘检测算法。它做了四件事:去噪、算梯度、非极大值抑制、双阈值检测。

你想想看,为什么Canny效果好?因为它不仅找到了梯度大的地方,还通过非极大值抑制把边缘细化成单像素宽,再用双阈值过滤掉那些假的边缘。

# Canny边缘检测
edges = cv2.Canny(img, 50, 150)

这里的50和150是低阈值和高阈值。我个人的经验是:低阈值设30-50,高阈值设100-150。具体数值要根据图像对比度来调。对比度高的图,阈值可以设大点。

实战建议:做实时目标检测时,别一上来就用Canny。先做高斯滤波,再做Canny,效果会好很多。我见过太多人直接拿原始图做边缘检测,结果全是噪点。

2.5 小结

这一章的内容,说白了就是三件事:图像怎么存(矩阵)、颜色怎么表示(颜色空间)、特征怎么提(滤波+边缘检测)。

这些基础看似简单,但做项目时处处都是坑。我建议你动手写代码试试:拿一张自己的照片,分别用RGB和HSV做颜色分割,看看效果差异。再试试不同滤波方式对边缘检测的影响。

下一章,我们会聊特征点检测与匹配。那是目标跟踪和三维重建的基础。嗯,到时候再细聊。

课后练习:用OpenCV读取一张图片,依次做高斯滤波、Canny边缘检测,然后显示结果。试试调整Canny的阈值,观察边缘的变化。