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)

参数说明:

  1. image:需要进行轮廓查找的二值图像。
  2. contours:存储轮廓的数组,这是一个VectorOfVectorOfPoint类型。
  3. hierarchy:存储轮廓的层级信息,它是一个包含四个整数的数组,其结构为:

同层下一个轮廓索引-同层上一个轮廓索引-第一个子轮廓索引-父轮廓索引

通常使用VectorOfRect来存储这个层级结构信息,以上结构信息对应Rect的:

X-Y-Width-Height

  1. mode:轮廓查找的模式。这是一个RetrType枚举类型,包含以下成员:
    1. List:提取所有轮廓,不建立层级关系。
    2. Ccomp:提取所有轮廓,并建立两层层级关系。
    3. External:只提取最外层的轮廓。
    4. Tree:提取所有的轮廓并建立完整的层级关系。
  2. method:轮廓近似的方法。这是一个ChainApproxMethod枚举类型,主要成员:
    1. ChainCode:表示使用链码近似算法,该算法使用像素点的坐标差异来表示轮廓的形状。计算复杂度较低。
    2. ChainApproxNone:表示不使用近似算法,直接使用所有像素点来表示轮廓的形状。计算复杂度较低。
    3. ChainApproxSimple:表示使用简单的近似算法,该算法使用线段连接像素点来近似轮廓的形状。计算复杂度较高。
    4. ChainApproxTc89L1:表示使用Teh-Chin链码近似算法之一,该算法可以更加准确地表示轮廓的形状。计算复杂度较高。
    5. ChainApproxTc89Kcos:表示使用Teh-Chin链码近似算法之一,该算法可以更加准确地表示轮廓的形状。计算复杂度较高。
  3. 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)

参数说明:

  1. contours:要绘制的轮廓数组,这是一个VectorOfVectorOfPoint类型。对应使用FindContours方法获得的contours。
  2. contourIdx:要绘制的轮廓的索引。传入-1表示绘制所有的轮廓。
  3. color:绘制轮廓的颜色。可以使用MCvScalar结构指定颜色值。
  4. thickness:绘制轮廓的线条粗细。
  5. lineType:绘制轮廓的线条类型。
  6. hierarchy:轮廓的层级信息,如果不需要使用层级信息,可设置为Nothing。
  7. maxLevel:绘制轮廓的最大层级,默认值为Integer.MaxValue,表示绘制所有层级的轮廓。
  8. 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

参数说明:

  1. contour:要计算面积的轮廓。这是一个VectorOfPoint类型。对应使用FindContours方法获得的contours所包含的成员。
  2. 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

参数说明:

  1. contour:要计算周长的轮廓。这是一个VectorOfPoint类型。对应使用FindContours方法获得的contours所包含的成员。
  2. 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 输出轮廓的面积和周长

相关推荐
EdisonZhou25 分钟前
大模型应用开发初探 : 通用函数调用Planner
aigc·.net·.net core
DisonTangor1 小时前
阿里通义千问开源Qwen2.5系列模型:Qwen2-VL-72B媲美GPT-4
人工智能·计算机视觉
豆浩宇1 小时前
Halcon OCR检测 免训练版
c++·人工智能·opencv·算法·计算机视觉·ocr
嵌入式杂谈1 小时前
OpenCV计算机视觉:探索图片处理的多种操作
人工智能·opencv·计算机视觉
时光追逐者1 小时前
分享6个.NET开源的AI和LLM相关项目框架
人工智能·microsoft·ai·c#·.net·.netcore
红米煮粥1 小时前
图像处理-掩码
图像处理·opencv·计算机视觉
Zhangci]2 小时前
OpenCv(一)
人工智能·opencv·计算机视觉
Java资深爱好者12 小时前
VB.NET中如何利用ASP.NET进行Web开发
前端·asp.net·.net
Lingbug15 小时前
.Net日志组件之NLog的使用和配置
后端·c#·.net·.netcore
shiming887918 小时前
MATLAB图像处理
图像处理·计算机视觉·matlab