在计算机视觉中,模板匹配是一种基础且实用的目标检测方法。但在实际场景中,目标物体往往会以不同角度、翻转形态出现,仅用单一模板进行匹配会遗漏大量有效结果。本文将以图片箭头识别为例,从基础图像旋转讲起,逐步优化模板匹配方案,最终实现全方向箭头的精准检测。
一、OpenCV 图像旋转的两种实现方式
在处理方向多变的目标时,首先需要掌握图像旋转的基础操作。OpenCV 提供了两种常用的旋转实现方式,分别基于numpy原生函数和 OpenCV 内置方法。
1.1基于 numpy.rot90 的旋转
numpy.rot90 可以快速实现 90° 倍数的旋转,通过 k 参数控制旋转方向和次数:
k=-1:顺时针旋转 90°
k=1:逆时针旋转 90°
k=2:旋转 180°
python
import cv2
import numpy as np
# 读取原始图像
img = cv2.imread('kele.png')
# 顺时针旋转90度
rotated_image1 = np.rot90(img, k=-1)
# 逆时针旋转90度
rotated_image2 = np.rot90(img, k=1)
# 旋转 180°
rotated_image3 = np.rot90(img, k=2)
# 显示对比
cv2.imshow('原图', img)
cv2.imshow('顺时针90度', rotated_image1)
cv2.imshow('逆时针90度', rotated_image2)
cv2.imshow('旋转 180°', rotated_image3)
cv2.waitKey(0)
cv2.destroyAllWindows()

1.2基于 cv2.rotate 的旋转
OpenCV 提供了更语义化的旋转接口,直接通过枚举常量指定旋转角度,可读性更强:
cv2.ROTATE_90_CLOCKWISE:顺时针 90°
cv2.ROTATE_90_COUNTERCLOCKWISE:逆时针 90°
cv2.ROTATE_180:旋转 180°
python
import cv2
# 读取原始图像
img = cv2.imread('kele.png')
# 顺时针旋转90度
rotated = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
# 逆时针旋转90度
rotated1 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
# 旋转180度
rotated2 = cv2.rotate(img, cv2.ROTATE_180)
# 显示对比
cv2.imshow('s90', rotated)
cv2.imshow('n90', rotated1)
cv2.imshow('180', rotated2)
cv2.waitKey(0)
cv2.destroyAllWindows()

二、项目实战:多方向箭头识别
在下面这个图片当中实现模板匹配



2.1、基础模板匹配:仅识别同方向箭头
模板匹配的核心思想是:在原图中滑动模板窗口,计算窗口与模板的相似度,超过阈值则判定为匹配目标。
python
import cv2
import numpy as np
# 1. 读取图像并转为灰度图(降低计算量)
img_rgb = cv2.imread('image.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
# 2. 读取模板图像(箭头模板,灰度模式)
template = cv2.imread('tem.jpg', flags=0)
h, w = template.shape[:2] # 获取模板高宽
# 3. 执行模板匹配(使用归一化相关系数法)
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
# 4. 设定阈值,筛选高匹配度区域
threshold = 0.9
loc = np.where(res >= threshold) # 得到匹配坐标 (行, 列)
# 5. 遍历匹配点,绘制矩形框
for pt in zip(*loc[::-1]): # 转换为 (x, y) 坐标
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), color=(0, 0, 255), thickness=1)
# 6. 显示结果
cv2.imshow('jiego', img_rgb)
cv2.waitKey(0)
cv2.destroyAllWindows()

存在问题
仅能识别与模板方向完全一致的箭头,对旋转、翻转的箭头完全失效;
实际场景中目标姿态多变,基础匹配方案实用性极低。
三、优化:多模板匹配实现全方向识别
为了解决方向问题,我们可以生成模板的所有可能姿态(旋转 + 翻转),构建模板库后逐一匹配,最终实现全方向箭头的识别。
核心优化思路
- 生成模板的 7 种变形:原模板的旋转和翻转的所有变形,覆盖所有可能的箭头姿态;
- 遍历所有变形模板,分别执行模板匹配;
- 汇总所有匹配结果,在原图上绘制所有检测到的箭头。
python
import cv2
import numpy as np
# 1. 读取图像
img_rgb = cv2.imread('image.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('tem.jpg', 0) # 模板灰度图
h, w = template.shape[:2]
# 2. 构建多姿态模板库
templates = []
templates.append(template) # 原模板
templates.append(cv2.rotate(template, cv2.ROTATE_90_CLOCKWISE)) # 顺时针90°
templates.append(cv2.rotate(template, cv2.ROTATE_90_COUNTERCLOCKWISE)) # 逆时针90°
templates.append(cv2.rotate(template, cv2.ROTATE_180)) # 180°
templates.append(cv2.flip(template, 1)) # 水平翻转
templates.append(cv2.flip(template, 0)) # 垂直翻转
templates.append(cv2.flip(template, -1)) # 水平+垂直翻转
# 3. 遍历所有模板执行匹配
threshold = 0.9 # 匹配阈值
for temp in templates:
res = cv2.matchTemplate(img_gray, temp, cv2.TM_CCOEFF_NORMED)
loc = np.where(res >= threshold)
# 绘制匹配框
for pt in zip(*loc[::-1]):
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 1)
# 4. 显示最终结果
cv2.imshow("jieguo", img_rgb)
cv2.waitKey(0)
cv2.destroyAllWindows()
