网站开启速度变慢了,网页设计与制作策划书,扬州seo推广,昆明市城市基本建设档案馆网站目录 3.9 OpenCV中的轮廓线3.9.1 轮廓线#xff1a;入门目标什么是轮廓线#xff1f;如何绘制轮廓线#xff1f;轮廓线逼近法 3.9.2 轮廓线的特征1. 矩2. 轮廓线面积3. 轮廓线周长4. 轮廓逼近5. 凸面体6. 检查凸性7. 边界矩形8. 最小包围圈9. 拟合椭圆10. 拟合直线 3.9.3 轮… 目录 3.9 OpenCV中的轮廓线3.9.1 轮廓线入门目标什么是轮廓线如何绘制轮廓线轮廓线逼近法 3.9.2 轮廓线的特征1. 矩2. 轮廓线面积3. 轮廓线周长4. 轮廓逼近5. 凸面体6. 检查凸性7. 边界矩形8. 最小包围圈9. 拟合椭圆10. 拟合直线 3.9.3 轮廓属性1.纵横比2.外延3.实体性4.等效直径5.方向6.掩膜和像素点7.最大值、最小值和它们的位置8.平均颜色或平均灰度9.极点 翻译及二次校对cvtutorials.com 编辑者廿瓶鲸和鲸社区Siby团队成员
3.9 OpenCV中的轮廓线
3.9.1 轮廓线入门
目标
理解什么是轮廓线。学习查找轮廓、绘制轮廓等。你将看到这些函数cv.findContours(), cv.drawContours()
什么是轮廓线
轮廓线可以简单地解释为连接所有连续点沿边界的曲线具有相同的颜色或灰度。轮廓线是形状分析和物体检测与识别的一个有用工具。
为了获得更好的准确性使用二进制图像。因此在寻找轮廓线之前应用阈值或Canny边缘检测。从OpenCV 3.2开始findContours()不再修改源图像了。在OpenCV中寻找轮廓线就像从黑色背景中寻找白色物体。所以请记住要找到的物体应该是白色的背景应该是黑色的。
让我们来看看如何找到二进制图像的轮廓线。
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)
contours, hierarchy cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)cv.findContours()函数中有三个参数第一个是源图像第二个是轮廓检索模式第三个是轮廓逼近方法。然后它输出轮廓线和层次结构。轮廓线是一个包含图像中所有轮廓线的Python列表。每个单独的轮廓线是一个Numpy数组包含物体边界点的x,y坐标。 注意:我们将在后面详细讨论第二个和第三个参数以及层次结构。在那之前代码样本中给它们的值对所有的图像都能正常工作。 如何绘制轮廓线
为了绘制轮廓线我们使用了cv.drawContours函数。它也可以用来绘制任何形状只要你有它的边界点。它的第一个参数是源图像第二个参数是轮廓线应该以Python列表的形式传递第三个参数是轮廓线的索引在绘制单个轮廓线时很有用。 要绘制所有轮廓线传递-1其余参数是颜色、厚度等。
绘制一幅图像中的所有轮廓线。
cv.drawContours(img, contours, -1, (0,255,0), 3)要画一个单独的轮廓比如说第4个轮廓。
cv.drawContours(img, contours, 3, (0,255,0), 3)但在大多数时候下面的方法会很有用。
cnt contours[4]
cv.drawContours(img, [cnt], 0, (0,255,0), 3)注意事项:最后两种方法是一样的但是你会发现最后一种方法更有用。 轮廓线逼近法
这是cv.findContours函数的第三个参数。它实际上表示什么呢
上面我们说过轮廓线是具有相同灰度的形状的边界。它存储了一个形状的边界的x,y坐标。但它是否存储了所有的坐标这是由这个轮廓逼近方法指定的。
如果你传递cv.CHAIN_APPROX_NONE所有的边界点都会被存储。但实际上我们需要所有的点吗例如你找到了一条直线的轮廓。你需要这条线上的所有点来表示这条直线吗不我们只需要那条线的两个端点。这就是cv.CHAIN_APPROX_SIMPLE的作用。它删除了所有多余的点并压缩了轮廓从而节省了内存。
下面是一个矩形的图片演示了这个技术。只要在轮廓线数组中的所有坐标上画一个圆用蓝色画。第一张图片显示了我用cv.CHAIN_APPROX_NONE得到的点734个点第二张图片显示了用cv.CHAIN_APPROX_SIMPLE的点只有4个点。看它节省了多少内存。 3.9.2 轮廓线的特征
在这篇文章中我们将学习
找到轮廓的不同特征如面积、周长、中心点、边界盒等。你会看到很多与轮廓线有关的函数。
1. 矩
图像矩帮助你计算一些特征如物体的质心、物体的面积等。
函数cv.ments()给出了一个所有计算出的矩的字典。见下文:
import numpy as np
import cv2 as cv
img cv.imread(star.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)从这个矩你可以提取有用的数据如面积、中心点等。中心点是由CxM10/M00和CyM01/M00的关系给出的。这可以按以下方式进行。
cx int(M[m10]/M[m00])
cy int(M[m01]/M[m00])2. 轮廓线面积
轮廓线面积由函数cv.contourArea()或从矩M[‘m00’]给出。
area cv.contourArea(cnt)3. 轮廓线周长
它也被称为弧长。它可以用cv.arcLength()函数计算出来。第二个参数指定形状是一个封闭的轮廓如果传递的是True还是只是一条曲线。
perimeter cv.arcLength(cnt,True)4. 轮廓逼近
它根据我们指定的精度将一个轮廓形状逼近到另一个顶点数量较少的形状。它是Douglas-Peucker算法的一个实现。
为了理解这一点假设你试图在图像中找到一个正方形但由于图像中的一些问题你没有得到一个完美的正方形而是一个 “坏形状”如下图所示。现在你可以用这个函数来近似地处理这个形状。在这个函数中第二个参数叫做epsilon它是轮廓到近似轮廓的最大距离。它是一个精度参数。为了得到正确的输出需要明智地选择epsilon。
epsilon 0.1*cv.arcLength(cnt,True)
approx cv.approxPolyDP(cnt,epsilon,True)下面在第二张图片中绿线显示了epsilon为弧长的10%时的近似曲线。第三张图显示的是epsilon为弧长的1%时的情况。第三个参数指定曲线是否是封闭的。 5. 凸面体
凸面体看起来与轮廓逼近相似但它不是两者在某些情况下可能提供相同的结果。在这里cv.convexHull()函数检查曲线是否有凸性缺陷并进行修正。一般来说凸形曲线是指总是凸出来的曲线或者至少是平的。而如果是向内隆起则被称为凸性缺陷。例如请看下面的手的图片。红线表示手的凸体。双面的箭头标志显示了凸性缺陷这是局部最大凸包与轮廓的偏差。 关于它的语法有一点需要讨论。
hull cv.convexHull(point[, hull[, clockwise[, returnPoints])参数细节:
points是我们传入的轮廓线。hull是输出通常我们避免使用它。clockwise方向标志。如果它是True输出的凸面体是顺时针方向的。否则它的方向是逆时针的。returnPoints : 默认为 “真”。然后它返回凸包点的坐标。如果是False它返回与凸包点对应的轮廓点的索引。
因此要得到上图中的凸包只需按以下方法即可:
hull cv.convexHull(cnt)但是如果你想找到凸性缺陷你需要传递returnPoints False。为了理解它我们将采取上面的矩形图像。首先我发现它的轮廓为cnt。现在我用returnPoints True找到了它的凸面我得到了以下值。[[234 202]], [[51 202]], [[51 79]], [[234 79]]是矩形的四个角点。现在如果用returnPoints False做同样的事情我得到的结果是[[129], [67], [0], [142]]。这些是轮廓线中相应的点的索引。例如检查第一个值cnt[129] [[234, 202]]这与第一个结果相同其他的也是如此。
当我们讨论凸性缺陷时你会再次看到它。
6. 检查凸性
有一个函数可以检查一条曲线是否是凸的即cv.isContourConvex()。它只是返回True或False。没什么大不了的。
k cv.isContourConvex(cnt)7. 边界矩形
有两种类型的边界矩形。
7.a. 直线边界矩形
这是一个直线矩形它不考虑物体的旋转。因此边界矩形的面积不会是最小的。它是由函数cv.boundingRect()找到的。
(x,y)为矩形的左上角坐标(w,h)为其宽度和高度。
x,y,w,h cv.boundingRect(cnt)
cv.rectangle(img,(x,y),(xw,yh),(0,255,0),2)7.b. 旋转的矩形
这里边界矩形是以最小面积绘制的所以它也考虑了旋转。使用的函数是cv.minAreaRect()。它返回一个包含以下细节的Box2D结构–中心x,y宽度高度旋转的角度。但是要画这个矩形我们需要矩形的4个角。它可以通过函数cv.boxPoints()获得
rect cv.minAreaRect(cnt)
box cv.boxPoints(rect)
box np.int0(box)
cv.drawContours(img,[box],0,(0,0,255),2)两个矩形都显示在一张图片上。绿色矩形显示的是正常的边界矩形。红色矩形是旋转后的矩形。 8. 最小包围圈
接下来我们使用cv.minEnclosingCircle()函数找到一个物体的圆。它是一个以最小面积完全覆盖物体的圆。
(x,y),radius cv.minEnclosingCircle(cnt)
center (int(x),int(y))
半径 int(radius)
cv.circle(img,center,radius,(0,255,0),2)9. 拟合椭圆
下一个是将一个椭圆拟合到一个物体上。它返回旋转后的矩形以及内接的椭圆。
ellipse cv.fitEllipse(cnt)
cv.ellipse(img,ellipse,(0,255,0),2)10. 拟合直线
同样地我们可以将一条线拟合到一组点上。下面的图片包含一组白色的点。我们可以对它进行近似的直线拟合。
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)3.9.3 轮廓属性
在这里我们将学习如何提取一些常用的物体属性如实体性、等效直径、掩膜图像、平均灰度等。更多的特征可以在Matlab regionprops文档中找到。
注意中心点、面积、周长等也属于这一类但我们在上一章已经看到了
1.纵横比
它是物体的边界矩形的宽度和高度的比率。 A s p e c t R a t i o W i d t h H e i g h t Aspect \; Ratio \frac{Width}{Height} AspectRatioHeightWidth
x,y,w,h cv.boundingRect(cnt)
aspect_ratio float(w)/h2.外延
外延是指轮廓线面积与边界矩形面积的比率。 E x t e n t O b j e c t A r e a B o u n d i n g R e c t a n g l e A r e a Extent \frac{Object \; Area}{Bounding \; Rectangle \; Area} ExtentBoundingRectangleAreaObjectArea
area cv.contourArea(cnt)
x,y,w,h cv.boundingRect(cnt)
rect_area w*h
extent float(area)/rect_area3.实体性
实体性是指轮廓面积与凸包面积的比率。 S o l i d i t y C o n t o u r A r e a C o n v e x H u l l A r e a Solidity \frac{Contour \; Area}{Convex \; Hull \; Area} SolidityConvexHullAreaContourArea
area cv.contourArea(cnt)
hull cv.convexHull(cnt)
hull_area cv.contourArea(hull)
solidity float(area)/hull_area4.等效直径
等效直径是指其面积与轮廓面积相同的圆的直径。 E q u i v a l e n t D i a m e t e r 4 × C o n t o u r A r e a π Equivalent \; Diameter \sqrt{\frac{4 \times Contour \; Area}{\pi}} EquivalentDiameterπ4×ContourArea
area cv.contourArea(cnt)
equi_diameter np.sqrt(4*area/np.pi)5.方向
方向是指物体指向的角度。以下方法也给出了主轴和次轴的长度。
(x,y),(MA,ma),angle cv.fitEllipse(cnt)6.掩膜和像素点
在某些情况下我们可能需要包括该对象的所有点。可以按以下方式进行:
mask np.zeros(imgray.shape,np.uint8)
cv.drawContours(mask,[cnt],0,255,-1)
pixelpoints np.transpose(np.nonzero(mask))
#pixelpoints cv.findNonZero(mask)这里给出了两种方法一种是使用Numpy函数另一种是使用OpenCV函数最后一行注释来做同样的事情。结果也是一样的但有一点不同。Numpy给出的坐标是行列格式而OpenCV给出的坐标是xy格式。所以基本上答案会互换。注意rowycolumnx。
7.最大值、最小值和它们的位置
我们可以用掩膜图像找到这些参数。
min_val, max_val, min_loc, max_loc cv.minMaxLoc(imgray,mask mask)8.平均颜色或平均灰度
在这里我们可以找到一个物体的平均颜色。也可以是灰度模式下物体的平均灰度。我们再次使用相同的掩膜来做这件事。
mean_val cv.mean(im,mask mask)9.极点
极点指的是物体的最上面、最下面、最右边和最左边的点。
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])例如如果我把它应用于印度地图我得到以下结果。