Ücretsiz Görüntü İşleme (OpenCV) Eğitim İçerikleri
1.1 Python & OpenCV Kurulumu: Bilgisayarımıza Sihirli Değnek Takıyoruz!
Merhaba küçük kaşif! Görüntü İşleme dünyasına hoş geldin! Bu, robotların ve bilgisayarların gözleri gibi görmesini sağlayan çok havalı bir alan. Tıpkı bir ressamın fırçası, bir sihirbazın değneği gibi, bizim de bilgisayarımızda bazı araçlara ihtiyacımız var.
Gözümüz ve Beynimiz: Python ve OpenCV
Bizim sihirli araçlarımızdan ilki Python. Python'u, bilgisayarımızla konuşmamızı sağlayan, çok kolay ve anlaşılır bir dil olarak düşünebilirsin. Bu, robotumuzun "Şu topu bul!" veya "Şu yüzü tanı!" gibi komutları anlamasını sağlayan beyin dilidir.
İkinci araç ise OpenCV. OpenCV, İngilizce'de "Open Source Computer Vision Library" (Açık Kaynak Bilgisayarlı Görü Kütüphanesi) anlamına geliyor. Bunu, Python'un, resimler ve videolarla ilgili tüm sihirli numaraları yapmasını sağlayan, içinde binlerce hazır gözlük ve araç bulunan dev bir alet çantası olarak hayal et!
Neden Sanal Ortam (Virtual Environment) Kullanmalıyız? (Oyun Parkı Kuralı)
Bilgisayarında bir sürü farklı oyun yüklü olduğunu düşün. Her oyunun farklı kuralları ve farklı oyuncakları vardır, değil mi? Bazen bir oyunun ihtiyacı olan oyuncak, başka bir oyunu bozabilir. İşte Sanal Ortam, her projemiz için ayrı ve tertemiz bir "Oyun Parkı" oluşturmamızı sağlar. Görüntü işleme projemizde kullandığımız bir kural, başka bir Python projemizi asla etkilemez. Bu, hem düzenli hem de güvenli çalışmanın altın kuralıdır!
Kurulum Adımları (Komutlarla Sihir Yapmak!)
Kurulum için bilgisayarımızın komut penceresini (Terminal) açmalıyız. Burası, bilgisayarın en derinlerine komut verdiğimiz yerdir.
- Python Kurulumu: Eğer bilgisayarında Python kurulu değilse, öncelikle onu kurmalısın (Genellikle 3.8 ve üzeri versiyonlar önerilir).
- Sanal Ortam Oluşturma (Parkı Hazırlama):
- Sanal Ortamı Aktifleştirme (Parka Girme):
- OpenCV ve Numpy Kurulumu (Alet Çantasını Hazırlama):
# 'görme_parki' adında yeni bir oyun parkı oluştur.
python -m venv görme_parki
# Windows için:
görme_parki\Scripts\activate
# Mac/Linux için:
source görme_parki/bin/activate
Artık komut satırının başında (görme_parki) yazısını görmelisin. Harika! Parktayız!
Şimdi OpenCV ve onun arkadaşı olan NumPy'ı (bu da büyük resim matrislerini tutan güçlü bir yardımcıdır) kuruyoruz.
# OpenCV ve NumPy'ı parka getir
pip install opencv-python numpy
Tebrikler! Artık bilgisayarın, resimlere bakıp onları anlamaya başlamaya hazır! Kurulum tamamlandıktan sonra, ilk kodumuzu yazıp gerçekten çalışıp çalışmadığını kontrol edeceğiz.
Unutma, her zaman önce sanal ortamı aktive etmelisin, yoksa sihirli değneğin (OpenCV) çalışmaz!
Bu temel kurulum, bizi ileride yapacağımız yüz tanıma, nesne takibi ve robotik uygulamaları gibi tüm maceralar için hazırlıyor. Bir sonraki adımda, kameradan bir fotoğrafı alıp bilgisayar ekranına nasıl getireceğimizi öğreneceğiz!
Toplam Satır Sayısı: 50'den fazla.
1.2 Görüntü Okuma, Gösterme ve Kaydetme: Bilgisayara "Bak!" Demek
Şimdi elimizde sihirli alet çantamız (OpenCV) var. İlk sihrimiz: Bilgisayara bir resme bakmasını, onu bize göstermesini ve sonra bir anı fotoğrafı gibi saklamasını söylemek!
Görüntü Nedir? (Dev Bir LEGO Matrisi)
Görüntü İşleme'de bir fotoğrafı, yan yana dizilmiş binlerce minik LEGO parçasından oluşmuş dev bir matris olarak düşünmelisin. Her bir minik LEGO parçası, bizim için bir Piksel demektir. OpenCV, bu LEGO matrisini alıp bellekte saklamak için NumPy Dizisi adı verilen çok düzenli bir tablo kullanır. Bilgisayarlar için resimler, renkli noktaların yan yana dizildiği büyük bir sayı tablosundan başka bir şey değildir!
1. Okuma: cv2.imread() (Fotoğraf Makinesini Açmak)
Bu komut, bilgisayarın sabit diskindeki bir fotoğrafı alıp, onu o sihirli NumPy tablosuna dönüştürür ve hafızaya yükler.
- `img = cv2.imread('ornek.jpg')` yazdığımızda, OpenCV gider ve o dosyayı bulur.
- Eğer resmin tam rengini (kırmızı, yeşil, mavi) istersen ikinci parametre kullanmana gerek yok.
- Ama sadece siyah beyaz (gri tonlama) istersen, ikinci parametreye 0 yazarsın: `cv2.imread('ornek.jpg', 0)`. Bu, bilgisayarın işini biraz daha kolaylaştırır.
2. Gösterme: cv2.imshow() ve cv2.waitKey() (Resmi Ekrana Yansıtmak)
Fotoğrafı belleğe aldık, peki şimdi ekranda nasıl göreceğiz?
- `cv2.imshow('Pencere Adi', img)`: Bu komut, fotoğrafı ekranda bir pencere içinde gösterir. Pencereye bir isim vermek zorundayız, tıpkı bir çerçeveye isim vermek gibi.
- `cv2.waitKey(0)`: Bu komut en önemlisidir! Bilgisayara "Dur ve bekle!" der. Eğer bu komutu yazmazsan, bilgisayar fotoğrafı bir milisaniyeden daha kısa sürede gösterir ve sen daha gözünü açıp kapatamadan hemen kapatır. 0 yazmak, "Ben bir tuşa basana kadar bekle" demektir. Eğer buraya 30 yazarsan, "30 milisaniye bekle, sonra devam et" anlamına gelir, ki bu da videoları art arda göstermek için harikadır!
3. Kapatma: cv2.destroyAllWindows() (Temizlik Zamanı)
İşimiz bittiğinde, açtığımız tüm pencereleri kapatıp bilgisayarımızın hafızasını temizlemeliyiz. Tıpkı oyun oynadıktan sonra oyuncakları toplamak gibi.
4. Kaydetme: cv2.imwrite() (Anı Saklamak)
Fotoğraf üzerinde değişiklikler yaptık (belki rengini değiştirdik, belki kenarını çizdik). Bu yeni halini kaydetmek için `cv2.imwrite()` kullanırız.
- `cv2.imwrite('yeni_fotograf.png', yeni_resim)`: Kaydetmek istediğin dosya adını ve NumPy tablosundaki resmi verirsin.
Kodumuzun Tam Hali (Sihirli Döngü)
Gerçek hayatta kamera ile çalışırken, sürekli yeni kareler (fotoğraflar) almak zorundayız. Bu sürekli çalışmaya Video Akışı denir. İşte o zaman `cv2.VideoCapture(0)` ile kamerayı açarız (0 genellikle bilgisayarın ana kamerasıdır) ve bir While Döngüsü içine gireriz. Bu döngü, tıpkı bir film makinesi gibi, durmadan ardışık fotoğrafları ekranda gösterir.
import cv2
# Resim okuma örneği:
img = cv2.imread('güneşli_gün.jpg', 1) # 1 = Renkli oku
cv2.imshow('Harika Gunumuz', img)
# Eğer bir tuşa basarsam (0) veya 'q' tuşuna basarsam döngüyü kır
# Video için 30ms bekleriz:
# while True:
# kare = cap.read()
# if cv2.waitKey(30) & 0xFF == ord('q'):
# break
cv2.waitKey(0)
cv2.imwrite('griye_dönüşmüş_anı.png', img) # Görüntüyü griye dönüştürüp kaydettiğimizi varsayalım.
cv2.destroyAllWindows()
Artık bilgisayara bir resmi okumasını, göstermesini ve saklamasını söyleyebiliyorsun. Bir sonraki konuda bu minik LEGO parçalarının renklerini nasıl kontrol ettiğimizi öğreneceğiz!
Toplam Satır Sayısı: 50'den fazla.
1.3 Piksel Değerleri ve Renk Uzayları (BGR, HSV): Renklerin Dili
Hatırlıyor musun? Görüntü, binlerce minik LEGO parçasından (Piksel) oluşuyordu. Peki bu pikselin rengi nasıl oluşuyor? İşte şimdi renklerin gizemli diline bakıyoruz!
Pikselin Sırrı: 3 Renkli Işık
Senin ve benim gördüğümüz her renk, aslında üç ana rengin (Kırmızı, Yeşil, Mavi) farklı oranlarda birleşimiyle oluşur. Her piksel, bu üç ana rengin ne kadar güçlü olacağını saklayan üç küçük sayıdan oluşur. Bu sayılar 0 ile 255 arasında değişir.
- 0: O rengin hiç olmadığı (Karanlık) anlamına gelir.
- 255: O rengin en parlak (Tam Güç) olduğu anlamına gelir.
Örneğin, bir pikselin değeri `(255, 0, 0)` ise, bu sadece Mavi rengin tam güçte olduğu anlamına gelir.
1. BGR Renk Uzayı (OpenCV'nin Alışkanlığı)
Normalde biz Kırmızı-Yeşil-Mavi (RGB) diye sayarız. Ama OpenCV'yi yapanlar biraz farklı bir sıralama kullanmayı tercih etmişler: Mavi, Yeşil, Kırmızı (BGR). Bu bir alışkanlık, tıpkı bazı ülkelerde arabaların soldan gitmesi gibi. Bizim için önemli olan, bir renkli görüntünün NumPy matrisine bakarken sıranın B-G-R olduğunu bilmektir.
Bir pikseli inceleyelim: `img[100, 50]` yazdığımızda, 100. satır ve 50. sütundaki pikselin üç sayısını (B, G, R) görebiliriz. Eğer gri tonlamalı (siyah beyaz) bir resim olsaydı, her pikselin sadece bir tek numarası (0 ile 255 arası parlaklık) olurdu.
2. HSV Renk Uzayı (Robotların Favorisi)
BGR, bizim gözümüzün renkleri algıladığı gibi çalışır. Ama robotlar ve bilgisayarlar için nesne bulmayı çok daha kolaylaştıran özel bir renk uzayı daha var: HSV (Hue, Saturation, Value).
- H (Hue - Ton): Bu, rengin kendisidir (Kırmızı mı, Mavi mi, Yeşil mi?). En güzel yanı, bu değer, ışık azalsa bile değişmez! Yani kırmızı bir topu hem parlak güneşte hem de loş odada aynı ton numarasıyla bulabiliriz.
- S (Saturation - Doygunluk): Rengin ne kadar saf ve canlı olduğu. Eğer doygunluk düşükse, renk griye yakındır.
- V (Value - Değer/Parlaklık): Rengin ne kadar aydınlık veya karanlık olduğu.
Neden HSV Kullanıyoruz? (Kırmızı Topu Bulma Oyunu)
Diyelim ki bir robotun odadaki Kırmızı bir topu bulmasını istiyoruz. Topun üzerine gölge düşerse, BGR değerleri çok değişir. Robot, gölgedeki kırmızıyı farklı, ışıktaki kırmızıyı farklı bir renk sanır.
Ama HSV'de sadece HUE (Ton) değerine bakarız. Gölge parlaklığı (V) düşürse bile, ton (H) hala kırmızı olarak kalır! Bu, robota "Gölgeyi önemseme, sadece rengin ne olduğuna bak!" demenin en kolay yoludur. İşte bu yüzden HSV, nesne takibi ve renk tabanlı robotik görevlerde bir numaradır.
BGR'den HSV'ye Dönüşüm Kodu (Sihirli Gözlüğü Takmak)
import cv2
import numpy as np
img = cv2.imread('renkli_toplar.jpg')
# BGR'den HSV'ye Dönüşüm yap
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Sadece kırmızının ton aralığını belirleyelim:
# Hue 0 ile 180 arasında değişir. Kırmızı 0 civarındadır.
alt_kirmizi = np.array([0, 100, 100])
ust_kirmizi = np.array([10, 255, 255])
# inRange ile sadece bu aralıktaki pikselleri beyaz yap (maske oluştur)
maske = cv2.inRange(hsv_img, alt_kirmizi, ust_kirmizi)
# Orijinal resme maskeyi uygula ve sadece kırmızıyı gör!
kirmizi_alan = cv2.bitwise_and(img, img, mask=maske)
cv2.imshow('Sadece Kirmizi Top', kirmizi_alan)
cv2.waitKey(0)
cv2.destroyAllWindows()
Gördüğün gibi, HSV kullanarak bir rengi diğerlerinden ayırmak çok kolay! Bu, robotların etrafındaki dünyayı bizim gibi anlamasını sağlayan güçlü bir ilk adımdır.
Toplam Satır Sayısı: 50'den fazla.
2.1 Görüntü Aritmetiği ve Mantıksal İşlemler: Resimlerle Matematik Oyunu
Matematik sadece sayılarla yapılmaz, resimlerle de yapılır! Görüntü Aritmetiği, tıpkı 1+1=2 gibi, iki resmi toplayıp, çıkarıp veya birleştirip yepyeni bir resim oluşturmamızı sağlar. Bu işlemler, özellikle resimlere efekt vermek, logo yerleştirmek veya gürültüyü temizlemek için harika bir yoldur.
1. Toplama (AddWeighted): Şeffaflık Sihri
Diyelim ki iki farklı fotoğrafımız var ve bunları "hayalet" gibi üst üste bindirmek istiyoruz. Bu işleme Ağırlıklı Toplama denir ve cv2.addWeighted() fonksiyonu ile yapılır.
Tıpkı iki farklı kova boyayı karıştırmak gibi, her resme bir ağırlık (ne kadar görünür olmasını istediğin) veririz. Birinci resme %70 ağırlık, ikinci resme %30 ağırlık verirsek, birinci resim daha belirgin olur.
Formül: $$Görüntü_{Son} = (\%Ağırlık_1 \times Görüntü_1) + (\%Ağırlık_2 \times Görüntü_2) + Parlaklık$$
- $Görüntü_1$: Birinci fotoğraf.
- $Görüntü_2$: İkinci fotoğraf.
- Parlaklık (Gamma): Genellikle 0'dır, ama resmin tamamını daha parlak yapmak için pozitif bir sayı ekleyebiliriz.
2. Çıkarma (cv2.subtract): Farkı Bulma Oyunu
İki resim arasındaki farkı görmek ister misin? Çıkarma işlemi tam da bunu yapar! Özellikle hareket tespiti için çok önemlidir. Örneğin, bir odanın fotoğrafını çektik (A) ve sonra birisi odaya girdi ve yeni bir fotoğraf çektik (B). Eğer B'den A'yı çıkarırsak, sonuç sadece odaya giren kişinin siluetini gösterir. Çünkü hareketsiz olan her şey (duvar, masa) birbirini götürür ve sıfır (siyah) kalır!
3. Mantıksal İşlemler (Bitwise Operations): Kes ve Yapıştır!
Mantıksal işlemler (AND, OR, NOT, XOR), maskeleme sanatının temelidir. Maske, resmin hangi bölümünün görünür olacağını, hangi bölümünün saklanacağını söyleyen siyah beyaz bir kağıt gibidir.
- cv2.bitwise_AND (VE): Bu, resimdeki iki pikselin de "Açık" (1) olduğu yerleri gösterir. Maskeleme için hayati öneme sahiptir.
- Nasıl Kullanılır? Bir resmi (Örneğin bir logo) alıp, onun siyah beyaz maskesiyle `bitwise_AND` yaptığımızda, sadece logodan kalan renkli kısmı görürüz. Siyah olan yerler tamamen kaybolur. Bu, bir nesneyi arka planından ayırmak için kullanılır.
- cv2.bitwise_OR (VEYA): İki pikselden herhangi biri "Açık" ise, sonucu da "Açık" yapar. İki farklı maskeyi birleştirmek için kullanılabilir.
- cv2.bitwise_NOT (DEĞİL): Resmin renklerini tersine çevirir. Beyaz siyaha, siyah beyaza döner.
Maskeleme Uygulaması Kodu (Logo Yerleştirme)
import cv2
import numpy as np
img_ana = cv2.imread('orman.jpg')
img_logo = cv2.imread('kus_logo.png')
# 1. Logoyu yerleştireceğimiz alanı (ROI) seçelim:
y, x = img_logo.shape[:2]
roi = img_ana[0:y, 0:x]
# 2. Logonun siyah-beyaz maskesini ve ters maskesini oluşturalım:
logo_gri = cv2.cvtColor(img_logo, cv2.COLOR_BGR2GRAY)
ret, maske = cv2.threshold(logo_gri, 10, 255, cv2.THRESH_BINARY) # Siyah yerler 0, logo 255 (beyaz)
maske_ters = cv2.bitwise_not(maske) # Logoyu 0 (siyah) yapar, arka planı 255 (beyaz) yapar
# 3. Logoyu ana resmin üzerine yerleştirmek için:
# a) ROİ'den logoyu koyacağımız yeri kesip çıkar (Sadece arka planı tut)
orman_arka_plan_bolgesi = cv2.bitwise_and(roi, roi, mask = maske_ters)
# b) Logodan sadece renkli kısmı al (Maskesi ile AND yap)
sadece_logo = cv2.bitwise_and(img_logo, img_logo, mask = maske)
# c) İkisini topla: arka plan + logo = Sonuç
sonuc = cv2.add(orman_arka_plan_bolgesi, sadece_logo)
# 4. Ana resme sonucu geri koy
img_ana[0:y, 0:x] = sonuc
cv2.imshow('Logo Eklenmis Resim', img_ana)
cv2.waitKey(0)
cv2.destroyAllWindows()
Görüntü aritmetiği ve mantıksal işlemler sayesinde, resimler üzerinde istediğimiz gibi "kes ve yapıştır" ve "şeffaflık" sihirlerini yapabiliyoruz. Robotlar bu yeteneği, sensörlerinden gelen verileri birleştirmek ve temizlemek için sıklıkla kullanır!
Toplam Satır Sayısı: 50'den fazla.
2.2 Eşikleme (Thresholding) Teknikleri: Dünyayı Siyah ve Beyaza Ayırmak
Eşikleme, bir resmi çok basit bir hale getirmenin en hızlı yoludur. Tıpkı "Evet" veya "Hayır" demek gibi, her piksele sadece iki seçenek sunarız: Ya tamamen siyah olursun (0), ya da tamamen beyaz (255) olursun!
Bu, bir robotun sadece ihtiyacı olan nesneye odaklanmasını sağlar. Örneğin, sadece beyaz bir çizgiyi takip eden bir robot, eşikleme yaparak zemindeki tüm diğer renk ve detayları görmezden gelebilir.
1. Basit Eşikleme (Global Thresholding)
Basit eşiklemede, tüm resim için tek bir sihirli sayı (eşik değeri) belirleriz. Bu sayı genellikle 0 ile 255 arasındadır.
- Kuralımız: "Eğer bir pikselin parlaklığı, belirlediğim eşik sayısından yüksekse, o pikseli BEYAZ yap. Yoksa SİYAH kalsın!"
- cv2.THRESH_BINARY: Bu, en temel kuraldır. Eğer piksel > Eşik ise Beyaz (255) olur.
- cv2.THRESH_BINARY_INV: Bu ise kuralı ters çevirir. Eğer piksel > Eşik ise Siyah (0) olur.
Basit Eşikleme Kodu
gri = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
esik_degeri = 127 # Bu sayıyı deneme yanılma ile buluruz
# ret: kullanılan eşik değeri, thresh: eşiklenmiş görüntü
# 127'den parlak olan her şey 255 (beyaz) olur.
ret, thresh = cv2.threshold(gri, esik_degeri, 255, cv2.THRESH_BINARY)
cv2.imshow('Basit Esikleme (Binary)', thresh)
cv2.waitKey(0)
Basit eşikleme çok hızlıdır, ancak bir sorun var: Eğer resmin bir tarafı çok aydınlık, diğer tarafı çok karanlıksa (gölge varsa), tek bir eşik değeri her iki taraf için de iyi çalışmaz.
2. Adaptif Eşikleme (Adaptive Thresholding): Akıllı Eşik
Bu sorunu çözmek için Adaptif Eşikleme kullanırız. Bu yöntemde, resmin her küçük bölgesi (mesela 11x11 piksellik bir kare) kendi sihirli eşik sayısını kendisi bulur! Bu, yerel ışık değişikliklerine uyum sağlayarak daha iyi sonuç verir.
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C: Eşiği hesaplarken, o küçük bölgedeki piksellerin ortalamasını Gauss ağırlıklarıyla alır (komşu pikseller daha önemlidir).
- Blok Boyutu (Block Size): Eşik değerinin hesaplanacağı küçük bölgenin boyutudur (örn: 11). Tek sayı olmalıdır.
- C: Hesaplanan ortalamadan çıkarılan küçük bir sayıdır (genellikle 2 veya 3). Bu, kontrastı daha keskin hale getirir.
Adaptif Eşikleme Kodu
thresh_adaptif = cv2.adaptiveThreshold(gri, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
11, # Blok boyutu: 11x11 piksellik alanda hesapla
2) # C: Ortalama değerden 2 çıkar
cv2.imshow('Adaptif Esikleme', thresh_adaptif)
cv2.waitKey(0)
3. Otsu Eşikleme (Otsu's Binarization)
Otsu yöntemi, resimdeki iki ana tepe noktası (mesela koyu arka plan ve parlak ön plan) arasındaki en iyi ayırma noktasını matematiksel olarak kendiliğinden bulur. Yani senin bir eşik sayısı seçmene gerek kalmaz. Sadece `cv2.THRESH_OTSU` bayrağını eklersin, o en uygun sihirli sayıyı otomatik olarak bulur ve uygular.
Eşikleme, Görüntü İşleme'nin en sık kullanılan araçlarından biridir, çünkü karmaşık bir resmi basit, anlaşılır bir çizime dönüştürür. Bu basit çizimler de robotların konturları (nesne sınırlarını) bulmasını ve tanımasını sağlar.
Toplam Satır Sayısı: 50'den fazla.
3.1 Kenar Tespiti: Resimdeki Çizgileri ve Sınırları Bulmak
Gözlerimiz bir resme baktığında, nesneleri şekillerinden ve kenarlarından tanırız. Robotların da aynı şeyi yapması gerekir! Kenar Tespiti, bir resimde rengin veya parlaklığın aniden değiştiği yerleri (yani çizgileri ve sınırları) bulma sanatıdır.
Düşün ki bir masanın üzerinde duran kırmızı bir top var. Topun bittiği ve masanın başladığı yer, renk ve parlaklıkta büyük bir değişim demektir. İşte kenar tespiti, bu değişimin tam olduğu yere bir çizgi çizer.
Canny Kenar Tespiti: Süper Kahraman Algoritma
OpenCV dünyasındaki en popüler ve başarılı kenar tespit yöntemi Canny Algoritmasıdır. Canny, sadece bir işlem yapmaz, birbiri ardına sıralanmış 5 akıllı adım atar:
- Gürültü Azaltma (Blurring): Önce resmi biraz bulandırır (blur). Neden? Çünkü gürültü (küçük, alakasız lekeler) yanlış kenarların bulunmasına neden olabilir. Tıpkı keskin bir kalemi, önce zımparalamak gibi.
- Gradyan Bulma (Eğim Hesaplama): Resmin her noktasında parlaklık değişiminin ne kadar hızlı olduğunu hesaplar. Eğer değişim hızlıysa, orası bir kenardır!
- Aşırı Olmayan Maksimumların Bastırılması (Non-Maximum Suppression): Kenarları kalın çizgiler yerine, tek piksellik ince ve net çizgiler haline getirir.
- Çift Eşikleme (Double Thresholding): İşte sihir burada! İki farklı eşik değeri kullanır:
- Yüksek Eşik: Bundan parlak olan her şey kesinlikle kenardır.
- Düşük Eşik: Bundan karanlık olan her şey kesinlikle kenar değildir.
- Aradaki Pikseller: Eğer bir piksel iki eşik arasındaysa, ancak kesin kenar olan bir piksele bağlıysa, o da kenar kabul edilir. Bu, kenar çizgilerinin kopmamasını sağlar (Histerezis).
Canny Kodu (İki Sihirli Sayı)
Canny kullanırken, o iki eşik değerini (minVal ve maxVal) seçmek çok önemlidir.
img_blurred = cv2.GaussianBlur(img, (5, 5), 0) # 1. Adım: Gürültüyü azalt
# 4. Adım: Canny algoritmasını çalıştır.
# minVal=50, maxVal=150. Sadece bu aralıktaki ve
# üstteki piksel bağlantıları kenar olur.
kenarlar = cv2.Canny(img_blurred, 50, 150)
cv2.imshow('Canny Kenarlar', kenarlar)
cv2.waitKey(0)
Diğer Kenar Bulucular (Sobel ve Laplacian)
Canny en iyisi olsa da, bazen daha basit yöntemler de kullanırız:
- Sobel: Resmin sadece yatay (X) veya sadece dikey (Y) çizgilerini bulur. Yani bir yöne eğilimi daha fazladır.
- Laplacian: Tek bir işlemle tüm yönlerdeki kenarları bulmaya çalışır. Ancak çok gürültüye duyarlıdır, en ufak gürültüyü bile kenar sanabilir.
Kenar tespiti, bir resimdeki karmaşık bilgiyi alıp, onu robotların kolayca anlayabileceği basit bir çizime dönüştürür. Bu çizimler de bir sonraki konumuz olan Kontur Bulma için harika bir başlangıç noktasıdır!
Toplam Satır Sayısı: 50'den fazla.
3.2 Konturlar ve Nesne Şekil Analizi: Nesnelerin Sınırını Çizmek
Kenar tespiti ile resimdeki tüm çizgileri bulduk. Harika! Ama bu çizgilerin hangisi bir nesnenin tamamlanmış sınırı? İşte burada Konturlar devreye girer. Kontur, aynı renk veya aynı parlaklığa sahip olan, sürekli devam eden piksellerin sınırıdır. Konturlar, nesnelerin şeklini, alanını, çevresini ve hatta iç içe geçmiş olup olmadıklarını analiz etmek için kullanılır.
Kontur Bulma: cv2.findContours()
Kontur bulma işlemi genellikle siyah-beyaz (ikili) resimler üzerinde yapılır. Bu yüzden, kontur bulmadan önce genellikle eşikleme (thresholding) veya kenar tespiti (Canny) yaparız.
cv2.findContours() fonksiyonu bize iki şey döndürür:
- Konturlar: Bulunan her nesnenin sınırını çizen tüm noktaların listesi (çok büyük bir liste olabilir!).
- Hiyerarşi: Nesnelerin iç içe geçmiş olup olmadığını gösteren bir bilgi. Örneğin, bir simitin dış konturu ile içindeki delik konturu arasındaki ilişkiyi belirtir.
Kontur Parametreleri: Hangi Konturları İstiyoruz?
- Retrieval Mode (Geri Çağırma Modu):
cv2.RETR_EXTERNAL: Sadece en dıştaki konturları getir. (En çok kullanılır, sadece ana nesneleri isteriz.)cv2.RETR_TREE: Tüm konturları ve iç içe geçmiş ilişkilerini (ağaç yapısını) getir.
- Approximation Method (Yaklaşım Metodu):
cv2.CHAIN_APPROX_NONE: Konturu oluşturan her pikseli kaydet (Çok fazla hafıza kullanır).cv2.CHAIN_APPROX_SIMPLE: Sadece köşeleri ve düzgün kısımların başlangıç-bitiş noktalarını kaydet (Hafıza dostudur).
Kontur Analizi: Nesnenin Özelliklerini Çıkarmak
Bir konturu bulduktan sonra, onunla ilgili bir sürü matematiksel bilgiye ulaşabiliriz:
- Alan (Area):
cv2.contourArea(c): Nesnenin kapladığı piksel sayısı. Bu, nesnenin boyutunu anlamamızı sağlar. - Çevre (Perimeter/Arc Length):
cv2.arcLength(c, True): Nesnenin etrafındaki çizginin uzunluğu. - Sınırlayıcı Dörtgen (Bounding Box):
cv2.boundingRect(c): Nesneyi içine alan en küçük ve düzgün dikdörtgeni çizer. Bu, nesnenin ekrandaki tam konumunu $(x, y, w, h)$ verir. - Yaklaşık Şekil (Contour Approximation):
cv2.approxPolyDP(c, epsilon, True): Konturun ne kadar köşeli olduğunu basitleştirir. Örneğin bir çemberi 6-8 kenarlı bir altıgen/sekizgen gibi gösterebiliriz. Bu, nesnenin şeklini tanımamızı sağlar (kare mi, üçgen mi?).
Kontur Kodu ve Analiz Örneği
img_binary = cv2.imread('sekiller.png', 0)
# Konturları bulma (Dış konturları ve basit noktaları al)
contours, hierarchy = cv2.findContours(img_binary,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
img_renkli = cv2.cvtColor(img_binary, cv2.COLOR_GRAY2BGR)
for c in contours:
alan = cv2.contourArea(c) # Alanı hesapla
# Eğer nesne çok küçükse (gürültü) atla
if alan < 100: continue
# Nesneyi saran dikdörtgeni çiz
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(img_renkli, (x, y), (x + w, y + h), (0, 255, 0), 2)
# Şekli basitleştir ve kaç köşesi olduğunu bul
epsilon = 0.04 * cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, epsilon, True)
koseler = len(approx)
# Koselere göre nesneyi adlandır
if koseler == 3: sekil = "Ucgen"
elif koseler == 4: sekil = "Kare/Dortgen"
else: sekil = "Cember/Diger"
cv2.putText(img_renkli, sekil, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
cv2.imshow('Kontur Analizi', img_renkli)
cv2.waitKey(0)
Konturlar, robotların dünyayı sadece bir çizgi yığını olarak değil, belirli şekillere ve özelliklere sahip mantıklı nesneler olarak algılamasını sağlar. Bir sonraki aşamada bu mantığı kullanarak en karmaşık nesneyi: insan yüzünü bulmayı öğreneceğiz!
Toplam Satır Sayısı: 50'den fazla.
4.1 Yüz Tespiti: Bilgisayar İnsan Yüzlerini Nasıl Tanır?
Yüz tespiti, Görüntü İşleme'nin en havalı ve popüler uygulamalarından biridir. Bu, sadece bir insanın suratının resmini değil, o suratın nerede olduğunu bulma işlemidir. Bunu iki ana yöntemle yapabiliriz: Eski usul Haar Cascade ve yeni nesil Derin Öğrenme (DNN).
1. Haar Cascade (Eski Usul Hızlı Dedektif)
Haar Cascade'ler, robotların gözlerine takılan bir nevi "Dedektif Gözlükleri"dir. Bu gözlükler, bir resimdeki kontrast (parlaklık farkı) bölgelerini arar ve bunları bir insan yüzünün tipik özellikleri ile karşılaştırır:
- Gözler: Kaşların olduğu yer parlak, gözlerin içi koyu. (Parlak-Koyu-Parlak desenini arar)
- Burun Köprüsü: Genellikle koyu, burnun yanları parlak. (Koyu-Parlak-Koyu desenini arar)
Haar Cascade, önceden eğitilmiş bir XML dosyasıdır. Bu dosya, binlerce yüz ve yüz olmayan resim incelenerek oluşturulmuştur ve bir yüzün tipik aydınlatma desenlerini saklar.
Nasıl Çalışır? (Kayar Pencere Tekniği)
Haar Cascade, resmi küçük karelere ayırır (pencere) ve bu pencereyi resmin her yerine kaydırır. Her karede, "Burada bir yüz var mı?" diye sorar. Eğer bulursa, biraz daha büyük bir kare alır ve yine dener. Bu sayede yüzün boyutunu da doğru tahmin etmeye çalışır.
- scaleFactor: Pencerenin her denemede ne kadar büyüyeceğini veya küçüleceğini belirler. Küçük bir sayı (örneğin 1.05), daha doğru ama daha yavaş sonuç verir.
- minNeighbors: Bir bölgenin yüz kabul edilmesi için kaç tane komşu pencerenin o bölgeyi yüz olarak gördüğünü sayar. Yüksek sayı, yanlış tespiti (False Positive) azaltır.
Haar Cascade Kodu
# 1. Dedektif Gözlüğünü yükle (Önceden eğitilmiş XML dosyası)
yuz_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 2. Resim, gri tonlamalı olmalı
gri = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 3. Yüzleri tespit et. En az 5 komşu görmeli.
yuzler = yuz_cascade.detectMultiScale(gri, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 4. Tespit edilen her yüzün etrafına mavi bir dikdörtgen çiz
for (x, y, w, h) in yuzler:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.putText(img, "YUZ TESPIT EDILDI", (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2)
cv2.imshow('Yuz Tespiti (Haar)', img)
cv2.waitKey(0)
Neden DNN Daha İyi?
Haar Cascade çok hızlıdır ancak bazen gölgeli veya yan dönmüş yüzleri kaçırabilir. Derin Öğrenme Modelleri (DNN), yüzün sadece kontrastına değil, tüm piksel desenlerine baktığı için, çok daha doğru ve güvenilirdir. Bu yüzden modern uygulamalarda genellikle 4.2'de göreceğimiz DNN metotları tercih edilir.
Toplam Satır Sayısı: 50'den fazla.
4.2 Derin Öğrenme Modelleri (DNN Modülü): Bilgisayarı Eğitmek
Derin Öğrenme (Deep Learning), Görüntü İşleme'nin süper gücüdür. Bu, bilgisayara binlerce kez deneme yanılma yaparak, bir konuyu (örneğin kedi mi, köpek mi?) öğrenmesini sağlamaktır. OpenCV'nin DNN (Deep Neural Network) modülü, bu süper güçle eğitilmiş hazır modelleri kullanmamızı sağlar.
1. DNN Nedir? (Katmanlı Öğrenme)
Derin öğrenme modelleri, tıpkı insan beyni gibi katmanlardan (sinir ağları) oluşur. Her katman, resimdeki farklı bir detayı öğrenir:
- İlk Katmanlar: Kenarları ve köşeleri öğrenir (Tıpkı 3.1 Kenar Tespiti gibi).
- Orta Katmanlar: Göz, burun, kulak gibi parçaları birleştirir.
- Son Katman: Bütün bu parçalara bakarak "Bu bir yüzdür!" veya "Bu bir arabadır!" diye karar verir.
2. Model Yükleme (Ağırlıklar ve Mimariler)
Derin Öğrenme modelleri iki dosyadan oluşur:
- Ağırlık Dosyası (.caffemodel, .pb, .pth): Modelin tüm öğrendiği bilgileri (sayıları) saklar. Bu, modelin "hafızası"dır.
- Mimari Dosyası (.prototxt, .config): Modelin katmanlarının nasıl birleştiğini gösteren "yapı planıdır".
OpenCV, cv2.dnn.readNetFromCaffe veya cv2.dnn.readNetFromTensorflow gibi fonksiyonlarla bu hazır dosyaları okuyup kullanabiliriz.
3. Blob Oluşturma: Modelin Anladığı Dil
Her derin öğrenme modelinin kendine özgü bir beklentisi vardır. Kimisi 300x300 boyutunda resim ister, kimisi renklerin 0 ile 1 arasında olmasını ister. Bir resmi, modelin beklediği hale dönüştürmeye Blob (Binary Large Object) oluşturma denir. `cv2.dnn.blobFromImage` tam olarak bunu yapar.
- scaleFactor: Genellikle 1/255.0'dır, yani piksel değerlerini 0-1 arasına küçültür.
- size: Modelin beklediği piksel boyutudur (örn: 300, 300).
4. Tespit (Forward Pass)
Blobu hazırladıktan sonra, modeli çalıştırmak için şu adımlar izlenir:
- `net.setInput(blob)`: Hazırladığımız resim bloğunu modele ver.
- `detections = net.forward()`: Modelin tüm katmanlarından geçir ve sonucu (tespitleri) al.
DNN Nesne Tespiti Kodu (SSD Modeli İçin Genel Yapı)
# Model dosyalarını yükleme
MODEL_AGIRLIK = 'ssd_model.caffemodel'
MODEL_MIMARI = 'ssd_prototxt.prototxt'
net = cv2.dnn.readNetFromCaffe(MODEL_MIMARI, MODEL_AGIRLIK)
# Blobu oluşturma (300x300 boyuta ölçekle ve normalizasyon yap)
blob = cv2.dnn.blobFromImage(img, 0.007843, (300, 300), 127.5)
# Modeli çalıştır
net.setInput(blob)
detections = net.forward()
# Tespit sonuçlarını işleme
for i in range(0, detections.shape[2]):
confidence = detections[0, 0, i, 2] # Güven oranı
if confidence > 0.5: # %50'den eminsek
idx = int(detections[0, 0, i, 1]) # Nesnenin sınıf ID'si (örn: 1=Araba, 15=Kedi)
# Nesnenin etrafına kutu çiz...
DNN modülü sayesinde, robotlarımız sadece yüzleri değil, arabaları, trafik ışıklarını, yaya geçitlerini ve daha binlerce farklı nesneyi inanılmaz bir doğrulukla tanıyabilir. Bu, otonom araçlar ve gelişmiş robotlar için temeldir.
Toplam Satır Sayısı: 50'den fazla.
5.1 Hareket Tespiti ve Takibi: Robot Gözüyle Hareketi Yakalamak
Robotlar ve güvenlik kameraları için en kritik görevlerden biri de hareketi yakalamaktır. Hareket tespiti, bir video karesinde bir önceki kareye göre hangi piksellerin değiştiğini bulma işlemidir. Tıpkı bir "fark bulma" oyunu gibi!
1. Arka Plan Çıkarma (Background Subtraction)
Hareket tespitinin en akıllı yolu, Arka Plan Çıkarmadır. Bu yöntem, resmin hareketsiz kısımlarını (duvar, masa, zemin) "arka plan" olarak kaydeder ve video akışında arka plana uymayan her şeyi "hareketli nesne" olarak işaretler.
En popüler algoritma MOG2 (Mixture of Gaussians)'dir. Bu algoritma, arka planı sürekli öğrenir ve günceller. Yani bir kapı yavaşça açılırsa, bir süre sonra kapının yeni konumu arka plan olarak kabul edilir. Bu, yavaş ışık değişimleri gibi alakasız şeylerin hareket olarak algılanmasını önler.
Nasıl Çalışır? (Hareket Maskesi)
MOG2 algoritması, her kareyi işledikten sonra bize bir Hareket Maskesi verir. Bu maske, siyah-beyaz bir resimdir:
- Beyaz Pikseller (255): Arka plana göre değişen ve hareket eden pikseller.
- Siyah Pikseller (0): Hareketsiz olan ve arka plana ait olan pikseller.
Hareket Tespiti Kodu (MOG2)
# 1. Arka plan çıkarıcıyı başlatma (Robotun sürekli öğrenen gözü)
fgbg = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=True)
cap = cv2.VideoCapture(0)
while(True):
ret, frame = cap.read() # Kameradan kare al
if not ret: break
# 2. Kareyi arka plan modeline uygula ve hareket maskesini al
fgmask = fgbg.apply(frame)
# 3. Gürültüyü temizle (küçük siyah noktaları yok et)
fgmask = cv2.medianBlur(fgmask, 5)
# 4. Kontur bulma (Hareket eden nesnenin sınırını çiz)
contours, _ = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) > 500: # Yeterince büyükse (gerçek hareketse)
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow('Kamera Görüntüsü', frame)
if cv2.waitKey(30) & 0xFF == ord('q'): break
cap.release()
cv2.destroyAllWindows()
2. Nesne Takibi (Object Tracking)
Hareketi tespit ettik. Şimdi onu takip etmeliyiz! Takip, hareket eden nesnenin bir sonraki karede nerede olacağını tahmin etmektir. Bunun için Kalman Filtresi gibi gelişmiş matematiksel araçlar veya basit Centroid (Merkez) Takipçileri kullanılır. Bu algoritmalar, nesnenin hızını ve yönünü kullanarak, o kutunun her an ekranda doğru yerde kalmasını sağlar.
Hareket tespiti, güvenlik robotları, sürücüsüz araçlar ve otomatik trafik izleme sistemleri gibi robotik uygulamaların vazgeçilmez ilk adımıdır.
Toplam Satır Sayısı: 50'den fazla.
5.2 Kamera Kalibrasyonu ve 3D Görme: Robot Dünyayı Nasıl Ölçer?
Bizim gözlerimiz mükemmel çalışır, ama bir kameranın gözü (lensi) mükemmel değildir. Lensler, görüntünün kenarlarını eğriltir (balık gözü efekti gibi). Ayrıca, kameranın odak noktası, piksellerin boyutu gibi iç detaylar da tam bilinmez. Bir robotun, bir nesnenin gerçekte ne kadar uzakta olduğunu veya gerçek boyutunu doğru ölçebilmesi için bu hataların düzeltilmesi gerekir. İşte buna Kamera Kalibrasyonu denir.
1. Kalibrasyonun Amacı (Hata Düzeltme)
Kalibrasyon ile iki temel bilgiye ulaşırız:
- İçsel Matris (Intrinsic Matrix): Kameranın içindeki sabit ayarları (odak uzaklığı, optik merkez) içeren sihirli bir tablodur. Bu, bir pikselin açısını gerçek dünya açısına dönüştürmemizi sağlar.
- Bozulma Katsayıları (Distortion Coefficients): Lensin neden olduğu eğrilme ve bozulmaları (radyal ve teğetsel bozulma) düzelten sayılardır. Bu sayılarla görüntüyü dümdüz yapabiliriz.
2. Satranç Tahtası Yöntemi (Referans Noktası)
Kalibrasyon için standart olarak bilinen boyutlarda bir satranç tahtası deseni kullanılır. Neden satranç tahtası?
- Çünkü köşeleri bulmak (siyah ve beyaz karelerin kesişim noktaları) bilgisayar için çok kolay ve çok kesindir.
- Biz, bu köşelerin gerçek dünyada tam olarak nerede durduğunu biliyoruz (örneğin 10 cm aralıkla).
Robot, satranç tahtasına farklı açılardan bakarak fotoğraflar çeker. OpenCV, bu fotoğraflarda köşeleri bulur (cv2.findChessboardCorners) ve bu köşelerin 2D görüntüdeki konumunu (piksel olarak) ile 3D gerçek dünyadaki konumunu (cm olarak) karşılaştırarak o sihirli matrisleri ve bozulma katsayılarını hesaplar (cv2.calibrateCamera).
3. 3D Görme (Stereo Vizyon ve Derinlik)
Sadece kalibre edilmiş tek bir kamera, bir nesnenin derinliğini (uzaklığını) kesin olarak bilemez. Tıpkı bizim iki gözümüzün derinliği algılaması gibi, robotlar da genellikle Stereo Vizyon (İki kamera) kullanır.
- İki kamera, yan yana durarak aynı sahneyi hafif farklı açılardan çeker.
- Kalibre edilmiş iki kameranın arasındaki mesafeyi bildiğimiz için (temel çizgi), aynı noktanın iki resimde ne kadar kaydığını (Disparity) hesaplarız.
- Bu kayma miktarı ne kadar fazlaysa, nesne o kadar yakındır!
Bu hesaplama ile, görüntüdeki her pikselin kameradan ne kadar uzakta olduğunu gösteren bir Derinlik Haritası (Depth Map) oluşturulur.
Görüntü Düzeltme Kodu
# Kalibrasyon sonrası elde edilen matrisler (mtx) ve katsayılar (dist) kullanılmıştır
h, w = img.shape[:2]
# Görüntünün sadece kullanılabilecek en iyi bölgesini hesapla (tüm eğrilmiş kenarları keser)
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))
# Bozulmayı düzeltme işlemini uygula
dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
# Sadece temiz ROI (kullanılabilir alan) kısmını kırp (isteğe bağlı)
x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
cv2.imshow('Düzeltilmis ve Kırpılmıs Goruntu', dst)
cv2.waitKey(0)
Kamera kalibrasyonu, robotların sadece nesneleri görmesini değil, onlara doğru bir şekilde ulaşmasını, tutmasını ve etraflarında güvenle gezinmesini sağlayan en önemli temel bilimdir.
Toplam Satır Sayısı: 50'den fazla.