开启成长之旅!这是我参与「日新计划 2 月更文应战」的第 19 天,点击查看活动详情

方针

在本文中,将学习

  • 如何找到概括的不同特征,例如面积,周长,质心,鸿沟框等。
  • 将看到很多与概括有关的函数

图画矩

图画矩是指图画的某些特定像素灰度的加权平均值(矩),或者是图画具有类似功用或意义的特点, 能够帮助计算一些特征,例如物体的质心,物体的面积等。函数cv2.moments()供给了所有计算出的矩值。见下文:

import cv2
import numpy as np
img = cv2.imread('start.png', 0)
ret, thresh = cv2.threshold(img, 127, 255, 0)
contours, hierarchy = cv2.findContours(thres, 1, 2)
cnt = contours[0]
M = cv2.moments(cnt)
print(M)

{‘m00’: 13724.5, ‘m10’: 1797933.3333333333, ‘m01’: 1873571.8333333333, ‘m20’: 246067666.25, ‘m11’: 245442859.54166666, ‘m02’: 279142772.0833333, ‘m30’: 34995570121.700005, ‘m21’: 33592122871.399998, ‘m12’: 36568730961.566666, ‘m03’: 44488834889.950005, ‘mu20’: 10535277.37527883, ‘mu11’: 1695.8166170418262, ‘mu02’: 23375974.410556376, ‘mu30’: -729.2795791625977, ‘mu21’: 258212.5407886505, ‘mu12’: 80070.37276697159, ‘mu03’: -11313.452514648438, ‘nu20’: 0.055931042112529486, ‘nu11’: 9.002970424438718e-06, ‘nu02’: 0.12410139406924131, ‘nu30’: -3.304857392468866e-08, ‘nu21’: 1.170135087607162e-05, ‘nu12’: 3.628528357540433e-06, ‘nu03’: -5.126887992711116e-07}

此时,能够提取有用的数据,例如面积,质心等。 质心由联系给出 Cx=M10M00C_x = \frac{M_{10}}{M_{00}} Cy=M01M00C_y = \frac{M_{01}}{M_{00}}

能够按照以下步骤进行:

cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])

概括面积

概括区域由函数cv2.contourArea()或从矩M['m00']中给出。

area = cv2.contourArea(cnt)
area = int(M['m00'])

概括周长

周长也被称为弧长。能够运用cv2.arcLength()函数找到它。第二个参数指定形状是闭合概括(True)还是曲线。

perimeter = cv2.arcLength(cnt, True)

概括近似

根据指定的精度,能够将概括形状近似为极点数量较少的其他形状。它是Douglas-Peucker算法(是一种将线段组成的曲线降采样为点数较少的类似曲线的算法)的实现。

为了理解这一点,假设企图在图画中找到一个正方形,可是因为图画中的某些问题,没有得到一个完美的正方形,而是一个“坏形状”(如下图所示)。现在,能够运用此函数来近似形状。 在这种状况下,第二个参数称为epsilon,它是从概括到近似概括的最大距离, 是一个精度参数。需求正确选择epsilon才能取得正确的输出。

epsilon = 0.1*cv.arcLength(cnt,True)
approx = cv.approxPolyDP(cnt,epsilon,True)

下面,在第二张图片中,绿线显现了=弧长*0.1时的近似曲线。第三幅图显现了=弧长*0.01时的状况。第三个参数指定曲线是否闭合。

OpenCV 17: 轮廓特征

概括凸包

凸包外观看起来与概括迫临类似,但不类似(在某些状况下两者或许供给相同的成果)。cv2.convexHull()函数查看曲线是否存在凸凹缺点并对其进行校对。一般而言,凸曲线是一直凸出或至少平坦的曲线。假如在内部凸出,则称为凸度缺点。例如,查看下面的手的图画。红线显现手的凸包。双向箭头标记显现凸度缺点,这是凸包与概括线之间的局部最大偏差。

OpenCV 17: 轮廓特征

函数参数:

hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]] 参数详细信息: *points:传递到的概括。

  • hull: 输出
  • clockwise:方向标记。假如为True,则输出凸包为顺时针方向。不然,其方向为逆时针方向。
  • returnPoints:默认状况下为True。然后回来凸包的坐标。假如为False,则回来与凸包点相对应的概括点的索引

简化版: hull = cv.convexHull(cnt)

可是,假如要查找凸度缺点,则需求传递returnPoints = False。为了理解它,以上面的矩形图画为例。

  • 首先,获取它的概括为cnt
  • 之后,获取returnPoints = True的凸包,得到以下值:[[[234 202]],[[51 202]],[[51 79]],[[234 79]]],它们是四个角矩形的点。
  • 可是,returnPoints = False履行相同的操作,则会得到以下成果:[[129],[67],[0],[142]]这些是概括中相应点的索引。例如,查看第一个值:cnt [129] = [[234,202]]与第一个成果相同(对于其他成果依此类推)。

查看凸度

cv2.isContourConvex()具有查看曲线是否凸出的函数。它仅仅回来True还是False

k = cv.isContourConvex(cnt)

鸿沟矩形

有两种类型的鸿沟矩形。

OpenCV 17: 轮廓特征

1.直角矩形

它是一个矩形,不考虑物体的旋转。所以鸿沟矩形的面积不是最小的。它是由函数cv2.boundingRect()找到的

cv2.boundingRect(img) img是一个二值图,也就是它的参数; 回来四个值,分别是x,y,w,h;x,y是矩阵左上点的坐标,w,h是矩阵的宽和高

import cv2
import numpy as np
img = cv2.imread('box.png', 0)
ret, thresh = cv2.threshold(img, 127, 255, 0)
cnt, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
x, y, w, h = cv2.boundingRect(cnts[0])
cv2.rectangle(img, (x, y), (x+w, y+h), (0,255,0), 2)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV 17: 轮廓特征

2.旋转矩形

鸿沟矩形是用最小面积绘制的,所以它考虑了旋转。运用的函数是cv2.minAreaRect()。它回来一个Box2D结构,其间包括以下细节 (中心(x,y),(宽度,高度),旋转角度)。但要画出这个矩形,咱们需求矩形的四个角。它由函数cv2.boxPoints()取得

img = cv2.imread('approx.png', 0)
ret, thresh = cv2.threshold(img, 127, 250, 0)
cnt, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
rect = cv2.minAreaRect(cnt[0])
box = cv2.boxPoints(rect)
box = np.int64(box)
cv2.drawContours(img, [box], 0, (255,255,0), 2)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

两个矩形都显现在一张单独的图画中。绿色矩形显现正常的鸿沟矩形。红色矩形是旋转后的矩形。

OpenCV 17: 轮廓特征

最小闭合圈

接下来,运用函数cv2.minEnclosingCircle()查找目标的圆。它是一个以最小面积彻底掩盖物体的圆

img = cv2.imread('approx.png', 0)
ret, thresh = cv2.threshold(img, 127, 250, 0)
cnt, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
(x, y), radius = cv2.minEnclosingCircle(cnt[0])
center = (int(x), int(y))
radius = int(radius)
cv2.circle(img, center, radius, (255,255,0), 2)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV 17: 轮廓特征

拟合一个椭圆

下一个是把一个椭圆拟合到一个物体上。它回来内接椭圆的旋转矩形。

img = cv2.imread('approx.png', 0)
ret, thresh = cv2.threshold(img, 127, 250, 0)
cnt, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
ellipse = cv2.fitEllipse(cnt[0])
cv2.ellipse(img, ellipse, (255,255,0), 3)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV 17: 轮廓特征

拟合直线

相同,能够将一条直线拟合到一组点。下图包括一组白点。咱们能够近似一条直线。

import cv2
# 直线
import cv2
img = cv2.imread('approx.png', 0)
rows, cols = img.shape[:2]
ret, thresh = cv2.threshold(img, 127, 250, 0)
cnt, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
[vx,vy,x,y] = cv2.fitLine(cnt[0], cv2.DIST_L2, 0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
cv2.line(img,(cols-1,righty),(0,lefty),(255,255,0),2)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV 17: 轮廓特征

附加资源

  • zh.wikipedia.org/wiki/%E7%9F…
  • docs.opencv.org/4.1.2/dd/d4…