分割质量好不好,预处理占一半。
16-bit归一化、高斯滤波、中值滤波、CLAHE增强------五步流水线,一步都不能少。
一、为什么需要预处理
BSE电镜图像的常见问题:
| 问题 | 影响 |
|---|---|
| 位深不一致 | 8-bit或16-bit混用,分割算法只认8-bit |
| 噪声干扰 | 电子噪声导致颗粒感,影响分割精度 |
| 对比度不足 | 各相灰度差异小,Otsu找不到最优阈值 |
| 格式多样 | 灰度、彩色、带Alpha通道,需统一 |
二、预处理流水线
text
原始图像 → 位深归一化 → 灰度化 → 高斯滤波 → 中值滤波 → CLAHE增强 → 输出
| 步骤 | 作用 | 关键参数 |
|---|---|---|
| 位深归一化 | 统一为8-bit | 16-bit除以256 |
| 灰度化 | 单通道 | COLOR_BGR2GRAY |
| 高斯滤波 | 抑制高斯噪声 | 5×5核 |
| 中值滤波 | 去除椒盐噪点 | 3×3核 |
| CLAHE | 增强局部对比度 | clipLimit=2.0 |
三、完整代码
python
import cv2
import numpy as np
def safe_imread(img_path, flags=cv2.IMREAD_UNCHANGED):
try:
img = cv2.imread(img_path, flags)
if img is not None:
return img
except:
pass
try:
with open(img_path, 'rb') as f:
data = f.read()
img_array = np.frombuffer(data, np.uint8)
img = cv2.imdecode(img_array, flags)
return img
except Exception as e:
print(f"Error reading image: {e}")
return None
def preprocess_image(img_path):
img = safe_imread(img_path, cv2.IMREAD_UNCHANGED)
# 位深归一化
if img.dtype == np.uint16:
img = (img / 256).astype(np.uint8)
elif img.dtype != np.uint8:
img = img.astype(np.uint8)
# 灰度化
if len(img.shape) == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 高斯滤波
blurred = cv2.GaussianBlur(img, (5, 5), 0)
# 中值滤波
denoised = cv2.medianBlur(blurred, 3)
# CLAHE增强
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
equalized = clahe.apply(denoised)
return equalized
四、各步骤详解
位深归一化
python
if img.dtype == np.uint16:
img = (img / 256).astype(np.uint8)
策略:除以256(而非65535/255),直接取高字节,计算更快。
灰度化
python
if len(img.shape) == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
Otsu分割只需要单通道,多通道无意义。
高斯滤波(5×5)
python
blurred = cv2.GaussianBlur(img, (5, 5), 0)
为什么选5×5:3×3太弱,7×7太强,5×5是平衡点。
中值滤波(3×3)
python
denoised = cv2.medianBlur(blurred, 3)
为什么先高斯再中值:先抑制连续噪声,再去除孤立噪点。顺序颠倒效果变差。
CLAHE增强
python
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
equalized = clahe.apply(denoised)
| 参数 | 本项目值 | 说明 |
|---|---|---|
| clipLimit | 2.0 | 对比度限制,越大对比度越强 |
| tileGridSize | (8, 8) | 分块大小 |
五、调参指南
| 问题 | 调整 |
|---|---|
| 噪声很大 | 高斯核(7,7)或中值核5 |
| 对比度太低 | clipLimit=3.0 |
| 明暗不均 | tileGridSize=(4,4) |
下篇预告
下一篇写多级Otsu分割算法详解:从二值Otsu扩展到多级分割,递归阈值搜索。