procesamiento de imágenes para mejorar la precisión del OCR tesseract


He estado usando tesseract para convertir documentos en texto. La calidad de los documentos varía enormemente, y estoy buscando consejos sobre qué tipo de procesamiento de imágenes podría mejorar los resultados. He notado que el texto que está altamente pixelado - por ejemplo, el generado por las máquinas de fax - es especialmente difícil de procesar para tesseract-presumiblemente todos esos bordes dentados de los caracteres confunden los algoritmos de reconocimiento de formas.

¿Qué tipo de técnicas de procesamiento de imágenes mejorar la precisión? He estado usando un desenfoque gaussiano para suavizar las imágenes pixeladas y he visto algunas pequeñas mejoras, pero espero que haya una técnica más específica que produzca mejores resultados. Por ejemplo, un filtro que se ajustó a imágenes en blanco y negro, que suavizaría los bordes irregulares, seguido de un filtro que aumentaría el contraste para hacer que los caracteres fueran más distintos.

¿Algún consejo general para alguien que es un novato en el procesamiento de imágenes?

Author: JAL, 2012-02-28

12 answers

  1. fijar DPI (si es necesario) 300 DPI es mínimo
  2. corregir el tamaño del texto (por ejemplo, 12 pt debe estar bien)
  3. trate de arreglar las líneas de texto (deskew y dewarp texto)
  4. trate de fijar la iluminación de la imagen (por ejemplo, ninguna parte oscura de la imagen)
  5. binarizar y eliminar el ruido de la imagen

No hay una línea de comandos universal que se ajuste a todos los casos (a veces necesita desenfocar y enfocar la imagen). Pero puedes probar TEXTCLEANER desde los scripts ImageMagick de Fred.

Si usted no es fan de la línea de comandos, tal vez usted puede tratar de utilizar el código abierto scantailor.sourceforge.net o comercial bookrestorer.

 73
Author: user898678,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-20 09:51:15

De ninguna manera soy un experto en OCR. Pero esta semana tuve necesidad de convertir texto de un jpg.

Empecé con un coloreado, RGB 445x747 pixel jpg. Inmediatamente intenté tesseract en esto, y el programa convirtió casi nada. Luego entré en GIMP e hice lo siguiente. imagen > modo>escala de grises imagen > escala de imagen > 1191x2000 píxeles filtros > mejorar > máscara de desenfoque con valores de radio = 6.8, cantidad = 2.69, umbral = 0 Luego guardé como un nuevo jpg al 100% de calidad.

Teseracto entonces fue capaz de extraer todo el texto en una .txt file

Gimp es tu amigo.

 63
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-24 18:45:55

Tres puntos para mejorar la legibilidad de la imagen: 1) Redimensionar la imagen con altura y anchura variables (multiplicar 0.5 y 1 y 2 con altura y anchura de la imagen). 2) Convertir la imagen a formato de escala de grises (Blanco y negro). 3) Eliminar los píxeles de ruido y hacer más claro(Filtrar la imagen).

Refiérase al siguiente código:

//Resize
  public Bitmap Resize(Bitmap bmp, int newWidth, int newHeight)
        {

                Bitmap temp = (Bitmap)bmp;

                Bitmap bmap = new Bitmap(newWidth, newHeight, temp.PixelFormat);

                double nWidthFactor = (double)temp.Width / (double)newWidth;
                double nHeightFactor = (double)temp.Height / (double)newHeight;

                double fx, fy, nx, ny;
                int cx, cy, fr_x, fr_y;
                Color color1 = new Color();
                Color color2 = new Color();
                Color color3 = new Color();
                Color color4 = new Color();
                byte nRed, nGreen, nBlue;

                byte bp1, bp2;

                for (int x = 0; x < bmap.Width; ++x)
                {
                    for (int y = 0; y < bmap.Height; ++y)
                    {

                        fr_x = (int)Math.Floor(x * nWidthFactor);
                        fr_y = (int)Math.Floor(y * nHeightFactor);
                        cx = fr_x + 1;
                        if (cx >= temp.Width) cx = fr_x;
                        cy = fr_y + 1;
                        if (cy >= temp.Height) cy = fr_y;
                        fx = x * nWidthFactor - fr_x;
                        fy = y * nHeightFactor - fr_y;
                        nx = 1.0 - fx;
                        ny = 1.0 - fy;

                        color1 = temp.GetPixel(fr_x, fr_y);
                        color2 = temp.GetPixel(cx, fr_y);
                        color3 = temp.GetPixel(fr_x, cy);
                        color4 = temp.GetPixel(cx, cy);

                        // Blue
                        bp1 = (byte)(nx * color1.B + fx * color2.B);

                        bp2 = (byte)(nx * color3.B + fx * color4.B);

                        nBlue = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        // Green
                        bp1 = (byte)(nx * color1.G + fx * color2.G);

                        bp2 = (byte)(nx * color3.G + fx * color4.G);

                        nGreen = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        // Red
                        bp1 = (byte)(nx * color1.R + fx * color2.R);

                        bp2 = (byte)(nx * color3.R + fx * color4.R);

                        nRed = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        bmap.SetPixel(x, y, System.Drawing.Color.FromArgb
                (255, nRed, nGreen, nBlue));
                    }
                }



                bmap = SetGrayscale(bmap);
                bmap = RemoveNoise(bmap);

                return bmap;

        }


//SetGrayscale
  public Bitmap SetGrayscale(Bitmap img)
        {

            Bitmap temp = (Bitmap)img;
            Bitmap bmap = (Bitmap)temp.Clone();
            Color c;
            for (int i = 0; i < bmap.Width; i++)
            {
                for (int j = 0; j < bmap.Height; j++)
                {
                    c = bmap.GetPixel(i, j);
                    byte gray = (byte)(.299 * c.R + .587 * c.G + .114 * c.B);

                    bmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
                }
            }
            return (Bitmap)bmap.Clone();

        }
//RemoveNoise
   public Bitmap RemoveNoise(Bitmap bmap)
        {

            for (var x = 0; x < bmap.Width; x++)
            {
                for (var y = 0; y < bmap.Height; y++)
                {
                    var pixel = bmap.GetPixel(x, y);
                    if (pixel.R < 162 && pixel.G < 162 && pixel.B < 162)
                        bmap.SetPixel(x, y, Color.Black);
                    else if (pixel.R > 162 && pixel.G > 162 && pixel.B > 162)
                        bmap.SetPixel(x, y, Color.White);
                }
            }

            return bmap;
        }

IMAGEN DE ENTRADA
IMAGEN DE ENTRADA

IMAGEN DE SALIDA IMAGEN DE SALIDA

 26
Author: Sathyaraj Palanisamy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-15 00:34:37

Esto es algo de hace, pero todavía podría ser útil.

Mi experiencia muestra que cambiar el tamaño de la imagen en memoria antes de pasarla a tesseract a veces ayuda.

Pruebe diferentes modos de interpolación. El post https://stackoverflow.com/a/4756906/146003 me ayudó mucho.

 16
Author: Atmocreations,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:32

Lo que fue EXTREMADAMENTE ÚTIL para mí de esta manera son los códigos fuente para el proyecto Capture2Text. http://sourceforge.net/projects/capture2text/files/Capture2Text/.

POR cierto: Felicitaciones a su autor por compartir un algoritmo tan minucioso.

Preste especial atención al archivo Capture2Text\SourceCode\leptonica_util\leptonica_util.c-esa es la esencia de la preprocesación de imágenes para esta utilidad.

Si va a ejecutar los binarios, puede comprobar la transformación de la imagen antes / después del proceso en la carpeta Capture2Text\Output\.

P.d. la solución mencionada utiliza Tesseract para OCR y Leptonica para preprocesamiento.

 13
Author: Wiseman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-21 12:13:00

Versión Java para el código de Sathyaraj anterior:

// Resize
public Bitmap resize(Bitmap img, int newWidth, int newHeight) {
    Bitmap bmap = img.copy(img.getConfig(), true);

    double nWidthFactor = (double) img.getWidth() / (double) newWidth;
    double nHeightFactor = (double) img.getHeight() / (double) newHeight;

    double fx, fy, nx, ny;
    int cx, cy, fr_x, fr_y;
    int color1;
    int color2;
    int color3;
    int color4;
    byte nRed, nGreen, nBlue;

    byte bp1, bp2;

    for (int x = 0; x < bmap.getWidth(); ++x) {
        for (int y = 0; y < bmap.getHeight(); ++y) {

            fr_x = (int) Math.floor(x * nWidthFactor);
            fr_y = (int) Math.floor(y * nHeightFactor);
            cx = fr_x + 1;
            if (cx >= img.getWidth())
                cx = fr_x;
            cy = fr_y + 1;
            if (cy >= img.getHeight())
                cy = fr_y;
            fx = x * nWidthFactor - fr_x;
            fy = y * nHeightFactor - fr_y;
            nx = 1.0 - fx;
            ny = 1.0 - fy;

            color1 = img.getPixel(fr_x, fr_y);
            color2 = img.getPixel(cx, fr_y);
            color3 = img.getPixel(fr_x, cy);
            color4 = img.getPixel(cx, cy);

            // Blue
            bp1 = (byte) (nx * Color.blue(color1) + fx * Color.blue(color2));
            bp2 = (byte) (nx * Color.blue(color3) + fx * Color.blue(color4));
            nBlue = (byte) (ny * (double) (bp1) + fy * (double) (bp2));

            // Green
            bp1 = (byte) (nx * Color.green(color1) + fx * Color.green(color2));
            bp2 = (byte) (nx * Color.green(color3) + fx * Color.green(color4));
            nGreen = (byte) (ny * (double) (bp1) + fy * (double) (bp2));

            // Red
            bp1 = (byte) (nx * Color.red(color1) + fx * Color.red(color2));
            bp2 = (byte) (nx * Color.red(color3) + fx * Color.red(color4));
            nRed = (byte) (ny * (double) (bp1) + fy * (double) (bp2));

            bmap.setPixel(x, y, Color.argb(255, nRed, nGreen, nBlue));
        }
    }

    bmap = setGrayscale(bmap);
    bmap = removeNoise(bmap);

    return bmap;
}

// SetGrayscale
private Bitmap setGrayscale(Bitmap img) {
    Bitmap bmap = img.copy(img.getConfig(), true);
    int c;
    for (int i = 0; i < bmap.getWidth(); i++) {
        for (int j = 0; j < bmap.getHeight(); j++) {
            c = bmap.getPixel(i, j);
            byte gray = (byte) (.299 * Color.red(c) + .587 * Color.green(c)
                    + .114 * Color.blue(c));

            bmap.setPixel(i, j, Color.argb(255, gray, gray, gray));
        }
    }
    return bmap;
}

// RemoveNoise
private Bitmap removeNoise(Bitmap bmap) {
    for (int x = 0; x < bmap.getWidth(); x++) {
        for (int y = 0; y < bmap.getHeight(); y++) {
            int pixel = bmap.getPixel(x, y);
            if (Color.red(pixel) < 162 && Color.green(pixel) < 162 && Color.blue(pixel) < 162) {
                bmap.setPixel(x, y, Color.BLACK);
            }
        }
    }
    for (int x = 0; x < bmap.getWidth(); x++) {
        for (int y = 0; y < bmap.getHeight(); y++) {
            int pixel = bmap.getPixel(x, y);
            if (Color.red(pixel) > 162 && Color.green(pixel) > 162 && Color.blue(pixel) > 162) {
                bmap.setPixel(x, y, Color.WHITE);
            }
        }
    }
    return bmap;
}
 12
Author: Fábio Silva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-20 01:37:59

El umbral adaptativo es importante si la iluminación es desigual en la imagen. Mi preprocesamiento usando GraphicsMagic se menciona en este post: https://groups.google.com/forum/#! topic / tesseract-ocr / jONGSChLRv4

GraphicsMagic también tiene la función-lat para el Umbral Adaptativo de tiempo lineal que intentaré pronto.

Se describe otro método de umbral utilizando OpenCV aqui: http://docs.opencv.org/trunk/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html

 6
Author: rleir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-16 21:35:52

La documentación de Tesseract contiene algunos buenos detalles sobre cómo mejorar la calidad de OCR a través de pasos de procesamiento de imágenes.

Hasta cierto punto, Tesseract los aplica automáticamente. También es posible indicar a Tesseract que escriba una imagen intermedia para la inspección, es decir, para comprobar el funcionamiento del procesamiento interno de imágenes (busque tessedit_write_images en la referencia anterior).

Más importante aún, el nuevo sistema de red neuronal en Tesseracto 4 produce mucho mejor OCR resultados-en general y especialmente para imágenes con algo de ruido. Está habilitado con --oem 1, por ejemplo, como en:

$ tesseract --oem 1 -l deu page.png result pdf

(este ejemplo selecciona el idioma alemán)

Por lo tanto, tiene sentido probar primero qué tan lejos se llega con el nuevo modo Tesseract LSTM antes de aplicar algunos pasos personalizados de procesamiento previo de imágenes.

(a finales de 2017, Tesseract 4 aún no se ha lanzado como estable, pero la versión de desarrollo es utilizable)

 5
Author: maxschlepzig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-22 09:45:46

Como regla general, suelo aplicar las siguientes técnicas de preprocesamiento de imágenes usando la biblioteca OpenCV:

  1. Cambiar el tamaño de la imagen (se recomienda si está trabajando con imágenes que tienen un DPI inferior a 300 dpi):

    img = cv2.resize(img, None, fx=1.2, fy=1.2, interpolation=cv2.INTER_CUBIC)
    
  2. Conversión de imagen a escala de grises:

    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
  3. Aplicando dilatación y erosión para eliminar el ruido (puede jugar con el tamaño del núcleo dependiendo de su conjunto de datos):

    kernel = np.ones((1, 1), np.uint8)
    img = cv2.dilate(img, kernel, iterations=1)
    img = cv2.erode(img, kernel, iterations=1)
    
  4. Aplicando desenfoque, que se puede hacer utilizando una de las siguientes líneas (cada una de las cuales tiene sus pros y contras, sin embargo, el desenfoque mediano y el filtro bilateral generalmente funcionan mejor que el desenfoque gaussiano.):

    cv2.threshold(cv2.GaussianBlur(img, (5, 5), 0), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.threshold(cv2.bilateralFilter(img, 5, 75, 75), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.threshold(cv2.medianBlur(img, 3), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.adaptiveThreshold(cv2.GaussianBlur(img, (5, 5), 0), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    
    cv2.adaptiveThreshold(cv2.bilateralFilter(img, 9, 75, 75), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    
    cv2.adaptiveThreshold(cv2.medianBlur(img, 3), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    

Recientemente he escrito una guía bastante simple para Tesseract, pero debería permitirle escribir su primer script de OCR y aclarar algunos obstáculos que experimenté cuando las cosas estaban menos claras de lo que me hubiera gustado en la documentación.

En caso de que quieras echarles un vistazo, aquí estoy compartir los enlaces con usted:

 5
Author: bkaankuguoglu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-11 07:46:14

Hice esto para obtener buenos resultados de una imagen que no tiene texto muy pequeño.

  1. Aplicar desenfoque a la imagen original.
  2. Aplicar Umbral Adaptativo.
  3. Aplicar efecto de afilado.

Y si aún no se obtienen buenos resultados, escala la imagen al 150% o 200%.

 2
Author: Hamza Iqbal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-11 20:14:03

Leer texto de documentos de imagen usando cualquier motor OCR tiene muchos problemas para obtener una buena precisión. No hay una solución fija para todos los casos, pero aquí hay algunas cosas que deben considerarse para mejorar los resultados de OCR.

1) Presencia de ruido debido a la mala calidad de la imagen / elementos no deseados/manchas en la región de fondo. Esto requiere algunas operaciones de preprocesamiento, como la eliminación de ruido, que se puede hacer fácilmente utilizando métodos de filtro gaussiano o filtro de mediana normal. Estos son también disponible en OpenCV.

2) Orientación incorrecta de la imagen: Debido a una orientación incorrecta, el motor OCR no segmenta correctamente las líneas y palabras de la imagen, lo que da la peor precisión.

3) Presencia de líneas: Mientras se realiza la segmentación de palabras o líneas, el motor OCR a veces también intenta fusionar las palabras y las líneas y, por lo tanto, procesar contenido incorrecto y, por lo tanto, dar resultados incorrectos. Hay otros temas también, pero estos son los básicos.

Este post OCR application es un caso de ejemplo en el que se puede aplicar un pre-pre-procesamiento y post-procesamiento de imágenes en el resultado de OCR para obtener una mejor precisión de OCR.

 2
Author: flamelite,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-23 10:11:58

El reconocimiento de texto depende de una variedad de factores para producir una salida de buena calidad. La salida OCR depende en gran medida de la calidad de la imagen de entrada. Esta es la razón por la cual cada motor de OCR proporciona pautas con respecto a la calidad de la imagen de entrada y su tamaño. Estas pautas ayudan a OCR engine a producir resultados precisos.

He escrito un artículo detallado sobre el procesamiento de imágenes en python. Por favor, siga el enlace de abajo para más explicación. También se agregó el código fuente de python para implementar proceso.

Por favor, escriba un comentario si tiene una sugerencia o mejor idea sobre este tema para mejorarlo.

Https://medium.com/cashify-engineering/improve-accuracy-of-ocr-using-image-preprocessing-8df29ec3a033

 1
Author: Brijesh Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-18 06:43:22