Extrahieren Sie mit Python Text aus Bildern in PDF-Dateien

Heutzutage haben mittlere und große Unternehmen riesige Mengen an gedruckten Dokumenten im täglichen Gebrauch. Darunter sind Rechnungen, Quittungen, Unternehmensdokumente, Berichte und Medienmitteilungen.

Für diese Unternehmen kann der Einsatz eines OCR-Scanners viel Zeit sparen und gleichzeitig die Effizienz sowie die Genauigkeit verbessern. 

Mithilfe von Algorithmen zur optischen Zeichenerkennung (OCR) können Computer gedruckte oder handgeschriebene Dokumente automatisch analysieren und Textdaten in bearbeitbaren Formaten aufbereiten, damit Computer sie effizient verarbeiten können. OCR-Systeme wandeln ein zweidimensionales Textbild, das maschinengedruckten oder handgeschriebenen Text enthalten könnte, von seiner Bilddarstellung in maschinenlesbaren Text um.

Im Allgemeinen umfasst eine OCR-Engine mehrere Schritte, die erforderlich sind, um einen maschinellen Lernalgorithmus für eine effiziente Problemlösung mit Hilfe der optischen Zeichenerkennung zu trainieren.

Die folgenden Schritte, die sich von einer Engine zur anderen unterscheiden können, sind ungefähr erforderlich, um sich der automatischen Zeichenerkennung zu nähern:

In diesem Tutorial zeige ich Ihnen Folgendes:

  • So führen Sie einen OCR-Scanner für eine Bilddatei aus.
  • So schwärzen oder markieren Sie einen bestimmten Text in einer Bilddatei.
  • So führen Sie einen OCR-Scanner für eine PDF-Datei oder eine Sammlung von PDF-Dateien aus.

Bitte beachten Sie, dass es in diesem Tutorial um das Extrahieren von Text aus Bildern in PDF-Dokumenten geht.

Um zu beginnen, müssen wir die folgenden Bibliotheken verwenden:

Tesseract OCR :  ist eine Open-Source-Texterkennungs-Engine, die unter der Apache 2.0-Lizenz verfügbar ist und deren Entwicklung seit 2006 von Google gesponsert wird. Im Jahr 2006 galt Tesseract als eine der genauesten Open-Source-OCR-Engines. Sie können es direkt verwenden oder die API verwenden, um den gedruckten Text aus Bildern zu extrahieren. Das Beste daran ist, dass es eine große Auswahl an Sprachen unterstützt. 

Die Installation der Tesseract-Engine würde den Rahmen dieses Artikels sprengen. Sie müssen jedoch der offiziellen Installationsanleitung von Tesseract folgen , um es auf Ihrem Betriebssystem zu installieren.

Um das Tesseract-Setup zu validieren, führen Sie bitte den folgenden Befehl aus und überprüfen Sie die generierte Ausgabe:

Validierung der Tesseract-InstallationPython-tesseract : ist ein Python-Wrapper für die Tesseract-OCR-Engine von Google. Es ist auch als eigenständiges Aufrufskript für Tesseract nützlich, da es alle Bildtypen lesen kann, die von den Pillow- und Leptonica-Imaging-Bibliotheken unterstützt werden, einschließlich jpeg, png, gif, bmp, tiff und andere.

OpenCV : ist eine Python-Open-Source-Bibliothek für Computer Vision, maschinelles Lernen und Bildverarbeitung. OpenCV unterstützt eine Vielzahl von Programmiersprachen wie Python, C++, Java usw. Es kann Bilder und Videos verarbeiten, um Objekte, Gesichter oder sogar die Handschrift eines Menschen zu identifizieren. 

PyMuPDF : MuPDF ist eine äußerst vielseitige, anpassbare PDF-, XPS- und eBook-Interpreterlösung, die in einer Vielzahl von Anwendungen als PDF-Renderer, Viewer oder Toolkit verwendet werden kann. PyMuPDF ist eine Python-Bindung für MuPDF. Es ist ein leichter PDF- und XPS-Viewer.

Numpy: ist ein universelles Array-Verarbeitungspaket. Es stellt ein hochleistungsfähiges multidimensionales Array-Objekt und Tools zum Arbeiten mit diesen Arrays bereit. Es ist das grundlegende Paket für wissenschaftliches Rechnen mit Python. Außerdem kann Numpy auch als effizienter mehrdimensionaler Container für generische Daten verwendet werden.

Pillow: baut auf PIL (Python Image Library) auf. Es ist ein wesentliches Modul für die Bildverarbeitung in Python.

Pandas: ist eine BSD-lizenzierte Open-Source-Python-Bibliothek, die leistungsstarke, einfach zu verwendende Datenstrukturen und Datenanalysetools für die Programmiersprache Python bereitstellt. 

Dateityp: Kleines und abhängigkeitsfreies Python-Paket zum Ableiten von Dateityp und MIME-Typ.

Dieses Tutorial zielt darauf ab, ein leichtes, befehlszeilenbasiertes Dienstprogramm zu entwickeln, um einen Text zu extrahieren, zu redigieren oder hervorzuheben, der in einem Bild oder einer gescannten PDF-Datei oder in einem Ordner enthalten ist, der eine Sammlung von PDF-Dateien enthält.

Aufstellen

Lassen Sie uns zunächst die Anforderungen installieren:

$ pip install Filetype==1.0.7 numpy==1.19.4 opencv-python==4.4.0.46 pandas==1.1.4 Pillow==8.0.1 PyMuPDF==1.18.9 pytesseract==0.3.7

Beginnen wir mit dem Importieren der erforderlichen Bibliotheken:

import os
import re
import argparse
import pytesseract
from pytesseract import Output
import cv2
import numpy as np
import fitz
from io import BytesIO
from PIL import Image
import pandas as pd
import filetype

# Path Of The Tesseract OCR engine
TESSERACT_PATH = "C:\Program Files\Tesseract-OCR\tesseract.exe"
# Include tesseract executable
pytesseract.pytesseract.tesseract_cmd = TESSERACT_PATH

TESSERACT_PATHHier befindet sich die ausführbare Tesseract-Datei. Offensichtlich müssen Sie es für Ihren Fall ändern.

def pix2np(pix):
    """
    Converts a pixmap buffer into a numpy array
    """
    # pix.samples = sequence of bytes of the image pixels like RGBA
    #pix.h = height in pixels
    #pix.w = width in pixels
    # pix.n = number of components per pixel (depends on the colorspace and alpha)
    im = np.frombuffer(pix.samples, dtype=np.uint8).reshape(
        pix.h, pix.w, pix.n)
    try:
        im = np.ascontiguousarray(im[..., [2, 1, 0]])  # RGB To BGR
    except IndexError:
        # Convert Gray to RGB
        im = cv2.cvtColor(im, cv2.COLOR_GRAY2RGB)
        im = np.ascontiguousarray(im[..., [2, 1, 0]])  # RGB To BGR
    return im

Diese Funktion konvertiert einen Pixmap-Puffer, der einen mit der PyMuPDF-Bibliothek erstellten Screenshot darstellt, in ein NumPy-Array.

Um die Tesseract-Genauigkeit zu verbessern, definieren wir einige Vorverarbeitungsfunktionen mit OpenCV:

# Image Pre-Processing Functions to improve output accurracy
# Convert to grayscale
def grayscale(img):
    return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Remove noise
def remove_noise(img):
    return cv2.medianBlur(img, 5)

# Thresholding
def threshold(img):
    # return cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    return cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

# dilation
def dilate(img):
    kernel = np.ones((5, 5), np.uint8)
    return cv2.dilate(img, kernel, iterations=1)

# erosion
def erode(img):
    kernel = np.ones((5, 5), np.uint8)
    return cv2.erode(img, kernel, iterations=1)

# opening -- erosion followed by a dilation
def opening(img):
    kernel = np.ones((5, 5), np.uint8)
    return cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

# canny edge detection
def canny(img):
    return cv2.Canny(img, 100, 200)

# skew correction
def deskew(img):
    coords = np.column_stack(np.where(img > 0))
    angle = cv2.minAreaRect(coords)[-1]
    if angle < -45:
        angle = -(90 + angle)
    else:
        angle = -angle
    (h, w) = img.shape[:2]
    center = (w//2, h//2)
    M = cv2.getRotationMatrix2D(center, angle, 1.0)
    rotated = cv2.warpAffine(
        img, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
    return rotated

# template matching
def match_template(img, template):
    return cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)

def convert_img2bin(img):
    """
    Pre-processes the image and generates a binary output
    """
    # Convert the image into a grayscale image
    output_img = grayscale(img)
    # Invert the grayscale image by flipping pixel values.
    # All pixels that are grater than 0 are set to 0 and all pixels that are = to 0 are set to 255
    output_img = cv2.bitwise_not(output_img)
    # Converting image to binary by Thresholding in order to show a clear separation between white and blacl pixels.
    output_img = threshold(output_img)
    return output_img

Wir haben Funktionen für viele Vorverarbeitungsaufgaben definiert, darunter das Konvertieren von Bildern in Graustufen, das Spiegeln von Pixelwerten, das Trennen von weißen und schwarzen Pixeln und vieles mehr.

Als nächstes definieren wir eine Funktion zum Anzeigen eines Bildes:

def display_img(title, img):
    """Displays an image on screen and maintains the output until the user presses a key"""
    cv2.namedWindow('img', cv2.WINDOW_NORMAL)
    cv2.setWindowTitle('img', title)
    cv2.resizeWindow('img', 1200, 900)
    # Display Image on screen
    cv2.imshow('img', img)
    # Mantain output until user presses a key
    cv2.waitKey(0)
    # Destroy windows when user presses a key
    cv2.destroyAllWindows()

Die display_img()Funktion zeigt auf dem Bildschirm ein Bild in einem Fenster mit einem auf den titleParameter gesetzten Titel an und hält dieses Fenster geöffnet, bis der Benutzer eine Taste auf der Tastatur drückt.

def generate_ss_text(ss_details):
    """Loops through the captured text of an image and arranges this text line by line.
    This function depends on the image layout."""
    # Arrange the captured text after scanning the page
    parse_text = []
    word_list = []
    last_word = ''
    # Loop through the captured text of the entire page
    for word in ss_details['text']:
        # If the word captured is not empty
        if word != '':
            # Add it to the line word list
            word_list.append(word)
            last_word = word
        if (last_word != '' and word == '') or (word == ss_details['text'][-1]):
            parse_text.append(word_list)
            word_list = []
    return parse_text

Die obige Funktion durchläuft den erfassten Text eines Bildes und ordnet den erfassten Text Zeile für Zeile an. Dies hängt vom Bildlayout ab und kann bei einigen Bildformaten eine Anpassung erfordern.

Als nächstes definieren wir eine Funktion, um mit regulären Ausdrücken nach Text zu suchen :

def search_for_text(ss_details, search_str):
    """Search for the search string within the image content"""
    # Find all matches within one page
    results = re.findall(search_str, ss_details['text'], re.IGNORECASE)
    # In case multiple matches within one page
    for result in results:
        yield result

Wir werden diese Funktion verwenden, um im erfassten Inhalt eines Bildes nach bestimmtem Text zu suchen. Es gibt einen Generator der gefundenen Übereinstimmungen zurück.

def save_page_content(pdfContent, page_id, page_data):
    """Appends the content of a scanned page, line by line, to a pandas DataFrame."""
    if page_data:
        for idx, line in enumerate(page_data, 1):
            line = ' '.join(line)
            pdfContent = pdfContent.append(
                {'page': page_id, 'line_id': idx, 'line': line}, ignore_index=True
            )
    return pdfContent

save_page_content()Funktion hängt den erfassten Inhalt eines Bildes Zeile für Zeile an, nachdem es an den pdfContentPandas-Datenrahmen gescannt wurde.

Lassen Sie uns nun eine Funktion erstellen, um den resultierenden Datenrahmen in einer CSV-Datei zu speichern:

def save_file_content(pdfContent, input_file):
    """Outputs the content of the pandas DataFrame to a CSV file having the same path as the input_file
    but with different extension (.csv)"""
    content_file = os.path.join(os.path.dirname(input_file), os.path.splitext(
        os.path.basename(input_file))[0] + ".csv")
    pdfContent.to_csv(content_file, sep=',', index=False)
    return content_file

Als Nächstes schreiben wir eine Funktion, die den Konfidenzwert des aus dem gescannten Bild entnommenen Textes berechnet:

def calculate_ss_confidence(ss_details: dict):
    """Calculate the confidence score of the text grabbed from the scanned image."""
    # page_num  --> Page number of the detected text or item
    # block_num --> Block number of the detected text or item
    # par_num   --> Paragraph number of the detected text or item
    # line_num  --> Line number of the detected text or item
    # Convert the dict to dataFrame
    df = pd.DataFrame.from_dict(ss_details)
    # Convert the field conf (confidence) to numeric
    df['conf'] = pd.to_numeric(df['conf'], errors='coerce')
    # Elliminate records with negative confidence
    df = df[df.conf != -1]
    # Calculate the mean confidence by page
    conf = df.groupby(['page_num'])['conf'].mean().tolist()
    return conf[0]

Zur Hauptfunktion gehen: Bild scannen:

def ocr_img(
        img: np.array, input_file: str, search_str: str, 
        highlight_readable_text: bool = False, action: str = 'Highlight', 
        show_comparison: bool = False, generate_output: bool = True):
    """Scans an image buffer or an image file.
    Pre-processes the image.
    Calls the Tesseract engine with pre-defined parameters.
    Calculates the confidence score of the image grabbed content.
    Draws a green rectangle around readable text items having a confidence score > 30.
    Searches for a specific text.
    Highlight or redact found matches of the searched text.
    Displays a window showing readable text fields or the highlighted or redacted text.
    Generates the text content of the image.
    Prints a summary to the console."""
    # If image source file is inputted as a parameter
    if input_file:
        # Reading image using opencv
        img = cv2.imread(input_file)
    # Preserve a copy of this image for comparison purposes
    initial_img = img.copy()
    highlighted_img = img.copy()
    # Convert image to binary
    bin_img = convert_img2bin(img)
    # Calling Tesseract
    # Tesseract Configuration parameters
    # oem --> OCR engine mode = 3 >> Legacy + LSTM mode only (LSTM neutral net mode works the best)
    # psm --> page segmentation mode = 6 >> Assume as single uniform block of text (How a page of text can be analyzed)
    config_param = r'--oem 3 --psm 6'
    # Feeding image to tesseract
    details = pytesseract.image_to_data(
        bin_img, output_type=Output.DICT, config=config_param, lang='eng')
    # The details dictionary contains the information of the input image
    # such as detected text, region, position, information, height, width, confidence score.
    ss_confidence = calculate_ss_confidence(details)
    boxed_img = None
    # Total readable items
    ss_readable_items = 0
    # Total matches found
    ss_matches = 0
    for seq in range(len(details['text'])):
        # Consider only text fields with confidence score > 30 (text is readable)
        if float(details['conf'][seq]) > 30.0:
            ss_readable_items += 1
            # Draws a green rectangle around readable text items having a confidence score > 30
            if highlight_readable_text:
                (x, y, w, h) = (details['left'][seq], details['top']
                                [seq], details['width'][seq], details['height'][seq])
                boxed_img = cv2.rectangle(
                    img, (x, y), (x+w, y+h), (0, 255, 0), 2)
            # Searches for the string
            if search_str:
                results = re.findall(
                    search_str, details['text'][seq], re.IGNORECASE)
                for result in results:
                    ss_matches += 1
                    if action:
                        # Draw a red rectangle around the searchable text
                        (x, y, w, h) = (details['left'][seq], details['top']
                                        [seq], details['width'][seq], details['height'][seq])
                        # Details of the rectangle
                        # Starting coordinate representing the top left corner of the rectangle
                        start_point = (x, y)
                        # Ending coordinate representing the botton right corner of the rectangle
                        end_point = (x + w, y + h)
                        #Color in BGR -- Blue, Green, Red
                        if action == "Highlight":
                            color = (0, 255, 255)  # Yellow
                        elif action == "Redact":
                            color = (0, 0, 0)  # Black
                        # Thickness in px (-1 will fill the entire shape)
                        thickness = -1
                        boxed_img = cv2.rectangle(
                            img, start_point, end_point, color, thickness)
                            
    if ss_readable_items > 0 and highlight_readable_text and not (ss_matches > 0 and action in ("Highlight", "Redact")):
        highlighted_img = boxed_img.copy()
    # Highlight found matches of the search string
    if ss_matches > 0 and action == "Highlight":
        cv2.addWeighted(boxed_img, 0.4, highlighted_img,
                        1 - 0.4, 0, highlighted_img)
    # Redact found matches of the search string
    elif ss_matches > 0 and action == "Redact":
        highlighted_img = boxed_img.copy()
        #cv2.addWeighted(boxed_img, 1, highlighted_img, 0, 0, highlighted_img)
    # save the image
    cv2.imwrite("highlighted-text-image.jpg", highlighted_img)  
    # Displays window showing readable text fields or the highlighted or redacted data
    if show_comparison and (highlight_readable_text or action):
        title = input_file if input_file else 'Compare'
        conc_img = cv2.hconcat([initial_img, highlighted_img])
        display_img(title, conc_img)
    # Generates the text content of the image
    output_data = None
    if generate_output and details:
        output_data = generate_ss_text(details)
    # Prints a summary to the console
    if input_file:
        summary = {
            "File": input_file, "Total readable words": ss_readable_items, "Total matches": ss_matches, "Confidence score": ss_confidence
        }
        # Printing Summary
        print("## Summary ########################################################")
        print("\n".join("{}:{}".format(i, j) for i, j in summary.items()))
        print("###################################################################")
    return highlighted_img, ss_readable_items, ss_matches, ss_confidence, output_data
    # pass image into pytesseract module
    # pytesseract is trained in many languages
    #config_param = r'--oem 3 --psm 6'
    #details = pytesseract.image_to_data(img,config=config_param,lang='eng')
    # print(details)
    # return details

Das obige führt Folgendes aus:

  • Scannt einen Bildpuffer oder eine Bilddatei.
  • Bearbeitet das Bild vor.
  • Führt die Tesseract-Engine mit vordefinierten Parametern aus.
  • Berechnet den Konfidenzwert des erfassten Bildinhalts.
  • Zeichnet ein grünes Rechteck um die lesbaren Textelemente mit einem Vertrauenswert von mehr als 30.
  • Sucht nach einem bestimmten Text innerhalb des Bildinhalts.
  • Markiert oder redigiert die gefundenen Übereinstimmungen des gesuchten Textes.
  • Zeigt ein Fenster mit lesbaren Textfeldern oder dem hervorgehobenen Text oder dem geschwärzten Text an.
  • Erzeugt den Textinhalt des Bildes.
  • Druckt eine Zusammenfassung auf der Konsole.
def image_to_byte_array(image: Image):
    """
    Converts an image into a byte array
    """
    imgByteArr = BytesIO()
    image.save(imgByteArr, format=image.format if image.format else 'JPEG')
    imgByteArr = imgByteArr.getvalue()
    return imgByteArr

def ocr_file(**kwargs):
    """Opens the input PDF File.
    Opens a memory buffer for storing the output PDF file.
    Creates a DataFrame for storing pages statistics
    Iterates throughout the chosen pages of the input PDF file
    Grabs a screen-shot of the selected PDF page.
    Converts the screen-shot pix to a numpy array
    Scans the grabbed screen-shot.
    Collects the statistics of the screen-shot(page).
    Saves the content of the screen-shot(page).
    Adds the updated screen-shot (Highlighted, Redacted) to the output file.
    Saves the whole content of the PDF file.
    Saves the output PDF file if required.
    Prints a summary to the console."""
    input_file = kwargs.get('input_file')
    output_file = kwargs.get('output_file')
    search_str = kwargs.get('search_str')
    pages = kwargs.get('pages')
    highlight_readable_text = kwargs.get('highlight_readable_text')
    action = kwargs.get('action')
    show_comparison = kwargs.get('show_comparison')
    generate_output = kwargs.get('generate_output')
    # Opens the input PDF file
    pdfIn = fitz.open(input_file)
    # Opens a memory buffer for storing the output PDF file.
    pdfOut = fitz.open()
    # Creates an empty DataFrame for storing pages statistics
    dfResult = pd.DataFrame(
        columns=['page', 'page_readable_items', 'page_matches', 'page_total_confidence'])
    # Creates an empty DataFrame for storing file content
    if generate_output:
        pdfContent = pd.DataFrame(columns=['page', 'line_id', 'line'])
    # Iterate throughout the pages of the input file
    for pg in range(pdfIn.pageCount):
        if str(pages) != str(None):
            if str(pg) not in str(pages):
                continue
        # Select a page
        page = pdfIn[pg]
        # Rotation angle
        rotate = int(0)
        # PDF Page is converted into a whole picture 1056*816 and then for each picture a screenshot is taken.
        # zoom = 1.33333333 -----> Image size = 1056*816
        # zoom = 2 ---> 2 * Default Resolution (text is clear, image text is hard to read)    = filesize small / Image size = 1584*1224
        # zoom = 4 ---> 4 * Default Resolution (text is clear, image text is barely readable) = filesize large
        # zoom = 8 ---> 8 * Default Resolution (text is clear, image text is readable) = filesize large
        zoom_x = 2
        zoom_y = 2
        # The zoom factor is equal to 2 in order to make text clear
        # Pre-rotate is to rotate if needed.
        mat = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate)
        # To captue a specific part of the PDF page
        # rect = page.rect #page size
        # mp = rect.tl + (rect.bl - (0.75)/zoom_x) #rectangular area 56 = 75/1.3333
        # clip = fitz.Rect(mp,rect.br) #The area to capture
        # pix = page.getPixmap(matrix=mat, alpha=False,clip=clip)
        # Get a screen-shot of the PDF page
        # Colorspace -> represents the color space of the pixmap (csRGB, csGRAY, csCMYK)
        # alpha -> Transparancy indicator
        pix = page.getPixmap(matrix=mat, alpha=False, colorspace="csGRAY")
        # convert the screen-shot pix to numpy array
        img = pix2np(pix)
        # Erode image to omit or thin the boundaries of the bright area of the image
        # We apply Erosion on binary images.
        #kernel = np.ones((2,2) , np.uint8)
        #img = cv2.erode(img,kernel,iterations=1)
        upd_np_array, pg_readable_items, pg_matches, pg_total_confidence, pg_output_data \
            = ocr_img(img=img, input_file=None, search_str=search_str, highlight_readable_text=highlight_readable_text  # False
                      , action=action  # 'Redact'
                      , show_comparison=show_comparison  # True
                      , generate_output=generate_output  # False
                      )
        # Collects the statistics of the page
        dfResult = dfResult.append({'page': (pg+1), 'page_readable_items': pg_readable_items,
                                   'page_matches': pg_matches, 'page_total_confidence': pg_total_confidence}, ignore_index=True)
        if generate_output:
            pdfContent = save_page_content(
                pdfContent=pdfContent, page_id=(pg+1), page_data=pg_output_data)
        # Convert the numpy array to image object with mode = RGB
        #upd_img = Image.fromarray(np.uint8(upd_np_array)).convert('RGB')
        upd_img = Image.fromarray(upd_np_array[..., ::-1])
        # Convert the image to byte array
        upd_array = image_to_byte_array(upd_img)
        # Get Page Size
        """
        #To check whether initial page is portrait or landscape
        if page.rect.width > page.rect.height:
            fmt = fitz.PaperRect("a4-1")
        else:
            fmt = fitz.PaperRect("a4")

        #pno = -1 -> Insert after last page
        pageo = pdfOut.newPage(pno = -1, width = fmt.width, height = fmt.height)
        """
        pageo = pdfOut.newPage(
            pno=-1, width=page.rect.width, height=page.rect.height)
        pageo.insertImage(page.rect, stream=upd_array)
        #pageo.insertImage(page.rect, stream=upd_img.tobytes())
        #pageo.showPDFpage(pageo.rect, pdfDoc, page.number)
    content_file = None
    if generate_output:
        content_file = save_file_content(
            pdfContent=pdfContent, input_file=input_file)
    summary = {
        "File": input_file, "Total pages": pdfIn.pageCount, 
        "Processed pages": dfResult['page'].count(), "Total readable words": dfResult['page_readable_items'].sum(), 
        "Total matches": dfResult['page_matches'].sum(), "Confidence score": dfResult['page_total_confidence'].mean(), 
        "Output file": output_file, "Content file": content_file
    }
    # Printing Summary
    print("## Summary ########################################################")
    print("\n".join("{}:{}".format(i, j) for i, j in summary.items()))
    print("\nPages Statistics:")
    print(dfResult, sep='\n')
    print("###################################################################")
    pdfIn.close()
    if output_file:
        pdfOut.save(output_file)
    pdfOut.close()

Die image_to_byte_array()Funktion konvertiert ein Bild in ein Byte-Array.

Die ocr_file()Funktion macht folgendes:

  • Öffnet die PDF-Eingabedatei.
  • Öffnet einen Speicherpuffer zum Speichern der ausgegebenen PDF-Datei.
  • Erstellt einen Pandas-Datenrahmen zum Speichern der Seitenstatistiken.
  • Iteriert durch die ausgewählten Seiten der PDF-Eingabedatei.
  • Nimmt einen Screenshot (Bild) der ausgewählten Seite der eingegebenen PDF-Datei auf.
  • Konvertiert den Screenshot (pix) in ein NumPy-Array.
  • Scannt den erfassten Screenshot.
  • Sammelt die Statistiken des Screenshots (der Seite).
  • Speichert den Inhalt des Screenshots.
  • Fügt den aktualisierten Screenshot zur Ausgabedatei hinzu.
  • Speichert den gesamten Inhalt der PDF-Eingabedatei in einer CSV-Datei.
  • Speichert bei Bedarf die ausgegebene PDF-Datei.
  • Druckt eine Zusammenfassung auf der Konsole.

Fügen wir eine weitere Funktion zum Verarbeiten eines Ordners hinzu, der mehrere PDF-Dateien enthält:

def ocr_folder(**kwargs):
    """Scans all PDF Files within a specified path"""
    input_folder = kwargs.get('input_folder')
    # Run in recursive mode
    recursive = kwargs.get('recursive')
    search_str = kwargs.get('search_str')
    pages = kwargs.get('pages')
    action = kwargs.get('action')
    generate_output = kwargs.get('generate_output')
    # Loop though the files within the input folder.
    for foldername, dirs, filenames in os.walk(input_folder):
        for filename in filenames:
            # Check if pdf file
            if not filename.endswith('.pdf'):
                continue
            # PDF File found
            inp_pdf_file = os.path.join(foldername, filename)
            print("Processing file =", inp_pdf_file)
            output_file = None
            if search_str:
                # Generate an output file
                output_file = os.path.join(os.path.dirname(
                    inp_pdf_file), 'ocr_' + os.path.basename(inp_pdf_file))
            ocr_file(
                input_file=inp_pdf_file, output_file=output_file, search_str=search_str, pages=pages, highlight_readable_text=False, action=action, show_comparison=False, generate_output=generate_output
            )
        if not recursive:
            break

Diese Funktion soll die PDF-Dateien scannen, die in einem bestimmten Ordner enthalten sind. Es durchläuft die Dateien des angegebenen Ordners entweder rekursiv oder nicht, abhängig vom Wert des Parameters recursive, und verarbeitet diese Dateien eine nach der anderen.

Es akzeptiert die folgenden Parameter:

  • input_folder: Der Pfad des Ordners, der die zu verarbeitenden PDF-Dateien enthält.
  • search_str: Der Text, nach dem gesucht werden soll, um bearbeitet zu werden.
  • recursive: ob dieser Prozess rekursiv ausgeführt werden soll, indem die Unterordner durchlaufen werden oder nicht.
  • action: die auszuführende Aktion unter den folgenden: Hervorheben, Schwärzen.
  • pages: die zu berücksichtigenden Seiten.
  • generate_output: Wählen Sie aus, ob der Inhalt der eingegebenen PDF-Datei in einer CSV-Datei gespeichert werden soll oder nicht

Bevor wir fertig sind, definieren wir nützliche Funktionen zum Analysieren von Befehlszeilenargumenten:

def is_valid_path(path):
    """Validates the path inputted and checks whether it is a file path or a folder path"""
    if not path:
        raise ValueError(f"Invalid Path")
    if os.path.isfile(path):
        return path
    elif os.path.isdir(path):
        return path
    else:
        raise ValueError(f"Invalid Path {path}")


def parse_args():
    """Get user command line parameters"""
    parser = argparse.ArgumentParser(description="Available Options")
    parser.add_argument('-i', '--input-path', type=is_valid_path,
                        required=True, help="Enter the path of the file or the folder to process")
    parser.add_argument('-a', '--action', choices=[
                        'Highlight', 'Redact'], type=str, help="Choose to highlight or to redact")
    parser.add_argument('-s', '--search-str', dest='search_str',
                        type=str, help="Enter a valid search string")
    parser.add_argument('-p', '--pages', dest='pages', type=tuple,
                        help="Enter the pages to consider in the PDF file, e.g. (0,1)")
    parser.add_argument("-g", "--generate-output", action="store_true", help="Generate text content in a CSV file")
    path = parser.parse_known_args()[0].input_path
    if os.path.isfile(path):
        parser.add_argument('-o', '--output_file', dest='output_file',
                            type=str, help="Enter a valid output file")
        parser.add_argument("-t", "--highlight-readable-text", action="store_true", help="Highlight readable text in the generated image")
        parser.add_argument("-c", "--show-comparison", action="store_true", help="Show comparison between captured image and the generated image")
    if os.path.isdir(path):
        parser.add_argument("-r", "--recursive", action="store_true", help="Whether to process the directory recursively")
    # To Porse The Command Line Arguments
    args = vars(parser.parse_args())
    # To Display The Command Line Arguments
    print("## Command Arguments #################################################")
    print("\n".join("{}:{}".format(i, j) for i, j in args.items()))
    print("######################################################################")
    return args

Die is_valid_path()Funktion validiert einen als Parameter eingegebenen Pfad und prüft, ob es sich um einen Dateipfad oder einen Verzeichnispfad handelt.

Die parse_args()Funktion definiert und legt die entsprechenden Einschränkungen für die Befehlszeilenargumente des Benutzers fest, wenn dieses Dienstprogramm ausgeführt wird.

Nachfolgend finden Sie Erläuterungen zu allen Parametern:

  • input_path: Ein erforderlicher Parameter zur Eingabe des Pfads der zu verarbeitenden Datei oder des zu verarbeitenden Ordners. Dieser Parameter ist mit der is_valid_path()zuvor definierten Funktion verknüpft.
  • action: Die Aktion, die in einer Liste vordefinierter Optionen ausgeführt werden soll, um eine fehlerhafte Auswahl zu vermeiden.
  • search_str: Der Text, nach dem gesucht werden soll, um bearbeitet zu werden.
  • pages: die Seiten, die bei der Verarbeitung einer PDF-Datei zu berücksichtigen sind.
  • generate_content: Gibt an, ob der erfasste Inhalt der Eingabedatei, ob ein Bild oder eine PDF-Datei, in eine CSV-Datei umgewandelt werden soll oder nicht.
  • output_file: Der Pfad der Ausgabedatei. Das Ausfüllen dieses Arguments wird durch die Auswahl einer Datei als Eingabe eingeschränkt, nicht eines Verzeichnisses.
  • highlight_readable_text: Grüne Rechtecke um lesbare Textfelder mit einem Konfidenzwert von mehr als 30 zeichnen.
  • show_comparison: Zeigt ein Fenster mit einem Vergleich zwischen dem Originalbild und dem verarbeiteten Bild an.
  • recursive: ob ein Ordner rekursiv verarbeitet werden soll oder nicht. Das Ausfüllen dieses Arguments wird durch die Auswahl eines Verzeichnisses eingeschränkt.

Schreiben wir zum Schluss den Hauptcode, der zuvor definierte Funktionen verwendet:

if __name__ == '__main__':
    # Parsing command line arguments entered by user
    args = parse_args()
    # If File Path
    if os.path.isfile(args['input_path']):
        # Process a file
        if filetype.is_image(args['input_path']):
            ocr_img(
                # if 'search_str' in (args.keys()) else None
                img=None, input_file=args['input_path'], search_str=args['search_str'], highlight_readable_text=args['highlight_readable_text'], action=args['action'], show_comparison=args['show_comparison'], generate_output=args['generate_output']
            )
        else:
            ocr_file(
                input_file=args['input_path'], output_file=args['output_file'], search_str=args['search_str'] if 'search_str' in (args.keys()) else None, pages=args['pages'], highlight_readable_text=args['highlight_readable_text'], action=args['action'], show_comparison=args['show_comparison'], generate_output=args['generate_output']
            )
    # If Folder Path
    elif os.path.isdir(args['input_path']):
        # Process a folder
        ocr_folder(
            input_folder=args['input_path'], recursive=args['recursive'], search_str=args['search_str'] if 'search_str' in (args.keys()) else None, pages=args['pages'], action=args['action'], generate_output=args['generate_output']
        )

Testen wir unser Programm:

$ python pdf_ocr.py

Ausgabe:

usage: pdf_ocr.py [-h] -i INPUT_PATH [-a {Highlight,Redact}] [-s SEARCH_STR] [-p PAGES] [-g GENERATE_OUTPUT]

Available Options

optional arguments:
  -h, --help            show this help message and exit
  -i INPUT_PATH, --input_path INPUT_PATH
                        Enter the path of the file or the folder to process
  -a {Highlight,Redact}, --action {Highlight,Redact}
                        Choose to highlight or to redact
  -s SEARCH_STR, --search_str SEARCH_STR
                        Enter a valid search string
  -p PAGES, --pages PAGES
                        Enter the pages to consider e.g.: (0,1)
  -g GENERATE_OUTPUT, --generate_output GENERATE_OUTPUT
                        Generate content in a CSV file

Beachten Sie Folgendes, bevor Sie unsere Testszenarien untersuchen:

  • Um PermissionErrordiesen Fehler zu vermeiden, schließen Sie bitte die Eingabedatei, bevor Sie dieses Dienstprogramm ausführen.
  • Die Suchzeichenfolge entspricht den Regeln regulärer Ausdrücke unter Verwendung des in Python integrierten re-Moduls. Wenn Sie die Suchzeichenfolge beispielsweise auf „organi[sz]e“ setzen, werden sowohl „organisieren“ als auch „organisieren“ gefunden.

Lassen Sie uns zunächst versuchen, ein Bild einzugeben (Sie können es hier abrufen, wenn Sie die gleiche Ausgabe erhalten möchten), ohne dass eine PDF-Datei beteiligt ist:

$ python pdf_ocr.py -s "BERT" -a Highlight -i example-image-containing-text.jpg

Folgendes wird die Ausgabe sein:

## Command Arguments #################################################
input_path:example-image-containing-text.jpg
action:Highlight
search_str:BERT
pages:None
generate_output:False
output_file:None
highlight_readable_text:False
show_comparison:False
######################################################################
## Summary ########################################################
File:example-image-containing-text.jpg
Total readable words:192
Total matches:3
Confidence score:89.89337547979804
###################################################################

Und im aktuellen Verzeichnis ist ein neues Bild erschienen:

Hervorheben von Text im Bild mit OCR-PythonSie können den gesamten erkannten Text übergeben -toder --highlight-readable-texthervorheben (mit einem anderen Format, um die Suchzeichenfolge von den anderen zu unterscheiden).

Sie können auch übergeben -coder --show-comparisondas Originalbild und das bearbeitete Bild im selben Fenster anzeigen.

Das funktioniert jetzt für Bilder, versuchen wir es mit PDF-Dateien:

$ python pdf_ocr.py -s "BERT" -i image.pdf -o output.pdf --generate-output -a "Highlight"

image.pdfist eine einfache PDF-Datei, die das Bild im vorherigen Beispiel enthält (auch hier können Sie es abrufen ).

Dieses Mal haben wir eine PDF-Datei an das -iArgument und output.pdfals resultierende PDF-Datei übergeben (in der die gesamte Hervorhebung erfolgt). Der obige Befehl erzeugt die folgende Ausgabe:

## Command Arguments #################################################
input_path:image.pdf
action:Highlight
search_str:BERT
pages:None
generate_output:True
output_file:output.pdf
highlight_readable_text:False
show_comparison:False
######################################################################
## Summary ########################################################
File:image.pdf
Total pages:1
Processed pages:1
Total readable words:192.0
Total matches:3.0
Confidence score:83.1775128855722
Output file:output.pdf
Content file:image.csv

Pages Statistics:
   page  page_readable_items  page_matches  page_total_confidence
0   1.0                192.0           3.0              83.177513
###################################################################

Die output.pdfDatei wird nach der Ausführung erstellt, wobei sie das gleiche Original-PDF enthält, jedoch mit hervorgehobenem Text. Darüber hinaus haben wir jetzt Statistiken über unsere PDF-Datei, in der insgesamt 192 Wörter erkannt wurden und 3 mit unserer Suche mit einer Zuverlässigkeit von etwa 83,2 % abgeglichen wurden.

Außerdem wird eine CSV-Datei generiert, die den erkannten Text aus dem Bild in jeder Zeile enthält.

Es gibt andere Parameter, die wir in unseren Beispielen nicht verwendet haben, fühlen Sie sich frei, sie zu erkunden. Sie können auch einen ganzen Ordner an das -iArgument übergeben, um eine Sammlung von PDF-Dateien zu scannen.

Tesseract ist perfekt zum Scannen sauberer und klarer Dokumente. Ein Scan von schlechter Qualität kann zu schlechten OCR-Ergebnissen führen. Normalerweise liefert es keine genauen Ergebnisse der Bilder, die von Artefakten wie teilweiser Okklusion, verzerrter Perspektive und komplexem Hintergrund betroffen sind.

Quelle des Originalartikels unter https://www.thepythoncode.com 

What is GEEK

Buddha Community

Shardul Bhatt

Shardul Bhatt

1626775355

Why use Python for Software Development

No programming language is pretty much as diverse as Python. It enables building cutting edge applications effortlessly. Developers are as yet investigating the full capability of end-to-end Python development services in various areas. 

By areas, we mean FinTech, HealthTech, InsureTech, Cybersecurity, and that's just the beginning. These are New Economy areas, and Python has the ability to serve every one of them. The vast majority of them require massive computational abilities. Python's code is dynamic and powerful - equipped for taking care of the heavy traffic and substantial algorithmic capacities. 

Programming advancement is multidimensional today. Endeavor programming requires an intelligent application with AI and ML capacities. Shopper based applications require information examination to convey a superior client experience. Netflix, Trello, and Amazon are genuine instances of such applications. Python assists with building them effortlessly. 

5 Reasons to Utilize Python for Programming Web Apps 

Python can do such numerous things that developers can't discover enough reasons to admire it. Python application development isn't restricted to web and enterprise applications. It is exceptionally adaptable and superb for a wide range of uses.

Robust frameworks 

Python is known for its tools and frameworks. There's a structure for everything. Django is helpful for building web applications, venture applications, logical applications, and mathematical processing. Flask is another web improvement framework with no conditions. 

Web2Py, CherryPy, and Falcon offer incredible capabilities to customize Python development services. A large portion of them are open-source frameworks that allow quick turn of events. 

Simple to read and compose 

Python has an improved sentence structure - one that is like the English language. New engineers for Python can undoubtedly understand where they stand in the development process. The simplicity of composing allows quick application building. 

The motivation behind building Python, as said by its maker Guido Van Rossum, was to empower even beginner engineers to comprehend the programming language. The simple coding likewise permits developers to roll out speedy improvements without getting confused by pointless subtleties. 

Utilized by the best 

Alright - Python isn't simply one more programming language. It should have something, which is the reason the business giants use it. Furthermore, that too for different purposes. Developers at Google use Python to assemble framework organization systems, parallel information pusher, code audit, testing and QA, and substantially more. Netflix utilizes Python web development services for its recommendation algorithm and media player. 

Massive community support 

Python has a steadily developing community that offers enormous help. From amateurs to specialists, there's everybody. There are a lot of instructional exercises, documentation, and guides accessible for Python web development solutions. 

Today, numerous universities start with Python, adding to the quantity of individuals in the community. Frequently, Python designers team up on various tasks and help each other with algorithmic, utilitarian, and application critical thinking. 

Progressive applications 

Python is the greatest supporter of data science, Machine Learning, and Artificial Intelligence at any enterprise software development company. Its utilization cases in cutting edge applications are the most compelling motivation for its prosperity. Python is the second most well known tool after R for data analytics.

The simplicity of getting sorted out, overseeing, and visualizing information through unique libraries makes it ideal for data based applications. TensorFlow for neural networks and OpenCV for computer vision are two of Python's most well known use cases for Machine learning applications.

Summary

Thinking about the advances in programming and innovation, Python is a YES for an assorted scope of utilizations. Game development, web application development services, GUI advancement, ML and AI improvement, Enterprise and customer applications - every one of them uses Python to its full potential. 

The disadvantages of Python web improvement arrangements are regularly disregarded by developers and organizations because of the advantages it gives. They focus on quality over speed and performance over blunders. That is the reason it's a good idea to utilize Python for building the applications of the future.

#python development services #python development company #python app development #python development #python in web development #python software development

August  Larson

August Larson

1624428000

Creating PDF Invoices in Python with pText

Introduction

The Portable Document Format (PDF) is not a WYSIWYG (What You See is What You Get) format. It was developed to be platform-agnostic, independent of the underlying operating system and rendering engines.

To achieve this, PDF was constructed to be interacted with via something more like a programming language, and relies on a series of instructions and operations to achieve a result. In fact, PDF is based on a scripting language - PostScript, which was the first device-independent Page Description Language.

In this guide, we’ll be using pText - a Python library dedicated to reading, manipulating and generating PDF documents. It offers both a low-level model (allowing you access to the exact coordinates and layout if you choose to use those) and a high-level model (where you can delegate the precise calculations of margins, positions, etc to a layout manager).

We’ll take a look at how to create a PDF invoice in Python using pText.

#python #pdf #creating pdf invoices in python with ptext #creating pdf invoices #pdf invoice #creating pdf invoices in python with ptext

Navigating Between DOM Nodes in JavaScript

In the previous chapters you've learnt how to select individual elements on a web page. But there are many occasions where you need to access a child, parent or ancestor element. See the JavaScript DOM nodes chapter to understand the logical relationships between the nodes in a DOM tree.

DOM node provides several properties and methods that allow you to navigate or traverse through the tree structure of the DOM and make changes very easily. In the following section we will learn how to navigate up, down, and sideways in the DOM tree using JavaScript.

Accessing the Child Nodes

You can use the firstChild and lastChild properties of the DOM node to access the first and last direct child node of a node, respectively. If the node doesn't have any child element, it returns null.

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");
console.log(main.firstChild.nodeName); // Prints: #text

var hint = document.getElementById("hint");
console.log(hint.firstChild.nodeName); // Prints: SPAN
</script>

Note: The nodeName is a read-only property that returns the name of the current node as a string. For example, it returns the tag name for element node, #text for text node, #comment for comment node, #document for document node, and so on.

If you notice the above example, the nodeName of the first-child node of the main DIV element returns #text instead of H1. Because, whitespace such as spaces, tabs, newlines, etc. are valid characters and they form #text nodes and become a part of the DOM tree. Therefore, since the <div> tag contains a newline before the <h1> tag, so it will create a #text node.

To avoid the issue with firstChild and lastChild returning #text or #comment nodes, you could alternatively use the firstElementChild and lastElementChild properties to return only the first and last element node, respectively. But, it will not work in IE 9 and earlier.

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");
alert(main.firstElementChild.nodeName); // Outputs: H1
main.firstElementChild.style.color = "red";

var hint = document.getElementById("hint");
alert(hint.firstElementChild.nodeName); // Outputs: SPAN
hint.firstElementChild.style.color = "blue";
</script>

Similarly, you can use the childNodes property to access all child nodes of a given element, where the first child node is assigned index 0. Here's an example:

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");

// First check that the element has child nodes 
if(main.hasChildNodes()) {
    var nodes = main.childNodes;
    
    // Loop through node list and display node name
    for(var i = 0; i < nodes.length; i++) {
        alert(nodes[i].nodeName);
    }
}
</script>

The childNodes returns all child nodes, including non-element nodes like text and comment nodes. To get a collection of only elements, use children property instead.

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");

// First check that the element has child nodes 
if(main.hasChildNodes()) {
    var nodes = main.children;
    
    // Loop through node list and display node name
    for(var i = 0; i < nodes.length; i++) {
        alert(nodes[i].nodeName);
    }
}
</script>

#javascript 

Alec  Nikolaus

Alec Nikolaus

1599758100

Convert Text to Speech in Python

Learn how to convert your Text into Voice with Python and Google APIs

Text to speech is a process to convert any text into voice. Text to speech project takes words on digital devices and convert them into audio with a button click or finger touch. Text to speech python project is very helpful for people who are struggling with reading.

Project Prerequisites

To implement this project, we will use the basic concepts of Python, Tkinter, gTTS, and playsound libraries.

  • Tkinter is a standard GUI Python library that is one of the fastest and easiest ways to build GUI applications using Tkinter.
  • gTTS (Google Text-to-Speech) is a Python library, which is a very easy library that converts the text into audio.
  • The playsound module is used to play audio files. With this module, we can play a sound file with a single line of code.

To install the required libraries, you can use pip install command:

pip install tkinter
pip install gTTS
pip install playsound

Download Python Text to Speech Project Code

Please download the source code of Text to Speech Project: Python Text to Speech

Text to Speech Python Project

The objective of this project is to convert the text into voice with the click of a button. This project will be developed using Tkinter, gTTs, and playsound library.

In this project, we add a message which we want to convert into voice and click on play button to play the voice of that text message.

  • Importing the modules
  • Create the display window
  • Define functions

So these are the basic steps that we will do in this Python project. Let’s start.

#python tutorials #python project #python project for beginners #python text to speech #text to speech convertor #python

Art  Lind

Art Lind

1602968400

Python Tricks Every Developer Should Know

Python is awesome, it’s one of the easiest languages with simple and intuitive syntax but wait, have you ever thought that there might ways to write your python code simpler?

In this tutorial, you’re going to learn a variety of Python tricks that you can use to write your Python code in a more readable and efficient way like a pro.

Let’s get started

Swapping value in Python

Instead of creating a temporary variable to hold the value of the one while swapping, you can do this instead

>>> FirstName = "kalebu"
>>> LastName = "Jordan"
>>> FirstName, LastName = LastName, FirstName 
>>> print(FirstName, LastName)
('Jordan', 'kalebu')

#python #python-programming #python3 #python-tutorials #learn-python #python-tips #python-skills #python-development