Skip to main content

图片识别

模板匹配

  • 基础语法

    cv2.matchTemplate(img:imgArray,  template_img:imgArray, method:int) -> Array
    # 所有模版匹配用到的flag
    list_flag(TM_)

六种匹配模式

  • 内置的method(匹配方法)分为6种,每种都有不同的适用场景

    # cv2.TM_x
    methods = {
    "TM_SQDIFF":0,
    "TM_SQDIFF_NORMED":1,
    "TM_CCORR":2,
    "TM_CCORR_NORMED":3,
    "TM_CCOEFF":4,
    "TM_CCOEFF_NORMED":5,
    }
  • cv2.TM_SQDIFF | 0 - 平方差匹配法

    • 该方法使用平方差进行匹配,因此最佳的匹配结果在结果为0处,值越大匹配结果越差。

    • 计算平方不同,计算出来的值越小,越相关

    • 计算模板与目标图像的方差,由于是像素值差值的平方的和,所以值越小匹配程度越高;

    • 结果获取

      # 平方差匹配法 值越小越相关
      method = cv2.TM_SQDIFF
      res = cv2.matchTemplate(img_target, img_template, method)

      minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(res)
  • cv2.TM_SQDIFF_NORMED | 1

    • 该方法使用归一化的平方差进行匹配,最佳匹配也在结果为0处。
    • 计算归一化相关性 ,计算出来的值越接近1,越相关
    • 范化的cv::TM_SQDIFF,取值为0-1之间,完美匹配返回值为0
  • cv2.TM_CCORR | 2 - 相关性匹配方法

    • 相关性匹配方法,该方法使用源图像与模板图像的卷积结果进行匹配,因此,最佳匹配位置在值最大处,值越小匹配结果越差。

    • 计算相关性,计算出来的值越大,越相关

    • 使用dot product计算匹配度(不清楚怎么计算dot product,没看过代码),越高匹配度就好;

    • 结果获取

      # 相关性匹配方法,值越大越相关
      method = cv2.TM_CCORR
      res = cv2.matchTemplate(img_target, img_template, method)
  • cv2.TM_CCORR_NORMED | 3

    • 计算归一化相关性,计算出来的值越大,越相关
    • 范化的cv::TM_CCORR,0-1之间
    • 归一化的相关性匹配方法,与相关性匹配方法类似,最佳匹配位置也是在值最大处。
  • cv2.TM_CCOEFF | 4 - 相关系数匹配法

    • 相关性匹配方法,该方法使用源图像与模板图像的卷积结果进行匹配,因此,最佳匹配位置在值最大处,值越小匹配结果越差。
    • 计算相关系数,计算出来的值越大,越相关
    • 采用模板与目标图像像素与各自图像的平均值计算dot product,正值越大匹配度越高,负值越大图像的区别越大,但如果图像没有明显的特征(即图像中的像素值与平均值接近)则返回值越接近0
  • cv2.TM_CCOEFF_NORMED | 5

    • 计算归一化相关系数,计算出来的值越接近1,越相关,既越大

    • 范化的cv::TM_CCOEFF,-1 ~ 1之间

    • 归一化的相关性匹配方法,与相关性匹配方法类似,最佳匹配位置也是在值最大处。归一化的相关性匹配方法,与相关性匹配方法类似,最佳匹配位置也是在值最大处。

    • 结果提取:

      # 相关系数匹配法 
      method = cv2.TM_CCOEFF_NORMED
      res = cv2.matchTemplate(img_target, img_template, method)
      minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(res)
      print(maxVal, maxLoc)

注意:cv2 内置的匹配模式尽量采用带归一化的方式,结果可靠性最高

  • 使用场景
  1. 首先应尽量使用归一化的方法进行匹配
  2. 有明确目标模板的情况下,选用 TM_CCORR_NORMED | 5 方法效果可能较好,
  3. 没有明确目标模板的情况下,可以选用
from typing import *

Img = NewType('cv2.imread', list)
TM_FLAG = NewType("cv2.TM_CCOEFF|cv2.TM_CCOEFF_NORMED|cv2.TM_CCORR|cv2.TM_CCORR_NORMED|cv2.TM_SQDIFF|cv2.TM_SQDIFF_NORMED", int)
Region = NewType('(startX, startY, endX, endY)', Tuple[int])

def img_match(img_target:Img, img_template:Img, method:TM_FLAG=1, region:Optional[Region]=None, sim:float=0.8) -> bool:

res = cv2.matchTemplate(img_target, img_template, method)

minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(res)
max_res:bool = maxVal > sim
min_res:bool = (1 - minVal) > sim

match method:
case 0 | "TM_SQDIFF" :
if minVal == 0 or maxVal == 0:return True
return min_res

case 1 | "TM_SQDIFF_NORMED":
return max_res

case 2 | "TM_CCORR":
return max_res

case 3 | "TM_CCORR_NORMED":
return max_res

case 4 | "TM_CCOEFF":
return max_res

case 5 | "TM_CCOEFF_NORMED":
return max_res

case _:
return False