Home / 
Blog / 
OCR auf technische Zeichnungen anwenden

OCR auf technische Zeichnungen anwenden

Dr. Frank Weilandt

Am 10. May 2019 in Hands-on Machine Learning

(Dieser Artikel ist eine Übersetzung des englischsprachigen Originalartikels. Die Übersetzung wurde teilweise automatisch mit www.DeepL.com/Translator erstellt.)


Wir arbeiten derzeit an einem spannenden Projekt, bei dem der Computer Zahlen und Buchstaben in technischen Zeichnungen einliest. Diese Zahlen und Buchstaben werden verwendet, um die Objekte in den Zeichnungen zu kennzeichnen. Hier sind einige Beispiele für diese Art von technischen Zeichnungen (klicken Sie auf die Bilder, um sie zu vergrößern):

Unternehmen sammeln im Laufe der Jahre oft große Mengen ähnlicher Zeichnungen, aber ihre automatische Interpretation ist eine Herausforderung. Für den Menschen mag es offensichtlich sein, auf welches Objekt oder Teil der Zeichnung sich eine Zahl bezieht, aber wie können wir einem Computer beibringen, die Zusammenhänge zu erkennen? Dazu bedarf es natürlich der Computervision und insbesondere der OCR (Optical Character Recognition).


Um unsere Präsentation zu vereinfachen, nehmen wir nur Punkte als Objekte. Jetzt können wir daraus eine Aufgabe machen, die für Kinder einfach ist, aber für den Computer schwieriger: Verbinden von nummerierten Punkten. Es sind dicke Punkte auf einem Blatt Papier gedruckt, jeder Punkt hat eine Zahl daneben. Dann zeichnet man Linien von einem Punkt zum nächsten, in der durch die Zahlen angegebenen Reihenfolge. Wenn Ihnen diese Beschreibung nichts sagt, schauen Sie sich diesen Wikipedia-Eintrag an.


Im Allgemeinen kann dies eine ziemlich anspruchsvolle Aufgabe für einen Computer sein: Wenn nur eine einzelne Ziffer falsch interpretiert wird, ist es unmöglich, die Punkte zu sortieren. Zudem enthalten viele dieser Bilder für Kinder einige gedruckte Linien, die weder Punkte noch Zahlen sind. In den Beispielen hier beschränken wir uns auf Rätsel, die auf der Website http://www.picturedots.com/ erstellt wurden. Der Algorithmus geht davon aus, dass wir maximal 99 Punkte haben, dass jede Zahl nur zu einem Punkt gehört und dass sich die Zahlen in der gegebenen Bilddatei nicht schneiden.


Viele Annahmen. Aber die Gesamtstrategie, die Punkte von den Ziffern zu trennen und dann die Ziffern mittels OCR einzulesen, ist für ähnliche Aufgaben immer noch sinnvoll.

Vorbereitungen

Dieses Notebook verwendet Python 3. Zunächst importieren wir die benötigten Pakete: Wir verwenden die Bildverarbeitungsbibliothek OpenCV (Version 3) mehrmals in diesem Notebook. Der Python-Wrapper pytesseract für die Google Tesseract-OCR-Engine wird nur einmal in einer Zelle weiter unten angewendet. Man kann sich auch ein anderes Werkzeug zum Lesen jeder Ziffer vorstellen, vielleicht auch einen Klassifikator, den man selbst trainiert hat, angepasst an die für die Ziffern verwendete Schriftart. Hier war glücklicherweise kein Training notwendig. Alle Dateien werden aus dem Verzeichnis image_dir gelesen oder in dieses geschrieben. Wir verwenden Matplotlib, um Bilder zu visualisieren, wenn show_images auf True gesetzt ist.

import os
import cv2
import pytesseract

show_images = True
image_dir = 'dots'
image_file = os.path.join(image_dir, 'input.png')

im = cv2.imread(image_file, cv2.IMREAD_COLOR)
if show_images:
    import matplotlib.pyplot as plt
    %matplotlib inline
    plt.figure(figsize=(15,10))
    plt.imshow(im);

Begrenzungsrahmen

Die folgende Funktion findet Begrenzungsrahmen für alle Objekte im Bild. Jeder Rahmen wird entweder als Begrenzungsrahmen eines Punktes oder einer Ziffer klassifiziert. Beachten Sie, dass wir davon ausgehen, dass es keine anderen Objekte im Bild gibt. Wenn es mehr Objekte gäbe, bräuchte man eine Regel, um sie auszuschließen. Um Ziffern von Punkten zu unterscheiden, verwenden wir, dass ein Kästchen, das eine Ziffer umschließt, eine größere Höhe als Breite hat. Dies gibt uns zwei Listen von Boxen: rects_digits um die Ziffern und rects_dots um die Punkte. Die Funktion gibt auch das per Schwellenwertverfahren gewonnene  Bild im_th und die Konturen ctrs zurück, die für die weitere Inspektion der Zwischenschritte verwendet werden können.

def find_dots_and_digits(im):
    im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    ret, im_th = cv2.threshold(im_gray, 30, 255, cv2.THRESH_BINARY_INV)
    im2, ctrs, _ = cv2.findContours(im_th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    rects = [cv2.boundingRect(ctr) for ctr in ctrs]
    rects_digits = []
    rects_dots = []
    for rect in rects:
        if rect[3] > 1.1*rect[2]:
            rects_digits.append(rect)
        else:
            rects_dots.append(rect)
    return (im_th, ctrs, rects_digits, rects_dots)

Tesseract einsetzen

Nun lesen wir die Ziffern mit Tesseract OCR und schreiben die Ausgabe der OCR in das Dictionary rect_to_ocr. Es gibt hier zwei wichtige Parameter für Tesseract: Seitensegmentierungsmodus (PSM) und die erwartete Sprache. Wir haben PSM auf die Zahl 10 gesetzt. Das bedeutet, dass Tesseract die Eingabe als ein einziges Zeichen behandelt. Dies gilt hier, da jedes Feld genau eine Ziffer enthält.


In unseren Experimenten interpretierte Tesseract manchmal eine Ziffer als Buchstaben. Um dies zu vermeiden, könnte man eine Zeichen-Whitelist verwenden. Unsere Version von Tesseract 4.0 unterstützt diese Funktion jedoch nicht. Daher haben wir ein wenig mit dem verwendeten Zeichensatz experimentiert. Die Software dazu zu bringen, Ziffern oder hebräische Buchstaben zu erwarten, hat die Verwechslungen beseitigt und die Ziffern korrekt identifiziert. Wenn du selbst experimentieren möchtest, findest du hier eine Erklärung der Möglichkeiten, die Tesseract bereitstellt.

im_th, ctrs, rects_digits, rects_dots = find_dots_and_digits(im)
width_boxes_digits = 0
rect_to_ocr = {}

for rect in rects_digits:
    box = 255 - im_th[rect[1]-2:rect[1]+rect[3]+2, rect[0]-2:rect[0]+rect[2]+2]
    text = pytesseract.image_to_string(box, config='--psm 10', lang='heb')
    rect_to_ocr[rect] = int(text)
    width_boxes_digits += rect[2]/len(rects_digits)

Hier zoomen wir in das Bild, um einige der gefundenen Begrenzungsrahmen zu visualisieren.

if show_images:
    im_boxes = im.copy()
    for rect in rects_dots:
        cv2.rectangle(im_boxes, (rect[0], rect[1]),
                      (rect[0] + rect[2], rect[1] + rect[3]), (0, 255, 0), 2)
    for rect in rects_digits:
        cv2.rectangle(im_boxes, (rect[0], rect[1]),
                      (rect[0] + rect[2], rect[1] + rect[3]), (0, 0, 255), 2)
    plt.figure(figsize=(20,10))
    plt.imshow(im_boxes[400:800, 1300:1800])


Die folgende Zelle erstellt das Dictionary numbered_dots. Jede Zahl wird dem Mittelpunkt des nächstgelegenen Punktes zugeordnet. Das Dictionary ist wie folgt aufgebaut: Für jeden Punkt sucht man nach Ziffern, die sich auf der rechten Seite des Punktes und nicht zu weit entfernt befinden. Diese Strategie reicht für die Art der von uns verwendeten Bilder aus. Wenn es zwei Ziffern gibt, sortieren wir die Begrenzungsrechtecke nach der x-Koordinate und kombinieren beide Ziffern zu einer Zahl.

numbered_dots = {}
for rect_dot in rects_dots:
    rects_close_digits = []
    for rect_digit in rects_digits:
        if 0 < rect_digit[0] - rect_dot[0] < 3 * width_boxes_digits:
            if -5 < rect_dot[1] - rect_digit[1] < 2 * width_boxes_digits:
                rects_close_digits.append(rect_digit)
    rects_close_digits.sort()
    number = rect_to_ocr[rects_close_digits[0]]
    if len(rects_close_digits) == 2:
        number = 10 * number + rect_to_ocr[rects_close_digits[1]]
    midpoint = (rect_dot[0] + rect_dot[2]//2, rect_dot[1] + rect_dot[3]//2)
    numbered_dots[number] = midpoint

Es ist ein Apfel!

Jetzt können wir endlich alle Informationen kombinieren und die Verbindungslinien in das vorgegebene Bild zeichnen. Das endgültige Bild wird in image_dir geschrieben.

picture = im.copy()
for n in range(1, len(numbered_dots)):
    cv2.line(picture, numbered_dots[n], numbered_dots[n+1], (255, 0, 0), 5)
cv2.imwrite(os.path.join(image_dir, 'connected_dots.png'), picture)
if show_images:
    plt.figure(figsize=(15,10))
    plt.imshow(picture)
Referenzen

Übersetzt mit Hilfe von deepl.com

Lesen Sie auch

15. Jul 2019

(Dieser Artikel ist eine Übersetzung des englischsprachigen Originalartikels. Die Übersetzung wurde teilweise automatisch mit weiterlesen

24. May 2019

(Dieser Artikel ist eine Übersetzung des englischsprachigen Originalartikels. Die Übersetzung... weiterlesen


Erfahren Sie, was dida für Sie tun kann