如何使用 SIFT 查找图像中的所有匹配对象

问题描述 投票:0回答:0

我有一张钻石卡的图片和一张钻石的小图片,我想找到大图片中的所有钻石

以下是图片:

下面是实验代码:

using System.Collections.Generic;
using System;
using OpenCvSharp;
using OpenCvSharp.Features2D;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var src = new Mat("8_diamonds.png");
            var templ = new Mat("diamonds_template.png");
            var dst = new Mat();
            SiftDetector(src, templ, dst, 0, 3, 0.04, 10, 0.6, 1.75);
            Cv2.ImShow("dst", dst);
            Cv2.ImShow("src", src);
            Cv2.ImShow("templ", templ);
            Cv2.WaitKey();
        }

        private static Scalar[] _Scalars = new[]
        {
            new Scalar(255, 0, 0),
            new Scalar(0, 255, 0),
            new Scalar(0, 0, 255),
            new Scalar(255, 255, 0),
            new Scalar(0, 255, 255),
            new Scalar(255, 0, 255),
        };

        public static void SiftDetector(Mat src, Mat templ, Mat dst,
            int nFeatures = 0,
            int nOctaveLayers = 3,
            double contrastThreshold = 0.04,
            double edgeThreshold = 10,
            double sigma = 1.6,
            double ratio_thresh = 0.75)
        {
            var detector = SIFT.Create(nFeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma);
            var descriptors_templ = new Mat();
            var descriptors_src = new Mat();
            detector.DetectAndCompute(templ, null, out var keypoints_templ, descriptors_templ);
            detector.DetectAndCompute(src, null, out var keypoints_src, descriptors_src);

            var matcher = new FlannBasedMatcher();

            src.CopyTo(dst);
            if (dst.Channels() == 1)
            {
                Cv2.CvtColor(dst, dst, ColorConversionCodes.GRAY2BGR);
            }

            for (int j = 0; j < 5; j++)
            {
                var knn_matches = matcher.KnnMatch(descriptors_templ, descriptors_src, 2);

                //-- Filter matches using the Lowe's ratio test            
                var good_matches = new List<DMatch>();
                for (var i = 0; i < knn_matches.Length; i++)
                {
                    if (knn_matches[i][0].Distance < ratio_thresh * knn_matches[i][1].Distance)
                    {
                        good_matches.Add(knn_matches[i][0]);
                    }
                }

                if (good_matches.Count < 4)
                {
                    break;
                }

                var dstPts = new List<Point2d>();
                var srcPts = new List<Point2d>();
                for (var i = 0; i < good_matches.Count; i++)
                {
                    dstPts.Add(keypoints_templ[good_matches[i].QueryIdx].Pt.ToPoint2d());
                    srcPts.Add(keypoints_src[good_matches[i].TrainIdx].Pt.ToPoint2d());
                }

                Mat H = Cv2.FindHomography(dstPts, srcPts, HomographyMethods.Ransac);

                if (H.Cols != 0)
                {
                    var obj_corners = new Point2d[4];
                    obj_corners[0] = new Point2d(0, 0);
                    obj_corners[1] = new Point2d(templ.Cols, 0);
                    obj_corners[2] = new Point2d(templ.Cols, templ.Rows);
                    obj_corners[3] = new Point2d(0, templ.Rows);
                    var scene_corners = Cv2.PerspectiveTransform(obj_corners, H);

                    var drawingPoints = scene_corners.Select(p => (Point)p).ToArray();
                    Cv2.Polylines(dst, new[] { drawingPoints }, true, Scalar.Lime, 4);
                }

                foreach (var match in srcPts)
                {
                    dst.Circle(match.ToPoint(), 5, _Scalars[j % _Scalars.Length], 2);
                }

                var toRemove = good_matches.Select(p => p.TrainIdx).Distinct().ToList();

                foreach (var row in toRemove)
                {
                    descriptors_src.Row(row).SetTo(new Scalar(float.MaxValue, float.MaxValue, float.MaxValue));
                }
            }
        }
    }

    static class Extentions
    {
        public static Point2d ToPoint2d(this Point2f point2F)
        {
            return new Point2d(point2F.X, point2F.Y);
        }
    }
}

在这段代码中,我搜索匹配项,在找到的对象周围绘制,然后删除匹配项并再次搜索。

结果是:

问题是我如何找到所有的钻石,而不仅仅是第一颗?

SIFT
不是必需的,
SURF
或任何类似的算法也是可能的。

使用 Python 的答案也将不胜感激。

python c# opencv computer-vision sift
© www.soinside.com 2019 - 2024. All rights reserved.