【Python】使用Opencv对图像进行边缘轮廓检测,获得轮廓面积、周长等信息(Contour Features)

您所在的位置:网站首页 opencv获取图像尺寸 【Python】使用Opencv对图像进行边缘轮廓检测,获得轮廓面积、周长等信息(Contour Features)

【Python】使用Opencv对图像进行边缘轮廓检测,获得轮廓面积、周长等信息(Contour Features)

#【Python】使用Opencv对图像进行边缘轮廓检测,获得轮廓面积、周长等信息(Contour Features)| 来源: 网络整理| 查看: 265

目标: 1.通过使用opencv获得不同物体的轮廓,以及轮廓所对应的特征,比如说面积、周长、质心、边界框等等。 2.学习一些与轮廓提取有关的函数。

提示:不同版本的python与opencv库可能在函数使用上有少许不同,在使用过程中如果发现不同之处,请到官网查询API:

目录 开始轮廓特征Moments图像的矩图像重心轮廓面积轮廓周长(弧长)轮廓近似估计(多边形逼近)凸包(Convex Hull)检查凸性最小矩形边框最小包围圆近似椭圆近似直线 轮廓特性

开始

在很多图像应用场景下需要检测出一个物体的边界轮廓,在opencv中,使用cv2.findContours()找到轮廓,使用cv2.drawContours()画出轮廓。 为了更好的检测效果,我们使用了二进制图像,也就是只有黑白像素(0和255)的图像输入,所以在进行边缘检测之前,最好先使用threshold阈值二值化算法或者是Canny边缘检测算法对图像进行大致的预处理,然后再输入findContours函数中找到轮廓。 例子:

import numpy as np import cv2 as cv im = cv.imread('test.jpg') imgray = cv.cvtColor(im, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) #不同cv2版本的findContours函数返回值的数量不同,我的环境下返回三个值,官方文档返回两个值 _,contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

使用drawContours函数画出轮廓:

把所有检测到的轮廓都画在图像上: cv.drawContours(img, contours, -1, (0,255,0), 3) 把检测到的第四条轮廓画在图像上: cv.drawContours(img, contours, 3, (0,255,0), 3) 大多数情况下,下面这种方式也可以使用: cnt = contours[4] cv.drawContours(img, [cnt], 0, (0,255,0), 3)

当轮廓中有大量直线线段时,可以使用cv.CHAIN_APPROX_SIMPLE(2)参数,而不使用cv.CHAIN_APPROX_NONE(1)参数。因为1会记录下轮廓边的每个像素,而2只会记录线段两端的点。比如说下面这个图,左边用的是参数1,右边用的是参数2: 在这里插入图片描述 有意思的一点是cv2.drawContours这个函数的第二个参数,如果传入的使一个列表list,列表元素类型是numpy array,那么不管findContours的参数是(1)还是(2),都会将相邻两点之间连接起来,而不会画出离散的点。如果想通过(2)画出离散的点,需要将numpy array从list中拿出来,然后作为drawContours的第二个参数传入,这样画出的就是离散的点。例子:

import cv2 import numpy as np img = cv2.imread('test9.jpg') ret,thresh = cv2.threshold(cv2.cvtColor(img,cv2.COLOR_BGR2GRAY),127,255,0) _,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#得到轮廓信息 #情况一,传入list,元素是numpy数组,函数将会画出相邻两点之间的连线 imgnew = cv2.drawContours(img, contours, 1, (0,255,0), 3)#第三个参数是1,代表了取出contours中index为1的array cv2.imshow('contour',imgnew) #情况二,传入numpy数组,函数将仅仅会画出这些点,而不会将他们依次连接 imgnew = cv2.drawContours(img, contours[1], -1, (0,255,0), 3)#第三个参数为-1,代表了画出contours[0]中所有的点 cv2.imshow('contour',imgnew)

情况一 在这里插入图片描述 情况二: 在这里插入图片描述

轮廓特征 Moments图像的矩

cv.moments()用来获取轮廓的矩,通过图像的矩可以计算某些特征,比如说物体的重心等等。例子:

import numpy as np import cv2 as cv img = cv.imread('test.jpg',0) ret,thresh = cv.threshold(img,127,255,0) contours,hierarchy = cv.findContours(thresh, 1, 2) cnt = contours[0] M = cv.moments(cnt)#计算图像矩 print( M ) 图像重心

对于上面获取的M,可以提炼出一些有用的信息,比如说面积,重心等等。重心可以通过以下方程进行计算: C x = M 10 M 00 C_x=\frac{M_{10}}{M_{00}} Cx​=M00​M10​​和 C y = M 01 M 00 C_y=\frac{M_{01}}{M_{00}} Cy​=M00​M01​​。

cx = int(M['m10']/M['m00'])#重心的x坐标 cy = int(M['m01']/M['m00'])#重心的y坐标 轮廓面积

轮廓面积通过cv.contourArea()获取或者直接从moments中的M[‘m00’]。

area = cv.contourArea(cnt) 轮廓周长(弧长)

可以使用cv.arcLength()获取轮廓的周长。第二个参数规定了这个轮廓是否是闭合的,True代表是闭合的,False代表轮廓仅仅是一个曲线。

perimeter = cv.arcLength(cnt,True) 轮廓近似估计(多边形逼近)

通过cv.approxPolyDP()函数可以找到一个和cnt近似的轮廓,基于Douglas-Peucker algorithm算法思想,用指定精度逼近多边形曲线。 根据我们指定的一个精度,可以将轮廓形状近似为顶点较少的其他形状。比如说你试图在一个图像找到一个长方形,但是由于图像中的某些问题,你没有得到一个完美的长方形,而是一个“坏形状”(如下图所示),现在你就可以通过这个功能获取一个近似的形状。在这种情况下,第二个参数称为epsilon,它是轮廓到近似轮廓的最大距离,是一个精度参数。第三个参数规定了这个轮廓是否是闭合的。 在这里插入图片描述 上面的图像中,第一张是通过阈值二值化处理后的图像,第二张是当 e p s i l o n = 0.1 ∗ p e r i m e t e r epsilon=0.1*perimeter epsilon=0.1∗perimeter时画出的近似图像,第三张是当$epsilon=0.01*perimeter $时画出的近似图像。

凸包(Convex Hull)

我们通常使用cv.convexHull(cnt)函数检测轮廓的凸缺陷,凸缺陷指的是轮廓向里凹陷的情况,比如说下面这种情况,紫色的线展示了图像中的凸包。 在这里插入图片描述

import cv2 import numpy as np img = cv2.imread('hand.jpg') #低于127时设置成255,255是白色,代表亮度(能量)最高,包括三通道的图像中(255,255,255)是白色 ret,thresh = cv2.threshold(cv2.cvtColor(img,cv2.COLOR_BGR2GRAY),127,255,0) _,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#得到轮廓信息 cnt=contours[1] hull=cv2.convexHull(cnt) #函数的返回值是一组点(numpy array),我们需要依次将其通过线段连接起来,所以将其放入list imgnew1 = cv2.drawContours(img, [hull], -1,(255,0,255), 3) cv2.imshow('convexHull',imgnew1) cv2.waitKey(0) cv2.destroyAllWindows() 检查凸性

使用cv.isContourConvex()函数来检测这个函数是否是凸出的。只返回True或者False。

k = cv.isContourConvex(cnt) 最小矩形边框

矩形边框(Bounding Rectangle)是说用一个最小的矩形,把找到的形状包起来。有两种情况的矩形边框可以选择,一种是绿色的,就是正常的矩形,另外一种带旋转的矩形,是红色边框,面积会更小一些: 在这里插入图片描述 首先介绍下cv2.boundingRect(img)这个函数

这个函数很简单,img是一个二值图,也就是输入图像;这个函数返回四个值,分别是x,y,w,h。其中,x,y是矩阵左上点的坐标,w,h是矩阵的宽和高,然后利用cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)画出矩形。

参数解释 第一个参数:img是输入图像 第二个参数:(x,y)是矩阵的左上点坐标 第三个参数:(x+w,y+h)是矩阵的右下点坐标 第四个参数:(0,255,0)是画线对应的rgb颜色 第五个参数:2是所画的线的宽度 代码如下:

import cv2 import numpy as np img = cv2.imread('bounding rectangle.jpg') ret,thresh = cv2.threshold(cv2.cvtColor(img,cv2.COLOR_BGR2GRAY),127,255,0) _,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#得到轮廓信息 cnt=contours[1] x,y,w,h=cv2.boundingRect(cnt) #Straight Bounding Rectangle cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) #Rotate Rectangle rect=cv2.minAreaRect(cnt) box=cv2.boxPoints(rect) box=np.int64(box) imgnew=cv2.drawContours(img,[box],0,(0,0,255),2) cv2.imshow('boundingRect',imgnew) cv2.waitKey(0) cv2.destroyAllWindows()

处理结果: 在这里插入图片描述

最小包围圆

使用cv.minEnclosingCircle()获得一个轮廓的最小包围圆。

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

在这里插入图片描述

近似椭圆

使用cv.fitEllipse(cnt)函数将轮廓近似成一个椭圆,函数返回一个旋转之后的矩形,椭圆就在这个矩形里。

ellipse = cv.fitEllipse(cnt) cv.ellipse(img,ellipse,(0,255,0),2)

在这里插入图片描述

近似直线

可以通过cv.fitLine函数得到一组点的近似直线,如果这组点是轮廓的点,那么得出的就是轮廓的近似直线。

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

在这里插入图片描述

轮廓特性

在Opencv官网可以了解到更多轮廓特性,比如说Aspect Ratio、Extent等等。 链接在此



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3