ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

OpenCV-Python -- Contour Features

2020-11-25 20:58:40  阅读:154  来源: 互联网

标签:cnt img Python image cv2 OpenCV -- 轮廓 255


学习目标

  • 寻找不同的轮廓特征,比如面积,周长,重心,边框
  • 与轮廓相关的函数

矩(Moments)

图像矩可以帮助计算一些特征,比如目标对象的质心,对象的面积等。cv2.moments()返回一个字典,包含计算的矩值,下面介绍该函数的使用:

def moments(array, binaryImage=None): # real signature unknown; restored from __doc__
    """
       @brief 计算最大到3阶矩或者栅格形状(rasterized shape).
       
       The function computes moments, up to the 3rd order, of a vector shape or a 
       rasterized shape. The results are returned in the structure cv::Moments.
       该函数计算图像的矩(最大到3阶),或者向量的形状,或者栅格化形状。
       
       @param array Raster image (single-channel, 8-bit or floating-point 2D array) or an 
       array (1xN,或者Nx1的2D点),通常是cv2.findContours返回的轮廓信息.
    
       @param binaryImage If it is true, all non-zero image pixels are treated as 1's. The 
       parameter is used for images only.
       @returns moments.  
       
       @note Only applicable to contour moments calculations from Python bindings: Note 
       that the numpy type for the input array should be either np.int32 or np.float32.
       python的接口仅仅用于轮廓矩的计算。
    """
    pass

下面具体看下例子:

img1 = cv2.imread('star.png', 1)
img = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
print(len(contours))
cnt = contours[1]
M = cv2.moments(cnt)
print(M)

# 计算图像的质心
x1 = M['m10']/M['m00']
y1 = M['m01']/M['m00']
print(x1)
print(y1)

image = cv2.drawContours(img1, contours, -1, (255, 0, 0), 3)
cv2.imshow('image', image)
cv2.waitKey(0)

下面是M的打印结果:

{'m00': 10174.5, 'm10': 1274781.0, 'm01': 1171712.0,
 'm20': 170342228.25, 'm11': 146795270.54166666, 'm02': 145563982.25,
 'm30': 24004385811.4, 'm21': 19614391639.716667, 'm12': 18235939976.05,
 'm03': 19211850096.9, 'mu20': 10622674.663976133, 'mu11': -10586.755694389343,
 'mu02': 10627718.950181842, 'mu30': 41250.74350357056, 'mu21': 155917.34777283669,
 'mu12': 410996.8116209507, 'mu03': 653829.4448013306, 'nu20': 0.10261426257635634,
 'nu11': -0.0001022672879496034, 'nu02': 0.10266299001323984, 'nu30': 3.9504729315724535e-06,
 'nu21': 1.4931785699470972e-05, 'nu12': 3.9360060967885616e-05, 'nu03': 6.261549015059886e-05}

画出找到的2个轮廓,前面介绍过寻找轮廓和画轮廓:
在这里插入图片描述

轮廓面积

计算的函数如下,当然也可以使用图像矩计算,M['m00'],使用如下:

area = cv2.contourArea(cnt)  # cnt是返回的轮廓信息,参考上面的例子
# 输出为:10174.5

图像的面积统计如下:
在二值图像内,非零像素标记为1,零像素标记为0,那么所有的非零元素求和则为面积,其实就是轮廓内的所有1求和。可以用规则的多边形测试,即可验证

轮廓周长(Contour Perimeter)

计算函数为:cv2.arcLength(),第二个参数指明轮廓是否封闭(true),或者是曲线:

perimeter = cv2.arcLength(cnt,True)

图像的周长统计如下:
在二值图像内,非零像素标记为1,零像素标记为0,将轮廓所有的元素求和,即是周长。

轮廓近似(Contour Approximation)

在特定的精度要求下,可以选择用更少的轮廓点近似另一个形状。应用的算法为 Douglas-Peucker algorithm

为了理解这个算法,假设我们尝试在图像中寻找方形,由于某些原因,无法得到完美的方形,而是一个不好的形状。那么我们可以用形状近似该形状。函数的介绍如下:

approx = cv2.approxPolyDP(cnt,epsilon,True)
	"""
		功能:得到图像中多边形的近似轮廓点。
		cnt:表示输入的形状(轮廓)
		epsilon:近似的精度,表示近似轮廓与原轮廓的最大距离
		布尔值:true表示轮廓是封闭的,否则不是封闭的
		approx:返回值,与输入轮廓属性一样
	"""

应用示例如下:

    img = cv2.imread('s2.png')
    print(img.shape)
    cv2.imshow('ori image', img)

    img1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, thresh = cv2.threshold(img1, 127, 255, 0)
    contours, hierarchy = cv2.findContours(thresh, 1, 2)
    cnt = contours[0]
    print(len(contours))
    # 原始的轮廓
    # image_ori = cv2.drawContours(img, contours, -1, (0, 0, 255), 2)
    # cv2.imshow('ori contour', image_ori)
    epsilon = 0.1*cv2.arcLength(cnt, True)
    print(epsilon)
    approx = cv2.approxPolyDP(cnt, epsilon, True)
    print(len(approx))
    image = cv2.drawContours(img, approx, -1, (0, 0, 255), 3)

    cv2.imshow('image', image)
    cv2.waitKey(0)

在这里插入图片描述在这里插入图片描述

轮廓凸包(Convex Hull)

轮廓凸包与轮廓近似有些类似,但是事实上是不一样的(在某些特殊情况下可能结果看着一样)。这里,函数cv2.convexHull()用于检查曲线的凸包缺陷,并纠正。一般来说,凸曲线通常是向外凸的,或者至少也是平坦的。如果曲线向内凸,那么称之为凸包缺陷(convexity defects)。比如,下面的图像,红色的线表示手的凸包,双向箭头表示凸包缺陷,他是凸包到轮廓的局部最大偏差。

在这里插入图片描述

hull = cv2.convexHull(points, hull=None, clockwise=None, returnPoints=None )

功能:寻找目标的凸包
points:输入的2D点,通常是轮廓点。
hull:输入的凸包点。
clockwise:方向的标志,如果为True,则顺时针输出,否则逆时针。
returnPoints:默认是True,输出凸包点的左边。如果为False,返回凸包点在轮廓点中的索引。

hull = cv2.convexHull(cnt)

如果需要寻找凸包的凹陷点,那么returnPoints=False

示例如下:

在这里插入代码片

检查凸凹性(Checking Convexity)

可以使用函数检查曲线是否是凸的,cv2.isContourConvex(). 返回 True或者False.

边界矩形(Bounding Rectangle)

总共有两种类型的边界矩形。

常规边框(Straight Bounding Rectangle)

常规的边框,目标对象没有旋转。所以边框的面积不会存在最小值。函数为cv2.boundingRect()
令(x,y)是矩形的左上角坐标,(w,h)是宽和高。

x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

旋转矩形(Rotated Rectangle)

这里,边框需要是最小区域,所以考虑对象的旋转。函数为cv2.minAreaRect(),返回边框的2D结构,具体包括(左上角坐标(x,y),(width,height),旋转角度)。但是画该边框我们需要边框的四个角,获取方式如下:

rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int(box)
im = cv2.drawContours(im,[box],0,(0,0,255),2)

下面的图像是运行的结果,绿色框表示正常的边框,红色表示旋转框:

在这里插入图片描述

最小闭合圆(Minimum Enclosing Circle)

下面我们目标的最小包围圆,函数为cv2.minEnclosingCircle(),使用最小的圆形区域包围目标对象,具体使用如下:

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

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

拟合椭圆(Fitting an Ellipse)

下面使用椭圆拟合目标,例子如下:

ellipse = cv2.fitEllipse(cnt)
im = cv2.ellipse(im,ellipse,(0,255,0),2)

在这里插入图片描述

拟合直线(Fitting a Line)

类似,我们可以用直线拟合点,下面的图像包含一系列白色的点,我们可以用直线拟合,例子如下:

rows,cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
img = cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)

在这里插入图片描述

标签:cnt,img,Python,image,cv2,OpenCV,--,轮廓,255
来源: https://blog.csdn.net/kxh123456/article/details/109825933

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有