EmguCV学习笔记 VB.Net 2.3 Mat类

news2024/12/25 0:00:32

 版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。

EmguCV学习笔记目录 Vb.net

EmguCV学习笔记目录 C#

笔者的博客网址:VB.Net-CSDN博客

教程相关说明以及如何获得pdf教程和代码(博客上的教程内容会和pdf教程一致,教程中也会包含所有代码),请移步:EmguCV学习笔记

2.3 Mat类

Mat类也是OpenCV中的矩阵类,EmguCV对其进行了封装。Mat类提供了图像数据读取、保存方法,提供矩阵运算方法,如矩阵加减、乘法、转置等,如等。Mat类是EmguCV中处理图像的最常用和最重要的类,需要好好掌握。

Mat类常用属性:

  1. Rows和Cols:分别表示矩阵的行数和列数。可以通过这两个属性来获取矩阵的大小。
  2. Step:表示矩阵每一行的字节数。这个属性可以用于计算矩阵中某个元素的地址。
  3. Data:表示矩阵数据的指针。这个指针指向矩阵数据的第一个元素,可以通过它来访问矩阵中的每个元素。
  4. Depth:这是一个DepthType枚举,表示矩阵中每个元素的深度,即数据类型的位数。例如,CV_8U表示每个元素是8位无符号整数。

DepthType枚举元素主要有:

元素名称

元素值

占用位数

说明

Cv8U

0

8位

无符号整数 Byte

Cv8S

1

8位

符号整数 SByte

Cv16U

2

16位

无符号整数 UInt16

Cv16S

3

16位

符号整数 Int16

Cv32S

4

32位

无符号整数 Int32

Cv32F

5

32位

浮点数 Single

Cv64F

6

64位

浮点数  Double

注意:在OpenCV中使用CV_8UC1这样的类型,表示8位无符号单通道矩阵。C后面的数字表示通道数。

  1. NumberOfChannels:表示矩阵中每个元素的通道数。例如,3通道的CV_8U通常表示每个元素有3个通道,分别表示红、绿、蓝三个颜色通道。
  2. IsContinuous:表示矩阵是否是连续的。如果矩阵的所有元素在内存中是连续存储的,那么这个属性的值为true,否则为false。
  3. Size:表示矩阵的大小,即行数和列数。这个属性返回一个Size类型的对象,可以通过它来获取矩阵的行数和列数。
  4. Width和Height:分别表示矩阵的宽度和高度。可以通过这两个属性来获取矩阵的大小。
  5. ElementSize:表示矩阵中每个元素的大小,即字节数。这个属性等价于Depth属性。

不同通道数、不同深度的Mat对应的数据结构如下面的图示:

 

图2-27 Rows=4、Cols=3、CV8U、单通道Mat数据的结构

 

图2-28 Rows=4、Cols=3、CV8U、三通道Mat数据的结构

 

图2-29 Rows=4、Cols=3、CV32S、三通道Mat的数据结构

2.3.1 构造函数

1、使用行数、列数、深度、通道数初始化Mat

【代码位置:frmChapter2_2_1】Button1_Click、showMatInfo

   '构造函数1:使用行数、列数、深度、通道数初始化Mat

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        '指定行数4、列数3,无符号整数 Byte,通道数1

        Dim m8U1 As New Mat(4, 3, CvEnum.DepthType.Cv8U, 1)

        '将值设置为255

        m8U1.SetTo(New MCvScalar(255))

        '输出Mat信息

        showMatInfo(m8U1, "m8U1")

        TextBox1.Text &= "============" & vbCrLf

        '指定行数4、列数3,无符号整数 Byte,通道数3

        Dim m8U3 As New Mat(4, 3, CvEnum.DepthType.Cv8U, 3)

        m8U3.SetTo(New MCvScalar(200, 100, 0))

        showMatInfo(m8U3, "m8U3")

        TextBox1.Text &= "============" & vbCrLf

        '指定行数4、列数3,无符号整数 Int32,通道数3

        Dim m32S3 As New Mat(4, 3, CvEnum.DepthType.Cv32S, 3)

        m32S3.SetTo(New MCvScalar(200, 100, 0))

        showMatInfo(m32S3, "m32S3")

End Sub

    '此方法输出Mat的信息

    Private Sub showMatInfo(ByVal m As Mat, ByVal strTypeName As String)

        TextBox1.Text &= "strTypeName" & strTypeName & vbCrLf

        TextBox1.Text &= "Cols" & m.Cols & vbCrLf

        TextBox1.Text &= "Rows" & m.Rows & vbCrLf

        TextBox1.Text &= "Depth" & m.Depth & vbCrLf

        TextBox1.Text &= "ElementSize" & m.ElementSize & vbCrLf

        TextBox1.Text &= "Height" & m.Height & vbCrLf

        TextBox1.Text &= "Width" & m.Width & vbCrLf

        TextBox1.Text &= "NumberOfChannels" & m.NumberOfChannels & vbCrLf

        TextBox1.Text &= "Step" & m.Step & vbCrLf

        TextBox1.Text &= "Width*Height" & m.Size.Width & "*" & m.Size.Height & vbCrLf

        TextBox1.Text &= "IsContinuous" & m.IsContinuous & vbCrLf

End Sub

显示结果如下:

 

图2-30 显示Mat信息

2、使用行数、列数、深度、通道数、指向数据的指针、步长初始化Mat

【代码位置:frmChapter2_2_1】Button2_Click、outputMatdata8U1C

    '构造函数2:使用行数、列数、深度、通道数、指向数据的指针、步长 初始化Mat

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

        '包含数据的数组

        Dim buffer() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}

        '定义指针并分配内存空间

        Dim matptr As IntPtr = Marshal.AllocHGlobal(buffer.Length)

        '将数组拷贝到指针对应的内存空间

        Marshal.Copy(buffer, 0, matptr, buffer.Length)

        '指定行数4、列数3,无符号整数 Byte,通道数1,数据,步长3

        Dim m As New Mat(4, 3, CvEnum.DepthType.Cv8U, 1, matptr, 3)

        '显示Mat中元素的值

        Call outputMatdata8U1C(m)

    End Sub

    '输出矩阵中元素的值

    '为简化说明,在此方法中只考虑Cv8U单通道且数据连续的Mat

    Private Sub outputMatdata8U1C(ByVal m As Mat)

        Dim colcount As Integer = m.Cols

        Dim rowcount As Integer = m.Rows

        '获得数组大小

        Dim bufferSize As Integer = m.Step * m.Rows

        '定义数组

        Dim buffer() As Byte

        ReDim buffer(bufferSize 1)

        'Mat的数据指针指向的内存拷贝到数组

        System.Runtime.InteropServices.Marshal.Copy(m.DataPointer, buffer, 0, bufferSize)

        '循环输出每个元素的值

        For row As Integer = 0 To rowcount 1

            For col As Integer = 0 To colcount 1

                TextBox1.Text &= buffer(row * colcount + col) & " "

            Next

            TextBox1.Text &= vbCrLf

        Next

    End Sub

显示结果如下:

 

图2-31 输出Mat元素的值

3、使用图片、色彩模式初始化Mat

其中参数ImreadModes(图像读取模式)枚举可以使用来指定不同的图像读取模式,以读取不同类型的图像。ImreadModes包含以下成员:

  1. Unchanged:不改变深度和通道数,读取原始图像。
  2. GrayScale:将图像转换为单通道灰度图像。
  3. Color:将图像转换为三通道彩色图像。
  4. AnyDepth:读取图像时不限制深度。
  5. AnyColor:读取图像时不限制通道数。
  6. LoadGdal:使用GDAL库读取图像。
  7. ReducedGrayscale2:将图像转换为8位单通道灰度图像。
  8. ReducedColor2:将图像转换为8位三通道彩色图像。
  9. ReducedGrayscale4:将图像转换为4位单通道灰度图像。
  10. ReducedColor4:将图像转换为4位三通道彩色图像。
  11. ReducedGrayscale8:将图像转换为1位单通道灰度图像。
  12. ReducedColor8:将图像转换为1位三通道彩色图像。

【代码位置:frmChapter2_2_1】Button3_Click

    '构造函数3:使用图片、图像读取模式初始化Mat

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click

        '使用三通道彩色图像模式将数据载入Mat

        Dim m1 As New Mat("C:\learnEmgucv\lena.jpg", CvEnum.ImreadModes.Color)

        Call showMatInfo(m1, "彩色图片")

        '使用灰度图像模式将数据载入Mat

        Dim m2 As New Mat("C:\learnEmgucv\lena.jpg", CvEnum.ImreadModes.Grayscale)

        Call showMatInfo(m2, "灰度图片")

End Sub

显示结果如下:

 

图2-32 使用图片初始化Mat

4、无参数的构造函数

下面的代码使用Mat无参数的构造函数,同时通过Matrix给Mat赋值,这也是本教程代码中常用的方式。

【代码位置:frmChapter2_2_1】Button4_Click

    '构造函数4:无任何参数,同时此代码中还使用Matrix赋值给Mat

    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click

        Dim m As New Mat()

        Dim inputBytes(,) As Byte = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}

        Dim matr As New Matrix(Of Byte)(inputBytes)

        '使用Matrix.Mat属性给Mat赋值

        m = matr.Mat

        showMatInfo(m, "MatrixToMat")

End Sub

显示结果如下:

 

图2-33 使用Matrix给Mat赋值

2.3.2 给Mat元素赋值

在【3.2.1 构造函数】中其实已经讲述了如何给Mat元素赋值的方法。这里另外还有一个方法,就是将数组拷贝到Mat数据指针处。

【代码位置:frmChapter2_2_1】Button5_Click

    '将值拷贝到mat

    Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click

        '这里特地少了1个值,方便查看效果

        Dim buffer() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

        Dim m As New Mat(4, 3, CvEnum.DepthType.Cv8U, 1)

        '输出mat元素的值,可以看到值是随机的

        Call outputMatdata8U1C(m)

        TextBox1.Text &= "===============" & vbCrLf

        Dim matptr As IntPtr = m.DataPointer

        '将数组拷贝到指针处

        Marshal.Copy(buffer, 0, matptr, buffer.Length)

        '由于差1个值,所以,Mat中最后一个元素的值仍然是之前的

        Call outputMatdata8U1C(m)

End Sub

显示结果如下:

 

图2-34 使用数组给Mat赋值

2.3.3 读取Mat元素的值

1、读取Cv8U单通道且数据连续的Mat的元素的值,在【3.2.1 构造函数】第二部分代码【outputMatdata8U1C】中已经实现。这里不在累述。

2、读取Cv16U三通道且数据连续的Mat的元素的值,

【代码位置:frmChapter2_2_1】Button6_Click

    '获得Cv16u(即shortInt16)、3通道且连续的Mat元素的值

    Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click

        Dim m As New Mat(4, 3, CvEnum.DepthType.Cv16U, 3)

        '将所有元素设置为(200, 100, 0)

        m.SetTo(New MCvScalar(200, 100, 0))

        '计算数组所占用的内存的大小

        Dim bufferlen As Integer = m.Step * m.Rows / 2

        '因为用的16U,也就是2个字节,对应Short类型

        Dim buffer() As Short

        ReDim buffer(bufferlen 1)

        'Mat的数据指针指向的内存拷贝到数组

        System.Runtime.InteropServices.Marshal.Copy(m.DataPointer, buffer, 0, bufferlen)

        '简单输出,未考虑行列

        For Each b As Short In buffer

            TextBox1.Text &= b & vbCrLf

        Next

End Sub

显示结果如下:

 

图2-35 输出Cv16U三通道Mat元素的值

3、单通道Mat数据拷贝到数组

以下代码中使用到了Mat的CopyTo方法。

【代码位置:frmChapter2_2_1】Button7_Click

    '单通道mat数据拷贝到数组

    Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click

        Dim m As New Mat()

        Dim matr As New Matrix(Of Byte)(New Byte(,) {{0, 220, 0}, {30, 140, 199}, {80, 220, 7}, {65, 42, 190}})

        m = matr.Mat

        Dim b() As Byte

        ReDim b(m.Cols * m.Rows 1)

        '使用CopyTo方法将Mat中的元素的值拷贝到数组

        m.CopyTo(b)

        '输出数组中的值

        For i As Integer = 0 To b.Length 1

            TextBox1.Text &= b(i) & vbCrLf

        Next

End Sub

显示结果如下:

 

图2-36 单通道Mat元素的值输出到数组

4、三通道Mat数据拷贝到数组

【代码位置:frmChapter2_2_1】Button8_Click

    '三通道mat数据拷贝到数组

    Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click

        Dim m As New Mat(4, 3, CvEnum.DepthType.Cv8U, 3)

        m.SetTo(New MCvScalar(200, 100, 0))

        Dim b() As Byte

        ReDim b(m.Cols * m.Rows * m.NumberOfChannels 1)

        '使用CopyTo方法将Mat中的元素的值拷贝到数组

        m.CopyTo(b)

        '输出数组中的值

        For i As Integer = 0 To b.Length 1

            TextBox1.Text &= b(i) & vbCrLf

        Next

End Sub

显示结果如下:

 

图2-37 三通道Mat元素的值输出到数组

2.3.4 修改Mat元素的值

【代码位置:frmChapter2_2_1】Button9_Click

    '修改Mat中的数值

    Private Sub Button9_Click(sender As Object, e As EventArgs) Handles Button9.Click

        Dim m As New Mat(4, 3, CvEnum.DepthType.Cv8U, 1)

        m.SetTo(New MCvScalar(255))

        TextBox1.Text &= "修改前的矩阵:" & vbCrLf

        Call outputMatdata8U1C(m)

        '需要修改的行列元素的值

        Dim row As Integer

        Dim col As Integer

        '修改行序号0,列序号0位置元素(如果将二维数组拉通排列,序号0的元素)的值

        row = 0

        col = 0

        Dim ptr1 As IntPtr = m.DataPointer

        ptr1 += row * 3 + col

        Dim newvalue(0) As Byte

        newvalue(0) = 100

        System.Runtime.InteropServices.Marshal.Copy(newvalue, 0, ptr1, 1)

        '修改行序号1,列序号1位置元素(如果将二维数组拉通排列,序号4的元素)的值

        row = 1

        col = 1

        Dim ptr2 As IntPtr = m.DataPointer

        ptr2 += row * 3 + col

        newvalue(0) = 200

        System.Runtime.InteropServices.Marshal.Copy(newvalue, 0, ptr2, 1)

        TextBox1.Text &= vbCrLf & "修改后的矩阵:" & vbCrLf

        Call outputMatdata8U1C(m)

End Sub

显示结果如下,可以看到(0,0)和(1,1)位置的元素已经被修改:

 

图2-38 修改Mat元素的值

2.3.5 Mat的克隆

使用Mat的Clone方法来实现对一个Mat的完全复制。

以下代码测试,说明修改克隆后的Mat对源Mat不产生影响。

【代码位置:frmChapter2_2_1】Button10_Click

    'clone,不会影响源Mat

    Private Sub Button10_Click(sender As Object, e As EventArgs) Handles Button10.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {3, 3, 3}})

        m1 = matr1.Mat

        Call outputMatdata8U1C(m1)

        TextBox1.Text &= "===============" & vbCrLf

        Dim m2 As New Mat

        m2 = m1.Clone

        Call outputMatdata8U1C(m2)

        TextBox1.Text &= "===============" & vbCrLf

        '需要修改的行列元素的值

        Dim row As Integer

        Dim col As Integer

        '修改行序号0,列序号0位置元素(如果将二维数组拉通排列,序号0的元素)的值

        row = 0

        col = 0

        Dim ptr1 As IntPtr = m2.DataPointer

        ptr1 += row * 3 + col

        Dim newvalue(0) As Byte

        newvalue(0) = 100

        System.Runtime.InteropServices.Marshal.Copy(newvalue, 0, ptr1, 1)

        Call outputMatdata8U1C(m2)

        TextBox1.Text &= "===============" & vbCrLf

        Call outputMatdata8U1C(m1)

End Sub

显示结果如下,可以看到(0,0)和(1,1)位置的元素已经被修改:

 

图2-39 克隆Mat修改后不会影响源Mat

作为对比,请将上述代码中的

m2 = m1.Clone

修改为

m2 = m1

【代码位置:frmChapter2_2_1】Button11_Click

    '使用=赋值,会影响源Mat

    Private Sub Button11_Click(sender As Object, e As EventArgs) Handles Button11.Click

        ……

        '修改Button10_Click中此处的代码:

        m2 = m1

        ……

End Sub

显示结果如下,可以看到(0,0)和(1,1)位置的元素已经被修改:

 

图2-40  赋值并修改后会影响源Mat

2.3.6 获得子Mat

以下代码使用Mat的构造函数方法之一,源Mat和矩形(Rectangle)作为参数,生成一个子Mat。测试修改子Mat中元素的值,源Mat也会对应改变。

【代码位置:frmChapter2_2_1】Button12_Click、outputMatdata8U1CAfter

outputMatdata8U1Cafter作用是输出数据不连续的Mat的值。

   '不连续的子矩阵

    Private Sub Button12_Click(sender As Object, e As EventArgs) Handles Button12.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}})

        m1 = matr1.Mat

        Call outputMatdata8U1C(m1)

        TextBox1.Text &= "===============" & vbCrLf

        'm2实际和m1指向的内存空间位置相同,m2修改会影响m1

        '原始视图 DataPointer,与m1相比较,指针位置多了4

        'IsContinuous属性(数据是否连续)为False

        '实际值查看在:原始视图-非公共成员-bytes

        Dim m2 As New Mat(m1, New Rectangle(1, 1, 2, 2))

        TextBox1.Text &= "输出连续数据" & vbCrLf

        Call outputMatdata8U1C(m2)

        TextBox1.Text &= "===============" & vbCrLf

        TextBox1.Text &= "输出不连续数据" & vbCrLf

        Call outputMatdata8U1CAfter(m2)

        TextBox1.Text &= "===============" & vbCrLf

        '需要修改的行列元素的值

        Dim row As Integer

        Dim col As Integer

        '修改行序号0,列序号0位置元素(如果将二维数组拉通排列,序号0的元素)的值

        row = 0

        col = 0

        Dim ptr1 As IntPtr = m2.DataPointer

        ptr1 += row * 3 + col

        Dim newvalue(0) As Byte

        newvalue(0) = 100

        System.Runtime.InteropServices.Marshal.Copy(newvalue, 0, ptr1, 1)

        Call outputMatdata8U1CAfter(m2)

        TextBox1.Text &= "===============" & vbCrLf

        '再次输出m1,可以看到修改m2中元素的之后,m1对应元素的值也变化了

        Call outputMatdata8U1CAfter(m1)

    End Sub

    'outputMatdata8U1C方法进行修改,修改后的方法考虑数据不连续的情况

    '为简化说明,这里仍然使用8U单通道Mat

    Private Sub outputMatdata8U1CAfter(ByVal m As Mat)

        Dim colcount As Integer = m.Cols

        Dim rowcount As Integer = m.Rows

        Dim matstep As Integer = m.Step

        '每次读取数据时候的指针位置

        Dim pos As IntPtr = IntPtr.Zero

        For i As Integer = 0 To rowcount 1

            '检查指针位置,

            '如果是第一次循环,即pos初始为0,那么指针位置为mat的指针位置

            '否则,应该将指针位置增加step

            If pos = IntPtr.Zero Then

                pos = m.DataPointer

            Else

                pos += matstep

            End If

            Dim bufferSize As Integer = colcount

            Dim buffer() As Byte

            ReDim buffer(bufferSize 1)

            '每次循环从新的指针位置拷贝数据,拷贝的数量为mat的列数。

            System.Runtime.InteropServices.Marshal.Copy(pos, buffer, 0, bufferSize)

            For col As Integer = 0 To colcount 1

                TextBox1.Text &= buffer(col) & " "

            Next

            TextBox1.Text &= vbCrLf

        Next

End Sub

显示结果如下:

 

图2-41 生成子矩阵并修改后与原矩阵对比

2.3.7 修改Mat的深度

以下代码使用Mat的ConvertTo方法将Mat的深度从Cv8U修改到Cv16U

【代码位置:frmChapter2_2_1】Button13_Click

    '更改matDepthType

    Private Sub Button13_Click(sender As Object, e As EventArgs) Handles Button13.Click

        Dim m As New Mat(4, 3, CvEnum.DepthType.Cv8U, 3)

        m.SetTo(New MCvScalar(200, 100, 0))

        '输出Mat信息

        showMatInfo(m, "m8U3")

        TextBox1.Text &= "============" & vbCrLf

        Dim mOut As New Mat

        m.ConvertTo(m, CvEnum.DepthType.Cv16U)

        '输出Mat信息

        showMatInfo(m, "m16U3")

        TextBox1.Text &= "============" & vbCrLf

End Sub

显示结果如下:

 

图2-42 修改深度后的矩阵与原矩阵对比

2.3.8 最大值和最小值

Mat使用MinMax方法来获得最大值和最小值及对应坐标。使用方式和Matrix相同。

【代码位置:frmChapter2_2_1】Button14_Click

    '最大最小值以及对应坐标位置

    Private Sub Button14_Click(sender As Object, e As EventArgs) Handles Button14.Click

        Dim m As New Mat()

        Dim matr As New Matrix(Of Byte)(New Byte(,) {{0, 220, 0}, {30, 140, 199}, {80, 220, 7}, {65, 42, 190}})

        m = matr.Mat

        Dim maxvalues() As Double

        Dim minvalues() As Double

        Dim maxposes() As Point

        Dim minposes() As Point

        '只能查找每个通道的最大值和最小值,而不是查找每个通道的所有最大值和最小值

        '最大值和最小值的位置,也只是返回最先的那个。

        m.MinMax(minvalues, maxvalues, minposes, maxposes)

        TextBox1.Text &= "最小值:" & minvalues(0) & " 位置:" & minposes(0).X & "," & minposes(0).Y & vbCrLf

        TextBox1.Text &= "最大值:" & maxvalues(0) & " 位置:" & maxposes(0).X & "," & maxposes(0).Y

End Sub

显示结果如下:

 

图2-43 获得Mat元素最大最小值

2.3.9 Mat的运算

2.3.9.1 加法

【代码位置:frmChapter2_2_1】Button15_Click

   '加法

    Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 220, 0}, {30, 140, 225}, {80, 200, 7}, {65, 42, 190}})

        m1 = matr1.Mat

        Dim m2 As New Mat()

        Dim matr2 As New Matrix(Of Byte)(New Byte(,) {{50, 40, 220}, {130, 16, 80}, {95, 221, 229}, {17, 3, 22}})

        m2 = matr2.Mat

        Dim mout As New Mat

        '方法1

        mout = m1 + m2

        '方法2

        'CvInvoke.Add(m1, m2, mout)

        Call outputMatdata8U1C(mout)

End Sub

显示结果如下:

 

图2-44 Mat的加法

2.3.9.2 减法

【代码位置:frmChapter2_2_1】Button16_Click

    '减法

    Private Sub Button16_Click(sender As Object, e As EventArgs) Handles Button16.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 220, 0}, {30, 140, 225}, {80, 200, 7}, {65, 42, 190}})

        m1 = matr1.Mat

        Dim m2 As New Mat()

        Dim matr2 As New Matrix(Of Byte)(New Byte(,) {{50, 40, 220}, {130, 16, 80}, {95, 221, 229}, {17, 3, 22}})

        m2 = matr2.Mat

        Dim mout As New Mat

        '方法1:直接相减,对于小于0的值设置为0

        mout = m1 m2

        '方法2:使用 CvInvoke.AbsDiff,与直接相减有所不同,小于0的值将取绝对值

        'CvInvoke.AbsDiff(m1, m2, mout)

        Call outputMatdata8U1C(mout)

End Sub

使用上述方法,应注意直接相减和使用AbsDiff函数的区别。

显示结果如下:

 

图2-45 Mat的减法

2.3.9.3 乘法

【代码位置:frmChapter2_2_1】Button17_Click

    '乘法

    Private Sub Button17_Click(sender As Object, e As EventArgs) Handles Button17.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}})

        m1 = matr1.Mat

        '矩阵乘以一个数值

        Dim mout1 As New Mat

        mout1 = m1 * 2

        Call outputMatdata8U1C(mout1)

        TextBox1.Text &= "===============" & vbCrLf

        '两个矩阵相乘,大小必须相同

        Dim m2 As New Mat()

        Dim matr2 As New Matrix(Of Byte)(New Byte(,) {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}})

        m2 = matr2.Mat

        '对应元素相乘,不同于一般的矩阵相乘

        Dim mout2 As New Mat

        CvInvoke.Multiply(m1, m2, mout2)

        Call outputMatdata8U1C(mout2)

End Sub

显示结果如下:

 

图2-45 Mat的乘法

2.3.9.4 除法

【代码位置:frmChapter2_2_1】Button18_Click

   '除法

    Private Sub Button18_Click(sender As Object, e As EventArgs) Handles Button18.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 21, 112}, {21, 36, 55}, {24, 77, 24}, {90, 210, 121}})

        m1 = matr1.Mat

        '矩阵除以一个数值

        Dim mout1 As New Mat

        mout1 = m1 / 2

        Call outputMatdata8U1C(mout1)

        TextBox1.Text &= "===============" & vbCrLf

        '两个矩阵相除,大小必须相同

        Dim m2 As New Mat()

        Dim matr2 As New Matrix(Of Byte)(New Byte(,) {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}})

        m2 = matr2.Mat

        '对应元素相除,不同于一般的矩阵相除

        Dim mout2 As New Mat(m1.Size, DepthType.Cv8U, 1)

        CvInvoke.Divide(m1, m2, mout2)

        Call outputMatdata8U1C(mout2)

End Sub

显示结果如下:

 

图2-46 Mat的除法

注意:如果相除的矩阵元素类型是整型,不论被除数还是除数为0,都将会返回0。如果相除的矩阵元素类型是浮点型,被除数不为0,除数为0,那么将返回∞(无穷大);被除数为0,且除数为0,那么将返回NaN。下面的代码演示了使用0作为被除数时的输出结果,其中outputMatdata64F1C函数输出64位浮点值类型Mat的元素的值。

【代码位置:frmChapter2_2_1】Button19_Click、outputMatdata64F1C

  '除法

    Private Sub Button19_Click(sender As Object, e As EventArgs) Handles Button19.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Double)(New Double(,) {{9, 0, 0}, {22, 33, 55}, {24, 23, 24}, {90, 87, 121}})

        m1 = matr1.Mat

        '两个矩阵相除,大小必须相同

        Dim m2 As New Mat()

        Dim matr2 As New Matrix(Of Double)(New Double(,) {{0, 0, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}})

        m2 = matr2.Mat

        '对应元素相除,不同于一般的矩阵相除

        Dim mout As New Mat(m1.Size, DepthType.Cv64F, 1)

        CvInvoke.Divide(m1, m2, mout)

        Call outputMatdata64F1C(mout)

    End Sub

    '输出64位浮点值类型Mat的元素的值

    Private Sub outputMatdata64F1C(ByVal m As Mat)

        Dim colcount As Integer = m.Cols

        Dim rowcount As Integer = m.Rows

        '获得数组大小

        Dim bufferSize As Integer = m.Step * m.Rows

        '定义数组

        Dim buffer() As Byte

        ReDim buffer(bufferSize 1)

        'Mat的数据指针指向的内存拷贝到数组

        System.Runtime.InteropServices.Marshal.Copy(m.DataPointer, buffer, 0, bufferSize)

        '注意Double类型占用8个字节

        Dim bteOutDouble(7) As Byte

        For i As Integer = 0 To buffer.Length 1 Step 8

            For j As Integer = 0 To 7

                bteOutDouble(j) = buffer(i + j)

            Next

            '这里使用了BitConverter.ToDouble将字节数组转Double

            Dim outDouble As Double = BitConverter.ToDouble(bteOutDouble, 0)

            TextBox1.Text &= outDouble.ToString & vbCrLf

        Next

End Sub

显示结果如下:

 

图2-48 Mat浮点类型的除法

可以看到输出的前三个值分别为:∞、NaN、0

2.3.9.5 And运算

【代码位置:frmChapter2_2_1】Button20_Click

    'And运算

    Private Sub Button20_Click(sender As Object, e As EventArgs) Handles Button20.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {3, 3, 3}})

        m1 = matr1.Mat

        Dim m2 As New Mat()

        Dim matr2 As New Matrix(Of Byte)(New Byte(,) {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}})

        m2 = matr2.Mat

        Dim mout As New Mat

        '方法1

        mout = m1 And m2

        '方法2

        'CvInvoke.BitwiseAnd(m1, m2, mout)

        Call outputMatdata8U1C(mout)

End Sub

显示结果如下:

 

图2-48 Mat的And运算

2.3.9.6 Or运算

【代码位置:frmChapter2_2_1】Button21_Click

   'Or运算

    Private Sub Button21_Click(sender As Object, e As EventArgs) Handles Button21.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {3, 3, 3}})

        m1 = matr1.Mat

        Dim m2 As New Mat()

        Dim matr2 As New Matrix(Of Byte)(New Byte(,) {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}})

        m2 = matr2.Mat

        Dim mout As New Mat

        '方法1

        mout = m1 Or m2

        '方法2

        'CvInvoke.BitwiseOr(m1, m2, mout)

        Call outputMatdata8U1C(mout)

End Sub

显示结果如下:

 

图2-49 Mat的Or运算

2.3.9.7 Xor运算

【代码位置:frmChapter2_2_1】Button22_Click

    'xor运算

    Private Sub Button22_Click(sender As Object, e As EventArgs) Handles Button22.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {3, 3, 3}})

        m1 = matr1.Mat

        Dim m2 As New Mat()

        Dim matr2 As New Matrix(Of Byte)(New Byte(,) {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}})

        m2 = matr2.Mat

        Dim mout As New Mat

        'Mat没有Xor方法,直接使用xor是错误的

        'mout = m1 Xor m2

        CvInvoke.BitwiseXor(m1, m2, mout)

        Call outputMatdata8U1C(mout)

End Sub

显示结果如下:

 

图2-50 Mat的Xor运算

2.3.9.8 Not运算

【代码位置:frmChapter2_2_1】Button23_Click

    'not运算

    Private Sub Button23_Click(sender As Object, e As EventArgs) Handles Button23.Click

        Dim m1 As New Mat()

        Dim matr1 As New Matrix(Of Byte)(New Byte(,) {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}})

        m1 = matr1.Mat

        Dim mout As New Mat

        '方法1

        mout = Not m1

        '方法2

        'CvInvoke.BitwiseNot(m1, mout)

        Call outputMatdata8U1C(mout)

End Sub

显示结果如下:

 

图2-51 Mat的Not运算

2.3.10 载入并显示图像

在【2.3.1 构造函数】中讲述过使用Mat载入图片,但是未进行显示。以下代码将显示Lena的彩色图像和灰度图像,请在窗体上放置2个ImageBox控件。ImageBox控件也是在Vs的【工具箱】|【Emgu.CV】下面。

【代码位置:frmChapter2_2_2】Button1_Click

    '载入并显示图片

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        '彩色图片

        Dim m1 As New Mat("C:\learnEmgucv\lena.jpg", CvEnum.ImreadModes.Color)

        ImageBox1.Image = m1

        '灰度图片

        Dim m2 As New Mat("C:\learnEmgucv\lena.jpg", CvEnum.ImreadModes.Grayscale)

        ImageBox2.Image = m2

End Sub

显示结果如下:

 

图2-52 图像显示

可以将图像简单理解为包含了很多像素点的矩阵,也就对应了Mat这个矩阵。

2.3.11 图像通道的分离与合并

图像通道的分离,使用Mat的Split方法,将多通道图像按照通道分别存入一个Mat数组。

图像通道的合并,使用 CvInvoke的Merge方法,将多个单通道图像合并成一个多通道图像。Merge方法的语法如下:

Public Shared Sub Merge(src As VectorOfMat, dst As Mat)

需要注意的是,要合并的单通道Mat对象必须有相同的行数、列数和深度类型。合并后的多通道Mat对象的通道数等于要合并的单通道Mat对象的数量。

在进行分离和合并的时候,需要使用到VectorOfMat类型。VectorOf~直译为向量,可以简单理解为类似于数组或者集合,用来表示不定长度数组,可以通过索引来获得里面指定的元素。例如:VectorOfMat理解为多个Mat的数组,VectorOfPoint理解为多个点的数组。在EmguCV中还定义有VectorOfRect、VectorOfFloat、VectorOfTriangle2DF等等,特别是还会有VectorOfVectorOf~,表示数组的数组,例如在后面处理图像轮廓时会用到VectorOfVectorOfPoint,表示多个点的数组然后又做了个数组。

VectorOf~通过Push方法向数组中增加元素。VectorOfMat中使用Push,也就是增加通道,但需要注意,如果要显示合并后的图像,图像必须有正确的通道数,如,不能有2通道的图像。

在以下代码中可以看到上述方法和类型的用法。

【代码位置:frmChapter2_2_2】Button2_Click

   'Mat按照通道分离,然后合并

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

        Dim m As New Mat("C:\learnEmgucv\lena.jpg", CvEnum.ImreadModes.Color)

        Dim mDst() As Mat

        '按通道数分离

        mDst = m.Split()

        '显示0号通道,即蓝色(B)通道

        ImageBox1.Image = mDst(0)

        '011BGG通道合并成新的图像

        Dim vm As New VectorOfMat

        vm.Push(mDst(0))

        vm.Push(mDst(1))

        vm.Push(mDst(1))

        Dim mDstMerge As New Mat

        CvInvoke.Merge(vm, mDstMerge)

        ImageBox2.Image = mDstMerge

End Sub

显示结果如下:

图2-53 图像通道的分离与合并

在以下代码中加入了一个自定义的通道,最后把图像显示出来。

【代码位置:frmChapter2_2_2】Button3_Click

    'Mat按照通道分离,然后组合,更多的效果

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click

        Dim m As New Mat("C:\learnEmgucv\lena.jpg", CvEnum.ImreadModes.Color)

        '显示源图像

        ImageBox1.Image = m

        Dim mDst() As Mat

        '按通道数分离

        mDst = m.Split()

        '011BGG通道组合成新的图像

        Dim vm As New VectorOfMat

        vm.Push(mDst(0))

        vm.Push(mDst(1))

        '设置第三个通道,元素的值都为0

        Dim m2 As New Mat(m.Size, CvEnum.DepthType.Cv8U, 1)

        m2.SetTo(New MCvScalar(0))

        vm.Push(m2)

        Dim mDstMerge As New Mat

        CvInvoke.Merge(vm, mDstMerge)

        ImageBox2.Image = mDstMerge

End Sub

显示结果如下:

 

图2-54 图像通道的分离与合并之二

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

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

相关文章

StackStorm自动化平台

1. StackStorm概述 1.1 StackStorm介绍 StackStorm是一个开源的事件驱动自动化平台,它允许开发者和系统管理员自动化IT和网络操作。StackStorm结合了IT运维、DevOps和网络安全团队的需求,提供了一个集中式的工作流自动化解决方案,包括事件响…

Windows10、ARM开发板、虚拟机Ubuntu可同时上网

一、Windows10端设置 1、打开网络配置 2、打开适配器 3、将window连接的wifi网卡设置为共享模式 4、查看本地连接的ip 到此,window10端设置完毕 二、设置虚拟机端(Ubuntu) 1、打开网络配置 2、打开适配器 3、查看本地连接的网卡名称 4、配置…

超越流水线,企业研发规范落地新思路

作者:子丑 内容大纲: 1、研发规范≠流程约束 2、自动化工具→研发规范载体 3、研发规范在工具上的落地示例 4、研发规范的选型方法与常见实践 研发规范≠流程约束 这个故事特别适合研发规范的场景,我们要避免成为把猫绑在柱子上的信众…

[NOIP2007 普及组] 守望者的逃离 题解

题意 给定 M ( 0 ≤ M ≤ 1 0 3 ) , S ( 1 ≤ S ≤ 1 0 8 ) , T ( 1 ≤ T ≤ 3 1 0 5 ) M(0 \leq M \leq 10^3),S(1 \leq S \leq 10^8),T(1 \leq T \leq 3\times 10^5) M(0≤M≤103),S(1≤S≤108),T(1≤T≤3105),守望者开始在位置 0 0 0,对于每一秒&…

C++调用C#方法(附踩坑点)

C调用C#方法 写在前面效果思路步骤可能的问题 写在后面 写在前面 工作需要用C调用C#写到代码,看来网上写的方法,自己也踩了一些坑,这里总结一下,我只试了CLR的方法。 主要参考了下面几篇博客 C调用C#库简单例程(Lucky…

【BUU】[NewStarCTF 2023 公开赛道]Final -CP读取文件内容

漏洞检测 访问首页发现是ThinkPHP5 的站点 用工具扫描一下,发现存在ThinkPHP5.0.23 RCE漏洞 访问验证,写入shell 成功写入shell. 根目录发现flag,但是权限不足 提权获取flag 准备提权,这里一开始尝试了find,但是find权限不足 尝试采用cp命令,移动到web目录,发现访问还是…

MySQL InnoDB中一个update语句从执行到提交的全过程(3)

接上文MySQL InnoDB中一个update语句从执行到提交的全过程(2)-CSDN博客 目录 六、本地提交 怎样保证binlog和redo log的状态一致呢? MySQL 中的内部 XA 机制 宕机时不同状态的处理 物理落盘策略 七、主备复制 八、返回提交成功 总结一…

Windows 10/11和Linux双系统用户请勿安装最新更新 否则将无法启动

据蓝点网报道,Windows 10/11 最新累积更新存在已知问题,如果你同时安装了 Linux 双系统则会在更新后导致系统无法正常启动。 启动时会出现如下报错: Verifiying shim SBAT data failed: Security Policy Violation.Something has gone serio…

私域场景中的数字化营销秘诀

​在当今的商业世界,私域场景的营销变得愈发重要。今天咱们就来深入探讨一下私域场景中的几个关键营销手段。 一、会员管理与营销 企业一旦拥有完善的会员体系,数字化手段就能大放异彩。它可以助力企业对会员进行精细划分,深度了解会员的消费…

win11笔记本电脑 声音输出设置为扬声器 | 添加蓝牙设备 | win11环境变量设置

🥇 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 🎉 声明: 作为全网 AI 领域 干货最多的博主之一,❤️ 不负光阴不负卿 ❤️ 文章目录 win11笔记本电脑 声音输出设置为扬声器搜索设置,打开设置选择声音选…

AI安全-文生图

1 需求 2 接口 3 示例 大模型图像安全风险探析 - 先知社区 前言 文生图模型是一种新兴的人工智能技术,它通过对大规模文本数据的学习,能够生成逼真的图像。这种模型包含两个主要组件:一个文本编码器和一个图像生成器。 文本编码器接收文本输入,并将其转换为一种数字化的表示…

Idea开发代码注释规范

规范 类注释:每个类都应该有一个简短的注释,描述这个类的用途和主要功能。注释应该放在类的声明之前,使用JavaDoc格式。 /*** 这是一个示例类,用于演示如何编写类注释。*/ public class ExampleClass {// ... }方法注释&#xf…

【Oracle点滴积累】解决PrereqSession failed: RawInventory gets null OracleHomeInfo故障的方法

广告位招租! 知识无价,人有情,无偿分享知识,希望本条信息对你有用! 今天和大家分享在安装Oracle Critical Patch Update (Patch Number:33806138) 遇到PrereqSession failed: RawInventory gets null OracleHomeInfo故…

github官网在线通过vscode编辑器模式查看编辑代码

文章目录 背景步骤关于快捷键话外 背景 今天新发现的一个小玩意儿 步骤 在github项目主页(我尝试了无痕模式不行) 按键盘的.这个按键,就是m右边2个,然后就会打开这个网站 github.dev/xxx 首次进入的时候,会像首次…

IDEA系列(四):IDEA导入Maven工程项目并配置Tomcat启动

IDEA系列(四):IDEA导入Maven工程项目并配置Tomcat启动 前言 【本篇使用IDEA版本:大概2020版本,较早了,不过版本大体一致】【若需要码,请扫描关注编程D艺术,回复idea2024,获取码使你的IDEA更加方…

Arm-v8/v9虚拟化原理---aarch64_virtualization_guide

一、相关参考(请仅参考,任意一篇足矣) 1.https://www.cnblogs.com/LoyenWang/p/13584020.html 2.https://zhuanlan.zhihu.com/p/470045640 3.万字剖析 Armv8 架构虚拟化-腾讯云开发者社区-腾讯云 4.https://zhuanlan.zhihu.com/p/5290842…

Docker——常用命令

1.Docker是做什么的? Docker 是一个开源的应用容器引擎,它让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。它可以帮助我们下载应用镜像,创建并运行镜…

SSM宠物领养系统-计算机毕设定制-附项目源码(可白嫖)55139

目 录 摘要 1 绪论 1.1 意义 1.2国内外研究现状 1.3ssm框架 1.4Vue.js 主要功能 1.4论文结构与章节安排 2 2 宠物领养系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3数据删除流程 2.3 系统功能分析 2.3.1功能性分析…

泰坦尼克号 - 从灾难中学习机器学习/Titanic - Machine Learning from Disaster(kaggle竞赛)第一集(了解赛题)

此次目的: 准备出几期博客来记录我学习kaggle数据科学入门竞赛的过程,顺便也将其中所学习到的知识分享出来。这是第一集(了解赛题),后面还会更新更详尽的代码和讲解等。(所学主要的内容来自与b站大学恩师“…

从数据分析到智能生产:AI在工业中的应用与未来

导语 | 人工智能技术的迅猛发展,正在引领第四次工业革命悄然而至。尽管 AI 技术在工业领域的部署仍有诸多难题亟待解决,但这并不能阻挡历史趋势的车轮滚滚向前,AI 正在为工业领域带来新的变革。今天,我们特邀了上海腾展长融董事 &…