Estoy tratando de detectar campos de texto en Windows Form pero CvInvoke.MinAreaRect(contour) devuelve un rectángulo, rotado por -7.29419661 Ángulo. ingrese la descripción de la imagen aquí

Mi código es

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

La imagen original es:

enter image description here

Si quito el comentario de la sección

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

Los tamaños de las reacciones detectadas son similares a los tamaños de los campos ...

Dígame, por favor, ¿por qué se rotan los rectos devueltos y cómo solucionarlo?

1
Arthur 8 oct. 2019 a las 12:37

1 respuesta

La mejor respuesta

Puede ver en la salida de Canny que el algoritmo está interpretando las sombras como bordes. La forma más sencilla de solucionarlo es prefiltrar la imagen con un umbral con un valor alto cercano al blanco del fondo del cuadro.

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);
2
Carlos Sanmartín Bustos 8 oct. 2019 a las 13:10