4. 图像预处理技术:去噪算法、图像增强与归一化处理
各位工程师朋友,大家好。我是你们的老朋友,一个在晶圆制造缺陷分析领域摸爬滚打了十几年的老兵。今天咱们来聊聊图像预处理。说白了,这就是给晶圆缺陷图像“洗把脸”,让它更清楚地暴露问题。
你想想看,从SEM或者光学显微镜下拍回来的原始图像,往往带着各种噪声,对比度也不理想。直接拿去做缺陷识别,结果肯定一塌糊涂。我刚开始做这个项目时,就吃过这个亏——图像没处理好,模型训练出来全是“幻觉”,把灰尘当成了划痕。嗯,从那以后,我养成了一个习惯:预处理做不好,绝不往下走。
4.1 去噪算法:把“雪花”和“椒盐”赶走
晶圆图像里的噪声,主要来自电子元器件的热噪声、光照不均匀,还有传感器本身的瑕疵。常见的去噪算法有三种,我一个个说。
4.1.1 高斯滤波
高斯滤波,说白了就是“加权平均”。它用一个高斯核(一个中间大、边缘小的权重矩阵)去卷积整张图像。每个像素的新值,由它周围像素的加权平均决定。
我个人习惯用 cv2.GaussianBlur()。核心参数就两个:核大小(必须是奇数)和标准差σ。σ越大,图像越模糊,去噪效果越强,但细节丢失也越严重。
import cv2
import numpy as np
# 读取图像
img = cv2.imread('wafer_defect.png', 0) # 灰度图
# 高斯滤波,核大小5x5,标准差1.5
gaussian_blur = cv2.GaussianBlur(img, (5, 5), 1.5)
cv2.imshow('Original', img)
cv2.imshow('Gaussian Blur', gaussian_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.1.2 中值滤波
中值滤波,对付“椒盐噪声”(黑白点)特别管用。它的原理很简单:把窗口内的像素值排序,取中间值作为新像素值。这样,那些孤立的噪声点就被“剔除”了。
我在项目中遇到过一种情况:晶圆边缘有大量随机出现的亮点(椒盐噪声),用高斯滤波根本去不掉,换成中值滤波,一次搞定。
# 中值滤波,核大小3x3
median_blur = cv2.medianBlur(img, 3)
cv2.imshow('Median Blur', median_blur)
4.1.3 双边滤波
双边滤波,是“保边去噪”的高手。它同时考虑了空间距离和像素值差异。什么意思呢?就是离得近、颜色又相似的像素,权重高;离得远或者颜色差异大的,权重低。这样,噪声被平滑了,但边缘(比如划痕的边界)被保留了下来。
嗯,这里要注意:双边滤波的计算量比较大,处理高分辨率晶圆图像时,速度会慢一些。我一般只在需要精细保留边缘特征时才用它。
# 双边滤波,d=9,sigmaColor=75,sigmaSpace=75
bilateral = cv2.bilateralFilter(img, 9, 75, 75)
cv2.imshow('Bilateral Filter', bilateral)
- 高斯滤波: 速度快,适合高斯噪声,但会模糊边缘。
- 中值滤波: 去椒盐噪声神器,边缘保留比高斯好。
- 双边滤波: 保边去噪效果最好,但计算慢,参数调起来麻烦。
4.2 图像增强:让缺陷“浮出水面”
去噪之后,图像干净了,但可能对比度不够。比如,一个浅划痕在灰蒙蒙的背景上,肉眼都看不清。这时候就需要图像增强。
4.2.1 直方图均衡化
直方图均衡化,说白了就是把图像的灰度分布“拉平”。原本集中在某个小范围的灰度值,被拉伸到整个0-255区间。这样,暗的地方变亮,亮的地方变暗,细节就出来了。
我记得有一次处理一张晶圆边缘的缺陷图,背景太暗,缺陷几乎看不见。用了直方图均衡化之后,缺陷轮廓一下子就清晰了。
# 全局直方图均衡化
equ = cv2.equalizeHist(img)
cv2.imshow('Histogram Equalization', equ)
# 自适应直方图均衡化(CLAHE)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
clahe_img = clahe.apply(img)
cv2.imshow('CLAHE', clahe_img)
4.2.2 对比度拉伸
对比度拉伸,更直接。它把图像中最低的灰度值映射到0,最高的映射到255,中间的线性拉伸。你可以手动指定拉伸的范围,比如只拉伸灰度值在50-200之间的部分。
我建议在做对比度拉伸前,先看看图像的直方图。如果直方图集中在某个小区域,拉伸效果会非常明显。
# 手动对比度拉伸
def contrast_stretch(img, low=50, high=200):
stretched = np.clip((img - low) * (255.0 / (high - low)), 0, 255)
return stretched.astype(np.uint8)
stretched_img = contrast_stretch(img, 50, 200)
cv2.imshow('Contrast Stretched', stretched_img)
- 图像整体偏暗或偏亮,且直方图分布较窄 → 直方图均衡化。
- 图像局部对比度不足,且噪声较多 → CLAHE。
- 你知道缺陷的灰度范围,想突出特定区域 → 对比度拉伸。
4.3 归一化处理:让数据“规规矩矩”
归一化,就是把像素值统一映射到一个固定的范围,比如0到1,或者-1到1。为什么要做这个?因为后续的机器学习模型(比如CNN)对输入数据的尺度很敏感。如果一张图的像素值在0-255,另一张在100-200,模型会学得很吃力。
我常用的归一化方法有两种:
- Min-Max归一化: 把像素值线性映射到[0,1]区间。公式很简单:
(x - min) / (max - min)。 - Z-score标准化: 让数据均值为0,标准差为1。公式:
(x - mean) / std。这种方法对异常值不那么敏感。
# Min-Max归一化到[0,1]
normalized_img = img / 255.0
# Z-score标准化
mean = np.mean(img)
std = np.std(img)
zscore_img = (img - mean) / std
4.4 本章知识体系总览
为了让大家更直观地理解这些技术之间的关系,我画了一张流程图。它展示了从原始图像到预处理完成的标准流程。
这张图清晰地展示了整个流程:原始图像 → 去噪(高斯/中值/双边) → 图像增强(直方图均衡化/对比度拉伸) → 归一化。每一步都有它的作用,缺一不可。
好了,关于图像预处理技术,我就讲到这里。记住,预处理做得好,后续的缺陷识别才能事半功倍。下次见!