python识别图像中绿⾊的部分_[OpenCV-Python]OpenCV中的
图像处理部。。。
部分 IV
OpenCV 中的图像处理
21 OpenCV 中的轮廓
21.1 初识轮廓
⽬标
· 理解什么是轮廓
· 学习轮廓,绘制轮廓等
· 函数:cv2.findContours(),cv2.drawContours()
21.1.1 什么是轮廓
轮廓可以简单认为成将连续的点(连着边界)连在⼀起的曲线,具有相同、的颜⾊或者灰度。轮廓在形状分析和物体的检测和识别中很有⽤。
· 为了更加准确,要使⽤⼆值化图像。在寻轮廓之前,要进⾏阈值化处理、或者 Canny 边界检测。
· 查轮廓的函数会修改原始图像。如果你在到轮廓之后还想使⽤原始图、像的话,你应该将原始图像存储到其他变量中。
· 在 OpenCV 中,查轮廓就像在⿊⾊背景中超⽩⾊物体。你应该记住,、要的物体应该是⽩⾊⽽背景应该是⿊⾊。
让我们看看如何在⼀个⼆值图像中查轮廓:
函数 cv2.findContours() 有三个参数,第⼀个是输⼊图像,第⼆个是轮廓检索模式,第三个是轮廓近似⽅法。返回值有三个,第⼀个是图像,第⼆个是轮廓,第三个是(轮廓的)层析结构。轮廓(第⼆个返回值)是⼀个 Python列表,其中存储这图像中的所有轮廓。每⼀个轮廓都是⼀个 Numpy 数组,包含对象边界点(x,y)的坐标。
注意:我们后边会对第⼆和第三个参数,以及层次结构进⾏详细介绍。在那之前,例⼦中使⽤的参数值对所有图像都是适⽤的。
21.1.2 怎样绘制轮廓
函数 cv2.drawContours() 可以被⽤来绘制轮廓。它可以根据你提供的边界点绘制任何形状。它的第⼀个参数是原始图像,第⼆个参数是轮廓,⼀个 Python 列表。第三个参数是轮廓的索引(在绘制独⽴轮廓是很有⽤,当设置为 -1 时绘制所有轮廓)。接下来的参数是轮廓的颜⾊和厚度等。
在⼀幅图像上绘制所有的轮廓:
importnumpy as np
importcv2
im = cv2.imread('test.jpg')
imgray =cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
image, contours, hierarchy =cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
绘制独⽴轮廓,如第四个轮廓:
img = cv2.drawContour(img, contours, -1, (0,255,0), 3)
但是⼤多数时候,下⾯的⽅法更有⽤:
img = cv2.drawContours(img, contours, 3, (0,255,0), 3)
注意:最后这两种⽅法结果是⼀样的,但是后边的知识会告诉你最后⼀种⽅法更有⽤。
21.1.3 轮廓的近似⽅法
这是函数 cv2.findCountours() 的第三个参数。它到底代表什么意思呢?
上边我们已经提到轮廓是⼀个形状具有相同灰度值的边界。它会存贮形状边界上所有的 (x,y) 坐标。但是需要将所有的这些边界点都存储吗?这就是这个参数要告诉函数 cv2.findContours 的。
这个参数如果被设置为 cv2.CHAIN_APPROX_NONE,所有的边界点都会被存储。但是我们真的需要这么多点吗?例如,当我们的边界是⼀条直线时。你⽤需要直线上所有的点来表⽰直线吗?不是的,我们只需要这条直线的两个端点⽽已。这就是
cv2.CHAIN_APPROX_SIMPLE 要做的。它会将轮廓上的冗余点都去掉,压缩轮廓,从⽽节省内存开⽀。我们⽤下图中的矩形来演⽰这个技术。在轮廓列表中的每⼀个坐标上画⼀个蓝⾊圆圈。第⼀个图显⽰使⽤ cv2.CHAIN_APPROX_NONE 的效果,⼀共 734 个点。第⼆个图是使⽤ cv2.CHAIN_APPROX_SIMPLE 的结果,只有 4 个点。看到他的威⼒了吧!
21.2 轮廓特征
⽬标
· 查轮廓的不同特征,例如⾯积,周长,重⼼,边界框等。
· 你会学到很多轮廓相关函数
21.2.1 矩
图像的矩可以帮助我们计算图像的质⼼,⾯积等。详细信息请查看Image Moments。
函数 s() 会将计算得到的矩以⼀个字典的形式返回。如下:
importcv2importnumpy as np
img= cv2.imread('star.jpg',0)
ret,thresh= cv2.threshold(img,127,255,0)
contours,hierarchy= cv2.findContours(thresh, 1, 2)
cnt=contours[0]
s(cnt)print M
根据这些矩的值,我们可以计算出对象的重⼼:
和
. 。
#This can be done as follows:
cx = int(M['m10']/M['m00'])
cy= int(M['m01']/M['m00'])
21.2.2 轮廓⾯积
轮廓的⾯积可以使⽤函数 urArea() 计算得到,也可以使⽤矩(0 阶矩),M['m00']。
area = urArea(cnt)
21.2.3 轮廓周长
也被称为弧长。可以使⽤函数 cv2.arcLength() 计算得到。这个函数的第⼆参数可以⽤来指定对象的形状是闭合的(True),还是打开的(⼀条曲线)。
perimeter = cv2.arcLength(cnt,True)
21.2.4 轮廓近似
将轮廓形状近似到另外⼀种由更少点组成的轮廓形状,新轮廓的点的数⽬由我们设定的准确度来决定。使⽤的Douglas-Peucker算法,你可以到获得更多此算法的细节。
为了帮助理解,假设我们要在⼀幅图像中查⼀个矩形,但是由于图像的种种原因,我们不能得到⼀个完美的矩形,⽽是⼀个“坏形
状”(如下图所⽰)。
现在你就可以使⽤这个函数来近似这个形状()了。这个函数的第⼆个参数叫epsilon,它是从原始轮廓到近似轮廓的最⼤距离。它是⼀个准确度参数。选择⼀个好的 epsilon 对于得到满意结果⾮常重要。
epsilon = 0.1*cv2.arcLength(cnt,True)
approx= cv2.approxPolyDP(cnt,epsilon,True)
下边,第⼆幅图中的绿线是当 epsilon = 10% 时得到的近似轮廓,第三幅图是当 epsilon = 1% 时得到的近似轮廓。第三个参数设定弧线是否闭合。
21.2.5 凸包
凸包与轮廓近似相似,但不同,虽然有些情况下它们给出的结果是⼀样的。
函数 vexHull() 可以⽤来检测⼀个曲线是否具有凸性缺陷,并能纠正缺陷。⼀般来说,凸性曲线总是凸出来的,⾄少是平的。如果有地⽅凹进去了就被叫做凸性缺陷。例如下图中的⼿。红⾊曲线显⽰了⼿的凸包,凸性缺陷被双箭头标出来了。
关于他的语法还有⼀些需要交代:
hull = vexHull(points[, hull[, clockwise[, returnPoints]]
参数:
· points 我们要传⼊的轮廓
· hull 输出,通常不需要
· clockwise ⽅向标志。如果设置为 True,输出的凸包是顺时针⽅向的。否则为逆时针⽅向。
· returnPoints 默认值为 True。它会返回凸包上点的坐标。如果设置为 False,就会返回与凸包点对应的轮廓上的点。
要获得上图的凸包,下⾯的命令就够了:
hull = vexHull(cnt)
但是如果你想获得凸性缺陷,需要把 returnPoints 设置为 False。以上⾯的矩形为例,⾸先我们到他的轮廓 cnt。现在我把returnPoints 设置为 True 查凸包,我得到下列值:
[[[234 202]], [[ 51 202]], [[ 51 79]], [[234 79]]],其实就是矩形的四个⾓点。
现在把 returnPoints 设置为 False,我得到的结果是[[129],[ 67],[ 0],[142]]。他们是轮廓点的索引。例如:cnt[129] =
rectangle函数opencv[[234,202]],这与前⾯我们得到结果的第⼀个值是⼀样的。
在凸检验中你我们还会遇到这些。
21.2.6 凸性检测
函数 cv2.isContourConvex() 可以可以⽤来检测⼀个曲线是不是凸的。它只能返回 True 或 False。没什么⼤不了的。
k = cv2.isContourConvex(cnt)
21.2.7 边界矩形
有两类边界矩形。
直边界矩形 ⼀个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。所以边界矩形的⾯积不是最⼩的。可以使⽤函数
cv2.boundingRect() 查得到。
(x,y)为矩形左上⾓的坐标,(w,h)是矩形的宽和⾼。
x,y,w,h =cv2.boundingRect(cnt)
img= angle(img,(x,y),(x+w,y+h),(0,255,0),2)
旋转的边界矩形 这个边界矩形是⾯积最⼩的,因为它考虑了对象的旋转。⽤到的函数为 cv2.minAreaRect()。返回的是⼀个 Box2D 结构,其中包含矩形左上⾓⾓点的坐标(x,y),矩形的宽和⾼(w,h),以及旋转⾓度。但是要绘制这个矩形需要矩形的 4 个⾓点,可以通过函数 cv2.boxPoints() 获得。
rect =cv2.minAreaRect(cnt)
box=cv2.boxPoints(rect)
box=np.int0(box)
im= cv2.drawContours(im,[box],0,(0,0,255),2)
把这两中边界矩形显⽰在下图中,其中绿⾊的为直矩形,红的为旋转矩形。
21.2.8 最⼩外接圆
函数 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)
21.2.9 椭圆拟合
使⽤的函数为 cv2.ellipse(),返回值其实就是旋转边界矩形的内切圆。
ellipse =cv2.fitEllipse(cnt)
im= cv2.ellipse(im,ellipse,(0,255,0),2)
21.2.10 直线拟合
我们可以根据⼀组点拟合出⼀条直线,同样我们也可以为图像中的⽩⾊点拟合出⼀条直线。
rows,cols = img.shape[:2]#cv2.fitLine(points, distType, param, reps, aeps[, line ]) → line#points – Input vector of 2D or 3D points, stored in std::vector<> or Mat.#line – Output line parameters. In case of 2D fitting, it should be a vector of#4 elements (likeVec4f) - (vx, vy, x0, y0), where (vx, vy) is a normalized#vector collinear to the line and (x0, y0) is a point on the line. In case of#3D fitting, it should be a vector of 6 elements (like Vec6f) - (vx, vy, vz,#x0, y0, z0), where (vx, vy, vz) is a normalized vector collinear to the line#and (x0, y0, z0) is a point on the line.#distType – Distance used by the M-
estimator#distType=CV_DIST_L2#ρ(r) = r2 /2 (the simplest and the fastest least-squares method)#param – Numerical parameter ( C ) for some types of distances. If it is 0, an optimal value#is chosen.#reps – Sufficient accuracy for the radius (distance between the coordinate origin and the#line).#aeps – Sufficient accuracy for the angle. 0.01 would be a good default value for reps and#aeps.
[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)
21.3 轮廓的性质
本⼩节我们将要学习提取⼀些经常使⽤的对象特征。你可以在Matlab regionprops documentation 更多的图像特征。
21.3.1 长宽⽐
边界矩形的宽⾼⽐
x,y,w,h =cv2.boundingRect(cnt)
aspect_ratio= float(w)/h
21.3.2 Extent
轮廓⾯积与边界矩形⾯积的⽐。
area =urArea(cnt)
x,y,w,h=cv2.boundingRect(cnt)
rect_area= w*h
extent= float(area)/rect_area
21.3.3 Solidity
轮廓⾯积与凸包⾯积的⽐。
area =urArea(cnt)
vexHull(cnt)
hull_urArea(hull)
solidity= float(area)/hull_area
21.3.4 Equivalent Diameter
与轮廓⾯积相等的圆形的直径
area =urArea(cnt)
equi_diameter= np.sqrt(4*area/np.pi)
21.3.5 ⽅向
对象的⽅向,下⾯的⽅法还会返回长轴和短轴的长度
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
21.3.6 掩模和像素点
有时我们需要构成对象的所有像素点,我们可以这样做:
mask =np.zeros(imgray.shape,np.uint8)#这⾥⼀定要使⽤参数 -1, 绘制填充的的轮廓
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论