OpenCV 图像轮廓查找与绘制全攻略:从函数使用到实战应用详解
摘要:本文详细介绍了 OpenCV 中用于查找图像轮廓的 cv2.findContours() 函数以及绘制轮廓的 cv2.drawContours() 函数的使用方法。涵盖 cv2.findContours() 各参数(如 mode 不同取值对应不同轮廓检索模式)及返回值的详细解析,搭配多幅示例图片与丰富代码示例展示不同模式下的效果差异,同时展示了 cv2.drawContours() 的用法,并通过案例讲解如何利用轮廓绘制功能获取前景对象,助力读者全面掌握图像轮廓相关操作要点及应用场景。
如果您觉得我的文章对您有帮助,可以点赞收藏关注,持续学习更多与OpenCV相关的知识
OpenCV 图像轮廓查找与绘制全攻略:从函数使用到实战应用详解
- 查找并绘制轮廓
- cv2.findContours()函数的使用
- 返回值countours的属性
- 参数mode与返回值hierarchy
- cv2.drawContours()函数的使用
- 利用轮廓绘制功能,获取前景对象
- 致谢
查找并绘制轮廓
边缘检测能检测出边缘,但是边缘不连续,但不是一个整体。OpenCV提供了cv2.findContours()去查找图像轮廓,cv2.drawContours()将轮廓绘制起来。
cv2.findContours()函数的使用
该函数的语法如下:
image与被处理图像一致,contours返回的轮廓 ,hierarchy 图像的拓普信息(轮廓层次) = cv2.findContours(image原始图像,mode轮廓检索模式,method轮廓的近似方法)
这里有一个补充:当OpenCV版本的大于4.x,返回值没有image
我通过画图板画了一个例子,存储在和代码同一个文件夹下,大家可以复制我的图片,去作为练习,(补充一个重要的前提:OpenCV中,都是从黑色背景中找白色对象,对象是白的,背景是黑的,图片必须是灰度二值图像,对于彩色图像要做好阈值处理):
我将这张图片命名为countours.JPG,这是我的文件夹(我用的是 jupyter notebook 大家用pycharm的就把代码和图片放在同一个文件夹下就可以运行我的代码了):
返回值countours的属性
他的类型是list:
import numpy as np
import cv2
img = cv2.imread("countours.JPG",cv2.IMREAD_GRAYSCALE)
countours , hierarchy = cv2.findContours(img,mode = cv2.RETR_EXTERNAL,method = cv2.CHAIN_APPROX_NONE)
print(type(countours))
每一条轮廓的shape与内容都用列表的方法访问:
一定要注意 必须先用高斯滤波进行平滑处理去除噪声 再用二值化阈值处理,才能计算出正确的轮廓
import numpy as np
import cv2
img = cv2.imread("countours.JPG",cv2.IMREAD_GRAYSCALE)# 先用高斯滤波平滑处理
img = cv2.GaussianBlur(img, (5, 5), 0)
# 再用阈值处理转化为二值图像
_,img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)
countours , hierarchy = cv2.findContours(img,mode = cv2.RETR_EXTERNAL,method = cv2.CHAIN_APPROX_NONE)
print(len(countours))
for i in range(len(countours)):print(countours[i].shape)print(countours[i])
通过代码找出来十条轮廓,与我们手动标注的数量一致:
参数mode与返回值hierarchy
我将这张图片命名为mode.JPG,这是我的文件夹(我用的是 jupyter notebook 大家用pycharm的就把代码和图片放在同一个文件夹下就可以运行我的代码了):
不同的mode参数对应着不同的hierarchy,分为四种:
第一种:cv2.RETR_EXTERNAL(只检测外轮廓)
import numpy as np
import cv2
img = cv2.imread("mode.JPG",cv2.IMREAD_GRAYSCALE)# 先用高斯滤波平滑处理
img = cv2.GaussianBlur(img, (5, 5), 0)
# 再用阈值处理转化为二值图像
_,img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)
countours , hierarchy = cv2.findContours(img,mode = cv2.RETR_EXTERNAL,method = cv2.CHAIN_APPROX_NONE)
print(len(countours))
print(hierarchy)
输出值[1 -1 -1 -1]代表 第0个轮廓的后一个轮廓是第一个轮廓,他没有前一个轮廓 所以第二个元素是-1 他没有子轮廓 和父轮廓 所以第三第四个元素都是 - 1
输出值[-1 0 -1 -1]代表第1个轮廓 没有后面轮廓了 所以是-1 他的前一个轮廓 是0,他没有子轮廓和父轮廓 所以第三个第四个元素都是 -1
找到了两条轮廓,原因是cv2.RETR_EXTERNAL会导致只搜索外轮廓:
第二种:cv2.RETR_LIST
检测到的轮廓不考虑父子关系
在上面的代码中修改mode = cv2.RETR_LIST,运行结果如下:
这个结果前两行的第一个元素都是 1 2 说明他们有后一个轮廓 ,因为没有考虑父子关系,所以每一行的三四元素都是-1 第1 第2 轮廓都有前一个轮廓 分别是 0 和1 ,所以第二列 是 -1 0 1
第三种:cv2.RETR_CCOMP
检查所有轮廓并组织称一个两级层次结构,修改参数mode = cv2.RETR_CCOMP,继续运行得到如下结果:
可以看到第1 轮廓 和 第2 轮廓存在了 父子 关系 :
对于1,2轮廓来说他们是父子关系,所以不存在后一个轮廓所以是-1:
第四种:cv2.RETR_TREE
生成一个等级树,为了验证第四个和第三个的区别,我重新用画图板画了一张图起名为tree.JPG,大家可以复制到自己的文件夹下:
import numpy as np
import cv2
img = cv2.imread("tree.JPG",cv2.IMREAD_GRAYSCALE)
# 先用高斯滤波平滑处理
img = cv2.GaussianBlur(img, (5, 5), 0)
# 再用阈值处理转化为二值图像
_,img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)
countours_comp , hierarchy_comp = cv2.findContours(img,mode = cv2.RETR_CCOMP,method = cv2.CHAIN_APPROX_NONE)
countours_tree , hierarchy_tree = cv2.findContours(img,mode = cv2.RETR_TREE,method = cv2.CHAIN_APPROX_NONE)
print(hierarchy_comp)
print(hierarchy_tree)
详细分析一下,运行结果:
显而易见的是 cv2.RETR_CCOMP时,最多产生一个两级的父子结构:
但是cv2.RETR_TREE产生了一个多级的父子结构树:
cv2.drawContours()函数的使用
语法:
cou_image待绘制的轮廓图像 = cv2.drawCountours(image待处理图像,countours需要绘制的轮廓 list类型,countourIdx绘制的边缘索引,color绘制的颜色,thickness绘制轮廓的粗细,lineType画笔类型,hierarchy拓普信息,maxLevel层次的深度,offset偏移参数,使得轮廓偏移多少位置)
使用tree.JPG做案例来用代码验证一下效果:
import numpy as np
import cv2
img = cv2.imread("tree.JPG",cv2.IMREAD_GRAYSCALE)
# 先用高斯滤波平滑处理
img = cv2.GaussianBlur(img, (5, 5), 0)
# 再用阈值处理转化为二值图像
_,img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)
countours_tree , hierarchy_tree = cv2.findContours(img,mode = cv2.RETR_TREE,method = cv2.CHAIN_APPROX_NONE)n = len(countours_tree)
contourImg = []
cv2.imshow("orig",img)
for i in range(n):temp = np.zeros(img.shape,np.uint8)contourImg.append(temp)contourImg[i] = cv2.drawContours(contourImg[i],countours_tree,i,(255,255,255),5)cv2.imshow(f"contour[ {i}]",contourImg[i])
cv2.waitKey()
cv2.destroyAllWindows()
利用轮廓绘制功能,获取前景对象
这部分的案例使用pig.JPG图片,需要的可以直接复制,跟代码放在同一文件夹之下:
先讲解一下代码的思路,首先转化成灰度值和二值图像,然后获取轮廓,绘制整个轮廓,利用按位与运算与原图像进行按位与运算,提取前景对象。
import numpy as np
import cv2
bgr_img = cv2.imread("pig.JPG")
img = cv2.cvtColor(bgr_img,cv2.COLOR_BGR2GRAY)
# 先用高斯滤波平滑处理
img = cv2.GaussianBlur(img, (5, 5), 0)
# 再用阈值处理转化为二值图像
_,img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)
countours_tree , hierarchy_tree = cv2.findContours(img,mode = cv2.RETR_TREE,method = cv2.CHAIN_APPROX_NONE)
mask = np.zeros(bgr_img.shape,np.uint8)
mask = cv2.drawContours(mask,countours_tree,-1,(255,255,255),-1)
loc = cv2.bitwise_and(mask,bgr_img)
cv2.imshow("mask",mask)
cv2.imshow("loc",loc)
cv2.waitKey()
cv2.destroyAllWindows()
致谢
本文参考了一些博主的文章,博取了他们的长处,也结合了我的一些经验,对他们表达诚挚的感谢,使我对 图像轮廓查找与绘制 有更深入的了解,也推荐大家去阅读一下他们的文章。纸上学来终觉浅,明知此事要躬行:
python+opencv基础篇——实现提取轮廓
相关文章:

OpenCV 图像轮廓查找与绘制全攻略:从函数使用到实战应用详解
摘要:本文详细介绍了 OpenCV 中用于查找图像轮廓的 cv2.findContours() 函数以及绘制轮廓的 cv2.drawContours() 函数的使用方法。涵盖 cv2.findContours() 各参数(如 mode 不同取值对应不同轮廓检索模式)及返回值的详细解析,搭配…...

电机驱动MCU介绍
电机驱动MCU是一种专为电机控制设计的微控制器单元,它集成了先进的控制算法和高性能的功率输出能力。 电机驱动MCU采用高性能的处理器核心,具有快速的运算速度和丰富的外设接口。它内置了专业的电机控制算法,包括PID控制、FOC(Fi…...

人工智能学习框架详解及代码使用案例
人工智能学习框架详解及代码使用案例 人工智能(AI)学习框架是构建和训练AI模型的基础工具,它们提供了一组预定义的算法、函数和工具,使得开发者能够更快速、更高效地构建AI应用。本文将深入探讨人工智能学习框架的基本概念、分类、优缺点、选择要素以及实际应用,并通过代…...

修改Textview中第一个字的字体,避免某些机型人民币¥不显示
在 Android 中,系统提供了三种常用的字体类型,分别是: Serif(衬线字体): 这种字体有明显的衬线或笔画末端装饰,通常用于印刷品和书籍,给人一种正式和优雅的感觉。示例:Typeface.SERI…...

彻底理解quadtree四叉树、Octree八叉树 —— 点云的空间划分的标准做法
1.参考文章: (1)https://www.zhihu.com/question/25111128 这里面的第一个回答,有一幅图: 只要理解的四叉树的构建,对于八叉树的构建原理类比方法完全一样:对于二维平面内的随机分布的这些点&…...

Python时间序列优化之道滑动与累积窗口的应用技巧
大家好,在时间序列数据处理中,通常会进行滑动窗口计算(rolling)和累积窗口计算(expanding)等操作,以便分析时间序列的变化趋势或累积特征。Pandas提供的rolling和expanding函数提供了简单、高效的实现方式,特别适用于金融、气象、…...

Buffered 和 BuffWrite
Buffered和BuffWrite是Java IO包中的两个类,用于提高IO操作的效率。 Buffered是一个缓冲区类,可以将一个InputStream或者一个Reader包装起来,提供了一定的缓冲区大小,可以一次读取多个字节或字符,减少了读取的次数&am…...

【娱乐项目】基于cnchar库与JavaScript的汉字查询工具
Demo介绍 利用了 cnchar 库来进行汉字相关的信息查询,并展示了汉字的拼音、笔画数、笔画顺序、笔画动画等信息用户输入一个汉字后,点击查询按钮,页面会展示该汉字的拼音、笔画数、笔画顺序,并绘制相应的笔画动画和测试图案 cnchar…...

泷羽sec-蓝队基础之网络七层杀伤链 (下)学习笔记
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...

FPGA 开发工程师
目录 一、FPGA 开发工程师的薪资待遇 二、FPGA 开发工程师的工作内容 1. 负责嵌入式 FPGA 方案设计,包括仿真、软件编写和调试等工作。 2. 使用工具软件建立 FPGA 综合工程,编写综合策略和时序约束。 3. 进行 FPGA 设计的优化与程序维护,…...

【Leetcode 每日一题】3250. 单调数组对的数目 I
问题背景 给你一个长度为 n n n 的 正 整数数组 n u m s nums nums。 如果两个 非负 整数数组 ( a r r 1 , a r r 2 ) (arr_1, arr_2) (arr1,arr2) 满足以下条件,我们称它们是 单调 数组对: 两个数组的长度都是 n n n。 a r r 1 arr_1 arr1 是…...

较类中的方法和属性比较
在 Python 中,类中有以下几种常见的方法和属性,它们的作用和用法有所不同。以下是详细比较: --- ### **1. 实例方法** - **定义**:使用 def 定义,第一个参数是 self,表示实例对象本身。 - **作用**&#…...

nVisual可视化资源管理工具
nVisual主要功能 支持自定义层次化的场景结构 与物理世界结构一致,从全国到区域、从室外到室内、从机房到设备。 支持自定义多种空间场景 支持图片、CAD、GIS、3D等多种可视化场景搭建。 丰富的模型库 支持图标、机柜、设备、线缆等多种资源对象创建。 资源可…...

自动类型推导(auto 和 decltype)
一、auto关键字 基本概念 在 C 11 中引入了auto关键字用于自动类型推导。它可以让编译器根据变量的初始化表达式自动推断出变量的类型。这在处理复杂的类型,如迭代器、lambda 表达式的类型等情况时非常有用。 使用示例 例如,在迭代器的使用中…...

新型大语言模型的预训练与后训练范式,谷歌的Gemma 2语言模型
前言:大型语言模型(LLMs)的发展历程可以说是非常长,从早期的GPT模型一路走到了今天这些复杂的、公开权重的大型语言模型。最初,LLM的训练过程只关注预训练,但后来逐步扩展到了包括预训练和后训练在内的完整…...

基于投影寻踪博弈论-云模型的滑坡风险评价
目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于投影寻踪博弈论-云模型的滑坡风险评价 基于投影寻踪博弈论-云模型的滑坡风险评价是一个复杂而有趣的主题,涉及到博弈论、风险评估和模糊逻辑等领域的交叉应用。这个方法结合了博弈论中的投影寻踪技术…...

WRF-Chem模式安装、环境配置、原理、调试、运行方法;数据准备及相关参数设置方法
大气污染是工农业生产、生活、交通、城市化等方面人为活动的综合结果,同时气象因素是控制大气污染的关键自然因素。大气污染问题既是局部、当地的,也是区域的,甚至是全球的。本地的污染物排放除了对当地造成严重影响外,同时还会在…...

Spring中每次访问数据库都要创建SqlSession吗?
一、SqlSession是什么二、源码分析1)mybatis获取Mapper流程2)Spring创建Mapper接口的代理对象流程3)MapperFactoryBean#getObject调用时机4)SqlSessionTemplate创建流程5)SqlSessionInterceptor拦截逻辑6)开…...

力扣刷题TOP101:6.BM7 链表中环的入口结点
目录: 目的 思路 复杂度 记忆秘诀 python代码 目的 {1,2},{3,4,5}, 3 是环入口。 思路 这个任务是找到带环链表的环入口。可以看作是上一题龟兔赛跑(Floyd 判圈算法)的延续版:乌龟愤愤不平地举报兔子跑得太快,偷偷…...

浅谈telnet和ping
telnet 和 ping 是网络诊断工具,用于测试网络连接性和故障排查,但它们有不同的用途和功能。以下是它们的主要区别: 1. ping 功能描述 用途:ping 命令用于测试主机与目标地址(IP或域名)之间的连通性。工作…...

P4-3【应用数组进行程序设计 | 第三节】——知识要点:字符数组
知识要点:字符数组 视频: P4-3【应用数组进行程序设计 | 第三节】——知识要点:字符数组 目录 一、任务分析 二、必备知识与理论 三、任务实施 一、任务分析 本任务要求输入一行字符,统计其中的单词数,单词之间用…...

彻底理解微服务配置中心的作用
常见的配置中心有SpringCloudConfig、Apollo、Nacos等,理解它的作用,无非两点,一是配置中心能做什么,不使用配置中心会出现什么问题。 作用:配置中心是用来集中管理服务的配置,它是用来提高系统配置的维护…...

SpringBoot开发——详细讲解 Spring Boot 项目中的 POM 配置
文章目录 一、POM 文件简介二、单模块项目的 POM 配置1. 创建基本的 Spring Boot 单模块项目2. 重点解析三、多模块项目的 POM 配置1. 多模块项目结构2. 父模块 POM 文件3. 子模块 POM 文件4. 重点解析结语在 Spring Boot 项目中,POM(Project Object Model)文件起着关键作用…...

pyspark实现基于协同过滤的电影推荐系统
最近在学一门大数据的课,课程要求很开放,任意做一个大数据相关的项目即可,不知道为什么我就想到推荐算法,一直到着手要做之前还没有新的更好的来代替,那就这个吧。 推荐算法 推荐算法的发展由来已久,但和…...

视觉语言模型(VLM)学习笔记
目录 应用场景举例 VLM 的总体架构包括: 深度解析:图像编码器的实现 图像编码器:视觉 Transformer 注意力机制 视觉-语言投影器 综合实现 训练及注意事项 总结 应用场景举例 基于文本的图像生成或编辑:你输入 “生成一张…...

学习笔记:黑马程序员JavaWeb开发教程(2024.11.29)
10.5 案例-部门管理-新增 如何接收来自前端的数据: 接收到json数据之后,利用RequestBody注解,将前端响应回来的json格式的数据封装到实体类中 对代码中Controller层的优化 发现路径中都有/depts,可以将每个方法对应请求路径中的…...

文档加密怎么做才安全?
公司的文档包含很多机密文件,这些文件不仅关乎公司的核心竞争力,还涉及到客户隐私、商业策略等敏感信息。因此,文档的保管和传递一直是我们工作的重中之重。 为了确保机密文件的安全,公司需要制定了一系列严格的保密措施。从文件的…...

使用Setup Factory将C#的程序打包成安装包
一、软件下载 https://download.csdn.net/download/qq_65356682/90042701 可以直接下载 二、软件使用 打开 1、创建一个新的项目 2、设置如下信息,也可以不设置,最好填非空的、 产品名就是你安装成功后生成文件的名称 3、如下文件夹路径就是你C#中ex…...

解决 java -jar 报错:xxx.jar 中没有主清单属性
问题复现 在使用 java -jar xxx.jar 命令运行 Java 应用程序时,遇到了以下错误: xxx.jar 中没有主清单属性这个错误表示 JAR 文件缺少必要的启动信息,Java 虚拟机无法找到应用程序的入口点。本文将介绍该错误的原因以及如何通过修改 pom.xm…...

Java HashSet 介绍
怀旧网个人博客网站地址:怀旧网,博客详情:Java HashSet 介绍 哈希值介绍 创建一个实体类 public class Student {private String name;private int age;public Student(String name, int age) {this.name name;this.age age;} }使用测试…...