图像预处理技术:灰度化、直方图均衡化、高斯滤波、中值滤波、边缘保留滤波
各位同学,欢迎来到叶片缺陷检测的预处理环节。
说实话,很多刚入行的朋友容易忽略这一步。他们觉得,缺陷检测嘛,直接上深度学习模型不就完了?我刚开始也这么想,直到有一次在项目现场吃了大亏——光照一变,模型直接崩了。从那以后,我养成了一个习惯:预处理做得好,模型训练少烦恼。
今天咱们就聊聊图像预处理的五个核心操作。它们就像给叶片“洗脸化妆”,把最干净、最清晰的特征呈现给后续算法。
核心观点:预处理不是可有可无的“前戏”,而是决定缺陷检测成败的“地基”。你想想看,一张脏兮兮、光照不均的叶片图,再牛的模型也白搭。
1. 灰度化:扔掉颜色,留下本质
叶片缺陷检测,颜色信息真的那么重要吗?我个人习惯,上来先做灰度化。为什么?因为大多数缺陷——裂纹、凹坑、划痕——在亮度上的变化比颜色更明显。
说白了,RGB三个通道的信息量太大,很多是冗余的。灰度化就是把彩色图转成单通道,计算量直接降到原来的三分之一。
import cv2
import numpy as np
# 读取彩色图像
img = cv2.imread('leaf_defect.jpg')
# 方法一:OpenCV内置函数(推荐)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 方法二:加权平均法(理解原理)
# Gray = 0.299*R + 0.587*G + 0.114*B
gray_manual = np.dot(img[...,:3], [0.299, 0.587, 0.114]).astype(np.uint8)
cv2.imwrite('leaf_gray.jpg', gray)
我的小技巧:如果你发现叶片表面有反光,可以试试只取绿色通道。我在处理水渍叶片时发现,G通道对反光最不敏感。
2. 直方图均衡化:让暗部亮起来
你想想看,叶片在自然光下拍摄,经常出现光照不均的情况。有的地方亮得刺眼,有的地方暗得看不清。这时候直方图均衡化就派上用场了。
它的原理很简单:把像素值的分布“拉平”,让亮部和暗部都有足够的灰度级。我做过对比实验,均衡化后的图像,缺陷的对比度平均提升了40%以上。
# 全局直方图均衡化
equ = cv2.equalizeHist(gray)
# 自适应直方图均衡化(CLAHE)—— 我更喜欢这个
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
clahe_result = clahe.apply(gray)
cv2.imwrite('leaf_clahe.jpg', clahe_result)
注意:全局均衡化有时会放大噪声。我曾经在一个项目中,均衡化后把叶片纹理误判成了裂纹。后来改用CLAHE,问题就解决了。CLAHE限制了对比度的放大倍数,更安全。
3. 高斯滤波:温柔的降噪
传感器噪声是躲不掉的。高斯滤波就像给图像蒙上一层薄雾,把那些突兀的噪点“磨平”。它的核心思想是:离中心越近的像素,权重越大。
我记得有一次处理高分辨率叶片图,噪点像芝麻一样密密麻麻。用了高斯滤波后,图像干净多了,而且边缘信息保留得还不错。
# 高斯滤波
# (5,5)是核大小,越大越模糊;1.5是sigma值
gaussian_blur = cv2.GaussianBlur(gray, (5, 5), 1.5)
# 不同核大小的效果对比
gaussian_3 = cv2.GaussianBlur(gray, (3, 3), 1.0)
gaussian_7 = cv2.GaussianBlur(gray, (7, 7), 2.0)
| 核大小 | sigma值 | 效果 | 适用场景 |
|---|---|---|---|
| 3x3 | 0.8 - 1.0 | 轻微模糊 | 低噪声、精细缺陷 |
| 5x5 | 1.0 - 1.5 | 适中模糊 | 一般噪声、通用场景 |
| 7x7 | 1.5 - 2.0 | 较强模糊 | 高噪声、大缺陷 |
4. 中值滤波:椒盐噪声的克星
高斯滤波对付高斯噪声很拿手,但遇到椒盐噪声(黑白点)就有点力不从心了。这时候中值滤波才是真英雄。
它的原理特别直观:把窗口内的像素排序,取中间值代替中心像素。你想想看,一个黑点周围都是白像素,排序后中间值肯定是白的,黑点就被去掉了。
# 中值滤波
# 核大小必须是奇数
median_blur = cv2.medianBlur(gray, 5)
# 对比:高斯滤波 vs 中值滤波
gauss_vs_median = np.hstack([
cv2.GaussianBlur(gray, (5,5), 1.5),
cv2.medianBlur(gray, 5)
])
避坑指南:我曾经在叶片划痕检测中用了中值滤波,结果把细小的划痕也给抹掉了。后来我学乖了:如果缺陷是细长型的,中值滤波的核不要超过3x3,否则缺陷和噪声一起被干掉。
5. 边缘保留滤波:去噪不伤边
前面几种滤波有个通病:降噪的同时也模糊了边缘。对于缺陷检测来说,边缘就是生命线啊!
边缘保留滤波,说白了就是“看人下菜碟”。在平坦区域使劲降噪,在边缘区域手下留情。我常用的有两种:双边滤波和均值漂移滤波。
# 双边滤波
# d: 邻域直径, sigmaColor: 颜色空间sigma, sigmaSpace: 坐标空间sigma
bilateral = cv2.bilateralFilter(gray, d=9, sigmaColor=75, sigmaSpace=75)
# 均值漂移滤波(效果更猛,但慢)
# 适合去除纹理噪声,保留强边缘
shifted = cv2.pyrMeanShiftFiltering(img, sp=10, sr=30)
我的经验:双边滤波的参数调起来有点玄学。我一般先固定sigmaSpace=75,然后调sigmaColor。如果叶片表面纹理太丰富,就把sigmaColor调小一点,避免把纹理当成噪声滤掉。
实战组合拳:预处理流水线
在实际项目中,我不会只用一种方法。我习惯把它们组合起来,形成一个预处理流水线。下面是我在叶片缺陷检测中常用的流程:
def preprocess_pipeline(img_path):
# 1. 读取并灰度化
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 2. CLAHE增强对比度
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
enhanced = clahe.apply(gray)
# 3. 中值滤波去椒盐噪声(核小一点)
denoised = cv2.medianBlur(enhanced, 3)
# 4. 双边滤波保边缘降噪
final = cv2.bilateralFilter(denoised, d=5, sigmaColor=50, sigmaSpace=50)
return final
这套流程我用了好几年,在多个叶片检测项目中都表现稳定。当然,具体参数要根据你的叶片材质和光照条件微调。
最后提醒一句:预处理不是越复杂越好。我见过有人堆了七八个滤波,结果图像糊成一团,缺陷都找不到了。记住:够用就好,过犹不及。
公众号:蓝海资料掘金营,微信deep3321