4、图像预处理:图像灰度化、直方图均衡化、高斯滤波、中值滤波、边缘检测
各位同学,咱们今天聊聊图像预处理。这步活儿,说白了就是给原始图像“洗把脸”,让它能更好地被后续算法识别。
我做了这么多年机器视觉,发现一个规律:很多项目最后跑不通,问题往往出在预处理阶段。你想想看,一张满是噪点的图,再牛的算法也白搭。所以,别小看这几个基础操作。
4.1 图像灰度化
工业相机拍出来的,大多是彩色图像。但咱们做视觉检测时,颜色信息很多时候是多余的。灰度化,就是把三通道的彩色图,转成单通道的灰度图。
为什么要这么做?
- 减少计算量:三通道变一通道,数据量直接降到原来的三分之一。
- 去除冗余信息:很多特征(边缘、纹理)在灰度空间里就足够表达了。
- 提高鲁棒性:光照变化对灰度图的影响,比彩色图小得多。
常用的灰度化方法有三种:
| 方法 | 公式 | 特点 |
|---|---|---|
| 最大值法 | Gray = max(R, G, B) | 亮度偏高,细节丢失 |
| 平均值法 | Gray = (R + G + B) / 3 | 均衡,但不够自然 |
| 加权平均法 | Gray = 0.299R + 0.587G + 0.114B | 符合人眼感知,最常用 |
我个人习惯用加权平均法。OpenCV里直接调用 cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 就行。不过要注意,OpenCV默认是BGR顺序,别搞反了。
核心代码:
import cv2
img = cv2.imread('input.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite('gray.jpg', gray)
4.2 直方图均衡化
你有没有遇到过这种情况?一张图拍出来,整体偏暗或者偏亮,细节根本看不清。这就是图像对比度太低了。
直方图均衡化,就是用来解决这个问题的。它把像素值的分布“拉伸”开,让暗的地方更暗,亮的地方更亮,中间层次更丰富。
我在项目中遇到过一件事:一个产线上的字符识别项目,因为环境光不均匀,字符总是识别错。后来加了直方图均衡化,识别率直接从70%飙到了95%。
实现起来也很简单:
import cv2
img = cv2.imread('dark.jpg', 0) # 以灰度图读入
equ = cv2.equalizeHist(img)
cv2.imwrite('equ.jpg', equ)
小技巧:如果图像局部光照不均,可以用自适应直方图均衡化(CLAHE)。它能避免整体均衡化带来的噪声放大问题。
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
4.3 高斯滤波
图像里的噪声,就像脸上的痘痘,得想办法去掉。高斯滤波就是最常用的“磨皮”工具。
它的原理很简单:用一个高斯核(权重矩阵)去卷积整张图像。中心像素的权重最大,越往边缘权重越小。这样既能平滑噪声,又能保留边缘信息。
嗯,这里要注意:高斯核的大小和标准差σ,直接影响滤波效果。
- 核越大:平滑效果越强,但细节丢失也越多。
- σ越大:权重分布越平缓,平滑效果越强。
我建议:对于一般的工业图像,用5×5的核,σ=1.0就够用了。
import cv2
img = cv2.imread('noisy.jpg')
blur = cv2.GaussianBlur(img, (5, 5), 1.0)
cv2.imwrite('gaussian.jpg', blur)
避坑指南:我曾经在一个项目中,为了去噪把高斯核设成了15×15。结果噪声是没了,但边缘也糊了,导致后续的边缘检测完全失效。记住:滤波不是越强越好,够用就行。
4.4 中值滤波
高斯滤波对付高斯噪声很有效,但遇到椒盐噪声(黑白点)就有点力不从心了。这时候,中值滤波就派上用场了。
中值滤波的原理更简单:把窗口内的像素值排序,取中间值作为输出。这样一来,那些孤立的噪声点(特别亮或特别暗)就会被直接剔除。
你想想看,一个3×3的窗口里,如果有一个白点(255),其他都是正常值(100左右),排序后中间值肯定还是100左右。白点就被干掉了。
中值滤波的核大小也很有讲究:
| 核大小 | 适用场景 |
|---|---|
| 3×3 | 轻度噪声,细节保留好 |
| 5×5 | 中度噪声,常用 |
| 7×7及以上 | 重度噪声,但边缘会变圆滑 |
import cv2
img = cv2.imread('salt_pepper.jpg')
median = cv2.medianBlur(img, 5)
cv2.imwrite('median.jpg', median)
实战经验:在工业现场,如果相机传感器老化或者传输线缆有干扰,经常会出现椒盐噪声。我一般先用中值滤波处理一遍,再用高斯滤波做二次平滑。效果比单独用一种好得多。
4.5 边缘检测
好了,前面做了那么多预处理,最终目的往往是为了提取特征。而边缘,就是图像中最基本、最重要的特征。
边缘检测的算法很多,但工业界最常用的还是Canny算子。它为什么这么受欢迎?因为它把边缘检测做成了一个完整的流程:
- 高斯滤波:先平滑,去除噪声。
- 计算梯度:用Sobel算子算出每个像素的梯度幅值和方向。
- 非极大值抑制:只保留梯度方向上的局部最大值,让边缘变细。
- 双阈值检测:用高低两个阈值,确定哪些是强边缘、弱边缘和非边缘。
- 边缘连接:只保留与强边缘相连的弱边缘。
说白了,Canny就是一套“组合拳”,每一步都经过精心设计。
使用Canny时,最重要的参数就是两个阈值:
- 低阈值:低于这个值的,直接丢弃。
- 高阈值:高于这个值的,确定为强边缘。
我个人的经验是:高阈值设为低阈值的2-3倍。比如低阈值50,高阈值150。这个比例在大多数场景下都适用。
import cv2
img = cv2.imread('processed.jpg', 0)
edges = cv2.Canny(img, 50, 150)
cv2.imwrite('edges.jpg', edges)
调试技巧:如果你不确定阈值设多少合适,可以用滑动条动态调整。OpenCV里可以用 cv2.createTrackbar() 实现。我每次做新项目,都会先跑一遍滑动条调试,找到最佳阈值再固化到代码里。
小结
图像预处理这五个步骤,是机器视觉的基石。灰度化降维、直方图均衡化增强对比度、高斯滤波去噪、中值滤波去椒盐噪声、Canny边缘检测提取特征——每一步都有它的用武之地。
最后送大家一句话:预处理做得好,后续算法跑得稳。别急着上深度学习,先把这些基本功练扎实了。
下一章,咱们聊聊特征提取与匹配,看看怎么从边缘信息里找到我们想要的目标。