Hough Dönüşümü ve Köşe Tespiti
2026
Önceki derslerde Canny ve Sobel gibi operatörlerle kenar tespiti yapmayı öğrendik.
Ancak kenar tespiti bize sadece “burada bir değişim var” diyen pikselleri (binary harita) verir. Bu piksellerin bir doğru mu yoksa bir daire mi oluşturduğunu matematiksel olarak bilmiyoruz.
Soru: Bu dağınık kenar noktalarını (pikselleri) nasıl anlamlı geometrik şekillere dönüştürebiliriz?
Cevap: Hough Dönüşümü (Hough Transform).
Bir doğruyu Kartezyen koordinat sisteminde (\(y\) ve \(x\)) şu şekilde ifade ederiz:
\[ y = mx + c \]
Sorun: Dikey bir doğru düşünün (\(x = 5\)). Bu doğrunun eğimi (\(m\)) sonsuzdur. Bilgisayarlar sonsuz değerleri sevmez ve hesaplamada sorun çıkarır. Bu yüzden Hough dönüşümünde farklı bir koordinat sistemi kullanmalıyız.
Hough dönüşümü, doğruları temsil etmek için Rho (\(\rho\)) ve Theta (\(\theta\)) parametrelerini kullanır.
\[ \rho = x \cos \theta + y \sin \theta \]
Bu gösterim sayesinde dikey doğrular dahil her türlü doğru sorunsuz ifade edilebilir.
Hough dönüşümünün en can alıcı noktası burasıdır:
Görüntü uzayındaki noktaların Hough uzayında kesişmesi:
OpenCV’de iki tür Hough Doğru Tespiti fonksiyonu vardır:
cv2.HoughLines)
cv2.HoughLinesP)
| Özellik | HoughLines (Standart) | HoughLinesP (Olasılıksal) |
|---|---|---|
| Çıktı | (ρ, θ) sonsuz doğru | (x₁, y₁, x₂, y₂) segment |
| Hız | Yavaş | Çok hızlı |
| Örnekleme | Tüm pikseller | Seçili pikseller |
| Boşluk toleransı | Zayıf | Güçlü |
| Gürültü | Daha hassas | Daha dayanıklı |
| Köşe analizi | Zor | Kolay |
| Pratik kullanım | Teorik | Gerçek uygulamalara uygun |
Parametre Açıklamaları
lines = cv2.HoughLinesP(
image, # Kenar görüntüsü (Binary / Canny çıktısı)
rho, # Piksel cinsinden uzaklık çözünürlüğü (genelde 1)
theta, # Radyan cinsinden açı çözünürlüğü (genelde np.pi/180)
threshold, # Doğru kabul edilmesi için gereken minimum oy (kesişim)
minLineLength, # Bu değerden daha kısa olan çizgiler reddedilir
maxLineGap # Aynı doğru üzerindeki noktalar arası max boşluk (kopukluk)
)Aşağıdaki kod Pyodide aracılığıyla doğrudan tarayıcınızda çalışır. Parametrelerle (threshold, minLineLength, maxLineGap) dilediğiniz gibi oynayabilir, “Run Code” tuşu ile kodu tekrar çalıştırabilirsiniz:
Kenarlardan doğru tespit ederken, her kenar noktasının Hough uzayında bir eğri oluşturduğunu ve bu eğrilerin kesiştiği noktaların doğruyu verdiğini görmüştük.
Daire tespitinde de benzer bir fikir kullanılır:
Önce basit bir senaryo düşünelim:
Bu, görüntü uzayındaki (image space) manzaramızdır:
Dairenin denklemini hatırlayalım:
\[ (x - a)^2 + (y - b)^2 = r^2 \]
Burada: - \((a, b)\): dairenin merkezi - \(r\): yarıçap
Şimdi işi basitleştirmek için yarıçapın bilindiğini varsayalım (\(r\) sabit).
Tek bir kenar noktasına bakalım, örneğin \(P_1(x_1, y_1)\). Bu nokta için denklem:
\[ (x_1 - a)^2 + (y_1 - b)^2 = r^2 \]
Bu kez bilinmeyenler \(a\) ve \(b\) (merkezin koordinatlarıdır). Bu denklem, merkez uzayında \((a, b)\):
Yani:
Görüntü uzayında tek bir nokta, merkez uzayında olası merkezleri gösteren bir daire üretir.
Aynı mantığı diğer noktalar için de uygularsak:
Bu daireler ortak bir noktada kesişirlerse, bu nokta:
“Bu kenar noktalarının hepsinin üzerinde bulunduğu, yarıçapı \(r\) olan dairenin merkezidir.”
Bu, çizgisel Hough ile birebir paraleldir:
Gerçek görüntülerde:
Bu durumda parametre uzayı 3 boyutludur:
Her kenar noktası için, çok sayıda olası yarıçap değerine karşılık:
Sorun:
Bu 3B akümülatör hem çok yavaş, hem de bellek açısından maliyetli olabilir.
OpenCV, daire tespitini hızlandırmak için gradyan bilgisini kullanır:
Sonuç:
cv2.HoughCircles Fonksiyonunun MantığıOpenCV’de daire tespiti için kullanılan fonksiyon:
Parametre Açıklamaları
circles = cv2.HoughCircles(
image, # Gri seviye görüntü (⚠️ Canny uygulanmamış olmalı!)
method, # Genelde cv2.HOUGH_GRADIENT
dp, # Akümülatör çözünürlüğü (1: orijinal, 2: yarısı)
minDist, # Tespit edilen daire merkezleri arası minimum mesafe
param1, # Canny için yüksek eşik (düşüğü otomatik olarak yarısı olur)
param2, # Dairenin kabul edilmesi için gereken minimum oy (Merkez oyu)
minRadius, # Aranacak minimum yarıçap (0: bilinmeyen)
maxRadius # Aranacak maksimum yarıçap (0: bilinmeyen)
)Aşağıdaki Pyodide simülasyonunda param2 değerini (kabul oyu) veya Blur seviyesini düşürdüğünüzde nelerin hatalı şekilde çember kabul edildiğini bizzat test edebilirsiniz:
| Özellik | Doğru Tespiti (HoughLinesP) |
Daire Tespiti (HoughCircles) |
|---|---|---|
| Girdi | Kenar Haritası (Canny çıktısı - Binary) | Gri Seviye Görüntü (Blur uygulanmış) |
| Yöntem | Olasılıksal Oylama | Gradyan Yönü + Oylama |
| Hız | Hızlı | Göreceli Yavaş |
| Parametreler | Rho, Theta, Threshold | MinDist, Param1, Param2 |
| Kullanım | Şerit, Barkod, Tablo çizgileri | Göz bebeği, Hücre, Para, Trafik işaretleri |
Bir odaya küçücük bir pencereden baktığınızı hayal edin. Sadece o pencerenin içini görebiliyorsunuz. Amacımız, pencerenin nerede olduğunu anlamak.
Pencereyi (Kırmızı Kare) görüntü üzerinde hafifçe sağa, sola, yukarı veya aşağı kaydıralım. Pencerenin içindeki görüntü ne kadar değişiyor?
Görsel olarak 3 durum vardır
Pencere gökyüzü gibi boş bir alandaysa, onu ne tarafa hareket ettirirseniz ettirin, pencerenin içindeki görüntü değişmez.
Pencere bir binanın kenarındaysa:
Pencere bir binanın sivri ucundaysa (köşe):
Bu “değişimi” matematiksel bir formüle dökelim.
Görüntü üzerindeki penceremiz \((x,y)\) noktasında olsun. Bu pencereyi \((u, v)\) kadar (örneğin sağa 1, yukarı 1 piksel) kaydıralım.
Eski pencere ile yeni pencere arasındaki farkı hesaplamamız lazım. Buna Hata Kareler Toplamı (SSD - Sum of Squared Differences) diyoruz ve \(E(u,v)\) ile gösteriyoruz.
\[ E(u,v) = \sum_{x,y} \underbrace{w(x,y)}_{\text{Pencere}} [ \underbrace{I(x+u, y+v)}_{\text{Kaydırılmış}} - \underbrace{I(x,y)}_{\text{Orijinal}} ]^2 \]
Her bir piksel için pencereyi her yöne kaydırıp farkı hesaplamak bilgisayar için çok yavaştır. Harris burada bir matematiksel “yaklaşım” kullanır: Taylor Serisi.
Bir fonksiyonun (görüntünün) bir sonraki adımda ne olacağını, o anki eğimine (türevine) bakarak tahmin edebiliriz.
\[ I(x+u, y+v) \approx I(x,y) + I_x u + I_y v \]
Bu tahmini, yukarıdaki ana formülümüze koyarsak, o karmaşık \(E(u,v)\) formülü aşağıdaki matris çarpımına dönüşür:
\[ E(u,v) \approx \begin{bmatrix} u & v \end{bmatrix} \underbrace{\begin{bmatrix} \sum I_x^2 & \sum I_x I_y \\ \sum I_x I_y & \sum I_y^2 \end{bmatrix}}_{M \text{ Matrisi}} \begin{bmatrix} u \\ v \end{bmatrix} \]
İşte bütün olay bu \(M\) matrisidir! Bu 2x2’lik matris, o bölgedeki tüm değişimin özetidir.
\[ M = \sum_{x,y} w(x,y) \begin{bmatrix} I_x^2 & I_x I_y \\ I_x I_y & I_y^2 \end{bmatrix} \]
Şimdi elimizde her piksel için hesaplanmış bir \(M\) matrisi var. Bu matrisin geometrik şeklini anlamak için Özdeğerlerine (\(\lambda_1, \lambda_2\)) bakarız.
Bu özdeğerleri bir Elips gibi düşünebilirsiniz:
Bunu grafik üzerinde görselleştirelim:
Türevler (değişim) her yönde çok azdır. Elips bir noktadan farksızdır. * Görsel: Boş küme.
Bir yönde değişim çok büyük (Kenara dik), diğer yönde çok küçüktür (Kenar boyunca). * Görsel: İnce uzun bir elips (Sosis gibi).
Her iki yönde de değişim çok büyüktür. * Görsel: Büyük ve şişman bir daire/elips.
Bilgisayarda her piksel için özdeğer (\(\lambda\)) hesaplamak (“Karekök” işlemi gerektirdiği için) maliyetlidir.
Harris, zekice bir matematiksel numara ile özdeğerleri hesaplamadan sonuca ulaşan bir skor fonksiyonu (\(R\)) geliştirmiştir:
\[ R = \det(M) - k \cdot (\text{trace}(M))^2 \]
Burada:
Matematiksel Karar Mekanizması
Görsel işleme hattı şöyledir:
Bu teorik adımlar aşağıdaki Pyodide simülasyonunda görüldüğü gibi tek fonksiyona inmektedir. Pencere boyutunu veya \(k\) sabiti (R eşiği) değerini değiştirerek, düz kenarların yanılgıyla köşe olarak algılanıp algılanmadığını inceleyebilirsiniz:
Bilgisayarla Görü – OMÜ | 🏠