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

embedded/2025/1/11 9:13:24/

目录

图像轮廓检测

轮廓的查找

轮廓的绘制

轮廓的特征

面积

周长

根据面积显示特定轮廓

轮廓的近似

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

外接圆

外接矩形


图像轮廓检测

轮廓的查找

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)):# 如果当前轮廓的面积大于 10000if 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.ppmy.cn/embedded/152964.html

相关文章

深度学习张量的秩、轴和形状

深度学习张量的秩、轴和形状 秩、轴和形状是在深度学习中我们最关心的张量属性。 秩轴形状 秩、轴和形状是在深度学习中开始使用张量时我们最关心的三个属性。这些概念相互建立,从秩开始,然后是轴,最后构建到形状,所以请注意这…

儿童玩具加拿大SOR/2011-17测试安全标准

加拿大儿童玩具都有什么标准? SOR/2011-17(玩具法规)SOR/2016-188(邻苯二甲酸盐法规)SOR/2016-193(表面涂层材料法规)SOR/2018-83(含铅消费品法规) 加拿大的技术法规通常…

深入理解 pytest_runtest_makereport:如何在 pytest 中自定义测试报告

pytest_runtest_makereport 是 pytest 系统中的一个钩子函数,它允许我们在测试执行时获取测试的报告信息。通过这个钩子,我们可以在测试运行时(无论是成功、失败还是跳过)对测试结果进一步处理,比如记录日志、添加自定…

HTML5 加载动画(Loading Animation)

加载动画(Loading Animation)详解 概述 加载动画是指在数据加载过程中,向用户展示的一种视觉效果,旨在提升用户体验,告知用户系统正在处理请求。它可以减少用户的等待焦虑感,提高界面的互动性。 常见的加…

集成Log4j2以及异步日志

文章目录 1.环境搭建1.在sunrays-common下创建一个单独的模块2.依赖关系1.继承父模块的版本和通用依赖 3.创建自动配置相关1.目录2.pom.xml3.Log4j2AutoConfiguration.java 自动配置类4.META-INF/spring.factories 指定自动配置类 2.集成Log4j2以及异步日志1.目录2.引入依赖3.l…

Nacos server 2.4.0 版本已知问题和 Bug 汇总

Nacos server 2.4.0 版本已知问题和 Bug 汇总 核心功能问题 集群模式下的数据一致性问题 在特定条件下,可能出现节点间数据同步延迟某些情况下会出现脑裂现象Issue #9876: 数据同步时可能出现死锁 内存泄漏问题 长时间运行后可能出现内存泄漏当配置变更频繁时&…

Dart语言的数据结构

Dart 语言中的数据结构 Dart 是一种现代化的编程语言,广泛用于构建高效、逻辑清晰的移动、Web 和服务器端应用程序。作为一种面向对象的语言,Dart 提供了一系列强大的数据结构,帮助开发者更高效地管理和操作数据。在本文中,我们将…

【SpringAOP】Spring AOP 底层逻辑:切点表达式与原理简明阐述

前言 🌟🌟本期讲解关于spring aop的切面表达式和自身实现原理介绍~~~ 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 🔥 你的点赞就是小编不断更新的最大动力 &am…