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

Python使用cv2时出现模板匹配断言错误及文件读取警告,求解决方案

拼图求解Python代码异常解决方案

错误原因分析

  • 临时文件路径错误:Windows系统无Linux风格的/tmp默认路径,导致cv2.imwrite无法写入文件,后续cv2.imread读取失败生成空图像。
  • 模板尺寸大于背景图:图像加载失败或裁剪/扩展逻辑问题,导致传入cv2.matchTemplate的模板尺寸超过背景图尺寸,触发OpenCV断言错误。
  • 数据类型不匹配:扩展边界时用dtype=int创建零矩阵,与OpenCV图像默认的uint8类型冲突,可能损坏图像数据。
  • 冗余灰度转换操作:__sobel_operator已返回单通道灰度图,存盘再读取的__img_to_grayscale操作完全多余,还引入路径风险。

分步解决方案

1. 移除冗余灰度转换函数

直接删除__img_to_grayscale函数,__sobel_operator输出的grad已是单通道灰度图,无需额外转换。

2. 修正边界扩展数据类型

将所有np.zeros的dtype=int改为dtype=np.uint8,匹配OpenCV图像默认类型。

3. 调整背景与模板处理逻辑

去掉背景和模板处理中调用__img_to_grayscale的代码,直接使用__sobel_operator输出的图像。

4. (可选)跨平台临时文件处理

若后续需用临时文件,改用Python标准库tempfile生成跨平台路径,规避系统差异问题。

修改后的完整代码

import cv2
import numpy as np


PIXELS_EXTENSION = 10


class PuzzleSolver:  # 修正拼写错误:Puzle -> Puzzle
    def __init__(self, piece_path, background_path):
        self.piece_path = piece_path
        self.background_path = background_path

    def get_position(self):
        template, x_inf, y_sup, y_inf = self.__piece_preprocessing()
        background = self.__background_preprocessing(y_sup, y_inf)

        # 检查尺寸,避免模板过大
        assert background.shape[0] >= template.shape[0] and background.shape[1] >= template.shape[1], \
            "模板尺寸不能大于背景图尺寸"
        
        res = cv2.matchTemplate(background, template, cv2.TM_CCOEFF_NORMED)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
        top_left = max_loc

        origin = x_inf
        end = top_left[0] + PIXELS_EXTENSION

        return end - origin

    def __background_preprocessing(self, y_sup, y_inf):
        background = self.__sobel_operator(self.background_path)
        background = background[y_sup:y_inf, :]
        background = self.__extend_background_boundary(background)
        return background

    def __piece_preprocessing(self):
        img = self.__sobel_operator(self.piece_path)
        x, w, y, h = self.__crop_piece(img)
        template = img[y:h, x:w]

        template = self.__extend_template_boundary(template)
        return template, x, y, h

    def __crop_piece(self, img):
        white_rows = []
        white_columns = []
        r, c = img.shape

        # 用numpy批量判断,提升效率
        for row in range(r):
            if np.any(img[row, :] != 0):
                white_rows.append(row)

        for column in range(c):
            if np.any(img[:, column] != 0):
                white_columns.append(column)

        x = white_columns[0]
        w = white_columns[-1]
        y = white_rows[0]
        h = white_rows[-1]

        return x, w, y, h

    def __extend_template_boundary(self, template):
        # 修正dtype为uint8
        extra_border = np.zeros((template.shape[0], PIXELS_EXTENSION), dtype=np.uint8)
        template = np.hstack((extra_border, template, extra_border))

        extra_border = np.zeros((PIXELS_EXTENSION, template.shape[1]), dtype=np.uint8)
        template = np.vstack((extra_border, template, extra_border))

        return template

    def __extend_background_boundary(self, background):
        # 修正dtype为uint8
        extra_border = np.zeros((PIXELS_EXTENSION, background.shape[1]), dtype=np.uint8)
        return np.vstack((extra_border, background, extra_border))

    def __sobel_operator(self, img_path):
        scale = 1
        delta = 0
        ddepth = cv2.CV_16S

        img = cv2.imread(img_path, cv2.IMREAD_COLOR)
        # 新增图像加载检查
        if img is None:
            raise FileNotFoundError(f"无法加载图像:{img_path}")
            
        img = cv2.GaussianBlur(img, (3, 3), 0)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        grad_x = cv2.Sobel(gray, ddepth, 1, 0, ksize=3, scale=scale, delta=delta, borderType=cv2.BORDER_DEFAULT)
        grad_y = cv2.Sobel(gray, ddepth, 0, 1, ksize=3, scale=scale, delta=delta, borderType=cv2.BORDER_DEFAULT)
        abs_grad_x = cv2.convertScaleAbs(grad_x)
        abs_grad_y = cv2.convertScaleAbs(grad_y)
        grad = cv2.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0)

        return grad


solver = PuzzleSolver("example/piece.png", "example/background.png")
solution = solver.get_position()

print(solution)

额外优化说明

  • 修正类名拼写错误PuzleSolver -> PuzzleSolver
  • 优化__crop_piece函数效率,用np.any替代嵌套循环判断
  • 新增图像加载检查,提前抛出文件不存在错误
  • 新增尺寸断言,提前阻止无效模板匹配操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 07:05:56