OpenCV的轮廓检测

1. 轮廓检测的基本概念

轮廓是图像中连续的、闭合的曲线段,代表物体的边界(如圆形的轮廓是一条闭合曲线)。OpenCV 的轮廓检测通过 cv2.findContours() 实现,可用于形状识别、物体计数、图像分割等场景。

2. 核心函数与参数

(1)cv2.findContours():检测轮廓

contours, hierarchy = cv2.findContours(image,      # 输入图像(必须为二值图,需提前灰度化+二值化)mode,       # 轮廓检索模式(如RETR_EXTERNAL、RETR_TREE)method      # 轮廓逼近方法(如CHAIN_APPROX_SIMPLE、CHAIN_APPROX_NONE)
)

返回值

contours:检测到的轮廓列表,每个轮廓是一个点的集合(ndarray 类型)。

hierarchy:轮廓的层次结构(如嵌套关系),若无需层次可忽略。

  • 参数说明mode(轮廓检索模式):
    • 模式含义
      RETR_EXTERNAL仅检测最外层轮廓(忽略内部嵌套的轮廓,适合简单物体计数)。
      RETR_LIST检测所有轮廓,但不建立层次关系(最快,适合无需嵌套分析的场景)。
      RETR_CCOMP检测所有轮廓,组织为两级结构(外层为连通域,内层为孔洞)。
      RETR_TREE检测所有轮廓,并建立完整的树状层次(适合嵌套轮廓,如 “矩形内的圆形”)。
    • method(轮廓逼近方法):

      方法含义
      CHAIN_APPROX_NONE存储轮廓的所有像素点(最详细,速度慢、占用内存大)。
      CHAIN_APPROX_SIMPLE压缩轮廓,仅保留关键顶点(如矩形仅存 4 个角点,速度快、内存小)。
      CHAIN_APPROX_TC89_L1使用 Teh-Chin 链逼近算法(适合曲线轮廓)。

(2)cv2.drawContours():绘制轮廓

cv2.drawContours(image,       # 要绘制轮廓的目标图像contours,    # 轮廓列表(来自findContours的输出)contourIdx,  # 要绘制的轮廓索引(-1表示绘制所有轮廓)color,       # 轮廓颜色(如(0,255,0)表示绿色)thickness=2, # 轮廓线宽度(-1表示“填充轮廓”)
)

3. 完整流程:从预处理到轮廓检测

轮廓检测对图像质量敏感,需先进行预处理(灰度化、二值化、降噪)。以下是完整代码示例:

import cv2
import numpy as np# 1. 读取并预处理图像
img = cv2.imread("shape.jpg")                # 读取彩色图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度化
blur = cv2.GaussianBlur(gray, (5,5), 0)       # 高斯降噪(可选,视情况而定)
_, binary = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY)  # 二值化(>127设为255,否则0)# 2. 检测轮廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE,       # 检测所有轮廓并建立树状层次cv2.CHAIN_APPROX_SIMPLE  # 压缩轮廓,保留关键顶点
)# 3. 绘制轮廓(绿色,线宽2)
cv2.drawContours(img, contours, -1, (0,255,0), 2)  # 4. 显示结果
cv2.imshow("Contours", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

4. 关键注意事项

预处理必须到位
轮廓检测要求输入为二值图像(仅有黑 / 白)。若原图是彩色,需先转灰度(cv2.COLOR_BGR2GRAY),再二值化(cv2.threshold);若有噪声,可先高斯模糊(cv2.GaussianBlur)。

版本兼容性:

OpenCV 2 返回 (contours, hierarchy)(2 个值);

OpenCV 3/4 返回 (img, contours, hierarchy)(3 个值)。

若代码需兼容多版本,可按以下方式处理:

ret = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if len(ret) == 3:img, contours, hierarchy = ret  # OpenCV 3/4
else:contours, hierarchy = ret       # OpenCV 2

轮廓筛选与分析

若需筛选特定轮廓(如面积最大的轮廓),可遍历 contours 并计算面积:

max_area = 0
max_contour = None
for cnt in contours:area = cv2.contourArea(cnt)if area > max_area:max_area = areamax_contour = cnt

5. 应用场景形状识别

通过轮廓的周长、面积、近似多边形(cv2.approxPolyDP)判断形状(如矩形、圆形)。

物体计数:统计图像中轮廓的数量(需配合RETR_EXTERNAL排除内部孔洞)。

图像分割:用轮廓包围区域,提取目标物体。

6.实例:

import cv2
phone =cv2.imread('phone.png')#波收颇图
phone_gray =cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
cv2.imshow('phone_gray',phone_gray)
cv2.waitKey(0)
ret, phone_binary= cv2.threshold(phone_gray, 120, 255,cv2.THRESH_BINARY)
cv2.imshow( 'phone_binary',phone_binary)
cv2.waitKey(0)
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)image_copy = phone.copy()
cv2.drawContours(image=image_copy, contours=contours, contourIdx=-1,color=(0,255,0),thickness=4)
cv2.imshow('Contours_show',image_copy)
cv2.waitKey(0)# cv2.contourArea(contour[, oriented]) -> retval  轮廓面积
# oriented: 定向区域标志,默认值为 False,返回面积的绝对值,True 时则根据轮廓方向返回带符号的数值area_0 = cv2.contourArea(contours[0])
print(area_0)
area_1 = cv2.contourArea(contours[1])
print(area_1)# arcLength(InputArray curve, bool closed)  轮廓周长
# curve: 输入的二维点集(轮廓顶点),可以是 vector 或 Mat 类型。
# closed: 用于指示曲线是否封闭。length = cv2.arcLength(contours[0], closed=True)
print(length)# 根据面积筛选显示轮廓
a_list = []
for i in contours:if cv2.contourArea(i) > 10000:a_list.append(i)image_copy = phone.copy()
image_copy = cv2.drawContours(image=image_copy, contours=a_list, contourIdx=-1, color=(0, 255, 0), thickness=3)
cv2.imshow('Contours_show_10000', image_copy)
cv2.waitKey(0)# '''轮廓定位方法 根据轮廓面积进行排序'''
sortcnt = sorted(contours, key=cv2.contourArea, reverse=True)[0]  # 选取最大面积的轮廓
image_contours = cv2.drawContours(phone.copy(), contours=[sortcnt], contourIdx=-1, color=(0, 0, 255), thickness=3) # 绘制轮廓
cv2.imshow('image_contours', image_contours)
cv2.waitKey(0)

这段代码是基于 OpenCV 的图像轮廓检测与分析示例,主要实现了从图像读取、预处理到轮廓提取、筛选和排序的完整流程。以下是代码解析:

1. 导入库与读取图像

import cv2
phone = cv2.imread('phone.png')  # 读取原始图像(假设为手机相关图像)

导入 OpenCV 库(cv2),用于图像处理。

使用cv2.imread()读取本地图像phone.png,返回的phone是 BGR 格式的彩色图像(OpenCV 默认读取格式)。

2. 图像预处理(灰度化与二值化)

# 灰度化:将彩色图像转为单通道灰度图
phone_gray = cv2.cvtColor(phone, cv2.COLOR_BGR2GRAY)
cv2.imshow('phone_gray', phone_gray)  # 显示灰度图
cv2.waitKey(0)  # 等待用户按键(0表示无限等待)# 二值化:将灰度图转为黑白二值图(轮廓检测的前提)
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
cv2.imshow('phone_binary', phone_binary)  # 显示二值图
cv2.waitKey(0)

灰度化:通过cv2.cvtColor()将 BGR 彩色图转为灰度图(单通道),减少计算量,为后续处理简化图像。

二值化:使用cv2.threshold()将灰度图转为黑白二值图:

阈值设为 120,即灰度值 > 120 的像素设为 255(白色),≤120 的设为 0(黑色)。cv2.THRESH_BINARY是二值化模式,返回ret(阈值)和二值化结果phone_binary

cv2.imshow()cv2.waitKey(0)用于显示图像并暂停,等待用户确认后继续。

3. 轮廓检测与绘制

# 检测轮廓(OpenCV 3/4版本返回3个值,用_忽略第一个)
_, contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)# 复制原始图像,在副本上绘制所有轮廓
image_copy = phone.copy()
cv2.drawContours(image=image_copy, contours=contours,  # 轮廓列表contourIdx=-1,      # -1表示绘制所有轮廓color=(0,255,0),    # 轮廓颜色(绿色,BGR格式)thickness=4         # 轮廓线宽
)
cv2.imshow('Contours_show', image_copy)  # 显示所有轮廓
cv2.waitKey(0)

轮廓检测cv2.findContours()从二值图中提取轮廓:

输入:二值图phone_binary(背景为黑,目标为白)。

参数cv2.RETR_TREE:检测所有轮廓,并保留完整的层次关系(如嵌套轮廓的父子关系)。

参数cv2.CHAIN_APPROX_NONE:存储轮廓的所有像素点(不压缩,最完整但内存占用大)。

返回:contours(轮廓列表,每个轮廓是像素坐标的数组)、hierarchy(轮廓层次信息)。

绘制轮廓cv2.drawContours()在图像副本上绘制轮廓,避免修改原图。

4. 轮廓特征计算(面积与周长)

# 计算轮廓面积(第一个和第二个轮廓)
area_0 = cv2.contourArea(contours[0])
print(area_0)  # 打印第一个轮廓的面积
area_1 = cv2.contourArea(contours[1])
print(area_1)  # 打印第二个轮廓的面积# 计算轮廓周长(第一个轮廓,闭合轮廓)
length = cv2.arcLength(contours[0], closed=True)
print(length)  # 打印第一个轮廓的周长

轮廓面积cv2.contourArea(contour)计算单个轮廓的面积(单位:像素 ²)。

轮廓周长cv2.arcLength(curve, closed)计算轮廓周长:closed=True表示轮廓是闭合的(如圆形、矩形)。

5. 按面积筛选轮廓

# 筛选面积>10000的轮廓(去除小面积噪声)
a_list = []
for i in contours:if cv2.contourArea(i) > 10000:a_list.append(i)# 绘制筛选后的轮廓
image_copy = phone.copy()
image_copy = cv2.drawContours(image=image_copy, contours=a_list,  # 仅包含大面积轮廓的列表contourIdx=-1, color=(0, 255, 0), thickness=3
)
cv2.imshow('Contours_show_10000', image_copy)  # 显示筛选结果
cv2.waitKey(0)

实际场景中,检测到的轮廓可能包含噪声(如小斑点),通过面积阈值(10000)筛选出有意义的大轮廓。

遍历所有轮廓,将面积大于 10000 的轮廓存入a_list,再绘制这些轮廓。

6. 按面积排序并提取最大轮廓

# 按面积降序排序轮廓,取最大面积的轮廓
sortcnt = sorted(contours, key=cv2.contourArea, reverse=True)[0]# 绘制最大面积的轮廓(红色)
image_contours = cv2.drawContours(phone.copy(), contours=[sortcnt],  # 注意:contours参数需传入列表,这里用[sortcnt]包装contourIdx=-1, color=(0, 0, 255),  # 红色(BGR格式)thickness=3
)
cv2.imshow('image_contours', image_contours)  # 显示最大轮廓
cv2.waitKey(0)

sorted(contours, key=cv2.contourArea, reverse=True):按轮廓面积降序排序,reverse=True表示从大到小。

[0]取排序后的第一个元素(面积最大的轮廓)。

绘制时,contours参数需传入列表,因此用[sortcnt]包装单个轮廓。

总结

这段代码完整演示了轮廓检测的典型流程:
读取图像 → 灰度化 → 二值化 → 检测轮廓 → 分析轮廓特征(面积、周长) → 筛选 / 排序轮廓 → 可视化结果
核心目的是从图像中提取目标的边界(轮廓),并通过面积等特征筛选出感兴趣的目标)。

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

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

相关文章

亚信安全亮相鸿蒙生态大会2025 携手鸿蒙生态绘就万物智联新蓝图

8 月30 日,以 “新场景・新体验” 为主题的鸿蒙生态大会 2025 在深圳福田会展中心隆重开幕。本次大会由全球智慧物联网联盟(GIIC)主办、鸿蒙生态服务(深圳)有限公司承办,旨在搭建全球鸿蒙生态伙伴的高层次交…

Linux内核进程管理子系统有什么第四十回 —— 进程主结构详解(36)

接前一篇文章:Linux内核进程管理子系统有什么第三十九回 —— 进程主结构详解(35) 本文内容参考: Linux内核进程管理专题报告_linux rseq-CSDN博客 《趣谈Linux操作系统 核心原理篇:第三部分 进程管理》—— 刘超 《…

面试问题:进程和线程,编译步骤,const,map和unordered_map,深入理解unordered_map

目录 进程和线程的区别 const修饰指针(左边内容,右边指向) 1. const 修饰指针指向的内容(指向常量) 2. const 修饰指针本身(常量指针) 3. const 同时修饰指针本身和指向的内容(指向常量的常量指针&…

利用棒棒糖图探索Office (US)的IMDB评分

利用棒棒糖图探索Office (US)的IMDB评分 import numpy as np import pandas as pd import matplotlib.colors as mc import matplotlib.image as image import matplotlib.pyplot as pltfrom matplotlib.cm import ScalarMappable from matplotlib.lines import Line2D from m…

Zephyr如何注册设备实例

设备树 → 编译期生成 → 运行时访问 流程图&#xff1a;Zephyr dev->config 工作流程设备树 (.dts) ───────────────────────────── anx745139 {compatible "analogix,anx7451";reg <0x39>;reset-gpios <&gpio1 5 …

Spring Boot 日志框架选择指南:Logback vs Log4j2

在 Spring Boot 应用中&#xff0c;您需要明确选择一个日志框架 - ​​不能同时使用两种日志实现​​。以下是关于 spring-boot-starter-log4j2和 spring-boot-starter-logging的全面比较和选择建议&#xff1a;核心区别特性spring-boot-starter-log4j2(Log4j2)spring-boot-sta…

Axure科技感可视化原型案例:赋能设计与研发的宝藏资源

在当今数字化浪潮中&#xff0c;数据可视化已成为企业洞察市场、优化运营、快速决策不可或缺的工具。Axure&#xff0c;作为原型设计领域的领航者&#xff0c;凭借其强大的功能和丰富的资源&#xff0c;为数据可视化大屏的设计注入了科技活力与创新元素。本文将深入探讨Axure科…

跨境电商账号风控核心:IP纯净度与浏览器指纹的防护策略

对跨境电商从业者而言&#xff0c;账号突然被封是常见却令人头痛的问题。即便严格遵守平台规则、使用代理IP&#xff0c;账号仍可能因风控策略而受限。这背后&#xff0c;IP纯净度与浏览器指纹识别是两大常被忽视却至关重要的技术因素。本文将从技术角度解析其原理&#xff0c;…

daily notes[7]

文章目录perl notereferencesperl note A hash in perl can be initialized with array,for example: my %numbers ("one", 1, "two", 2); print $fruit_color{"one"}; it is wonderful that the hash can be sliced to result in an array …

WPF迁移avalonia之图像处理(一)

从WPF迁移到avalonia中&#xff0c;对于图像处理部分&#xff0c;在WPF常用System.Windows.Drawing中图像处理元素&#xff0c;但是在开发avalonia应用时考虑跨平台特性&#xff0c;则必须有对应的跨平台替换方案。主要考虑Avalonia.Media.Imaging.Bitmap和SkiaSharp.SKBitmap …

242. 有效的字母异位词| 349. 两个数组的交集

242. 有效的字母异位词 nums [0]*26 : 这行代码创建了一个包含26个0的列表&#xff0c;这个列表通常用于计数或者作为某种映射的基础&#xff0c;比如统计字符串中每个字母出现的次数&#xff08;假设只考虑小写字母a-z&#xff09;。 ord() Python 中的一个内置函数&#x…

HTML第二课:块级元素

HTML第二课&#xff1a;块级元素块级元素块级元素 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang"zh-CN"> <head><meta http-equiv"Content-…

微论-突触的作用赋能思考(可能是下一代人工智能架构的启发式理论)

突触智能&#xff1a;微观结构与宏观智慧的桥梁摘要&#xff1a;传统人工智能模型&#xff0c;尤其是深度学习&#xff0c;将突触简单抽象为一个静态的权重参数&#xff0c;这极大地简化了生物计算的复杂性。本文受启发于生物突触的微观功能&#xff0c;提出了一种新的智能架构…

ARM - GPIO 标准库开发

一、STM32MP157AAA开发板套件介绍1.1 核心板 - 主板如图所示&#xff1a;主板各部分介绍1.2 IO 拓展板如图所示&#xff1a;IO拓展板各部分介绍开发板名称&#xff08;硬件平台&#xff09;&#xff1a;FS-MP1A主控制器&#xff1a;STM32MP157AAA3 Cortex-A7 * 2 Cortex-M4 -…

橙武低代码:不仅仅是云SaaS,更是云端开发+本地部署的新范式

版权归作者所有&#xff0c;转载请注明出处。 一、低代码的时代背景 在过去十年里&#xff0c;软件研发模式经历了巨大的演变。从传统的瀑布开发&#xff0c;到敏捷、DevOps&#xff0c;再到如今的低代码/无代码平台&#xff0c;研发效率和交付模式发生了根本性变化。低代码的…

神经语言学视角:脑科学与NLP深层分析技术的交叉融合

引言&#xff1a;从“统计拟合”到“类人理解”——NLP的下一个范式近年来&#xff0c;以Transformer架构为核心的大型语言模型&#xff08;LLM&#xff09;在自然语言处理&#xff08;NLP&#xff09;领域取得了前所未有的成功 。它们能够生成流畅的文本、回答复杂的问题&…

Coze源码分析-工作空间-项目查询-前端源码

前言 本文将深入分析Coze Studio项目中用户登录后进入工作空间查看和管理项目的前端实现&#xff0c;通过源码解读来理解工作空间项目开发功能的架构设计和技术实现。Coze Studio采用了现代化的React TypeScript技术栈&#xff0c;结合微前端架构和模块化设计&#xff0c;为用…

【系统架构师设计(9)】系统设计:结构化设计与面向对象设计

文章目录一、核心思想&#xff1a;模块化与对象化的设计哲学1、结构化设计的核心思想2、面向对象设计的核心思想3、两种设计方法的本质区别二、结构化设计知识点1、设计阶段2、设计原则3、 内聚类型&#xff08;从低到高&#xff09;耦合类型&#xff08;从低到高&#xff09;模…

还在从零开发AI应用?这个项目直接给你500个现成方案!!!

大家好&#xff0c;我是顾北&#xff0c;一名AI应用探索者&#xff0c;也是GitHub开源项目收集者。昨晚又在GitHub上瞎逛...咦&#xff0c;碰到了一个特别有意思的项目。说实话吧&#xff0c;作为一个天天折腾AI工具的人&#xff0c;见过的项目没有一千也有八百了&#xff0c;但…

react+taro的使用整理

前言&#xff1a; 本文主要整理下我们跨段工具taro的具体使用方法与相关资料。 taro官网&#xff1a; 安装及使用 | Taro 文档 安装&#xff1a; 全局脚手架安装&#xff1a; npm install -g tarojs/cli 使用脚手架安装我们的taro项目 taro init myApp 运行到不同小程序教…