OpenCv: поиск нескольких совпадений

У меня есть следующее, но я не могу понять, как найти ВСЕ совпадения в исходном изображении.

    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;
                }
            }
        }
    }

Я могу выделить лучший матч, но не все. Мне нужно как-то получить все спички.

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);
  }
}

Приведенный выше код, заменяющий строки minMaxLoc, сработал с переводом с C++ и использованием оболочки OpenCvSharp:

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);
        }
    }
}

Вот решение с использованием методов 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);
    }     

}

если вы найдете это полезным, пожалуйста, проголосуйте так же полезно. Спасибо

Другие вопросы по тегам