2. 训练数据重复样本识别与去重
任务说明
在AI训练数据集中,模糊图像会引入噪声标签,降低模型收敛速度与最终精度。本案例实现一个基于清晰度评分的图像筛选工具,使用拉普拉斯方差(Variance of Laplacian)与Tenengrad梯度两种方法计算图像清晰度,并依据阈值剔除模糊样本。
环境依赖
需要 Python 3.8+、OpenCV(opencv-python)、NumPy。安装命令:
pip install opencv-python numpy
完整实现
import cv2
import numpy as np
from pathlib import Path
def laplacian_variance(image_path):
"""拉普拉斯方差:值越小图像越模糊"""
img = cv2.imread(str(image_path), cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError(f"无法读取图像: {image_path}")
return cv2.Laplacian(img, cv2.CV_64F).var()
def tenengrad_score(image_path):
"""Tenengrad梯度:使用Sobel算子计算梯度幅值均值"""
img = cv2.imread(str(image_path), cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError(f"无法读取图像: {image_path}")
gx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
gy = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
magnitude = np.sqrt(gx**2 + gy**2)
return magnitude.mean()
def filter_blurry_images(input_dir, output_dir, method="laplacian",
threshold=100.0, move=False):
"""
筛选并剔除模糊图像。
- method: "laplacian" 或 "tenengrad"
- threshold: 清晰度阈值,低于该值判定为模糊
- move: True 将模糊图移入 output_dir;False 仅打印结果
"""
input_dir = Path(input_dir)
output_dir = Path(output_dir)
if not input_dir.exists():
raise FileNotFoundError(f"输入目录不存在: {input_dir}")
score_func = laplacian_variance if method == "laplacian" else tenengrad_score
image_exts = {".jpg", ".jpeg", ".png", ".bmp", ".tiff"}
images = [p for p in input_dir.iterdir()
if p.suffix.lower() in image_exts]
if not images:
print("输入目录中没有找到支持的图像文件")
return
if move:
output_dir.mkdir(parents=True, exist_ok=True)
blurry_count = 0
for img_path in sorted(images):
score = score_func(img_path)
is_blurry = score < threshold
status = "模糊" if is_blurry else "清晰"
print(f"{img_path.name}: {method}得分={score:.2f} → {status}")
if is_blurry and move:
dest = output_dir / img_path.name
img_path.rename(dest) # 移动文件
blurry_count += 1
print(f"\n共检测 {len(images)} 张图像,判定模糊 {blurry_count} 张")
if __name__ == "__main__":
# 示例调用:将 input_images 中拉普拉斯得分低于 100 的图像移入 blurry/
filter_blurry_images(
input_dir="input_images",
output_dir="blurry",
method="laplacian",
threshold=100.0,
move=True
)
运行与验证
准备数据:创建 input_images/ 目录,放入若干清晰图像与明显模糊的图像(可用手机拍摄时抖动产生,或用高斯模糊处理清晰图生成)。
执行筛选:
python blur_detector.py
判定标准:
- 程序逐张输出每张图像的清晰度得分与“清晰/模糊”判定;
- 当
move=True时,被判定为模糊的图像文件会从input_images/移动到blurry/目录; - 肉眼检查
blurry/中的图像确实视觉模糊,而input_images/中剩余图像视觉清晰,即说明筛选有效。
阈值调优建议:拉普拉斯方差通常以 100 为经验分界(低于100偏模糊),但受图像内容影响较大——纹理丰富的清晰图得分可能上千,而平滑背景为主的清晰图可能只有几十。建议先以 move=False 运行观察得分分布,再设定合理阈值。Tenengrad得分整体偏高,阈值需另行观察确定。
两种方法对比
常见问题
- 得分普遍偏低:若图像本身分辨率低或场景平滑(如天空、白墙),清晰图得分也可能低于阈值。此时应降低阈值或改用Tenengrad方法。
- 读取失败:确认图像路径无中文或特殊字符,且OpenCV支持该格式。
- 移动而非复制:代码使用
rename()实现移动,若需保留原图请将move参数改为False并手动处理输出列表。