# Image Moments
可帮助您计算一些特征,例如对象的质心、对象的面积等。参考 Image Moments上的维基百科页面函数 cv.moments() 给出了所有计算出的矩值的字典。如下:
import numpy as np
import cv2 as cv
img = cv.imread('star.jpg',0)
ret,thresh = cv.threshold(img,127,255,0)
contours,hierarchy = cv.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv.moments(cnt)
print( M )
cv.moments()计算多边形或光栅化形状的三阶以内的所有力矩。该函数计算矢量形状或光栅化形状的 3 阶矩。结果在结构 cv::Moments 中返回。
1.质心
# 质心计算公式
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
# 打印质心坐标
print(cx, cy)
# 在图片中描绘质心,红色
img[cx-10:cx+10, cy-10:cy+10] = (255, 0, 0)
# 展示图片
plt.imshow(img), plt.axis("off")
plt.show()
结果图片如下(质心为红色小点):
2.周长和面积
周长:它也称为弧长。可以使用 cv.arcLength() 函数找到它。第二个参数指定形状是闭合轮廓(为 True时),还是只是曲线(为False时)。
面积:轮廓面积由函数 cv.contourArea() 或从moments中的M[‘m00’] 给出。
# 定义周长和面积列表
area = []
perimeter = []
for i in range(len(contours)):
# 储存周长和面积
area.append(cv.contourArea(contours[i]))
perimeter.append(cv.arcLength(contours[i], True))
# 对得到的周长和面积进行升序排序
sorted_area = np.sort(area)
sorted_perimeter = np.sort(perimeter)
print("sorted_area", sorted_area)
print("sorted_perimeter", sorted_perimeter)
3. 近似轮廓
根据我们指定的精度,它将轮廓形状近似为顶点数量较少的另一种形状。它是 Douglas-Peucker算法的实现。检查维基百科页面以获取算法和演示。为了理解这一点,假设您试图在图像中找到一个正方形,但由于图像中的一些问题,您没有得到一个完美的正方形,而是一个“坏形状”(如下面的第一张图片所示)。现在您可以使用此函数来近似形状。在此,第二个参数称为 epsilon,它是从轮廓到近似轮廓的最大距离。它是一个精度参数。需要明智地选择 epsilon 才能获得正确的输出。
参考以下示例:
img_c1, img_c2, img_c3 = img.copy(), img.copy(), img.copy() # 复制一个图片脚本
cnt = contours[0] # 选择第一个轮廓点向量
epsilon1 = 0.1 * cv.arcLength(cnt, True) # 选择轮廓近似阈值,0.1*周长,封闭图形
approx1 = cv.approxPolyDP(cnt, epsilon1, True) # 获得近似阈值轮廓
epsilon2 = 0.01 * cv.arcLength(cnt, True)
approx2 = cv.approxPolyDP(cnt, epsilon2, True)
img_contour = cv.drawContours(img_c1, [cnt], 0, (255, 0, 0), -1) # 填充原图轮廓
img_contour = cv.drawContours(img_c1, [approx1], 0, (0, 255, 0), 3) # 画出0.1近似轮廓
img_contour2 = cv.drawContours(img_c2, [cnt], 0, (255, 0, 0), -1) # 填充原图轮廓
img_contour2 = cv.drawContours(img_c2, [approx2], 0, (0, 255, 0), 3) # 画出0.01轮廓
# img_contour[cx-10:cx+10, cy-10:cy+10] = (255, 255, 255)
plt.subplot(131), plt.imshow(img, 'gray'), plt.title("Oringal")
plt.axis('off')
plt.subplot(132), plt.imshow(img_c1, ), plt.title("approx_contour")
plt.axis('off')
plt.subplot(133), plt.imshow(img_c2, ), plt.title("img_contour")
plt.axis('off')
plt.show()
下面,在第二张图中,绿线显示了 epsilon = 10% 弧长的近似曲线。第三张图显示了相同的 epsilon = 弧长的 1%。第三个参数指定曲线是否闭合。