Verstehen & Implementieren von Formerkennung mit Hough-Transformation mit OpenCV & Python

Feature Image

Heute werden wir lernen, wie man Linien und Kreise in einem Bild mit Hilfe einer Technik namens Hough-Transformation erkennt.

Was ist ein Hough-Raum?

Bevor wir die Hough-Transformation auf Bilder anwenden, müssen wir verstehen, was ein Hough-Raum ist, und das werden wir anhand eines Beispiels lernen.

Parameterraum

Wenn wir mit Bildern arbeiten, können wir uns vorstellen, dass das Bild eine 2D-Matrix über einigen x- und y-Koordinaten ist, unter denen eine Linie als y = mx + b

Parameterraum

Parameterraum

Aber im Parameterraum, den wir Hough-Raum nennen, kann ich dieselbe Linie stattdessen als m gegen b darstellen, so dass die Charakterisierung einer Linie im Bildraum ein einzelner Punkt an der Position m-b im Hough-Raum sein wird.

Hough-Raum

Hough-Raum

Aber wir haben ein Problem, mit y = mx + b können wir keine vertikale Linie darstellen, da die Steigung unendlich ist. Wir brauchen also eine bessere Art der Parametrisierung, nämlich Polarkoordinaten (rho und theta).

Hough-Raum

  • rho: beschreibt den Abstand der Linie vom Ursprung
  • theta: beschreibt den Winkel von der Horizontalen weg
Linienpolarkoordinaten

Linienpolarkoordinaten

Eine sehr wichtige Beobachtung ist jedoch, was passiert, wenn wir mehrere Punkte um eine Linie herum nehmen, und wir transformieren in unseren Hough-Raum.

Punkte und Linienbeziehung im Hough-Raum

Punkte und Linienbeziehung im Hough-Raum

Ein einzelner Punkt im Bildraum wird zu einer Kurve im Hough-Raum, mit der Besonderheit, dass Punkte auf einer Linie im Bildraum durch mehrere Kurven mit einem einzigen Berührungspunkt dargestellt werden.

Und das ist unser Ziel, die Punkte zu finden, an denen sich eine Gruppe von Kurven schneidet.

Was ist die Hough-Transformation?

Die Hough-Transformation ist eine Methode zur Erkennung einfacher Formen wie Kreise, Linien usw. in einem Bild.

Das Merkmal „einfach“ wird durch die Darstellung der Form in Form von Parametern bestimmt. Eine „einfache“ Form wird nur durch einige wenige Parameter dargestellt, z. B. eine Linie durch ihre Steigung und ihren Achsenabschnitt oder ein Kreis, der durch x, y und Radius dargestellt werden kann.

In unserem Linienbeispiel ist eine Hough-Transformation für die Verarbeitung der Punkte auf dem Bild und die Berechnung der Werte im Hough-Raum verantwortlich.

Der Algorithmus für die Durchführung der Transformation und das anschließende Auffinden der sich schneidenden Kurven ist etwas kompliziert und würde daher den Rahmen dieses Beitrags sprengen. Wir werden jedoch einen Blick auf eine Implementierung dieses Algorithmus werfen, die Teil der OpenCV-Bibliothek ist.

Linienerkennung mit OpenCV

In OpenCV ist die Linienerkennung mit Hilfe der Hough-Transformation in den Funktionen HoughLines und HoughLinesP (Probabilistic Hough Transform) implementiert. Wir werden uns auf die letztere konzentrieren.

Die Funktion erwartet die folgenden Parameter:

  • image: 8-bit, einkanaliges binäres Quellbild. Das Bild kann von der Funktion geändert werden.
  • lines: Ausgabevektor von Zeilen. Jede Linie wird durch einen 4-Elemente-Vektor (x_1, y_1, x_2, y_2) dargestellt, wobei (x_1, y_1) und (x_2, y_2) die Endpunkte jedes erkannten Liniensegments sind.
  • rho: Abstandsauflösung des Akkumulators in Pixel.
  • theta: Winkelauflösung des Akkumulators im Bogenmaß.
  • threshold: Schwellenparameter für den Akkumulator. Es werden nur die Zeilen zurückgegeben, die genügend Stimmen erhalten haben
  • minLineLength: Minimale Zeilenlänge. Linienabschnitte, die kürzer sind, werden abgelehnt.
  • maxLineGap: Maximal zulässiger Abstand zwischen Punkten auf derselben Linie, um sie zu verbinden.

Zu kompliziert? Mit einem Beispiel ist es einfacher:

# Read image img = cv2.imread('lanes.jpg', cv2.IMREAD_COLOR)# Convert the image to gray-scalegray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Find the edges in the image using canny detectoredges = cv2.Canny(gray, 50, 200)# Detect points that form a linelines = cv2.HoughLinesP(edges, 1, np.pi/180, max_slider, minLineLength=10, maxLineGap=250)# Draw lines on the imagefor line in lines: x1, y1, x2, y2 = line cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 3)# Show resultcv2.imshow("Result Image", img)

Und hier ist das Ergebnis:

Beispiel für die Linienerkennung

Beispiel für die Linienerkennung

Es ist sehr wichtig, dass wir als Parameter für die Hough-Transformation tatsächlich nur ein Kantenbild verwenden, sonst funktioniert der Algorithmus nicht wie gewünscht.

Erkennen von Kreisen mit OpenCV

Der Prozess läuft in etwa so ab wie bei den Linien, mit der Ausnahme, dass wir dieses Mal eine andere Funktion aus der OpenCV-Bibliothek verwenden werden. Wir verwenden nun HoughCircles, die die folgenden Parameter akzeptiert:

  • image: 8-Bit, Einkanal, Graustufen-Eingabebild.
  • circles: Ausgabevektor der gefundenen Kreise. Jeder Vektor ist als 3-Element-Gleitkomma-Vektor (x, y, Radius) kodiert.
  • circle_storage: In der C-Funktion ist dies ein Speicherbereich, der die Ausgabesequenz der gefundenen Kreise enthält.
  • method: Zu verwendende Erkennungsmethode. Derzeit ist nur die Methode CV_HOUGH_GRADIENT implementiert, die im Wesentlichen 21HT
  • dp: Umgekehrtes Verhältnis der Akkumulatorauflösung zur Bildauflösung. Zum Beispiel, wenn dp=1 ist, hat der Akkumulator die gleiche Auflösung wie das Eingangsbild. Bei dp=2 hat der Akkumulator die Hälfte der Breite und Höhe.
  • minDist: Mindestabstand zwischen den Zentren der erkannten Kreise. Ist der Parameter zu klein, können neben einem echten Kreis auch mehrere Nachbarkreise fälschlicherweise erkannt werden. Ist er zu groß, können einige Kreise übersehen werden.
  • param1: Erster methodenspezifischer Parameter. Im Falle von CV_HOUGH_GRADIENT ist dies der höhere der beiden Schwellenwerte, die an den Canny()-Kantendetektor übergeben werden (der niedrigere ist zweimal kleiner).
  • param2: Zweiter methodenspezifischer Parameter. Im Falle von CV_HOUGH_GRADIENT ist dies der Akkumulationsschwellenwert für die Kreismittelpunkte in der Erkennungsphase. Je kleiner er ist, desto mehr falsche Kreise können erkannt werden. Kreise, die den größeren Akkumulatorwerten entsprechen, werden zuerst zurückgegeben.
  • minRadius: Minimaler Kreisradius.
  • maxRadius: Maximaler Kreisradius.

Erinnern Sie sich, dass die Parameter unterschiedlich sein müssen, da wir einen Kreis nicht mit der gleichen Parametrisierung beschreiben können, die wir für Linien verwendet haben, und stattdessen eine Gleichung wie (x - x0)^^2 + (y - y0)^^2 = r^^2 verwenden müssen.

Und zum Code:

# Read image as gray-scaleimg = cv2.imread('circles.png', cv2.IMREAD_COLOR)# Convert to gray-scalegray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Blur the image to reduce noiseimg_blur = cv2.medianBlur(gray, 5)# Apply hough transform on the imagecircles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1, img.shape/64, param1=200, param2=10, minRadius=5, maxRadius=30)# Draw detected circlesif circles is not None: circles = np.uint16(np.around(circles)) for i in circles: # Draw outer circle cv2.circle(img, (i, i), i, (0, 255, 0), 2) # Draw inner circle cv2.circle(img, (i, i), 2, (0, 0, 255), 3)

Beachten Sie, dass wir im Vergleich zum vorherigen Beispiel hier keine Funktion zur Kantenerkennung anwenden. Das liegt daran, dass die Funktion HoughCircles über eine integrierte Canny-Erkennung verfügt.

Und das Ergebnis:

Beispiel für die Kreiserkennung

Beispiel für die Kreiserkennung

Schlussfolgerung

Die Hough-Transformation ist ein hervorragendes Verfahren zur Erkennung einfacher Formen in Bildern und hat zahlreiche Anwendungsmöglichkeiten, die von medizinischen Anwendungen wie Röntgen-, CT- und MRT-Analysen bis hin zu selbstfahrenden Autos reichen. Wenn Sie daran interessiert sind, mehr über den Hough-Raum zu erfahren, empfehle ich Ihnen, den Code auszuführen, verschiedene Konfigurationen selbst auszuprobieren und die OpenCV-Dokumentation für weitere Informationen zu konsultieren.

Danke fürs Lesen!

Schreibe einen Kommentar

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