目录

  • 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)

从这个矩,你可以提取有用的数据,如面积、中心点等。中心点是由Cx=M10/M00和Cy=M01/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),(x+w,y+h),(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} AspectRatio=HeightWidth​

x,y,w,h = cv.boundingRect(cnt)
aspect_ratio = float(w)/h

2.外延

外延是指轮廓线面积与边界矩形面积的比率。
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} Extent=BoundingRectangleAreaObjectArea​

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

3.实体性

实体性是指轮廓面积与凸包面积的比率。
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} Solidity=ConvexHullAreaContourArea​

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

4.等效直径

等效直径是指其面积与轮廓面积相同的圆的直径。
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给出的坐标是(x,y)格式。所以基本上答案会互换。注意,row=y,column=x。

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])

例如,如果我把它应用于印度地图,我得到以下结果。

OpenCV中的图像处理3.9(六)轮廓线特征与属性相关推荐

  1. Python中的图像处理(第六章)Python图像量化及采样处理(2)

    Python中的图像处理(第六章)Python图像量化及采样处理(2) 前言 一. Python准备 二. Python仿真 三. 小结 前言 随着人工智能研究的不断兴起,Python的应用也在不断上 ...

  2. 第四章:OpenCV中的图像处理

    第四章:OpenCV中的图像处理 本章节你将学习图像的改变色彩空间.提取对象.图像的几何变换.图像的阈值.平滑图像等OpenCV图像处理的基本内容. 更多内容请关注我的GitHub库:TonyStar ...

  3. OpenCV中的图像处理 —— 图像阈值+图像平滑+形态转换

    OpenCV中的图像处理 -- 图像阈值+图像平滑+形态转换 目录 OpenCV中的图像处理 -- 图像阈值+图像平滑+形态转换 1. 图像阈值 1.1 简单阈值 1.2 自适应阈值 1.3 Otsu ...

  4. OpenCV 中的图像处理 004_平滑图像

    本文主要内容来自于 OpenCV-Python 教程 的 OpenCV 中的图像处理 部分,这部分的全部主要内容如下: 改变色彩空间 学习在不同色彩空间之间改变图像.另外学习跟踪视频中的彩色对象. 图 ...

  5. python识别图像中绿色的部分_[OpenCV-Python] OpenCV 中的图像处理 部分 IV (四)

    部分 IV OpenCV 中的图像处理 21 OpenCV 中的轮廓 21.1 初识轮廓 目标 • 理解什么是轮廓 • 学习找轮廓,绘制轮廓等 • 函数:cv2.findContours(),cv2. ...

  6. OpenCV中的图像处理 —— 傅里叶变换+模板匹配

    OpenCV中的图像处理 -- 傅里叶变换+模板匹配 现在也在逐渐深入啦,希望跟大家一起进步越来越强 目录 OpenCV中的图像处理 -- 傅里叶变换+模板匹配 1. 傅里叶变换 1.1 Numpy实 ...

  7. OpenCV中的图像处理 —— 霍夫线 / 圈变换 + 图像分割(分水岭算法) + 交互式前景提取(GrabCut算法)

    OpenCV中的图像处理 -- 霍夫线 / 圈变换 + 图像分割(分水岭算法) + 交互式前景提取(GrabCut算法)

  8. OpenCV中的图像处理 —— 改变颜色空间+图像几何变换

    OpenCV中的图像处理 -- 改变颜色空间+图像几何变换 这一部分主要介绍OpenCV图像处理中的改变颜色空间和图像的几何变换,颜色空间的改变应用非常广泛,在处理图像的实际问题中,经常需要要图像变换 ...

  9. python去除图片复杂背景_[OpenCV-Python] OpenCV 中的图像处理 部分 IV (五)

    部分 IV OpenCV 中的图像处理 22 直方图 22.1 直方图的计算,绘制与分析 目标 • 使用 OpenCV 或 Numpy 函数计算直方图 • 使用 Opencv 或者 Matplotli ...

  10. OpenCV中的图像处理 —— 图像梯度+Canny边缘检测+图像金字塔

    OpenCV中的图像处理 -- 图像梯度+Canny边缘检测+图像金字塔 目录 OpenCV中的图像处理 -- 图像梯度+Canny边缘检测+图像金字塔 1. 图像梯度 1.1 Sobel和Schar ...

最新文章

  1. python写byte数组到文件_这可能是写过最详细的Python文件操作。网友:收藏备用(中篇)...
  2. MySql模糊查询中特殊字符处理
  3. 大巧不工-WEB前端设计修炼之道pdf
  4. 前端包管理工具 yarn
  5. phpstudy2018 安装xdebug扩展
  6. 如何画好一张架构图?(内含知识图谱)
  7. SAP CRM系统里Opportunity预期销售金额和货币相关的自动转换
  8. javaone_JavaOne 2012覆盖率
  9. jQuery插件scrollToTop 4行代码实现网站回到顶部
  10. 网页打开共享目录_“馆员说事儿”之三大中文数据库期刊封面、目录、封底下载方法步骤(三)中国知网...
  11. Java反射机制介绍
  12. HBase数据模型解析和基本的表设计分析
  13. 计算机基础多选试题及答案,计算机基础试题及答案
  14. Android APK反编译教程(带工具)
  15. 洛谷-UVA12676 Inverting Huffman(反转树)
  16. cPanel主机自定义php.ini文件
  17. Invalid prop: custom validator check failed for prop “pagination“.
  18. MOS管当开关控制时,为什么一般用PMOS做上管NMOS做下管?
  19. 开发软件费用为什么这么贵?
  20. 《新零售 低价高效的数据赋能之路》读后感

热门文章

  1. 向日葵远程崩了 官方回应:预计16点前将恢复正常登录
  2. 巨控PLC远程下载调试最新方案
  3. 架构漫谈:业务架构、应用架构与基础架构
  4. 【低功耗蓝牙】④ 蓝牙MIDI协议
  5. 2013年度中国优秀开源项目
  6. 2048左移JAVA代码实现,200 行代码实现 2048 游戏
  7. element弹出toast提示窗口
  8. layui数据表格增加序号列(第二页从1开始 or 接上一页序号开始)
  9. 下拉推广系统立择火星推荐_下拉框软件都择火星下拉下拉框软件速来火星下拉...
  10. 无法完全卸载Office软件 完美卸载Office办公软件教程