如何在OpenCV图像对比中设置容差忽略偏移仅显示真实差异
解决方法与代码示例
1. 精准定位消除偏移根源
模板匹配默认的整数坐标定位易产生微小偏移,改用亚像素级定位可大幅提升对齐精度:
import cv2 import numpy as np # 加载灰度图 ref_gray = cv2.imread("reference.png", cv2.IMREAD_GRAYSCALE) sample_gray = cv2.imread("sample_scanned.png", cv2.IMREAD_GRAYSCALE) sample_h, sample_w = sample_gray.shape # 用归一化相关系数做匹配,抗干扰性更强 match_result = cv2.matchTemplate(ref_gray, sample_gray, cv2.TM_CCOEFF_NORMED) _, max_val, _, max_loc = cv2.minMaxLoc(match_result) # 亚像素修正:取峰值周围3x3区域计算梯度,微调坐标 y, x = np.unravel_index(np.argmax(match_result), match_result.shape) patch = match_result[y-1:y+2, x-1:x+2] dy, dx = np.gradient(patch)[0][1,1], np.gradient(patch)[1][1,1] sub_x, sub_y = x - dx/2, y - dy/2 top_left = (int(round(sub_x)), int(round(sub_y))) # 裁剪参考图对应区域,确保与样本图完全对齐 ref_crop = ref_gray[top_left[1]:top_left[1]+sample_h, top_left[0]:top_left[0]+sample_w]
2. 过滤偏移产生的无效差异
若仍存在细微偏移,用阈值+形态学操作过滤边缘小差异,只保留真正的打印缺失:
# 计算绝对差异图 diff = cv2.absdiff(ref_crop, sample_gray) # 阈值过滤:只保留灰度差大于30的区域(可根据实际调整) _, thresh_diff = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY) # 形态学闭操作:先膨胀再腐蚀,消除小噪点,保留大缺失区域 kernel = np.ones((2,2), np.uint8) cleaned_diff = cv2.morphologyEx(thresh_diff, cv2.MORPH_CLOSE, kernel)
3. 彩色叠加只显示有效差异
用处理后的差异图做掩码,仅在缺失区域叠加红蓝对比:
# 生成红蓝彩色层 ref_blue = np.zeros((sample_h, sample_w, 3), dtype=np.uint8) ref_blue[..., 0] = ref_crop # BGR格式,蓝色通道用参考图灰度值 sample_red = np.zeros((sample_h, sample_w, 3), dtype=np.uint8) sample_red[..., 2] = sample_gray # 红色通道用样本图灰度值 # 转换掩码为BGR格式 mask_bgr = cv2.cvtColor(cleaned_diff, cv2.COLOR_GRAY2BGR) // 255 # 叠加:仅在掩码区域显示红蓝对比 overlay = cv2.bitwise_and(ref_blue, mask_bgr) + cv2.bitwise_and(sample_red, mask_bgr) # 非差异区域设为黑色 overlay[cleaned_diff == 0] = 0 # 显示结果 cv2.imshow("Printer Quality Check", overlay) cv2.waitKey(0) cv2.destroyAllWindows()
4. 进阶:精准提取目标缺失元素
若已知待检测元素(如B和O右侧小点)的大小,可通过轮廓筛选直接定位:
# 提取差异图中的轮廓 contours, _ = cv2.findContours(cleaned_diff, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) final_mask = np.zeros_like(cleaned_diff) for cnt in contours: area = cv2.contourArea(cnt) # 根据实际元素大小设置面积阈值(需自行调整) if 10 < area < 100: cv2.drawContours(final_mask, [cnt], -1, 255, -1) # 用最终掩码生成结果 final_mask_bgr = cv2.cvtColor(final_mask, cv2.COLOR_GRAY2BGR) // 255 final_overlay = cv2.bitwise_and(ref_blue, final_mask_bgr) + cv2.bitwise_and(sample_red, final_mask_bgr) cv2.imshow("Target Defects Only", final_overlay)
内容的提问来源于stack exchange,提问作者Medestrac
相关产品推荐
相关产品推荐

