Tesseract: Reconocimiento óptico de caracteres de Java simple

El desarrollo de símbolos que tienen algún valor es un rasgo exclusivo de los humanos. Reconocer estos símbolos y entender las letras de una imagen es absolutamente normal...

Introducción

El desarrollo de símbolos que tienen algún valor es un rasgo exclusivo de los humanos. Reconocer estos símbolos y comprender las letras de una imagen es absolutamente normal para nosotros. Realmente nunca captamos las letras como lo hacen las computadoras, basamos completamente nuestra capacidad para leerlas en nuestra vista.

Por otro lado, las computadoras necesitan algo más concreto y organizado para trabajar. Necesitan una representación digital, no gráfica.

A veces, esto simplemente no es posible. En ocasiones, deseamos automatizar una tarea de reescribir texto a partir de una imagen con nuestras propias manos.

Para estas tareas, se ideó el Reconocimiento óptico de caracteres (OCR) como una forma de permitir que las computadoras "lean" contenido gráfico como texto, similar a cómo los humanos lo hacen. Por supuesto, estos sistemas, si bien son relativamente precisos, aún pueden fallar un poco. Incluso si lo son, corregir los errores del sistema sigue siendo mucho más fácil y rápido que hacerlo todo a mano desde cero.

Al igual que todos los sistemas, el software de reconocimiento óptico de caracteres de naturaleza similar se entrena en conjuntos de datos preparados que lo alimentan con suficientes datos para aprender la diferencia entre los caracteres. También es muy importante cómo aprenden estas redes, si queremos que sean precisas, aunque este es un tema para otro artículo.

En lugar de reinventar la rueda y encontrar una solución muy compleja (pero útil), tranquilicémonos un poco y usemos lo que ya se ofrece.

Teseracto

El gigante de la tecnología, Google, ha estado desarrollando un motor OCR, teseracto, que tiene una historia de décadas desde su creación original. Ofrece una API para varios idiomas, aunque nos centraremos en la API de Tesseract Java.

Tesseract es muy fácil de implementar y, por lo tanto, no es demasiado poderoso. Se usa principalmente para leer texto generado por computadora en imágenes en blanco y negro, lo que se hace con una precisión decente. Aunque en realidad no está diseñado para texto del mundo real.

Para el Reconocimiento Óptico de Caracteres avanzado del mundo real, sería mejor usar algo como Visión de Google, que veremos en otro artículo .

Dependencia Maven

Para importar el motor a nuestro proyecto, simplemente debemos agregar una dependencia:

1
2
3
4
5
<dependency>
    <groupId>net.sourceforge.tess4j</groupId>
    <artifactId>tess4j</artifactId>
    <version>3.2.1</version>
</dependency>

Reconocimiento óptico de caracteres

Usar Tesseract es absolutamente sencillo:

1
2
3
Tesseract tesseract = new Tesseract();
tesseract.setDatapath("E://DataScience//tessdata");
System.out.println(tesseract.doOCR(new File("...")));

En primer lugar, creamos una instancia del objeto Tesseract y establecemos la ruta de datos a los modelos LSTM (Memoria a largo plazo a corto plazo) previamente entrenados para su uso.

Los datos se pueden descargar desde la cuenta github oficial.

Luego, llamamos al método doOCR(), que acepta un archivo y devuelve una cadena: el contenido extraído.

Vamos a alimentarlo con una imagen con letras negras grandes y claras sobre un fondo blanco:

Alimentarlo con una imagen así producirá un resultado perfecto:

1
Optical Character Recognition in Java is made easy with the help of Tesseract'

Sin embargo, esta imagen es extremadamente fácil de escanear. Es normalizado, de alta resolución y la fuente es consistente.

A ver que pasa si intento escribir algo yo mismo, en un papel, y lo dejamos pasar por la app:

Podemos ver instantáneamente la diferencia que hace:

1
A411, written texz: is different {mm compatar generated but

Algunas palabras están perfectamente bien y se podría distinguir fácilmente "el texto escrito es diferente al generado por computadora", pero la primera y la última palabra están muy equivocadas.

Ahora, para hacer que esto sea un poco más fácil de usar, vamos a transferirlo a una aplicación Spring Boot muy simple para mostrar el resultado de una manera gráficamente más agradable.

Implementación

Aplicación Spring Boot

En primer lugar, comencemos generando nuestro proyecto a través de Spring Initializr. Incluya las dependencias spring-boot-starter-web y spring-boot-starter-thymeleaf. Importaremos Tesseract manualmente:

Controlador

La aplicación no necesita más que un solo controlador, que sirve nuestras dos vistas y maneja la carga de imágenes y el reconocimiento óptico de caracteres:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Controller
public class FileUploadController {
    
    @RequestMapping("/")
    public String index() {
        return "upload";
    }

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public RedirectView singleFileUpload(@RequestParam("file") MultipartFile file,
                                   RedirectAttributes redirectAttributes, Model model) throws IOException, TesseractException {

        byte[] bytes = file.getBytes();
        Path path = Paths.get("E://simpleocr//src//main//resources//static//" + file.getOriginalFilename());
        Files.write(path, bytes);

        File convFile = convert(file);
        Tesseract tesseract = new Tesseract();
        tesseract.setDatapath("E://DataScience//tessdata");
        String text = tesseract.doOCR(file2);
        redirectAttributes.addFlashAttribute("file", file);
        redirectAttributes.addFlashAttribute("text", text);
        return new RedirectView("result");
    }

    @RequestMapping("/result")
    public String result() {
        return "result";
    }

    public static File convert(MultipartFile file) throws IOException {
        File convFile = new File(file.getOriginalFilename());
        convFile.createNewFile();
        FileOutputStream fos = new FileOutputStream(convFile);
        fos.write(file.getBytes());
        fos.close();
        return convFile;
    }
}

Tesseract funciona con Files de Java, pero no es compatible con MultipartFile, que obtenemos al aceptar un archivo a través de nuestro formulario. Para mitigar esto, hemos agregado un método convert() simple, que convierte el MultipartFile en un Archivo normal.

Una vez que hemos extraído el texto usando Tesseract, simplemente lo agregamos al modelo, junto con la imagen escaneada y lo agregamos a la vista redirigida - resultado.

Puntos de vista

Ahora, definamos una vista que podamos usar para simplemente cargar un archivo a través de un formulario:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<html>
<body>
<h1>Upload a file for OCR:</h1>

<form method="POST" action="/upload" enctype="multipart/form-data">
    <input type="file" name="file" /><br/><br/>
    <input type="submit" value="Submit" />
</form>

</body>
</html>

Y la página resultante:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<html xmlns:th="http://www.thymeleaf.org">
<body>

<h1>Extracted Content:</h1>
<h2>><span th:text="${text}"></span></h2>

<p>From the image:</p>
<img th:src="'/' + ${file.getOriginalFilename()}"/>
</body>
</html>

Ejecutar esta aplicación nos dará la bienvenida con una interfaz sencilla:

Al agregar una imagen y enviarla, se extraerá el texto y se mostrará la imagen en la pantalla:

¡Éxito!

Conclusión

Usando el motor Tesseract de Google, creamos una aplicación extremadamente simple que acepta una imagen a través de un formulario, extrae el contenido textual y nos devuelve la imagen enviada.

Esta no es una aplicación particularmente útil en sí misma, debido al poder limitado de Tesseract y al hecho de que la aplicación es demasiado simple para cualquier otro uso además de fines de demostración, pero debería servir como una herramienta divertida que podría implementar y probar. con.

El reconocimiento óptico de caracteres puede ser útil cuando desea digitalizar contenido, especialmente cuando se trata de documentos. Estos son fáciles de escanear y son bastante precisos cuando se trata de extraer contenido. Por supuesto, siempre es aconsejable revisar el documento resultante en busca de posibles errores.