EmguCV学习笔记 VB.Net 6.2 轮廓处理
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。
教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客
教程C#版本请访问:EmguCV学习笔记 C# 目录-CSDN博客
笔者的博客网址:https://blog.csdn.net/uruseibest
教程配套文件及相关说明以及如何获得pdf教程和代码,请移步:EmguCV学习笔记
学习VB.Net知识,请移步: vb.net 教程 目录_vb中如何用datagridview-CSDN博客
学习C#知识,请移步:C# 教程 目录_c#教程目录-CSDN博客
6.2 轮廓处理
6.2.1 VectorOfPoint
VectorOfPoint是EmguCV中用于存储和操作点数可变的点集(Point)的类,它可以用来存储任意数量的点。在前面的章节中介绍过VectorOf~这样的类型。这里单独介绍一下VectorOfPoint。
使用VectorOfPoint类可以方便地进行点集的存储和操作,是在EmguCV中进行图像处理和分析的重要工具之一。在实际中,VectorOfPoint可以理解为很多点的集合,比如图像中的某个填充矩形,它就是由很多点组合在一起的,可以认为这个矩形就是一个VectorOfPoint。
VectorOfPoint类提供了一系列方法和属性,用于对点集进行增删改查、排序、遍历等操作,方便进行图像处理和分析。
1、创建VectorOfPoint对象
创建VectorOfPoint对象的方式如下:
Dim vop As New VectorOfPoint
2、向VectorOfPoint对象中增加点
通过Push方法向VectorOfPoint对象中增加点(这里需要传入点数组),例如:
vop.Push(New Point() {New Point(10, 20), New Point(30, 30)})
3、从VectorOfPoint对象中获取点
可以通过索引器或ToArray方法从VectorOfPoint对象中获取指定位置或所有位置的点,例如:
Dim p As Point = vop(0)
Dim arrP() As Point = vop.ToArray
4、修改VectorOfPoint对象中的点
非常遗憾的是,没有提供直接修改的方法。
5、获取VectorOfPoint中的点的数量
可以通过Length属性获取VectorOfPoint中点的数量。
6、清除VectorOfPoint对象中的点
可以通过Clear方法实现。
其它VectorOf~开头的类型,请参考VectorOfPoint。
6.2.2 VectorOfVectorOfPoint
VectorOfVectorOfPoint是EmguCV中用于存储和操作多个点集(VectorOfPoint)的类,它也是一个泛型类,可以用来存储任意数量的点集。该类提供了一系列方法和属性,用于对点集进行增删改查、排序、遍历等操作,方便进行图像处理和分析。
在实际中,VectorOfVectorOfPoint可以理解为很多VectorOfPoint的集合,比如图像中有矩形、圆形、多边形等,它们分别是由很多点组合在一起的,即这些图形自身是一个VectorOfPoint,而VectorOfVectorOfPoint就包含(可能是全部包含,也可能是部分包含)多个这样的VectorOfPoint。
VectorOfVectorOfPoint类的操作和VectorOfPoint类似,这里不再累述。
其它VectorOfVectorOf~开头的类型,请参考VectorOfVectorOfPoint。
6.2.3 轮廓查找FindContours
通过CvInvoke.FindContours方法,可以在二值图像中查找轮廓,该方法声明如下:
Public Shared Sub FindContours(image As Emgu.CV.IInputOutputArray, contours As Emgu.CV.IOutputArray, hierarchy As Emgu.CV.IOutputArray, mode As Emgu.CV.CvEnum.RetrType, method As Emgu.CV.CvEnum.ChainApproxMethod, Optional offset As System.Drawing.Point = Nothing)
参数说明:
- image:需要进行轮廓查找的二值图像。
- contours:存储轮廓的数组,这是一个VectorOfVectorOfPoint类型。
- hierarchy:存储轮廓的层级信息,它是一个包含四个整数的数组,其结构为:
同层下一个轮廓索引-同层上一个轮廓索引-第一个子轮廓索引-父轮廓索引
通常使用VectorOfRect来存储这个层级结构信息,以上结构信息对应Rect的:
X-Y-Width-Height
- mode:轮廓查找的模式。这是一个RetrType枚举类型,包含以下成员:
- List:提取所有轮廓,不建立层级关系。
- Ccomp:提取所有轮廓,并建立两层层级关系。
- External:只提取最外层的轮廓。
- Tree:提取所有的轮廓并建立完整的层级关系。
- method:轮廓近似的方法。这是一个ChainApproxMethod枚举类型,主要成员:
- ChainCode:表示使用链码近似算法,该算法使用像素点的坐标差异来表示轮廓的形状。计算复杂度较低。
- ChainApproxNone:表示不使用近似算法,直接使用所有像素点来表示轮廓的形状。计算复杂度较低。
- ChainApproxSimple:表示使用简单的近似算法,该算法使用线段连接像素点来近似轮廓的形状。计算复杂度较高。
- ChainApproxTc89L1:表示使用Teh-Chin链码近似算法之一,该算法可以更加准确地表示轮廓的形状。计算复杂度较高。
- ChainApproxTc89Kcos:表示使用Teh-Chin链码近似算法之一,该算法可以更加准确地表示轮廓的形状。计算复杂度较高。
- offset:输入参数,表示轮廓坐标的偏移量。
具体代码参看6.2.4 节【轮廓绘制DrawContours】
!
6.2.4 轮廓绘制DrawContours
在Emgu.CV中,CvInvoke.DrawContours函数用于绘制轮廓。它的用法如下:
Public Shared Sub DrawContours(image As Emgu.CV.IInputOutputArray, contours As Emgu.CV.IInputArrayOfArrays, contourIdx As Integer, color As Emgu.CV.Structure.MCvScalar, Optional thickness As Integer = 1, Optional lineType As Emgu.CV.CvEnum.LineType = 8, Optional hierarchy As Emgu.CV.IInputArray = Nothing, Optional maxLevel As Integer = 2147483647, Optional offset As System.Drawing.Point = Nothing)
参数说明:
- contours:要绘制的轮廓数组,这是一个VectorOfVectorOfPoint类型。对应使用FindContours方法获得的contours。
- contourIdx:要绘制的轮廓的索引。传入-1表示绘制所有的轮廓。
- color:绘制轮廓的颜色。可以使用MCvScalar结构指定颜色值。
- thickness:绘制轮廓的线条粗细。
- lineType:绘制轮廓的线条类型。
- hierarchy:轮廓的层级信息,如果不需要使用层级信息,可设置为Nothing。
- maxLevel:绘制轮廓的最大层级,默认值为Integer.MaxValue,表示绘制所有层级的轮廓。
- offset:绘制轮廓的坐标偏移量,默认值为Nothing。
【代码位置:frmChapter6】Button4_Click
'FindContours查找轮廓
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
'直接载入灰度图像
Dim m1 As New Mat("C:\learnEmgucv\shape1.jpg", CvEnum.ImreadModes.Grayscale)
ImageBox1.Image = m1
'二值化
Dim mid1 As New Mat
CvInvoke.Threshold(m1, mid1, 150, 255, ThresholdType.BinaryInv)
'最好使最外层为黑色。如果为白色,那么会将最外层算为一个轮廓。所以这里使用 ThresholdType.BinaryInv
ImageBox2.Image = mid1
Dim contours As New VectorOfVectorOfPoint
Dim hierarchy As New VectorOfRect
'同层下一个轮廓索引-同层上一个轮廓索引-第一个子轮廓索引-父轮廓索引
CvInvoke.FindContours(mid1, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple)
Dim m2 As New Mat
m2 = m1.Clone()
m2.SetTo(New MCvScalar(0))
'绘制轮廓
For i As Integer = 0 To contours.Size - 1
CvInvoke.DrawContours(m2, contours, i, New MCvScalar(255), 2)
Next
ImageBox3.Image = m2
'输出轮廓层级信息
For i As Integer = 0 To hierarchy.Size - 1
Console.WriteLine(i & "-" & hierarchy(i).X & "-" & hierarchy(i).Y & "-" & hierarchy(i).Width & "-" & hierarchy(i).Height)
Next
End Sub
运行后如下图所示:
图6-4 绘制出的轮廓
图6-5 输出轮廓间关系
以下代码只绘制出最外层轮廓,由于不需要层级关系,所以hierarchy设置为nothing,mode设置为External。
【代码位置:frmChapter6】Button5_Click
'FindContours查找轮廓
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
Dim m1 As New Mat("C:\learnEmgucv\shape1.jpg", CvEnum.ImreadModes.Grayscale)
ImageBox1.Image = m1
Dim mid1 As New Mat
CvInvoke.Threshold(m1, mid1, 150, 255, ThresholdType.BinaryInv)
ImageBox2.Image = mid1
Dim contours As New VectorOfVectorOfPoint
Dim hierarchy As New VectorOfRect
'只提取最外层轮廓
CvInvoke.FindContours(mid1, contours, Nothing, RetrType.External, ChainApproxMethod.ChainApproxSimple)
'在全黑的图像上绘制出轮廓
Dim m2 As New Mat
m2 = m1.Clone()
m2.SetTo(New MCvScalar(0))
For i As Integer = 0 To contours.Size - 1
CvInvoke.DrawContours(m2, contours, i, New MCvScalar(255), 2)
Next
ImageBox3.Image = m2
End Sub
运行后如下图所示:
图6-6 绘制出的轮廓
6.2.5 轮廓面积 ContourArea
CvInvoke.ContourArea方法用于计算轮廓的面积。它的声明如下:
Public Shared Function ContourArea(contour As Emgu.CV.IInputArray, Optional oriented As Boolean = False) As Double
参数说明:
- contour:要计算面积的轮廓。这是一个VectorOfPoint类型。对应使用FindContours方法获得的contours所包含的成员。
- calculateArea:指定轮廓是否有方向,即面积是否为有向面积。如果为True,则计算的是有向面积,否则计算的是无向面积。有向面积是指轮廓线的外侧为正面,内侧为负面,因此有向面积可以为正数或负数;无向面积则是指轮廓线所包含的平面区域的面积,只能为正数。默认情况下,该参数为 false,即不考虑方向,总是返回面积的绝对值。
【代码位置:frmChapter6】Button6_Click
'按照面积进行筛选输出
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Dim m1 As New Mat("C:\learnEmgucv\shape1.jpg", CvEnum.ImreadModes.Grayscale)
ImageBox1.Image = m1
'二值化
Dim mid1 As New Mat
CvInvoke.Threshold(m1, mid1, 150, 255, ThresholdType.BinaryInv)
ImageBox2.Image = mid1
Dim contours As New VectorOfVectorOfPoint
Dim hierarchy As New VectorOfRect
'查找轮廓
CvInvoke.FindContours(mid1, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple)
Dim m2 As New Mat
m2 = m1.Clone()
m2.SetTo(New MCvScalar(0))
For i As Integer = 0 To contours.Size - 1
Dim carea As VectorOfPoint = contours(i)
'获得轮廓面积
Dim area As Double = CvInvoke.ContourArea(carea, False)
'符合条件时,绘制轮廓
If area < 10000 Then
CvInvoke.DrawContours(m2, contours, i, New MCvScalar(255), -1)
End If
Next
ImageBox3.Image = m2
End Sub
运行后如下图所示:
图6-7 输出面积小于10000的轮廓
6.2.6 轮廓周长 ArcLength
在Emgu.CV中,CvInvoke.ArcLength函数用于计算轮廓的弧长(周长)。它的用法如下:
Public Shared Function ArcLength(curve As Emgu.CV.IInputArray, isClosed As Boolean) As Double
参数说明:
- contour:要计算周长的轮廓。这是一个VectorOfPoint类型。对应使用FindContours方法获得的contours所包含的成员。
- closed:表示轮廓是否是闭合的。如果为True,返回轮廓的曲线长度;如果为False,返回轮廓的周长。
【代码位置:frmChapter6】Button7_Click
'轮廓的面积和周长
Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click
Dim m1 As New Mat("C:\learnEmgucv\shape1.jpg", CvEnum.ImreadModes.Grayscale)
ImageBox1.Image = m1
'二值化并取反
Dim mid1 As New Mat
CvInvoke.Threshold(m1, mid1, 150, 255, ThresholdType.BinaryInv)
ImageBox2.Image = mid1
Dim contours As New VectorOfVectorOfPoint
Dim hierarchy As New VectorOfRect
'查找轮廓
CvInvoke.FindContours(mid1, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple)
Dim m2 As New Mat
m2 = m1.Clone()
m2.SetTo(New MCvScalar(0))
For i As Integer = 0 To contours.Size - 1
'绘制轮廓
CvInvoke.DrawContours(m2, contours, i, New MCvScalar(255), 2)
'获得面积
Dim area As Double = CvInvoke.ContourArea(contours(i), False)
'获得周长
Dim length As Double = CvInvoke.ArcLength(contours(i), True)
'输出面积和周长
Console.WriteLine(i & "-" & area & "-" & length)
Next
ImageBox3.Image = m2
End Sub
运行后如下图所示:
图6-8 输出轮廓的面积和周长
相关文章:

EmguCV学习笔记 VB.Net 6.2 轮廓处理
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…...

【Python的魅力】:利用Pygame实现游戏坦克大战——含完整源码
文章目录 一、游戏运行效果二、代码实现2.1 项目搭建2.2 加载我方坦克2.3 加载敌方坦克2.4 添加爆炸效果2.5 坦克大战之音效处理 三、完整代码 一、游戏运行效果 二、代码实现 坦克大战游戏 2.1 项目搭建 本游戏主要分为两个对象,分别是我方坦克和敌方坦克。用户可…...

【机器学习】经典CNN架构
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 经典CNN架构1. 引言2. LeNet3. AlexNet4. VGGNet5. GoogLeNet(Inception)6. Res…...

图像数据处理21
五、边缘检测 5.2基于二阶导数的边缘检测 一阶导数(如Sobel、Prewitt算子)能够捕捉到灰度值的快速变化,但有时会因检测到过多的边缘点而导致边缘线过粗。为了更加精确地定位边缘位置,可以利用二阶导数的零交叉点。零交叉点是是函…...

day37动态规划+三.Github链接本地仓库
一.动态规划 474.一和零 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。 思路:这道题更像是另一种的0-…...

设备运维故障排查与修复技巧
运维中最常见的40个故障问题及其解决方法: 1. 网络不通问题:无法访问网络资源。 解决方法:检查物理线路、交换机端口、网卡驱动和配置,使用ping、traceroute等工具定位问题。 2. 网络速度慢问题:访问网络资源速度慢。 解决方法:分析带宽使用情况,检查是否存在广播风…...

探索Python的自动化魔法:AutoIt库揭秘
文章目录 探索Python的自动化魔法:AutoIt库揭秘第一部分:背景介绍第二部分:AutoIt是什么?第三部分:如何安装AutoIt库?第四部分:AutoIt的五个简单函数第五部分:场景应用第六部分&…...

【I/O多路复用】
基于I/O多路复用的并发编程 I/O实现I/O多路复用select优缺点 pollepoll优点 I/O I/O复用是基于一个单进程或单线程的一个执行流当中监控多个输入输出流的技术(网络套接字或者文件描述符进行监控)。单进程或单线程,允许多个用户对单进程发起连…...

【python报错已解决】“IndexError: list index out of range”
🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 引言 你是否在处理Python列表时遇到了“IndexError: list index out of range”的错误?这个错误可能会让你的程序中…...

oracle和mysql查询某字段在哪个表中
oracle和mysql查询某字段在哪个表中 oracle的 select TABLE_NAME from user_tab_columns where COLUMN_NAME字段名mysql的: select table_schema ,table_name from information_schema.columns where column_name ‘字段名’ 查询结果table_schema为数据库名&a…...

TCP vs UDP:揭秘可靠性与效率之争
概述 今天我们开始主要讲解TCP的相关知识点。在之前讲解分层章节的时候,我们提到过一个重要观点。在网络层及以下几层,更多的是让主机与主机建立连接,也就是说你的电脑需要知道另一台电脑在哪里才能连接上它。然而,在网络中的通信…...

“树”的高度的计算——CSP-J1真题详解
如同树有高度一样,数据结构中的“树”也有高度,只不过这个高度指的是第几“层”。就像武功可以修炼到第几层一样,树也可以长到第几层。 需要指明的是,树的根节点属于第几层是没有严格的定义的,一般被认为是处于第0层或…...

Docker介绍、docker安装以及实现docker的远程管理
1.Docker介绍 1.Docker介绍 Docker 是⼀个开源的应用容器引擎,可以实现虚拟化,完全采用“沙盒”机制,容器之间不会存在任何接口。 Docker 通过 Linux Container(容器)技术将任意类型的应用进行包装,变成一…...

【UE5】基于摄像机距离逐渐剔除角色
效果 步骤 1. 新建一个工程,在内容浏览器中添加第三人称游戏内容包 2. 找到第三人称角色的材质实例“MI_Quinn_01”并打开 找到材质实例的父项材质“M_Mannequin” 打开材质“M_Mannequin” 在材质图表中添加如下节点 此时运行效果如文章开头所示。 参考视频&#…...

LabVIEW优化内存使用
在LabVIEW中,优化内存使用的关键在于理解LabVIEW的内存管理机制并采用一些最佳实践。以下是一些可能帮助减少内存占用的方法: 1. 减少数据副本的生成 避免不必要的数据复制:每当你在程序中传递数组或子数组时,LabVIEW可能会创建副…...

多进程和多线程基础概念LINUX
进程和程序的区别 程序是静态的,它是保存在磁盘上的指令的有序集合,没有任何执行的概念进程是一个动态的概念,它是程序执行的过程,包括了动态创建、调度和销毁的整个过程 并行:在 cpu 多核的支持下,实现物…...

React Native的Android端fetch的网络请求FormData请求错误:TypeError:Network request failed
// formdataconst formData new FormData();formData.append("code", appUserCode);formData.append("wallet", appName);// const formDataStr code appUserCode &wallet appName;// 参数形式//const _body code${appUserCode}&wallet${app…...

python之matplotlib (1 介绍及基本用法)
介绍 matplotlib是Python中的一个绘图库,它提供了一个类似于 MATLAB 的绘图系统。使用matplotlib你可以生成图表、直方图、功率谱、条形图、错误图、散点图等。matplotlib广泛用于数据可视化领域,是 Python 中最著名的绘图库之一。 同样matplotlib的安…...

ROS2常用指令
ROS2(Robot Operating System 2)是一个用于机器人软件开发的灵活框架,它提供了一套丰富的工具和库来支持机器人的开发、模拟、部署和测试。ROS2的常用指令可以大致分为几个类别,包括功能包管理、节点管理、话题管理、服务管理、动…...

SQL注入(原理、分类、union、POST注入)
目录 【学习目标、重难点知识】 【学习目标】 【重难点知识】 SQL注入简介 SQL注入原理 SQL注入类型 MySQL与SQL注入的相关知识 information_schema 数据库的结构 数据库查询语句 limit的用法 需要记住的几个函数 注释符号 SQL注入探测方法 SQL注入漏洞攻击流程…...

【勒索病毒应急响应流程】
概述 不同应急事件响应方式不同,建议大家阅读以下案例,解决自己当前的困扰,当然也可以根据自己的经验对文章进行补充和修正,欢迎在评论区留言。 案例1 事件概述 某安服团队接到某政府部门的远程应急响应求助,要求对被勒索服务器进行排查分析并溯源。 排查溯源 1、应…...

C ++初阶:C++入门级知识点
目录 🌞0.前言 🚈1.C输入输出 🚈2.缺省参数 🚝2.1全缺省参数 🚝2.2半缺省参数 🚈3.函数重载 🚝3.1参数类型不同 🚝 3.2参数个数不同 🚝3.3参数类型顺序不同 …...

php中如何高效地实现一个函数以判断给定日期是否位于多个预定义的时间范围内,同时确保代码的可读性、可维护性和性能优化
背景信息: 我有一个包含多个时间范围的数组,每个时间范围由起始日期和结束日期组成(目前以字符串形式给出),例如: $ranges [[start > 2023-01-01, end > 2023-03-31],[start > 2023-06-01, end …...

存在重复元素 II(LeetCode)
题目 给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] nums[j] 且 abs(i - j) < k 。如果存在,返回 true ;否则,返回 false 。 解题 """ 时间复杂度…...

认知杂谈21
今天分享 有人说的一段争议性的话 I I 自在之“坏”:真实自我的绽放 在社交场合中,听到“他不是个好人”这句话可能会让人惊讶,但其实被贴上“坏人”标签的人往往敢于跳出规则框架,展现真实自我。他们不做表面和谐的牺牲品&am…...

2024前端面试题-工程化篇
1.webpack(模块打包工具)五大核心 Entry入口,Output定义输出路径和命名规则,Loader模块转换器,Plugin扩展插件,Mode模式(Webpack使用相应模式的配置) 2.谈一谈你对Loader和Plugin的…...

【附源码】Python :PYQT界面点击按钮随机变色
系列文章目录 Python 界面学习:PYQT界面点击按钮随机变色 文章目录 系列文章目录一、项目需求二、源代码三、代码分析3.1 导入模块:3.2 定义App类:3.3 构造函数:3.4 初始化用户界面:3.5 设置窗口属性:3.6 …...

[Qt][QSS][下]详细讲解
目录 1.样式属性0.前言1.盒模型(Box Model) 2.常用控件样式属性1.按钮2.复选框3.单选框4.输入框5.列表6.菜单栏7.注意 1.样式属性 0.前言 QSS中的样式属性⾮常多,不需要都记住,核⼼原则是⽤到了就去查 ⼤部分的属性和CSS是⾮常相似的 QSS中有些属性&am…...

RAII在实现webserver这个项目中是怎么体现的?起到了什么作用
在WebServer项目中,RAII(Resource Acquisition Is Initialization,即资源获取即初始化)是一种重要的资源管理策略,它主要通过智能指针、锁、文件句柄等对象的生命周期来管理资源的分配和释放。RAII在WebServer项目中的…...

QT下显示自己派生的QWidget界面(提升为)
在实际开发过程中,我们可能有这样的需求,自己绘制一个仪表盘界面,然后将其贴到主界面上方。 这个时候就会用到“提升为”这个功能,该功能目的是将QWidget提升为自己派生的QWdiget子类,具体操作为,在主界面…...