C# 使用emguCV 3.1.0在图像集合中查找匹配图像

C# 使用emguCV 3.1.0在图像集合中查找匹配图像,c#,opencv,emgucv,flann,C#,Opencv,Emgucv,Flann,我正在做一个项目,从图像集合中识别图像的相似性百分比。我使用了EmugCV 3.1.0。代码如下所示。虽然程序运行,但它有以下问题 找到匹配项时,始终显示第一个图像的百分比。找到附件 如果我们将同一图像两次放入dbimage collection,并将该图像作为查询图像,则所有匹配百分比为零。找到附件 字符串[]dbImages={imgPath+1.jpg,imgPath+2.jpg,imgPath+3.jpg,imgPath+4.jpg}; 字符串queryImage=imgPath+4.j

我正在做一个项目,从图像集合中识别图像的相似性百分比。我使用了EmugCV 3.1.0。代码如下所示。虽然程序运行,但它有以下问题

找到匹配项时,始终显示第一个图像的百分比。找到附件 如果我们将同一图像两次放入dbimage collection,并将该图像作为查询图像,则所有匹配百分比为零。找到附件

字符串[]dbImages={imgPath+1.jpg,imgPath+2.jpg,imgPath+3.jpg,imgPath+4.jpg}; 字符串queryImage=imgPath+4.jpg

在这些图像中,图像2和4是相同的

代码如下所示

    public partial class Form1 : Form
    {
        private static double surfHessianThresh = 300;
        private static SURF detector;
        public Form1()
        {
            InitializeComponent();
            ImageMatching();
        }

        public void ImageMatching()
        {
            string MatchString = null;
            detector = new SURF(surfHessianThresh);
            IList<IndecesMapping> matches = Match();
            IOrderedEnumerable<IndecesMapping> orderedMatches = matches.OrderByDescending(match => match.Similarity);

            foreach (IndecesMapping match in orderedMatches)
            {
                MatchString = MatchString + "\n" + match.ToString();
            }
            lblMatch.Text = MatchString;
            //Console.WriteLine();
            //Console.WriteLine("MOST LIKELY MATCH: " + orderedMatches.First());

            //Console.WriteLine("Press enter to exit...");
            //Console.ReadLine();
        }

        /// <summary>
        /// Main method.
        /// </summary>
        static public IList<IndecesMapping> Match()
        {

            string imgPath = "E:\\Riyas\\Projects\\Image Recognition\\Sample Projects\\EmguSample3.1.0\\EmguSample3.1.0\\";
            string[] dbImages = { imgPath + "1.jpg", imgPath + "2.jpg", imgPath + "3.jpg", imgPath + "4.jpg" };
            string queryImage = imgPath + "1.jpg";

            IList<IndecesMapping> imap;

            // compute descriptors for each image
            var dbDescsList = ComputeMultipleDescriptors(dbImages, out imap);

            // concatenate all DB images descriptors into single Matrix
            Matrix<float> dbDescs = ConcatDescriptors(dbDescsList);

            // compute descriptors for the query image
            Matrix<float> queryDescriptors = ComputeSingleDescriptors(queryImage);

            FindMatches(dbDescs, queryDescriptors, ref imap);

            return imap;
        }

        /// <summary>
        /// Computes image descriptors.
        /// </summary>
        /// <param name="fileName">Image filename.</param>
        /// <returns>The descriptors for the given image.</returns>
        static public Matrix<float> ComputeSingleDescriptors(string fileName)
        {
            Matrix<float> descs = null;
            using (Image<Gray, Byte> img = new Image<Gray, byte>(fileName))
            {
                MKeyPoint[] mkeyPoints = detector.Detect(img, null);
                VectorOfKeyPoint keyPoints = new VectorOfKeyPoint();
                keyPoints.Push(mkeyPoints);

                UMat observedDescriptors = new UMat();
                detector.Compute(img, keyPoints, observedDescriptors);
                descs = new Matrix<float>(observedDescriptors.Size);
                detector.Compute(img, keyPoints, descs);
            }

            return descs;
        }


        /// <summary>
        /// Convenience method for computing descriptors for multiple images.
        /// On return imap is filled with structures specifying which descriptor ranges in the concatenated matrix belong to what image.
        /// </summary>
        /// <param name="fileNames">Filenames of images to process.</param>
        /// <param name="imap">List of IndecesMapping to hold descriptor ranges for each image.</param>
        /// <returns>List of descriptors for the given images.</returns>
        static public IList<Matrix<float>> ComputeMultipleDescriptors(string[] fileNames, out IList<IndecesMapping> imap)
        {
            imap = new List<IndecesMapping>();

            IList<Matrix<float>> descs = new List<Matrix<float>>();

            int r = 0;

            for (int i = 0; i < fileNames.Length; i++)
            {
                var desc = ComputeSingleDescriptors(fileNames[i]);
                descs.Add(desc);

                imap.Add(new IndecesMapping()
                {
                    fileName = fileNames[i],
                    IndexStart = r,
                    IndexEnd = r + desc.Rows - 1
                });

                r += desc.Rows;
            }

            return descs;
        }


        /// <summary>
        /// Computes 'similarity' value (IndecesMapping.Similarity) for each image in the collection against our query image.
        /// </summary>
        /// <param name="dbDescriptors">Query image descriptor.</param>
        /// <param name="queryDescriptors">Consolidated db images descriptors.</param>
        /// <param name="images">List of IndecesMapping to hold the 'similarity' value for each image in the collection.</param>
        static public void FindMatches(Matrix<float> dbDescriptors, Matrix<float> queryDescriptors, ref IList<IndecesMapping> imap)
        {
            var indices = new Matrix<int>(queryDescriptors.Rows, 2); // matrix that will contain indices of the 2-nearest neighbors found
            var dists = new Matrix<float>(queryDescriptors.Rows, 2); // matrix that will contain distances to the 2-nearest neighbors found

            // create FLANN index with 4 kd-trees and perform KNN search over it look for 2 nearest neighbours
            KdTreeIndexParamses kdparam = new KdTreeIndexParamses(4);

            var flannIndex = new Index(dbDescriptors, kdparam);
            flannIndex.KnnSearch(queryDescriptors, indices, dists, 2, 24);

            for (int i = 0; i < indices.Rows; i++)
            {
                // filter out all inadequate pairs based on distance between pairs
                if (dists.Data[i, 0] < (0.6 * dists.Data[i, 1]))
                {
                    // find image from the db to which current descriptor range belongs and increment similarity value.
                    // in the actual implementation this should be done differently as it's not very efficient for large image collections.
                    foreach (var img in imap)
                    {
                        if (img.IndexStart <= i && img.IndexEnd >= i)
                        {
                            img.Similarity++;
                            break;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Concatenates descriptors from different sources (images) into single matrix.
        /// </summary>
        /// <param name="descriptors">Descriptors to concatenate.</param>
        /// <returns>Concatenated matrix.</returns>
        static public Matrix<float> ConcatDescriptors(IList<Matrix<float>> descriptors)
        {
            int cols = descriptors[0].Cols;
            int rows = descriptors.Sum(a => a.Rows);

            float[,] concatedDescs = new float[rows, cols];

            int offset = 0;

            foreach (var descriptor in descriptors)
            {
                // append new descriptors
                Buffer.BlockCopy(descriptor.ManagedArray, 0, concatedDescs, offset, sizeof(float) * descriptor.ManagedArray.Length);
                offset += sizeof(float) * descriptor.ManagedArray.Length;
            }

            return new Matrix<float>(concatedDescs);
        }
    }

    public class IndecesMapping
    {
        public int IndexStart { get; set; }
        public int IndexEnd { get; set; }
        public int Similarity { get; set; }
        public string fileName { get; set; }

        public override string ToString()
        {
            return fileName + ": " + Similarity + "%";
        }
    }

以下是艾哈迈德博客的完整解决方案