Extraer texto de un pdf con Python II. OCR de imagenes embebidas en un pdf.

¿Como hacer un OCR de imágenes contenidas en un pdf?

Muchos pdfs proceden de escaner o de una conversión de tiff multipágina con el mismo origen, siendo imágenes embebidas donde el texto son pixels y no caracteres.

En esos casos, la extracción del texto por procedimientos estandar no dará el resultado esperado porque no hay texto como tal.

En la entrada anterior, Extraer texto de un pdf con Python, vimos como instalar y comenzar a trabajar con pdfminer3k extrayendo textos de un pdf.

Si bien únicamente accedíamos a objetos propiamente de texto, los LTTextBox y LTTextLine.

Localizar y extraer imágenes del pdf con pdfminer3k

Vamos a combinar dos librerías que ya conocemos, pdfminer3k y tesseract.

Recordaréis que dejamos pendiente de implementar el tratamiento de LTFigure.

for lt_obj in layout:
    if isinstance(lt_obj, LTTextBox) or isinstance(lt_obj, LTTextLine):
        # aqui hacemos la magia:
        spagetxt = lt_obj.get_text().strip() + " "
        ...
    elif isinstance(lt_obj, LTFigure):
        print("LTFigure, pte implementar!")

Bien, solo tenemos que implementar la recuperación de la imagen para su ocr.

Incluimos las siguientes lineas en la función principal.

elif isinstance(lt_obj, LTFigure):
    spagetxt=""
    for im in lt_obj:
        if isinstance(im, LTImage):
            try:
                imdata = im.stream.get_data()                    
            except:
                imdata = im.stream.get_rawdata()
            fnameimg=saveimg(imdata)
            if(fnameimg!=""):
                spagetxt=gettxt(fnameimg) #obtiene texto sin generar archivo txt
                if(spagetxt!=""):
                    btxt=True
                    fptxt.write(spagetxt)
                    print(spagetxt)
                os.remove(fnameimg)

La función saveimg, crea un archivo temporal por cada LTimage y devuelve el nombre.

   
def saveimg(imgdata):
    if imgdata is None:
        print("imgdata esta vacio")
        return ""
    if not imgdata.startswith(b'\xff\xd8\xff\xe0'):
        print("imgdata no es valido")
        return ""
    
    fd, fname = tempfile.mkstemp(prefix='ncm_', suffix='.jpg')
    try:
        with open(fname, 'wb') as f:
            f.write(imgdata)              
    except:
        return ""
    finally:
        os.close(fd)
        print("return " + fname)
        return fname

Implementación del OCR con tesseract

Añadimos los siguientes import en la cabecera.

import tempfile, os
import cv2
import pytesseract

La función gettxt espera como parámetro el path de una imagen y devuelve el texto extraido de ella.

def fileexist(spath):
    my_file = Path(spath)
    if my_file.is_file():
        return True
    else:
        return False
    
def gettxt(spath):
    try:
        if not (fileexist(spath)):
            return ""
        img = cv2.imread(spath)    
        sret=""
        sret=pytesseract.image_to_string(img)        
        print("ocr ok!")
        return sret
    except Exception as e:
        print("Error: %s" % (e))
        return ""
    except:
        print("Error desconocido")
        return ""

El código completo

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 13 10:55:00 2018
dge
@author: altaruru
"""
import tempfile, os
import cv2
import pytesseract

from pathlib import Path
from pdfminer.pdfparser import PDFParser, PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTTextBox, LTTextLine, LTImage, LTFigure

def fileexist(spath):
    my_file = Path(spath)
    if my_file.is_file():
        return True
    else:
        return False
    
def gettxt(spath):
    try:
        if not (fileexist(spath)):
            return ""
        img = cv2.imread(spath)    
        sret=""
        sret=pytesseract.image_to_string(img)        
        print("ocr ok!")
        return sret
    except Exception as e:
        print("Error: %s" % (e))
        return ""
    except:
        print("Error desconocido")
        return ""
    
def saveimg(imgdata):
    if imgdata is None:
        print("imgdata esta vacio")
        return ""
    if not imgdata.startswith(b'\xff\xd8\xff\xe0'):
        print("imgdata no es valido")
        return ""
    
    fd, fname = tempfile.mkstemp(prefix='ncm_', suffix='.jpg')
    try:
        with open(fname, 'wb') as f:
            f.write(imgdata)              
    except:
        return ""
    finally:
        os.close(fd)
        print("return " + fname)
        return fname
        
        
def pdf2txt(pdfname, txtname):
    btxt=False
    try:
        fp = open(pdfname, 'rb')    
        parser = PDFParser(fp)
        doc = PDFDocument()
        parser.set_document(doc)
        doc.set_parser(parser)
        doc.initialize('')
        rsrcmgr = PDFResourceManager()
        laparams = LAParams()
    
        laparams.char_margin = 1.0
        laparams.word_margin = 1.0
        device = PDFPageAggregator(rsrcmgr, laparams=laparams)
        interpreter = PDFPageInterpreter(rsrcmgr, device)    
        ncount=0
        print("pdf2txt %s..." % pdfname) # informa por consola del nombre de archivo
    
        # abre archivo de texto para la salida
        fptxt = open(txtname, 'w')
        # recorre el documento procesando cada página
        for page in doc.get_pages():
            interpreter.process_page(page)
            layout = device.get_result()
            # recorre la página procesando cada objeto
            for lt_obj in layout:
                if isinstance(lt_obj, LTTextBox) or isinstance(lt_obj, LTTextLine):
                    spagetxt = lt_obj.get_text().strip() + " "
                    if(spagetxt!=""):
                        btxt=True
                        fptxt.write(spagetxt)
                        #print(spagetxt)
                elif isinstance(lt_obj, LTFigure):
                    spagetxt=""
                    for im in lt_obj:
                        if isinstance(im, LTImage):
                            try:
                                imdata = im.stream.get_data()                    
                            except:
                                imdata = im.stream.get_rawdata()
                            fnameimg=saveimg(imdata)
                            if(fnameimg!=""):
                                spagetxt=gettxt(fnameimg)
                                if(spagetxt!=""):
                                    btxt=True
                                    fptxt.write(spagetxt)
                                    print(spagetxt)
                                os.remove(fnameimg)
            ncount+=1
    
        print("end")
        fptxt.closed
        fp.closed
    except Exception as e:
        print("Error: %s" % (e))        
    return btxt

pdf2txt("/home/nuse/Documentos/src/pysrc/imgs/Computer-Vision-Resources.pdf","/home/nuse/Documentos/src/pysrc/imgs/Computer-Vision-Resources.txt")

 

Feliz dia!

Deja un comentario

Tu dirección de correo electrónico no será publicada.