在上一篇文章Opencv基于Python图像轮廓——轮廓绘制及其特征中,我们已经学习到了轮廓的一些特征,如质心、面积、周长等。在本篇文章,我们将继续学习到以下内容:
它是图象边界矩形的宽度与高度的比值。
A s p e c t R a t i o = W i d t h H e i g h t Aspect \; Ratio = \frac{Width}{Height} AspectRatio=HeightWidth
以下代码结果是基于上篇文章Opencv基于Python图像轮廓——轮廓绘制及其特征得到的。
# 宽高比
x, y, w, h = cv.boundingRect(cnt)
aspect_ratio = float(w)/h
print(aspect_ratio)
0.891156462585034
范围是轮廓区域面积与边界矩形区域面积的比值。
E x t e n t = O b j e c t A r e a B o u n d i n g R e c t a n g l e A r e a Extent = \frac{Object \; Area}{Bounding \; Rectangle \; Area} Extent=BoundingRectangleAreaObjectArea
# 轮廓面积与边界矩形面积的比
area = cv.contourArea(cnt)
x, y, w, h = cv.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area
print(extent)
0.25502414706340554
坚实度是轮廓线面积与其凸包面积之比。
S o l i d i t y = C o n t o u r A r e a C o n v e x H u l l A r e a Solidity = \frac{Contour \; Area}{Convex \; Hull \; Area} Solidity=ConvexHullAreaContourArea
# 轮廓面积与凸包面积的比
area = cv.contourArea(cnt)
hull = cv.convexHull(cnt)
hull_area = cv.contourArea(hull)
solidity = float(area)/hull_area
print(solidity)
0.9522055259331071
等效直径是面积与轮廓面积相等的圆的直径。
E q u i v a l e n t D i a m e t e r = 4 × C o n t o u r A r e a π Equivalent \; Diameter = \sqrt{\frac{4 \times Contour \; Area}{\pi}} EquivalentDiameter=π4×ContourArea
# 与轮廓面积相等的圆形直径
area = cv.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)
print(equi_diameter)
79.07515035834193
取向是物体指向的角度。以下方法还给出了主轴和副轴的长度。
# 方向
(x, y), (MA, ma), angle = cv.fitEllipse(cnt)
print((x, y), (MA, ma), angle)
(269.22100830078125, 255.53665161132812) (34.14046859741211, 225.88348388671875) 139.3023223876953
在某些情况下,我们可能需要构成该对象的所有点,可以按照以下步骤完成:
# 轮廓的掩膜与像素点
img = cv.imread('./data/boundingRect.png', 0)
mask = np.zeros(img.shape, np.uint8)
mask = cv.drawContours(mask, [cnt], 0, 255, -1)
cv.imshow('mask', mask)
cv.waitKey(0)
cv.destroyAllWindows()
pixelpoints = np.transpose(np.nonzero(mask))
#pixelpoints = cv.findNonZero(mask)
这里提供了两个方法,一个使用Numpy函数,另一个使用OpenCV函数(最后的注释行)。结果也是一样的,只是略有不同。Numpy给出的坐标是 (行、列)
格式,而OpenCV给出的坐标是(x,y)
格式。所以基本上结果是可以互换的。注意, row = x, column = y
。
我们可以使用掩码图像找到这些参数。
# 最大值和最小值及其位置
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(img, mask=mask)
print(min_val, max_val, min_loc, max_loc)
255.0 255.0 (225, 183) (225, 183)
在这里,我们可以找到对象的平均颜色,或者可以是灰度模式下物体的平均强度,我们再次使用相同的掩码进行此操作。
# 平均颜色及平均灰度
mean_val = cv.mean(img, mask=mask)
print(mean_val)
(255.0, 0.0, 0.0, 0.0)
极点是指对象的最顶部,最底部,最右侧和最左侧的点。
# 极端点
leftmost = tuple(cnt[cnt[:, :, 0].argmin()][0])
rightmost = tuple(cnt[cnt[:, :, 0].argmax()][0])
topmost = tuple(cnt[cnt[:, :, 1].argmin()][0])
bottommost = tuple(cnt[cnt[:, :, 1].argmax()][0])
print (leftmost, rightmost, topmost, bottommost)
(204, 202) (334, 307) (225, 183) (312, 329)
我们已经在Opencv基于Python图像轮廓——轮廓绘制及其特征中学习到关于轮廓的凸包。从这个凸包上的任何偏差都可以被认为是凸性缺陷。OpenCV有一个函数来找到这个,cv.convexityDefects()。一个基本的函数调用如下:
hull = cv.convexHull(cnt,returnPoints = False)
defects = cv.convexityDefects(cnt,hull)
注意: 我们必须在发现凸包时,传递
returnPoints= False
,以找到凸性缺陷。
它返回一个数组,其中每行包含这些值——[起点、终点、最远点、到最远点的近似距离]。我们可以用图像把它形象化。我们画一条连接起点和终点的线,然后在最远处画一个圆。记住,返回的前三个值是cnt的索引。所以我们必须从cnt中获取这些值。
import numpy as np
import cv2 as cv
img = cv.imread('./data/convexityDefects.png')
imggray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imggray, 127, 255, cv.THRESH_OTSU)
img2, contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cnt = contours[1]
hull = cv.convexHull(cnt, returnPoints=False)
defects = cv.convexityDefects(cnt, hull)
for i in range(defects.shape[0]):
s, e, f, d = defects[i, 0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
cv.line(img, start, end, [0, 255, 0], 3)
cv.circle(img, far, 5, [0, 0, 255], -1)
cv.imshow('convexityDefects', img)
cv.waitKey()
cv.destroyAllWindows()
这个函数找出图像中一点到轮廓线的最短距离。它返回的距离,点在轮廓线外时为负,点在轮廓线内时为正,点在轮廓线上时为零。
例如,我们可以检查点 (50,50)
如下:
dist = cv.pointPolygonTest(cnt,(50,50),True)
在函数中,第三个参数是measureDist。如果它是真的,它会找到有符号的距离。如果为假,则查找该点是在轮廓线内部还是外部(分别返回+1、-1和0)。
# 点多边形测试
dist = cv.pointPolygonTest(cnt, (50, 50), True)
print(dist)
-202.71408436514716
注意: 如果你不想找到距离,请确保第三个参数为False,因为这是一个耗时的过程。因此,将其设置为False可使速度提高2-3倍。
OpenCV附带一个函数cv.matchShapes(),该函数使我们能够比较两个形状或两个轮廓,并返回一个显示相似性的度量,结果越低,匹配越好,它是根据矩值计算出来的。
import cv2 as cv
import numpy as np
img1 = cv.imread('./data/convexityDefects.png', 0)
img2 = cv.imread('./data/matchShapes.png', 0)
ret, thresh = cv.threshold(img1, 127, 255, 0)
ret, thresh2 = cv.threshold(img2, 127, 255, 0)
img2, contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cnt1 = contours[1]
img2, contours, hierarchy = cv.findContours(thresh2, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cnt2 = contours[1]
ret = cv.matchShapes(cnt1, cnt2, 1, 0.0)
print(ret)