OpenCv:查找多个匹配项

时间:2012-09-08 05:58:56

标签: c# opencv opencvsharp

我有以下内容,但我无法弄清楚如何在源图像中找到所有匹配项。

    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 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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);
        }
    }
}

答案 2 :(得分: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);
    }     

}

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