当前位置: 首页 > ai >正文

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.xdnf.cn/news/18994.html

相关文章:

  • 神经语言学与脑科学启发的NLP深层分析:从统计拟合到机制理解的范式转变
  • 基于Spring Boot的短信平台平滑切换设计方案
  • 基于Matlab实现模糊综合评价程序
  • 使用 Java 替换和修改 PDF 文本的方法
  • c++标准模板库
  • 赋能你的应用:英超实时数据接入终极指南(API vs. WebSocket)
  • mongoDB学习(docker)
  • Bert学习笔记
  • HDFS 基本原理与操作流程
  • Python 【深度解析】线程与进程:操作系统中多任务的核心机制
  • 嵌入式第四十一天(数据库)
  • undefined和null
  • 【大模型14】Fine-tuning与大模型优化1
  • HunyuanVideo-Foley视频音效生成模型介绍与部署
  • 【完整源码+数据集+部署教程】胚胎发育阶段检测系统源码和数据集:改进yolo11-SCConv
  • Git 8 ,git 分支开发( 切换分支开发,并设置远程仓库默认分支 )
  • 机器视觉opencv教程(二):二值化、自适应二值化
  • 云计算学习笔记——逻辑卷管理、进程管理、用户提权RAID篇
  • 利用亮数据MCP服务器构建个性化学习情报官智能体
  • 第三章 Vue3 + Three.js 实战:用 OrbitControls 实现相机交互与 3D 立方体展示
  • 《应用密码学》——基础知识及协议结构模块(笔记)
  • 第2.1节:AI大模型之GPT系列(GPT-3、GPT-4、GPT-5)
  • 箭头函数和普通函数的区别
  • websocket的应用
  • 【物联网】什么是 DHT11(数字温湿度传感器)?
  • 为什么不能创建泛型数组?
  • 【计算机408计算机网络】第三章:自底向上五层模型之数据链路层
  • 轮廓周长,面积,外界圆,外界矩形近似轮廓和模板匹配和argparse模块实现代码参数的动态配置
  • STL 深度解析之vector【C++每日一学】
  • AI接管浏览器:Anthropic发布Claude for Chrome,是效率革命还是安全噩梦?