OpenCV计算机视觉 06 图像轮廓检测(轮廓的查找、绘制、特征、近似及轮廓的最小外接圆外接矩形)

news2025/1/8 14:42:49

目录

图像轮廓检测

轮廓的查找

轮廓的绘制

轮廓的特征

面积

周长

根据面积显示特定轮廓

轮廓的近似

给定轮廓的最小外接圆、外接矩形

外接圆

外接矩形


图像轮廓检测

轮廓的查找

API函数

image, contours, hierarchy = cv2.findContours(img, mode, method)

代入参数含义:

img:需要实现轮廓检测的原图

mode: 轮廓的检索模式,主要有四种方式:

cv2.RETR_EXTERNAL:只检测外轮廓,所有子轮廓被忽略

cv2.RETR_LIST:检测的轮廓不建立等级关系,所有轮廓属于同一等级

cv2.RETR_CCOMP:返回所有的轮廓,只建立两个等级的轮廓。一个对象的外轮廓为第1级组织结构。

而对象内部中空洞的轮廓为第2级组织结构,空洞中的任何对象的轮廓又是第 1 级组织结构。

-> cv2.RETR_TREE:返回所有的轮廓,建立一个完整的组织结构的轮廓。

method:轮廓的近似方法,主要有以下两种:

-> cv2.CHAIN_APPROX_NONE:存储所有的轮廓点。

cv2.CHAIN_APPROX_SIMPLE:压缩模式,只保留该方向的终点坐标,

例如一个矩形轮廓只需4个点来保存轮廓信息。

返回值

image:返回处理的原图

contours:包含图像中所有轮廓的list对象。

其中每一个独立的轮廓信息以边界点坐标(x,y)的形式储存在numpy数组中。

hierarchy:轮廓的层次结构。一个包含4个值的数组:[Next, Previous, First Child, Parent]

Next:与当前轮廓处于同一层级的下一条轮廓

Previous:与当前轮廓处于同一层级的上一条轮廓

First Child:当前轮廓的第一条子轮廓

Parent:当前轮廓的父轮廓

注意:做轮廓检测前需要将图片读取为二值数据,即像素值只为0和255。

获取给定图像phone.png中物体的轮廓信息,包括轮廓的数量和层次结构,以便进行后续的图像处理。

import cv2
​
# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 打印轮廓的层次结构
print(hierarchy)
# 打印轮廓的数量
print(len(contours))

输出信息解读

输出的 hierarchy 是一个包含了轮廓之间关系信息的数组。其中每个子数组 [6 -1 1 -1] 等代表了一个轮廓的相关信息:

  • 第一个数字(如 6、2、3 等)表示下一个同级轮廓的索引。

  • 第二个数字(如 -1)表示前一个同级轮廓的索引。

  • 第三个数字(如 1、-1 等)表示第一个子轮廓的索引。

  • 第四个数字(如 -1)表示父轮廓的索引。

输出的 9 表示检测到的轮廓数量。

轮廓的绘制

API函数

cv2.drawContours(image, contours, contourIdx, color, thickness=None,
                 lineType=None, hierarchy=None, maxLevel=None, offset=None)

参数含义

image:要在其上绘制轮廓的输入图像。

contours:轮廓列表,通常由cv2.findContours()函数返回。

contourIdx:要绘制的轮廓的索引。如果为负数,则绘制所有轮廓。 -1 color:轮廓的颜色,以BGR格式表示。例如,(0, 255, 0)表示绿色。

thickness:轮廓线的粗细。默认值为1。

lineType:轮廓线的类型。默认值为cv2.LINE_8。

hierarchy:轮廓层次结构。通常由cv2.findContours()函数返回。

maxLevel:绘制的最大轮廓层级。默认值为None,表示绘制所有层级。 offset:轮廓点的偏移量。默认值为None。

绘制出刚刚的phone.png图像中的轮廓

# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 复制原始图像
image_copy = phone.copy()
# 在复制的图像上绘制轮廓
image_copy = cv2.drawContours(image=image_copy, contours=contours, contourIdx=-1, color=(0, 255, 0), thickness=3)
# 显示绘制了轮廓的图像,窗口标题为'Contours_show'
cv2.imshow('Contours_show', image_copy)
# 等待用户按键,参数 0 表示无限等待
cv2.waitKey(0)  
轮廓的特征
面积

API函数

cv2.contourArea(contour[, oriented])

参数含义

contour:顶点构成的二维向量组(如轮廓列表contours中的一个轮廓)

oriented:定向区域标志,默认值为 False,返回面积的绝对值,

                                        Ture 时则根据轮廓方向返回带符号的数值

周长

API函数

arcLength(InputArray curve, bool closed)

参数含义

curve:输入的二维点集(轮廓顶点),可以是 vector 或 Mat 类型。

closed:用于指示曲线是否封闭。

问题:1. 求上述例子中 contours 列表中第一个和第二个轮廓的面积,并打印出这两个面积的值。

2. 计算 contours 列表中第一个封闭的轮廓的周长并打印

import cv2
# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 计算 contours 列表中第一个轮廓的面积,并将结果存储在 area_0 变量中
area_0 = cv2.contourArea(contours[0])  
# 计算 contours 列表中第二个轮廓的面积,并将结果存储在 area_1 变量中
area_1 = cv2.contourArea(contours[1])  
# 打印第一个和第二个轮廓的面积
print(area_0,area_1) 
# 计算 contours 列表中第一个轮廓的周长
length = cv2.arcLength(contours[0], closed=True)
# 打印第一个轮廓的周长
print(length)
根据面积显示特定轮廓

绘制出上述案例中面积大于10000的轮廓

import cv2
# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 创建一个空列表用于存储面积大于 10000 的轮廓
a_list = []
# 遍历 contours 中的每个轮廓
for i in range(len(contours)):
    # 如果当前轮廓的面积大于 10000
    if cv2.contourArea(contours[i]) > 10000:
        # 将该轮廓添加到 a_list 列表中
        a_list.append(contours[i])
# 复制原始图像
image_copy = phone.copy()
# 在复制的图像上绘制面积大于 10000 的轮廓
image_copy = cv2.drawContours(image=image_copy, contours=a_list, contourIdx=-1, color=(0, 255, 0), thickness=3 )
# 显示绘制了特定轮廓的图像,窗口标题为'Contours_show_10000'
cv2.imshow('Contours_show_10000', image_copy)
# 等待用户按键
cv2.waitKey(0)
轮廓的近似

API函数

approx = cv2.approxPolyDP(curve, epsilon, closed)

参数含义:

curve:输入轮廓。

epsilon:近似精度,即两个轮廓之间最大的欧式距离。该参数越小,得到的近似结果越接近实际轮廓;

反之,得到的近似结果会更加粗略。

closed:布尔类型的参数,表示是否封闭轮廓。

如果是 True,表示输入轮廓是封闭的,近似结果也会是封闭的;

否则表示输入轮廓不是封闭的,近似结果也不会是封闭的。

返回值:

approx:近似结果,是一个ndarray数组,为1个近似后的轮廓,包含了被近似出来的轮廓上的点的坐标

import cv2
​
# 读取图像'phone.png'
phone = cv2.imread('phone.png')  
# 将图像转换为灰度图
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY) 
# 对灰度图进行二值化处理
ret,phone_thresh = cv2.threshold(phone_gray,120,255,cv2.THRESH_BINARY) 
# 获取二值化图像的轮廓
_,contours, hierarchy = cv2.findContours(phone_thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)  
# 设置近似精度
epsilon = 0.01 * cv2.arcLength(contours[0],True)  
# 对第一个轮廓进行近似
approx = cv2.approxPolyDP(contours[0], epsilon, True)  
# 复制原始图像
phone_new = phone.copy()  
# 在复制的图像上绘制近似后的轮廓
image_contours = cv2.drawContours(phone_new,[approx],contourIdx=-1,color=(0,255,0),thickness=3) 
# 显示原始图像
cv2.imshow('phone',phone)  
cv2.waitKey(0)  
# 显示绘制了近似轮廓的图像
cv2.imshow('image_contours',image_contours)  
cv2.waitKey(0)  
给定轮廓的最小外接圆、外接矩形
外接圆

计算API函数

(x,y),r = cv2.minEnclosingCircle(cnt) 

输入参数含义:

cnt 指定的轮廓

返回值:

(x,y) 是外接圆的圆心坐标

r 是外接圆的半径。

外接矩形

计算API函数

x,y,w,h = cv2.boundingRect(cnt) 

输入参数含义:

cnt 指定的轮廓

返回值:

(x,y) 外接矩形的左上角坐标

w 矩形的宽度

h 矩形的高度

绘制出上述案例中第七个轮廓的最小外接圆与外接矩形

import cv2
​
# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 获取第 7 个轮廓
cnt = contours[6]  
# 计算轮廓的外接圆
(x,y),r = cv2.minEnclosingCircle(cnt)  
# 绘制外接圆
phone_circle = cv2.circle(phone.copy(),(int(x),int(y)),int(r),(0,255,0),2)  
# 显示绘制了外接圆的图像
cv2.imshow('phone_circle',phone_circle)
cv2.waitKey(0)
​
# 计算轮廓的最小外接矩形
x,y,w,h = cv2.boundingRect(cnt)  
# 绘制矩形
phone_rectangle = cv2.rectangle(phone.copy(),(x,y),(x+w,y+h),(0,255,0),2)  
# 显示绘制了矩形的图像
cv2.imshow('phone_rectangle',phone_rectangle)
cv2.waitKey(0)

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

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

相关文章

ROS2 跨机话题通信问题(同一个校园网账号)

文章目录 写在前面的话校园网模式(失败)手机热点模式(成功) 我的实验细节实验验证1、ssh 用户名IP地址 终端控制2、互相 ping 通 IP3、ros2 run turtlesim turtlesim_node/turtle_teleop_key4、ros2 multicast send/receive5、从机…

web3与AI结合-Sahara AI 项目介绍

背景介绍 Sahara AI 于 2023 年创立,是一个 "区块链AI" 领域的项目。其项目愿景是,利用区块链和隐私技术将现有的 AI 商业模式去中心化,打造公平、透明、低门槛的 “协作 AI 经济” 体系,旨在重构新的利益分配机制以及…

【C++】你了解异常的用法吗?

文章目录 Ⅰ. C语言传统的处理错误的方式Ⅱ. C异常概念Ⅲ. 异常的使用1、异常的抛出和匹配原则2、在函数调用链中异常栈展开匹配原则3、异常的重新抛出4、异常安全5、异常规范 Ⅳ. 自定义异常体系Ⅴ. C标准库的异常体系Ⅵ. 异常的优缺点1、异常的优点2、异常的缺点3、总结 Ⅰ. …

Matlab仿真径向受压圆盘光弹图像

Matlab仿真径向受压圆盘光弹图像-十步相移法 主要参数 % 定义圆盘参数 R 15; % 圆盘半径,单位:mm h 5; % 圆盘厚度,单位:mm P 300; % 径向受压载荷大小,单位&#xff…

游戏引擎学习第75天

仓库:https://gitee.com/mrxiao_com/2d_game_2 Blackboard: 处理楼梯通行 为了实现楼梯的平滑过渡和角色的移动控制,需要对楼梯区域的碰撞与玩家的运动方式进行优化。具体的处理方式和遇到的问题如下: 楼梯区域的过渡: 在三维空间中&#x…

算法的学习笔记—不用常规控制语句求 1 到 n 的和

😀前言 在算法编程中,有时我们会遇到一些特殊的限制条件,这些限制会迫使我们跳出常规思维。本文讨论的问题就是一个典型案例:在不能使用基本控制语句的情况下,如何求解 1 到 n 的和。这个问题不仅考验编程技巧&#xf…

网络协议安全的攻击手法

1.使用SYN Flood泛洪攻击: SYN Flood(半开放攻击)是最经典的ddos攻击之一,他利用了TCP协议的三次握手机制,攻击者通常利用工具或控制僵尸主机向服务器发送海量的变源端口的TCP SYN报文,服务器响应了这些报文后就会生成大量的半连…

141.《mac m1安装mongodb详细教程》

文章目录 下载从官网下载安装包 下载后双击解压出文件夹安装文件名修改为 mongodb配置data存放位置和日志log的存放位置启动方式一方式二方式二:输入mongo报错以及解决办法 本人电脑 m2 pro,属于 arm 架构 下载 官网地址: mongodb官网 怎么查看自己电脑应该下载哪个版本,输入…

C++ operator = 返回void 会发生什么?

1.operator 正常情况 #include <iostream> using namespace std;class Box { public:Box(double L) : length(L) {}Box(const Box& b){}Box& operator (const Box&){return *this;}public:double length; // 长度 };int main() {Box box1(1.0);Box box2(…

Redis中字符串和列表的区别

在 Redis 中&#xff0c;字符串&#xff08;String&#xff09;和列表&#xff08;List&#xff09;是两种截然不同的数据类型&#xff0c;它们各自有着独特的特点和适用场景。 数据结构 • 字符串&#xff08;String&#xff09;&#xff1a; • 在 Redis 中&#xff0c;字符串…

Elasticsearch JavaRestClient版

文章目录 初始化RestHighLeveClient&#xff08;必要条件&#xff09;索引库操作1.创建索引库&#xff08;4步&#xff09;2.删除索引库&#xff08;3步&#xff09;3.判断索引库是否存在&#xff08;3步&#xff09;4.总结&#xff1a;四步走 文档操作1.创建文档&#xff08;4…

使用Dinky快速提交Flink operator任务

官网地址&#xff1a;K8s集成 | Dinky 1.目前使用版本 Dinky1.2.0、Flink1.18.1、Flink operator0.10.0 2.制作镜像 2.1创建DockerFile ARG FLINK_VERSION1.18.1 FROM flink:${FLINK_VERSION}-scala_2.12 RUN mkdir -p /opt/flink/usrlib COPY commons-cli-1.3.1.jar …

探索数字化展馆:开启科技与文化的奇幻之旅

在科技飞速发展的当下&#xff0c;数字展馆作为一种新兴的展示形式&#xff0c;正逐渐走进大众的视野。数字展馆不仅仅是传统展馆的简单“数字化升级”&#xff0c;更是融合了多媒体、数字化技术以及人机交互等前沿科技的创新产物。 数字展馆借助VR、AR、全息投影等高科技手段&…

免费GEMINI模型使用及API调用

一、概述 谷歌最新发布的Gemini 2.0 FLASH模型为AI应用带来了新的可能性。该模型分为两个版本&#xff1a;gemini-2.0-flash-exp 和 gemini-2.0-flash-thinking-exp-1219。这两个模型目前限时免费使用&#xff0c;用户可以通过智匠MindCraft客户端或小程序直接体验&#xff0c;…

调整Python+Pytest+Allure+Yaml+Pymysql框架中需要执行的用例顺序

当pytest框架中有时时候会因为用例的前后关联关系需要调整用例执行顺序时则可以跟进具体的要求调整pytest.ini配置文件中执行用例文件夹的前后顺序 当如果是需要调整某个文件夹中用例的执行顺序时&#xff0c;则跟进具体的文件调整对应testcases中test_*.py文件中的执行顺序

容器技术思想 Docker K8S

容器技术介绍 以Docker为代表的容器技术解决了程序部署运行方面的问题。在容器技术出现前&#xff0c;程序直接部署在物理服务器上&#xff0c;依赖管理复杂&#xff0c;包括各类运行依赖&#xff0c;且易变&#xff0c;多程序混合部署时还可能产生依赖冲突&#xff0c;给程序…

系统思考—变革之舞

彼得圣吉在《变革之舞》中提到&#xff1a;变革的关键是持续学习。在这个变化万千的世界里&#xff0c;组织不能停留在过去的经验上&#xff0c;我们如何系统性的抛弃过去成功的经验&#xff0c;不断学习新技能&#xff0c;适应复杂的环境。每个人不仅要学会解决眼前的问题&…

OpenCV的人脸检测模型FaceDetectorYN

OpenCV的人脸检测模型FaceDetectorYN 1. 官网地址2. 如何使用2.1.到opencv_zoo下载模型文件和代码2.2. 下载文件展示2.3. 修改了demo支持读取视频文件&#xff0c;默认是图片和摄像头## 2.4 效果展示 1. 官网地址 https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetector…

25/1/6 算法笔记<强化学习> 初玩V-REP

我们安装V-REP之后&#xff0c;使用的是下面Git克隆的项目。 git clone https://github.com/deep-reinforcement-learning_book/Chapter16-Robot-Learning-in-Simulation.git 项目中直接组装好了一个机械臂。 我们先来分析下它的对象树 DefaultCamera:摄像机&#xff0c;用于…

Linux驱动开发:深入理解I2C时序(二)

在Linux驱动开发中,I2C时序的理解和正确处理是保证I2C设备正常工作和通信的关键。I2C协议的时序特性决定了数据的有效传输和设备间的协作。因此,掌握I2C的时序细节,以及如何在Linux内核中进行时序处理,能够让开发者更好地处理设备通信问题。 本文将继续深入探讨I2C通信协议…