OpenCV基于Python图像轮廓——轮廓属性

轮廓属性

  • 目标
  • 1. 常见的轮廓属性
    • 1.1 长宽比
    • 1.2 范围
    • 1.3 坚实度
    • 1.4 等效直径
    • 1.5 方向
    • 1.6 掩码和像素点
    • 1.7 最大值,最小值及其位置
    • 1.8 平均颜色或平均强度
    • 1.9 极端点
  • 2. 更多属性
    • 2.1 凸性缺陷
    • 2.2 点多边形测试
    • 2.3 形状匹配

目标

在上一篇文章Opencv基于Python图像轮廓——轮廓绘制及其特征中,我们已经学习到了轮廓的一些特征,如质心、面积、周长等。在本篇文章,我们将继续学习到以下内容:

  • 提取一些常用的物体属性,如坚实度,等效直径,掩模图像,平均强度等
  • 图像轮廓的凸性缺陷以及如何找到它们
  • 查找点到多边形的最短距离
  • 匹配不同的形状

1. 常见的轮廓属性

1.1 长宽比

它是图象边界矩形的宽度与高度的比值。
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

1.2 范围

范围是轮廓区域面积与边界矩形区域面积的比值。
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

1.3 坚实度

坚实度是轮廓线面积与其凸包面积之比。
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

1.4 等效直径

等效直径是面积与轮廓面积相等的圆的直径。
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

1.5 方向

取向是物体指向的角度。以下方法还给出了主轴和副轴的长度。

# 方向
(x, y), (MA, ma), angle = cv.fitEllipse(cnt)
print((x, y), (MA, ma), angle)

(269.22100830078125, 255.53665161132812) (34.14046859741211, 225.88348388671875) 139.3023223876953

1.6 掩码和像素点

在某些情况下,我们可能需要构成该对象的所有点,可以按照以下步骤完成:

# 轮廓的掩膜与像素点
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)

OpenCV基于Python图像轮廓——轮廓属性_第1张图片

这里提供了两个方法,一个使用Numpy函数,另一个使用OpenCV函数(最后的注释行)。结果也是一样的,只是略有不同。Numpy给出的坐标是 (行、列)格式,而OpenCV给出的坐标是(x,y)格式。所以基本上结果是可以互换的。注意, row = x, column = y

1.7 最大值,最小值及其位置

我们可以使用掩码图像找到这些参数。

# 最大值和最小值及其位置
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)

1.8 平均颜色或平均强度

在这里,我们可以找到对象的平均颜色,或者可以是灰度模式下物体的平均强度,我们再次使用相同的掩码进行此操作。

# 平均颜色及平均灰度
mean_val = cv.mean(img, mask=mask)
print(mean_val)

(255.0, 0.0, 0.0, 0.0)

1.9 极端点

极点是指对象的最顶部,最底部,最右侧和最左侧的点。

# 极端点
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)

2. 更多属性

2.1 凸性缺陷

我们已经在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()

OpenCV基于Python图像轮廓——轮廓属性_第2张图片

2.2 点多边形测试

这个函数找出图像中一点到轮廓线的最短距离。它返回的距离,点在轮廓线外时为负,点在轮廓线内时为正,点在轮廓线上时为零。

例如,我们可以检查点 (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倍。

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)

1.1241123297334
OpenCV基于Python图像轮廓——轮廓属性_第3张图片
此匹配结果值较高,说明了匹配效果较差

你可能感兴趣的:(opencv,计算机视觉,python)