You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用OpenCV和Python检测近似匹配的模板图案(非深度学习)

近似匹配被划掉方框的OpenCV实现方案

方法1:多尺度模板匹配

matchTemplate仅支持同尺寸目标匹配,通过对模板进行多尺度缩放,在不同尺度下执行模板匹配,可覆盖大小近似的目标。步骤如下:

  • 定义合理的缩放比例范围(比如0.5到1.5,步长0.1)
  • 逐次缩放模板,执行模板匹配
  • 设定匹配阈值,筛选符合条件的结果

代码示例:

import cv2
import numpy as np

# 加载原图和模板(灰度模式)
img = cv2.imread('data/wet/6.jpg', cv2.IMREAD_GRAYSCALE)
template = cv2.imread('data/wet/9.jpg', cv2.IMREAD_GRAYSCALE)
template_h, template_w = template.shape

# 匹配阈值(需根据实际图像调整)
threshold = 0.8
# 缩放比例范围
scale_range = np.arange(0.5, 1.5, 0.1)

img_copy = img.copy()

for scale in scale_range:
    # 缩放模板
    scaled_template = cv2.resize(template, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)
    scaled_h, scaled_w = scaled_template.shape
    if scaled_h > img.shape[0] or scaled_w > img.shape[1]:
        continue  # 跳过比原图尺寸大的模板
    
    # 用归一化相关系数执行匹配
    res = cv2.matchTemplate(img, scaled_template, cv2.TM_CCOEFF_NORMED)
    # 提取所有超过阈值的匹配位置
    loc = np.where(res >= threshold)
    
    # 绘制匹配框
    for pt in zip(*loc[::-1]):
        cv2.rectangle(img_copy, pt, (pt[0] + scaled_w, pt[1] + scaled_h), 255, 2)

# 保存并展示结果
cv2.imwrite('data/wet/multi_scale_match.jpg', img_copy)
cv2.imshow('Multi-scale Match', img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()

方法2:基于Hu矩的轮廓匹配

Hu不变矩具备旋转、缩放、平移不变性,适合检测形状近似的目标。步骤如下:

  • 对模板和原图做二值化处理,提取轮廓
  • 计算模板轮廓的Hu矩
  • 遍历原图轮廓,计算每个轮廓的Hu矩并与模板比对,用相似度阈值筛选匹配目标

代码示例:

import cv2
import numpy as np

# 加载模板和原图(灰度模式)
template = cv2.imread('data/wet/9.jpg', cv2.IMREAD_GRAYSCALE)
img = cv2.imread('data/wet/6.jpg', cv2.IMREAD_GRAYSCALE)

# 二值化(可根据图像明暗调整阈值,或用cv2.THRESH_OTSU自动计算)
_, template_bin = cv2.threshold(template, 127, 255, cv2.THRESH_BINARY_INV)
_, img_bin = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)

# 提取模板轮廓
template_contours, _ = cv2.findContours(template_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not template_contours:
    print("未检测到模板轮廓")
    exit()
# 取模板的最大轮廓
template_contour = max(template_contours, key=cv2.contourArea)
# 计算模板的Hu矩并做对数转换增强区分度
template_hu = cv2.HuMoments(cv2.moments(template_contour)).flatten()
template_hu = -np.sign(template_hu) * np.log10(np.abs(template_hu))

# 提取原图轮廓
img_contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
img_copy = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)  # 转彩色方便绘制彩色框

# 相似度阈值(数值越小,形状越相似,需调整)
sim_threshold = 0.2

for contour in img_contours:
    # 计算当前轮廓的Hu矩
    hu = cv2.HuMoments(cv2.moments(contour)).flatten()
    hu = -np.sign(hu) * np.log10(np.abs(hu))
    # 计算与模板Hu矩的欧式距离
    distance = np.linalg.norm(template_hu - hu)
    if distance < sim_threshold:
        # 绘制bounding rectangle
        x, y, w, h = cv2.boundingRect(contour)
        cv2.rectangle(img_copy, (x, y), (x+w, y+h), (0, 255, 0), 2)

# 保存并展示结果
cv2.imwrite('data/wet/hu_match.jpg', img_copy)
cv2.imshow('Hu Moment Match', img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()

方法3:边缘多尺度匹配

先提取模板和原图的边缘特征,再进行多尺度模板匹配,可忽略图像纹理细节,仅匹配形状轮廓。步骤如下:

  • 对模板和原图执行Canny边缘检测
  • 对边缘模板做多尺度缩放,执行模板匹配
  • 设定阈值筛选匹配结果

代码示例:

import cv2
import numpy as np

# 加载图像
img = cv2.imread('data/wet/6.jpg', cv2.IMREAD_GRAYSCALE)
template = cv2.imread('data/wet/9.jpg', cv2.IMREAD_GRAYSCALE)

# 提取边缘(Canny阈值需根据图像调整)
img_edges = cv2.Canny(img, 50, 150)
template_edges = cv2.Canny(template, 50, 150)
template_h, template_w = template_edges.shape

threshold = 0.7
scale_range = np.arange(0.6, 1.4, 0.1)
img_copy = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

for scale in scale_range:
    scaled_template = cv2.resize(template_edges, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)
    scaled_h, scaled_w = scaled_template.shape
    if scaled_h > img_edges.shape[0] or scaled_w > img_edges.shape[1]:
        continue
    
    res = cv2.matchTemplate(img_edges, scaled_template, cv2.TM_CCOEFF_NORMED)
    loc = np.where(res >= threshold)
    
    for pt in zip(*loc[::-1]):
        cv2.rectangle(img_copy, pt, (pt[0]+scaled_w, pt[1]+scaled_h), (255, 0, 0), 2)

# 保存并展示结果
cv2.imwrite('data/wet/edge_multi_match.jpg', img_copy)
cv2.imshow('Edge Multi-scale Match', img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()

注意事项

  • 所有阈值参数需根据实际图像调试,建议从中间值开始逐步调整
  • 若目标存在旋转,可在多尺度匹配基础上加入旋转角度遍历(如每隔10度旋转模板),但会增加计算量
  • 二值化步骤可尝试cv2.THRESH_OTSU自动计算阈值,适配不同明暗的图像

内容的提问来源于stack exchange,提问作者Sahan Kodituwakku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 23:34:55