OpenCV-Python(21):OPenCV查找及绘制轮廓

news2024/11/28 22:03:23

1.认识轮廓

1.1 目标

  • 理解什么是轮廓
  • 学习掌握找轮廓、绘制轮廓等
  • 学习使用cv2.findContours()、cv2.drawContours()函数的用法

1.2 什么是轮廓

        在OpenCV中,轮廓是图像中连续的边界线的曲线,具有相同的颜色或者灰度,用于表示物体的形状。轮廓在图像处理和计算机视觉中非常重要,常用于物体检测、形状分析、图像分割等任务。

提示:

  • 为了使轮廓更加准确,要使用二值化图像。所以,在寻找轮之前,要进行阈值化处理或者Canny边界检测。
  • 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后想使用原始图像的话,你应该将原始图像存储到其他变量中。
  • 在OpenCV 中,查找廓就像在黑色背景中查找白色物体。你应该记住,要找的物体应该是白色而背景应该是黑色。

在OpenCV中,可以通过以下步骤找到图像中的轮廓:

  1. 对图像进行预处理,如灰度化、二值化等操作。
  2. 使用cv2.findContours()函数找到图像中的轮廓。该函数会返回一个包含轮廓信息的列表。
  3. 遍历轮廓列表,可以使用cv2.drawContours()函数将轮廓绘制到图像上。
  4. 对轮廓进行进一步的分析和操作,如计算轮廓的面积、周长,寻找轮廓的凸包等。

cv2.findContours()是一个用于查找图像中轮廓的函数。它的语法如下:

contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

参数说明:

  • image:输入的二值化图像,通常为灰度图像或二值图像。
  • mode:轮廓检索模式,指定轮廓的层级结构。常用的取值有:
    • cv2.RETR_EXTERNAL:只检测最外层的轮廓。
    • cv2.RETR_LIST:检测所有的轮廓,不建立层级关系。
    • cv2.RETR_CCOMP:检测所有的轮廓,并将它们组织为两层的层级结构。
    • cv2.RETR_TREE:检测所有的轮廓,并完整地重建轮廓之间的层级关系。
  • method:轮廓近似方法。常用的取值有:
    • cv2.CHAIN_APPROX_NONE:保存所有的轮廓点。
    • cv2.CHAIN_APPROX_SIMPLE:压缩水平、垂直和对角线方向上的轮廓,仅保留终点。
  • contours:输出的轮廓列表,每个轮廓由一系列点组成。
  • hierarchy:可选输出的层级关系,用于表示轮廓之间的层级关系。
  • offset:可选的偏移量,用于调整轮廓的位置。

4.0以上的版本cv2.findContours()函数会返回两个值(OpenCV 3.0系列版本会返回3个值,多出的第一个值是图像),分别是轮廓列表和层级关系。轮廓列表是一个包含每个轮廓的Numpy数组,每个数组中的元素表示轮廓上的一个点,包含对边界点(x,y)的坐标。层级关系是一个包含每个轮廓的层级关系信息的Numpy数组,用于表示轮廓之间的层级关系,可用于进一步分析轮廓的形状和结构。以下是一个使用cv2.findContours()函数查找轮廓的示例代码:

import cv2

# 读取图像
image = cv2.imread("image.jpg")

# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 寻找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 三个参数的返回
'''
_,contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
'''

# 绘制轮廓
cv2.drawContours(image, contours, -1, (0, 255, 0), 3)

# 显示图像
cv2.imshow("Contours", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

代码中,首先读取了一张图像,并对其进行了灰度化和二值化处理。然后使用cv2.findContours()函数找到图像中的轮廓,并将其绘制到原始图像上。最后显示图像并等待按键关闭窗口。

1.3 怎样绘制轮廓

    cv2.drawContours()是一个用于绘制轮廓的函数,它可以根据你提供的边界点绘制任何形状。它的语法如下:

cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])

参数说明:

  • image:要绘制轮廓的图像。
  • contours:轮廓列表,即cv2.findContours()函数返回的轮廓列表。
  • contourIdx:要绘制的轮廓的索引,绘制独立轮廓时很有用,-1表示绘制所有轮廓。
  • color:绘制轮廓的颜色,可以是一个BGR元组或一个整数。
  • thickness:轮廓线的粗细,默认为1。
  • lineType:轮廓线的类型,默认为cv2.LINE_8,表示8连通线。
  • hierarchy:层级关系,即cv2.findContours()函数返回的层级关系。
  • maxLevel:绘制轮廓的最大层级,默认为0,表示只绘制当前层级的轮廓。
  • offset:可选的偏移量,用于调整轮廓的位置。

cv2.drawContours()函数用于在图像上绘制轮廓。可以通过设置contourIdx参数来指定要绘制的轮廓的索引,-1表示绘制所有轮廓。可以通过设置color参数来指定绘制轮廓的颜色。绘制的轮廓线的粗细可以通过thickness参数进行设置,默认为1。轮廓线的类型可以通过lineType参数进行设置,默认为cv2.LINE_8,表示画8连通线。

以下是一个使用cv2.drawContours()函数绘制轮廓的示例代码:

import cv2

# 读取图像
image = cv2.imread("image.jpg")

# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 寻找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 绘制轮廓
cv2.drawContours(image, contours, -1, (0, 255, 0), 3)

# 显示图像
cv2.imshow("Contours", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

在上述代码中,首先读取了一张图像,并对其进行了灰度化和二值化处理。然后使用cv2.findContours()函数找到图像中的轮廓,并使用cv2.drawContours()函数将轮廓绘制到原始图像上。最后显示图像并等待按键关闭窗口。

绘制独立的廓,如第四个轮廓:

img = cv2.drawContour(img, contours, -1, (0,255,0), 3)

但是大多数时候下面的方法更有用:

img = cv2.drawContours(img, contours, 3, (0,255,0), 3)

注意:最后这两种方法结果是一样的,但是后面的知识会告诉你最后一种方法更有用。

1.4 轮廓的近似方法

        上面查找轮廓的时候,提到了是函数cv2.findCountours() 有一个轮廓的近似方法参数,那么它到底代表什么意思呢?
        上面我们已经提到轮廓是一个形状具有相同灰度值的边界。它会存储形状边界上所有的(x,y)坐标。但是,需要将所有的这些边界点都存储吗?这就是这个参数要告诉函数cv2.findContours 的。
        这个参数如果被设置为cv2.CHAIN_APPROX_NONE,所有的边界点都会被存储。但是我们真的需要这么么多点吗?例如,当我们找的边界是一条直线时。你用需要把直线上所有的点来表示直线吗?不是的,我们只需要这条直线的两个端点而已。这就是cv2.CHAIN_APPROX_SIMPLE 要做的。它会将将廓上的冗余点去掉,压缩轮廓,从而节省内存开支。
        我们用下图中的矩形来演示这个技术。在轮廓列表中的每一个坐标上画一个蓝色圆圈。第一个图显示使用cv2.CHAIN_APPROX_NONE 的效果,一共734 个点。第二个图是使用cv2.CHAIN_APPROX_SIMPLE 的结果,只有4 个点。看到他的威力了吧:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1348767.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

labuladong日常刷题-差分数组 | LeetCode 1109航班预定统计 | 花式遍历 151反转字符串里的单词

差分数组–前缀和数组的升级 LeetCode 1109 航班预定统计 2024.1.1 题目链接labuladong讲解[链接] class Solution { public:vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {//构建航班人数数组&#xff0c;数组大小为n,初…

填充点云孔洞(较大的洞)halcon算法

前言 很多时候,一些小洞可以通过平滑算法,或者三角化算法的参数调整,即可对较小的孔洞进行填充,但是较大的洞却很难通过上面的算法进行填充。 下面介绍一种填充孔洞的思路: 步骤一:对点云进行滤波处理,找到孔洞所在平面 本文为了更直观的进行讲解,去掉了去除噪声和…

如何在2024年编写Android应用程序

如何在2024年编写Android应用程序 本文将介绍以下内容&#xff1a; 针对性能进行优化的单活动多屏幕应用程序 &#x1f92b;&#xff08;没有片段&#xff09;。应用程序架构和模块化 → 每个层面。Jetpack Compose 导航。Firestore。应用程序架构&#xff08;模块化特征驱动…

软件测试/测试开发丨Python 模块与包 学习笔记

python的程序结构 组成&#xff1a; packagemodulefunction 模块 模块是在代码量变得相当⼤了之后&#xff0c;为了将需要重复使⽤的有组织的代码放在⼀起&#xff0c;这部分代码可以被其他程序引⽤&#xff0c;从⽽使⽤该模块⾥的函数等功能&#xff0c;引⽤的过程叫做导…

NodeJs - Chrome内存分析工具使用

NodeJs - Chrome内存分析工具使用 一. 前期准备二. Chrome 内存分析工具使用2.1 查看快照2.2 使用案例 一. 前期准备 我们下载好相关依赖&#xff1a; npm i v8-profiler-next测试代码&#xff1a; const v8Profiler require(v8-profiler-next) const fs require(fs)funct…

从入门到精通UNet: 让你快速掌握图像分割算法

文章目录 一、UNet 算法简介1.1 什么是 UNet 算法1.2 UNet 的优缺点1.3 UNet 在图像分割领域的应用 二、准备工作2.1 Python 环境配置2.2 相关库的安装 三、数据处理3.1 数据的获取与预处理3.2 数据的可视化与分析 四、网络结构五、训练模型5.1 模型训练流程5.2 模型评估指标5.…

服务器硬件及RAID配置实战

目录 1、RAID的概念 2、RAID的实现方式 3、标准的RAID 3.1 RAID 0 3.2 RAID 1 3.3 RAID 5 3.4 RAID 10 4、建立硬件 RAID的过程步骤 1、进入RAID 1.1 重启服务器 1.2 进入RAID界面 1.3 在RAID界面切换目录 2、创建RAID 2.1 移动到RAID卡 2.2 按F2&#xff0c;选择…

【嵌入式学习笔记-01】什么是UC,操作系统历史介绍,计算机系统分层,环境变量(PATH),错误

【嵌入式学习笔记】什么是UC&#xff0c;操作系统历史介绍&#xff0c;计算机系统分层&#xff0c;环境变量&#xff08;PATH&#xff09;&#xff0c;错误 文章目录 计算机系统分层什么是操作系统&#xff1f; 环境变量什么是环境变量&#xff1f;环境变量的添加&#xff1f;常…

java 纯代码导出pdf合并单元格

java 纯代码导出pdf合并单元格 接上篇博客 java导出pdf&#xff08;纯代码实现&#xff09; 后有一部分猿友叫我提供一下源码&#xff0c;实际上我的源码已经贴在帖子上了&#xff0c;都是同样的步骤&#xff0c;只是加多一点设置就可以了。今天我再次上传一下相对情况比较完整…

WINDOWS 批量修改图片文件名称

博主家里有一台电脑&#xff0c;存放家庭全部的照片和视频&#xff0c;从智能手机和3G网络发展开始&#xff0c;家里的照片和视频越来越多&#xff0c;已经达到上万个文件。终于&#xff0c;博主找到一个方法整理和保存这些珍贵的数据资料。 一、按年代目录整理照片和视频 按年…

【大数据面试知识点】Spark的DAGScheduler

Spark数据本地化是在哪个阶段计算首选位置的&#xff1f; 先看一下DAGScheduler的注释&#xff0c;可以看到DAGScheduler除了Stage和Task的划分外&#xff0c;还做了缓存的跟踪和首选运行位置的计算。 DAGScheduler注释&#xff1a; The high-level scheduling layer that i…

【随口一说】最近的CSDN

这段时间随便发的一篇博文很快就有“点赞”、“收藏”、“关注”的信息&#xff0c; 而且简单看了一眼用户&#xff0c;很多都是空的或者一堆转载&#xff0c; 机器人也太明显了点&#xff0c;很让人不舒服&#xff0c; 不花点心思设计文章评优推送算法反倒用机器人刷热门&…

【C++】类与对象

文章目录 1. 面向过程和面向对象的初步认识2. 类的引入3. 类的定义4. 类的访问限定符及封装4.1 访问限定符4.2 封装 5. 类的作用域6. 类的实例化7. 类对象模型7.1 如何计算类对象的大小7.2 类对象的存储方式猜测7.3 结构体内存对齐规则 8. this指针8.1 this指针的引出8.2 this指…

3294 李白的酒

#include<bits/stdc.h> using namespace std; int main(){int n;double ans;scanf("%d",&n);for(int i1;i<n;i)ans1,ans/2;printf("%.5f",ans); }

一元函数微分学——刷题(10

目录 1.题目&#xff1a;2.解题思路和步骤&#xff1a;3.总结&#xff1a;小结&#xff1a; 1.题目&#xff1a; 2.解题思路和步骤&#xff1a; 首先题目中给了一个要点&#xff0c;就是周期为5&#xff0c;显然要求的那个点和题目没任何关系&#xff0c;所以利用周期为5&…

[DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]

文章目录 概要I Introduction小结 概要 提出的架构&#xff0c;双注意力U-Net与特征融合&#xff08;DAU-FI Net&#xff09;&#xff0c;解决了语义分割中的挑战&#xff0c;特别是在多类不平衡数据集上&#xff0c;这些数据集具有有限的样本。DAU-FI Net 整合了多尺度空间-通…

数据的分片和路由

之前我们讲解了数据的复制&#xff0c;也就是说让多台机器保留相同的副本&#xff0c;适合用于读多写少的问题&#xff0c;我们这里讲的是数据的分片&#xff0c;分片的目的是将数据进行切分让他们分布到不同的机器上&#xff0c;其中一个动机是数据可能很大如果单纯存放到一个…

macos系统中,获取系统的“文件夹”图标,比如“下载文件夹”有不同的文件夹图标,怎么获得这个文件夹图标呢

在macOS系统中&#xff0c;如果您想要获取“下载”文件夹的图标以用作其他用途&#xff08;例如制作快捷方式、自定义应用图标等&#xff09;&#xff0c;可以按照以下步骤操作&#xff1a; 打开Finder。使用Spotlight搜索或者直接导航到 /System/Library/CoreServices/CoreTy…

记矩阵基础概念

转自up&#xff1a;Naruto_Qcsdn&#xff1a;三维空间几何变换矩阵 先贴个站里分享的基础概念。 learn form 肥猫同学VFX b站&#xff1a;会用transform就会用矩阵 移动 旋转 缩放 1.transofrm ——输出变化矩阵 可以移动transform查看变化去理解 位移 缩放 旋转 由此—…

B+树的插入删除

操作 插入 case2的原理,非叶子节点永远和最右边的最左边的节点的值相等。 case3:的基本原理 非叶子节点都是索引节点 底层的数据分裂之后 相当于向上方插入一个新的索引(你可以认为非叶子节点都是索引),反正第二层插入160 都要分裂,然后也需要再插入(因为索引部分不需要重…