Macademia'nın robotik ve mühendislik programı · ücretsiz seviye tespiti ve kişisel öğrenme yolu

10. hafta / 14

Robotlar için bilgisayarlı görü

Araçlar: Python (OpenCV), bu platform, Webots kamerası

Bu haftanın sonunda

  • İğne deliği (pinhole) kamera modelini ve kalibrasyonun neden önemli olduğunu açıklamak
  • Nesneleri HSV'de renge göre ayırmak ve konumlarını bir denetim hatasına çevirmek
  • Şerit çizgilerini ve işaretçileri (ArUco) bulup gezinmede kullanmak

Ders notları

Kamera, bir robotun taşıyabileceği en zengin ve kullanması en zor sensördür: 640×480'lik renkli bir görüntü neredeyse bir milyon sayıdır ve saniyede otuz kez gelir. Robot görüsü bu sayıları birkaç kullanışlı büyüklüğe çevirir: çizgi nerede, hedef nerede, işaretçi ne kadar uzakta.

İğne deliği modeli

Kamera çerçevesindeki bir 3B nokta (X, Y, Z) şu piksele düşer (u, v):

u = fx · X / Z + cx     v = fy · Y / Z + cy

fx, fy (piksel cinsinden odak uzaklığı) ve cx, cy (ana nokta) birlikte iç parametre matrisini oluşturur. Satranç tahtası deseniyle kalibrasyon bunları ve mercek bozulmasını kestirir. Kalibrasyon yapılmazsa görüntüden ölçülen mesafeler yanlış olur.

Renge göre ayırma (segmentasyon)

RGB rengi ve parlaklığı birbirine karıştırır; bir gölge üç kanalı da değiştirir. HSV ise renk tonunu (hangi renk), doygunluğu ve parlaklığı ayırır; bu yüzden bir ton aralığı nesneyi değişen ışıkta da bulur. Akış: bulanıklaştır → HSV → eşikle (maske) → küçük lekeleri silmek için morfolojik açma → en büyük kontur → ağırlık merkezi. Ağırlık merkezinin görüntü merkezinden yatay sapması bir PID için hata sinyalidir: buna görsel servo (visual servoing) denir.

Şerit tespiti

  • Aracın önünde bir ilgi bölgesi (ROI) kırp.
  • Kenarları bul (Canny) ya da şerit rengini eşikle.
  • Çizgi (Hough dönüşümü) ya da polinom uydur; çoğu zaman önce kuş bakışı perspektif dönüşümü yapılır.
  • Şerit merkezinin yanal sapması ve yön hatası direksiyon denetleyicisini sürer; tıpkı 1. haftadaki çizgi izleyen gibi, ama IR sensör yerine kamerayla.

İşaretçiler (fiducial markers)

ArUco ve AprilTag basılı kare kodlardır. OpenCV onları bulur ve kalibre edilmiş bir kamerayla tam 3B pozlarını verir. Drone'lar bunları hassas iniş için, robot kollar nesnenin yerini bulmak için kullanır.

Görü nerede çalışır?

Klasik görü bir Raspberry Pi'de çalışır; derin ağlar bir hızlandırıcı ister (11. hafta). Akıllı kamera modülleri (HuskyLens, Pixy2, Grove Vision AI) tespiti kartın üzerinde yapar ve UART ya da I²C üzerinden yalnız koordinat gönderir, böylece bir Uno bile onları kullanabilir. ESP32-CAM görüntüyü Wi-Fi ile daha güçlü bir bilgisayara aktarır.

Derinlemesine

Görüş alanından odak uzaklığına

Kalibrasyondan önce piksel cinsinden odak uzaklığını yatay görüş alanından (HFOV) ve görüntü genişliği W'dan tahmin edebilirsiniz:

fx = (W / 2) / tan(HFOV / 2)

Raspberry Pi Camera v2'nin HFOV değeri yaklaşık 62,2°'dir; 640 piksel genişlikte fx ≈ 320 / tan(31,1°) ≈ 530 piksel olur. Ardından dama tahtası kalibrasyonu gerçek değeri ve bozulma (distortion) katsayılarını verir.

Çözümlü örnek: tek görüntüden mesafe ve yön

10 cm'lik bir ArUco işaretçisi fx = 600 piksel ile 40 piksel genişliğinde görünüyor. Benzer üçgenlerden

Z = fx · Wreal / wpx = 600 × 0.10 / 40 = 1.5 m

Tek bir piksellik ölçüm hatası önemlidir: 39 pikselde aynı formül 1,54 m verir. Duyarlılık dZ ≈ Z² / (fx Wreal) = 2,25 / 60 ≈ piksel başına 0,04 m'dir ve mesafenin karesiyle büyür; hassas iniş yapan dronların alçaldıkça daha küçük bir işaretçiye geçmesinin nedeni budur. cx = 320 piksel ve fx = 530 piksel iken u = 400 pikseldeki bir hedefin yönü şudur:

ψ = atan((u − cx) / fx) = atan(80 / 530) ≈ 8.6°

6. haftanın yön PID'sine ham piksel farkını değil ψ'yi verin: böylece kamera çözünürlüğünü değiştirdiğinizde kazançlar değişmez.

Görüntünün nerede işleneceğini veri hızı belirler

Saniyede 30 karede ham 640 × 480 RGB, 640 × 480 × 3 × 30 ≈ 27,6 MB/s eder; 1280 × 720'de yaklaşık 83 MB/s'dir. İkisi de bir mikrodenetleyiciden veya tipik bir Wi-Fi bağlantısından geçmez; bu yüzden ESP32-CAM genellikle yaklaşık on kat daha küçük olan JPEG kareler gönderir, Raspberry Pi 4B veya Jetson ise kareleri kameranın yanında işler ve yalnızca sonuçları gönderir.

Uygulamada HSV

  • OpenCV renk tonunu (hue) 0 ile 179 arasında saklar (derecenin yarısı). Kırmızı iki uçta birden durur, bu yüzden VEYA ile birleştirilmiş iki aralık ister: yaklaşık 0 ile 10 ve 170 ile 179.
  • Doygunluğu düşük veya parlaklığı çok düşük piksellerin renk tonu anlamsızdır; örneğin S > 80 ve V > 50 şartı koyun.
  • Mümkünse otomatik pozlamayı ve otomatik beyaz dengesini kilitleyin; yoksa robot bir pencereye döndükçe eşikleriniz kayar.

Kuş bakışı görünüm ve işaretçi konumu

Bilinen dört zemin noktası ve pikselleri 3 × 3'lük bir homografi tanımlar (cv2.getPerspectiveTransform). Dönüşümden sonra bir piksel sabit bir zemin mesafesine, örneğin 1 cm'ye karşılık gelir; böylece şerit kayması doğrudan metreye çevrilir. Bu yalnızca düz zeminde geçerlidir. ArUco için solvePnP, dört köşeden ve kalibre edilmiş iç parametrelerden 6B konumu (pose) çıkarır. Küçük veya neredeyse tam karşıdan görülen işaretçiler, kareler arasında yer değiştiren neredeyse eşit iyilikte iki konum verebilir; daha büyük işaretçiler, işaretçi panoları veya AprilTag'ler bunu azaltır.

Simülasyon

Renk ve şerit ayırma

Yapay bir kamera görüntüsü HSV'ye çevrilir ve eşiklenerek maskeye dönüşür. Maskenin ağırlık merkezi (ya da şerit merkezi) bir direksiyon hatasına dönüşür. Aralıkları ayarla, ışığı değiştir, topu sürükle, sonra döngüyü P denetleyiciyle kapat.

Kod

Python (OpenCV): kırmızı bir nesneyi izle ve direksiyon hatasını hesapla
import cv2
import numpy as np

cap = cv2.VideoCapture(0)
lo, hi = np.array([0, 120, 70]), np.array([10, 255, 255])   # HSV'de kırmızı aralığı

while True:
    ok, frame = cap.read()
    if not ok:
        break
    mask = cv2.inRange(cv2.cvtColor(frame, cv2.COLOR_BGR2HSV), lo, hi)
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((5, 5), np.uint8))
    cnts, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    if cnts:
        c = max(cnts, key=cv2.contourArea)
        M = cv2.moments(c)
        if M["m00"] > 500:
            cx, cy = int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])
            err = cx - frame.shape[1] // 2        # PID'e ver -> dönüş hızı
            cv2.circle(frame, (cx, cy), 8, (0, 255, 0), -1)
            cv2.putText(frame, f"error {err}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
    cv2.imshow("tracking", frame)
    if cv2.waitKey(1) == 27:
        break
Python (OpenCV): yol görüntüsünden şerit sapması
import cv2
import numpy as np

def lane_offset(frame):
    h, w = frame.shape[:2]
    roi = frame[int(h * 0.6):, :]                      # aracın önündeki yol
    gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(cv2.GaussianBlur(gray, (5, 5), 0), 60, 150)
    lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 40, minLineLength=40, maxLineGap=20)
    if lines is None:
        return None
    xs = [x for l in lines for x in (l[0][0], l[0][2])]
    left = [x for x in xs if x < w / 2]
    right = [x for x in xs if x >= w / 2]
    if not left or not right:
        return None
    centre = (max(left) + min(right)) / 2
    return (centre - w / 2) / (w / 2)                   # -1 .. +1, direksiyon PID'ine ver

Sık yapılan hatalar

  • OpenCV'nin görüntüleri BGR olarak yüklediğini unutup COLOR_RGB2HSV ile dönüştürmek; tüm renk eşikleri yanlış olur.
  • OpenCV renk tonunu 0 ile 179 arasında saklarken derece cinsinden (0 ile 360) aralıklar kullanmak.
  • Kırmızıyı tek bir renk tonu aralığıyla bölütlemek ve nesnenin yarısını kaybetmek.
  • Otomatik pozlamayı ve beyaz dengesini açık bırakmak; ayarlanmış eşikler ışık değişince çalışmaz.
  • Metrik mesafeleri veya işaretçi konumlarını kalibre edilmemiş, tahmini iç parametrelerle hesaplamak.
  • Ham piksel farkını PID hatası olarak kullanıp sonra kamera çözünürlüğünü değiştirmek; tüm kazançlar sessizce ölçek değiştirir.

Yazılım mühendisliği bağlantısı

Görüntü işleme kodu mantık kadar veriye de bağlıdır, bu yüzden veriye dayalı testler ister. Depoda küçük bir gerçek veya simüle kare kümesini (tests/images/), her biri için beklenen sonuçla birlikte saklayın: şerit kayması, işaretçi kimliği ve konumu, hedef ağırlık merkezi.

  • Fikstür testleri (fixture tests), işlem hattını saklanan her görüntü üzerinde çalıştırır ve beklenen değerlerle bir tolerans içinde karşılaştırır.
  • Sürüm kontrolünde yapılandırma: HSV eşikleri ve kamera kalibrasyon dosyası (camera_info.yaml) koddaki sihirli sayılar değil, girdilerdir.
  • Performans bütçesi: CI'da kare başına milisaniyeyi ölçün ve işlem hattı referans makinede örneğin 20 ms'yi aşarsa başarısız kılın.
  • Saf görüntü işlemeyi kamera G/Ç'sinden ayırın; böylece aynı fonksiyon testlerde, Webots'ta ve robotta çalışır.

Dönem projesi uygulaması: zor durumları (gölgeler, virajlar, açılı duran bir işaretçi) kapsayan on Webots karesi yakalayın, beklenen çıktıları etiketleyin ve bunları fikstür testi olarak ekleyin.

Laboratuvar görevi

Önce tarayıcıdaki renk izleme simülasyonunu çalıştır, sonra OpenCV izleyicisini kendi kameranla: seçtiğin bir nesne için HSV aralığını ayarla ve hatayı 10 Hz'de yazdır. Webots'ta proje aracına bir kamera ekle ve lane_offset() fonksiyonunun verdiği şerit sapmasını her karede yazdır.

Kendini sına

  1. Bir kamerada f_x = 800 piksel. 0,20 m genişliğindeki bir nesne 50 piksel genişliğinde görünüyor. Nesne ne kadar uzaktadır?

  2. OpenCV'nin HSV uzayında kırmızı bir nesne nasıl bölütlenmelidir?

  3. Bir hedef u = 400 pikselde, c_x = 320 piksel ve f_x = 530 piksel. Optik eksene göre yönü nedir?

  4. Saniyede 30 kare veren 1280 × 720 RGB bir kameranın ham veri hızı nedir?

Bu hafta dönem projesinde

  • Otonom kara aracı: Şerit takibi. lane_offset() + PID ile bir tur; sapma grafiği teslim.
  • Otonom drone görevi: İşaretçi tespiti. Kamera görüntüsünden ArUco pozu; piksel hatası ve tahmini mesafe kaydı.
  • Görsel kılavuzlu robot kol: Küp tespiti ve homografi. Renk ayırma + homografiyle küplerin dünya konumu; hata tablosu.

Ödev

Şerit sapmasını 6. haftadaki PID sınıfına bağla ve Webots aracının şeritten çıkmadan pistte bir tur atmasını sağla. Kısa bir video ve sapmanın zamana göre grafiğini teslim et.

Bu haftanın donanımı (Hyvex)

Esc
  • PanelAna sayfaSayfa
  • ModüllerTüm modüllerSayfa
  • ParçalarParça ansiklopedisiSayfa
  • Mühendislik yoluBüyükler için robotik: 128 parça, 7 seviyeSayfa
  • Robotik dersi (ESOF 323)Üniversite robotik dersi, 14 haftaSayfa
  • TestlerimMini testler ve puanlarSayfa
  • Blok atölyesiSerbest blok programlamaAraç
  • Devre laboratuvarıSanal Arduino ve devreAraç
  • Robot arenasıSanal robot sürüşüAraç
  • OyunlarBloklarla 8 öğretici oyunAraç
  • Mikro Kart atölyesiSanal LED kartı bloklarla programlaAraç
  • Robot atölyesiMikro Kart'ı robota tak, bloklarla görev yapAraç