轮廓检测 与 模板匹配

注意:轮廓检测需要使用二值图像

img_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

#为了更高的精确率使用二值图像,第一个返回值为127,即阈值,第二个为二值图像
_, img_bin = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)


#cv2.findContours(img, mode, method),其中img为图像,mode为轮廓的检索方式,如检索所有轮廓、只检索最外面的轮廓等
#method为轮廓的逼近方法,cv2.CHAIN_APPROX_NONE:以freeman链码的方式输出轮廓,所有其他方法输出多边形
#cv2.CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,只保留终点部分

#第二个返回值为轮廓
binary, contours, hie = cv2.findContours(img_bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

# 如果不用copy,将会把轮廓画到原图像,会改变原图像
img_draw = img1.copy()

#第三个参数为画第几个轮廓,-1为所有
img_ret = cv2.drawContours(img_draw, contours, -1, (0, 255, 0), 2)
cv2.imshow('img_ret', img_ret)


cv2.waitKey(0)
cv2.destroyAllWindows()

轮廓特征计算:

contours[i]表示第i个特征,计算特征时需要将每个轮廓单独拿出来

如计算第2个轮廓的面积

cv2.contourArea(contours[2])

计算周长

True表示是闭合的

cv2.arcLength(contours[2], True)

轮廓近似:

例如弧AB,连接AB得直线AB,找出弧AB中距离直线AB最远的点C,若C到直线AB的距离长度d小于所设定的阈值,则弧AB近似得直线AB

否则以C为分割点,分治

#epsilon相当于拟合程度,周长乘的数越小,和原来轮廓的拟合程度越高
epsilon = 0.01 * cv2.arcLength(contours[2], True)
img_appro = img1.copy()

#返回近似的轮廓
approx = cv2.approxPolyDP(contours[2], epsilon, True)

img_appro_ret = cv2.drawContours(img_appro, approx, -1, [0, 255, 0], 2)
cv2.imshow('img_appro_ret', img_appro_ret)
cv2.waitKey(0)
cv2.destroyAllWindows()

模板匹配:

模板匹配跟卷积原理很像,模板在原图像上从原点开始滑动,计算模板与 图像被模板覆盖的地方的差别程度,这个差别程度的计算方法在opencv里有6种,

然后将每次的计算结果放到一个矩阵中,作为结果输出,假设原图像是A * B的大小,模板是a * b的大小,则输出的结果矩阵为(A -  a + 1) * (B - b + 1)

第三个参数,匹配方法

使用不同的方法产生的结果的意义可能不太一样,有些返回的值越大表示匹配程度越好,而有些方法返回的值越小表示匹配程度越好。

关于参数 method:
CV_TM_SQDIFF 平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。
CV_TM_CCORR 相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。
CV_TM_CCOEFF 相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。
CV_TM_SQDIFF_NORMED 归一化平方差匹配法

CV_TM_CCORR_NORMED 归一化相关匹配法

CV_TM_CCOEFF_NORMED 归一化相关系数匹配法

也可以用阿拉伯数字代替

img1 = cv2.imread('C:/Users/Dell/Downloads/1.jpg')
img_temp = cv2.imread('C:/Users/Dell/Downloads/4.jpg')
img_c = img1.copy()

#模板图片的长和宽
w, h = img_temp.shape[ : 2]

#返回匹配矩阵
ret = cv2.matchTemplate(img1, img_temp, 1)


#返回矩阵中的最小值、最大值、最小值坐标、最大值坐标
min_v, max_v, min_id, max_id = cv2.minMaxLoc(ret)

#求要画的矩形框的右下角坐标,如果是平方差匹配TM_SQDIFF或者归一化平方差匹配TM_SQDIFF_NORED使用min_id,否则使用max_id
right_low = (min_id[0] + w, min_id[1] + h)

cv2.rectangle(img_c, min_id, right_low, (0, 0, 255), 2)

cv2.imshow('img_c', img_c)
cv2.waitKey(0)
cv2.destroyAllWindows()

匹配多个对象:

img_temp = cv2.imread('C:/Users/Dell/Downloads/4.jpg')
img_c = img1.copy()

w, h = img_temp.shape[ : 2]

match_degree = cv2.matchTemplate(img_c, img_temp, 3)

#返回小于等于0.2的坐标,如果非平方差匹配,用大于等于
ret = np.where(match_degree <= 0.2)

for pt in zip(*ret[:: -1]):
    right_low = (pt[0] + w, pt[1] + h)
    cv2.rectangle(img_c, pt, right_low, (0, 0, 255), 1)

cv2.imshow('kk', img_c)
cv2.waitKey(0)
cv2.destroyAllWindows()
自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
原文地址:https://www.cnblogs.com/WTSRUVF/p/15256975.html