Python编程:缺陷检测图像预处理

图像预处理是工业缺陷检测系统中的关键环节,直接影响后续检测的准确性。下面将详细介绍一些工业缺陷检测图像预处理流程,包含多种优化技术和实用方法。

基础预处理流程

import cv2
import numpy as np
from skimage import exposure
import matplotlib.pyplot as plt

def basic_preprocessing(image_path):
    """
    基础图像预处理流程
    包含灰度化、去噪、增强和边缘保留等基本操作
    """
    # 读取图像
    img = cv2.imread(image_path)
    if img is None:
        raise ValueError("无法加载图像,请检查路径")
    
    # 1. 颜色空间转换
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 2. 直方图均衡化
    equalized = cv2.equalizeHist(gray)
    
    # 3. 去噪 (非局部均值去噪保留边缘)
    denoised = cv2.fastNlMeansDenoising(equalized, None, h=15, 
                                       templateWindowSize=7, 
                                       searchWindowSize=21)
    
    # 4. 高斯模糊
    blurred = cv2.GaussianBlur(denoised, (5,5), 0)
    
    return img, gray, equalized, denoised, blurred

def visualize_preprocessing(images, titles):
    """可视化预处理各阶段结果"""
    plt.figure(figsize=(15,10))
    for i in range(len(images)):
        plt.subplot(2, 3, i+1)
        plt.imshow(images[i], cmap='gray')
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()

# 使用示例
if __name__ == "__main__":
    image_path = "defective_part.jpg"
    original, gray, equalized, denoised, blurred = basic_preprocessing(image_path)
    
    images = [original, gray, equalized, denoised, blurred]
    titles = ['Original', 'Grayscale', 'Equalized', 'Denoised', 'Blurred']
    visualize_preprocessing(images, titles)

高级预处理

1 自适应光照校正

def adaptive_illumination_correction(gray_image):
    """
    自适应光照校正
    解决不均匀光照问题
    """
    # 1. 估计光照背景 (使用大核高斯模糊)
    background = cv2.GaussianBlur(gray_image, (101,101), 0)
    
    # 2. 从原图中减去背景 (转换为浮点避免截断)
    corrected = cv2.addWeighted(gray_image.astype(np.float32), 1, 
                             background.astype(np.float32), -1, 
                             128)
    
    # 3. 重新缩放至0-255范围
    corrected = np.clip(corrected, 0, 255).astype(np.uint8)
    
    # 4. 自适应直方图均衡化
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
    final = clahe.apply(corrected)
    
    return final, background

2 多尺度增强

def multi_scale_enhancement(image, sigma_list=[1, 3, 5]):
    """
    多尺度图像增强
    通过不同尺度的高斯核提取细节
    """
    # 转换为浮点型
    image = image.astype(np.float32) / 255.0
    
    # 初始化结果矩阵
    enhanced = np.zeros_like(image)
    
    for sigma in sigma_list:
        # 高斯模糊
        blurred = cv2.GaussianBlur(image, (0,0), sigma)
        
        # 细节层 = 原图 - 模糊图
        detail = image - blurred
        
        # 加权叠加 (权重与尺度成反比)
        enhanced += detail / sigma
    
    # 合并原始低频信息
    enhanced = enhanced + image
    
    # 归一化到0-255
    enhanced = np.clip(enhanced * 255, 0, 255).astype(np.uint8)
    
    return enhanced

3 纹理增强

def texture_enhancement(image, method='lbp', radius=3, neighbors=24):
    """
    纹理增强方法
    支持LBP(局部二值模式)和Gabor滤波
    """
    if method == 'lbp':
        # LBP纹理增强
        lbp = local_binary_pattern(image, neighbors, radius, method='uniform')
        enhanced = (lbp * 255 / lbp.max()).astype(np.uint8)
    elif method == 'gabor':
        # Gabor滤波增强
        kernel = cv2.getGaborKernel((21,21), 5, np.pi/4, 10, 0.5, 0, ktype=cv2.CV_32F)
        enhanced = cv2.filter2D(image, cv2.CV_8UC3, kernel)
    else:
        raise ValueError("不支持的纹理增强方法")
    
    return enhanced

缺陷增强技术

1 基于背景减除的缺陷增强

def defect_enhancement(image, background_estimation='morph'):
    """
    缺陷增强技术
    通过背景减除突出缺陷区域
    """
    if background_estimation == 'morph':
        # 形态学背景估计
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (51,51))
        background = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)
    else:
        # 高斯背景估计
        background = cv2.GaussianBlur(image, (101,101), 0)
    
    # 背景减除
    diff = cv2.absdiff(image, background)
    
    # 增强对比度
    enhanced = cv2.normalize(diff, None, 0, 255, cv2.NORM_MINMAX)
    
    return enhanced, background

2 基于频域的缺陷检测

def frequency_domain_enhancement(image, low_cutoff=0.1, high_cutoff=0.3):
    """
    频域缺陷增强
    通过频域滤波增强缺陷特征
    """
    # 傅里叶变换
    dft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
    dft_shift = np.fft.fftshift(dft)
    
    # 创建带通滤波器
    rows, cols = image.shape
    crow, ccol = rows//2, cols//2
    mask = np.zeros((rows, cols, 2), np.uint8)
    r1 = int(low_cutoff * rows/2)
    r2 = int(high_cutoff * rows/2)
    cv2.circle(mask, (ccol, crow), r2, (1,1), -1)
    cv2.circle(mask, (ccol, crow), r1, (0,0), -1)
    
    # 应用滤波器
    fshift = dft_shift * mask
    
    # 逆傅里叶变换
    ishift = np.fft.ifftshift(fshift)
    img_back = cv2.idft(ishift)
    img_back = cv2.magnitude(img_back[:,:,0], img_back[:,:,1])
    
    # 归一化
    enhanced = cv2.normalize(img_back, None, 0, 255, cv2.NORM_MINMAX)
    
    return enhanced.astype(np.uint8)

流水线示例

def complete_preprocessing_pipeline(image_path, 
                                  illumination_corr=True,
                                  texture_enhance=True,
                                  defect_enhance=True):
    """
    完整的工业缺陷检测预处理流水线
    """
    # 1. 基础预处理
    original = cv2.imread(image_path)
    gray = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
    
    # 2. 光照校正
    if illumination_corr:
        gray, _ = adaptive_illumination_correction(gray)
    
    # 3. 多尺度增强
    enhanced = multi_scale_enhancement(gray)
    
    # 4. 纹理增强
    if texture_enhance:
        enhanced = texture_enhancement(enhanced, method='lbp')
    
    # 5. 缺陷增强
    if defect_enhance:
        enhanced, _ = defect_enhancement(enhanced)
    
    # 6. 最终去噪
    final = cv2.fastNlMeansDenoising(enhanced, None, h=7, 
                                   templateWindowSize=5, 
                                   searchWindowSize=15)
    
    # 可视化
    plt.figure(figsize=(15,10))
    images = [original, gray, enhanced, final]
    titles = ['Original', 'Grayscale', 'Enhanced', 'Final Preprocessed']
    
    for i in range(len(images)):
        plt.subplot(2, 2, i+1)
        if i == 0:
            plt.imshow(cv2.cvtColor(images[i], cv2.COLOR_BGR2RGB))
        else:
            plt.imshow(images[i], cmap='gray')
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()
    
    return final

# 使用示例
if __name__ == "__main__":
    processed = complete_preprocessing_pipeline("defective_product.jpg")

针对不同类型的工业缺陷,推荐以下预处理组合:

缺陷类型 推荐预处理组合
表面划痕 光照校正 + 多尺度增强 + 频域滤波
孔洞缺陷 纹理增强(LBP) + 形态学背景减除
边缘缺陷 多尺度增强 + Sobel边缘增强 + 非局部均值去噪
纹理异常 Gabor滤波 + 局部对比度增强
微小颗粒 高频增强 + 锐化 + 阈值分割

ROI提取:Python实现

ROI(Region of Interest,感兴趣区域)提取是工业缺陷检测中的关键步骤,能够有效缩小检测范围、提高处理效率。

基于阈值的ROI提取

1 自适应阈值法

import cv2
import numpy as np

def adaptive_threshold_roi(image):
    """
    基于自适应阈值的ROI提取
    适用于光照不均匀的场景
    """
    # 转换为灰度图
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    # 自适应阈值
    binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                 cv2.THRESH_BINARY_INV, 11, 2)
    
    # 形态学操作
    kernel = np.ones((3,3), np.uint8)
    cleaned = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=2)
    
    # 查找轮廓
    contours, _ = cv2.findContours(cleaned, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    rois = []
    for cnt in contours:
        if cv2.contourArea(cnt) > 1000:  # 面积阈值
            x,y,w,h = cv2.boundingRect(cnt)
            rois.append(image[y:y+h, x:x+w])
    
    return rois, cleaned

2 Otsu阈值法

def otsu_threshold_roi(image):
    """
    基于Otsu阈值的ROI提取
    适用于双峰直方图的图像
    """
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    # 高斯模糊
    blurred = cv2.GaussianBlur(gray, (5,5), 0)
    
    # Otsu阈值
    _, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
    
    # 查找轮廓
    contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    return [cv2.boundingRect(cnt) for cnt in contours if cv2.contourArea(cnt) > 500], binary

基于边缘检测的ROI提取

1 Canny边缘检测法

def canny_edge_roi(image, low_threshold=30, high_threshold=100):
    """
    基于Canny边缘检测的ROI提取
    """
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, low_threshold, high_threshold)
    
    # 膨胀连接边缘
    dilated = cv2.dilate(edges, None, iterations=2)
    
    # 查找轮廓
    contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    rois = []
    for cnt in contours:
        if cv2.contourArea(cnt) > 800:
            x,y,w,h = cv2.boundingRect(cnt)
            rois.append((x,y,w,h))
    
    return rois, edges

2 Sobel边缘检测法

def sobel_edge_roi(image, ksize=3):
    """
    基于Sobel算子的ROI提取
    """
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    # Sobel边缘检测
    sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=ksize)
    sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=ksize)
    
    # 计算梯度幅值
    gradient = np.sqrt(sobelx**2 + sobely**2)
    gradient = np.uint8(gradient / gradient.max() * 255)
    
    # 阈值处理
    _, binary = cv2.threshold(gradient, 50, 255, cv2.THRESH_BINARY)
    
    # 查找轮廓
    contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    return [cv2.boundingRect(cnt) for cnt in contours if cv2.contourArea(cnt) > 500], gradient

基于形态学的ROI提取

1 形态学分水岭法

def watershed_roi(image):
    """
    基于分水岭算法的ROI提取
    适用于重叠对象的分离
    """
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
    
    # 去除噪声
    kernel = np.ones((3,3), np.uint8)
    opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=2)
    
    # 确定背景区域
    sure_bg = cv2.dilate(opening, kernel, iterations=3)
    
    # 确定前景区域
    dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
    _, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)
    sure_fg = np.uint8(sure_fg)
    
    # 未知区域
    unknown = cv2.subtract(sure_bg, sure_fg)
    
    # 标记连通区域
    _, markers = cv2.connectedComponents(sure_fg)
    markers += 1
    markers[unknown==255] = 0
    
    # 分水岭算法
    markers = cv2.watershed(image, markers)
    image[markers == -1] = [255,0,0]  # 标记边界
    
    # 提取ROI
    rois = []
    for mark in np.unique(markers):
        if mark > 1:  # 忽略背景和边界
            mask = np.zeros(gray.shape, dtype="uint8")
            mask[markers == mark] = 255
            
            contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            for cnt in contours:
                if cv2.contourArea(cnt) > 500:
                    x,y,w,h = cv2.boundingRect(cnt)
                    rois.append((x,y,w,h))
    
    return rois, markers

鲁棒性ROI提取算法

def robust_roi_extraction(binary_image, 
                         min_area=1000, 
                         max_area_ratio=0.9,
                         solidity_thresh=0.8,
                         convexity_thresh=0.9,
                         aspect_ratio_range=(0.2, 5)):
    """
    鲁棒性ROI提取算法
    包含多级过滤条件和几何特征分析
    """
    # 查找轮廓(使用RETR_TREE获取层级关系)
    contours, hierarchy = cv2.findContours(binary_image, 
                                         cv2.RETR_TREE, 
                                         cv2.CHAIN_APPROX_SIMPLE)
    
    # 计算图像总面积
    img_area = binary_image.shape[0] * binary_image.shape[1]
    
    rois = []
    for i, cnt in enumerate(contours):
        # 1. 面积过滤
        area = cv2.contourArea(cnt)
        if area < min_area or area > (img_area * max_area_ratio):
            continue
        
        # 2. 几何特征计算
        # 凸包
        hull = cv2.convexHull(cnt)
        hull_area = cv2.contourArea(hull)
        
        # 凸性检测
        if hull_area == 0:
            continue
        solidity = float(area)/hull_area
        if solidity < solidity_thresh:
            continue
            
        # 凸度检测
        perimeter = cv2.arcLength(cnt, True)
        hull_perimeter = cv2.arcLength(hull, True)
        if hull_perimeter == 0:
            continue
        convexity = perimeter / hull_perimeter
        if convexity > convexity_thresh:
            continue
            
        # 3. 形状特征过滤
        # 最小外接矩形
        rect = cv2.minAreaRect(cnt)
        (_, (w, h), _) = rect
        
        # 长宽比过滤
        aspect_ratio = max(w, h) / (min(w, h) + 1e-6)
        if not (aspect_ratio_range[0] <= aspect_ratio <= aspect_ratio_range[1]):
            continue
            
        # 4. 层级关系过滤(排除嵌套轮廓)
        if hierarchy[0][i][3] != -1:  # 如果有父轮廓则跳过
            continue
            
        # 计算所有特征
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        
        # 计算等效椭圆
        ellipse = cv2.fitEllipse(cnt)
        
        rois.append({
            'contour': cnt,
            'bounding_rect': cv2.boundingRect(cnt),
            'min_area_rect': rect,
            'min_area_box': box,
            'convex_hull': hull,
            'ellipse': ellipse,
            'area': area,
            'solidity': solidity,
            'convexity': convexity,
            'aspect_ratio': aspect_ratio
        })
    
    # 按面积排序
    rois.sort(key=lambda x: x['area'], reverse=True)
    
    return rois

多尺度ROI检测

def multi_scale_roi_detection(image, 
                             min_scale=0.5, 
                             max_scale=1.5, 
                             scale_steps=3,
                             overlap_threshold=0.5):
    """
    多尺度ROI检测算法
    在不同尺度下检测ROI并合并结果
    """
    all_rois = []
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    for scale in np.linspace(min_scale, max_scale, scale_steps):
        # 缩放图像
        width = int(image.shape[1] * scale)
        height = int(image.shape[0] * scale)
        resized = cv2.resize(gray, (width, height), interpolation=cv2.INTER_AREA)
        
        # 预处理和ROI检测
        _, _, binary = enhanced_preprocess(resized)
        rois = robust_roi_extraction(binary)
        
        # 将ROI坐标转换回原始尺寸
        for roi in rois:
            # 转换边界矩形
            x, y, w, h = roi['bounding_rect']
            orig_rect = (
                int(x / scale), int(y / scale),
                int(w / scale), int(h / scale)
            
            # 转换最小外接矩形
            (cx, cy), (rw, rh), angle = roi['min_area_rect']
            orig_min_rect = (
                (cx / scale, cy / scale),
                (rw / scale, rh / scale),
                angle)
            
            # 转换轮廓点
            orig_contour = (roi['contour'] / scale).astype(np.int32)
            
            all_rois.append({
                'bounding_rect': orig_rect,
                'min_area_rect': orig_min_rect,
                'contour': orig_contour
            })
    
    # 非极大值抑制 (NMS) 去除重叠ROI
    final_rois = []
    while len(all_rois) > 0:
        # 选择面积最大的ROI
        all_rois.sort(key=lambda x: x['bounding_rect'][2] * x['bounding_rect'][3], reverse=True)
        selected = all_rois.pop(0)
        final_rois.append(selected)
        
        # 计算与剩余ROI的重叠
        to_remove = []
        x1, y1, w1, h1 = selected['bounding_rect']
        area1 = w1 * h1
        
        for i, roi in enumerate(all_rois):
            x2, y2, w2, h2 = roi['bounding_rect']
            
            # 计算交集
            x_left = max(x1, x2)
            y_top = max(y1, y2)
            x_right = min(x1 + w1, x2 + w2)
            y_bottom = min(y1 + h1, y2 + h2)
            
            if x_right < x_left or y_bottom < y_top:
                continue
                
            intersection_area = (x_right - x_left) * (y_bottom - y_top)
            area2 = w2 * h2
            overlap = intersection_area / min(area1, area2)
            
            if overlap > overlap_threshold:
                to_remove.append(i)
        
        # 从后往前删除避免索引问题
        for i in sorted(to_remove, reverse=True):
            all_rois.pop(i)
    
    return final_rois

你可能感兴趣的:(C++与python交互编程,python,opencv,计算机视觉)