计算机视觉(九):图像轮廓

在计算机视觉(Computer Vision, CV)中,图像轮廓(Image Contour)是图像中物体边界的重要表现形式。它不仅能描述物体的形状特征,还能为目标识别、目标检测、图像分割、场景理解、三维重建等任务提供重要依据。与像素级的边缘检测相比,轮廓更强调封闭的边界、整体性和几何结构。

基本概念

定义

在图像处理中,轮廓通常指图像中前景目标与背景之间的边界线。它是一个闭合曲线,可以用像素点序列来表示。

  • 对于二值图像,轮廓是前景与背景的交界线。
  • 对于灰度图像,轮廓常通过边缘检测或阈值分割得到。

轮廓与边缘的区别

  • 边缘(Edge):灰度强度发生显著变化的位置,可能是不连续的。
  • 轮廓(Contour):物体的完整边界,更强调闭合性和结构性。

数学表示

若一个二值目标区域记为 R,则其轮廓 C 可表示为:

在这里插入图片描述

即边界点是区域中与背景相邻的像素点集合。

提取方法

轮廓提取的目标是将图像中物体的边界点序列化,形成闭合曲线。

1. 阈值分割 + 轮廓提取

  • 先通过全局阈值(如 Otsu 算法)或自适应阈值将图像转为二值图。
  • 然后使用轮廓追踪算法(如 OpenCV findContours)提取边界。
  • 优点:简单高效,适合对比度清晰的目标。
  • 缺点:对噪声和光照敏感。

2. 边缘检测 + 轮廓连接

  • 常用边缘算子:Sobel、Canny、Laplacian。
  • 检测到边缘后,通过连通域分析、霍夫变换或形态学操作获得闭合轮廓。
  • 适合复杂纹理和低对比度图像。

3. 形态学方法

  • 利用腐蚀(Erode)、膨胀(Dilate)、开运算、闭运算等形态学操作去噪或填洞。
  • 提取骨架(Skeletonization)后再追踪轮廓。
  • 常用于噪声较多的工业检测任务。

4. 主动轮廓模型(Snake)

  • 通过能量函数(包含图像梯度约束和曲线光滑性约束)使轮廓曲线自动收缩到物体边界。
  • 优点:轮廓连续性好,可处理复杂目标。
  • 缺点:依赖初始轮廓位置,计算复杂。

5. 基于深度学习的方法

  • 使用语义分割(如 U-Net、Mask R-CNN)获得物体区域,再提取轮廓。
  • 优点:鲁棒性强,适应复杂场景。
  • 缺点:需要大量训练数据。

轮廓的表示与特征

提取到轮廓后,需要对其进行表示和特征化,便于后续处理。

1. 边界链码(Chain Code)

  • 以起点为基准,用 4 邻域或 8 邻域的方向序列描述轮廓。
  • 优点:存储紧凑。
  • 缺点:不平移不变。

2. 多边形逼近

  • 用折线逼近复杂轮廓,例如 Douglas-Peucker 算法。
  • 常用于简化轮廓,提高计算效率。

3. 矩(Moments)

  • 几何矩:描述面积、质心。
  • Hu 不变矩:在旋转、缩放、平移下保持不变,适合形状识别。

4. 傅里叶描述子

  • 将轮廓点序列看作复数序列,做傅里叶变换。
  • 低频分量表示整体形状,高频分量表示细节。
  • 可用于形状匹配。

5. 曲率与角点

  • 曲率较大的点通常对应物体的特征角点。
  • 在目标识别和姿态估计中很重要。

OpenCV中的轮廓查找

核心函数

cv2.findContours()函数

查找轮廓。

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

参数解析:

  • image: 输入的二值图像。注意: 此函数会修改输入图像,通常建议传入一个副本。
  • mode: 轮廓检索模式,决定了如何组织轮廓的层级关系。
    • cv2.RETR_EXTERNAL: 只检索最外层的轮廓。
    • cv2.RETR_LIST: 检索所有轮廓,但不建立任何层级关系。
    • cv2.RETR_CCOMP: 检索所有轮廓,并将它们组织成两级层次结构(外部轮廓和孔洞)。
    • cv2.RETR_TREE: 检索所有轮廓,并建立完整的轮廓层次结构树。
  • method: 轮廓近似方法,决定如何存储轮廓点。
    • cv2.CHAIN_APPROX_NONE: 存储轮廓上所有的点。
    • cv2.CHAIN_APPROX_SIMPLE: 只存储轮廓的端点,例如,一个矩形只存储四个角点。

返回值:

  • contours: 找到的所有轮廓的列表。每个轮廓都是一个 NumPy 数组,包含了该轮廓的所有点。
  • hierarchy: 一个可选的层级信息数组。它告诉我们每个轮廓的父轮廓、子轮廓、上一个轮廓和下一个轮廓。

cv2.drawContours()函数

在图像上绘制找到的轮廓。

cv2.drawContours(image, contours, contourIdx, color, thickness)

参数解析:

  • image: 要在上面绘制轮廓的图像。
  • contours: 轮廓列表,通常是 cv2.findContours() 的返回值。
  • contourIdx: 轮廓的索引,指定绘制哪个轮廓。如果要绘制所有轮廓,传入 -1
  • color: 轮廓的颜色,以 (B, G, R) 元组形式表示。
  • thickness: 轮廓线的粗细。如果传入 -1cv2.FILLED,则轮廓内部会被填充。

示例

查找并绘制图像中的轮廓

import cv2
import numpy as np# 1. 读取图像并转换为灰度图
image = cv2.imread('shape.png') 
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 2. 图像阈值化
# 将图像转换为二值图像,大于127的像素变为255,否则变为0
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)# 3. 查找轮廓
# 检索所有轮廓,并使用简单的近似方法
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 4. 在原图上绘制轮廓
# 绘制所有轮廓,颜色为绿色,粗细为2
output_image = image.copy()
cv2.drawContours(output_image, contours, -1, (0, 255, 0), 2)# 5. 显示结果
cv2.imshow('Original Image', image)
cv2.imshow('Binary Image', thresh)
cv2.imshow('Contours', output_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

执行效果:

在这里插入图片描述

形状分析与测量

通过计算轮廓的面积、周长等属性来了解物体的基本几何信息。

import cv2
import numpy as np# 1. 创建一个二值图像
img = np.zeros((300, 300), dtype=np.uint8)
# 画一个圆,填充它
cv2.circle(img, (150, 150), 80, 255, -1)# 2. 查找轮廓
contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 获取第一个也是唯一的轮廓
cnt = contours[0]# 3. 计算轮廓属性
area = cv2.contourArea(cnt)
perimeter = cv2.arcLength(cnt, True) # True 表示轮廓是闭合的#print(f"轮廓面积: {area}")
#print(f"轮廓周长: {perimeter}")# 4. 绘制轮廓的边界框和最小外接圆
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x, y), (x + w, y + h), (100), 2)(center_x, center_y), radius = cv2.minEnclosingCircle(cnt)
center = (int(center_x), int(center_y))
radius = int(radius)
cv2.circle(img, center, radius, (100), 2)cv2.imshow("Shape Analysis", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

执行效果:

在这里插入图片描述

形状匹配

形状匹配用于比较两个轮廓的相似度。这在物体识别、缺陷检测等任务中非常有用。cv2.matchShapes 函数是实现这一功能的关键。

import cv2
import numpy as np# 1. 定义两个形状(轮廓)
# 第一个形状:矩形
rect = np.zeros((200, 200), dtype=np.uint8)
cv2.rectangle(rect, (50, 50), (150, 150), 255, -1)
contours1, _ = cv2.findContours(rect, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 第二个形状:旋转的矩形
rotated_rect = np.zeros((200, 200), dtype=np.uint8)
M = cv2.getRotationMatrix2D((100, 100), 45, 1) # 旋转45度
rotated_rect = cv2.warpAffine(rect, M, (200, 200))
contours2, _ = cv2.findContours(rotated_rect, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 2. 匹配两个形状
# cv2.CONTOURS_MATCH_I1 是一个常用的方法
match_score = cv2.matchShapes(contours1[0], contours2[0], cv2.CONTOURS_MATCH_I1, 0)print(f"result: {match_score}")
# 分数越低,两个形状越相似。理想情况下,完全相同的形状得分为0。
# 即使形状经过旋转、缩放或平移,matchShapes函数也能很好地工作。cv2.imshow("Original", rect)
cv2.imshow("Rotated", rotated_rect)
cv2.waitKey(0)
cv2.destroyAllWindows()

执行结果:

在这里插入图片描述

基于轮廓的图像分割与对象提取

找到轮廓后,可以用它来创建一个掩模(Mask),以精确地从原始图像中提取出物体。

import cv2
import numpy as np# 1. 读取彩色图像
image = cv2.imread('object.jpg')# 2. 转到 HSV 颜色空间
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)# 3. 定义颜色范围(这里以绿色圆为例)
lower_green = np.array([40, 50, 50])
upper_green = np.array([80, 255, 255])# 4. 生成掩模
mask = cv2.inRange(hsv, lower_green, upper_green)# 5. 提取物体
extracted_object = cv2.bitwise_and(image, image, mask=mask)# 6. 显示
cv2.imshow("Original", image)
cv2.imshow("Mask", mask)
cv2.imshow("Extracted Object", extracted_object)
cv2.waitKey(0)
cv2.destroyAllWindows()

执行效果:

在这里插入图片描述

轮廓近似与多边形拟合

轮廓可能包含成千上万个点,为了简化形状并减少计算量,可以使用多边形拟合。

import cv2
import numpy as np# 1. 创建一个形状(这里是一个圆,但可以用于任何复杂的形状)
img = np.zeros((300, 300), dtype=np.uint8)
cv2.circle(img, (150, 150), 100, 255, -1)# 2. 查找轮廓
contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 使用CHAIN_APPROX_NONE来获取所有点
original_contour = contours[0]# 3. 轮廓近似
# 参数 epsilon 决定了近似的精度,值越小,近似越接近原始轮廓
epsilon = 0.04 * cv2.arcLength(original_contour, True)
approx_contour = cv2.approxPolyDP(original_contour, epsilon, True)# 4. 绘制原始轮廓和近似后的轮廓
# 原始轮廓(红色)
original_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.drawContours(original_img, [original_contour], -1, (0, 0, 255), 2)# 近似轮廓(绿色)
approx_img = np.zeros_like(original_img)
cv2.drawContours(approx_img, [approx_contour], -1, (0, 255, 0), 2)
cv2.imshow("Original vs. Approximated", np.hstack([original_img, approx_img]))
cv2.waitKey(0)
cv2.destroyAllWindows()

执行效果:

在这里插入图片描述

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

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

相关文章

ThinkPHP 6框架常见错误:htmlentities()函数参数类型问题解决

在ThinkPHP 6框架中,htmlentities() 函数是一个常用的PHP函数,用于将字符转换为HTML实体。这个函数通常在输出内容到浏览器时使用,以防止跨站脚本(XSS)攻击。然而,在使用过程中可能会遇到参数类型问题。错误…

网络通信 IO 模型学习总结基础强化

网络通信概念网络通信因为要处理复杂的物理信号,错误处理等,所以采用了分层设计。为什么要采用分层设计?1. 每层可以独立开发,测试和替换;2. 发生问题也可以快速定位到具体层次;3. 协议标准化,不…

【ComfyUI】深度 ControlNet 深度信息引导生成

今天给大家演示一个结合 ControlNet 深度信息的 ComfyUI 建筑可视化工作流。整个流程通过引入建筑专用的权重模型和深度控制网络,使得生成的建筑图像不仅具备高质量和超写实的细节,还能精确遵循输入图片的结构特征。在这个案例中,模型加载、文…

Python数据可视化科技图表绘制系列教程(六)

目录 散点图1 散点图2 添加线性回归线的散点图 自定义点形状的散点图 不同样式的散点图 抖动散点图 边际图 边缘为直方图的边际图 边缘为箱线图的边际图 曼哈顿图 【声明】:未经版权人书面许可,任何单位或个人不得以任何形式复制、发行、出租、…

spring AI 的简单使用

1. 引入 Spring 官⽅推出的⾸个稳定版⼈⼯智能(AI)集成框架. 旨在帮助 Java/Spring 开发者更便捷地在企业级应⽤中集成 AI 能⼒ (如⼤语⾔模型、机器学习、向量数据库、图像⽣成等)。 它主要提供了以下功能: • ⽀持主要的AI模型提供商, ⽐如 Anthropic、OpenAI、M…

图像去雾:从暗通道先验到可学习融合——一份可跑的 PyTorch 教程

一、为什么“去雾”依然是好课题? 真实需求大:手机拍照、自动驾驶、遥感、监控都要在恶劣天气下成像。 数据集相对干净:与通用目标检测相比,去雾只有“有雾/无雾”一对图像,标注成本低。 传统与深度并存:…

Ubuntu 22.04.1上安装MySQL 8.0及设置root密码

安装MySQL 8.0 在 Ubuntu 22.04.1 系统需要遵循几个明确的步骤,并在安装过程中配置root密码,以下是详细的过程和相关的注意事项。步骤 1: 更新系统 使用终端更新系统软件包列表以确保所有的包是最新的。sudo apt update sudo apt upgrade步骤 2: 安装MyS…

用 content-visibility 即刻提速:那个被你忽略的 CSS 性能杠杆

我有一支技术全面、经验丰富的小型团队,专注高效交付中等规模外包项目,有需要外包项目的可以联系我🔍 引言长页面、信息密集、滚动迟滞?**content-visibility** 这项相对较新的 CSS 属性,允许浏览器跳过视口外元素的渲…

字符串(2)

4.字符串的常见函数代码#include <stdio.h> #include <string.h> int main() {char* str1 "abc";char str2[100] "abc";char str3[5] { q,w,e,r ,\0 };printf("---------------------strlen&#xff08;长度&#xff09;-------------…

案例分享|企微智能会话风控系统:为尚丰盈铝业筑牢沟通安全防线

企微智能会话安全风险分析系统是一款基于企业微信原生集成的高性能处理平台&#xff0c;其核心在于通过智能监测和AI风险识别技术&#xff0c;对员工与内外部客户的聊天内容进行多模态分析&#xff08;涵盖文本、图片、语音、视频、文件等多种形式&#xff09;&#xff0c;利用…

Paimon——官网阅读:配置

配置(Maintenance) 系统表 表特定系统表 表特定系统表包含关于每个表的元数据和信息&#xff0c;例如创建的快照以及正在使用的选项。用户可以通过批量查询来访问系统表。 目前&#xff0c;Flink、Spark、Trino 和 StarRocks 支持查询系统表。 在某些情况下&#xff0c;表…

阿里云对象存储OSS的使用

文章目录注册阿里OSS注册并登录阿里云账号开通对象存储OSS创建Bucket修改权限创建AccessKey全局存储到你的计算机(可以跳过)查看官方文档(可以跳过)SSM使用引入依赖在spring-mvc.xml中加入配置创建上传工具类AliOssUtil响应工具类ResultJSON编写controller编写前端代码使用Elme…

香港云主机常见使用问题汇总

本文主要为初次或正在接触香港云主机的用户介绍&#xff0c;对于香港云服务器的一些问题进行解答&#xff0c;帮助用户更好的了解香港云主机&#xff0c;熟悉香港云主机。1.香港云主机是否需要备案?香港云主机无需进行像内地服务器那样的 ICP 备案&#xff0c;可直接部署使用。…

JAVA同城打车小程序APP打车顺风车滴滴车跑腿源码微信小程序打车源码

JAVA同城打车系统源码&#xff1a;多端融合的智能出行生态解决方案一、市场需求与行业背景在共享经济蓬勃发展和数字化转型加速的背景下&#xff0c;中国同城出行市场正迎来快速增长期。2025年中国同城出行市场规模预计突破8000亿元&#xff0c;年复合增长率超过25%。基于Sprin…

AI入坑: Trae 通过http调用.net 开发的 mcp server

1. 为什么要写这个 为什么要写这个内容&#xff0c;前几天开始加入到ai大军&#xff0c;通过一周的学习&#xff0c;看了国外网站、看了b站教程、看了抖音教程&#xff0c;居然发现都是开发在本地的mcp server。本地mcp没问题&#xff0c;个人使用都ok&#xff0c;或者通过npx下…

记录Pycharm所使用虚拟环境与终端无法对应

在anaconda安装时&#xff0c;本文中的安装位置在D盘&#xff0c; D:\soware\anaconda 理论环境位置 D:\soware\anaconda\envs 经检查PATH配置均未发现错误&#xff0c;其次问题并不在于Pycharm的设置中解译器与终端的设置经过多次查找未发现可用解决方案 在anaconda建立虚拟环…

国产数据库之YashanDB:新花怒放

YashanDB&#xff08;崖山数据库&#xff09;是由深圳计算科学研究院自主研发的一款新型关系数据库管理系统。 YashanDB 在经典数据库理论基础上&#xff0c;融入了原创的有界计算、近似计算、并行可扩展和跨模融合计算理论&#xff0c;可以满足金融、政企、能源等关键行业对高…

Java基础 9.5

1.异常处理基本介绍异常处理就是当异常发生的时候 对异常处理的方式异常处理方式try-catch-finally程序员在代码中捕获发生的异常 自行处理throws将发生的异常抛出 交给调用者&#xff08;方法&#xff09;处理 最顶级的处理者是JVM示意图2.try-catch方式处理异常说明Java提供t…

B.50.10.06-NoSQL数据库与电商应用

NoSQL数据库核心原理与电商应用实战核心思想: NoSQL (Not Only SQL) 数据库是为了解决传统关系型数据库在超大规模数据、高并发和灵活数据模型方面的不足而设计的。它们通过牺牲部分一致性&#xff08;通常是最终一致性&#xff09;和事务的严格性&#xff0c;来换取极高的性能…

把开发环境丢云上,我的电脑风扇再也没转过!

Hello&#xff0c;兄弟们&#xff0c;我来啦作为一个天天搬砖的程序员&#xff0c;每天最让我心态爆炸的是啥&#xff1f;不是产品又改需求&#xff0c;也不是 Bug 藏得深&#xff0c;而是TMD——配&#xff01;环&#xff01;境&#xff01;新项目 git clone 下来&#xff0c;…