本文基于opencv官方文档,是本人的学习笔记。版本是在linux下的opencv4.2.0,全部程序调通可运行,无bug。

# 模板匹配
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('wq.jpg', 0)
img2 = img.copy()
template = cv.imread('mouth.png', 0)
w, h = template.shape[::-1]
# 列表中所有的6种比较方法
methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR',
           'cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED']
for meth in methods:
    img = img2.copy()
    method = eval(meth)
    # 应用模板匹配
    res = cv.matchTemplate(img, template, method)
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
    # 如果方法是TM_SQDIFF或TM_SQDIFF_NORMED,则取最小值
    if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv.rectangle(img, top_left, bottom_right, 255, 2)
    plt.subplot(121), plt.imshow(res, cmap='gray')
    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
    plt.subplot(122), plt.imshow(img, cmap='gray')
    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)
    plt.show()

# 多对象的模板匹配
# 假设正在搜索具有多次出现的对象,
# 则cv.minMaxLoc()不会为您提供所有位置。
# 在这种情况下,我们将使用阈值化。
# 因此,在此示例中,我们将使用著名游戏Mario的屏幕截图,并在其中找到硬币。

img_rgb = cv.imread('mario.png')
img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
template = cv.imread('mario_coin.png', 0)
w, h = template.shape[::-1]
res = cv.matchTemplate(img_gray, template, cv.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]):
    cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
cv.imwrite('res.png', img_rgb)

# 图像分割
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('water_coins.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)

kernel = np.ones((5, 5), np.uint8)
closing = cv.morphologyEx(thresh, cv.MORPH_CLOSE, kernel)

# 噪声去除
kernel = np.ones((3, 3), np.uint8)
opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations=2)
# 确定背景区域
sure_bg = cv.dilate(opening, kernel, iterations=3)
# 寻找前景区域
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
# 找到未知区域
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg, sure_fg)

# 类别标记
ret, markers = cv.connectedComponents(sure_fg)
# 为所有的标记加1,保证背景是0而不是1
markers = markers + 1
# 现在让所有的未知区域为0
markers[unknown==255] = 0

markers = cv.watershed(img, markers)
img[markers==-1] = [0, 0, 255]

cv.imshow('ret', img)
cv.waitKey(0)
cv.destroyAllWindows()

img = cv.imread('chou.png')
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
rect = (75, 35, 380, 590)
cv.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2) | (mask==0), 0, 1).astype('uint8')
img = img * mask2[:, :, np.newaxis]
plt.imshow(img), plt.colorbar(), plt.show()

# newmask是我手动标记过的mask图像
newmask = cv.imread('chou.jpg', 0)
# 标记为白色(确保前景)的地方,更改mask = 1
# 标记为黑色(确保背景)的地方,更改mask = 0
mask[newmask==0] = 0
mask[newmask==255] = 1
mask, bgdModel, fgdModel = cv.grabCut(img, mask, None, bgdModel, fgdModel, 5, cv.GC_INIT_WITH_MASK)
mask = np.where((mask==2) | (mask==0), 0, 1).astype('uint8')
img = img * mask[:, :, np.newaxis]
plt.imshow(img), plt.colorbar(), plt.show()