Selbstgeschriebene Funktionen
In diesem Beispiel wird erklärt, worauf beim Schreiben von eigenen Funktionen für Vision-Applikationen zu achten ist. Dabei geht es im Wesentlichen um:
- Handhabung des HRESULT
- Handhabung von Interface Pointern
Auch andere Strukturen Diese Funktionsimplementierung ist an die Struktur der TwinCAT Vision API-Funktionen angelehnt. Es sind auch andere Strukturen denkbar, achten Sie jedoch auf die hier erklärten Punkte. |
Auch Methoden In diesem Beispiel wird eine Funktion beschrieben. Es ist jedoch in gleichem Maße für Methoden gültig. |
Dazu wird beispielhaft eine selbst geschriebene Funktion zum Zählen und Malen von Objekten betrachtet:
FUNCTION F_CountAndDrawObjects : HRESULT
Deklarationsteil
Die Attribute der Funktion sind wie folgt im VAR_INPUT
-Teil deklariert. Das Ursprungsbild wird direkt als ITcVnImage
übergeben. Da in einer Funktion oder Methode keine Variablenwerte gespeichert werden, muss in diesem Fall nichts weiter beachtet werden. Hingegen wird das Ergebnisbild als REFERENCE TO ITcVnDisplayableImage
übergeben, da es in der Funktion erstellt wird und nach außen zur weiteren Verarbeitung zurückgegeben werden soll. Hier wird aufgrund der Reference also keine Kopie des Interface Pointers erstellt.
VAR_INPUT
ipSrcImage : ITcVnImage;
ipDestImage : REFERENCE TO ITcVnImage;
aColor : TcVnVector4_LREAL;
nNumberOfObjects : REFERENCE TO ULINT;
hrPrev : HRESULT;
END_VAR
Zudem werden einige Hilfsvariablen im VAR
deklariert, die intern von der Funktion benötigt werden.
VAR
hr : HRESULT;
ipContours : ITcVnContainer;
stParams : TcVnParamsBlobDetection;
END_VAR
Eingangsprüfungen
Am Anfang der Funktion werden einige Eingangsprüfungen durchgeführt, um sicherzustellen, dass die Funktion ordnungsgemäß ausgeführt werden kann.
Zunächst wird mittels FAILED(hrPrev)
überprüft, ob in der bisherigen Verarbeitungskette ein Fehler aufgetreten ist. Wenn dies der Fall ist, wird derselbe Fehler zurückgegeben und die Funktion direkt beendet.
IF FAILED(hrPrev) THEN
F_CountAndDrawObjects := hrPrev;
RETURN;
END_IF
Ebenfalls wird überprüft, ob alle Interface Pointer, die als VAR_INPUT an die Funktion übergeben werden, valide sind. Anderenfalls kann die Funktion nämlich nichts damit anfangen und gibt als Return Code INVALIDPARM zurück.
IF ipSrcImage = 0 THEN
F_CountAndDrawObjects := Tc2_System.E_HRESULTAdsErr.INVALIDPARM;
RETURN;
END_IF
Sofern alle Eingangsprüfungen erfolgreich waren, müssen z. B. bei Funktionsblöcken noch die Referenzzähler aller als VAR_INPUT
übergebenen Interface Pointer inkrementiert werden. Denn durch das Übergeben des Interface Pointers wird eine Kopie erstellt, die nach dem Ausführen des Bausteins erhalten bleiben und daher im Referenzzähler abgebildet werden müssen. Die Methode TcAddRef
kann direkt ohne vorherige <> 0
Prüfung ausgeführt werden, da dies schon während der Eingangsprüfungen geschehen ist. Wie schon im Deklarationsteil beschrieben, ist das Erhöhen des Referenzzählers bei Funktionen und Metthoden nicht notwendig, da die Variablenwerte wie in diesem Fall die Pointer-Adresse nach der Ausführung nicht erhalten bleiben.
Hauptverarbeitung
Im Hauptteil der Funktion steht der tatsächliche Bildverarbeitungsablauf. Dieser ist hier nur beispielhaft und wird nicht weiter betrachtet. Der Aufruf von F_VN_ConvertColorSpace
verdeutlicht, dass Interface Pointer, die zum Zwecke der Ergebnisrückgabe als REFERENCE TO
übergeben werden, direkt von TwinCAT Vision API-Funktionen beschrieben werden können.
hr := F_VN_ConvertColorSpace(ipSrcImage, ipDestImage, TCVN_CST_GRAY_TO_RGB, hr);
stParams.bFilterByArea := TRUE;
stParams.fMinArea := 10_000;
stParams.fMaxArea := 100_000;
hr := F_VN_DetectBlobs(ipSrcImage, ipContours, stParams, hr);
hr := F_VN_GetNumberOfElements(ipContours, nNumberOfObjects, hr);
hr := F_VN_DrawContours(ipContours, -1, ipDestImage, aColor, 5, hr);
Durch diesen Bildverarbeitungsablauf werden Objekte im Ergebnisbild gemalt und ihre Anzahl als ULINT zurückgegeben:
Ursprungsbild | Ergebnisbild |
Anzahl gefundener Objekte: 4 |
|
Aufräumen und Rückgabe
Nach dem eigentlichen Bildverarbeitungsablauf müssen die Interface Pointer, die innerhalb der Funktion deklariert sind, wieder freigegeben werden. Dies ist der Fall, weil alle in der Funktion deklarierten Variablen (also auch die Interface Pointer) nach Beenden der Funktion gelöscht werden. Wenn im Hintergrund nun noch Daten vorhanden wären, die noch nicht freigegeben sind, entständen Speicher-Lecks.
FW_SafeRelease(ADR(ipContours));
Schließlich wird das HRESULT
als Rückgabewert der Funktion zugewiesen, um eventuelle Fehler nach außen zu melden. Damit es nicht verfälscht wird, sollten die Rückgabewerte der FW_SafeRelease
Funktionen nicht dem HRESULT
zugewiesen werden.
F_CountAndDrawObjects := hr;