2. 去除模糊图像
任务说明
在AI训练数据集中,模糊图像会引入噪声标签,降低模型收敛速度与最终精度。本案例实现一个基于拉普拉斯方差(Variance of Laplacian)的模糊图像过滤器:输入一批图像路径,输出清晰图像列表与模糊图像列表,并将模糊图像移入指定目录,完成数据清洗。
实现原理
拉普拉斯算子对图像二阶求导,可突出边缘与纹理区域。清晰图像包含丰富的高频细节,其拉普拉斯响应方差较大;模糊图像高频分量少,方差较小。通过设定阈值即可区分清晰与模糊图像。本实现使用OpenCV的cv2.Laplacian计算灰度图的拉普拉斯响应,再求方差作为清晰度评分。
代码实现
import cv2
import os
import shutil
import numpy as np
from pathlib import Path
def compute_laplacian_variance(image_path):
"""计算单张图像的拉普拉斯方差(清晰度评分)"""
img = cv2.imread(str(image_path))
if img is None:
raise ValueError(f"无法读取图像: {image_path}")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# ksize=3 使用3x3拉普拉斯核
laplacian = cv2.Laplacian(gray, cv2.CV_64F, ksize=3)
return laplacian.var()
def filter_blurry_images(input_dir, output_clear_dir, output_blurry_dir, threshold=100.0):
"""
过滤模糊图像
参数:
input_dir: 原始图像目录
output_clear_dir: 清晰图像输出目录
output_blurry_dir: 模糊图像输出目录
threshold: 拉普拉斯方差阈值,低于该值判定为模糊
返回:
(清晰图像列表, 模糊图像列表, 各图像评分字典)
"""
# 创建输出目录
Path(output_clear_dir).mkdir(parents=True, exist_ok=True)
Path(output_blurry_dir).mkdir(parents=True, exist_ok=True)
# 支持的图像扩展名
valid_ext = {'.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp'}
clear_images = []
blurry_images = []
scores = {}
# 遍历输入目录中的所有图像
for img_path in Path(input_dir).iterdir():
if img_path.suffix.lower() not in valid_ext:
continue
# 计算清晰度评分
score = compute_laplacian_variance(img_path)
scores[img_path.name] = score
# 根据阈值分类并移动文件
if score >= threshold:
dest = Path(output_clear_dir) / img_path.name
shutil.move(str(img_path), str(dest))
clear_images.append(dest.name)
else:
dest = Path(output_blurry_dir) / img_path.name
shutil.move(str(img_path), str(dest))
blurry_images.append(dest.name)
return clear_images, blurry_images, scores
if __name__ == "__main__":
# 使用示例:请根据实际路径修改
input_dir = "./raw_images" # 待清洗的原始图像目录
clear_dir = "./cleared_images" # 清洗后清晰图像目录
blurry_dir = "./blurry_images" # 被过滤的模糊图像目录
# 执行过滤,阈值设为100.0(可根据数据分布调整)
clear_list, blurry_list, score_dict = filter_blurry_images(
input_dir, clear_dir, blurry_dir, threshold=100.0
)
# 打印统计信息
print(f"清晰图像数量: {len(clear_list)}")
print(f"模糊图像数量: {len(blurry_list)}")
print("\n各图像清晰度评分:")
for name, score in sorted(score_dict.items(), key=lambda x: x[1]):
status = "清晰" if score >= 100.0 else "模糊"
print(f" {name}: {score:.2f} -> {status}")
落地与运行
依赖安装:
pip install opencv-python numpy
运行步骤:
- 创建目录结构:
raw_images(存放待清洗图像)、cleared_images、blurry_images(后两个可自动创建); - 将待清洗图像放入
raw_images目录; - 按需调整代码末尾的
input_dir路径与threshold阈值; - 执行脚本:
python blur_filter.py。
验证方法与判定标准
功能验证:
- 运行脚本后,检查
cleared_images与blurry_images目录是否已生成,且原raw_images目录中的图像已被移走; - 控制台输出的清晰/模糊图像数量之和应等于输入图像总数;
- 随机打开两个目录中的图像,目视确认清晰目录中无明显模糊图像,模糊目录中图像确实模糊。
阈值调优验证:
- 若清晰图像被误判为模糊,可降低阈值(如50.0);若模糊图像未被过滤,可提高阈值(如150.0);
- 观察输出的评分列表,找到清晰与模糊图像评分的分界值,据此设置合理阈值。
判定标准:脚本无报错执行完毕;输出统计数量与输入一致;两个输出目录中的图像内容与分类结果相符,即达到本案例目标。
数据流与判定逻辑
上图展示了本案例的数据处理流水线:图像从输入目录读取后,经拉普拉斯方差计算得到清晰度评分,再与阈值比较,最终分别落入清晰或模糊输出目录。评分列表同时输出,便于人工复核与阈值调整。