09- OpenCV模板匹配 (OpenCV系列) (机器视觉)

知识要点

  • 模板匹配:  res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)   
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# 画出匹配位置
cv2.rectangle(img, min_loc, (min_loc[0] + 85, min_loc[1] + 110), (0, 0, 255), 2)
  • 模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1) .
     
    • TM_SQDIFF:计算平方不同,计算出来的值越小,越相关

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

    • TM_CCOEFF:计算相关系数,计算出来的值越大,越相关

    • TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关

    • TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关

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

建议使用归一化的计算方法会相对公平一些.

  • matchTemplate(image, templ, method[, result[, mask]]) 进行模板匹配

    • image是要匹配的图片

    • templ是模板图片

    • method是计算方式

    • result是进行匹配计算后得到的矩阵.

    • mask是掩膜

  • minMaxLoc(src[, mask]) 获取最大值和最小值的位置.

    • 返回四个值, 分别是最小值, 最大值, 最小值坐标, 最大值坐标

  •  ret, dst = cv2.threshold(naza_gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)  # 大津算法

    • Otsu算法之所以称为最大类间方差法是因为,该方法主要是通过阈值进行前后背景分割


1 模板匹配

模板匹配:

cv2.matchTemplate(), 局部图片通过cv2.matchTemplate找出在原图片的位置

import cv2
import numpy as np

img = cv2.imread('./lena.jpg')
template = cv2.imread('./face.jpg')
print(img.shape, template.shape)  # (263, 263, 3)  (110, 85, 3)
# 匹配完的图片是差值
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
print(res.shape)   # (154, 179)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(min_val, max_val, min_loc, max_loc)  # 256897.0 200943056.0 (107,89) (157,45)

# 画出匹配位置
cv2.rectangle(img, min_loc, (min_loc[0] + 85, min_loc[1] + 110), (0, 0, 255), 2)
cv2.imshow('img', img)
cv2.imshow('tem',template)
cv2.waitKey(0)
cv2.destroyAllWindows()

1.1 六种模板匹配的方式

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('./lena.jpg', 0)   # 表示灰度图
template = cv2.imread('./face.jpg', 0)
w, h = template.shape[1], template.shape[0]
# 定义方法列表
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR', 
           'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
i = -1
for method in methods:
    img2 = img.copy()
    res = cv2.matchTemplate(img, template, eval(method))
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    if method in ['cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv2.rectangle(img2, top_left, bottom_right, (0, 0, 255), 2)  # 画矩形
    
    load_1 = [231, 232, 233, 234, 235, 236]
    i += 1
    plt.subplot(load_1[i]), plt.imshow(img2, cmap = 'gray')  # 画子图
    plt.axis('off')
    plt.title(method, {'fontsize': 9})
    
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()

1.2  同时匹配多个对象

通过设定阈值进行控制, 相关性大于0.8,  匹配上(matchTemplate)

import cv2
import numpy as np

mario = cv2.imread('./mario.jpg')
# 灰度化
mario_gray = cv2.cvtColor(mario, cv2.COLOR_BGR2GRAY)
template = cv2.imread('./mario_coin.jpg', 0)
w, h = template.shape[1], template.shape[0]

res = cv2.matchTemplate(mario_gray, template, cv2.TM_CCOEFF_NORMED) # 匹配
# 设定阈值,相关性大于0.8, 匹配上
threshold = 0.8
loc = np.where(res >= threshold)   # 分别返回Y, X轴的索引
# zip里面为数组,坐标点
for pt in zip(*loc[:: -1]):
    bottom_right = (pt[0] + w, pt[1] + h)
    cv2.rectangle(mario, pt, bottom_right, (0, 0, 255), 2)
    
cv2.imshow('mario', mario)
cv2.imshow('template', template)
cv2.waitKey(0)
cv2.destroyAllWindows()

2 otsu算法 (大津算法)

Otsu算法之所以称为最大类间方差法是因为,该方法主要是通过阈值进行前后背景分割 而该方法确定最佳阈值的方法是该值使类间方差最大,它是按图像的灰度特性,将图像分成背景和前景两部分,使类间方差最大的分割意味着错分概率最小。

常见的阈值类型:

  • cv2.THRESH_BINARY 大于阈值的部分被置为255,小于部分被置为0
  • cv2.THRESH_BINARY_INV 大于阈值部分被置为0,小于部分被置为255
  • cv2.THRESH_TRUNC 大于阈值部分被置为threshold,小于部分保持原样
  • cv2.THRESH_TOZERO 小于阈值部分被置为0,大于部分保持不变
  • cv2.THRESH_TOZERO_INV 大于阈值部分被置为0,小于部分保持不变
  • cv2.THRESH_OTSU,并且把阈值thresh设为0,算法会找到最优阈值,并作为第一个返回值ret返回。

当阈值范围无法人工确定时, 可以使用Otsu的方法通过计算确定阈值. Otsu适用于图片的灰度直方图是双峰结构的图形.

二值化处理图片, OTSU算法的假设是存在阈值 TH 将图像所有像素分为两类 C1 ( 小于TH )和 C2 ( 大于TH ),  存在阈值TH将图像所有像素分为两类C1(小于TH)和C2(大于TH),则这两类像素各自的均值就为m1、m2,图像全局均值为mG。

import cv2
import numpy as np
import matplotlib.pyplot as plt

naza = cv2.imread('./lena.jpg')
naza_gray = cv2.cvtColor(naza, cv2.COLOR_BGR2GRAY)
# 特别适合双峰结构的灰度图
_  = plt.hist(naza_gray.ravel(), bins = 256, range = [0, 255])
# 阈值处理
ret, dst = cv2.threshold(naza_gray, 50, 255, cv2.THRESH_BINARY)  # 前景
cv2.imshow('naza', np.hstack((naza_gray, dst)))
# 使用otsu算法
ret, dst = cv2.threshold(naza_gray, 0, 255,cv2.THRESH_BINARY|cv2.THRESH_OTSU) # 背景
print(ret)   # 115.0

cv2.imshow('dst', np.hstack((naza_gray, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值