OpenCV 图像轮廓查找与绘制全攻略:从函数使用到实战应用详解

news2024/11/30 11:04:31

在这里插入图片描述

摘要:本文详细介绍了 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基础篇——实现提取轮廓

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

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

相关文章

AI之Data之Label Tool:Label Studio(多类型数据标注工具)的简介、安装和使用方法、案例应用之详细攻略

AI之Data之Label Tool:Label Studio(多类型数据标注工具)的简介、安装和使用方法、案例应用之详细攻略 目录 Label Studio的简介 1、特点 Label Studio的安装和使用方法: 1、Label Studio 提供多种安装方式 T1、使用Docker安装 T2、使用pip安装&am…

【Linux相关】服务器无网情况配置conda

【Linux相关】 服务器无网情况配置conda 文章目录 环境配置1. 本地下载miniconda,传到服务器2. 确认安装包是否传送成功3. 确保有安装权限4. 安装5. 写路径6. 看一下是否成功 环境配置 ssh的话,服务器连不上网,无法在线下载,需要本…

Redis使用场景-缓存-缓存穿透

前言 之前在针对实习面试的博文中讲到Redis在实际开发中的生产问题,其中缓存穿透、击穿、雪崩在面试中问的最频繁,本文加了图解,希望帮助你更直观的了解缓存穿透😀 (放出之前写的针对实习面试的关于Redis生产问题的博…

Docker desktop 改变存储位置

项目场景: 在windows下,使用docker desktop是使用docker最简单直接的方式。但是,这毕竟是一个可视化的界面,使用起来还是和linux环境下的版本有很大的区别。 例如,使用docker desktop,会默认将镜像以及容…

[CA] 尝试深入理解core.cpp -1

#我给你代码,你给我在源代码上额外加上中文注释!,如果是函数告诉我它读取了什么结构,传递了什么值,可能或者已经知道它将在哪些函数利用,是体现了pipeline 的哪一步# #include "core.h" #includ…

宠物空气净化器推荐2024超详细测评 希喂VS霍尼韦尔谁能胜出

最近有粉丝一直在评论区和后台探讨宠物空气净化器是不是智商税的问题,有人认为宠物空气净化器肯定不是智商税,有些人认为将其购回家就是个没用的东西,还占地方,双方各有自己的观点。 其实宠物空气净化器和普通的空气净化器是有很大…

NeuIPS 2024 | YOCO的高效解码器-解码器架构

该研究提出了一种新的大模型架构,名为YOCO(You Only Cache Once),其目的是解决长序列语言模型推理中的内存瓶颈。YOCO通过解码器-解码器结构的创新设计,显著减少推理时的显存占用并提升了长序列的处理效率。 现有大模…

《数据挖掘:概念、模型、方法与算法(第三版)》

嘿,数据挖掘的小伙伴们!今天我要给你们介绍一本超级实用的书——《数据挖掘:概念、模型、方法与算法》第三版。这本书是数据挖掘领域的经典之作,由该领域的知名专家编写,系统性地介绍了在高维数据空间中分析和提取大量…

RT-DETR融合Inner-IoU及相关改进思路

RT-DETR使用教程: RT-DETR使用教程 RT-DETR改进汇总贴:RT-DETR更新汇总贴 《Inner-IoU: More Effective Intersection over Union Loss with Auxiliary Bounding Box》 一、 模块介绍 论文链接:https://arxiv.org/abs/2311.02877 代码链接&a…

解决“磁盘已插上,但Windows系统无法识别“问题

电脑上有2块硬盘,一块是500GB的固态硬盘,另一块是1000GB的机械硬盘,按下开机键,发现500G的固态硬盘识别了,但1000GB的机械硬盘却无法识别。后面为了描述方便,将"500GB的固态硬盘"称为X盘&#xf…

[2024年3月10日]第15届蓝桥杯青少组stema选拔赛C++中高级(第二子卷、编程题(2))

方法一&#xff08;string&#xff09;&#xff1a; #include <iostream> #include <string> using namespace std;// 检查是否为回文数 bool isPalindrome(int n) {string str to_string(n);int left 0, right str.size() - 1;while (left < right) {if (s…

智慧防汛平台在城市生命线安全建设中的应用

随着城市化进程的加快&#xff0c;城市基础设施的复杂性和互联性不断增强&#xff0c;城市生命线的安全管理面临前所未有的挑战。智慧防汛平台作为城市生命线安全建设的重要组成部分&#xff0c;通过现代信息技术提升城市防汛应急管理的智能化水平&#xff0c;保障城市安全。 …

【R安装】VSCODE安装及R语言环境配置

目录 VSCODE下载及安装VSCODE上配置R语言环境参考 Visual Studio Code&#xff08;简称“VSCode” &#xff09;是Microsoft在2015年4月30日Build开发者大会上正式宣布一个运行于 Mac OS X、Windows和 Linux 之上的&#xff0c;针对于编写现代Web和云应用的跨平台源代码编辑器&…

Unity3D模型场景等测量长度和角度功能demo开发

最近项目用到多段连续测量物体长度和角度功能&#xff0c;自己研究了下。 1.其中向量角度计算&#xff1a; 需要传入三个坐标来进行计算。三个坐标确定两条向量线段的方向&#xff0c;从而来计算夹角。 public Vector3 SetAngle(Vector3 p1, Vector3 p2,Vector3 p3) { …

02-线性表

目录 2.1线性表基本概念 线性表特点 2.2线性表的顺序表示和实现 Ⅰ.顺序表的初始化 Ⅱ.顺序表的取值 Ⅲ.顺序表的查找 Ⅳ.顺序表的插入 Ⅴ.顺序表的删除 2.3线性表的链式表示和实现 单链表&#xff08;线性链表&#xff09; Ⅰ.单链表的初始化 Ⅱ.单链表的取值 Ⅲ.单链…

云计算基础-期末复习

第一章&#xff1a;云计算概论 一、云计算的定义与特征 1. 定义&#xff1a; 云计算是一种通过网络以按需、可扩展的方式获取计算资源和服务的模式。它将计算资源视为一种公用事业&#xff0c;用户可以根据需求动态获取和释放资源&#xff0c;而无需了解底层基础设施的细节。…

大模型专栏--Spring Ai Alibaba介绍和功能演示

Spring AI Alibaba 介绍和功能演示 背景 Spring AI Alibaba 开源项目基于 Spring AI 构建&#xff0c;是阿里云通义系列模型及服务在 Java AI 应用开发领域的最佳实践&#xff0c;提供高层次的 AI API 抽象与云原生基础设施集成方案&#xff0c;帮助开发者快速构建 AI 应用。…

计算机网络 实验八 应用层相关协议分析

一、实验目的 熟悉CMailServer邮件服务软件和Outlook Express客户端软件的基本配置与使用&#xff1b;分析SMTP及POP3协议报文格式和SMTP及POP3协议的工作过程。 二、实验原理 为了观察到邮件发送的全部过程&#xff0c;需要在本地计算机上配置邮件服务器和客户代理。在这里我…

计算机组成与系统结构复习笔记

1 概念 冯诺伊曼机: ①采用存储程序工作方式: 事先编制好的程序和原始数据送入主存后执行, 取指令 → \to →指令译码并计算下条指令地址 → \to →取操作数并执行 → \to →结果送回主存, 自动逐条执行指令直至程序结束; ②由运算器, 存储器, 控制器, 输入设备, 输出设备 5 部…

CIKM23|基于会话推荐的因果关系引导图学习

论文链接&#xff1a;https://www.researchgate.net/profile/Dianer-Yu/publication/373143453_Causality-guided_Graph_Learning_for_Session-based_Recommendation/links/652b3fe006bdd619c48fdd00/Causality-guided-Graph-Learning-for-Session-based-Recommendation.pdf 这…