【Emgu CV教程】10.5、轮廓之凸包

文章目录

  • 一、什么叫轮廓的凸包
  • 二、凸包函数
  • 三、二维点集寻找凸包
  • 四、绘制物体轮廓的凸包
    • 1.原始素材
    • 2.代码
    • 3.运行结果


一、什么叫轮廓的凸包

凸包是一个更加简化的多边形,是轮廓最外层的“凸”多边形,与前一篇多边形近似拟合不同的是,凸包组成的折线图形,必须包含住整个轮廓,而且折线图形任意连续的三个点的内角小于180度。

下图中,右侧的多边形是凸包,左侧的是凹包,注意红框标注的那个点,就是凹点。
在这里插入图片描述
Emgu CV里面,或者说是OpenCV里面,只计算凸包,凹包没有意义。

二、凸包函数

public static void ConvexHull(
	IInputArray points, // 输入的轮廓
	IOutputArray hull, // 输出的凸包点集
	bool clockwise = false, //如果为true,输出的凸包是顺时针的,如果是false,输出的凸包是逆时针的。
	bool returnPoints = true // 为true就可以,一般别设为false
)

函数的输出结果 IOutputArray approxCurve ,是近似拟合点的集合。

三、二维点集寻找凸包

这是一个最简单的应用,假设我们有一堆已知的二维点集,这些点集的凸包,就像一堵围墙,可以把所有的点都围起来,代码可以这样写:

Mat dstMat = new Mat(500, 500, DepthType.Cv8U, 3);
dstMat.SetTo(new MCvScalar(0));

Random random = new Random();
VectorOfPoint vPoints1 = new VectorOfPoint(); // 存储随机点
VectorOfPoint hull = new VectorOfPoint();  // 存储凸包点
hull.Clear(); // 清除上一次数据
int count = random.Next(3, 50);

// 创建随机点集
System.Drawing.Point[] pt = new System.Drawing.Point[1];
for (int i = 0; i < count; i++)
{
    pt[0].X = random.Next(dstMat.Cols / 5, dstMat.Cols * 4 / 5);
    pt[0].Y = random.Next(dstMat.Rows / 5, dstMat.Rows * 4 / 5);
    CvInvoke.Circle(dstMat, pt[0], 3, new MCvScalar(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)), -1);
    vPoints1.Push(pt);
}

// 绘制凸包(闭合曲线)
CvInvoke.ConvexHull(vPoints1, hull, false, true);
for (int i = 0; i < hull.Size; i++)
{
    CvInvoke.Line(dstMat, hull[i], hull[(i + 1) % hull.Size], new MCvScalar(255, 255, 255), 2);
}

Image1.Source = dstMat.ToBitmapSource();

在一张 500 *500 大小的黑色背景图片中,创建随机数量的点,并利用ConvexHull()函数计算出凸包点,然后再用白色直线画出凸包图形。效果如下:
在这里插入图片描述

四、绘制物体轮廓的凸包

1.原始素材

原始图像srcMat如下:
在这里插入图片描述
这是一个毛笔书写的汉字“之”,分成了独立的4个部分,我们就对其4个部分做凸包检测。

2.代码

Mat tempMat = srcMat.Clone();
Mat dstMat = srcMat.Clone();
Mat gray = new Mat();
int threshold = 40;

// 转成灰度图再二值化
CvInvoke.CvtColor(tempMat, gray, ColorConversion.Bgr2Gray);
CvInvoke.Threshold(gray, gray, threshold, 255, ThresholdType.Binary);
CvInvoke.Imshow("Gray and threshold", gray);

// 定义轮廓集合
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
VectorOfRect hierarchy = new VectorOfRect();

CvInvoke.FindContours(gray, contours, hierarchy, RetrType.External, ChainApproxMethod.ChainApproxNone);

// 在一张黑色图中画出所有轮廓
Mat allContours = new Mat(new System.Drawing.Size(gray.Cols, gray.Rows), DepthType.Cv8U, 1);
allContours.SetTo(new MCvScalar(0, 0, 0));
CvInvoke.DrawContours(allContours, contours, -1, new MCvScalar(255, 255, 255), 1);

// 按照面积筛选,太小的轮廓不计算
Dictionary<int, double> dict = new Dictionary<int, double>();
if (contours.Size > 0)
{
    for (int i = 0; i < contours.Size; i++)
    {
        double area = CvInvoke.ContourArea(contours[i]);
        Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);

        if (rect.Width > 20 && rect.Height > 20 && area < 3000000)
        {
            dict.Add(i, area);
        }
    }
}

var item = dict.OrderByDescending(v => v.Value); // v.Value就代表面积,是降序排列

// 开始绘制凸包
Random random = new Random();
VectorOfInt hull = new VectorOfInt(); // 存储凸包点索引
foreach (var it in item)
{
    int key = it.Key;
    CvInvoke.ConvexHull(contours[key], hull);
    MCvScalar randomColor = new MCvScalar(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));
    for (int i = 0; i < hull.Size; i++)
    {
        if (i != hull.Size - 1)
        {
            CvInvoke.Line(dstMat, contours[key][hull[i]], contours[key][hull[i + 1]], randomColor, 2);
        }
        else
        {
            CvInvoke.Line(dstMat, contours[key][hull[i]], contours[key][hull[0]], randomColor, 2);
        }
    }
}

CvInvoke.Imshow("All contours, " + dict.Count(), allContours);
CvInvoke.Imshow("Final result image, " + dstMat.Size.ToString(), dstMat);

3.运行结果

如下所示:
在这里插入图片描述

注意:凸包和多边形近似拟合是不同的。凸包的形状可能和轮廓不相似,但是要保证轮廓都在凸包内部;多边形近似拟合可以和轮廓相似,但可能存在“凹点”。

最简单的理解,凸包可以想象为一条刚好包住所有点的橡皮圈。


原创不易,请勿抄袭。共同进步,相互学习。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学生宿舍智能控电柜安装调试技术

学生宿舍智能控电柜安装调试石家庄光大远通电器有限公司宿舍控电限电管理系统是一种用于管理学生宿舍用电的智能系统&#xff0c;主要功能包括: 1.实时监控和控制:该系统能够实时监测和记录宿舍的用电情况&#xff0c;包括电器使用情况、电量消耗等。管理人员可以通过电脑或手机…

数据结构(五)——树与二叉树的应用

5.5 树与二叉树的应用 5.5.1 哈夫曼树 结点的权&#xff1a;有某种现实含义的数值。 结点的带权路径长度&#xff1a;从树的根到该结点的路径长度&#xff08;经过的边数&#xff09;与该结点上权值的乘积。 树的带权路径长度&#xff1a;树中所有叶结点的带权路径长度之和…

FPGA电平标准

1.LVTTL&#xff1a;&#xff08;3.3v&#xff09; 2.LVCOMS&#xff1a;&#xff08;1.8v&#xff09; 3.LVDS&#xff08;1.8v&#xff09;&#xff1a;LVDS_25&#xff08;2.5v&#xff09; 4&#xff1a;如果是ddr3与fpga相连接fpga的vcco推荐&#xff08;1.5v&#xff09;…

【Linux】进程的基本概念(进程控制块,ps命令,top命令查看进程)

目录 01.进程的基本概念 程序与进程 进程的属性 02.进程控制块&#xff08;PCB&#xff09; task_struct的内容分类 组织进程 03.查看进程 ps命令 top指令 在计算机科学领域&#xff0c;进程是一项关键概念&#xff0c;它是程序执行的一个实例&#xff0c;是操作系统的…

【Linux C | 多线程编程】线程的退出

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 本文未经允许…

第九届蓝桥杯大赛个人赛省赛(软件类)真题C 语言 A 组-乘积尾零

solution 找末尾0的个数&#xff0c;即找有多少对2和5 >问题等价于寻找所给数据中&#xff0c;有多少个2和5的因子&#xff0c;较少出现的因子次数即为0的个数 #include <iostream> using namespace std; int main() {// 请在此输入您的代码printf("31");…

项目3-留言板

1.创建项目 记得将project type改为maven 将需要的包引入其中 更改版本号 引入MYSQL相关包记得进行配置&#xff01;&#xff01;&#xff01; spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncodingutf8&useSSLfalseusername: rootpassword:…

MySQL将id相同的两行数据合并group_concat

MySQL将id相同的两行数据合并 group_concat这个函数能将相同的行组合起来&#xff0c;省老事了。 MySQL中group_concat函数 完整的语法如下&#xff1a; group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator ‘分隔符’]) 1.基本查询 Sql代码 2.…

力扣热门算法题 89. 格雷编码,92. 反转链表 II,93. 复原 IP 地址

89. 格雷编码&#xff0c;92. 反转链表 II&#xff0c;93. 复原 IP 地址&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.24 可通过leetcode所有测试用例。 目录 89. 格雷编码 解题思路 完整代码 Python Java 92. 反转链表…

SOC 子模块---中断控制器

中断控制器对soc 中的各个外设进行中断管理&#xff0c;进行优先权排队&#xff0c;并送出IQR信号给CPU&#xff1b; 中断控制器在整个系统中的结构&#xff1a; IRQ<n>来源于不同的中断源&#xff0c;比如&#xff1a;I2C,SPI等&#xff0c;INTC收集这些中断&#xff0…

从人工智能入门到理解ChatGPT的原理与架构的第一天(First)

目录 一.ChatGPT的发展历程 二.Attention is all you need 三.对于GPT-4的智能水平评估 四.大语言模型的技术演化 1.从符号主义到连接主义 2.特征工程 2.1数据探索 2.2数据清洗 2.3数据预处理 2.3.1无量纲化 2.3.1.1标准化 2.3.1.2区间缩放法 2.3.1.3标准化与归一…

Numpy使用中的十大经典routines函数

1.np.ones(shape, dtypeNone, order‘C’) np.ones(shape(3, 4, 3), dtypenp.int32)array([[[1, 1, 1],[1, 1, 1],[1, 1, 1],[1, 1, 1]],[[1, 1, 1],[1, 1, 1],[1, 1, 1],[1, 1, 1]],[[1, 1, 1],[1, 1, 1],[1, 1, 1],[1, 1, 1]]])2.np.zeros(shape, dtypefloat, order‘C’) …

P1835 素数密度题解

题目 给定区间[L,R]&#xff08;1≤L≤R<&#xff0c;R−L≤&#xff09;&#xff0c;请计算区间中素数的个数。 输入输出格式 输入格式 第一行&#xff0c;两个正整数L和R。 输出格式 一行&#xff0c;一个整数&#xff0c;表示区间中素数的个数。 输入输出样例 输…

Python库xarray:强大的多维数据处理工具

Python库xarray&#xff1a;强大的多维数据处理工具 在数据科学和科学计算领域&#xff0c;处理多维数据是一项常见而重要的任务。Python库xarray是一个功能强大的工具&#xff0c;专门用于处理、分析和可视化多维数据集。本文将深入介绍xarray库的特性、用法和优势&#xff0c…

网盘——客户端登陆注册注销请求

关于网盘设计&#xff0c;在客户端登录注册注销部分&#xff0c;主要有以下五个部分&#xff1a;消息类型、界面设计、注册、登录、注销 消息类型&#xff1a;我们可以把它写成枚举类型的 界面设计&#xff1a; 注册&#xff1a;用户名唯一&#xff0c;防止重复注册。查询数…

UI自动化_id 元素定位

## 导包selenium from selenium import webdriver import time1、创建浏览器驱动对象 driver webdriver.Chrome() 2、打开测试网站 driver.get("你公司的平台地址") 3、使浏览器窗口最大化 driver.maximize_window() 4、在用户名输入框中输入admin driver.find_ele…

编译u-boot(硬件: atk-dl6y2c)和NFS/EMMC模式启动Linux Kernel

目录 概述 1 编译u-boot 1.1 解压文件 1.2 编译u-boot 2 配置环境 2.1 在Ubunt 搭建TFTP 2.2 建立下载目录 3 烧写bootloader到SD 4 使用NFS模式启动板卡 5 从EMMC 启动 Linux 系统 5.1 通过配置参数方式 5.2 使用命令直接启动内核 文中使用的代码下载地址&#xf…

QT(3/25)

完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示“登录成功”&#xff0c;提供一个OK按钮&#xff0c;用户点击OK后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面。 如果账号和密码不匹配&#…

day04_JDBC_课后练习 - 参考答案(一共11道练习题)

文章目录 day04_JDBC_课后练习第1题参考答案第1题-第3题的sql第4题第5题第6题第7题第8题第9题第10题第11题 day04_JDBC_课后练习 第1题 案例&#xff1a; 1、创建数据库day04_test01_bookstore 2、创建如下表格 &#xff08;1&#xff09;图书表books &#xff08;2&#…

基于SpringBoot+MyBatis校园周边美食探索及分享平台

采用技术 基于SpringBootMyBatis校园周边美食探索及分享平台的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 功能清单 前台首页 登录页面 美食鉴赏界面…