【问题标题】:OpenCv: Finding multiple matchesOpenCv:查找多个匹配项
【发布时间】:2012-09-01 22:44:02
【问题描述】:

我有以下内容,但我不知道如何在源图像中找到所有匹配项。

    static void Main()
    {
        using (var template = Cv.LoadImage(@"images\logo.png", LoadMode.GrayScale))
        using (var source = Cv.LoadImage(@"images\manyLogos.png", LoadMode.GrayScale))
        using (var sourceColour = Cv.LoadImage(@"images\manyLogos.png", LoadMode.Color))
        {
            var width = source.Width - template.Width + 1;
            var height = source.Height - template.Height + 1;
            using (var result = Cv.CreateImage(Cv.Size(width, height), BitDepth.F32, 1))
            {
                Cv.MatchTemplate(source, template, result, MatchTemplateMethod.SqDiff);
                var THRESHOLD = 0.08D;

                double minVal, maxVal;
                CvPoint minLoc, maxLoc;                    
                Cv.MinMaxLoc(result, out minVal, out maxVal, out minLoc, out maxLoc);

                var outlineColor = (minVal > THRESHOLD) ? CvColor.Green : CvColor.Red;
                Cv.Rectangle(sourceColour, Cv.Point(minLoc.X, minLoc.Y), Cv.Point(minLoc.X + template.Width, minLoc.Y + template.Height), outlineColor, 1, 0, 0);
            }

            using (var window = new CvWindow("Test"))
            {
                while (CvWindow.WaitKey(10) < 0)
                {
                    window.Image = sourceColour;
                }
            }
        }
    }

我可以概述最佳匹配,但不是所有匹配。我需要以某种方式获得所有匹配项。

【问题讨论】:

    标签: c# opencv opencvsharp


    【解决方案1】:

    这里是使用 Min_Max 和 Match_Template 方法的解决方案。希望它会有所帮助。

     public void multipleTemplateMatch(string SourceImages, string tempImage)
        {            
            Image<Bgr, byte> image_source = new Image<Bgr, byte>(SourceImages);
            Image<Bgr, byte> image_partial1 = new Image<Bgr, byte>(tempImage);
    
            double threshold = 0.9;
            ImageFinder imageFinder = new ImageFinder(image_source, image_partial1, threshold);
            imageFinder.FindThenShow();
    
        }   
    

    这是可以提供帮助的课程。

    class ImageFinder
    {
        private List<Rectangle> rectangles;  
        public Image<Bgr, byte> BaseImage { get; set; }
        public Image<Bgr, byte> SubImage { get; set; }
        public Image<Bgr, byte> ResultImage { get; set; }
        public double Threashold { get; set; }        
    
        public List<Rectangle> Rectangles
        {
            get { return rectangles; }
        }
    
        public ImageFinder(Image<Bgr, byte> baseImage, Image<Bgr, byte> subImage, double threashold)
        {
            rectangles = new List<Rectangle>();            
            BaseImage = baseImage;
            SubImage = subImage;
            Threashold = threashold;            
        }
    
        public void FindThenShow()
        {
            FindImage();
            DrawRectanglesOnImage();
            ShowImage();
        }
    
        public void DrawRectanglesOnImage()
        {
            ResultImage = BaseImage.Copy();
            foreach (var rectangle in this.rectangles)
            {
                ResultImage.Draw(rectangle, new Bgr(Color.Blue), 1);
            }
        }
    
        public void FindImage()
        {          
            rectangles = new List<Rectangle>();           
    
            using (Image<Bgr, byte> imgSrc = BaseImage.Copy())
            {
                while (true)
                {
                    using (Image<Gray, float> result = imgSrc.MatchTemplate(SubImage, TemplateMatchingType.CcoeffNormed))
                    {
                        double[] minValues, maxValues;
                        Point[] minLocations, maxLocations;
                        result.MinMax(out minValues, out maxValues, out minLocations, out maxLocations);
    
                        if (maxValues[0] > Threashold)
                        {
                            Rectangle match = new Rectangle(maxLocations[0], SubImage.Size);
                            imgSrc.Draw(match, new Bgr(Color.Blue), -1);
                            rectangles.Add(match);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }          
    
        }
    
        public void ShowImage()
        {
            Random rNo = new Random();
            string outFilename = "matched Templates" + rNo.Next();            
            CvInvoke.Imshow(outFilename, ResultImage);
        }     
    
    }
    

    如果您觉得这有帮助,请投票同样有用。 谢谢

    【讨论】:

      【解决方案2】:

      从 C++ 翻译并使用 OpenCvSharp 包装器,上面的代码替换了 minMaxLoc 行,对我有用:

      double threshold=0.9
      var thresholdImage=Cv.CreateImage(newImageSize, BitDepth.F32,1);
      Cv.Threshold(result, thresholdImage, threshold, 255, ThresholdType.Binary);
      for (int r = 0; r < thresholdImage.GetSize().Height; r++)
      {
          for (int c = 0; c < thresholdImage.GetSize().Width; c++)
          {
              if (thresholdImage.GetRow(r)[c].Val0 > 0)
              {
                  Cv.Rectangle(soruceColour, Cv.Point(c, r), Cv.Point(c + template.Width, r + template.Height), CvColor.Red, 1, 0, 0);
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        使用 matchTemplate 方法,您的输出图像将为您提供像素值,这些像素值表示您的模板在此特定位置的匹配程度。在您的情况下,值越低,匹配效果越好,因为您使用了 MatchTemplateMethod.SqDiff。

        你的问题是,当你使用 minMaxLoc 函数时,你会得到你所要求的,在这种情况下,这是最好的匹配,即 min)。

        所有匹配项都是其值低于您设置的阈值的像素。 由于我不习惯 csharp,这里是它在 C++ 中的用法,你可以进行翻译:

        // after your call to MatchTemplate
        float threshold = 0.08;
        cv::Mat thresholdedImage;
        cv::threshold(result, thresholdedImage, threshold, 255, CV_THRESH_BINARY);
        // the above will set pixels to 0 in thresholdedImage if their value in result is lower than the threshold, to 255 if it is larger.
        // in C++ it could also be written cv::Mat thresholdedImage = result < threshold;
        // Now loop over pixels of thresholdedImage, and draw your matches
        for (int r = 0; r < thresholdedImage.rows; ++r) {
          for (int c = 0; c < thresholdedImage.cols; ++c) {
            if (!thresholdedImage.at<unsigned char>(r, c)) // = thresholdedImage(r,c) == 0
              cv::circle(sourceColor, cv::Point(c, r), template.cols/2, CV_RGB(0,255,0), 1);
          }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-12-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-17
          相关资源
          最近更新 更多