5.3. Piksel formatları¶
Kenarları tespit eden bir algoritma her pikselin bir parlaklık değeri tutmasını bekler. Renkli bir nesneyi izleyen bir algoritma her pikselin renk taşımasını bekler. Morfolojik kapama yapan bir algoritma her pikselin ya açık ya da kapalı olmasını bekler. Bir Image nesnesinin taşıdığı piksel formatı – katalogdaki Vision Sensors’ta sıralananlardan biri – bu beklentileri önceden denetlenebilir kılan şeydir: format, piksellerin hangi biçimde olduğunu ve dolayısıyla hangi algoritmaların bir dönüştürme adımı olmadan onlar üzerinde çalışabileceğini önceden söyler.
Bu sayfa, bu kısıtlamanın pratikte nasıl işlediğiyle ilgilidir. Doğru formatın hangisi olduğu, işlem hattının ne yapacağına bağlıdır; formatlar arasındaki dönüştürme yöntemleri ise birden fazlasına ihtiyaç duyan bir işlem hattının aşamaları birbirine bağlamasının yoludur.
Beş sıkıştırılmamış piksel formatı ve baytlarının nasıl paketlendiği. JPEG ve PNG burada çizilmemiştir, çünkü bunlar sabit boyutlu piksel ızgaraları yerine değişken uzunlukta sıkıştırılmış akışlardır.¶
5.3.1. Gri tonlamanın yük beygiri¶
Klasik makine görüşünün çoğu, parlaklık değerleriyle çalışmaya indirgenir. Kenar tespiti, şablon eşleştirme, AprilTag çözme, optik akış kestirimi, morfolojik işleçler, nokta (blob) analizi – bunların tümü, algoritmaların işlediği düzeyde, her pikselin ne kadar parlak olduğuna ve parlaklığın yakındaki piksellerin parlaklığıyla nasıl karşılaştırıldığına bakar. Sahnenin rengi, onları çağıran uygulama için çoğu zaman yararlıdır, ama algoritmaların kendisi buna ihtiyaç duymaz.
Gri tonlama formatı algoritmalara tam olarak bunu, hiçbir ek yük olmadan verir. Piksel başına bir bayt, 0 (siyah) ile 255 (beyaz) arasında bir parlaklık değeri tutar. Format, RGB565 ve YUV422’nin yarısı, RGB888’in ise üçte biri boyutundadır; dolayısıyla her işlem daha az veri üzerinden geçer – hem daha hızlı hem de daha az arabellek baskısıyla. Çerçeve arabelleğinin (frame buffer) betiğin geri kalanıyla RAM için yarıştığı küçük kameralarda, bu yer kaplama farkı bir işlem hattının hiç sığıp sığmayacağını belirleyen şey olabilir. Renk, algoritmanın ihtiyaç duyduğu ipucu değilse, gri tonlama doğru yanıttır.
5.3.2. RGB565 ile renk¶
Renk gerçekten ipucu olduğunda – renkli bir işareti izlemek, kırmızı elmaları yeşillerden ayırmak, bir kullanıcı arabirimi öğesini tonuyla seçmek – piksel başına iki bayt, algoritmaların gerçekleştirdiği sınıflandırma türleri için yeterli renk sağlar. RGB565, kameradaki varsayılan renk formatıdır ve yüzeydeki renk farkında yöntemlerin beklediği formattır.
Açıklama eklenmiş bir çerçeve oluşturma – tespit kutuları çizme, tanılama metni yazma, çerçeveyi bir ekrana ya da uzak bir görüntüleyiciye gönderme – de doğal olarak RGB565 gerektirir. IDE önizlemesi, yerleşik ekran denetleyicileri ve çoğu ağ hedefi bu formatı ya doğrudan tüketir ya da ondan ucuza dönüştürür.
5.3.3. Depolama formatı olarak Bayer¶
Bir Bayer görüntüsü, ISP onu bitmiş bir renk gösterimine debayer etmeden önceki ham sensör çıktısıdır. Her piksel, tek bir renk kanalını tutan bir bayttır – mozaikteki o konumdaki renk filtresinin geçirdiği kanal. Bu, bir Bayer görüntüsünü gri tonlama görüntüsüyle aynı boyutta ve RGB888’in üçte biri boyutunda yapar; bu da Bayer’in gerçekten işe yaradığı şeyle örtüşür: RAM bağlayıcı kısıtlama olduğunda aynı anda çok sayıda çerçeve depolamak.
İşin püf noktası, image modülündeki algoritmaların Bayer görüntüleri üzerinde doğrudan çalışmamasıdır. Debayer işlemi olmadan hiçbir piksel kendi başına bir renk yargısında bulunmaya yetecek bilgi taşımaz ve algoritmaların aradığı örüntüler – kenarlar, köşeler, noktalar (blob) – mozaik tarafından bozulurdu. Bir Bayer görüntüsünü okumanın ya da değiştirmenin tek yolları get_pixel() ve set_pixel() yöntemleridir; geri kalan her şey bitmiş bir gösterim bekler.
Ortaya çıkan örüntü, çerçeveleri bir kuyrukta beklemeleri gereken süre boyunca Bayer olarak depolamak ve her birini işlenmesi fiilen başladığı anda gri tonlamaya ya da RGB565’e dönüştürmektir. Dönüştürme CPU döngülerine mal olur ama aksi takdirde bitmiş çerçeveleri uygulamanın ömrü boyunca tutmak için bağlı kalacak RAM’i tasarruf eder.
Not
image modülünün Bayer pikselleri üzerindeki tek doğrudan işlemleri get_pixel(), set_pixel() ve IDE önizlemesini ya da bir uzak görüntüleyiciyi besleyen JPEG kodlama yoludur. Çizim, analiz ve filtreleme işlemlerinin tümü önce gri tonlamaya, RGB565’e ya da binary’ye dönüştürmeyi gerektirir.
5.3.4. Her ikisini de isteyen işlem hatları için YUV422¶
YUV422, her pikselin bilgisini bir parlaklık (luminans) kanalına (Y) ve iki renklilik (krominans) kanalına (U ve V) ayırır ve krominansı alt örnekleyerek bitişik piksel çiftlerinin tek bir U ve tek bir V paylaşmasını sağlar. Piksel başına bayt ortalaması ikiye çıkar – RGB565 ile aynı – ama bunlar öyle düzenlenir ki Y kanalı, arabellekte bilinen ofsetlerde duran, halihazırda sürekli bir 8 bitlik gri tonlama görüntüsüdür.
Bu düzen, bir işlem hattının bazı aşamaları gri tonlama işi, bazıları ise renk gerektirdiğinde tam olarak istediği şeydir. Gri tonlama aşamaları için Y değerlerini doğrudan okumak, açık bir dönüştürme maliyetini atlar; U ve V kanalları ise sonraki bir aşama gerçekten renge ihtiyaç duyduğunda oradadır. Bu özel örüntünün dışında, RGB565 genellikle renk için daha basit seçenek, gri tonlama ise yalnızca parlaklık işi için daha basit seçenektir – YUV422’nin değeri, her ikisinde de aynı anda iyi olmasından gelir.
Not
image modülü YUV422 üzerinde gri tonlama, RGB565 ya da binary’den daha sınırlı bir şekilde çalışır – gri tonlama işi için doğrudan Y kanalı okumaları ve IDE önizlemesini ya da bir uzak görüntüleyiciyi besleyen JPEG kodlama yolu. Renk farkında yöntemler RGB565 bekler; YUV422 çerçeveleri renk analizinden ya da çizimden önce açık bir dönüştürmeye ihtiyaç duyar.
5.3.5. Binary, maskeler ve eşiklenmiş çıktı¶
Bir binary görüntü, piksel başına bir bittir: her piksel ya 0 ya da 1 olur. Bu format nadiren bir sensör yakalaması olarak görünür; bunun yerine eşiklemenin doğal çıktısı olarak (burada bir renk ya da parlaklık testi her pikseli “evet, eşleşiyor” ya da “hayır, eşleşmiyor” olarak sınıflandırır) ve morfolojik işlemlerin ve birçok yöntemin kabul ettiği mask argümanının doğal girdisi olarak ortaya çıkar.
Formatın pratik avantajı boyutudur. Bir binary görüntü, bir gri tonlama görüntüsünün yer kaplamasının sekizde biridir; dolayısıyla büyük bir maskeyi etrafta taşımak – bir aşağı akış işleminin hangi konumlara dokunması gerektiğine dair piksel başına bir seçim – ucuzdur. Birçok işlemin bir binary görüntüyü mask= anahtar sözcük argümanı olarak kabul etmesi, aynı noktanın diğer yüzüdür: format küçüktür ve bir aşamanın binary çıktısını başka bir aşamanın maske girdisine zincirlemek yaygın bir işlem hattı örüntüsüdür.
5.3.6. Sınırda JPEG ve PNG¶
JPEG ve PNG Image nesneleri katalogdaki diğerlerinden farklıdır. Bunlar piksel ızgaraları değildir; piksel verilerini, piksel düzeyindeki işlemlerin okuyamayacağı bir biçimde kodlayan sıkıştırılmış bayt akışlarıdır. Bir JPEG üzerinde get_pixel() çağırmak, bir konumdaki pikseli döndürmez; piksel, yöntemin getirebileceği şekilde arabellekte herhangi bir yerde açılmış olarak durmaz.
JPEG ve PNG, piksel verilerinin kameradan sıkıştırılmış biçimde çıktığı ya da girdiği yer olan görüntü işlemenin sınırında ortaya çıkar. Bir çerçeveyi JPEG olarak diske kaydetmek dosyayı küçük tutar; bir çerçeveyi JPEG olarak ağ üzerinden göndermek iletimi ucuz tutar; bir referans çerçevesini bir JPEG dosyasından yüklemek, onun diskte ham piksellerin olacağından çok daha küçük bir biçimde durmasını sağlar. Bu kullanım durumlarının herhangi biri için sıkıştırılmış gösterim doğru yanıttır. Ancak bir JPEG üzerinde gerçek bir işlem yapmak için uygulama önce onu çalışılabilir bir formata dönüştürür – ve bu dönüştürme, sıkıştırılmış baytların piksellere açıldığı ve arabellek şişmesinin (30 KB’lik bir JPEG, 600 KB’lik RGB565 olabilir) fiilen gerçekleştiği yerdir.
5.3.7. Formatlar arası dönüştürme¶
Dönüştürme yolu, farklı formatları tek bir işlem hattına diken şeydir. Image sınıfı üzerindeki beş yöntem, mevcut bir görüntüyü alır ve farklı bir formatta yeni bir görüntü döndürür:
to_grayscale(), klasik algoritmaların istediği format olan, piksel başına tek baytlık bir görüntü üretir.to_rgb565(), hem renk farkında yöntemlerin hem de IDE önizlemesinin konuştuğu, piksel başına iki baytlık renk formatını üretir.to_bitmap(), morfoloji vemaskargümanlarının kabul ettiği format olan, bir bitlik bir binary görüntü üretir.to_jpeg(), kaydetmeye ya da iletime uygun, JPEG ile sıkıştırılmış bir görüntü üretir.to_png(), JPEG’in daha küçük dosyaları yerine kayıpsız kodlama tercih edildiğinde PNG ile sıkıştırılmış bir görüntü üretir.
Her dönüştürme varsayılan olarak yerinde çalışır: kaynak görüntünün arabelleği dönüştürülmüş sonuçla üzerine yazılır ve kaynağın orijinal pikselleri çağrı döndükten sonra kaybolur. Bu, hem CPU hem de bellek için en ucuz seçenektir ve kaynak çerçeveye başka hiçbir şey için ihtiyaç duyulmayacağında doğru yanıttır.
Kaynağa hâlâ ihtiyaç duyulduğunda – işlem hattının sonraki bir aşamasının orijinal çerçeveyi görmesi gerektiğinde – iki anahtar sözcük argümanı yerinde varsayılanı geçersiz kılar. copy=True, dönüştürülmüş görüntü için Python yığınında (heap) ayrı bir arabellek ayırır ve kaynağı olduğu gibi bırakır. copy_to_fb=True aynı ayırmayı yapar ama bunu yığın yerine çerçeve arabelleğine (frame buffer) koyar – ki bu, dönüştürülmüş görüntünün IDE önizlemesine düşmesi gerektiğinde bir uygulamanın başvurduğu şeydir, çünkü IDE çerçeve arabelleğinden okur.
İki başka yöntem, düz bir dönüştürmeyle değil, bir palet aracılığıyla renklendirilmiş RGB565 görüntüleri üretir. to_rainbow(), her tek kanallı girdi değerini görünür spektrumdan geçen yumuşak bir gradyan boyunca bir renge eşler. to_ironbow(), her girdi değerini, siyahtan koyu kırmızılar ve turuncular boyunca beyaza giden doğrusal olmayan termal görüntüleyici paletine eşler. Her ikisi de ölçüm araçlarından çok görselleştirme araçlarıdır; amaç, ham değerleri aksi takdirde göze görünmez olan tek kanallı bir görüntüyü bir bakışta okunabilir kılmaktır.
5.3.8. Arabellek boyutu¶
Formatlar hakkında açıkça belirtmeye değer son bir ayrıntı. size() her zaman piksel sayısını değil, bayt arabelleği boyutunu raporlar. Sıkıştırılmamış formatlar için bu, doğrudan boyutlardan ve piksel başına bayttan kaynaklanır: width * height * bytes_per_pixel. JPEG ve PNG için bu, sahnenin neyi içerdiğine bağlı olarak çerçeveden çerçeveye değişen sıkıştırılmış akışın boyutudur. Bayt bütçelerinden arabellek ayıran kod ilk durum için size() kullanır; kameradan sıkıştırılmış çerçeveler akıtan kod ise akışın gerçekte kaç bayt içerdiğini bilmek için her sıkıştırmadan sonra onu okur.