4. ünite / 12
Evrişim ve filtreler: bulanıklaştırma, keskinleştirme, gürültü
Çekirdek, kenar koşulu, kutu ve Gauss bulanıklığı, medyan filtre, keskinleştirme; PSNR ile ölçüm.
Bu ünitenin sonunda
- 3×3 bir evrişimi elle hesaplamak
- Kutu, Gauss ve medyan filtrelerini gürültü türüne göre seçmek
- Keskinleştirme çekirdeğinin neden toplamı 1 olan bir çekirdek olduğunu açıklamak
- Filtre sonucunu PSNR ile sayısal olarak karşılaştırmak
Ders notları
Komşuluk işlemlerinde yeni değer, pikselin çevresine de bakar. Bunun en genel biçimi evrişimdir: küçük bir ağırlık tablosu (çekirdek) görüntü üstünde kayar, her konumda ağırlıklı toplam alınır.
OpenCV'nin filter2D'si çekirdeği çevirmez (matematikte buna korelasyon denir); simetrik çekirdeklerde fark yoktur. Görüntünün kenarında komşu eksik kalır: OpenCV varsayılan olarak BORDER_REFLECT_101 ile yansıtır.
Bulanıklaştırma ailesi
- Kutu: tüm ağırlıklar eşit (1/9). Hızlı ama kenarları kare biçimli yayar.
- Gauss: ağırlıklar merkezden uzaklaştıkça azalır; ayrılabilir olduğundan iki 1B geçişle yapılır. Gauss gürültüsü için iyidir.
- Medyan: doğrusal değildir, komşuların ortancasını alır. Tuz-biber gürültüsünü siler, kenarları korur.
Keskinleştirme
[0 −1 0; −1 5 −1; 0 −1 0] çekirdeği "orijinal + (orijinal − komşu ortalaması)" demektir. Ağırlıkların toplamı 1 olduğu için düz bölgeler değişmez, ayrıntı güçlenir; gürültü de güçlenir. Ölçmek için PSNR (tepe sinyal/gürültü oranı, dB) kullanılır: temiz görüntüye ne kadar yakın, o kadar yüksek.
Oyun alanı
Evrişim ve filtreler
Bir çekirdek görüntü üstünde kayar, her konumda ağırlıklı toplam alır. Gürültü ekle (tuz-biber ya da Gauss) ve kutu, Gauss, medyan ve keskinleştirme filtrelerini karşılaştır. Çekirdeğin sayıları sağda.
Kendin dene
Renkli şekillere %8 tuz-biber gürültüsü ekle. Kutu, Gauss ve medyanı 3 ve 5 boyutlarıyla dene ve PSNR'leri bir tabloya yaz. Hangisi kazandı, neden? Sonra gürültüyü Gauss'a çevir ve tabloyu tekrarla. Son olarak gürültüsüz görüntüde keskinleştirmeyi aç ve çekirdekteki sayıları toplayarak düz bölgelerin neden değişmediğini doğrula.
Kod
import cv2
import numpy as np
img = cv2.imread('girdi.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY).astype(np.float32)
k = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) # keskinleştirme
def conv3(f, k):
p = np.pad(f, 1, mode='reflect') # kenarlar: yansıtma
out = np.zeros_like(f)
for dy in range(3):
for dx in range(3): # 9 kaydırılmış kopyanın ağırlıklı toplamı
out += k[dy, dx] * p[dy: dy + f.shape[0], dx: dx + f.shape[1]]
return out
mine = conv3(gray, k)
ref = cv2.filter2D(gray, -1, k, borderType=cv2.BORDER_REFLECT_101)
print('en büyük fark:', float(np.abs(mine[1:-1, 1:-1] - ref[1:-1, 1:-1]).max()))
cv2.imwrite('cikti.png', np.clip(ref, 0, 255).astype(np.uint8)) # float sonucu uint8 aralığına kırpimport cv2
import numpy as np
img = cv2.imread('girdi.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
rng = np.random.default_rng(0)
noisy = gray.copy()
m = rng.random(gray.shape)
noisy[m < 0.03] = 0 # %3 biber
noisy[m > 0.97] = 255 # %3 tuz
out = {
'box': cv2.blur(noisy, (5, 5)),
'gauss': cv2.GaussianBlur(noisy, (5, 5), 1.2),
'median': cv2.medianBlur(noisy, 5), # tuz-biberde açık ara en iyisi
'sharp': cv2.filter2D(noisy, -1, np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])),
}
for name, f in out.items():
print(f'{name:6s} PSNR = {cv2.PSNR(gray, f):5.1f} dB') # yüksek PSNR: aslına daha yakın
cv2.imwrite('cikti.png', np.hstack([noisy, out['gauss'], out['median']]))Sık yapılan hatalar
- Çekirdek ağırlıklarını normalleştirmemek: toplamı 9 olan bir kutu filtresi görüntüyü dokuz kat parlatır ve doyurur.
- Keskinleştirme sonucunu uint8'de hesaplamak: negatif değerler kaybolur; önce float, sonra kırp.
- Tuz-biber gürültüsünü Gauss ile temizlemeye çalışmak: noktalar yalnız yayılır, medyan gerekir.
- Büyük çekirdeği her karede çalıştırmak: 15×15 kutu filtresi integral görüntüyle ya da ayrılabilir geçişlerle çok daha hızlıdır.
Yazılım mühendisliği bağlantısı
Evrişimin elle yazılmış hâli ile kütüphane hâlini karşılaştırmak (yukarıdaki kodda olduğu gibi) bir referans uygulama testidir: yavaş ama açık kod, hızlı ama karmaşık kodu doğrular.
- Kenar piksellerini ayrı test et; hataların çoğu kenar koşulundadır.
- Performans için önce ölç (cv2.getTickCount ya da time.perf_counter), sonra optimize et.
Kendini sına
[1 2 1; 2 4 2; 1 2 1] / 16 çekirdeği, ortası 160, diğer sekiz komşusu 0 olan bir 3×3 bölgede merkezde ne verir?
Tuz-biber gürültüsü için en uygun filtre hangisidir?
Keskinleştirme çekirdeğinin ağırlıkları toplamı neden 1'dir?
Gauss filtresinin iki 1B geçişle yapılabilmesinin adı nedir?
