OCR
Dieses Beispiel zeigt, wie Zeichen z.B. von Daten und Chargennummern auf Produktverpackungen mit der OCR-Funktionalität (Optical Character Recognition) erkannt werden können. Der Code veranschaulicht die Anwendung von der Standardfunktion F_VN_OCR als auch der erweiterten F_VN_OCRExp Funktion inklusive der benötigten Vor- und Nachverarbeitung.
Erläuterung
Die Funktionen ermöglichen die Erkennung von alphanumerischen Zeichen in Binärbildern (weiße Zeichen auf schwarzem Hintergrund). Die Klassifizierung basiert auf Machine Learning Modellen mit unterschiedlichem Funktions- und Zeichenumfang.
- Durch das Enum ETcVnOcrModelType kann auf die verschiedenen Modelle zugegriffen werden:
TCVN_OMT_NUMBERS
: ZahlenTCVN_OMT_NUMBERS_SC
: Zahlen + SonderzeichenTCVN_OMT_UCLETTERS
: GroßbuchstabenTCVN_OMT_NUMBERS_SC_UCLETTERS
: Kombinierter Zeichensatz- Die Funktion
F_VN_OCRExp
bietet erweiterte Optionen: sPattern
für definierte Format- und Zeichenvorgaben (z.B. „uudd“ für „AB12“)eOcrOptions
zusätzliche ETcVnOcrOptions die die Funktionsweise und Ergebnisausgabe beeinflussenipBoundingBoxes
für die Rückgabe von Bounding Boxes für die erkannten ZeichenipConfidences
für die Konfidenzwerte pro Zeichen
Die vollständige Beschreibung, die Anforderungen und Einschränkungen sowie weitere Informationen finden Sie im Kapitel OCR und unter den jeweiligen Funktionen.
Modellinitialisierung
Für die OCR-Erkennung muss das zugrundeliegende Zeichenerkennungsmodell vor der ersten Nutzung initialisiert werden. Dies erfolgt über den Funktionsbaustein FB_VN_InitializeFunction, wobei bei eFunction
zunächst die zu initialisierende Funktion angegeben werden muss. Mit nOptions
werden die Modelle festgelegt, die später beim OCR-Funktionsaufruf verwendet werden sollen. Dabei können mehrere Modelle gleichzeitig mit einem Funktionsaufruf initialisiert werden.
Mit F_VN_CheckFunctionInitialization kann anschließend gecheckt werden, ob das jeweilige Modell initialisiert wurde. Soll das Model zur Laufzeit gewechselt werden oder wird nicht mehr benötigt, kann mit F_VN_DeinitializeFunction das Modell deinitialisiert werden, um so den Speicher wieder freizugeben.
Variablen
bInitialized : BOOL := FALSE;
fbInit : FB_VN_InitializeFunction;
nReturnCode : UDINT;
Code
IF NOT bInitialized THEN
fbInit(
eFunction := TCVN_IF_OCR,
nOptions := ETcVnOcrModelType.TCVN_OMT_NUMBERS_SC OR ETcVnOcrModelType.TCVN_OMT_UCLETTERS,
bStart := TRUE);
IF NOT fbInit.bBusy THEN
fbInit(bStart := FALSE);
IF NOT fbInit.bError THEN
bInitialized := TRUE;
nReturnCode := fbInit.nErrorId AND 16#FFF;
ELSE
nReturnCode := fbInit.nErrorId AND 16#FFF;
END_IF
END_IF
END_IF
Vorverarbeitung
Für die Anwendung der OCR-Funktionen sind einige Vorverarbeitungsschritte notwendig bzw. sinnvoll. Zunächst muss ein ROI definiert werden, die nur die zu erkennenden Zeichen einer Zeile und eine störungsfreie Zone um die Zeichen herum enthält. Des Weiteren muss diese Bildregion in ein 1-kanaliges Binärbild gewandelt werden, dass nur die weißen zu erkennenden Zeichen auf schwarzem Hintergrund enthält. In diesem Beispiel wird dazu die F_VN_Threshold verwendet, die abhängig von dem Hintergrund und der Zeichenfarbe normal oder invertiert angewendet wird.
Da in dem Beispielprojekt Bilder von unterschiedlichen Produkten mit verschiedenen Szenarien verwendet werden, wurden einige Parameter wie z.B. stRoi
und fThreshold
innerhalb der Funktion F_GetROI
für jedes Testbild individuell hinterlegt und anhand des Bildnamens abgerufen. In der Praxis werden die unterschiedlichen Parameterwerte üblicherweise über ein Rezept in der Bedienoberfläche gehändelt. Für die weitere Beschreibung der Beispielanwendung wird das folgende Bild verwendet, auf dem die spezifizierte ROI rot eingezeichnet wurde.

Zusätzlich zu den notwendigen Vorverarbeitungen können, wie im Beispiel gezeigt, Filteroperationen zur Rauschunterdrückung und morphologische Operationen wie Opening oder Closing angewendet werden, um kleine Störungen zu entfernen und Zeichenformen zu glätten bzw. zu vervollständigen. Häufig werden auch Funktionen zur Kontrastverstärkung verwendet. Die Wahl der geeigneten Filterfunktionen und Parameter hängt stark von den spezifischen Eigenschaften des Bildmaterials ab, daher können noch andere Funktionen z.B. aus ImageColorAndContrastProcessing, ImageFiltering oder ImageSegmentation zur Verbesserung beitragen.
Ein weiterer hilfreicher Schritt kann die Entfernung von Randobjekten mit den Funktionen F_VN_BrightBorderObjects und F_VN_SubtractImages sein. Dadurch werden störende Objekte am Rand der Bildregion eliminiert. Diese entstehen häufig bei ungenauer ROI-Definition, z. B. wenn Teile benachbarter Zeichen oder Zeilen versehentlich im Ausschnitt enthalten sind, insbesondere wenn die Abstände dazwischen recht klein sind.
In dem Beispielprojekt werden folgende Vorverarbeitungsschritte durchgeführt:
Code
// Set ROI
hr := F_VN_SetRoi_TcVnRectangle_UDINT(stRoi, ipBinaryImage, hr);
// Filter image
hr := F_VN_CreateStructuringElement(ipStructElem, ETcVnStructuringElementShape.TCVN_SES_RECTANGLE, 3,3, hr);
hr := F_VN_MorphologicalOperator(ipBinaryImage, ipBinaryImage, ETcvnMorphologicalOperator.TCVN_MO_OPENING, ipStructElem, hr);
// Binarize image depending on bright or dark text color
IF bInvertImage THEN
hr := F_VN_Threshold(ipBinaryImage, ipBinaryImage, fThreshold, 255, TCVN_TT_BINARY_INV, hr);
ELSE
hr := F_VN_Threshold(ipBinaryImage, ipBinaryImage, fThreshold, 255, TCVN_TT_BINARY, hr);
END_IF
// Remove border objects
hr := F_VN_BrightBorderObjects(ipBinaryImage, ipThreshBorder, hr);
hr := F_VN_SubtractImages(ipBinaryImage, ipThreshBorder, ipBinaryImage, hr);
OCR-Anwendung
Nach erfolgreicher Vorverarbeitung kann die OCR-Funktion angewendet werden. Im Beispielprojekt lässt sich über den Parameter bUseExpFunction
zwischen der Standard- und der Expert-Version wechseln. Die nachfolgende Beschreibung bezieht sich auf die Anwendung der Expert-Version und die zusätzlichen Möglichkeiten.
Mit dem Parameter sPattern
kann das zu erkennende Zeichenformat vorgegeben werden. Diese Möglichkeit ist besonders sinnvoll, wenn die Reihenfolge und der Typ der zu erkennenden Zeichen im Vorfeld bekannt sind. Dann kann für jede Position in der Zeichenkette spezifiziert werden, welches Zeichen erwartet wird. Dadurch hat die Funktion die Information welches Erkennungsmodell pro Zeichen verwendet werden soll, was zu besseren Ergebnissen führen kann. Die spezifischen Modelle enthalten weniger Zeichen, wodurch eine geringer Verwechselungsgefahr entsteht. Weiterhin gibt die Funktion direkt ein S_FALSE
zurück, wenn die erkannten Zeichen nicht mit der Vorgabe übereinstimmen.
Für das gezeigte Bild wird das Muster "uu#dddddddd" verwendet, um die Zeichenkette zu erkennen. Dies bedeutet, dass für die ersten zwei Zeichen das Modell TCVN_OMT_UCLETTERS
zum Einsatz kommt, um Großbuchstaben zu identifizieren. Anschließend nutzt die Funktion für die folgenden neun Zeichen das Modell TCVN_OMT_NUMBERS_SC
, wobei an erster Position ein Sonderzeichen und an den restlichen acht Positionen jeweils eine Ziffer erwartet werden.
Code
hrOCR := F_VN_OCRExp(
ipSrcImage := ipBinaryImage,
eModel := ETcVnOcrModelType.TCVN_OMT_NUMBERS_SC or ETcVnOcrModelType.TCVN_OMT_UCLETTERS,
ipCharacters := ipOCRResult,
sPattern := sPattern,
eOcrOptions := eOcrOptions,
ipBoundingBoxes := ipBoundingBoxes,
ipConfidences := ipConfidences,
hrPrev := hr,
fMinConfidence => fMinConfidence);
// Check if characters were found
hr := F_VN_GetNumberOfElements(ipOCRResult, nNumberOfElements, hrOCR);
IF SUCCEEDED(hr) AND nNumberOfElements > 0 THEN
// Export character to string
hr := F_VN_ExportSubContainer_String(ipOCRResult, 0, sText, 255, hr);
// Write text result to image
hr := F_VN_PutText(sText, ipOriginalImage, stRoi.nX + 5, stRoi.nY + 25, TCVN_FT_HERSHEY_DUPLEX, 1, aGreenColor, hr);
// Further processing …
END_IF
OCR-Ergebnisauswertung
Nach dem Aufruf der OCR-Funktion sollte zuerst der Rückgabewert HRESULT
ausgewertet und geprüft werden, ob oder wie viele Zeichen erkannt wurden. Wenn S_OK
zurückgegeben wird, hat die Standardfunktion Zeichen erkannt, bei der Expert Version hängt es davon ab, ob eine sPattern
Vorgabe übergeben wurde. Falls es eine Vorgabe gibt, wird nur S_OK
zurückgegeben, wenn die erkannten Zeichen damit übereinstimmen. Ansonsten wird S_False
zurückgegeben und man kann die erkannten Zeichen selbst weiter untersuchen.
Wenn Zeichen erkannt wurden, können diese in einen String exportiert und z.B. in ein Bild zur visuellen Rückmeldung eingezeichnet werden. Weiterhin kann die Anzahl der Zeichen, der gesamte String oder auch einzelne Zeichen mit hinterlegen Erwartungswerten verglichen werden. Da diese Beurteilungen sehr individuell sind und mit Standard SPS-Funktionen umgesetzt werden können, wird in diesem Beispiel darauf verzichtet.
Bei Verwendung der Expert-Version können zur detaillierteren Analyse noch die einzelnen Klassifizierungskonfidenzen der erkannten Zeichen exportiert, angeschaut und als Akzeptanzkriterien verwendet werden.
Um die Abgrenzungen, Überlappung oder evtl. falsch erkannte Zeichen zuordnen zu können, besteht die Möglichkeit die Bounding Boxen der einzelnen erkannten Zeichen abzurufen, auszuwerten und ein Bild einzuzeichnen. Beim Verrechnen und Einzeichnen muss ggf. die zuvor gesetzte ROI beachtet werden.
Code
// Get number of Confidence elements and export them if array is large enough
hr := F_VN_GetNumberOfElements(ipConfidences, nNumberOfElements, hr);
// Check if number of elements fits to array size
IF nNumberOfElements > 0 AND nNumberOfElements <= 12 THEN
hr := F_VN_ExportContainer(ipConfidences, ADR(aConfidences), SIZEOF(aConfidences), hr);
END_IF
// Get bounding box rectangle and draw it to filtered and original image
hr := F_VN_GetNumberOfElements(ipBoundingBoxes, nNumberOfElements, hr);
IF nNumberOfElements > 0 THEN
FOR nIterator := 0 TO nNumberOfElements -1 DO
hr := F_VN_GetAt_TcVnRectangle_DINT(ipBoundingBoxes, stRectangle, nIterator, hr);
hr := F_VN_DrawRectangle_TcVnRectangle_DINT(stRectangle, ipBinaryImage, aWhiteColor, 1, hr);
// Add ROI Offset
stRectangle.nX := stRectangle.nX + UDINT_TO_DINT(stRoi.nX);
stRectangle.nY := stRectangle.nY + UDINT_TO_DINT(stRoi.nY);
hr := F_VN_DrawRectangle_TcVnRectangle_DINT(stRectangle, ipOriginalImage, aBlueColor, 1, hr);
END_FOR
END_IF
Ergebnisdarstellung
Das folgende Bild zeigt die Ergebnisdarstellung der Expert-Funktion. In grün werden die erkannten Zeichen eingezeichnet und in blau die optionalen Bounding Boxen.

Die Konfidenzwerte für jedes erkannte Zeichen stehen zur weiteren Auswertung in dem Array aConfidences
zur Verfügung.
