当前位置: 首页 > news >正文

EmguCV学习笔记 VB.Net 6.3 轮廓外接多边形

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

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.3 轮廓外接多边形

6.3.1 最大外接矩形BoundingRectangle 

CvInvoke.BoundingRectangle方法用于获得轮廓的最大外接矩形。该方法其中一个声明:

Public Shared Function BoundingRectangle(points As Emgu.CV.IInputArray) As System.Drawing.Rectangle

参数说明:

  1. points:要计算最大外接矩形的轮廓。这是一个VectorOfPoint类型。对应使用FindContours方法获得的contours所包含的成员。

返回值:

返回一个Rectangle对象,表示计算得到的最大矩形的位置和大小。

代码参看6.3.2节【minAreaRect】中的示例。

6.3.2 最小外接矩形minAreaRect

在Emgu.CV中,CvInvoke.MinAreaRect函数用于计算轮廓的最小外接矩形。它的用法如下:

Public Shared Function MinAreaRect(points As Emgu.CV.IInputArray) As Emgu.CV.Structure.RotatedRect

参数说明:

  1. points:要计算最大外接矩形的轮廓。这是一个VectorOfPoint类型。对应使用FindContours方法获得的contours所包含的成员。

返回值:

返回一个RotatedRect对象,表示计算得到的最小外接矩形。通过RotatedRect的GetVertices方法返回四个顶点,然后可使用CvInvoke.Polylines绘制。

【代码位置:frmChapter6】Button8_Click

    '外接多边形:最大外接矩形 最小外接矩形

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

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

        '转灰度

        Dim mgray As New Mat

        CvInvoke.CvtColor(msrc, mgray, ColorConversion.Bgr2Gray)

        '二值化

        Dim mid As New Mat

        CvInvoke.Threshold(mgray, mid, 150, 255, ThresholdType.BinaryInv)

        Dim contours As New VectorOfVectorOfPoint

        Dim hierarchy As New VectorOfRect

        '获得轮廓

        CvInvoke.FindContours(mid, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple)

        '绘制最大外接矩形的图像

        Dim mmax As New Mat

        mmax = msrc.Clone()

        '绘制最小外接矩形的图像

        Dim mmin As New Mat

        mmin = msrc.Clone()

        For i As Integer = 0 To contours.Size - 1

            '获得最大外接矩形

            Dim rectmax As Rectangle = CvInvoke.BoundingRectangle(contours(i))

            CvInvoke.Rectangle(mmax, rectmax, New MCvScalar(255), 2)

            '获得最小外接矩形

            Dim rectmin As RotatedRect = CvInvoke.MinAreaRect(contours(i))

            Dim pf() As PointF = rectmin.GetVertices()

            '实现数组PointF到数组Point的转换

            Dim pf1() As Point = Array.ConvertAll(pf, New Converter(Of PointF, Point)AddressOf PointFToPoint))

            '不能按照矩形绘制,只能绘制多边形

            CvInvoke.Polylines(mmin, pf1, True, New MCvScalar(255, 0, 0), 2)

        Next

        ImageBox2.Image = mmax

        ImageBox3.Image = mmin

End Sub

运行后如下图所示:

图6-9 绘制轮廓的最大外接矩形和最小外接矩形

【代码位置:frmChapter6】Button9_Click

    '外接多边形:最大外接矩形 最小外接矩形

    'Image来代替mat完成最后的绘制

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

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

        ImageBox1.Image = m1

        Dim mid1 As New Mat

        CvInvoke.Threshold(m1, mid1, 150, 255, ThresholdType.BinaryInv)

        Dim contours As New VectorOfVectorOfPoint

        Dim hierarchy As New VectorOfRect

        CvInvoke.FindContours(mid1, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple)

        Dim m2 As New Image(Of Bgr, Byte)("C:\learnEmgucv\shape2.jpg")

        '最大外接矩形

        Dim mmax As New Image(Of Bgr, Byte)(m2.Width, m2.Height)

        mmax = m2.Clone()

        '最小外接矩形

        Dim mmin As New Image(Of Bgr, Byte)(m2.Width, m2.Height)

        mmin = m2.Clone()

        For i As Integer = 0 To contours.Size - 1

            '最大外接矩形

            Dim rectmax As Rectangle = CvInvoke.BoundingRectangle(contours(i))

            mmax.Draw(rectmax, New Bgr(0, 255, 0), 2)

            '或者以下代码:

            'CvInvoke.Rectangle(mmax, rectmax, New MCvScalar(255), 2)

            Dim rectmin As RotatedRect = CvInvoke.MinAreaRect(contours(i))

            mmin.Draw(rectmin, New Bgr(0, 255, 0), 2)

            '或者以下代码:

            'Dim pf() As PointF = rectmin.GetVertices()

            'Dim pf1() As Point = Array.ConvertAll(pf, New Converter(Of PointF, Point)AddressOf PointFToPoint))

            'CvInvoke.Polylines(mmin, pf1, True, New MCvScalar(255, 0, 0), 2)

        Next

        ImageBox2.Image = mmax

        ImageBox3.Image = mmin

End Sub

运行后如下图所示:

图6-10 绘制轮廓的最大外接矩形和最小外接矩形

6.3.3 多边形逼近ApproxPolyDP       

CvInvoke.ApproxPolyDP方法用于对轮廓进行多边形逼近。声明如下:

Public Shared Sub ApproxPolyDP(curve As Emgu.CV.IInputArray, approxCurve As Emgu.CV.IOutputArray, epsilon As Double, closed As Boolean)

参数说明:

  1. curve:要进行逼近的轮廓。这是一个VectorOfPoint类型。对应使用FindContours方法获得的contours所包含的成员。
  2. approxCurve:输出逼近后的多边形曲线。
  3. epsilon:逼近精度,即逼近后的多边形曲线与原轮廓的最大距离。
  4. closed:表示逼近后的多边形曲线是否是闭合的。如果为True,表示闭合;如果为False,表示开放。

【代码位置:frmChapter6】Button10_Click

   '外接多边形

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

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

        ImageBox1.Image = msrc

        Dim mid1 As New Mat

        CvInvoke.Threshold(msrc, 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 mpoly As New Mat(msrc.Size, DepthType.Cv8U, 3)

        mpoly.SetTo(New MCvScalar(255, 255, 255))

        For i As Integer = 0 To contours.Size - 1

            Dim result As New VectorOfPoint

            '获得逼近后的多边形曲线

            CvInvoke.ApproxPolyDP(contours(i), result, 4, True)

            Dim p() As Point

            p = result.ToArray

            '绘制多边形

            CvInvoke.Polylines(mpoly, p, True, New MCvScalar(255, 0, 0), 2)

            '输出多边形的边数

            CvInvoke.PutText(mpoly, p.Length, New Point(p(p.Length - 1).X - 20, p(p.Length - 1).Y), FontFace.HersheyComplex, 1, New MCvScalar(0, 0, 255), 1)

        Next

        ImageBox3.Image = mpoly

End Sub

运行后如下图所示:

图6-11 绘制轮廓外接多边形

6.3.4 最小外接圆MinEnclosingCircle

CvInvoke.MinEnclosingCircle方法用于计算轮廓的最小外接圆。它的声明之一:

Public Shared Function MinEnclosingCircle(points As Emgu.CV.IInputArray) As Emgu.CV.Structure.CircleF

示例参看6.3.6节 【FitEllipse】代码。

6.3.5 最小外接三角形MinEnclosingTriangle

CvInvoke.MinEnclosingTriangle方法用于计算轮廓的最小外接三角形。它的声明如下:

Public Shared Function MinEnclosingTriangle(points As Emgu.CV.IInputArray, triangles As Emgu.CV.IOutputArray) As Double

示例参看6.3.6节 【FitEllipse】代码。

6.3.6 拟合椭圆FitEllipse     

CvInvoke.FitEllipse方法用于拟合给定点集的椭圆。它的声明如下:

Public Shared Function FitEllipse(points As Emgu.CV.IInputArray) As Emgu.CV.Structure.RotatedRect

【代码位置:frmChapter6】Button11_Click

    '最小外接三角形、最小外接圆、拟合椭圆

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

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

        'ImageBox1.Image = m1

        Dim mid1 As New Mat

        CvInvoke.Threshold(m1, mid1, 150, 255, ThresholdType.BinaryInv)

        Dim contours As New VectorOfVectorOfPoint

        Dim hierarchy As New VectorOfRect

        CvInvoke.FindContours(mid1, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple)

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

        '外接三角形

        Dim mtriangle As New Mat

        mtriangle = m1.Clone()

        '外接圆形

        Dim mcircle As New Mat

        mcircle = m1.Clone()

        '拟合椭圆

        Dim mEllipse As New Mat

        mEllipse = m1.Clone()

        Dim triangle As New VectorOfPoint

        For i As Integer = 0 To contours.Size - 1

            Dim trianglearea As Double

            '获得外接三角形

            trianglearea = CvInvoke.MinEnclosingTriangle(contours(i), triangle)

            '使用封闭多边形来绘制三角形,也可以用line来绘制

            CvInvoke.Polylines(mtriangle, triangle, True, New MCvScalar(0), 2)

            Dim cf As CircleF

            cf = CvInvoke.MinEnclosingCircle(contours(i))

            '获得外接圆形

            CvInvoke.Circle(mcircle, New Point(CInt(cf.Center.X), CInt(cf.Center.Y)), cf.Radius, New MCvScalar(0), 2)

            '获得拟合椭圆

            Dim rr As RotatedRect

            rr = CvInvoke.FitEllipse(contours(i))

            CvInvoke.Ellipse(mEllipse, rr, New MCvScalar(0), 2)

        Next

        ImageBox1.Image = mtriangle

        ImageBox2.Image = mcircle

        ImageBox3.Image = mEllipse

End Sub

运行后如下图所示:

图6-12 轮廓的最小外接三角形、最小外接圆、拟合椭圆

6.3.7 拟合直线FitLine

拟合直线是指利用图像中的点集,找到一条最匹配点集的直线,使得该直线能够尽可能地覆盖所有的点。通过拟合直线,可以得到图像中点的分布情况,从而可以进行轮廓提取、边缘检测等操作。例如,在目标检测中,可以通过拟合直线来定位目标对象的位置和方向;在图像处理中,可以通过拟合直线来进行图像的分割、去除噪声、边缘检测等。

在Emgu.CV中,CvInvoke.FitLine函数用于拟合给定点集的直线,它的声明如下:

Public Shared Sub FitLine(points As Emgu.CV.IInputArray, line As Emgu.CV.IOutputArray, distType As Emgu.CV.CvEnum.DistType, param As Double, reps As Double, aeps As Double)

参数说明:

  1. input:输入的点集。
  2. line:输出的直线,这是一个VectorOfFloat类型,包含四个元素,其中line(0),line(1)是一个方向向量;line(2),line(3)是直线上一个点。可以通过此输出获得直线的斜率和截距:

斜率 = line (1) / line (0)

截距 = line (3) – 斜率 * line (2)

  1. distType:距离类型,可以是DistType.L1或者DistType.L2。
  2. param:距离类型的参数,和所选的距离类型有关,值可以设置为0,FitLine本身会自动选择最优化的值。
  3. reps:拟合直线的径向精度,默认为0.01。
  4. aeps:拟合直线的角度精度,默认为0.01。

【代码位置:frmChapter6】Button12_Click

    'FitLine

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

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

        Dim rand As New Random()

        Dim pts(19) As Point

        '设置随机点

        For i As Integer = 0 To 19

            Dim x As Integer = rand.Next(0, 500)

            Dim y As Integer = rand.Next(0, 500)

            pts(i) = New Point(x, y)

            CvInvoke.Circle(m, pts(i), 3, New MCvScalar(0, 0, 255), -1)

        Next

        Dim vop As New VectorOfPoint(pts)

        Dim vof As New VectorOfFloat()

        CvInvoke.FitLine(vop, vof, DistType.L2, 0, 0.01, 0.01)

        '计算斜率

        Dim k As Double = vof(1) / vof(0)

        '计算截距

        Dim b As Double = vof(3) - k * vof(2)

        '获得直线起点

        Dim startpoint As New Point(0, CInt(b))

        '获得直线终点

        Dim endpoint As New Point(m.Width - 1, CInt(k * (m.Width - 1) + b))

        CvInvoke.Line(m, startpoint, endpoint, New MCvScalar(255, 0, 0), 2)

        ImageBox1.Image = m

End Sub

运行后如下图所示:

图6-13 获得拟合直线

6.3.8 最短距离pointPolygonTest      

CvInvoke.PointPolygonTest方法用于计算给定点到多边形的最短距离,或判断点是否在多边形内部。该方法声明如下:

Public Shared Function PointPolygonTest(contour As Emgu.CV.IInputArray, pt As System.Drawing.PointF, measureDist As Boolean)

参数说明:

  1. contour:轮廓。这是一个VectorOfPoint类型。对应使用FindContours方法获得的contours所包含的成员。
  2. pt:要计算的点的坐标。
  3. measureDist:如果设置为true,则计算最短距离;如果设置为false,则仅判断点是否在多边形内部。

返回值:

如果measureDist设置为true,则返回给定点到多边形的最短距离,正值表示点在多边形外部,负值表示点在多边形内部。

如果measureDist设置为false,则返回一个整数值:1表示点在多边形内部,0表示点在多边形边界上,-1表示点在多边形外部。

【代码位置:frmChapter6】Button13_Click

    'PointPolygonTest 轮廓外一点到轮廓的距离

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

        Dim m As New Mat(400, 400, DepthType.Cv8U, 1)

        m.SetTo(New MCvScalar(0))

        '绘制一个矩形轮廓和一个圆形轮廓

        CvInvoke.Rectangle(m, New Rectangle(50, 50, 100, 100), New MCvScalar(255), -1)

        CvInvoke.Circle(m, New Point(300, 300), 100, New MCvScalar(255), -1)

        Dim m1 As New Mat

        m1 = m.Clone

        Dim p1 As New Point(240, 100)

        Dim contours As New VectorOfVectorOfPoint

        Dim hierarchy As New VectorOfRect

        CvInvoke.FindContours(m1, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple)

        Dim dis As New List(Of Double)

        For i As Integer = 0 To contours.Size - 1

            Dim dis1 As Double = CvInvoke.PointPolygonTest(contours(i), p1, True)

            dis.Add(dis1)

            '只看在轮廓的内外

            '点在轮廓上,返回0,不计算距离返回0

            '点在轮廓内,返回正数,不计算距离返回1

            '点在轮廓外,返回负数,不计算距离返回-1

            'Dim dis2 As Double = CvInvoke.PointPolygonTest(contours(i), p1, False)

            'Console.WriteLine(dis2)

        Next

        CvInvoke.Circle(m1, p1, 2, New MCvScalar(255), -1)

        ImageBox1.Image = m1

        '使用获得的距离绘制圆形

        Dim m3 As New Mat(400, 400, DepthType.Cv8U, 3)

        m3.SetTo(New MCvScalar(0))

        CvInvoke.Rectangle(m3, New Rectangle(50, 50, 100, 100), New MCvScalar(255, 255, 255), -1)

        CvInvoke.Circle(m3, New Point(300, 300), 100, New MCvScalar(255, 255, 255), -1)

        CvInvoke.Circle(m3, p1, 2, New MCvScalar(0, 0, 255), -1)

        For i As Integer = 0 To dis.Count - 1

            CvInvoke.Circle(m3, p1, Math.Abs(dis(i)), New MCvScalar(0, 255, 0), 2)

        Next

        ImageBox2.Image = m3

End Sub

运行后如下图所示:

图6-14 点到轮廓的外接圆

上述代码只能获得最小距离,如果要得到轮廓外一点到轮廓最小距离的轮廓上一点的坐标,可以采用以下方法:

1、图像M1上绘制图形A

2、获得图形A的轮廓A(M1上只有一个轮廓)

3、获得点A到图形A的最小距离d

4、图像M2上使用点A为圆心,最小距离d为半径画圆A

5、M2和M1做异或,得到圆A

6、获得圆A的轮廓B(M2上只有一个圆形的轮廓)

7、获得轮廓B上的每个点到轮廓A的距离,判断是否符合条件:理论上等于0就表示该点在轮廓A上,但是通常不会直接判断=0而是给定一个范围。

那么符合条件的点即为需要的坐标点。

实现代码如下:

【代码位置:frmChapter6】Button14_Click

    '获得点到轮廓的最短距离

    '以点为圆心,最短距离为半径画圆

    '获得圆的轮廓上的点,这里可能会出现误差

    '求出每个点到轮廓的最短距离

    '如果为0,那么这个点在轮廓上,

    '但是通常而言,会有偏差

  '感觉此方法误差比较大

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

        Dim m As New Mat(400, 400, DepthType.Cv8U, 1)

        m.SetTo(New MCvScalar(0))

        CvInvoke.Rectangle(m, New Rectangle(50, 50, 100, 100), New MCvScalar(255), -1)

        ImageBox1.Image = m

        Dim p1 As New Point(240, 100)

        Dim m1 As New Mat

        m1 = m.Clone

        '求出点到形状的距离

        Dim contours1 As New VectorOfVectorOfPoint

        CvInvoke.FindContours(m1, contours1, Nothing, RetrType.External, ChainApproxMethod.ChainApproxSimple)

        '这里只有一个形状轮廓,所以直接使用contours(0)

        Dim dis1 As Double = CvInvoke.PointPolygonTest(contours1(0), p1, True)

        '获得最短距离后画圆

        CvInvoke.Circle(m1, p1, Math.Abs(dis1), New MCvScalar(255), 1)

        ImageBox2.Image = m1

        'mm1异或,这里获得到刚才生成的圆形

        Dim m2 As New Mat

        CvInvoke.BitwiseXor(m, m1, m2)

        Dim contours2 As New VectorOfVectorOfPoint

        CvInvoke.FindContours(m2, contours2, Nothing, RetrType.External, ChainApproxMethod.ChainApproxSimple)

        '这里只有一个形状轮廓

        Dim cirpoints As VectorOfPoint = contours2(0)

        '保存形状上符合距离条件的点

        Dim shapes As New List(Of Point)

        For i As Integer = 0 To cirpoints.Size - 1

            Dim cirp As New Point(cirpoints(i).X, cirpoints(i).Y)

            '不用计算距离,只需要获得是否在轮廓上

            Dim dis As Double = CvInvoke.PointPolygonTest(contours1(0), cirp, True)

            '小于2视为符合条件

            If Math.Abs(dis) <= 1 Then

                shapes.Add(cirp)

            End If

        Next

        Dim m3 As New Mat

        m3 = m.Clone

        CvInvoke.CvtColor(m3, m3, ColorConversion.Gray2Bgr)

        '绘制点

        CvInvoke.Circle(m3, p1, 2, New MCvScalar(0, 0, 255), -1)

        '以点为圆心绘制圆,半径为最短距离

        CvInvoke.Circle(m3, p1, Math.Abs(dis1), New MCvScalar(0, 255, 0), 1)

        '画出线段

        For Each p As Point In shapes

            CvInvoke.Line(m3, p1, p, New MCvScalar(255, 0, 0), 1)

        Next

        ImageBox3.Image = m3

End Sub

运行后如下图所示:

图6-15 轮廓与轮廓外一点最小距离的坐标点

通过运行结果,可以看出此方法获得的坐标点太多,误差比较大,为此在下面的代码中进行改进,采用平均值来获得坐标点。

【代码位置:frmChapter6】Button15_Click

    '获得点到轮廓的最短距离

    '对上面代码上的改进,增加了平均值

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

        Dim m As New Mat(400, 400, DepthType.Cv8U, 1)

        m.SetTo(New MCvScalar(0))

        'CvInvoke.Circle(m, New Point(300, 300), 100, New MCvScalar(255), -1)

        CvInvoke.Rectangle(m, New Rectangle(50, 50, 100, 100), New MCvScalar(255), -1)

        ImageBox1.Image = m

        Dim p1 As New Point(240, 100)

        Dim m1 As New Mat

        m1 = m.Clone

        '求出点到形状的距离

        Dim contours As New VectorOfVectorOfPoint

        CvInvoke.FindContours(m1, contours, Nothing, RetrType.External, ChainApproxMethod.ChainApproxSimple)

        '这里只有一个形状轮廓

        Dim dis1 As Double = CvInvoke.PointPolygonTest(contours(0), p1, True)

        CvInvoke.Circle(m1, p1, Math.Abs(dis1), New MCvScalar(255), 1)

        ImageBox2.Image = m1

        Dim m2 As New Mat

        CvInvoke.BitwiseXor(m, m1, m2)

        'ImageBox3.Image = m2

        Dim contours1 As New VectorOfVectorOfPoint

        CvInvoke.FindContours(m2, contours1, Nothing, RetrType.External, ChainApproxMethod.ChainApproxSimple)

        '这里只有一个形状轮廓

        Dim cirpoints As VectorOfPoint = contours1(0)

        Dim shapes As New List(Of Point)

        For i As Integer = 0 To cirpoints.Size - 1

            Dim cirp As New Point(cirpoints(i).X, cirpoints(i).Y)

            '不用计算距离,只需要获得是否在轮廓上

            Dim dis As Double = CvInvoke.PointPolygonTest(contours(0), cirp, True)

            '距离是否在设置范围,这里是3,多少都没所谓,后面要计算平均值

            If Math.Abs(dis) <= 3 Then

                shapes.Add(cirp)

            End If

        Next

        Dim m3 As New Mat

        m3 = m.Clone

        CvInvoke.CvtColor(m3, m3, ColorConversion.Gray2Bgr)

        CvInvoke.Circle(m3, p1, Math.Abs(dis1), New MCvScalar(0, 255, 0), 1)

        CvInvoke.Circle(m3, p1, 2, New MCvScalar(0, 0, 255), -1)

        Dim totalx As Double = 0

        Dim totaly As Double = 0

        Dim avgx As Double

        Dim avgy As Double

        '平均值计算点坐标

        For i As Integer = 0 To shapes.Count - 1

            totalx += shapes(i).X

            totaly += shapes(i).Y

        Next

        avgx = totalx / shapes.Count

        avgy = totaly / shapes.Count

        CvInvoke.Line(m3, p1, New Point(CInt(avgx), CInt(avgy)), New MCvScalar(255, 0, 0), 1)

        ImageBox3.Image = m3

End Sub

运行后如下图所示:

图6-16 轮廓与轮廓外一点最小距离的坐标点

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • C#(asp.net)乡镇中学宿舍管理系统---附源码 97861
  • OSPF路由原理详解与关键点
  • 20L水箱植保无人机技术详解
  • NVM安装管理node.js版本(简单易懂)
  • 微信左滑删除聊天记录怎么恢复?记录找回秘籍,第一种更有效!
  • 基于java图书销售管理系统设计与实现
  • Aurora IP核 —— NFC功能
  • Unity3D 屏幕空间阴影的简单优化详解
  • 【MySQL数据库管理问答题】第6章 管理 MySQL 用户
  • windows vs2022 MFC使用webview2嵌入网页
  • 大数据-96 Spark 集群 SparkSQL Scala编写SQL操作SparkSQL的数据源:JSON、CSV、JDBC、Hive
  • [ComfyUI]Flux+MiniCPM-V强强联手艺术创意,媲美GPT4V级国产多模态视觉大模型
  • 【C/C++】pointer vs reference
  • JavaScript - Ajax
  • Spring常用的注解有哪些?作用是什么?怎么用?
  • 《网管员必读——网络组建》(第2版)电子课件下载
  • 「译」Node.js Streams 基础
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • canvas绘制圆角头像
  • eclipse(luna)创建web工程
  • input的行数自动增减
  • Java的Interrupt与线程中断
  • Laravel 菜鸟晋级之路
  • React16时代,该用什么姿势写 React ?
  • SpiderData 2019年2月25日 DApp数据排行榜
  • Spring核心 Bean的高级装配
  • storm drpc实例
  • Web标准制定过程
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 机器学习中为什么要做归一化normalization
  • 简单实现一个textarea自适应高度
  • 聚类分析——Kmeans
  • 跨域
  • 如何优雅地使用 Sublime Text
  • 做一名精致的JavaScripter 01:JavaScript简介
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • Python 之网络式编程
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 如何正确理解,内页权重高于首页?
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​插件化DPI在商用WIFI中的价值
  • #565. 查找之大编号
  • #define 用法
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • (3) cmake编译多个cpp文件
  • (3)(3.5) 遥测无线电区域条例
  • (windows2012共享文件夹和防火墙设置
  • (二)JAVA使用POI操作excel
  • (接口自动化)Python3操作MySQL数据库
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (每日持续更新)jdk api之FileReader基础、应用、实战