讲师中心 微信公众号
AI工具推荐 视频效率加速

OpenCV中动态合并多个轮廓的实用指南

小辰同学_8268

小辰同学_8268

发布时间:2025-12-08 12:30:09

|

540人浏览过

|

来源于php中文网

原创

opencv中动态合并多个轮廓的实用指南

本文旨在介绍如何在OpenCV中高效地合并多个轮廓。针对`cv.findContours()`返回的可变数量轮廓,传统循环内直接使用`np.vstack`可能导致数据丢失。教程将详细阐述正确的合并策略,即先将所有待合并轮廓收集到一个列表中,然后利用NumPy的`vstack`函数一次性完成合并操作,从而确保所有轮廓数据被完整整合。

在图像处理任务中,我们经常需要使用OpenCV的cv.findContours()函数来检测图像中的轮廓。该函数返回一个轮廓列表,每个轮廓通常是一个NumPy数组,表示构成该轮廓的所有点。在某些应用场景下,我们可能需要将多个检测到的轮廓合并成一个单一的轮廓数组,例如,当多个轮廓属于同一个逻辑对象,或者需要对一组特定轮廓进行统一处理时。

理解OpenCV中的轮廓数据结构

cv.findContours()函数返回的轮廓通常是一个Python列表,列表中的每个元素都是一个NumPy数组。这些NumPy数组的形状通常是 (N, 1, 2),其中 N 是轮廓中的点数,1 是一个额外的维度(有时可以省略),2 表示每个点的 (x, y) 坐标。

例如,以下代码演示了如何获取并查看轮廓的基本信息:

import cv2 as cv
import numpy as np

# 假设 img 是一张二值图像
# 为了演示,我们创建一个简单的图像
img = np.zeros((100, 100), dtype=np.uint8)
cv.rectangle(img, (10, 10), (30, 30), 255, -1)
cv.circle(img, (70, 70), 20, 255, -1)
cv.rectangle(img, (15, 15), (25, 25), 0, -1) # 制造一个内部轮廓

# 查找轮廓
data_contours, _ = cv.findContours(img, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)

# 对轮廓按长度进行排序(从大到小)
data_cnt = sorted(data_contours, key=len, reverse=True)

# 打印轮廓数量和每个轮廓的长度
data_cnt_len = [len(cnt) for cnt in data_cnt]

print(f"检测到的轮廓总数: {len(data_contours)}")
print(f"排序后轮廓的长度: {data_cnt_len}")
# 示例输出可能为:
# 检测到的轮廓总数: 3
# 排序后轮廓的长度: [100, 80, 4] (具体数值取决于图像和轮廓查找模式)

轮廓合并的常见误区与正确策略

当需要合并多个轮廓时,一个常见的错误是在循环中直接使用np.vstack()。例如,如果目标是合并前两个最大的轮廓:

# 错误的合并尝试
# contour_number = 2  # 假设要合并前两个轮廓
#
# merged_contours_incorrect = None
# for i in range(contour_number):
#     # 每次循环都会创建一个新的 NumPy 数组,并覆盖前一个结果
#     # 这导致最终只保留了循环中最后一个轮廓的数据
#     merged_contours_incorrect = np.vstack(data_cnt[i])
#
# if merged_contours_incorrect is not None:
#     print(f"错误合并后的形状: {merged_contours_incorrect.shape}")
#     # 示例输出可能为: (407, 2) 或 (80, 2) - 只保留了最后一个轮廓的形状

上述代码的问题在于,np.vstack()在每次循环中都会将当前的data_cnt[i]转换成一个NumPy数组(如果它本身不是),并将其赋值给merged_contours_incorrect。这意味着每次迭代都会覆盖前一次的结果,最终merged_contours_incorrect只包含了循环中最后一个轮廓的数据。

直播间话术巡检-windows
直播间话术巡检-windows

直播话术巡检系统(Windows版) — 实时语音转写、关键词检测、场景自动切换、告警推送、大屏可视化。支持 Windows VB-Cable 虚拟声卡音频采集,阿里云 ASR 实时识别。一键启动脚本,自动安装环境。

下载

正确的合并策略是先将所有需要合并的轮廓收集到一个Python列表中,然后再对这个列表使用np.vstack()。np.vstack()函数能够接受一个NumPy数组的序列(如列表或元组),并将它们按垂直方向堆叠起来。

实施正确的轮廓合并

以下是合并多个轮廓的正确方法:

  1. 初始化一个空列表:用于存储所有待合并的轮廓。
  2. 遍历并追加轮廓:在循环中,将每个需要合并的轮廓追加到这个列表中。
  3. 一次性堆叠:循环结束后,使用np.vstack()函数对整个列表进行操作,完成所有轮廓的合并。
# 正确的轮廓合并方法
merged_contours_list = []  # 创建一个空列表来存储轮廓
contour_number_to_merge = 2 # 假设我们要合并前两个最大的轮廓

for i in range(contour_number_to_merge):
    merged_contours_list.append(data_cnt[i])

# 使用 np.vstack 将列表中的所有轮廓一次性堆叠起来
if merged_contours_list: # 确保列表不为空
    final_merged_contour = np.vstack(merged_contours_list)
    print(f"正确合并后的形状: {final_merged_contour.shape}")
    # 示例输出可能为: (180, 1, 2) 或 (180, 2) - 两个轮廓点数的总和
else:
    print("没有轮廓可供合并。")

通过这种方法,final_merged_contour将包含所有被追加到merged_contours_list中的轮廓点数据。其形状的第一个维度将是所有合并轮廓点数的总和。

完整示例

为了提供一个更完整的上下文,我们结合图像创建、轮廓查找、排序和合并的整个流程:

import cv2 as cv
import numpy as np

def merge_selected_contours(image_path, num_to_merge=2):
    """
    加载图像,查找轮廓,排序,并合并指定数量的最大轮廓。

    Args:
        image_path (str): 图像文件路径。
        num_to_merge (int): 要合并的最大轮廓数量。

    Returns:
        np.ndarray: 合并后的轮廓数组,如果无轮廓则返回 None。
    """
    img = cv.imread(image_path, cv.IMREAD_GRAYSCALE)
    if img is None:
        print(f"错误: 无法加载图像 '{image_path}'")
        return None

    # 对图像进行二值化处理,以便 cv.findContours 工作
    _, binary_img = cv.threshold(img, 127, 255, cv.THRESH_BINARY)

    # 查找轮廓
    contours_found, _ = cv.findContours(binary_img, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)

    if not contours_found:
        print("未检测到任何轮廓。")
        return None

    # 按轮廓点数从大到小排序
    sorted_contours = sorted(contours_found, key=len, reverse=True)

    print(f"检测到的轮廓总数: {len(sorted_contours)}")
    print(f"排序后轮廓的长度: {[len(c) for c in sorted_contours]}")

    # 准备合并
    contours_to_merge = []
    # 确保不会尝试合并超过实际存在的轮廓数量
    actual_num_to_merge = min(num_to_merge, len(sorted_contours))

    print(f"将合并前 {actual_num_to_merge} 个轮廓。")

    for i in range(actual_num_to_merge):
        contours_to_merge.append(sorted_contours[i])

    if contours_to_merge:
        final_merged_contour = np.vstack(contours_to_merge)
        print(f"合并后的轮廓形状: {final_merged_contour.shape}")
        return final_merged_contour
    else:
        print("没有轮廓被选中进行合并。")
        return None

# 创建一个虚拟图像文件进行演示
dummy_image_path = "dummy_contours.png"
dummy_img = np.zeros((200, 200), dtype=np.uint8)
cv.rectangle(dummy_img, (20, 20), (80, 80), 255, -1)
cv.circle(dummy_img, (150, 150), 30, 255, -1)
cv.imwrite(dummy_image_path, dummy_img)

# 调用函数进行合并
merged_contour_result = merge_selected_contours(dummy_image_path, num_to_merge=2)

if merged_contour_result is not None:
    # 可以在这里对合并后的轮廓进行进一步处理,例如绘制
    output_img = np.zeros((200, 200, 3), dtype=np.uint8)
    cv.drawContours(output_img, [merged_contour_result], -1, (0, 255, 0), 2)
    cv.imshow("Merged Contours", output_img)
    cv.waitKey(0)
    cv.destroyAllWindows()

注意事项与最佳实践

  1. 数据类型和维度一致性:np.vstack()要求所有待堆叠的数组在除第一个维度(行数)之外的所有维度上都保持一致。OpenCV返回的轮廓通常满足这一条件,即它们的形状都是 (N, 1, 2) 或 (N, 2)。
  2. 效率:对于大量的NumPy数组合并,先将它们收集到一个Python列表中,然后调用一次np.vstack()通常比在循环中反复调用np.vstack()更高效。这是因为后者可能涉及多次内存重新分配和数据复制。
  3. 内存管理:合并非常大的轮廓或大量轮廓可能会占用大量内存。在处理大型图像或复杂轮廓时,请注意内存使用情况。
  4. 轮廓排序:在合并之前对轮廓进行排序(例如按面积、长度或位置)是一个常见的预处理步骤,这取决于你的具体需求。本教程中的示例展示了按轮廓长度排序。
  5. 空轮廓列表处理:在调用np.vstack()之前,最好检查一下用于存储轮廓的列表是否为空,以避免在列表为空时引发错误。

总结

在OpenCV中合并多个轮廓时,核心策略是避免在循环中直接使用np.vstack()。正确的做法是创建一个Python列表来暂存所有需要合并的轮廓,然后在循环结束后,对这个列表调用一次np.vstack()函数。这种方法不仅能确保所有轮廓数据被完整地整合,而且在处理大量轮廓时也更为高效。通过理解轮廓的数据结构和np.vstack()的工作原理,开发者可以更准确、高效地处理图像中的复杂轮廓数据。

热门AI工具

更多
Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

相关专题

更多
数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3111

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

554

2025.10.31

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

542

2026.02.12

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2641

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

376

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

397

2026.01.06

C++ 数据结构与算法实现教程合集
C++ 数据结构与算法实现教程合集

以 C++ 为实现语言,系统讲解核心数据结构与算法,涵盖链表(单链表/双链表/环检测)、栈与队列(单调栈/优先队列)、二叉树(遍历/BST/AVL/红黑树)、哈希表(开地址法/链地址法)、图(邻接表/BFS/DFS/Dijkstra/拓扑排序)、常见排序算法(快排/归并/堆排/计数排序)的实现与复杂度分析,同时分享 LeetCode 刷题技巧、竞赛编程常用模板(二分/前缀和/滑动窗口/动态规划),帮助开发者夯实算法基础。

472

2026.05.09

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

6107

2023.07.18

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

60

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn