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

OpenCV模板匹配提取tif图像地图时出现重复检测如何解决

模板匹配重复检测问题修复方案

核心问题原因

  • 现有去重逻辑错误:仅对匹配点的x/y坐标做±9像素的过滤,远小于模板尺寸,且判断逻辑存在漏洞(把x、y坐标存入同一个列表,lspoint2全程未使用,坐标判断条件完全不符合预期)
  • 阈值设置过低:TM_CCOEFF_NORMED取值范围为[-1,1],越接近1匹配度越高,当前0.15的阈值会产生大量误检
  • 无跨模板去重逻辑:多模板匹配时,同一个目标被多个模板命中会重复输出结果
  • 无重叠框过滤逻辑:模板匹配在目标区域附近会产生连续的高响应值,相邻偏移的匹配点都会命中阈值,产生大量重复框

修复方案

采用**非极大值抑制(NMS)**作为标准去重方案,步骤如下:

  1. 收集所有高于阈值的匹配框、对应置信度
  2. 按置信度从高到低排序,删除和当前最高置信度框重叠度高于阈值的其他框
  3. 多模板场景下,统一收集所有模板的匹配结果后做全局NMS,避免跨模板重复

修复后代码

1. 新增NMS工具函数

def non_max_suppression(boxes, scores, iou_threshold=0.3):
    # boxes格式:[[x1,y1,x2,y2], ...] x1y1左上角,x2y2右下角
    # scores格式:[score1, score2, ...]
    x1 = boxes[:, 0]
    y1 = boxes[:, 1]
    x2 = boxes[:, 2]
    y2 = boxes[:, 3]
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    order = scores.argsort()[::-1]  # 按置信度从高到低排序
    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)
        # 计算重叠区域
        xx1 = np.maximum(x1[i], x1[order[1:]])
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.minimum(y2[i], y2[order[1:]])
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        iou = inter / (areas[i] + areas[order[1:]] - inter)
        # 保留重叠度低于阈值的框
        inds = np.where(iou <= iou_threshold)[0]
        order = order[inds + 1]
    return keep

2. 改造模板匹配函数

import numpy as np
import PIL
import cv2
import csv
import os
import time
import glob

# 全局变量定义表头,避免原代码未定义报错
fields = ["文件路径", "模板宽", "模板高", "检测y2", "检测x2", "面积", "阈值", "耗时"]

def matchtemplatetiff(img, tmp, threshold):
    h, w, c = tmp.shape  # 注意numpy数组是高、宽、通道,原代码写反了w和h会导致框尺寸错误
    res = cv2.matchTemplate(img, tmp, cv2.TM_CCOEFF_NORMED)
    loc = np.where(res >= threshold)
    boxes = []
    scores = []
    for pt in zip(*loc[::-1]):
        x1, y1 = pt
        x2 = x1 + w
        y2 = y1 + h
        boxes.append([x1, y1, x2, y2])
        scores.append(res[y1, x1])
    return np.array(boxes), np.array(scores)

3. 改造批量处理逻辑

if __name__ == "__main__":
    # 可调参数
    threshold = 0.7  # 匹配度阈值,建议从0.6~0.8之间调整
    nms_threshold = 0.3  # 重叠度阈值,超过这个值的重复框会被过滤
    tiff_dir = "/content/drive/MyDrive/testpakistan/*.tif"
    template_dir = "/content/drive/MyDrive/templatepakistan/*.tif"
    out_dir = "/content/drive/MyDrive/testpakistan/"
    csv_path = "/content/drive/My Drive/Colab Notebooks/records_first.csv"

    # 预加载所有模板避免重复读取
    templates = []
    for tmp_path in glob.glob(template_dir):
        tmp = np.array(PIL.Image.open(tmp_path))
        templates.append(tmp)

    # 逐图处理
    for tifffile in glob.glob(tiff_dir):
        start_time = time.time()
        img = np.array(PIL.Image.open(tifffile))
        imgc = img.copy()
        all_boxes = []
        all_scores = []

        # 多模板匹配,收集所有结果
        for tmp in templates:
            boxes, scores = matchtemplatetiff(img, tmp, threshold)
            if len(boxes) > 0:
                all_boxes.extend(boxes)
                all_scores.extend(scores)
        
        if len(all_boxes) == 0:
            print(f"{tifffile} 未检测到目标")
            continue
        
        all_boxes = np.array(all_boxes)
        all_scores = np.array(all_scores)

        # 全局NMS去重
        keep_idx = non_max_suppression(all_boxes, all_scores, nms_threshold)
        final_boxes = all_boxes[keep_idx]

        # 输出结果
        n = 0
        for box in final_boxes:
            x1, y1, x2, y2 = box
            w = x2 - x1
            h = y2 - y1
            size = w * h * (2.54/400) * (2.54/400)
            # 保存裁剪图
            crop_img = imgc[y1:y2, x1:x2, :]
            cv2.imwrite(f"{tifffile}_map_{n}.tif", crop_img)
            # 写csv
            rows = [[tifffile, w, h, y2, x2, size, threshold, (time.time() - start_time)]]
            with open(csv_path, 'a', newline='') as csvfile:
                csvwriter = csv.writer(csvfile)
                if n == 0 and not os.path.exists(csv_path): # 仅首次写入表头
                    csvwriter.writerow(fields)
                csvwriter.writerows(rows)
            n += 1
        
        # 保存标注后的原图
        PIL.Image.fromarray(img, 'RGB').save(os.path.join(out_dir, os.path.basename(tifffile)))
        print(f"{tifffile} 处理完成,检测到{n}个目标,耗时{time.time()-start_time}秒")

额外调整说明

  • 修正了原代码中模板宽高写反的问题(numpy数组读取顺序为高、宽、通道,原代码w, h, c = tmp.shape会导致框尺寸错误)
  • 预加载所有模板避免重复读取文件,提升处理速度
  • 新增csv表头判断,避免重复写入表头
  • 调整匹配度阈值默认值为0.7,可根据实际匹配效果调整

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 04:00:05