【问题标题】:How to avoid rotation of rects, detected by MinAreaRect?如何避免由 MinAreaRect 检测到的矩形旋转?
【发布时间】:2019-10-08 21:10:19
【问题描述】:

我正在尝试检测 Windows 窗体上的文本字段,但 CvInvoke.MinAreaRect(contour) 返回矩形,旋转了 -7.29419661 角度。

我的代码是

        Image<Bgr, Byte> a =
          new Image<Bgr, byte>(@"d:/Art/documents/Projects/InputFieldsDetector/Images/Form345_1.PNG");

        imageBox1.Image = a;

        UMat grayed = new UMat();
        CvInvoke.CvtColor(a, grayed, ColorConversion.Bgr2Gray);
        imageBox2.Image = grayed;

        UMat canny = new UMat();
        CvInvoke.Canny(grayed, canny, 50, 200, 3);
        imageBox3.Image = canny;

        VectorOfVectorOfPoint cnts = new VectorOfVectorOfPoint();

        UMat hierarchy = new UMat();
        CvInvoke.FindContours(canny, cnts, null, RetrType.Tree, ChainApproxMethod.ChainApproxSimple);

        Image<Bgr, Byte> justCountor = a.Clone();

        List<string> sizes = new List<string>();

        int count = cnts.Size;
        for (int i = 0; i < count; i++)
        {
            VectorOfPoint contour = cnts[i];
            var area = CvInvoke.ContourArea(contour);
            //if (area > 10000 && area < 15000)
            if (area > 200 && area < 300)
            {
                sizes.Add(area.ToString());

                Point[] pts = contour.ToArray();
                var forDraw = CvInvoke.MinAreaRect(contour);
                // forDraw.Angle = 0;
                //forDraw.Center.Y += 10;

                justCountor.Draw(forDraw, new Bgr(Color.DarkOrange), 2);
            }
        }
        imageBox4.Image = justCountor;

        List<double> result = sizes.Select(x => double.Parse(x)).ToList();

        result.Sort();
        sizes = result.Select(x => x.ToString()).ToList();

        File.WriteAllLines("c:/temp/qqq.txt", sizes);

原图为:

如果我取消注释部分

            forDraw.Angle = 0;
            forDraw.Center.Y += 10;

检测到的矩形大小与字段大小相似...

请告诉我,为什么返回的矩形被旋转以及如何解决这个问题?

【问题讨论】:

    标签: c# opencv image-processing opencv3.0 emgucv


    【解决方案1】:

    您可以在 Canny 输出中看到该算法将阴影解释为边框。解决此问题的最简单方法是使用接近框背景白色的高值阈值对图像进行预过滤。

    Image<Bgr, Byte> a =
                  new Image<Bgr, byte>(@"d:/Art/documents/Projects/InputFieldsDetector/Images/Form345_1.PNG");
    
    imageBox1.Image = a;
    
    UMat grayed = new UMat();
    CvInvoke.CvtColor(a, grayed, ColorConversion.Bgr2Gray);
    imageBox2.Image = grayed;
    
    UMat thresholded = new UMat();
    CvInvoke.Threshold(grayed, thresholded, 128, 255, ThresholdType.Binary);
    imageBox5.Image = thresholded;
    
    UMat canny = new UMat();
    CvInvoke.Canny(thresholded, canny, 50, 200, 3);
    imageBox3.Image = canny;
    
    VectorOfVectorOfPoint cnts = new VectorOfVectorOfPoint();
    
    UMat hierarchy = new UMat();
    CvInvoke.FindContours(canny, cnts, null, RetrType.Tree, ChainApproxMethod.ChainApproxSimple);
    
    Image<Bgr, Byte> justCountor = a.Clone(); 
    List<string> sizes = new List<string>(); 
    int count = cnts.Size;
    for (int i = 0; i < count; i++)
    {
        VectorOfPoint contour = cnts[i];
        var area = CvInvoke.ContourArea(contour);
        if (area > 200 && area < 300)
        {
            sizes.Add(area.ToString());
            Point[] pts = contour.ToArray();
            var forDraw = CvInvoke.MinAreaRect(contour);
    
            // forDraw.Angle = 0;
            //forDraw.Center.Y += 10;
    
            if (forDraw.Angle==0)
                justCountor.Draw(forDraw, new Bgr(Color.DarkOrange), 2);
        }
    }
    imageBox4.Image = justCountor;
    
    List<double> result = sizes.Select(x => double.Parse(x)).ToList();
    result.Sort();
    sizes = result.Select(x => x.ToString()).ToList();
    File.WriteAllLines("c:/temp/qqq.txt", sizes);
    

    【讨论】:

    • 我尝试将 CvInvoke.Canny(grayed, canny, 10, 10, 3); 中的值从 10 更改为 700,但在大多数情况下,矩形被旋转或未检测到(对于最高值,类似于 700)。看起来阈值并没有解决问题
    • 我觉得 Canny 没问题。我的意思是你应该在 Canny 之前使用 CvInvoke.Threshold 来只获取白框。
    • 哇,伙计,哇!你真是天才!非常感谢!你能改变你的答案吗?请将此代码添加到您的答案中,以便其他人更好地理解 - pastebin.com/ZBxf68Bb
    • 有趣,为什么如果图像是代码UMat grayed = new UMat(); CvInvoke.CvtColor(a, grayed, ColorConversion.Bgr2Gray); imageBox2.Image = grayed; UMat thresholded = new UMat(); CvInvoke.Threshold(grayed, thresholded, 128, 255, ThresholdType.Binary); imageBox5.Image = thresholded; UMat canny = new UMat(); CvInvoke.Canny(thresholded, canny, 50, 200, 3); imageBox3.Image = canny; 的阈值,现在它会将每个字段检测为两个矩形 - 一个具有 Angle=0,另一个具有 Angle!=0?
    • 可能还是影子,试着像这样提升门槛水平:CvInvoke.Threshold(grayed, thresholded, 230, 255, ThresholdType.Binary);
    猜你喜欢
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-14
    相关资源
    最近更新 更多