2. 织物瑕疵检测中的纹理分析

任务目标

本案例使用灰度共生矩阵(GLCM)提取织物图像的纹理特征,通过对比无瑕疵区域与待检测区域的纹理差异,定位瑕疵区域并在原图上标记。输入为单张织物灰度图像,输出为标记了瑕疵边界框的结果图像及瑕疵数量。

实现方案

将图像划分为固定大小的重叠窗口,对每个窗口计算GLCM的对比度(contrast)和能量(energy)作为纹理特征。以图像中心区域(假设无瑕疵)的特征均值为基准,当窗口特征与基准的偏差超过阈值时判定为瑕疵窗口。相邻瑕疵窗口合并为连通域,绘制边界框。

依赖环境

  • Python 3.8+
  • OpenCV(pip install opencv-python)
  • NumPy(pip install numpy)
  • scikit-image(pip install scikit-image)

关键完整代码

import cv2
import numpy as np
from skimage.feature import graycomatrix, graycoprops

def compute_glcm_features(gray_patch):
    """计算单窗口的GLCM对比度和能量"""
    glcm = graycomatrix(gray_patch, distances=[1], angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],
                        levels=256, symmetric=True, normed=True)
    contrast = np.mean([graycoprops(glcm, 'contrast')[0, 0] for _ in range(4)])
    energy = np.mean([graycoprops(glcm, 'energy')[0, 0] for _ in range(4)])
    return contrast, energy

def detect_defects(image_path, win_size=32, step=16, threshold_mult=2.0):
    # 读取并转为灰度
    img = cv2.imread(image_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    h, w = gray.shape

    # 以图像中心区域作为无瑕疵基准
    ch, cw = h // 2, w // 2
    ref_size = min(win_size * 3, ch, cw)
    ref_patch = gray[ch - ref_size//2:ch + ref_size//2, cw - ref_size//2:cw + ref_size//2]
    ref_contrast, ref_energy = compute_glcm_features(ref_patch)

    # 滑窗检测
    defect_mask = np.zeros((h, w), dtype=np.uint8)
    for y in range(0, h - win_size + 1, step):
        for x in range(0, w - win_size + 1, step):
            patch = gray[y:y + win_size, x:x + win_size]
            contrast, energy = compute_glcm_features(patch)
            # 偏差判定:对比度偏离或能量偏离均视为瑕疵
            if (abs(contrast - ref_contrast) > threshold_mult * ref_contrast or
                abs(energy - ref_energy) > threshold_mult * ref_energy):
                defect_mask[y:y + win_size, x:x + win_size] = 255

    # 形态学闭运算连接邻近瑕疵窗口
    kernel = np.ones((win_size, win_size), np.uint8)
    defect_mask = cv2.morphologyEx(defect_mask, cv2.MORPH_CLOSE, kernel)

    # 找连通域并画框
    contours, _ = cv2.findContours(defect_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    result = img.copy()
    for cnt in contours:
        x, y, bw, bh = cv2.boundingRect(cnt)
        cv2.rectangle(result, (x, y), (x + bw, y + bh), (0, 0, 255), 2)

    return result, len(contours)

if __name__ == "__main__":
    # 使用示例:替换为实际图像路径
    out_img, num_defects = detect_defects("fabric.jpg")
    print(f"检测到瑕疵数量: {num_defects}")
    cv2.imwrite("result.jpg", out_img)

运行方式

  1. 将待检测织物图像命名为 fabric.jpg 放在脚本同目录;
  2. 运行 python fabric_defect_detection.py;
  3. 查看输出文件 result.jpg 和控制台打印的瑕疵数量。

验证方法

选择一张包含明显瑕疵(如破洞、污渍、织纹异常)的织物图像进行测试。通过标准:

  • 输出图像中瑕疵区域被红色矩形框标记,且框的位置与瑕疵实际位置基本吻合;
  • 无瑕疵的均匀织物图像检测到的瑕疵数量为0或极少(仅边缘噪声);
  • 调整 threshold_mult 参数(建议范围1.5~3.0)可控制检测灵敏度,数值越小越敏感。

常见问题

  • 检测结果噪声多:增大 threshold_mult 或增大 win_size 降低分辨率;
  • 漏检小瑕疵:减小 step 至8或4,但会增加计算时间;
  • 基准区域本身有瑕疵:可改为手动指定无瑕疵区域坐标,或使用整幅图像的纹理统计中位数作为基准。
输入织物图像 灰度化 + 滑窗划分 计算GLCM特征 与基准特征比较 偏差 > 阈值? 标记瑕疵窗口 连通域合并 绘制边界框 输出结果图像 是 否 GLCM特征:对比度 + 能量 窗口大小32px,步长16px