Computer Vision

Experimente in C++

Da die Bildverarbeitung auch für die Robotik sehr interessant ist, habe ich mich mal ein wenig damit befasst. Ausgehend von diesem Tutorial bei RN-Wissen, habe ich vorallem auch bei Wikipedia Ansätze dafür gefunden. Die Funktionsweisen aller Algorithmen werde ich hier nicht detailliert beschreiben, auf den verlinkten Seiten sind diese sowieso viel ausführlicher und korrekter erklärt.

Ich habe die Umrechnung der Bilder mit den Filtern Sobel, Scharr, Laplace, Threshold-Algorithmus sowie die Umrechnung vom RGB- in den HSV-Farbraum ersteinmal selbst in C++ umgesetzt. Anhand dessen ließen sich gut die Funktionsweise und die möglichen/sinnvollen Kombinationen der Filter und Algorithmen herausfinden und beobachten.

Links das Ausgangsbild. Ein Ball auf einem (scheinbar) komplizierten Hintergrund. Mit Hilfe des HSV-Farbraumes, mit dem Farbwertkanal (Mitte), kann man dann aber z.B. Blau herausfiltern, dann gestaltet sich das wesentlich einfacher. Im rechten Bild ist also der blaue Anteil aus dem Bild extrahiert (mittels Schwellwerten), es bleibt eigentlich nur der Ball übrig. Dieses Bild habe ich dann im Folgenden mit Kantenerkennungsalgorithmen bearbeitet.

Hier ist das Bild einmal mit dem Sobel-Operator bearbeitet (linkes Bild) und einmal mit dem Laplace-Operator (mittleres Bild). Die Kante des Balls ist schon deutlich zu erkennen. Nach einem Threshold (Schwellwertverfahren, d.h. keine Graustufen mehr sondern nur noch schwarz/weiß, rechtes Bild) ist sie dann klar abgegrenzt.

Soweit die eigene Programmierung der Algorithmen. Da die eigenen Algorithmen aber sehr langsam sind (mehrere Sekunden pro Bild und Filter/Algorithmus), habe ich beschlossen es mit OpenCV zu versuchen. OpenCV ist eine OpenSource-Programmbibliothek mit fertigen Algorithmen für die Bildverarbeitung und für maschinelles Sehen. Sie bietet neben vielem anderen auch die Algorithmen, die ich umgesetzt habe, nur wesentlich effizienter programmiert und daher schneller (z.B. in Echtzeit mit einer Webcam)…

Mittlerweile habe ich auch schon erste Versuche erfolgreich in OpenCV gemacht. Aber irgendwie gestaltet sich das Ganze noch sehr fehleranfällig: Ich bekomme sehr oft Exeptions (Fehler), die ich aber nicht wirklich deuten kann…

Der Code

Das ist z.B. meine selbst programmierte Funktion, in der das Bild mit dem X- und Y-Sobel Operator bearbeitet wird:

void XYSobel (void) {
  unsigned int Index = 0, Indey = 0; /* Index = x-Koordinate, Indey = y-Koordinate */
  float Pixelwert;
  
  Bildmatrix(Image4->Canvas); /* Ausgangsbild wird in das Array 'Bild' kopiert */
  
  while(Indey <= 240) { /* Zeilen werden durchlaufen */
    while(Index <= 320) { /* Pixel einer Zeile werden durchlaufen */
  
      /* Der Wert des Pixels wird mit den Matrizen der beiden Sobeloperatoren berechnet. hSobel ist die 3x3-Matrix des x-Sobeloperators, vSobel analog für den y-Sobeloperator: */
      int hSobel[3][3] = {{1, 2, 1}, {0, 0, 0}, {-1, -2, -1}};
      int vSobel[3][3] = {{1, 0, -1}, {2, 0, -2}, {1, 0, -1}};
      
      Pixelwert = (hSobel[0][0]*(Bild[Index-1][Indey-1]&0xFF) + hSobel[0][1]*(Bild[Index][Indey-1]&0xFF) + hSobel[0][2]*(Bild[Index+1][Indey-1]&0xFF) + hSobel[1][0]*(Bild[Index-1][Indey]&0xFF) + hSobel[1][1]*(Bild[Index][Indey]&0xFF) + hSobel[1][2]*(Bild[Index+1][Indey]&0xFF) + hSobel[2][0]*(Bild[Index-1][Indey+1]&0xFF) + hSobel[2][1]*(Bild[Index][Indey+1]&0xFF) + hSobel[2][2]*(Bild[Index+1][Indey+1]&0xFF));
      Pixelwert += (vSobel[0][0]*(Bild[Index-1][Indey-1]&0xFF) + vSobel[0][1]*(Bild[Index][Indey-1]&0xFF) + vSobel[0][2]*(Bild[Index+1][Indey-1]&0xFF) + vSobel[1][0]*(Bild[Index-1][Indey]&0xFF) + vSobel[1][1]*(Bild[Index][Indey]&0xFF) + vSobel[1][2]*(Bild[Index+1][Indey]&0xFF) + vSobel[2][0]*(Bild[Index-1][Indey+1]&0xFF) + vSobel[2][1]*(Bild[Index][Indey+1]&0xFF) + vSobel[2][2]*(Bild[Index+1][Indey+1]&0xFF));
      
      /*Der Pixel wird im Ausgangsbild eingefügt*/
      Endbild[Index][Indey] = int(round(0x7F + Pixelwert, 0)) + (int(round(0x7F + Pixelwert, 0)) << 8) + (int(round(0x7F + Pixelwert, 0)) << 16); Index++; } Index = 0; Indey++; } /*Das Bildarray wird wieder in ein Image Objekt kopiert*/ Imagematrix(Image5->Canvas);
}

Die anderen Filter unterscheiden sich programmiertechnisch nicht wesentlich von diesem. Die Scharr- und Laplace-Operatoren haben einfach andere Matritzen, mit denen das Bild bearbeitet wird.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.

Bitte beantworte kurz folgende Frage, um zu zeigen, dass du kein Roboter bist: *