当前位置: 首页 > news >正文

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

目录

  • 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个点)。看,它节省了多少内存!!!。

Image Name

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%时的情况。第三个参数指定曲线是否是封闭的。

Image Name

5. 凸面体

凸面体看起来与轮廓逼近相似,但它不是(两者在某些情况下可能提供相同的结果)。在这里,cv.convexHull()函数检查曲线是否有凸性缺陷并进行修正。一般来说,凸形曲线是指总是凸出来的曲线,或者至少是平的。而如果是向内隆起,则被称为凸性缺陷。例如,请看下面的手的图片。红线表示手的凸体。双面的箭头标志显示了凸性缺陷,这是局部最大凸包与轮廓的偏差。

Image Name

关于它的语法,有一点需要讨论。

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)

两个矩形都显示在一张图片上。绿色矩形显示的是正常的边界矩形。红色矩形是旋转后的矩形。

Image Name

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)

Image Name

9. 拟合椭圆

下一个是将一个椭圆拟合到一个物体上。它返回旋转后的矩形以及内接的椭圆。

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

Image Name

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)

Image Name

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

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

Image Name

相关文章:

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

目录 3.9 OpenCV中的轮廓线3.9.1 轮廓线:入门目标什么是轮廓线?如何绘制轮廓线?轮廓线逼近法 3.9.2 轮廓线的特征1. 矩2. 轮廓线面积3. 轮廓线周长4. 轮廓逼近5. 凸面体6. 检查凸性7. 边界矩形8. 最小包围圈9. 拟合椭圆10. 拟合直线 3.9.3 轮…...

burpsuite+xray实现联动测试(手动分析和自动化测试同时进行)

目的:安全测试过程中手动分析测试与xray自动化扫描测试结合,这样可以从多层保障安全测试的分析,针对平台业务接口量大的安全测试是十分有用的,可以实现双向测试同时开始。 xray简介 xray 是一款功能强大的安全评估工具&#xff…...

2023年专业连锁行业研究报告

第一章 行业概况 专业连锁行业是指以连锁经营模式运营的公司,其主要业务涵盖零售、餐饮、酒店、医疗、教育等领域。这些公司通过规模化、标准化的经营模式和供应链管理,提供专业化、高质量的产品和服务。专业连锁行业在全球范围内蓬勃发展,并…...

Mysql数据库(六):基本的SELECT语句

基本的SELECT语句 前言一、SELECT...二、SELECT ... FROM三、列的别名四、去除重复行五、空值参与运算六、着重号七、查询常数八、显示表结构九、过滤数据 前言 本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识,有兴趣的小伙伴可以关注博主&#…...

在CentOS7环境中,实现使用openresty配置文件,达到jwt指定用户userid不能访问的效果

#在CentOS7环境中,实现使用openresty配置文件,达到jwt指定用户userid不能访问的效果。 首先,你需要安装 OpenResty 和 JWT 组件: 安装 OpenResty 参考 OpenResty 的官方安装文档,在终端执行如下命令: $…...

SpringBoot 源码分析初始化应用上下文(1)-createApplicationContext

前言:springBoot的版本是 2.2.4.RELEASE 一、入口 /*** Run the Spring application, creating and refreshing a new* {link ApplicationContext}.* param args the application arguments (usually passed from a Java main method)* return a running {link A…...

STM32队列

目录 什么是队列? 队列特点 1. 数据入队出队方式 2. 数据传递方式 3. 多任务访问 4. 出队、入队阻塞 队列相关 API 函数 1. 创建队列 参数: 2. 写队列 参数: 返回值: 3. 读队列 参数: 返回值&#xf…...

探索Beyond Compare:让文件比较和管理变得简单高效

在这个信息爆炸时代,我们的日常生活和工作中需要处理大量的数据和文档。在这个过程中,有时候我们会面临找出不同文件之间的差异、合并重复内容等需求。那么,有没有一款软件可以帮助我们轻松地完成这些任务呢?答案当然是肯定的&…...

动态网站Servelt基础

文章目录 一、Servlet基础(一)Servlet概述1、Servlet是什么2、Servlet容器3、Servlet应用程序的体系结构 (二)Servlet的特点1、功能强大2、可移植3、性能高效4、安全性高5、可扩展 (三)Servlet接口1、Servl…...

Docker 网络

Docker 网络实现原理 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机…...

Tomcat的优化

Tomcat的优化 一、Tomcat 优化Tomcat 配置文件参数优化 二、系统内核优化三、Tomcat 配置 JVM 参数:参数含义 一、Tomcat 优化 Tomcat默认安装下的缺省配置并不适合生产环境,它可能会频繁出现假死现象需要重启,只有通过不断压测优化才能让它…...

一个问题来对比文心一言和chatgpt

问题: 请注意, 孩子不会说话,他无法用语言来回复妈妈的问题, 请生成以下剧本:一个妈妈和一岁不会说话的婴儿的日常vlog的剧本 文心一言 场景一:早晨 (妈妈和孩子在客厅里醒来) 妈妈&…...

防雪崩利器之Hystrix

Hystrix作为一个容错组件,本文从它的作用、熔断设计、工作流程和应用方面一一道来,帮助大家了解如何使用。 1、什么是灾难性雪崩效应 要讲Hystrix,我们就要讲一种场景,在微服务架构中,如果底层服务出现故障&#xff0…...

机器学习复习(上)

严正声明:本文的答案是ChatGPT的回答,仅供参考,不代表就是正确答案!!! 1.解释什么是过拟合和欠拟合,如何降低过拟合? 过拟合(overfitting)指的是一个模型在训练数据上表…...

node笔记_express结合formidable实现前后端的文件上传

文章目录 ⭐前言⭐安装http请求的文件解析依赖库💖 安装 formidable💖 node formidable接受formData上传参数 ⭐上传的页面搭建💖 vue2 element upload💖 node 渲染 上传文件 ⭐后端生成api上传文件到指定目录💖完整的…...

CKA 09_Kubernetes工作负载与调度 资源调度 三类QoS request 资源需求 limit 资源限额

文章目录 1. 资源调度1.1 准备工作1.2 为什么需要 request 和 limit1.3 内存限制1.3.1 Brustable1.3.2 Guaranteed1.3.3 BestEffort1.3.4 当容器申请的资源超出 limit 和 request 1.4 CPU限制 1. 资源调度 1.1 准备工作 Kubernetes 采用 request 和 limit 两种限制类型来对资源…...

【pytorch】维度变换

【pytorch】维度变换 View操作unSqueeze操作图片处理的一个案例squeeze 维度删减操作维度扩展-expand维度扩展-repeat矩阵的转置操作-transpose View操作 将一个四维的张量(b x c x h x w)转换成一个二维的张量 对于四张图片 将每一张图像用一行向量进…...

vue3中的nextTick()

目录 nextTick() 方法用法回调函数方式使用await方式使用 实现原理使用nextTick() 方法时的注意事项 nextTick() 方法 nextTick() 方法是一个非常强大的工具,是一个等待下一次 DOM 更新刷新的工具方法。用于将一个函数以异步的方式推迟到下一个 DOM 更新周期执行。…...

高效学习传感器|霍尔式传感器

01、霍尔式传感器的工作原理 1●霍尔效应 霍尔式传感器的物理基础是霍尔效应。如图1所示,在一块长度为l、宽度为b、厚度为d的长方体导电板上,左、右、前、后侧面都安装上电极。在长度方向上通入电流I,在厚度方向施加磁感应强度为B的磁场。 ■…...

2023年前端面试高频考点HTML5+CSS3

目录 浏览器的渲染过程⭐⭐⭐ CSS 、JS 阻塞 DOM 解析和渲染 回流(重排)和重绘⭐⭐ 选择器 ID选择器、类选择器、标签选择器(按优先级高到低排序)⭐⭐ 特殊符号选择器(>,,~,空格&#xff0…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...