Как избежать поворота ректов, обнаруженных MinAreaRect? - PullRequest
1 голос
/ 08 октября 2019

Я пытаюсь обнаружить текстовые поля в форме Windows, но CvInvoke.MinAreaRect(contour) возвращает прямоугольник, повернутый на -7.29419661 Угол. enter image description here

Мой код

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

Исходное изображение:

enter image description here

Если я раскомментирую раздел

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

Размеры обнаруженных рец аналогичны размерам полей ...

Скажите, пожалуйста, почему возвращаемые ректы вращаются и как это исправить?

1 Ответ

2 голосов
/ 08 октября 2019

В выводе 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);
...