Match Contours 1vsN (manuelle Formen)
In diesem Beispiel werden Konturen mit Hilfe der Funktion F_VN_MatchContours1vsN mit Referenz-Konturen verglichen. Dabei sind
- die Referenz-Konturen idealisierte, manuell erstellte Polygone
- und die anderen Konturen werden aus einem Bild extrahiert.
Erläuterung
Die Funktion F_VN_MatchContours vergleicht zwei gegebene Konturen mit Hilfe der Hu Momente. Die Funktion F_VN_MatchContours1vsN stellt eine Erweiterung dar, mit der eine Kontur gleichzeitig mit mehreren anderen Konturen verglichen werden kann. Dies wird in diesem Beispiel benutzt, um Werkstücke bezüglich vorgegebener Referenzformen zu klassifizieren.
Die Referenzformen sind idealisierte, manuell erstellte Polygone eines gleichschenkligen Dreiecks, eines Rechtecks/Quadrats und eines Trapezes. Da bei den Polygonen nur die Eckpunkte angegeben wurden, unterscheiden sich die Referenzformen von den Testkonturen in der Anzahl der zu beschreibenden Konturpunkte stark. Weiterhin unterscheiden sie sich in Lage, Orientierung, Größe und dem Grad der Störungen innerhalb der Kontur.
Um die Form der Bauteile aus dem Bild zu extrahieren, werden mit Hilfe der Funktion F_VN_DetectBlobs Konturen gesucht, die eine gewisse Mindestgröße haben. Die gefundenen Konturen werden daraufhin für das beschriebene Matching genutzt.
Eingangsparameter
Neben den zu vergleichenden Konturen, muss der Funktion nur ein Parameter übergeben werden, der die Berechnungsmethode beschreibt, mit der aus den Hu Momenten das Ungleichheitsmaß bestimmt wird (eComparisonMethod vom Typ ETcVnContoursMatchComparisonMethod). Die Methode TCVN_CMCM_CONTOURS_MATCH_I1
berechnet die Summe über die Differenzen der Kehrwerte der individuellen Charakteristiken, während die Methode TCVN_CMCM_CONTOURS_MATCH_I2
die Summe über die Differenzen der reinen Charakteristiken bildet. Im Gegensatz zu den ersten beiden Methoden berechnet die dritte Variante TCVN_CMCM_CONTOURS_MATCH_I3
nur die maximale Differenz der individuellen Charakteristiken. Je nach Anwendungsfall kann eine andere der drei Methoden am besten geeignet sein für den Vergleich zweier Konturen.
Variablen
Datentyp nur in diesem Beispiel Der Datentyp CustomTcVnArray4_Point2_DINT ist nicht in TwinCAT Vision enthalten, sondern wurde explizit für dieses Beispiel erstellt. Die Implementierung finden Sie im Download dieses Beispiels. |
// Indexes representing the different shapes
TRIANGLE : USINT := 0;
RECTANGLE : USINT := 1;
TRAPEZOID : USINT := 2;
// Images
ipImageIn : ITcVnImage;
ipImageInDisp : ITcVnDisplayableImage;
ipImageRes : ITcVnImage;
ipImageResDisp : ITcVnDisplayableImage;
// Contours
ipContourList : ITcVnContainer;
ipContour : ITcVnContainer;
ipIterator : ITcVnForwardIterator;
aShapeArrays : ARRAY [0..2] OF CustomTcVnArray4_Point2_DINT :=
[[[0,0],[40,0],[20, LREAL_TO_DINT(SQRT(1200))], [0,0]], // Triangle
[[0,0],[40,0],[40,40],[0,40]], // Rectangle
[[0,0],[40,0],[60,22],[20,22]]]; // Trapezoid;
aShapes : ARRAY[0..2] OF ITcVnContainer;
ipShapes : ITcVnContainer;
// Matching
ipMatchIndexes : ITcVnContainer;
ipDissimilarities : ITcVnContainer;
aMatchIndexes : ARRAY [0..2] OF ULINT;
aDissimilarities : ARRAY [0..2] OF LREAL;
// Parameters
stBlobParams : TcVnParamsBlobDetection;
fThreshold : REAL := 170;
fMinArea : REAL := 10000;
fMaxDissimilarity : LREAL := 0.02;
eComparisonMethod : ETcVnContoursMatchComparisonMethod := TCVN_CMCM_CONTOURS_MATCH_I3;
// drawing
aColors : ARRAY[0..2] OF TcVnVector4_LREAL :=
[[0, 175, 0, 0], [0, 0, 255, 0], [255, 0, 0, 0]]; // green, blue, red
aColorWhite : TcVnVector4_LREAL := [255, 255, 255];
aColorBlack : TcVnVector4_LREAL := [0, 0, 0];
aTexts : ARRAY[0..2] OF STRING := ['Triangle', 'Rectangle', 'Trapezoid'];
sText : STRING(255);
nTopLeftX : UDINT;
nTopLeftY : UDINT;
// Miscellaneous
aPixelValue : TcVnVector4_LREAL;
I : USINT;
stBoundingRectangle : TcVnRectangle_UDINT;
aOffsets : ARRAY [0..2] OF TcVnPoint := [[20, 50], [20, 100], [20, 160]];
hr : HRESULT;
Code
// Fill manually defined shapes into one container
hr := F_VN_CreateContainer(ipShapes, ContainerType_Vector_Vector_TcVnPoint2_DINT, 0, hr);
FOR i:=TRIANGLE TO TRAPEZOID DO
hr := F_VN_CreateContainerFromArray(ADR(aShapeArrays[i]), aShapes[i], ContainerType_Vector_TcVnPoint2_DINT, 4, hr);
hr := F_VN_InsertIntoContainer_ITcVnContainer(aShapes[i], ipShapes, i, hr);
END_FOR
// Prepare result image
hr := F_VN_ConvertColorSpace(ipImageIn, ipImageRes, TCVN_CST_GRAY_TO_RGB, hr);
// Check if background is light or dark
hr := F_VN_GetPixel(ipImageIn, aPixelValue, 50, 50, hr);
IF SUCCEEDED(hr) AND_THEN aPixelValue[0] < 128 THEN
stBlobParams.eThresholdType := TCVN_TT_BINARY;
ELSE
stBlobParams.eThresholdType := TCVN_TT_BINARY_INV;
END_IF
// Find contours in image
stBlobParams.bFilterByArea := TRUE;
stBlobParams.fMinArea := fMinArea;
stBlobParams.fMinThreshold := fThreshold;
hr := F_VN_DetectBlobs(ipImageIn, ipContourList, stBlobParams, hr);
// Iterate through all found contours
hr := F_VN_GetForwardIterator(ipContourList, ipIterator, hr);
WHILE hr = S_OK AND_THEN ipIterator.CheckIfEnd() <> S_OK DO
hr := F_VN_GetContainer(ipIterator, ipContour, hr);
hr := F_VN_IncrementIterator(ipIterator, hr);
// Match the current contour with the reference shapes
hr := F_VN_MatchContours1vsN(
ipRefContour:= ipContour,
ipContours:= ipShapes,
ipMatchIndexes:= ipMatchIndexes,
ipDissimilarities:= ipDissimilarities,
fDissimilarityThreshold:= 100,
eComparisonMethod:= eComparisonMethod,
hrPrev:= hr
);
hr := F_VN_ExportContainer(ipMatchIndexes, ADR(aMatchIndexes), SIZEOF(aMatchIndexes), hr);
hr := F_VN_ExportContainer(ipDissimilarities, ADR(aDissimilarities), SIZEOF(aDissimilarities), hr);
// Draw matching results
IF aDissimilarities[0] < fMaxDissimilarity THEN
// Calculate position of object
hr := F_VN_UprightBoundingRectangle(ipContour, stBoundingRectangle, hr);
nTopLeftX := LREAL_TO_UDINT(stBoundingRectangle.nX + 30);
nTopLeftY := LREAL_TO_UDINT(stBoundingRectangle.nY + (stBoundingRectangle.nHeight / 2));
// Draw matching result
hr := F_VN_DrawContours(ipContour, -1, ipImageRes, aColors[aMatchIndexes[0]], 5, hr);
hr := F_VN_PutTextExp(aTexts[aMatchIndexes[0]], ipImageRes, nTopLeftX, nTopLeftY, TCVN_FT_HERSHEY_SIMPLEX, 0.8, aColors[aMatchIndexes[0]], 2, TCVN_LT_8_CONNECTED, FALSE, hr);
hr := F_VN_DrawRectangle(nTopLeftX, nTopLeftY + 5, nTopLeftX + 200, nTopLeftY + 85, ipImageRes, aColorBlack, -1, hr);
// Draw all dissimilarity values
FOR i:=0 TO 2 DO
sText := CONCAT(LEFT(aTexts[aMatchIndexes[i]], 4), CONCAT(' ', REAL_TO_STRING(LREAL_TO_REAL(aDissimilarities[i]))));
hr := F_VN_PutTextExp(sText, ipImageRes, nTopLeftX + 5, nTopLeftY + 30 + 20*i, TCVN_FT_HERSHEY_SIMPLEX, 0.6, aColorWhite, 1, TCVN_LT_8_CONNECTED, FALSE, hr);
END_FOR
END_IF
END_WHILE
// Draw reference shapes
FOR i:=TRIANGLE TO TRAPEZOID DO
hr := F_VN_DrawContoursExp(aShapes[i], -1, ipImageRes, aColors[i], 2, TCVN_LT_8_CONNECTED, 0, 0, aOffsets[i], hr);
END_FOR
hr := F_VN_TransformIntoDisplayableImage(ipImageRes, ipImageResDisp, hr);
hr := F_VN_TransformIntoDisplayableImage(ipImageIn, ipImageInDisp, hr);
Ergebnisse
Das Ergebnisbild zeigt die Referenzformen (linker Rand), sowie diejenigen gefundenen Konturen, deren Ungleichheitsmaß bezogen auf alle Referenzformen einen Maximalwert nicht überschreitet. Weiterhin wird visualisiert, welcher Referenzform die gefundene Kontur am meisten ähnelt. Ein entsprechender Beschreibungstext (inklusive Ungleichheitsmaße für jede Referenzform) wird über die jeweilige Kontur gezeichnet. Für die vorgegebenen Parameter sieht das Ergebnis für das Bild MatchContours1.bmp wie folgt aus:
Es ist zu erkennen, dass der mit Abstand niedrigste Wert jeweils auf die korrekte Referenzkontur hinweist. Wird nun der Parameter eComparisonMethod von TCVN_CMCM_CONTOURS_MATCH_I3
auf TCVN_CMCM_CONTOURS_MATCH_I2
verändert, erkennt man, dass die Ergebnisse sich stark verändern. Dies führt auch dazu, dass der Parameter für die maximal akzeptierte Ungleichheit angepasst werden muss:
Die neuen Werte lassen eine deutlich weniger eindeutige Zuordnung zu entsprechenden Referenzformen zu, außerdem wird das runde Bauteil fälschlicher Weise der Referenzform „Rectangle“ zugeordnet. Diese Berechnungsmethode ist für dieses Beispiel also offenbar weniger gut geeignet.