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

Python实现检测小图是否为大图的一部分(支持水平缩放)

解决水平缩放小图的大图匹配问题

针对小图存在水平缩放时的大图匹配需求,cv2.matchTemplate()因模板尺寸固定无法适配缩放情况,以下提供两种无需分割图像的解决方案:

1. 定向多尺度模板匹配(针对水平缩放)

仅针对水平方向生成不同缩放比例的模板,遍历匹配后取最高相似度值:

import cv2
import numpy as np

def is_scaled_template_in_img(img, templ, scale_range=(0.5, 2.0), step=0.1):
    max_similarity = 0.0
    img_width = img.shape[1]
    templ_height, templ_width = templ.shape[:2]
    
    # 遍历水平方向的缩放比例
    for scale in np.arange(scale_range[0], scale_range[1], step):
        # 仅水平缩放,保持高度不变
        scaled_templ = cv2.resize(templ, (int(templ_width * scale), templ_height))
        # 跳过宽度超过原图的模板
        if scaled_templ.shape[1] > img_width:
            continue
        # 执行模板匹配
        result = cv2.matchTemplate(img, scaled_templ, cv2.TM_CCORR_NORMED)
        current_max = cv2.minMaxLoc(result)[1]
        if current_max > max_similarity:
            max_similarity = current_max
    return max_similarity

# 主逻辑
img = cv2.imread('img.jpg', 0)
path = 'symbols'
match_results = {}

for symb_no in range(1, 10):
    symbol = cv2.imread(f"{path}/{symb_no}.png", 0)
    # 先做高度适配(根据需求调整)
    symbol = cv2.resize(symbol, (symbol.shape[1], int(symbol.shape[0] * img.shape[1]/img.shape[0])))
    match_results[symb_no] = is_scaled_template_in_img(img, symbol)

# 按相似度降序输出
sorted_results = sorted(match_results.items(), key=lambda x: -x[1])
print({k: v for k, v in sorted_results})
  • 核心思路:针对水平方向生成一系列缩放模板,逐个匹配并记录最高相似度,以此判断小图是否存在。
  • 优化建议:根据实际场景调整scale_range和step,缩小范围或减小步长来平衡精度与效率。

2. SIFT特征匹配(尺度不变性方案)

SIFT特征自带尺度不变性,无需考虑缩放比例即可完成匹配:

import cv2
import numpy as np

def sift_match(img, templ, threshold=0.7, match_count_thresh=5):
    # 初始化SIFT检测器
    sift = cv2.SIFT_create()
    # 提取特征点与描述符
    kp1, des1 = sift.detectAndCompute(img, None)
    kp2, des2 = sift.detectAndCompute(templ, None)
    
    # FLANN高效匹配器
    index_params = dict(algorithm=1, trees=5)
    search_params = dict(checks=50)
    flann = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann.knnMatch(des1, des2, k=2)
    
    # 筛选优质匹配点
    good_matches = []
    for m, n in matches:
        if m.distance < threshold * n.distance:
            good_matches.append(m)
    
    # 根据匹配点数量判断是否存在
    return len(good_matches) > match_count_thresh

# 主逻辑
img = cv2.imread('img.jpg', 0)
path = 'symbols'
match_results = {}

for symb_no in range(1, 10):
    symbol = cv2.imread(f"{path}/{symb_no}.png", 0)
    match_results[symb_no] = sift_match(img, symbol)

print(match_results)
  • 核心优势:无需手动调整缩放比例,依赖特征点匹配稳定性更强,适合复杂场景。
  • 注意事项:OpenCV 4.x需提前安装opencv-contrib-python包;若小图特征较少,需调整match_count_thresh阈值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:31:05