A mai napon megtanuljuk, hogyan lehet egy képen vonalakat és köröket felismerni a Hough-transzformációnak nevezett technika segítségével.
Mi az a Hough-tér?
Mielőtt elkezdenénk a Hough-transzformációt képekre alkalmazni, meg kell értenünk, mi az a Hough-tér, és ezt egy példa segítségével fogjuk megtanulni.
Paramétertér
Mikor képekkel dolgozunk, elképzelhetjük a képet egy 2d mátrixként néhány x és y koordináta felett, amely alatt egy vonalat leírhatunk y = mx + b
De a paramétertérben, amit Hough-térnek fogunk nevezni, ugyanezt a vonalat ábrázolhatom m
vs b
helyett, így a vonal jellemzése a képtérben, egyetlen pont lesz a m-b
pozícióban a Hough-térben.
De van egy problémánk azonban, a y = mx + b
esetében nem tudunk függőleges egyenest ábrázolni, mivel a meredeksége végtelen. Tehát szükségünk van egy jobb módú parametrizálásra, polárkoordinátákra (rho és theta).
Hough-tér
- rho: az egyenesnek az origótól való távolságát írja le
- theta: a vízszintestől távolodó szöget írja le
Egy nagyon fontos megfigyelés azonban, hogy mi történik, ha egy egyenes körül több pontot veszünk, és átalakítjuk a Hough-térünkbe.
Egyetlen pont a képtérben egy görbére fordítható a Hough-térben, azzal a sajátossággal, hogy a képtérben egy vonal közötti pontokat több görbe fogja ábrázolni egyetlen érintési ponttal.
És ez lesz a célunk, hogy megtaláljuk azokat a pontokat, ahol egy görbecsoport metszi egymást.
Mi a Hough-transzformáció?
A Hough-transzformáció egy olyan jellemző-kivonási módszer, amely egyszerű alakzatok, például körök, vonalak stb. felismerésére szolgál egy képen.
Az “egyszerű” jellemzőt az alakzat paraméterek szerinti ábrázolásából vezetjük le. Egy “egyszerű” alakzat csak néhány paraméterrel reprezentálható, például egy egyenes reprezentálható a meredekségével és a metszéspontjával, vagy egy kör, amelyet x, y és sugárral lehet reprezentálni.
A vonalas példánkban a Hough-transzformáció feladata a képen lévő pontok feldolgozása és az értékek kiszámítása a Hough-térben.
A transzformáció végrehajtásához szükséges algoritmus, majd a metsző görbék megtalálása kicsit bonyolult, ezért nem tartozik e bejegyzés tárgykörébe. Viszont megnézzük ennek az algoritmusnak egy implementációját, amely az OpenCV könyvtár része.
A vonalak felismerése OpenCV-vel
Az OpenCV-ben a Hough-transzformációval történő vonalfelismerés a HoughLines
és HoughLinesP
(Probabilistic Hough Transform) függvényekben van implementálva. Mi ez utóbbira koncentrálunk.
A függvény a következő paramétereket várja:
-
image
: 8 bites, egycsatornás bináris forráskép. A képet a függvény módosíthatja. -
lines
: Vonalakból álló kimeneti vektor. Minden vonalat egy 4 elemű vektor (x_1, y_1, x_2, y_2) reprezentál, ahol (x_1,y_1) és (x_2, y_2) az egyes felismert vonalszakaszok végpontjai. -
rho
: Az akkumulátor távolsági felbontása pixelben. -
theta
: Az akkumulátor szögfelbontása radiánban. -
threshold
: Akkumulátor küszöbérték paraméter. Csak azok a sorok kerülnek vissza, amelyek elegendő szavazatot kapnak -
minLineLength
: Minimális sorhossz. Az ennél rövidebb vonalszakaszok elutasításra kerülnek. -
maxLineGap
: Az ugyanazon a vonalon lévő pontok közötti legnagyobb megengedett távolság, hogy összekapcsolja őket.
Túl bonyolult? egyszerűbb egy példával:
# 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)
És itt az eredmény:
Ez nagyon fontos, hogy valóban csak élekkel rendelkező képet használjunk a Hough-transzformáció paramétereként, különben az algoritmus nem fog rendeltetésszerűen működni.
Körök detektálása OpenCV segítségével
A folyamat nagyjából ugyanúgy zajlik, mint a vonalak esetében, azzal a különbséggel, hogy ezúttal egy másik függvényt fogunk használni az OpenCV könyvtárból. Most a HoughCircles
-t fogjuk használni, amely a következő paramétereket fogadja:
-
image
: 8 bites, egycsatornás, szürkeárnyalatos bemeneti kép. -
circles
: A megtalált körök kimeneti vektora. Minden vektor 3 elemű lebegőpontos vektorként van kódolva (x, y, sugár). -
circle_storage
: C függvényben ez egy memóriatároló, amely a talált körök kimeneti sorozatát tartalmazza. -
method
: Használandó észlelési módszer. Jelenleg az egyetlen implementált módszer a CV_HOUGH_GRADIENT , amely alapvetően 21HT -
dp
: Az akkumulátor felbontásának és a kép felbontásának inverz aránya. Például, ha dp=1 , az akkumulátor felbontása megegyezik a bemeneti kép felbontásával. Ha dp=2 , akkor az akkumulátor fele akkora szélességű és magasságú. -
minDist
: Az észlelt körök középpontjai közötti minimális távolság. Ha a paraméter túl kicsi, akkor egy igaz kör mellett több szomszédos kör is tévesen felismerhető. Ha túl nagy, néhány kör kimaradhat. -
param1
: Az első módszer-specifikus paraméter. CV_HOUGH_GRADIENT esetén ez a Canny() élérzékelőnek átadott kettő közül a magasabb küszöbérték (az alacsonyabb kétszer kisebb). -
param2
: Második módszer-specifikus paraméter. CV_HOUGH_GRADIENT esetén ez a körközéppontok felhalmozási küszöbértéke a felismerési szakaszban. Minél kisebb, annál több hamis kör kerülhet felismerésre. A nagyobb akkumulátorértékeknek megfelelő körök kerülnek először visszaküldésre. -
minRadius
: Minimális körsugár. -
maxRadius
: Maximális körsugár.
Ne feledjük, hogy a paramétereknek másnak kell lenniük, mivel a kört nem írhatjuk le ugyanazzal a paraméterezéssel, mint amit az egyeneseknél használtunk, hanem egy olyan egyenletet kell használnunk, mint a (x - x0)^^2 + (y - y0)^^2 = r^^2
.
És a kódhoz:
# 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)
Megjegyezzük, hogy az előző példához képest itt nem alkalmazunk semmilyen élfelismerő funkciót. Ennek oka, hogy a HoughCircles
függvény beépített canny-felismeréssel rendelkezik.
És az eredmény:
Következtetés
A Hough-transzformáció kiváló technika egyszerű alakzatok felismerésére a képeken, és számos alkalmazása van, az orvosi alkalmazásoktól kezdve, mint a röntgen, CT és MRI elemzés, az önvezető autókig. Ha többet szeretne megtudni a Hough-térről, javaslom, hogy ténylegesen futtassa a kódot, próbálja ki saját maga a különböző konfigurációkat, és további információkért nézze meg az OpenCV dokumentációját.
Köszönöm az olvasást!