5.17. Standart çekirdeklerin bir kataloğu¶
Klasik görüntü işleme, defalarca karşımıza çıkan epeyce büyük bir çekirdek ağırlık deseni kataloğu biriktirmiştir – kenar bulucular, keskinleştiriciler, kabartmalar, yumuşatıcılar, hareket bulanıklıkları – ve bunların her biri morph() üzerinden çalışır. Her biri kısadır, her biri tek bir iş yapar ve ağırlıkların temel mantığı bir kez anlaşıldığında çoğunu okumak kolaydır.
Aşağıdaki çekirdekler, aksi belirtilmedikçe hepsi 3’e 3’tür, dolayısıyla hepsi çağrıda size=1 kullanır. Her çekirdeğin ağırlık yapısı yanında açıklanmıştır, çünkü ağırlıkları okumak, bir çekirdeğin neden kabartma yaptığı, bir diğerinin neden keskinleştirdiği sezgisini oluşturan şeydir.
5.17.1. Birim çekirdek¶
Mümkün olan en basit çekirdek birim çekirdektir – merkezde bir, diğer her yerde sıfır:
identity = [0, 0, 0,
0, 1, 0,
0, 0, 0]
img.morph(1, identity)
Her çıktı pikseli, değerini komşuluğun merkezinden, yani aynı konumdaki giriş pikselinden alır. Görüntü değişmeden geçer. Birim çekirdeğin bir filtre olarak pratik bir kullanımı yoktur, ancak diğer her çekirdeği anlamak için yararlı bir temeldir: birim olmayan herhangi bir çekirdek, birim çekirdek artı bir miktar değişikliktir.
Merkez ağırlığı büyük, etrafında küçük negatif ağırlıklar bulunan bir çekirdek, çevreyi merkezden çıkarır. Merkez ağırlığı sıfır olan bir çekirdek, pikselin kendisini yok sayar ve yalnızca komşuları arasındaki farklara tepki verir. Bir çekirdeği bu şekilde okumak – merkez ağırlığının piksele ne yaptığı, çevredeki ağırlıkların neyi eklediği veya çıkardığı – etkisini tahmin etmenin en hızlı yoludur.
5.17.2. Kenar tespiti¶
Kenar tespit çekirdekleri, parlaklığın belirli bir yönde hızla değiştiği konumlara güçlü tepki verir ve parlaklığın tekdüze olduğu yerlerde sıfıra yakın çıktı üretir. Ağırlıkları sıfıra toplanan ailedir: düz bir alan (her pikselin aynı değerde olduğu) sıfır çıktı üretir, çünkü her pozitif ağırlık tam olarak eşit büyüklükteki bir negatif ağırlık tarafından iptal edilir.
Sobel-x en tipik örnektir. Dikey kenarları (sol/sağ parlaklık geçişlerini) tespit eder:
sobel_x = [-1, 0, 1,
-2, 0, 2,
-1, 0, 1]
img.morph(1, sobel_x, mul=0.25, add=128)
Eşleşen Sobel-y, 90 derece döndürülmüş aynı desendir; yatay kenarları (yukarı/aşağı parlaklık geçişlerini) tespit eder:
sobel_y = [-1, -2, -1,
0, 0, 0,
1, 2, 1]
Sobel-x’in orta satırı, -1 ve 1 yerine -2 ve 2 ağırlıklarına sahiptir. Merkez satırdaki ekstra ağırlık, çekirdeğe kenar boyunca yönde küçük bir yerleşik yumuşatma kazandırır; bu da onu, bu ekstra büyüklükleri kullanmayan daha basit Prewitt operatörüne göre gürültüye karşı daha dayanıklı kılar:
prewitt_x = [-1, 0, 1,
-1, 0, 1,
-1, 0, 1]
prewitt_y = [-1, -1, -1,
0, 0, 0,
1, 1, 1]
Prewitt her satırı eşit ağırlıklandırır, dolayısıyla tepkisi Sobel’inkinden biraz daha keskindir; ancak bunun bedeli, tek piksellik gürültüye daha duyarlı olmaktır (çekirdeği çalıştırmanın maliyeti aynıdır – evrişim, ağırlıklar ne olursa olsun aynı işi yapar). Güçlü kenarlara sahip temiz bir görüntüde, Sobel için gayet kullanışlı bir ikamedir.
Scharr ters yöne gider. Ağırlıkları daha büyüktür ve daha ince açılarda kenar yönünün doğru tespiti için ayarlanmıştır:
scharr_x = [-3, 0, 3,
-10, 0, 10,
-3, 0, 3]
img.morph(1, scharr_x, mul=0.0625, add=128)
mul=0.0625 böleni (1/16), daha büyük çarpımlar toplamından sonra çıktıyı yeniden 0 – 255 aralığına getirir. Scharr, uygulamanın geometrik olarak en sadık gradyan tepkisine ihtiyaç duyduğu ve bunun için biraz daha fazla aritmetiğe katlanmaya razı olduğu durumlarda doğru yanıttır.
5.17.3. Laplacian¶
Bir Laplacian çekirdeği, herhangi bir yöndeki kenarlara aynı anda tepki verir. Sobel çekirdeklerinin her biri parlaklık değişimlerini tek bir eksen boyunca tespit ederken, Laplacian’ın simetrik ağırlık deseni, kenarın hangi yöne gittiğine bakılmaksızın aynı şekilde tepki verir:
laplacian_4 = [ 0, -1, 0,
-1, 4, -1,
0, -1, 0]
img.morph(1, laplacian_4, add=128)
Yapısı: merkez ağırlığı 4, dört yatay/dikey komşu -1 ağırlıklı, dört köşegen ise sıfır ağırlıklı. Çekirdek sıfıra toplanır, dolayısıyla düz alanlar sıfır çıktı üretir. Parlaklığın değiştiği yerlerde, merkez değeri dört ana yön komşusunun ortalamasından farklıdır ve çıktı, bu farkın büyüklüğüdür.
8-bağlantılı varyant, köşegen komşuları da içerir:
laplacian_8 = [-1, -1, -1,
-1, 8, -1,
-1, -1, -1]
Her çekirdek biraz farklı şeyler tespit eder. 4-bağlantılı sürüm, yatay ve dikey kenarlarda daha temiz çıktı üretir; 8-bağlantılı olan ise daha yönden bağımsızdır – her yönde eşit derecede iyi tepki verir – ancak biraz daha gürültülü çıktı üretir. 8-bağlantılı çekirdek, kenarları görselleştirmek için kullanılması nedeniyle outline (anahat) adıyla da dolaşımdadır.
5.17.5. Kabartma¶
Bir kabartma (emboss) çekirdeği, klasik görüntü düzenleyicilerde bulunan yandan aydınlatılmış efektini üretir. Çıktı, görüntü bir kabartmaya dönüştürülmüş ve ardından bir köşeden aydınlatılmış gibi görünür:
emboss = [-2, -1, 0,
-1, 1, 1,
0, 1, 2]
img.morph(1, emboss, add=128)
Püf noktası, köşegen boyunca asimetridir. Sol üst köşe en negatif ağırlığa, sağ alt köşe en pozitif ağırlığa sahiptir ve köşeden köşeye olan köşegen, negatiften bir üzerinden pozitife doğru ilerler. Her pikselde çekirdek esasen “sağ alt tarafımdaki parlaklık eksi sol üst tarafımdaki parlaklık” hesaplar; bu da görüntünün o yönde aydınlandığı yerlerde pozitif, karardığı yerlerde negatiftir. 128 eklemek, işaretli çıktıyı orta griye yeniden ortalar, böylece efekt görünür olur.
Asimetriyi diğer köşegen boyunca döndürmek, ters yönden kabartma yapar:
emboss_alt = [ 0, 1, 2,
-1, 1, 1,
-2, -1, 0]
img.morph(1, emboss_alt, add=128)
İki kabartma yönü birlikte kullanıldığında yararlıdır – birini diğerinden çıkararak veya her birini aynı görüntü üzerinde çalıştırıp tepkileri karşılaştırarak – bir uygulamanın yönelim tespit etmesi gerektiğinde.
5.17.6. Yumuşatma¶
Yumuşatma çekirdekleri, ağırlıkları bire toplanan (ve hepsi negatif olmayan) ailedir. Böyle bir çekirdekten geçen düz bir alan, aynı düz parlaklığı üretir, çünkü çekirdek piksel değerlerinin farklarını güçlendirmek yerine onları birlikte ortalar.
En basiti, tam olarak mean() metodunun hesapladığı şey olan kutu bulanıklığıdır (box blur):
box_blur = [1, 1, 1,
1, 1, 1,
1, 1, 1]
img.morph(1, box_blur)
Çekirdek 9‘a toplanır, dolayısıyla çekirdek toplamına otomatik bölme, çarpımlar toplamını dokuz komşuluk pikseli üzerinden gerçek bir ortalamaya dönüştürür. Pratikte mean(), bu çekirdeği çalıştırmanın daha iyi yoludur – aynı çıktıyı, yalnızca ortalamayı hesaplamak için optimize edilmiş bir yol üzerinden daha hızlı üretir; oysa morph genel evrişim makinesini çalıştırır. Kutu bulanıklığı kataloğa dahildir çünkü diğer her yumuşatma çekirdeğini anlamak için doğru temeldir.
Gaussian ağırlıklarının 3’e 3’lük bir yaklaşımı, merkezi ve ana yön komşularını köşelerden daha fazla ağırlıklandırır:
gaussian = [1, 2, 1,
2, 4, 2,
1, 2, 1]
img.morph(1, gaussian)
Ağırlıklar, kendisiyle dış çarpımı alınmış 1, 2, 1 Pascal üçgeni satırıdır. Merkez ağırlığı 4 en büyüğüdür çünkü merkez piksel kendi çıktısına en çok katkıyı yapar; köşeler 1‘dir çünkü merkezden en uzak olanlardır. Çekirdek 16‘ya toplanır ve çekirdek toplamına otomatik bölme normalleştirmeyi halleder – mul argümanına gerek yoktur. 3’e 3 form, gerçek bir Gaussian’ın kaba bir yaklaşımıdır ve size=1‘de gaussian() ile ayırt edilemez; morph formu çoğunlukla bir uygulamanın yumuşatmayı aynı geçişte başka bir işlemle birleştirmek istediğinde yararlıdır.
5.17.7. Hareket bulanıklığı¶
Bir hareket bulanıklığı (motion-blur) çekirdeği, pikselleri tek bir yön boyunca ortalar ve dik yönü bulanıklaştırmadan bırakır. En basit durum yataydır:
motion_h = [0, 0, 0,
1, 1, 1,
0, 0, 0]
img.morph(1, motion_h)
Orta satır, yatay eksen boyunca üç pikseli ortalar; üst ve alt satırlar sıfırdır. Çekirdek 3‘e toplanır, dolayısıyla çekirdek toplamına otomatik bölme, herhangi bir mul gerekmeden gerçek bir üç piksellik ortalama üretir. Çıktı, girişin yatay olarak yayılmış bir kopyasıdır – bir kameranın, özne pozlama sırasında yana doğru hareket ederken yakaladığı efekt. Dikey hareket bulanıklığı, aynı desenin döndürülmüş halidir:
motion_v = [0, 1, 0,
0, 1, 0,
0, 1, 0]
Bir köşegen hareket bulanıklığı, ana köşegeni kullanır:
motion_diag = [1, 0, 0,
0, 1, 0,
0, 0, 1]
img.morph(1, motion_diag)
Hareket bulanıklığı çekirdekleri hem bir efekt olarak (görsel amaçlarla bir çerçeveyi kasıtlı olarak bulanıklaştırmak) hem de hareket bozulmalarına karşı dayanıklı olması gereken algoritmalar için bir test deseni olarak yararlıdır (algoritmayı hareketle bulanıklaştırılmış bir girişte çalıştırın ve hâlâ doğru yanıtı ürettiğini kontrol edin).
5.17.8. Çekirdekleri bir bakışta okumak¶
Birkaç pratik kural, yeni çekirdekleri ilk bakışta okumayı kolaylaştırır:
Negatif olmayan ağırlıklarla bire toplanma ⇒ yumuşatma (ortalama parlaklığı korur).
Hem pozitif hem negatif ağırlıklarla sıfıra toplanma ⇒ kenar tepkisi (düz alanlarda sıfır).
Büyük bir pozitif merkez ve küçük negatif çevrelerle bire toplanma ⇒ keskinleştirme (birim çekirdek artı kenar tepkisi).
Bire toplanmayla bir köşegen boyunca asimetrik ⇒ kabartma (her parlaklık geçişinin bir tarafını vurgular).
Bire toplanmayla tek bir eksen boyunca yoğunlaşmış ⇒ yönlü bulanıklık.
Çekirdeğin eşleştiği bunlardan ilki, genellikle ne yaptığına dair doğru tahmindir. En yararlı çekirdekler, yalnızca ağırlık desenlerinin düzeninden tanınabilir.
Standart çekirdeklerin hiçbiri uygulamanın istediği şeyi yapmadığında, sonraki adım bir tanesini elle ayarlamaktır. Yukarıdaki kuralların mul / add denetimleriyle birleşimi, klasik bir makine görüşü hattının şimdiye kadar istediği hemen hemen her doğrusal geçişi kapsar; oradan sonrası, ağırlıkları denemek, çıktıya bakmak ve yinelemek meselesidir.