注意:轮廓检测需要使用二值图像
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()