Förståelse och implementering av formdetektering med Hough Transform med OpenCV och Python

Feature Image

I dag kommer vi att lära oss hur man upptäcker linjer och cirklar i en bild med hjälp av en teknik som kallas Hough Transform.

Vad är Hough space?

Innan vi börjar tillämpa Hough transform på bilder måste vi förstå vad ett Hough space är, och det ska vi lära oss med hjälp av ett exempel.

Parameterrymd

När vi arbetar med bilder kan vi föreställa oss att bilden är en 2d-matris över vissa x- och y-koordinater, enligt vilken en linje skulle kunna beskrivas som y = mx + b

Parameterrymd

Parameterrymd

Men i parameterrymd, som vi kallar Hough-rymd, kan jag representera samma linje som m vs b istället, så karakteriseringen av en linje i bildrymd kommer att vara en enda punkt på positionen m-b i Hough-rymd.

Hough Space

Hough Space

Men vi har dock ett problem, med y = mx + b kan vi inte representera en vertikal linje, eftersom lutningen är oändlig. Så vi behöver ett bättre sätt att parametrisera, polarkoordinater (rho och theta).

Hough space

  • rho: beskriver linjens avstånd från ursprunget
  • theta: beskriver vinkeln från horisontalplanet
Linjens polära koordinater

Linjens polära koordinater

En mycket viktig iakttagelse är dock vad som händer när vi tar flera punkter runt en linje och transformerar till vårt Hough space.

Punkter och linjering i Hough Space

Punkter och linjering i Hough Space

En enskild punkt i bildrymden översätts till en kurva i Hough Space, med den speciella egenskapen att punkter bland en linje i bildrymden kommer att representeras av flera kurvor med en enda beröringspunkt.

Och detta kommer att vara vårt mål, att hitta de punkter där en grupp kurvor skär varandra.

Vad är Hough-transform?

Hough-transform är en metod för att extrahera egenskaper för att upptäcka enkla former som cirklar, linjer osv. i en bild.

Den ”enkla” egenskapen härleds från formrepresentationen i form av parametrar. En ”enkel” form representeras endast av några få parametrar, till exempel kan en linje representeras av dess lutning och intercept, eller en cirkel som kan representeras av x, y och radie.

I vårt linjeexempel kommer en Hough-transform att ansvara för att bearbeta prickarna på bilden och beräkna värdena i Hough-rymden.

Algoritmen för att få transformationen att hända och därefter hitta de skärande kurvorna är lite komplicerad, och ligger därför utanför ramen för detta inlägg. Vi kommer dock att ta en titt på en implementering av denna algoritm, som är en del av OpenCV-biblioteket.

Detektering av linjer med hjälp av OpenCV

I OpenCV implementeras linjedetektering med hjälp av Hough-transformation i funktionerna HoughLines och HoughLinesP (Probabilistisk Hough-transformation). Vi kommer att fokusera på den senare.

Funktionen förväntar sig följande parametrar:

  • image: 8-bitars binär källbild med en enda kanal. Bilden kan ändras av funktionen.
  • lines: Utdragsvektor av linjer. Varje linje representeras av en vektor med fyra element (x_1, y_1, x_2, y_2) , där (x_1, y_1) och (x_2, y_2) är slutpunkterna för varje detekterat linjesegment.
  • rho:
  • theta: Avståndsupplösning för ackumulatorn i pixlar: Vinkelupplösning för ackumulatorn i radianer.
  • threshold: Ackumulatorns vinkelupplösning i radianer: Parametern för tröskelvärdet för ackumulatorn. Endast de linjer returneras som får tillräckligt många röster
  • minLineLength: Minsta linjelängd. Linjesegment som är kortare än så förkastas.
  • maxLineGap:

Tro komplicerat? Det är lättare med ett exempel:

# 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)

Och här är resultatet:

Linjedetekteringsexempel

Linjedetekteringsexempel

Det är mycket viktigt att vi faktiskt använder en bild med enbart kanter som parameter för Hough-transformen, annars fungerar inte algoritmen som avsett.

Detektering av cirklar med hjälp av OpenCV

Processen går ungefär på samma sätt som för linjer, med undantaget att vi den här gången använder en annan funktion från OpenCV-biblioteket. Vi kommer nu att använda HoughCircles, som accepterar följande parametrar:

  • image: 8-bitars, enkanalig, gråskalig ingångsbild.
  • circles: Utgångsvektor av funna cirklar. Varje vektor är kodad som en 3-elementig flyttalsvektor (x, y, radie) .
  • circle_storage: I C-funktionen är detta en minneslagring som kommer att innehålla utgångssekvensen av funna cirklar.
  • method: Detektionsmetod som ska användas. För närvarande är den enda implementerade metoden CV_HOUGH_GRADIENT , som i princip är 21HT
  • dp: Omvänt förhållande mellan ackumulatorupplösningen och bildupplösningen. Till exempel, om dp=1 , har ackumulatorn samma upplösning som inmatningsbilden. Om dp=2 har ackumulatorn hälften så stor bredd och höjd.
  • minDist: Minsta avstånd mellan centrumen för de upptäckta cirklarna. Om parametern är för liten kan flera granncirklar upptäckas felaktigt utöver en riktig cirkel. Om den är för stor kan vissa cirklar missas.
  • param1: Första metodspecifika parametern. Vid CV_HOUGH_GRADIENT är det det högre tröskelvärdet av de två som överförs till kantdetektorn Canny() (det lägre är dubbelt så litet).
  • param2: Andra metodspecifika parametern. Vid CV_HOUGH_GRADIENT är det ackumulatortröskelvärdet för cirkelns centrum i detektionsskedet. Ju mindre den är, desto fler falska cirklar kan upptäckas. Cirklar som motsvarar de större ackumulatorvärdena returneras först.
  • minRadius: Minsta cirkelradie.
  • maxRadius: Vi kan inte beskriva en cirkel med samma parametrisering som vi använde för linjer, utan vi måste istället använda en ekvation som (x - x0)^^2 + (y - y0)^^2 = r^^2.

    Och till koden:

    # 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)

    Bemärk att jämfört med det föregående exemplet tillämpar vi inte någon kantdetekteringsfunktion här. Detta beror på att funktionen HoughCircles har inbyggd canny-detektion.

    Och resultatet:

    Circle Detection Example

    Circle Detection Example

    Slutsats

    Hough Transform är en utmärkt teknik för att upptäcka enkla former i bilder och har flera användningsområden, allt från medicinska tillämpningar som röntgen-, CT- och MR-analyser till självkörande bilar. Om du är intresserad av att veta mer om Hough space rekommenderar jag att du faktiskt kör koden, provar olika konfigurationer på egen hand och att du kollar in OpenCV-dokumentationen för ytterligare information.

    Tack för att du läste!

Lämna ett svar

Din e-postadress kommer inte publiceras.