Kurs içeriği (4 / 10)
  1. 1 Raspberry Pi ile Tanışma ve Kurulum 80 dk
  2. 2 Makine Öğrenmesi Nedir? İlk Modelimiz 80 dk
  3. 3 Kamera ve Görüntü İşlemenin Temelleri 80 dk
  4. 4 Görüntü Veri Seti Hazırlama 80 dk
  5. 5 Görüntü Tanıma Modeli Eğitip Pi’de Çalıştırma 120 dk
  6. 6 Mikrofon ve Sesin Temelleri 80 dk
  7. 7 Ses Veri Seti Hazırlama 80 dk
  8. 8 Ses Tanıma Modeli ile Sesli Komutlar 120 dk
  9. 9 Yapay Zekâyı Donanıma Bağlama: LED, Buzzer ve Servo 80 dk
  10. 10 Mini Proje: Akıllı Geri Dönüşüm Kutusu 160 dk

Raspberry Pi ile Makine Öğrenmesi: Görüntü ve Ses Tanıma · Ders 4 / 10

Görüntü Veri Seti Hazırlama

Uygulama ⏱ 80 dk

Akıllı geri dönüşüm kutumuz için kâğıt, plastik, metal ve boş sınıflarından oluşan bir görüntü veri seti topluyoruz. Fotoğrafları sınıf klasörlerine otomatik kaydeden bir Python programı yazıyor, iyi veri setinin kurallarını öğreniyor ve bulanık, karanlık ya da kopya fotoğrafları bulan bir kontrol programıyla veri setimizi temizliyoruz.

Bu derste

  • İyi bir görüntü veri setinin özelliklerini (denge, çeşitlilik, gerçek koşullar) açıklar.
  • Fotoğrafları sınıf klasörlerine numaralı olarak kaydeden bir program yazar ve kullanır.
  • Arka plan ve el gibi istenmeyen ipuçlarının modeli nasıl yanıltabileceğini açıklar.
  • Bulanık, karanlık ve kopya fotoğrafları bir Python programıyla tespit eder.
  • Veri toplarken kişisel verilerin korunmasına dikkat eder.

Malzemeler

  • Raspberry Pi 5 veya 4
  • Pi Camera Module 3 veya USB web kamerası
  • Kâğıt, plastik ve metal atık örnekleri (temiz)
  • Düz renkli bir zemin (karton) ve masa lambası
  • Thonny ve yzenv sanal ortamı

Makine öğrenmesinde sık duyulan bir söz vardır: “Çöp girerse çöp çıkar.” Modelimiz ne kadar akıllı olursa olsun, ancak ona gösterdiğimiz örnekler kadar iyi olabilir. Bu derste akıllı geri dönüşüm kutumuzun gözünü eğitecek fotoğrafları topluyoruz ve bunu doğru yapmayı öğreniyoruz.

Dersin Amacı ve Kazanımlar

Bu dersin sonunda:

  1. İyi bir görüntü veri setinin özelliklerini açıklayabileceksiniz.
  2. Fotoğrafları sınıf klasörlerine numaralı olarak kaydeden bir program kullanabileceksiniz.
  3. Arka plan ve el gibi istenmeyen ipuçlarının modeli nasıl yanıltabileceğini açıklayabileceksiniz.
  4. Bulanık, karanlık ve kopya fotoğrafları bir programla bulabileceksiniz.
  5. Veri toplarken kişisel verilerin korunmasına dikkat edeceksiniz.

Gerekli Malzemeler

Malzeme Açıklama
Raspberry Pi ve kamera Ders 3’te test ettiğimiz düzenek. Kamerayı bir tutucuya ya da kitap yığınına sabitleyin.
Atık örnekleri Her sınıftan en az 5–6 farklı nesne: gazete, karton kutu, pet şişe, yoğurt kabı, içecek kutusu, konserve kutusu. Hepsi temiz ve kuru olsun.
Zemin ve ışık Düz renkli bir karton ve masa lambası. Kutunun içinde kullanılacak ışığa benzer bir ortam hazırlayın.
Depolama Fotoğrafları bilgisayara taşımak için USB bellek (veya ağ üzerinden kopyalama)

💡 İpucu

Fotoğrafları, modelin gerçekte çalışacağı yerde ve aynı kamerayla çekin. Kutunun içinde loş bir ışık olacaksa parlak sınıf ışığında çekilmiş fotoğraflar modeli yanıltır. Kamerayı sabitleyin ve çekim süresince yerini değiştirmeyin.

Sınıflarımızı Belirleyelim

Projemizde dört sınıf olacak: kagit, plastik, metal ve bos. Neden bir “boş” sınıfı? Çünkü kamera hiçbir şey görmediğinde de model bir cevap vermek zorundadır. Boş sınıfı olmayan bir model, boş zemine bakıp “kâğıt” diyebilir. Klasör ve sınıf adlarında Türkçe karakter kullanmıyoruz; hem dosya yollarında hem de OpenCV’nin ekrana yazı yazarken sorun çıkmasın.

Görüntü veri setinin klasör yapısı

İyi Bir Veri Setinin Kuralları

  1. Denge: Her sınıfta yaklaşık aynı sayıda fotoğraf olsun. Başlangıç için sınıf başına 80–150 fotoğraf yeterlidir. Bir sınıf çok kalabalıksa model şüphede kaldığında hep onu söylemeye başlar.
  2. Çeşitlilik: Aynı pet şişenin 100 fotoğrafı yerine 6–8 farklı plastik nesnenin farklı açılardan, uzaklıklardan ve yönlerden fotoğrafları daha değerlidir. Ezilmiş, etiketi yırtılmış, ters duran nesneleri de ekleyin.
  3. Gerçek koşullar: Işık, zemin ve kamera açısı kutunun içindeki düzenle aynı olsun.
  4. Tek ipucu nesnenin kendisi olsun: Bütün metal fotoğraflarını siyah zeminde, kâğıtları beyaz zeminde çekerseniz model atığı değil zemini öğrenir. Benzer şekilde nesneleri elinizle tutuyorsanız elinizi her sınıfta gösterin; yoksa model “el varsa plastik” gibi yanlış bir kural çıkarabilir.
  5. Test için ayırın: Her sınıftan bir iki nesneyi hiç fotoğraflamayın ve kenara koyun. Projenin sonunda modeli bu “hiç görmediği” nesnelerle test edeceğiz.
  6. Gizlilik: Fotoğraflarda yüz, isim, okul numarası gibi kişisel bilgiler olmasın. Bir arkadaşınız görünecekse önce izin alın.

Veri toplama için çekim düzeneği

Fotoğrafları Otomatik Toplayan Program

Yüzlerce fotoğrafı tek tek çekip adlandırmak çok zaman alır. Aşağıdaki program sınıf adını, fotoğraf sayısını ve çekim aralığını sorar; sonra fotoğrafları veri/sinif_adi/ klasörüne sırayla numaralayarak kaydeder. Siz de bu sırada nesneyi döndürür, yerini değiştirir ya da yeni bir nesne koyarsınız.

# dosya: veri_topla.py  (Pi kamera ile sınıf klasörlerine fotoğraf kaydeder)
from picamera2 import Picamera2
import cv2
import os
import time

KLASOR = "veri"

picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(
    main={"size": (640, 480), "format": "RGB888"}))
picam2.start(show_preview=True)       # masaüstünde önizleme penceresi açar
time.sleep(2)

sinif = input("Sınıf adı (kagit, plastik, metal, bos): ").strip().lower()
adet = int(input("Kaç fotoğraf çekilsin? "))
aralik = float(input("Kaç saniyede bir? (ör. 0.5): "))

hedef = os.path.join(KLASOR, sinif)
os.makedirs(hedef, exist_ok=True)
mevcut = len([f for f in os.listdir(hedef) if f.endswith(".jpg")])

print("3 saniye sonra başlıyor. Nesneyi her fotoğrafta biraz döndürün!")
time.sleep(3)
for i in range(adet):
    kare = picam2.capture_array()
    kare = kare[:, 80:560]            # ortadan 480x480 kare kırp
    dosya = os.path.join(hedef, f"{sinif}_{mevcut + i + 1:03d}.jpg")
    cv2.imwrite(dosya, kare)
    print(f"[{i + 1}/{adet}] {dosya}")
    time.sleep(aralik)

picam2.stop()
print("Bitti! Bu sınıftaki toplam fotoğraf:", mevcut + adet)

Örnek çıktı: (Raspberry Pi 5 üzerinde örnek çalıştırma; kullanıcının yazdığı değerler de görünüyor. Uzun liste “...” ile kısaltıldı.)

Sınıf adı (kagit, plastik, metal, bos): plastik
Kaç fotoğraf çekilsin? 40
Kaç saniyede bir? (ör. 0.5): 0.5
3 saniye sonra başlıyor. Nesneyi her fotoğrafta biraz döndürün!
[1/40] veri/plastik/plastik_001.jpg
[2/40] veri/plastik/plastik_002.jpg
...
[40/40] veri/plastik/plastik_040.jpg
Bitti! Bu sınıftaki toplam fotoğraf: 40

Programın birkaç akıllı ayrıntısı var:

  • os.makedirs(..., exist_ok=True) klasör yoksa oluşturur, varsa hata vermez.
  • mevcut değişkeni klasörde kaç fotoğraf olduğunu sayar. Programı aynı sınıf için ikinci kez çalıştırdığınızda eski fotoğrafların üzerine yazılmaz, numaralandırma kaldığı yerden devam eder.
  • kare[:, 80:560] 640×480’lik görüntünün ortasından 480×480’lik bir kare keser. Teachable Machine fotoğrafları kare biçimde kullanır; baştan kare kaydedersek kenardaki nesnelerin kesilmesini önleriz.
  • f"{sayi:03d}" sayıyı üç basamaklı yazar: 7 yerine 007. Böylece dosyalar sıralandığında karışmaz.

USB web kamerası kullanıyorsanız picamera2 satırlarının yerine Ders 3’teki cv2.VideoCapture satırlarını, capture_array() yerine kamera.read() komutunu kullanın.

Veri Setini Kontrol Etme

Yüzlerce fotoğraf arasında bulanık, karanlık ya da yanlışlıkla iki kez kaydedilmiş olanları gözle bulmak zordur. Bu işi de Python’a yaptıralım. Önce kameranız yoksa da deneyebilmeniz için, içine bilerek birkaç kötü fotoğraf koyduğumuz yapay bir veri seti üretelim:

# dosya: deneme_veri_seti.py
# Kameranız yoksa kontrol programını denemek için yapay bir veri seti üretir.
# İçine bilerek birkaç kötü fotoğraf koyuyoruz.
import cv2
import numpy as np
import os
import shutil

rng = np.random.default_rng(7)
renkler = {"kagit": (200, 160, 40), "plastik": (40, 200, 230),
           "metal": (150, 150, 150), "bos": None}
adetler = {"kagit": 30, "plastik": 30, "metal": 18, "bos": 30}

for sinif, renk in renkler.items():
    os.makedirs(f"veri/{sinif}", exist_ok=True)
    for i in range(1, adetler[sinif] + 1):
        img = rng.integers(170, 230, (240, 240, 3), dtype=np.uint8)  # dokulu zemin
        if renk:
            x, y = rng.integers(40, 120, 2)
            cv2.rectangle(img, (int(x), int(y)), (int(x) + 90, int(y) + 70), renk, -1)
            cv2.putText(img, sinif[:2].upper(), (int(x) + 10, int(y) + 50),
                        cv2.FONT_HERSHEY_SIMPLEX, 1.2, (20, 20, 20), 3)
        if sinif == "kagit" and i in (5, 17):
            img = cv2.GaussianBlur(img, (31, 31), 0)       # bulanık
        if sinif == "plastik" and i == 9:
            img = (img * 0.2).astype(np.uint8)            # karanlık
        cv2.imwrite(f"veri/{sinif}/{sinif}_{i:03d}.jpg", img)

shutil.copy("veri/metal/metal_003.jpg", "veri/metal/metal_019.jpg")  # kopya
print("Deneme veri seti hazır.")

Beklenen çıktı:

Deneme veri seti hazır.

Şimdi kontrol programı. Kendi veri setinizde de aynen çalışır:

# dosya: veri_kontrol.py  (veri setindeki sorunlu fotoğrafları bulur)
import cv2
import os
import hashlib

KLASOR = "veri"
BULANIK_ESIK = 100    # netlik bunun altındaysa bulanık say
KARANLIK_ESIK = 60    # ortalama parlaklık bunun altındaysa karanlık say

sayilar = {}
gorulenler = {}

for sinif in sorted(os.listdir(KLASOR)):
    yol = os.path.join(KLASOR, sinif)
    if not os.path.isdir(yol):
        continue
    dosyalar = sorted(f for f in os.listdir(yol) if f.lower().endswith((".jpg", ".png")))
    sayilar[sinif] = len(dosyalar)
    for ad in dosyalar:
        tam = os.path.join(yol, ad)
        img = cv2.imread(tam)
        if img is None:
            print("Okunamadı:", tam)
            continue
        gri = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        netlik = cv2.Laplacian(gri, cv2.CV_64F).var()
        parlaklik = gri.mean()
        ozet = hashlib.md5(open(tam, "rb").read()).hexdigest()

        if netlik < BULANIK_ESIK:
            print(f"Bulanık olabilir: {tam} (netlik {netlik:.0f})")
        if parlaklik < KARANLIK_ESIK:
            print(f"Karanlık: {tam} (parlaklık {parlaklik:.0f})")
        if ozet in gorulenler:
            print(f"Kopya: {tam} = {gorulenler[ozet]}")
        else:
            gorulenler[ozet] = tam

print()
print("Sınıf başına fotoğraf sayısı:")
en_cok = max(sayilar.values())
for sinif, n in sayilar.items():
    uyari = "  <- az! Diğer sınıflarla dengeleyin." if n < en_cok * 0.7 else ""
    print(f"  {sinif:<8}{n:>4}{uyari}")

Beklenen çıktı:

Bulanık olabilir: veri/kagit/kagit_005.jpg (netlik 1)
Bulanık olabilir: veri/kagit/kagit_017.jpg (netlik 1)
Kopya: veri/metal/metal_019.jpg = veri/metal/metal_003.jpg
Karanlık: veri/plastik/plastik_009.jpg (parlaklık 39)

Sınıf başına fotoğraf sayısı:
  bos       30
  kagit     30
  metal     19  <- az! Diğer sınıflarla dengeleyin.
  plastik   30

Program bulanıklığı Laplace varyansı ile ölçer. Net bir fotoğrafta kenarlar keskindir ve bu değer yüksek çıkar; bulanık fotoğrafta kenarlar yumuşadığı için değer düşer. Parlaklık, gri tonlu görüntünün ortalamasıdır. Kopyaları bulmak için her dosyanın içeriğinden bir “parmak izi” (MD5 özeti) hesaplanır; iki dosyanın parmak izi aynıysa içerikleri de aynıdır. Programın bulduğu her sorunu yukarıdaki çıktıda görebilirsiniz: iki bulanık kâğıt, bir karanlık plastik, bir kopya metal fotoğrafı ve sayısı az kalan metal sınıfı.

Kontrol programının yakaladığı iyi ve kötü örnekler

Eşik değerleri (100 ve 60) her kamera ve ortam için biraz farklıdır. Kendi veri setinizde önce birkaç net ve birkaç bulanık fotoğrafın değerine bakın, eşikleri buna göre ayarlayın. Bulunan fotoğrafları silmeden önce mutlaka açıp kendiniz de bakın.

⚠️ Önemli Not

Veri setinizi farklı bir klasöre yedeklemeden hiçbir fotoğrafı silmeyin. Bir de şuna dikkat edin: Bütün fotoğrafları birkaç saniyede, nesneye hiç dokunmadan çekerseniz birbirinin neredeyse aynısı olan 100 fotoğraf elde edersiniz. Bu, modelin işine 100 değil, birkaç fotoğraf kadar yarar. Çekim aralığını kısa tutacaksanız nesneyi sürekli hareket ettirin.

Sıra Sizde

  1. Kolay: Dört sınıfın her biri için en az 80 fotoğraf toplayın ve veri_kontrol.py ile kontrol edin. Sonuçları defterinize yazın.
  2. Orta: veri_kontrol.py programına, her sınıfın ortalama parlaklığını yazdıran bir bölüm ekleyin. Sınıflar arasında büyük fark varsa bu neden bir sorun olabilir?
  3. Zor: Kontrol programını, sorunlu fotoğrafları silmek yerine veri_sorunlu/ klasörüne taşıyacak şekilde geliştirin. (İpucu: shutil.move())

Kendini Dene

  1. Veri setimize neden bir “bos” sınıfı ekledik?
  2. Bütün kâğıt fotoğrafları beyaz, bütün metal fotoğrafları siyah zeminde çekilirse ne olabilir?
  3. Kontrol programı bir fotoğrafın bulanık olduğunu nasıl anlıyor?

Cevaplar

  1. Kamera hiçbir nesne görmediğinde modelin de “boş” diyebilmesi için. Bu sınıf olmasaydı model boş zemine bakıp bir atık türü söylemek zorunda kalırdı.
  2. Model atığın kendisini değil zeminin rengini öğrenebilir. Beyaz zemine konan bir metal kutuyu “kâğıt” sanabilir.
  3. Gri tonlu görüntünün Laplace varyansını hesaplıyor. Kenarları keskin olan net fotoğraflarda bu değer yüksek, bulanık fotoğraflarda düşük çıkar. Değer eşiğin altındaysa fotoğrafı bulanık sayıyor.