图像预处理是计算机视觉任务(如目标检测、图像分割、人脸识别)的基础步骤,核心目的是消除图像中的噪声、提升对比度、修正几何畸变等,为后续高阶处理提供高质量输入。以下先系统梳理经典算法,再通过Python实现2个高频应用算法(直方图均衡化、中值滤波)。
一、图像预处理经典算法梳理
根据处理目标,可将经典算法分为5大类,每类包含核心算法、原理、目的及应用场景:
1. 几何变换类(修正空间畸变)
针对图像的空间位置或形状偏差,调整像素坐标以满足后续对齐、裁剪等需求。
算法 | 原理 | 核心目的 | 应用场景 |
---|---|---|---|
平移 | 对所有像素按指定偏移量(dx, dy)移动,公式:(x’, y’) = (x+dx, y+dy) | 调整图像位置 | 图像拼接、目标定位校准 |
旋转 | 以某点(如中心)为原点,按角度θ旋转,需处理像素插值避免模糊 | 修正图像倾斜 | 文档扫描(矫正倾斜文字) |
缩放 | 按比例(fx, fy)放大/缩小像素,常用双线性插值提升画质 | 统一图像尺寸 | 神经网络输入标准化(如224x224) |
翻转 | 水平翻转(左右镜像)或垂直翻转(上下镜像) | 数据增强、修正视角 | 人脸识别(增加样本多样性) |
2. 图像增强类(提升视觉质量)
通过调整像素灰度/颜色分布,增强图像的细节对比度,解决低光照、模糊等问题。
算法 | 原理 | 核心目的 | 应用场景 |
---|---|---|---|
全局直方图均衡化 | 拉伸像素灰度分布,使直方图趋于均匀(映射灰度累积概率) | 提升整体对比度 | 医学图像(如X光片)、低光照片 |
CLAHE(自适应直方图均衡化) | 将图像分块,对每块单独均衡化,限制对比度避免过增强 | 增强局部细节(如暗区) | 逆光照片、监控图像 |
伽马校正 | 通过幂函数(O = I^γ)调整灰度:γ<1提亮,γ>1压暗 | 修正光照不均 | 显示器校准、水下图像增强 |
对比度拉伸(线性变换) | 线性映射灰度范围:O = a*I + b(a>1增强对比度,a<1降低) | 扩展有效灰度区间 | 灰度范围狭窄的图像(如雾天图) |
3. 图像去噪类(消除干扰像素)
针对图像采集过程中的噪声(如椒盐噪声、高斯噪声),通过邻域像素平滑实现去噪。
算法 | 原理 | 核心目的 | 应用场景 |
---|---|---|---|
均值滤波 | 用邻域内所有像素的平均值替换中心像素 | 消除高斯噪声 | 轻微模糊的自然图像 |
中值滤波 | 用邻域内像素的中值替换中心像素 | 消除椒盐噪声(脉冲噪声) | 老照片、传感器噪声图像 |
高斯滤波 | 用高斯核(权重随距离递减)加权平均邻域像素 | 平滑图像、保留细节 | 预处理(如边缘检测前去噪) |
双边滤波 | 结合空间距离(邻域权重)和灰度相似度(避免模糊边缘)加权平均 | 去噪+保留边缘 | 人像美颜、纹理保留 |
4. 颜色空间转换(适配任务需求)
将图像从默认的RGB空间转换为其他空间,简化后续处理(如分离亮度与色彩)。
转换方向 | 原理 | 核心目的 | 应用场景 |
---|---|---|---|
RGB → 灰度 | 加权平均RGB通道:Gray = 0.299R + 0.587G + 0.114B(符合人眼感知) | 减少维度(3→1) | 灰度图像任务(如文字识别) |
RGB → HSV | 分离色调(H)、饱和度(S)、亮度(V)通道 | 单独调整亮度/色彩 | 图像增强、色彩分割 |
RGB → YCrCb | 分离亮度(Y)与色差(Cr/Cb)通道 | 视频压缩、肤色检测 | 人脸识别(肤色区域提取) |
5. 阈值处理(二值化分割)
将灰度图转换为二值图(仅黑白两色),突出目标区域。
算法 | 原理 | 核心目的 | 应用场景 |
---|---|---|---|
全局阈值 | 用固定阈值T分割:I>T设为255(白),否则设为0(黑)(如Otsu自动选T) | 简单目标分割 | 文字提取、硬币检测 |
自适应阈值 | 按局部区域动态计算阈值(如邻域均值) | 处理光照不均图像 | 文档扫描(文字与背景分离) |
二、Python实现经典算法(2个高频案例)
以下基于 OpenCV(图像处理库) 和 Matplotlib(图像显示库) 实现,需先安装依赖:
pip install opencv-python numpy matplotlib
案例1:直方图均衡化(全局+CLAHE)
需求:提升低对比度图像的细节(如逆光照片),对比全局均衡化与CLAHE的效果差异。
实现步骤:
- 加载图像并转换为灰度图(均衡化通常在单通道上进行);
- 实现全局直方图均衡化;
- 实现CLAHE(自适应均衡化);
- 显示原图、全局均衡化图、CLAHE图及对应直方图。
代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 1. 加载图像(以灰度模式读取,0表示灰度)
img = cv2.imread("low_contrast_image.jpg", 0) # 替换为你的图像路径
if img is None:
raise ValueError("图像加载失败,请检查路径是否正确!")
# 2. 全局直方图均衡化
global_eq = cv2.equalizeHist(img)
# 3. CLAHE(自适应直方图均衡化)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) # clipLimit限制对比度,tileGridSize分块大小
clahe_eq = clahe.apply(img)
# 4. 计算各图像的直方图(用于对比)
def calculate_histogram(image):
hist = cv2.calcHist([image], [0], None, [256], [0, 256])
return hist / hist.sum() # 归一化,便于显示
hist_original = calculate_histogram(img)
hist_global = calculate_histogram(global_eq)
hist_clahe = calculate_histogram(clahe_eq)
# 5. 显示结果(Matplotlib默认RGB,灰度图直接显示)
plt.figure(figsize=(15, 10))
# 图像显示
plt.subplot(2, 3, 1)
plt.imshow(img, cmap="gray")
plt.title("原图")
plt.axis("off")
plt.subplot(2, 3, 2)
plt.imshow(global_eq, cmap="gray")
plt.title("全局直方图均衡化")
plt.axis("off")
plt.subplot(2, 3, 3)
plt.imshow(clahe_eq, cmap="gray")
plt.title("CLAHE(自适应均衡化)")
plt.axis("off")
# 直方图显示
plt.subplot(2, 3, 4)
plt.plot(hist_original, color="black")
plt.title("原图直方图")
plt.xlabel("灰度值")
plt.ylabel("概率密度")
plt.subplot(2, 3, 5)
plt.plot(hist_global, color="black")
plt.title("全局均衡化直方图")
plt.xlabel("灰度值")
plt.subplot(2, 3, 6)
plt.plot(hist_clahe, color="black")
plt.title("CLAHE直方图")
plt.xlabel("灰度值")
plt.tight_layout()
plt.show()
结果分析:
- 全局均衡化:整体对比度提升,但可能导致局部过亮(如天空区域泛白);
- CLAHE:通过分块均衡化,在提升暗区细节(如建筑阴影)的同时,避免过增强,效果更自然。
案例2:中值滤波(消除椒盐噪声)
需求:去除图像中的椒盐噪声(随机黑白斑点),对比原图与去噪后的效果。
实现步骤:
- 加载灰度图并手动添加椒盐噪声(模拟真实噪声场景);
- 用中值滤波处理噪声图像;
- 对比原图、噪声图、去噪图。
代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 1. 加载灰度图像
img = cv2.imread("lena.jpg", 0) # 替换为你的图像路径(如经典Lena图)
if img is None:
raise ValueError("图像加载失败,请检查路径是否正确!")
# 2. 手动添加椒盐噪声(噪声比例:10%)
def add_salt_pepper_noise(image, noise_ratio=0.1):
h, w = image.shape
noise_img = image.copy()
# 计算噪声像素数量
noise_pixels = int(h * w * noise_ratio)
# 添加盐噪声(白色斑点,灰度255)
for _ in range(noise_pixels // 2):
x = np.random.randint(0, w)
y = np.random.randint(0, h)
noise_img[y, x] = 255
# 添加椒噪声(黑色斑点,灰度0)
for _ in range(noise_pixels // 2):
x = np.random.randint(0, w)
y = np.random.randint(0, h)
noise_img[y, x] = 0
return noise_img
noise_img = add_salt_pepper_noise(img, noise_ratio=0.1)
# 3. 中值滤波处理(核大小为3x3,需为奇数)
median_filtered = cv2.medianBlur(noise_img, ksize=3) # ksize可调整为5、7(核越大去噪越强,但细节越模糊)
# 4. 显示结果
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.imshow(img, cmap="gray")
plt.title("原图")
plt.axis("off")
plt.subplot(1, 3, 2)
plt.imshow(noise_img, cmap="gray")
plt.title("添加椒盐噪声(10%)")
plt.axis("off")
plt.subplot(1, 3, 3)
plt.imshow(median_filtered, cmap="gray")
plt.title("中值滤波(3x3核)")
plt.axis("off")
plt.tight_layout()
plt.show()
结果分析:
- 噪声图:出现明显的黑白斑点(椒盐噪声),细节被掩盖;
- 中值滤波后:大部分噪声被消除,图像细节(如面部轮廓、眼睛)保留较好,这是因为中值对脉冲噪声的抑制效果优于均值滤波。
三、总结
图像预处理算法的选择需结合具体任务和图像问题:
- 若图像对比度低:优先用CLAHE(优于全局均衡化);
- 若图像有椒盐噪声:优先用中值滤波(核大小根据噪声强度调整);
- 若需统一图像尺寸:用缩放(双线性插值);
- 若需分离亮度与色彩:将RGB转为HSV或YCrCb。
上述实现的2个算法是工业界最常用的预处理步骤,可直接集成到目标检测、图像分割等 pipeline 中,提升后续模型的精度。