当前位置:   article > 正文

【OpenCV-图像处理】图像轮廓2(轮廓特征)——OpenCV官方教程翻译(全网最详细)_cv2 轮廓

cv2 轮廓

一、目标

  • 找出轮廓的不同特征,如面积、周长、质心、边框等
  • 您将看到一些与轮廓线相关的函数cv2.moments() 、cv2.contourArea() 、cv2.arcLength() 、cv2.approxPolyDP()、cv2.convexHull()、cv2.isContourConvex()、cv2.boundingRect()、cv.boxPoints()、cv2.minEnclosingCircle()、cv2.circle()、cv2.fitEllipse()、cv2.ellipse、cv2.fitLine()、cv2.line()。

二、图像特征

2.1图像矩(Moments)

图像矩帮助你计算一些特征,如物体的质心,物体的面积等。

retval = cv2.moments	(	InputArray 	array,
							bool 	binaryImage = false 
)	
  • 1
  • 2
  • 3

计算多边形或栅格化形状的三阶以下的所有矩。

该函数计算矢量形状或栅格化形状的三阶矩。结果以cv2.Moments结构返回。

参数说明
array光栅图像(单通道,8位或浮点二维数组)或二维点(Point或Point2f)的数组(1×N或N×1)。
binaryImage如果为真,所有非零的图像像素都被视为1。该参数仅用于图像。

注意:仅适用于Python绑定的轮廓矩计算:请注意输入数组的numpy类型应该是np.int32或np.float32。

cv2.moments()举例演示

函数cv2.moments()给出了一个包含所有计算的矩值的字典。见下文:

#图像特征
import numpy as np
import cv2
img = cv2.imread('contours.png',0)
ret,thresh = cv2.threshold(img,127,255,0)
im2,contours,hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]		#选择第一个轮廓
M = cv2.moments(cnt)
print( M )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行结果:

{'m00': 6767.5, 'm10': 814777.6666666666, 'm01': 2387402.333333333, 'm20': 102820765.08333333, 'm11': 289971947.5416666, 'm02': 847682115.4166666, 'm30': 13587335639.2, 'm21': 36921824181.683334, 'm12': 103807857632.48334, 'm03': 302810377436.8, 'mu20': 4725065.622856379, 'mu11': 2539054.664254248, 'mu02': 5467131.86211288, 'mu30': 70406352.8231411, 'mu21': 37884093.78841543, 'mu12': -40822993.16253698, 'mu03': -87701174.08795166, 'nu20': 0.10316949757794143, 'nu11': 0.0554390171359535, 'nu02': 0.11937215108254287, 'nu30': 0.01868706888681732, 'nu21': 0.010055096478539381, 'nu12': -0.010835131416488656, 'nu03': -0.02327741483432793}
  • 1

这时,你可以提取有用的数据,如面积,质心等。质心由下面的关系给出,
在这里插入图片描述
可以这样写:

cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print( 'cx=%f'%(cx) )
print( 'cy=%f'%(cy) )
  • 1
  • 2
  • 3
  • 4

运行结果:

cx=120.000000
cy=352.000000
  • 1
  • 2

2.2轮廓面积(Contour Area)

轮廓线面积由函数cv.contourArea()或矩M[‘m00’]给出。

retval = cv2.contourArea	(	InputArray 	contour,
								bool 	oriented = false 
)	
  • 1
  • 2
  • 3

计算轮廓线面积。

该函数计算轮廓面积。与力矩相似,面积是用绿色公式计算的。因此,如果您使用drawContoursfillPoly绘制轮廓,返回的区域和非零像素的数量可能是不同的。此外,对于具有自交点的轮廓,该函数几乎肯定会给出错误的结果。

参数说明
contour二维点(轮廓顶点)的输入向量
oriented面向区域标志。如果为真,函数返回一个带符号的面积值,这取决于轮廓方向(顺时针方向或逆时针方向)。使用此特性,您可以通过取一个区域的符号来确定轮廓的方向。默认情况下,该参数为false,这意味着返回绝对值。

cv2.contourArea()举例演示

#轮廓面积
area = cv2.contourArea(cnt)
print('area=%f'%(area))
  • 1
  • 2
  • 3

运行结果:

area=6767.500000
  • 1

2.3轮廓周长(Contour Perimeter)

也叫弧长。可以使用cv.arcLength()函数来查找。第二个参数指定shape是封闭轮廓(如果传递值为True),否则仅仅是一条曲线。

retval = cv2.arcLength	(	InputArray 	curve,
							bool 	closed 
)	
  • 1
  • 2
  • 3

计算轮廓周长或曲线长度。

该函数计算曲线长度或封闭轮廓周长。

参数说明
curve二维点的输入向量
closed指示曲线是否闭合的标志。

cv2.arcLength()举例演示

#轮廓周长
perimeter = cv2.arcLength(cnt,True)
print('perimeter=%f'%(perimeter))
  • 1
  • 2
  • 3

运行结果:

perimeter=395.806138
  • 1

2.4轮廓近似(Contour Approximation)

它将一个轮廓形状近似为另一个具有较少顶点数的形状,这取决于我们指定的精度。它是Douglas-Peucker算法的一个实现。

为了理解这一点,假设你试图在图像中找到一个正方形,但由于图像中的一些问题,你没有得到一个完美的正方形,而是一个“坏形状”(如下面的第一张图像所示)。现在你可以使用这个函数来近似形状。在这里,第二个参数叫做,它是轮廓到近似轮廓的最大距离。它是一个精度参数。为了得到正确的输出,需要明智地选择。

approxCurve = cv2.approxPolyDP	(	InputArray 	curve,
									double 	epsilon,
									bool 	closed 
)	
  • 1
  • 2
  • 3
  • 4

以指定的精度近似多边形曲线。

函数cv2.approxPolyDP将一条曲线或一个多边形近似为另一条拥有较少顶点的曲线或多边形,从而它们之间的距离小于或等于指定的精度。它使用的是道格拉斯-派克算法http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm

参数说明
curve二维点的输入向量
approxCurve近似结果。类型应与输入曲线的类型匹配。
epsilon指定近似精度的参数。这是原始曲线与其近似值之间的最大距离。
closed如果为真,则近似的曲线是闭合的(它的第一个顶点和最后一个顶点是连接的)。否则,它不是闭合的。

cv2.approxPolyDP()举例演示

#轮廓近似
epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
  • 1
  • 2
  • 3

在下面的第二幅图中,绿线表示=弧长10%时的近似曲线。第三张图是相同的,当= 1%的弧长。第三个参数指定曲线是否关闭。
在这里插入图片描述

2.5 轮廓凸包(Convex Hull)

凸包看起来与轮廓近似相似,但不是(两者在某些情况下可能提供相同的结果)。这里,cv.convexHull()函数检查曲线的凹凸性缺陷并予以纠正。一般来说,凸曲线是总是向外凸出的曲线,或者至少是平坦的曲线。如果是内部凸起的,叫做凹凸缺陷。
例如,检查下面的手的图像。红线表示手的凸壳。双面箭头标志表明了凸包的凸性缺陷,即凸包与轮廓的局部最大偏差。
在这里插入图片描述

hull = cv2.convexHull	(	InputArray 	points,
						bool 	clockwise = false,
						bool 	returnPoints = true 
)	
  • 1
  • 2
  • 3
  • 4

求点集的凸包。

函数cv2.convexHull使用Sklansky的算法[165]找到一个二维点集的凸包,在当前的实现中具有O(N logN)复杂度。

参数说明
points二维点的输入向量
hull输出凸包。它要么是指标的整数向量,要么是点的向量。在第一种情况下,包元素是原始数组中凸包点的基于0的指标(因为凸包点集是原始点集的子集)。在第二种情况下,包元素是凸包点本身。
clockwise定位标志。如果为真,则输出凸壳为顺时针方向。反之,则为逆时针方向。假设坐标系的X轴向右,Y轴向上。
returnPoints操作标记。对于矩阵,当标志为真时,函数返回凸包点。否则,它返回凸包点的索引。当输出数组为std::vector时,该标志会被忽略,并且输出取决于vector的类型:std::vector暗示返回点=false, std::vector暗示返回点=true。

参数说明:
points 就是我们穿过的轮廓。
hull是输出,通常我们会避开它。
clockwise:方向标志。如果为真,则输出凸壳为顺时针方向。反之,则为逆时针方向。
returnPoints:默认为True。然后它返回船体点的坐标。如果为False,则返回与船体点对应的轮廓点的索引。

注意:点和凸包是不同的数组,不支持就地处理。

cv2.convexHull()举例演示

因此,要得到如上图所示的凸包,以下就足够了:

hull = cv2.convexHull(cnt)
  • 1

但是如果你想找到凸性缺陷,你需要传递returnPoints = False。为了理解它,我们将使用上面的矩形图像。首先我发现它的轮廓是cnt。现在我找到了它的凸壳与returnPoints = True,我得到了以下值:[[[234 202]],[[51 202]],[[51 79]],[[234 79]],这是矩形的四个角点。现在,如果对returnPoints = False执行同样的操作,我将得到以下结果:[[129],[67],[0],[142]]。这些是等高线中相应点的指数。例如,检查第一个值:cnt[129] =[[234, 202]],这个值与第一个结果相同(其他结果也是如此)。

2.6 检查凹凸性(Checking Convexity)

bool retval	=	cv2.isContourConvex(
										InputArray contour	
	)
  • 1
  • 2
  • 3

测试轮廓的凹凸性。

该函数测试输入轮廓是否为凸轮廓。轮廓必须是简单的,即没有自交点。否则,函数输出是未定义的。

cv2.isContourConvex()举例演示

k = cv.isContourConvex(cnt)
  • 1

2.7 轮廓矩形边框(Bounding Rectangle)

有两种类型的边界矩形。

2.7.1 直边界矩形

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

retval	=	cv2.boundingRect(	
								InputArray points	
)
  • 1
  • 2
  • 3

计算点集的右上边框。

该函数计算并返回指定点集的最小向上边框。

参数说明
points二维点的输入向量
cv2.boundingRect()举例演示

设(x,y)为矩形的左上角坐标,(w,h)为矩形的宽、高。

#轮廓矩形
def cv_show(img,name):
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()

x,y,w,h = cv2.boundingRect(cnt)
im = cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
cv_show(im,'im')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行结果:
在这里插入图片描述

2.7.2 旋转矩形边界(Rotated Rectangle)

在这里,边框是用最小面积绘制的,所以也考虑了旋转。使用的函数是cv2.minarearerect()。它返回一个Box2D结构,其中包含以下细节——(中心(x,y),(宽度,高度),旋转角度)。但是为了画出这个矩形,我们需要矩形的4个角。它由cv2.boxPoints()函数获得

retval = cv2.minAreaRect	(
								InputArray 	points	
)	
  • 1
  • 2
  • 3

找到一个旋转的包含输入2D点集的最小区域的矩形。

该函数计算并返回指定点集的最小区域边界矩形(可能是旋转的)。开发人员应该记住,当数据接近包含的Mat元素边界时,返回的RotatedRect可以包含负的索引。

参数说明
points二维点的输入向量
points = cv2.boxPoints	(	RotatedRect 	box,
)	
  • 1
  • 2

查找旋转矩形的四个顶点。用于绘制旋转矩形。

这个函数找到一个旋转后的矩形的四个顶点。这个函数在绘制矩形时很有用。

参数说明
box输入的旋转矩形
points矩形的四个顶点的输出数组。
cv2.minarearerect()、cv2.boxPoints()举例演示
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img,[box],0,(0,0,255),2)
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

2.8 最小封闭圆(Minimum Enclosing Circle)

接下来,我们使用cv2.minEnclosingCircle()函数找到一个对象的外圈。它是一个用最小面积完全覆盖物体的圆。

cv2.minEnclosingCircle()、cv2.circle()举例演示

(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv2.circle(img,center,radius,(0,255,0),2)
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

2.9 拟合椭圆(Fitting an Ellipse)

下一个是将椭圆与物体相匹配。它返回椭圆内接的旋转矩形。

cv2.fitEllipse()、cv2.ellipse举例演示

ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img,ellipse,(0,255,0),2)
  • 1
  • 2

在这里插入图片描述

2.9 拟合一条直线(Fitting a Line)

类似地,我们可以将一条直线拟合到一组点上。下图包含一组白点。我们可以近似出一条直线到它。

cv2.fitLine()、cv2.line()举例演示

rows,cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv.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),(0,255,0),2)
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
主要参考于OpenCV官方网站:http://www.opencv.org.cn/

目前博主已更新OpenCV平滑处理函数、形态学操作函数的详细介绍,链接如下:
【OpenCV-图像处理】图像平滑处理函数

【OpenCV-图像处理】形态学变换函数

【OpenCV-图像处理】图像阈值处理

【OpenCV-图像处理】如何计算图像梯度,以及如何使用梯度来检测边缘

【OpenCV-图像处理】Canny 边缘检测

【OpenCV-图像处理】图像金字塔

【OpenCV-图像处理】图像轮廓1(寻找、绘制轮廓)

<后续还会继续翻译和整理【OpenCV-图像处理】相关内容,如果需要,可持续关注我哦~>

<翻译和整理不易,留个赞或评论支持一下我吧^^>

如有疑问,欢迎批评指正^^

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/653575
推荐阅读
相关标签
  

闽ICP备14008679号