EmguCV学习笔记 C# 7.2 特征点检测

news2024/11/14 17:47:35

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

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博客

7.2 特征点检测

在EmguCV中,特征点通常使用Features2D命名空间下的类进行检测和提取,常用的特征点检测算法包括FAST、SIFT、SURF、ORB等。使用这些算法可以在图像中提取出关键点和特征描述子,进而用于图像匹配、目标跟踪、三维重建等领域。

7.2.1 Features2DToolbox类        

Features2DToolbox类提供了静态方法来绘制特征点和特征点连线。由于此类需要依赖于其他方法获得特征点或特征描述子,因此关于本节中介绍的Features2DToolbox类相关方法具体的例子,请看后面的章节。

7.2.1.1 DrawKeypoints

Features2Dtoolbox的DrawKeypoints方法用于在图像上绘制关键点。该函数可以将检测到的关键点绘制在图像上,以便进行可视化和分析。

函数的定义如下:

public static void DrawKeypoints(

                    IInputArray image,

                    VectorOfKeyPoint keypoints,

                    IInputOutputArray outImage,

                    Bgr color,

                    Features2DToolbox. KeypointDrawType type = Features2DToolbox.KeypointDrawType.Default

)

参数说明:

  1. image:要绘制关键点的图像。
  2. keypoints:要绘制的关键点,通常是通过SIFT、SURF、ORB等算法检测到的关键点。
  3. outImage:输出图像,通常是一个Mat对象,用于绘制关键点。
  4. color:绘制关键点的颜色,通常是一个MCvScalar对象,表示颜色的BGR值。
  5. type:绘制关键点的方式,通常是一个Features2DToolbox.KeypointDrawType枚举值,可以选择绘制关键点的位置、方向、大小等信息。它包括如下成员:
    1. KeypointDrawType.Default:绘制圆形。
    2. KeypointDrawType.DrawRichKeypoints:绘制带方向和大小信息的关键点。

7.2.1.2 DrawMatches

Features2Dtoolbox的DrawMatches方法用于绘制特征点匹配结果的函数,它可以将两幅图像中的匹配特征点连接起来,并将连接线绘制到一张新的图像中。常用声明如下:

public static void DrawMatches(

           IInputArray modelImage,

                    VectorOfKeyPoint modelKeypoints,

                    IInputArray observedImage,

                    VectorOfKeyPoint observedKeyPoints,

                    VectorOfDMatch matches,

                    IInputOutputArray result,

                    MCvScalar matchColor,

                    MCvScalar singlePointColor,

                    VectorOfByte mask = null,

           Features2DToolbox. KeypointDrawType flags = Features2DToolbox.KeypointDrawType.Default

)

参数说明:

  1. modelImage:模型图像。
  2. modelKeypoints:模型图像的特征点,类型为VectorOfKeyPoint。
  3. observedImage:匹配图像。
  4. observedKeyPoints:匹配图像的特征点,类型为VectorOfKeyPoint。
  5. matches:两幅图像中的匹配特征点,类型为VectorOfDMatch或者VectorOfVectorOfDMatch。
  6. result:输出图像,用于存储绘制结果。
  7. matchColor:用于绘制匹配线的颜色,类型为MCvScalar。
  8. singlePointColor:用于绘制特征点的颜色,类型为MCvScalar。
  9. mask:绘制掩码。
  10. flags:绘制标志,用于控制绘制的方式,类型为Features2DToolbox.DrawMatchesFlags枚举类型。

7.2.1.3 VoteForUniqueness

Feature2DToolbox类的VoteForUniqueness方法实现特征匹配的进一步优化,去除重复匹配和错误匹配,保留唯一匹配结果。该方法声明如下:

public static void VoteForUniqueness(

           VectorOfVectorOfDMatch matches,

                    double uniquenessThreshold,

           Mat mask

)

参数说明:

  1. matches:需要筛选的特征点,VectorOfVectorOfDMatch变量
  2. uniquenessThreshold:阈值,取值范围为0到1之间,一般设置为0.8或0.9。
  3. mask:输入输出矩阵,这是一个Row=matches.Size、Col=1的矩阵。输入的时候,指定哪些特征点需要进行唯一性计算。如果某个特征点的mask值为0,则不进行计算。通常设置为MCvScalar(255)。输出的时候,获得唯一性矩阵,其中唯一的特征点对应的像素值为255,非唯一的特征点对应的像素值为0。

7.2.1.4 VoteForSizeAndOrientation

VoteForSizeAndOrientation方法用于计算匹配的特征点之间的大小和方向的一致性得分,从而去除可能的错误匹配。该方法声明如下:

public static int VoteForSizeAndOrientation(

           VectorOfKeyPoint modelKeyPoints,

                    VectorOfKeyPoint observedKeyPoints,

                    VectorOfVectorOfDMatch matches,

                    Mat mask,

                    double scaleIncrement,

           int rotationBins

)

参数说明:

  1. modelKeyPoints:模型图像中的特征点,VectorOfKeyPoint类型。
  2. observedKeyPoints:匹配图像中的特征点,VectorOfKeyPoint类型。
  3. matches:匹配的特征点,VectorOfVectorOfDMatch类型。
  4. mask:蒙版。输入是VoteForUniqueness方法获得的mask。输出为大小和方向一致性得分矩阵,其中唯一的特征点对应的像素值为255,非唯一的特征点对应的像素值为0。
  5. scaleIncrement:缩放值,通常设置为1.5。
  6. rotationBins:匹配可旋转点的数量,通常设置为20。

返回值:

Mask中非0元素的个数。

7.2.1.5 GetHomographyMatrixFromMatchedFeatures

GetHomographyMatrixFromMatchedFeatures方法用于计算两幅图像中匹配的特征点之间的单应性矩阵,从而实现图像的配准和拼接。该方法声明如下:

public static Mat GetHomographyMatrixFromMatchedFeatures(

           VectorOfKeyPoint model,

                    VectorOfKeyPoint observed,

                    VectorOfVectorOfDMatch matches,

                    Mat mask,

           double ransacReprojThreshold

)

参数说明:

  1. model:模型图像中的特征点,VectorOfKeyPoint类型。
  2. observed:匹配图像中的特征点,VectorOfKeyPoint类型。
  3. matches:匹配的特征点,VectorOfVectorOfDMatch类型。
  4. mask:蒙版。输入通常是VoteForUniqueness方法或者VoteForSizeAndOrientation方法获得的mask,也可以手动设置。
  5. ransacReprojThreshold:RANSAC算法中的二次投影误差阈值,一般为1到10之间。

返回值:

返回单应性矩阵,如果找不到,则返回Nothing。

7.2.2 SIFT类 

EmguCV中的SIFT类是使用SIFT (Scale-Invariant Feature Transform)算法进行特征点检测和描述子生成的工具。SIFT算法是一种基于尺度空间极值检测和高斯差分图像描述子的算法,具有较高的特征检测精度和描述子匹配准确性,它可以在不同尺度和旋转角度下检测和描述图像中的特征点,由于其良好的尺度不变性和旋转不变性,被广泛应用于计算机视觉领域。SIFT算法原本申请了专利需要许可才能使用,但现在SIFT算法的专利已经到期。

SIFT类提供了以下方法来检测特征点和获得特征描述:

1、Detect方法

Detect方法使用SIFT特征检测器检测了图像中的SIFT特征点,并将检测结果保存在MKeyPoint类型数组变量中。

MKeyPoint类表示一个特征点,包含了该特征点的位置、尺度、方向等信息。

2、DetecRaw方法

DetecRaw方法同Detect方法,但是它将检测结果保存在VectorOfKeyPoint类型变量中。

VectorOfKeyPoint类表示一个特征点向量,可以用于管理和操作多个特征点,常用于特征点的提取、保存、加载、匹配等操作。

3、Compute方法

Compute方法用于在给定的图像和对应特征点处提取特征描述子,将提取结果保存在Mat类型变量中。

特征描述子包含了描述关键点周围区域的一组数值,可以用于比较、匹配和识别关键点。在使用SIFT算法提取特征描述子时,特征描述子保存在一个Mat类型变量中,该Mat的大小是“关键点的数量×128”,对应Mat的“行×列”,每个关键点为一行,128表示每个特征描述子包含128个数值,这些数值表示了关键点周围区域的特征信息,可以用于描述和区分不同的关键点。

4、DetectAndCompute方法

DetectAndCompute方法是Detect方法和Compute方法的集成,可以返回图像中的SIFT关键点和特征描述子。

参数说明:

  1. image:输入图像,类型为`Mat`。
  2. mask:掩膜图像,用于指定特征点的提取范围。该参数通常设置为Nothing。
  3. keypoints:提取到的特征点,类型为VectorOfKeyPoint。
  4. descriptors:计算得到的特征描述子,类型为Mat。
  5. useProvidedKeypoints:是否使用输入的特征点进行计算。当为False时,既要检测关键点,又要计算特征描述子;否则只获得特征描述子。

【代码位置:frmChapter7】Button6_Click

        //获得特征关键点

        private void Button6_Click(object sender, EventArgs e)

        {

            Mat msrc = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.AnyColor);

            Emgu.CV.Features2D.SIFT sift = new Emgu.CV.Features2D.SIFT();

            VectorOfKeyPoint vkp = new VectorOfKeyPoint();

            sift.DetectRaw(msrc, vkp);

            //绘制关键点

            Mat m1 = msrc.Clone();

            for (int i = 0; i < vkp.Size; i++)

                CvInvoke.Circle(m1, PointFToPoint(vkp[i].Point), 3, new MCvScalar(0, 0, 255), -1);

            ImageBox1.Image = m1;

            MKeyPoint[] mkp = sift.Detect(msrc);

            //绘制关键点

            Mat m2 = msrc.Clone();

            for (int i = 0; i < mkp.Length; i++)

                CvInvoke.Circle(m2, PointFToPoint(mkp[i].Point), 3, new MCvScalar(0, 0, 255), -1);

            ImageBox2.Image = m2;

        }

输出结果如下图所示:

图7-6 获得关键点比较

通过以下方法获得特征描述子

【代码位置:frmChapter7】Button7_Click

        //获得特征描述子

        private void Button7_Click(object sender, EventArgs e)

        {

            Mat msrc = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.AnyColor);

            Emgu.CV.Features2D.SIFT sift = new Emgu.CV.Features2D.SIFT();

            //使用DetectRaw方法来获得特征点,返回一个VectorOfKeyPoint

            VectorOfKeyPoint vkp1 = new VectorOfKeyPoint();

            sift.DetectRaw(msrc, vkp1);

            //获得特征描述子

            Mat mdst1 = new Mat();

            sift.Compute(msrc, vkp1, mdst1);

            //或者采用DetectAndCompute方法来获得特征描述子

            VectorOfKeyPoint vkp2 = new VectorOfKeyPoint();

            Mat mdst2 = new Mat();

            sift.DetectAndCompute(msrc, null, vkp2, mdst2, false);

        }

输出结果如下图所示:

 

图7-7 获得特征描述子

查看输出的特征描述子Mat,可以看到lena图像的关键点一共1110(Rows),Mat宽度128。特征描述子具体的使用参看后面。

7.2.3 BFMatcher类

EmguCV中的BFMatcher类是一个Brute-Force Matcher(暴力匹配器),用于在两个特征描述子集合之间进行匹配。BFMatcher类提供了两种匹配方法:暴力匹配和k近邻匹配,可以根据实际需求选择合适的方法。

BFMatcher类的主要方法为Match方法,可以接受两个特征描述子集合并返回它们之间的匹配结果。另外,该类还提供了一些其他的属性和方法,用于设置匹配算法的参数和获取匹配结果。

下面是BFMatcher类的常用方法和属性:

1. Match方法:在两个特征描述子集合之间进行匹配。

2. KnnMatch方法:使用k近邻算法在两个特征描述子集合之间进行匹配。

3. MatchType属性:设置匹配算法的类型。

4. CrossCheck属性:设置是否使用交叉验证。

7.2.3.1 Match

Match方法是在两个特征描述子集合之间进行匹配的函数,它的声明如下:

public void Match(

           IInputArray queryDescriptors,

                    IInputArray trainDescriptors,

                    VectorOfDMatch matches,

           IInputArray mask = null

)

该函数接受三个参数:

  1. queryDescriptors:查询图像的特征描述子,类型为Mat。
  2. trainDescriptors:训练图像的特征描述子,类型为Mat。
  3. matches:VectorOfDMatch类型。其中每个Dmatch结构表示每个查询描述子和其最佳匹配的训练描述子之间的匹配结果,它有三个主要属性:
    1. QueryIdx:对应查询图像查询描述子的索引。
    2. TrainIdx:对应训练图像描述子的索引。
    3. Distance:两个描述子之间的距离,越小表明匹配度越高。
  4. mask:掩膜图像,用于指定匹配的范围,类型为Mat。

【代码位置:frmChapter7】Button8_Click

        //特征点匹配

        private void Button8_Click(object sender, EventArgs e)

        {

            Mat m1 = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.AnyColor);

            Mat m2 = new Mat("c:\\learnEmgucv\\lena_keypoint.jpg", ImreadModes.AnyColor);

            Emgu.CV.Features2D.SIFT SIFT1 = new Emgu.CV.Features2D.SIFT();

            Mat des1 = new Mat();

            VectorOfKeyPoint vkp1 = new VectorOfKeyPoint();

            SIFT1.DetectAndCompute(m1, null, vkp1, des1, false);

            Mat m1c = m1.Clone();

            //使用Circle标记特征点

            for (int i = 0; i < vkp1.Size; i++)

                CvInvoke.Circle(m1c, PointFToPoint(vkp1[i].Point), 3, new MCvScalar(0, 0, 255), -1);

            ImageBox1.Image = m1c;

            Emgu.CV.Features2D.SIFT SIFT2 = new Emgu.CV.Features2D.SIFT();

            Mat des2 = new Mat();

            VectorOfKeyPoint vkp2 = new VectorOfKeyPoint();

            SIFT2.DetectAndCompute(m2, null, vkp2, des2, false);

            Mat m2c = m2.Clone();

            //使用DrawKeypoints标记特征点

            Features2DToolbox.DrawKeypoints(m2c, vkp2, m2c, new Bgr(0, 0, 255));

            ImageBox2.Image = m2c;

            VectorOfDMatch matches = new VectorOfDMatch();

            BFMatcher matcher = new BFMatcher(DistanceType.L2);

            //进行匹配

            matcher.Match(des2, des1, matches);

            Console.WriteLine("匹配成功特征点数目:" + matches.Size);

            Mat outimg = new Mat();

            //绘制将特征点连接起来

            //需要注意MatchDrawMatches参数的顺序

            Emgu.CV.Features2D.Features2DToolbox.DrawMatches(

                m1, vkp1, m2, vkp2, matches, outimg, new MCvScalar(0, 0, 255), new MCvScalar(0, 255, 0));

            ImageBox3.Image = outimg;

        }

输出结果如下图所示:

 

图7-8 图像特征点匹配

【代码位置:frmChapter7】Button9_Click

        //特征点匹配 采用一定算法对特征点进行筛选

        private void Button9_Click(object sender, EventArgs e)

        {

            Mat m1 = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.AnyColor);

            Mat m2 = new Mat("c:\\learnEmgucv\\lena_keypoint.jpg", ImreadModes.AnyColor);

            SIFT SIFT1 = new SIFT();

            Mat des1 = new Mat();

            VectorOfKeyPoint vkp1 = new VectorOfKeyPoint();

            SIFT1.DetectAndCompute(m1, null, vkp1, des1, false);

            Mat m1c = m1.Clone();

            for (int i = 0; i < vkp1.Size; i++)

                CvInvoke.Circle(m1c, PointFToPoint(vkp1[i].Point), 3, new MCvScalar(0, 0, 255), -1);

            ImageBox1.Image = m1c;

            SIFT SIFT2 = new SIFT();

            Mat des2 = new Mat();

            VectorOfKeyPoint vkp2 = new VectorOfKeyPoint();

            SIFT2.DetectAndCompute(m2, null, vkp2, des2, false);

            Mat m2c = m2.Clone();

            Features2DToolbox.DrawKeypoints(m2c, vkp2, m2c, new Bgr(0, 0, 255));

            ImageBox2.Image = m2c;

            VectorOfDMatch matches = new VectorOfDMatch();

            BFMatcher matcher = new BFMatcher(DistanceType.L2);

            matcher.Match(des2, des1, matches);

            Console.WriteLine("匹配成功特征点数目:" + matches.Size);

            List<MDMatch> lstGoodMatches = new List<MDMatch>();

            VectorOfDMatch goodMatches = new VectorOfDMatch();

            //采用一定算法对特征点进行筛选

            for (int i = 0; i < matches.Size - 1; i++)

                if (matches[i].Distance < 0.7 * matches[i + 1].Distance)

                    lstGoodMatches.Add(matches[i]);

            goodMatches.Push(lstGoodMatches.ToArray());

            Mat outimg = new Mat();

            Emgu.CV.Features2D.Features2DToolbox.DrawMatches(

                m1, vkp1, m2, vkp2, goodMatches, outimg, new MCvScalar(0, 0, 255), new MCvScalar(0, 255, 0));

            ImageBox3.Image = outimg;

        }

输出结果如下图所示:

图7-9 使用一定算法优化后的图像特征点匹配

7.2.3.2 knnMatch

knnMatch方法实现暴力匹配算法中的K近邻匹配(K-Nearest Neighbor Matching)。它用于在两个特征描述子集合之间进行K近邻匹配,并返回每个查询描述子和其最佳匹配的K个训练描述子之间的匹配结果。该方法声明如下:

public void KnnMatch(

           IInputArray queryDescriptors,

                    IInputArray trainDescriptors,

                    VectorOfVectorOfDMatch matches,

                    int k,

                    IInputArray mask = null,

           bool compactResult = false

)

该函数接受五个参数:

  1. queryDescriptors:查询图像的特征描述子,类型为Mat。
  2. trainDescriptors:训练图像的特征描述子,类型为Mat。
  3. matches:VectorOfDMatch类型。
  4. k:每个查询描述子在训练描述子集合中寻找的最佳匹配结果数目,但是实际匹配中获得的数目可能会小于k。
  5. mask:掩膜图像,用于指定匹配的范围,默认所有描述子都将进行匹配。
  6. compactResult:是否输出紧凑格式。False时,输出的匹配结果为DMatch对象列表,每个DMatch对象包含了一个查询特征点和一个训练特征点之间的距离和索引。True时,输出的匹配结果为紧凑格式的匹配结果,它是一个二维整数数组,每个元素为一个查询特征点的k个最近邻训练特征点的索引。默认为False。

【代码位置:frmChapter7】Button10_Click

        //特征点匹配 KnnMatch

        private void Button10_Click(object sender, EventArgs e)

        {

            Mat m1 = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.AnyColor);

            Mat m2 = new Mat("c:\\learnEmgucv\\lena_keypoint.jpg", ImreadModes.AnyColor);

            SIFT SIFT1 = new SIFT();

            Mat des1 = new Mat();

            VectorOfKeyPoint vkp1 = new VectorOfKeyPoint();

            SIFT1.DetectAndCompute(m1, null, vkp1, des1, false);

            Mat m1c = m1.Clone();

            for (int i = 0; i < vkp1.Size; i++)

                CvInvoke.Circle(m1c, PointFToPoint(vkp1[i].Point), 3, new MCvScalar(0, 0, 255), -1);

            ImageBox1.Image = m1c;

            SIFT SIFT2 = new SIFT();

            Mat des2 = new Mat();

            VectorOfKeyPoint vkp2 = new VectorOfKeyPoint();

            SIFT2.DetectAndCompute(m2, null, vkp2, des2, false);

            Mat m2c = m2.Clone();

            Features2DToolbox.DrawKeypoints(m2c, vkp2, m2c, new Bgr(0, 0, 255));

            ImageBox2.Image = m2c;

            VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch();

            BFMatcher matcher = new BFMatcher(DistanceType.L2);

            //使用KnnMatch匹配

            matcher.KnnMatch(des2, des1, matches, 3);

            Mat outimg = new Mat();

            Emgu.CV.Features2D.Features2DToolbox.DrawMatches(

                m1, vkp1, m2, vkp2, matches, outimg, new MCvScalar(0, 0, 255), new MCvScalar(0, 255, 0), null);

            ImageBox3.Image = outimg;

        }

输出结果如下图所示:

图7-10 图像特征点匹配

【代码位置:frmChapter7】Button11_Click

        //特征点匹配 采用一定算法对特征点进行筛选

        private void Button11_Click(object sender, EventArgs e)

        {

            Mat m1 = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.AnyColor);

            Mat m2 = new Mat("c:\\learnEmgucv\\lena_keypoint.jpg", ImreadModes.AnyColor);

            SIFT SIFT1 = new SIFT();

            Mat des1 = new Mat();

            VectorOfKeyPoint vkp1 = new VectorOfKeyPoint();

            SIFT1.DetectAndCompute(m1, null, vkp1, des1, false);

            Mat m1c = m1.Clone();

            for (int i = 0; i < vkp1.Size; i++)

                CvInvoke.Circle(m1c, PointFToPoint(vkp1[i].Point), 3, new MCvScalar(0, 0, 255), -1);

            ImageBox1.Image = m1c;

            SIFT SIFT2 = new SIFT();

            Mat des2 = new Mat();

            VectorOfKeyPoint vkp2 = new VectorOfKeyPoint();

            SIFT2.DetectAndCompute(m2, null, vkp2, des2, false);

            Mat m2c = m2.Clone();

            Features2DToolbox.DrawKeypoints(m2c, vkp2, m2c, new Bgr(0, 0, 255));

            ImageBox2.Image = m2c;

            VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch();

            BFMatcher matcher = new BFMatcher(DistanceType.L2);

            matcher.KnnMatch(des2, des1, matches, 3);

            //获得最小距离

            List<MDMatch> lstLastMatches = new List<MDMatch>();

            Double min_dist = 100;

            for (int i = 0; i < matches.Size; i++)

                if (matches[i][0].Distance < min_dist)

                    min_dist = matches[i][0].Distance;

            VectorOfVectorOfDMatch goodMatches = new VectorOfVectorOfDMatch();

            //采用一定算法对特征点进行筛选

            for (int i = 0; i < matches.Size; i++)

                if (matches[i][0].Distance < 2 * min_dist)

                    goodMatches.Push(matches[i]);

            Mat outimg = new Mat();

            Emgu.CV.Features2D.Features2DToolbox.DrawMatches(

                m1, vkp1, m2, vkp2, goodMatches, outimg, new MCvScalar(0, 0, 255), new MCvScalar(0, 255, 0), null);

            ImageBox3.Image = outimg;

        }

输出结果如下图所示:

图7-11 使用一定算法优化后的图像特征点匹配

【代码位置:frmChapter7】Button12_Click

        //图像匹配

        private void Button12_Click(object sender, EventArgs e)

        {

            Mat m1 = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.AnyColor);

            Mat m2 = new Mat("c:\\learnEmgucv\\lena_keypoint.jpg", ImreadModes.AnyColor);

            SIFT SIFT1 = new SIFT();

            Mat des1 = new Mat();

            VectorOfKeyPoint vkp1 = new VectorOfKeyPoint();

            SIFT1.DetectAndCompute(m1, null, vkp1, des1, false);

            Mat m1c = m1.Clone();

            for (int i = 0; i < vkp1.Size; i++)

                CvInvoke.Circle(m1c, PointFToPoint(vkp1[i].Point), 3, new MCvScalar(0, 0, 255), -1);

            ImageBox1.Image = m1c;

            SIFT SIFT2 = new SIFT();

            Mat des2 = new Mat();

            VectorOfKeyPoint vkp2 = new VectorOfKeyPoint();

            SIFT2.DetectAndCompute(m2, null, vkp2, des2, false);

            Mat m2c = m2.Clone();

            Features2DToolbox.DrawKeypoints(m2c, vkp2, m2c, new Bgr(0, 0, 255));

            ImageBox2.Image = m2c;

            VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch();

            BFMatcher matcher = new BFMatcher(DistanceType.L2);

            matcher.KnnMatch(des2, des1, matches, 3);

            Mat mask = new Mat(matches.Size, 1, DepthType.Cv8U, 1);

            mask.SetTo(new MCvScalar(255));

            //进一步优化特征匹配

            Features2DToolbox.VoteForUniqueness(matches, 0.8, mask);

            //去除可能的错误匹配

            Features2DToolbox.VoteForSizeAndOrientation(vkp1, vkp2, matches, mask, 1.5, 20);

            //得到模板和匹配图片的仿射矩阵

            Mat mtrans = new Mat();

            mtrans = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(vkp1, vkp2, matches, mask, 3);

            //得到模板图像矩形区域

            Rectangle rec = new Rectangle(Point.Empty, m1.Size);

            //提取模板图像矩形区域的四个顶点,为后面定位匹配图像做准备

            PointF[] pts = new PointF[4];

            pts[0] = new PointF(rec.Left, rec.Bottom);

            pts[1] = new PointF(rec.Right, rec.Bottom);

            pts[2] = new PointF(rec.Right, rec.Top);

            pts[3] = new PointF(rec.Left, rec.Top);

            //定位匹配图像

            pts = CvInvoke.PerspectiveTransform(pts, mtrans);

            //PointF() to Point()

            Point[] points = Array.ConvertAll(pts, new Converter<PointF, Point>(PointFToPoint));

            //绘制

            VectorOfPoint vp = new VectorOfPoint(points);

            for (int i = 0; i < vp.Size; i++)

                CvInvoke.Polylines(m2, vp, true, new MCvScalar(255, 0, 0), 4);

            CvInvoke.Imshow("m2", m2);

        }

输出结果如下图所示:

 

图7-12 图像匹配

7.2.4 Feature2D命名空间

Feature2D命名空间是EmguCV中用于处理图像特征的命名空间。该命名空间包含了多个类和方法,可以用于检测、提取和匹配图像特征。该命名空间中有两个重要的基类:

1、Feature2D类

Feature2D类是一个抽象类,用于定义检测和提取图像特征的接口。该类包含了多个方法,包括Detect方法、Compute方法和ComputeDescriptors方法等。具体的特征检测和提取算法都是通过Feature2D类的派生类来实现的,例如SIFT、ORB等。

2、XFeature2D类

XFeature2D类是EmguCV中用于实现新型特征算法的类,它包含了多种高级特征算法,如FREAK、LATCH和DAISY等。XFeature2D类的特征算法通常比feature2d类更高级、更复杂,具有更好的性能和效果。

Feature2D命名空间提供的图像特征类的使用请参考7.2.2 【SIFT类】

这里以AKAZE算法为例

【代码位置:frmChapter7】Button13_Click

        //AKAZE

        private void Button13_Click(object sender, EventArgs e)

        {

            Mat m1 = new Mat("c:\\learnEmgucv\\lena.jpg", ImreadModes.AnyColor);

            Mat m2 = new Mat("c:\\learnEmgucv\\lena_keypoint.jpg", ImreadModes.AnyColor);

            AKAZE AKAZE1 = new AKAZE();

            Mat des1 = new Mat();

            VectorOfKeyPoint vkp1 = new VectorOfKeyPoint();

            AKAZE1.DetectAndCompute(m1, null, vkp1, des1, false);

            Mat m1c = m1.Clone();

            //使用Circle标记特征点

            for (int i = 0; i < vkp1.Size; i++)

                CvInvoke.Circle(m1c, PointFToPoint(vkp1[i].Point), 3, new MCvScalar(0, 0, 255), -1);

            ImageBox1.Image = m1c;

            AKAZE AKAZE2 = new AKAZE();

            Mat des2 = new Mat();

            VectorOfKeyPoint vkp2 = new VectorOfKeyPoint();

            AKAZE2.DetectAndCompute(m2, null, vkp2, des2, false);

            Mat m2c = m2.Clone();

            //使用DrawKeypoints标记特征点

            Features2DToolbox.DrawKeypoints(m2c, vkp2, m2c, new Bgr(0, 0, 255));

            ImageBox2.Image = m2c;

            VectorOfDMatch matches = new VectorOfDMatch();

            BFMatcher matcher = new BFMatcher(DistanceType.L2);

            //进行匹配

            matcher.Match(des2, des1, matches);

            Console.WriteLine("匹配成功特征点数目:" + matches.Size);

            Mat outimg = new Mat();

            //绘制将特征点连接起来

            //需要注意MatchDrawMatches参数的顺序

            Emgu.CV.Features2D.Features2DToolbox.DrawMatches(

                m1, vkp1, m2, vkp2, matches, outimg, new MCvScalar(0, 0, 255), new MCvScalar(0, 255, 0));

            ImageBox3.Image = outimg;

        }

输出结果如下图所示:

图7-13 AKAZE算法实现的特征点匹配

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

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

相关文章

两个月冲刺软考——求解关系模式达到了第几范式题型(例题+讲解,一看就会)

目录 1.假设一对多联系不转换为一个独立的关系模式的话&#xff0c;那么生成的关系模式应该是将“一”的那一方的主键加入到“多”的一方的关系模式中。 2.求解关系模式达到了第几范式题型 1.假设一对多联系不转换为一个独立的关系模式的话&#xff0c;那么生成的关系模式应该…

10 款企业级项目管理系统是你理想中的那一款吗

市面上主流的 10 款企业级项目管理系统推荐&#xff1a;PingCode、Worktile、泛微 e-office、致远OA、Gitee、Asana、Trello、Basecamp、Monday.com、Smartsheet。 在选择合适的企业内部项目管理系统时&#xff0c;许多企业面临着如何找到一个既能满足当前需求&#xff0c;又能…

【生日视频制作】一群美女游轮船挥手AE模板修改文字软件生成器教程特效素材【AE模板】

生日视频制作教程一群美女游轮船挥手AE模板修改文字生成器素材 怎么如何做的【生日视频制作】一群美女游轮船挥手AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤&#xff1a; 安装AE软件 下载AE模板 把AE模板导入AE软件 修改图片或文字 渲染出视频

24年一级消防工程师报名流程图解(建议电脑)

报考流程&#xff1a; 1、登录中国人事考试网&#xff0c;点击网上报名&#xff0c;登录帐户和密.码&#xff0c;找到“一级消防工程师”的报考入口&#xff0c;选择报考省份&#xff0c;进入在线报名界面。 2、报考人员阅读《承诺制告知书》和《报名须知》后&#xff0c;点击“…

【精选】基于Python的电影推荐系统的设计与实现(全网第一无二,最新定制)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

后台框架-统一异常管理

搭建后台框架全局异常管理是一个很重要的部分&#xff0c;好在SpringBoot提供了很好的处理方法 使用ControllerAdvice ControllerAdvice是Spring MVC中的一个全局异常处理注解&#xff0c;它允许在一个地方集中处理所有控制器抛出的异常。通过使用ControllerAdvice&#xff0…

资源不是问题,网盘搜索神器!极空间部署聚合搜索工具『爱盼』

资源不是问题&#xff0c;网盘搜索神器&#xff01;极空间部署聚合搜索工具『爱盼』 哈喽小伙伴们好&#xff0c;我是Stark-C~ 经常分享一些NAS的玩法和攻略&#xff0c;但是被问及最多的还是资源问题&#xff0c;我在那里下载啊&#xff1f;我在那里看啊&#xff1f;等等...…

LLM系列 | 36:Google最新开源大模型:Gemma 2介绍及其微调(下篇)

引言 环境安装 数据准备 下载 处理 模型训练 模型inference 结果 gemma-2-9b gemma-2-9b-it 引言 低头观落日&#xff0c;引手摘飞星。 小伙伴们好&#xff0c;我是微信公众号《小窗幽记机器学习》的小编&#xff1a;卖黑神话的小女孩。本文紧接前文Google最新开源大…

HarmonyOS NEXT未成年人模式无缝联动所有应用,过滤非适龄内容

背景 随着消费电子产品和移动互联网的普及&#xff0c;未成年人互联网普及率96.8%&#xff0c;超过80%的未成年人都拥有自己的上网设备&#xff0c;而如何引导孩子正确上网一直是家长们的担忧。市场上很多电子设备、系统推出了一些未成年人管控能力&#xff0c;却需要家长到各…

前端技术(六)—— AJAX详解

一、原生 AJAX 1. AJAX 简介 AJAX 全称为 Asynchronous JavaScript And XML&#xff0c;就是异步的 JS 和 XML。 通过 AJAX 可以在浏览器中向服务器发送异步请求&#xff0c;最大的优势&#xff1a;无刷新获取数据。 AJAX 不是新的编程语言&#xff0c;而是一种将现有的标准组…

【练习3】点击消除

地址&#xff1a;点击消除_牛客题霸_牛客网 (nowcoder.com) 分析&#xff1a; 消除的是“相邻且相等”的数&#xff0c;可以考虑用栈。这里使用StringBuilder来代替栈&#xff0c;好处是StringBuilder可以实现尾插和尾删的操作。 public class Main {public static void main(S…

Caching介绍

缓存&#xff08;Caching&#xff09;是计算机系统中一个非常关键且常用的技术&#xff0c;用于提高数据访问速度和系统性能。在Java编程中&#xff0c;缓存同样扮演着重要角色&#xff0c;特别是在处理大量数据、频繁访问数据库或远程服务时。 缓存的基本原理 缓存的基本原理是…

雅特力AT-START-F423开发板

文章目录 1、开箱2、硬件设计3、点灯初试4、gpio输入和中断5、定时器基本定时6、定时器输出PWM7、串口使用8、ADC和DAC测试9、IIC驱动OLED测试10、SPI驱动测试11、总结 1、开箱 最近官方给寄了板子&#xff0c;顺便测评一下吧&#xff0c;首先是开箱环节 板子是调试器开发板的…

栈与队列,优先队列与双端队列(C++)

在C语言阶段&#xff0c;我们学过两种数据结构&#xff0c;栈与队列&#xff0c;一种是先进后出&#xff0c;一种是先进先出。 在C阶段&#xff0c;我们有新容器来方便快捷的使用栈和队列而不需要我们手动来编写 即stack与queue 我们直接来看对应接口 stack 同时放上对应的…

9.标准化与软件知识产权基础知识

大纲 标准的分类 标准的编号 保护期限 知识产权的确定 侵权判断 补充 真题 1

全国大学生数据建模比赛——深度学习

全国大学生数学建模比赛中&#xff0c;深度学习可以成为解决复杂问题的有力手段。 一、深度学习的优势在比赛中的体现 强大的模式识别能力&#xff1a;深度学习模型&#xff0c;如卷积神经网络&#xff08;CNN&#xff09;和循环神经网络&#xff08;RNN&#xff09;&#xff0…

Linux 系统进程管理实战

今天给伙伴们分享一下Linux 系统进程管理&#xff0c;希望看了有所收获。 我是公众号「想吃西红柿」「云原生运维实战派」作者&#xff0c;对云原生运维感兴趣&#xff0c;也保持时刻学习&#xff0c;后续会分享工作中用到的运维技术&#xff0c;在运维的路上得到支持和共同进步…

系统分析师6:计算机网络

文章目录 1 OSI/RM七层模型2 TCP/IP协议族2.1 常见TCP/IP协议基础2.2 DNS 3 IP地址4 网络规划与设计4.1 网络规划与设计的阶段4.2 层次化网络设计 5 综合布线6 网络存储技术-Raid7 网络接入技术 1 OSI/RM七层模型 集线器多个端口属于同一个冲突域&#xff1b; 交换机多个端口属…

nexus 清理 docker 镜像

下载配置 nexus-cli 看网上文档都用如下地址&#xff0c;但现在已经不能下载&#xff1a; wget https://s3.eu-west-2.amazonaws.com/nexus-cli/1.0.0-beta/linux/nexus-cli chmod x nexus-cli 在 github 上下载&#xff1a; wget https://github.com/heyonggs/nexus-cli/r…

【202408最新】Anaconda+VSCode+CUDA+Pytorch安装配置保姆级教程

最近新换了电脑&#xff0c;又开始从头配置代码环境&#xff0c;到处看教程真的一个头两个大&#xff0c;干脆自己整理了一下&#xff0c;方便以后一站式重装。也提供给大家参考。 1.Anaconda下载安装 Anaconda和Python是替代品&#xff08;也不是&#xff09;&#xff0c;下…