比较两个轮廓最简单的方法是比较二者的轮廓矩。轮廓矩代表了一个轮廓、一幅图像、一 组点集的全局特征。矩信息包含了对应对象不同类型的几何特征,例如大小、位置、角度、形 状等。矩特征被广泛地应用在模式识别、图像识别等方面。
1. 矩的计算:moments函数
OpenCV 提供了函数 cv2.moments()来获取图像的 moments 特征。通常情况下,我们将使用 函数 cv2.moments()获取的轮廓特征称为“轮廓矩”。轮廓矩描述了一个轮廓的重要特征,使用 轮廓矩可以方便地比较两个轮廓。
函数 cv2.moments()的语法格式为:
retval = cv2.moments( array[, binaryImage] )
式中有两个参数:
- array:可以是点集,也可以是灰度图像或者二值图像。当 array 是点集时,函数会把这 些点集当成轮廓中的顶点,把整个点集作为一条轮廓,而不是把它们当成独立的点来看 待。
- binaryImage:该参数为 True 时,array 内所有的非零值都被处理为 1。该参数仅在参数 array 为图像时有效。
【例 12.4】使用函数 cv2.moments()提取一幅图像的特征。
import cv2
import numpy as np
img = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/moments.bmp")
cv2.imshow("orginal",img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
n = len(contours)
contoursImg = []
for i in range(n):
temp = np.zeros(img.shape,np.uint8)
contoursImg.append(temp)
contoursImg[i] = cv2.drawContours(contoursImg[i],contours,i,(255,255,255),3)
cv2.imshow("contours="+str(i),contoursImg[i])
print("观察各个轮廓的距(moments):")
for i in range(n):
print("轮廓"+str(i)+"的距:\n",cv2.moments(contours[i]))
print("观察各个轮廓的面积:")
for i in range(n):
print("轮廓"+str(i)+"的面积:%d"%cv2.moments(contours[i])['m00'])
cv2.waitKey()
cv2.destroyAllWindows()
2. 计算轮廓的长度:arcLength函数
函数 cv2.arcLength()用于计算轮廓的长度,其语法格式为:
retval = cv2.arcLength( curve, closed )
式中返回值 retval 是轮廓的长度(周长)。 上式中有两个参数:
- curve 是轮廓。
- closed 是布尔型值,用来表示轮廓是否是封闭的。该值为 True 时,表示轮廓是封闭的。
【例 12.7】将一幅图像内长度大于平均值的轮廓显示出来。
img = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/contours0.bmp")
cv2.imshow("orginal",img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#! 获取轮廓
ret,binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#! 计算各轮廓的长度之和,平均长度
n = len(contours) #? 获取轮廓的个数
cntLen = [] #? 存储各轮廓的长度
for i in range(n):
cntLen.append(cv2.arcLength(contours[i],True))
print("第"+str(i)+"个轮廓的长度为:%d"%cntLen[i])
cntLenSum = np.sum(cntLen) #? 各轮廓的长度之和
cntLenAvr = cntLenSum/n #? 轮廓长度的平均值
print("轮廓的总长度为:%d"%cntLenSum)
print("轮廓的平均长度为:%d"%cntLenAvr)
#! 显示长度超过平均值的轮廓
contoursImg = []
for i in range(n):
temp = np.zeros(img.shape,np.uint8)
contoursImg.append(temp)
contoursImg[i] = cv2.drawContours(contoursImg[i],contours,i,(255,255,255),3)
if cntLen[i] > cntLenAvr:
cv2.imshow("contours["+str(i)+"]",contoursImg[i])
cv2.waitKey()
cv2.destroyAllWindows()