(三)OpenCV中的图像处理之轮廓

发布时间:2018-05-29 20:58  浏览次数:57

注释:本文翻译自OpenCV3.0.0 document->OpenCV-Python Tutorials,包括对原文档种错误代码的纠正


该章节分为以下四个小节:





(一)     Contours:Getting Started(轮廓:开始)

(二)     Contours Features(轮廓特征)

(三)     Contours Properties(轮廓属性)

(四)     Contours:More Functions(轮廓:更多方法)

(五)     Contours Hierarchy(轮廓分级)




第一小节:Contours:GettingStarted

1.目标:



* 明白什么是轮廓
* 学会找到这些轮廓,绘制轮廓
* 学习这些函数:cv2.findContours(),cv2.drawContours()
2.什么是轮廓



轮廓可以简单地解释为连接所有连续点(沿着边界),具有相同颜色或强度的曲线。轮廓是形状分析和物体检测和识别的有用工具。



*  为了更高的准确率,使用二值图像。在寻找轮廓之前,应用阈值或canny边缘检测
* findContours函数修改源图像,所有想要在找到轮廓后保存源图像,提前把源图像赋值给其它变量
* 再OpenCV中,查找轮廓就像从黑色背景中找到白色物体,所以记住,找到的物体应该是白色的,背景应该是黑色的。
下面的栗子:在二值图像中找到轮廓
''' Opencv中的轮廓: demo1 ''' import cv2 img = cv2.imread('2.jpg') # 图像灰度化 gray =
cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 3*3核的高斯滤波 gray = cv2.GaussianBlur(gray,
(3, 3), 0) # canny边缘检测 gray = cv2.Canny(gray, 100, 300) ret, thresh =
cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # binary是最后返回的二值图像
#findContours()第一个参数是源图像、第二个参数是轮廓检索模式,第三个参数是轮廓逼近方法
#输出是轮廓和层次结构,轮廓是图像中所有轮廓的python列表,每个单独的轮廓是对象边界点的(x,y)坐标的Numpy数组 binary, contours,
hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (0, 0, 255), 1) cv2.imshow("1", binary)
cv2.imshow("win10", img) cv2.waitKey(0) & 0xFF
结果:




3.怎样绘制轮廓




Cv2.drawContours()用来绘制轮廓,只要提供了边界点它也可以用来绘制各种形状。它的第一个边界是源图像,第二个参数是Python列表传递的轮廓,第三个参数是轮廓的索引(在绘制单个轮廓时有用,在绘制多个轮廓时传递-1),剩余的参数是颜色、厚度等。

绘制图像中的所有轮廓:
cv2.drawContours(img, contours, -1, (0,255,0), 3)
绘制个别轮廓,如第四轮廓:
cv2.drawContours(img, contours, 3, (0,255,0), 3)
但是通常情况下,下面的方式更有用:
cnt = contours[4]cv2.drawContours(img, [cnt], 0, (0,255,0), 3)
4.轮廓近似法



轮廓近似法是cv2.findContours()中第三个参数。

前面,我们说轮廓是具有相同强度的形状的边界。它存储形状边界的(x,y)坐标,但是它是否存储所有坐标?这是通过这种轮廓法来逼近的。


如果传递的参数为cv2.CHIAN_APPROX_NONE,则会存储所有边界。但实际情况下我们可能并不需要所有的点,比如发现一条直线的轮廓,所需要的只是这条线的两个端点。这就是cv2.CHAIN_APPROX_SIMPLE所做的,它删除了所有冗余的点并压缩轮廓,从而大大节省了内存。


在下面矩形图像中显示了这种技术,在轮廓数组上的所有坐标上绘制一个圆,第一个用cv2.CHIAN_APPROX_NONE绘制(734个点),第二个用cv2.CHAIN_APPROX_SIMPLE(4个点)绘制。







第二小节:ContoursFeatures(轮廓特征)

5.目标



* 找不同的轮廓特征,如:面积、周长、重心、边框
* 学会关于轮廓的方法
6.时刻



图像时刻可以帮助你计算一些特征,如物体的质心、物体的面积等。关于图像时刻的概念,参考维基百科。

函数cv2.moments()给出了计算所有时刻值的字典,详细如下:
import cv2import numpy as np img = cv2.imread('star.jpg',0)ret,thresh = cv2.
threshold(img,127,255,0)binary,contours,hierarchy = cv2.findContours(thresh, 1,
2)cnt = contours[0]M = cv2.moments(cnt)print M
然后可以提取有用的信息,如面积、质心等。质心由下面关系式给出:

    cx = int(M['m10']/M['m00'])cy = int(M['m01']/M['m00'])

7.轮廓区域

轮廓区域由cv2.contourArea()计算,或者由时刻中的M[‘m00’]得到:



area = cv2.contourArea(cnt)

8.轮廓周长



也称为轮廓弧长,由cv2.arcLength()计算得到,第二个参数指定shape是封闭轮廓(True)或仅仅是曲线。
perimeter = cv2.arcLength(cnt,True)

9.轮廓近似



如果图像没有明确的轮廓,使用cv2.approxPolyDP近似此轮廓。
epsilon = 0.1*cv2.arcLength(cnt,True)approx = cv2.approxPolyDP(cnt,epsilon,True
)

10.Convex Hull



ConvexHull将看起来类似于轮廓近似,但它不是(两者可能在某些情况下提供相同的结果)。这里,cv2.convexHull
()函数检查一个曲线的凸性缺陷并进行修正。一般来说,凸曲线是总是凸出的或至少平坦的曲线。如果内部膨胀,则称为凸面缺陷。例如,检查下面的图像。红线显示手的凸包。双面箭头标记显示凸度缺陷,这是船体与轮廓的局部最大偏差。

有必要去解释以下这个函数的参数:
hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]]
参数详情:



* Points:是传入的轮廓;
* Hull:是输出,通常我们避免它;
* Clockwise:方向标志。如果是true,则顺时针输出凸包,否则逆时针方式输出;
* ReturnPoints:默认情况下为true。它返回hull点的坐标,如果是false,则返回与hull点对应的轮廓点的索引。
所以要得到如上图所示的凸包,下面这条语句就足够了:

hull = cv2.convexHull(cnt)

但是如果你想找到凸面缺陷,你需要传递returnPoints=False。为了理解它,我们将采用上面的矩形图像。首先,我发现它的轮廓为cnt
。现在我发现它的凸包带有returnPoints=True,我得到了以下值:[[[234202]],[[51202]],[[5179]],[[23479]]]
这是四角矩形点。现在,如果对returnPoints=False做同样的处理,我会得到如下结果:[[129],[67],[0],[142]]
。这些是轮廓中相应点的指数。例如,检查第一个值:cnt[129]=[[234,202]],它与第一个结果相同(其它的点也是如此)。




11.检查凸度



这里有一个函数可以检查曲线是否凸起,cv2.isContourConvex().返回值为True或False.

k = cv2.isContourConvex(cnt)


12.边界矩形

1)直线边界矩形



它是一个直的矩形,不考虑对象的旋转。所以边界矩形的面积不会最小。这个矩形由函数cv2.boundingRect()发现。

设(x,y)为矩形的左上角坐标,(w,h)为其宽度和高度.



x,y,w,h = cv2.boundingRect(cnt)

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

2)旋转矩形




这里,边界矩形是以最小面积绘制的,所以它也考虑旋转。使用的函数是cv2.minAreaRect().它返回一个Box2D的结构,使用包含以下结构——(中心(x,y),(宽度,高度),旋转角度)。但要绘制这个矩形,我们需要矩形的四个角。它是通过函数cv2.boxPoints()获得的。



rect = cv2.minAreaRect(cnt)

box = cv2.boxPoints(rect)

box = np.int0(box)

cv2.drawContours(img,[box],0,(0,0,255),2)

两种边界矩形都在下图中显示,绿色是一般的边界矩形,红色的是旋转边界矩形


13.最小封闭圈



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

(x,y),radius = cv2.minEnclosingCircle(cnt)

center = (int(x),int(y))

radius =int(radius)

cv2.circle(img,center,radius,(0,255,0),2)

14.拟合椭圆



接下来将一个椭圆拟合到一个对象,它返回椭圆被刻在其中的旋转矩形。

ellipse = cv2.fitEllipse(cnt)

cv2.ellipse(img,ellipse,(0,255,0),2)

15.拟合线条



同样我们可以用一条线来拟合一组点。下图包含一组白点,可以近似为一条线。

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)

cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)




第三小节:ContoursProperties(轮廓属性)

1.目标:



* 学会找到不同轮廓的属性,如solidity,mean intensity等
* 学习提取像Solidity、Equivalent Diameter, Mask image,Mean Intensity等对象的一些常用属性
2.纵横比(Aspect Ratio)

 它是对象矩阵的宽高比:






x,y,w,h = cv2.boundingRect(cnt)aspect_ratio = float(w)/h
3.范围(Extent)

范围是轮廓面积和边界矩形面积的比率:






area = cv2.contourArea(cnt)x,y,w,h = cv2.boundingRect(cnt)rect_area = w*hextent
= float(area)/rect_area

4.密实度(Solidity)



密实度是轮廓面积与其凸包面积的比率:




area = cv2.contourArea(cnt)hull = cv2.convexHull(cnt)hull_area = cv2.
contourArea(hull)solidity = float(area)/hull_area

5.等效直径(EquivalentDiameter)

等效直径是与轮廓面积相同的圆的直径






area = cv2.contourArea(cnt)equi_diameter = np.sqrt(4*area/np.pi)

6.方向(Orientation)



方向是物体指向的角度。以下方法也给出主轴和副轴长度。
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)

7.蒙版和像素点(Maskand Pixel Points)



在某些情况下,我们可能需要包含该对象的所有点。它可以用以下方法做到:
mask = np.zeros(imgray.shape,np.uint8)cv2.drawContours(mask,[cnt],0,255,-1)
pixelpoints= np.transpose(np.nonzero(mask))#pixelpoints = cv2.findNonZero(mask)

这里有两个方法,一个使用Numpy函数,另一个使用OpenCV函数(最后一行注释)来执行相同操作。结果是一样的,但略有不同。Numpy以(行,列)格式给出坐标,而OpenCV以(x,y)格式给出坐标。所以基本上答案会互换。请注意,row=x和column=y.


8.最大最小值和它们的位置(maximumvalue,minimum value and their locations)



我们可以使用蒙版图像来找到这些参数。
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)

9.平均颜色或平均强度(meanColor or mean Intensity)



在这里,我们可以找到一个物体的平均颜色。或者它可以是灰度模式下物体的平均强度。我们再次使用相同的掩膜来做到这一点。
mean_val = cv2.mean(im,mask = mask)

10.极值点(ExtremePoints)



极值点表示对象的最上面、最下面、最左边和最右边点。
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])



第四小节:Contours:More Functions (轮廓:更多方法)

1.目标:



* 如何找到凸起缺陷
* 寻找从一个点到多个点的最短距离
* 匹配不同的形状
2.凸起缺陷



我们在第二章看到什么是凸包,关于轮廓。物体与该hull之间的任何偏差均可视为凸度缺陷。

OpenCV提供了一个现成的函数来查找这个,cv2.convexityDefects().基本的函数调用如下:
hull = cv2.convexHull(cnt,returnPoints = False)defects = cv2.
convexityDefects(cnt,hull)
Note:请记住,我们必须在找到凸包时通过returnPoints=False,以便找到凹凸缺陷。


它返回一个数组,其中每行包含这些值——[起点,终点,最远点,到最远点的近似距离]。我们可以使用图像对其进行可视化。我们绘制一条连接起点和终点的线,然后在最远点绘制一个圆。记得前三个返回的时cnt的索引。所以我们必须从cnt中提取这些点。

示例代码:
# -*- coding: utf-8 -*- import cv2 import numpy as np img =
cv2.imread('13.png') img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret,
thresh = cv2.threshold(img_gray, 127, 255, 0) binary, contours, hierarchy =
cv2.findContours(thresh, 2, 1) cnt = contours[0] hull = cv2.convexHull(cnt,
returnPoints=False) defects = cv2.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]) cv2.line(img, start, end, [0,
255, 0], 2) cv2.circle(img, far, 5, [0, 0, 255], -1) cv2.imshow('img', img)
cv2.waitKey(0) cv2.destroyAllWindows()
结果如下:




3.点多边形测试



该函数可查找图像中某点与轮廓之间的最短距离。当点在轮廓之外时,它返回负值的距离,点在内部时返回正值,如果点在轮廓上则返回零。

例如,我们可以按如下方式检查点(50,50):
dist = cv2.pointPolygonTest(cnt,(50,50),True)

在这个函数中,点三个参数是measureDist。如果它是true,它会找到标记的距离。如果是false,它会查找该点是在内部还是在外部还是在轮廓上。(分别返回+1,-1,0).

Note:如果你不想查找距离,请确保第三个参数是false,因为这是一个耗时的过程。所以,设置为false可以加速2-3倍。




4.形状匹配




OpenCV带有一个函数cv2.matchShapes(),可以用来比较两个形状或两个轮廓,并返回一个显示相似度的度量。结果越低,匹配效果越好。它基于hu-moment值进行计算。文档中解释了不同的测量方法。
# -*- coding: utf-8 -*- ''' 形状匹配 ''' import cv2 import numpy as np img1 =
cv2.imread('car.png', 0) img2 = cv2.imread('car1.png', 0) ret, thresh =
cv2.threshold(img1, 127, 255, 0) ret, thresh2 = cv2.threshold(img2, 127, 255,
0) binary, contours, hierarchy = cv2.findContours(thresh, 2, 1) cnt1 =
contours[0] binary, contours, hierarchy = cv2.findContours(thresh2, 2, 1) cnt2
= contours[0] ret = cv2.matchShapes(cnt1, cnt2, 1, 0.0) print(ret)


试着用上面的图片进行融合,输出结果:



得到的结果:



* 形状A和它自身,返回值:0
*  形状A和形状B,返回值:0.001946
* 形状A和形状C,返回值:0.326911
可以看出,即使图像旋转对此比较的影响也不大。



联系:

1. 检查cv2.pointPolygonTest()的文档,你可以找到一个红色和蓝色的漂亮图像。它表示从所有像素到白色曲线的距离。
取决于距离,曲线内的所有像素都是蓝色的。 同样的外点是红色的。 轮廓边缘用白色标记。 所以问题很简单。 编写一个代码来创建这样的距离表示

2. 使用cv2.matchShapes()比较数字或字母的图像。(这将是向OCR迈出的简单一步)


第五小节:ContourHierarchy(轮廓的层次结构)

1.目标:我们了解轮廓的层次结构,即轮廓中的亲子关系。

2.原理




在最近几篇关于轮廓的文章中,我们已经使用了OpenCV提供的与轮廓相关的几个函数。但当我们使用cv2.findContours()函数在图像中找到轮廓时,我们已经传递了一个参数ContourRetrieval
Mode,我们通常会传递cv2.RETR_LIST或者cv2.RETR_TREE,而且运行效果很好。但它们实际上意味着什么呢?


另外,在输出中,我们得到了三个数组,第一个是图像,第二个是轮廓,还有一个我们命名为层次结构的输出。但是我们从来没有在任何地方使用这个层次,那么这个层次结构是什么?它有什么用途?它与前面提到的函数参数有什么关系?

这些就是我们要谈论的点。


3.什么是层次结构




通常我们使用cv2.findContours()函数来检测图像中的对象。有时物体位于不同的位置,但在某些情况下,某些形状是其它形状。就像嵌套数字一样。在这种情况下,我们称外层为父层,内层为子层。这样,图像中的轮廓彼此之间有一些关系。我们可以指定一个轮廓是如何互相连接的,例如,它是否是其它轮廓的子节点,或者它是否是父节点等。此关系的表示形式称为层次结构。

考虑下面的示例图片:



在这幅图像里,这里有一些形状被标记为0-5,2和2a表示最外面盒子的外部和内部轮廓。

这里,轮廓0,1,2是外部或者最外面的。我们可以说,它们在层次结构0中,或者只是它们处于同一层次结构中。


接下来是轮廓2a,它可以被认为是轮廓2的子轮廓(或者相反,轮廓2是轮廓2a的父轮廓)。所以,让它在层次1,类似的,轮廓3是轮廓2的子轮廓,并且它在下一层出现。最后,轮廓4,5是轮廓3a的子轮廓,它们进入最后一个层级。从我对盒子的编号方式来看,我会说轮廓4是轮廓3a的第一个子轮廓(也就是轮廓5)。

我提到了这些名词术语。相同的层级(same hierarchy level),外部轮廓(external contour),子轮廓(child
contour),父轮廓(parent contour),第一个子轮廓(first child)。好了现在进入OpenCV.


4.OpenCV中的层次结构的表示(HierarchyRepresentation in OpenCV)




所以每个轮廓都有自己的信息,包括它是什么层级、谁是它的孩子,谁是它的父母等。OpenCV将它表示为一个包含四个值的数组:[Next,Previous,First_child,Parent].


5.轮廓检索模式(ContourRetrieval Mode)

1)RETR_LIST



这是四种flag中最简单(从解释的角度看)。它只检索所有轮廓,但不创建任何父子关系。在这条规则下,父母和孩子是平等的,他们只是轮廓。即它们都属于同一层级。

所以在这里,层级数组中的第三和第四项总是-1。但显然,next和previous项将具有相应的值。只需自己检查并验证它。


下面是我得到的结果,每行都是相应轮廓的层次结构细节。例如,第一行对应于轮廓0,下一个轮廓是轮廓1。因此,next=1没有先前的轮廓,所以previous=0.其余两个,如前所述,它是-1.
>>> hierarchyarray([[[ 1, -1, -1, -1],        [ 2,  0, -1, -1],        [ 3, 
1, -1, -1],        [ 4,  2, -1, -1],        [ 5,  3, -1, -1],        [ 6,  4,
-1, -1],        [ 7,  5, -1, -1],        [-1,  6, -1, -1]]])
如果你不使用任何层次结构功能,则这是在代码中使用的理想选择。

2)RETR_EXTERNAL



如果你使用这个标志,它只会返回极端的外部标志。所有的孩子轮廓都被留下。我们可以说,根据这条规定,只有每个家庭中年长的人才会得到照顾。它不关系家庭的其它成员。


那么,在我们的图像中,那里还有多少个极端的外部轮廓呢?即在层级0级别的?只有3个,即轮廓0,1,2对吗?现在尝试用这个flag查找轮廓。在这里,给每个元素的值与上面相同。将它与以上结果进行比较以下是我得到:
hierarchyarray([[[ 1, -1, -1, -1],        [ 2,  0, -1, -1],        [-1,  1,
-1, -1]]])
3)RETR_CCOMP




该flag检索所有轮廓并将它们排列为2级层次结构。即对象的外部轮廓(即其边界)被放置在层级-1中。对象内的孔的轮廓(如果有的话)放置在层次结构-2中。如果它内部有任何物体,其轮廓只能重新放置在层次1中。它在等级2中的孔洞等等。

只要考虑黑色背景上的“大白色的零”图像即可。零的外圈属于第一层次,零的内圈属于第二层次。

我们可以用一个简单的图像来解释它。在这里,我们已经用红色标出了轮廓的顺序以及它们所属的层次,颜色为绿色(1或2)。顺序与OpenCV检测轮廓的顺序相同。







所以考虑第一个轮廓,即轮廓0.它的层次结构是1.它有两个孔,轮廓1和2,它们属于层次2.因此对于轮廓0,同一层级中的下一个轮廓是轮廓3.其第一个孩子是在等级2中的轮廓-1。他没有父项,因此它在层次结构1中。所以它的层次数组是[3,-1,1,-1]。


现在轮廓-1。他在层次结构2中。下一个在同一层次中(在轮廓-1的父项之下)是轮廓2.没有前一个,也就是没有孩子。父母的轮廓是0,所以数组是[2,-1,-1,0].


同样的轮廓-2:它在层次-2.轮廓0下的同一层次中没有下一个轮廓。所以没有下一步。以前是轮廓-1.没有孩子啊,父母是轮廓-0.所以数组是[-1,1,-1,0].

轮廓-3:层次-1中的下一个轮廓是-5.以前是轮廓-0。孩子是轮廓4并且没有父母。所以数组是[5,0,4,-1].

轮廓4:在轮廓-3下的层次2中,他没有兄弟。所以没有下一个,没有以前,没有孩子,父母是轮廓3.所以数组是[-1,-1,-1,3].

这是我得到的最终答案:


 
>>> hierarchyarray([[[ 3, -1,  1, -1],        [ 2, -1, -1,  0],        [-1, 
1, -1,  0],        [ 5,  0,  4, -1],        [-1, -1, -1,  3],        [ 7,  3, 
6, -1],        [-1, -1, -1,  5],        [ 8,  5, -1, -1],        [-1,  7, -1,
-1]]])
4)RETR_TREE



这是最后一个,它检索所有轮廓并创建完整的家庭层次列表。它甚至告诉我们,爷爷,父亲,儿子,孙子是谁,甚至还有….


例如,我拍摄了上面的图像,重写了cv2.RETR_TREE的代码,根据OpenCV给出的轮廓重新排序并对其进行分析。再次,红色字母给出等高线数字,绿色字母给出等级顺序。





取轮廓-0:它在层次结构-0中。同一层次中的下一个轮廓是林廓-7.没有以前的轮廓。孩子是轮廓-1.没有父母。所以数组是[7,-1,1,-1].

采取轮廓-2:它在层次1.没有同一级别的轮廓。没有前一个,孩子是轮廓2。父级轮廓为0。所以数组是[-1,-1,2,0].

以下是完整答案:
>>> hierarchyarray([[[ 7, -1,  1, -1],        [-1, -1,  2,  0],        [-1,
-1,  3,  1],        [-1, -1,  4,  2],        [-1, -1,  5,  3],        [ 6, -1,
-1,  4],        [-1,  5, -1,  4],        [ 8,  0, -1, -1],        [-1,  7, -1,
-1]]])



最后一份代码示例:

''' OpenCV中的轮廓: 1.绘制轮廓:cv2.drawCOntours(img,contours,index,color,thickness)
2.轮廓近似法:有时候并不需要存储所有边界,只需要存储这条线的两个端点。删除所有冗余的点并压缩轮廓,从而大大节省内存
3.轮廓特征:cv2.moments()计算所有时刻值的字典,如物体的质心、物体的面积、周长、重心等 ''' import cv2 import numpy
as np from matplotlib import pyplot as plt plt.rcParams['font.sans-serif'] =
['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
img = cv2.imread('temple.png', 0) ret, thresh = cv2.threshold(img, 100, 255, 0)
binary, contours, hierarchy = cv2.findContours(thresh, 1, 2) cv2.imshow('1',
binary) cnt = contours[0] ''' M = cv2.moments(cnt) # 轮廓周长 perimeter =
cv2.arcLength(cnt, True) # 轮廓区域 area = cv2.contourArea(cnt) # area=M['m00'] #
轮廓近似 epsilon = 0.1 * cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt,
epsilon, True) # 轮廓凸包 hull = cv2.convexHull(cnt) print('cnt:', cnt)
print('轮廓近似坐标:', approx) print('轮廓周长:', perimeter) print('轮廓区域:', area)
print('图像时刻:', M) ''' #
直线边界矩形:是一个直的矩形,不考虑对象的旋转,所以边界矩形的面积不会最小,这个矩形由cv2.boundingRect()发现 x, y, w, h =
cv2.boundingRect(cnt) img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0,
0), 2) # 旋转矩形:边界矩形以最小面积绘制的,所以它考虑旋转,使用的函数是cv2.minAreaRect(), #
返回一个Box2D的结构(中心(x,y),(宽度,高度),旋转角度) # 绘制这个矩形需要矩形的四个角,它是通过函数cv2.boxPoints()获得的
rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) box = np.int0(box) img =
cv2.drawContours(img, [box], 0, (0, 0, 255), 0) #
最小封闭圈:使用函数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) #
拟合椭圆:接下来将一个椭圆拟合到一个对象,它返回椭圆被刻在其中的旋转矩形 ellipse = cv2.fitEllipse(cnt) img =
cv2.ellipse(img, ellipse, (0, 255, 0), 2) # 拟合线条:用一条线来拟合一组点,下图包含一组白点,可以近似为一条线
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)
cv2.imshow('6', img) ''' titles = ['原图', '直线边界矩形', '旋转矩形', '最小封闭圈', '拟合椭圆',
'拟合线条'] images = [img, rectContours, rotateRect, minCloseCircle, fitEllipse,
fitLine] for i in range(6): plt.subplot(2, 3, i + 1), plt.title(titles[i]),
plt.imshow(images[i]) plt.xticks([]), plt.yticks([]) plt.show() '''
cv2.waitKey(0) & 0xFF
结果:












标签

归档

阅读排行