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
相关产品推荐
相关产品推荐

