2. 基于灰度直方图的图像质量评估

任务说明

在工业OCR流水线中,图像质量直接决定识别成功率。本案例实现一个基于灰度直方图的图像质量评估工具,输入任意灰度图像,输出其灰度直方图数据、亮度均值、标准差对比度,并依据阈值给出“适合OCR/对比度过低/亮度过暗/亮度过亮”的质量判定,用于在采集端筛选出适合OCR的清晰图像。

核心实现

import numpy as np
import cv2
from collections import Counter

def compute_histogram(gray_img):
    """计算灰度直方图,返回256个bin的计数列表"""
    hist = cv2.calcHist([gray_img], [0], None, [256], [0, 256])
    return hist.flatten().astype(int)

def assess_image_quality(gray_img, low_contrast_thresh=30, dark_thresh=80, bright_thresh=200):
    """
    基于灰度直方图评估图像质量
    返回: (hist, metrics_dict, quality_label)
    """
    hist = compute_histogram(gray_img)
    total_pixels = gray_img.size

    # 亮度均值
    mean_val = float(np.mean(gray_img))
    # 标准差对比度
    std_val = float(np.std(gray_img))

    # 直方图有效灰度范围(覆盖99%像素)
    sorted_vals = np.argsort(hist)[::-1]
    cumsum = np.cumsum(np.sort(hist)[::-1])
    cutoff = total_pixels * 0.99
    n_bins_cover = int(np.searchsorted(cumsum, cutoff) + 1)
    used_levels = sorted_vals[:n_bins_cover]
    gray_range = int(np.max(used_levels) - np.min(used_levels))

    # 质量判定
    if std_val < low_contrast_thresh:
        label = "对比度过低-不适合OCR"
    elif mean_val < dark_thresh:
        label = "亮度过暗-不适合OCR"
    elif mean_val > bright_thresh:
        label = "亮度过亮-不适合OCR"
    else:
        label = "适合OCR"

    metrics = {
        "mean": round(mean_val, 2),
        "std": round(std_val, 2),
        "gray_range": gray_range,
        "total_pixels": total_pixels
    }
    return hist, metrics, label

def load_and_assess(image_path):
    """加载图像并评估,返回直方图、指标和判定结果"""
    img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    if img is None:
        raise ValueError(f"无法读取图像: {image_path}")
    hist, metrics, label = assess_image_quality(img)
    return hist, metrics, label

# 示例:对单张图像执行评估
if __name__ == "__main__":
    # 使用一张示例图像(请替换为实际路径)
    hist, metrics, label = load_and_assess("sample_ocr_image.png")
    print("质量指标:", metrics)
    print("判定结果:", label)
    # 直方图前10个灰度级的像素计数
    print("直方图前10个bin:", hist[:10].tolist())

关键逻辑说明

代码通过OpenCV读取灰度图,计算256级灰度直方图。亮度用像素均值衡量,对比度用标准差和有效灰度范围双重表征。判定规则为:标准差低于30视为对比度过低;均值低于80视为过暗;均值高于200视为过亮;其余情况判定为适合OCR。阈值可根据实际产线光照条件调整。

落地与验证

依赖安装:

pip install opencv-python numpy

运行方式:将代码保存为quality_assess.py,准备一张包含文字的实际拍摄图像(如产品标签照片),替换代码中的sample_ocr_image.png为实际路径后执行:

python quality_assess.py

验证方法:准备三张测试图——一张正常光照下的清晰文字图、一张过暗图、一张模糊低对比图。分别运行程序,观察输出:

  • 清晰图应输出“适合OCR”,且std值通常大于30,mean在80~200之间;
  • 过暗图mean应小于80,输出“亮度过暗”;
  • 模糊图std应小于30,输出“对比度过低”。

判定标准:程序输出的质量标签与人工目视判断一致,且直方图数据与图像实际灰度分布相符,即验证通过。

灰度直方图质量评估流程 输入灰度图像 (相机采集) 灰度直方图 256个bin计数 cv2.calcHist 特征提取 亮度均值 (mean) 对比度 (std) 有效灰度范围 质量判定规则 std < 30 → 对比度过低 mean < 80 → 过暗 mean > 200 → 过亮 否则 → 适合OCR 输出判定结果 适合OCR / 不适合原因 后续OCR识别 仅“适合OCR”图像进入识别 通过筛选 验证要点: 正常图→适合OCR 过暗图→亮度过暗 模糊图→对比度过低