【问题标题】:OpenCVSharp - Compare images - Sift/Surf/Hash/OrbOpenCVSharp - 比较图像 - Sift/Surf/Hash/Orb
【发布时间】:2021-06-07 14:57:28
【问题描述】:

我知道这个话题在互联网上被广泛讨论,但是我找不到我的问题的答案......

所以我的最终目标是提取图像的一部分并将其与“模板”进行比较。 我已经提取并裁剪了图像的一部分,所以这不是问题。

我遇到的问题是尝试将其与模板进行比较。模板最初是 SVG,所以我将其转换为 JPG 并删除了 alpha 通道。

模板:

实际图像取自网络摄像头,因此它是彩色的,但我可以轻松设置阈值以仅保留黑色/白色。

网络摄像头图像:

带有阈值的网络摄像头图像

所以我尝试了 3 种方法。

1. SIFT algorithm. 
 

private void MatchBySift(Mat src1, Mat src2)

        {

            var gray1 = new Mat();
            var gray2 = new Mat();

            Cv2.CvtColor(src1, gray1, ColorConversionCodes.BGR2GRAY);
            Cv2.CvtColor(src2, gray2, ColorConversionCodes.BGR2GRAY);

            var sift = SIFT.Create();

            // Detect the keypoints and generate their descriptors using SIFT
            KeyPoint[] keypoints1, keypoints2;
            var descriptors1 = new Mat();   //<float>
            var descriptors2 = new Mat();   //<float>
            sift.DetectAndCompute(gray1, null, out keypoints1, descriptors1);
            sift.DetectAndCompute(gray2, null, out keypoints2, descriptors2);

            // Match descriptor vectors
            var bfMatcher = new BFMatcher(NormTypes.L2, false);
            var flannMatcher = new FlannBasedMatcher();
            DMatch[] bfMatches;
            DMatch[] flannMatches;
            try
            {
                bfMatches = bfMatcher.Match(descriptors1, descriptors2);
                flannMatches = flannMatcher.Match(descriptors1, descriptors2);
            }
            catch
            {
                bfMatches = new DMatch[0];
                flannMatches = new DMatch[0];
            }
            

            // Draw matches
            var bfView = new Mat();
            Cv2.DrawMatches(gray1, keypoints1, gray2, keypoints2, bfMatches, bfView);
            var flannView = new Mat();
            Cv2.DrawMatches(gray1, keypoints1, gray2, keypoints2, flannMatches, flannView);
            Console.WriteLine("BF Matches: " + bfMatches.Length);
            Console.WriteLine("Flann Matches: " + flannMatches.Length);
            
            using (new Window("SIFT matching (by BFMather)", bfView))
            using (new Window("SIFT matching (by FlannBasedMatcher)", flannView))
            {
                Cv2.WaitKey();
            }
            
        }

2. SURF Algorithm

    private void MatchBySurf(Mat src1, Mat src2)
            {
                var gray1 = new Mat();
                var gray2 = new Mat();
    
                Cv2.CvtColor(src1, gray1, ColorConversionCodes.BGR2GRAY);
                Cv2.CvtColor(src2, gray2, ColorConversionCodes.BGR2GRAY);
    
                var surf = SURF.Create(200, 4, 2, true);
    
                // Detect the keypoints and generate their descriptors using SURF
                KeyPoint[] keypoints1, keypoints2;
                var descriptors1 = new Mat();   //<float>
                var descriptors2 = new Mat();   //<float>
                surf.DetectAndCompute(gray1, null, out keypoints1, descriptors1);
                surf.DetectAndCompute(gray2, null, out keypoints2, descriptors2);
    
                // Match descriptor vectors 
                var bfMatcher = new BFMatcher(NormTypes.L2, false);
                var flannMatcher = new FlannBasedMatcher();
                DMatch[] bfMatches;
                DMatch[] flannMatches;
                try
                {
                    bfMatches = bfMatcher.Match(descriptors1, descriptors2);
                    flannMatches = flannMatcher.Match(descriptors1, descriptors2);
                }
                catch
                {
                    bfMatches = new DMatch[0];
                    flannMatches = new DMatch[0];
                }
    
                // Draw matches
                var bfView = new Mat();
                Cv2.DrawMatches(gray1, keypoints1, gray2, keypoints2, bfMatches, bfView);
                var flannView = new Mat();
                Cv2.DrawMatches(gray1, keypoints1, gray2, keypoints2, flannMatches, flannView);
    
                Console.WriteLine("BF Matches: " + bfMatches.Length);
                Console.WriteLine("Flann Matches: " + flannMatches.Length);
                /*
                using (new Window("SURF matching (by BFMather)", bfView))
                using (new Window("SURF matching (by FlannBasedMatcher)", flannView))
                {
                    Cv2.WaitKey();
                }
                */
            }

3. Hash comparison

    private void MatchByHash(Mat src1, Mat src2)
            {
                Bitmap bit1 = BitmapConverter.ToBitmap(src1);
                Bitmap bit2 = BitmapConverter.ToBitmap(src2);
                List<bool> hash1 = GetHash(bit1);
                List<bool> hash2 = GetHash(bit2);
    
                int equalElements = hash1.Zip(hash2, (i, j) => i == j).Count(eq => eq);
    
                Console.WriteLine("Match by Hash: " + equalElements);
            }
    
            public List<bool> GetHash(Bitmap bmpSource)
            {
                List<bool> lResult = new List<bool>();
                //create new image with 16x16 pixel
                Bitmap bmpMin = new Bitmap(bmpSource, new System.Drawing.Size(16, 16));
                for (int j = 0; j < bmpMin.Height; j++)
                {
                    for (int i = 0; i < bmpMin.Width; i++)
                    {
                        //reduce colors to true / false                
                        lResult.Add(bmpMin.GetPixel(i, j).GetBrightness() < 0.5f);
                    }
                }
                return lResult;
            }

为什么我对结果不满意

  1. SIFT 和 SURF

比较上述图像时,我会根据匹配数得到一定的相似性。问题是当我使用不同的template image 时,我总是得到相同的数字......我认为这是因为没有颜色,但我需要在这里澄清

  1. 哈希

在其他“模板”上使用时,我得到了更高的结果!这基本上消除了这种方法,除非它可以以某种方式改进......

我也听说过 ORB 算法,但我还没有尝试实现它。这在我的场合会更好吗?

如果我可以尝试任何其他方法,请指出正确的方向!

谢谢

【问题讨论】:

    标签: c# opencv image-processing image-comparison


    【解决方案1】:

    主要是注册标志和模板。由于您的图像是准二进制并且仅包含徽标,因此您可以依赖矩的计算。您将为二值化图像和二值化模板计算它们。

    黑色像素的零阶矩是面积。面积比的平方根为您提供比例因子。

    Y 时刻的一阶 X 为您提供参考点(质心)的位置,这在两者中都是相同的。

    然后居中的二阶矩(X²、Y²、XY)将为您提供两个主要方向(通过计算惯性张量的特征向量),并由此得出徽标和模板之间的旋转角度。

    https://www.ae.msstate.edu/vlsm/shape/area_moments_of_inertia/papmi.htm

    现在您可以重新缩放、旋转和平移徽标或模板以叠加它们。您将通过简单地计算匹配颜色的像素来获得比较分数。

    【讨论】:

    • 我查看了链接,但我无法理解如何实现它。我想我不完全理解你的答案背后的“时刻”和总体思路...有没有能否提供给我一个代码示例?
    • @aberforth:没机会,对不起。
    猜你喜欢
    • 2015-07-02
    • 2019-06-03
    • 1970-01-01
    • 2019-06-29
    • 2013-04-06
    • 1970-01-01
    • 2021-03-31
    • 1970-01-01
    • 2016-06-26
    相关资源
    最近更新 更多