5.32. Kaydetme ve sıkıştırma

Şimdiye kadarki her sayfa, kamera üzerindeki görüntülerle çalıştı: çerçeve arabelleğine (frame buffer) yakalanan ya da MicroPython yığınında ayrılan, image modülü yöntemleriyle işlenen ve IDE önizlemesinde gösterilen ya da aynı betikte sonraki bir aşamaya beslenen görüntüler. Çoğu uygulamanın bir noktada bunun tersini yapması gerekir: hâlihazırda RAM’de bulunan bir görüntüyü alıp kalıcı bir yere – SD karta, bir USB ana bilgisayarına, bir ağ üzerinden – kameradan başka bir şeyin okuyabileceği bir yere koymak.

image modülü bu iş için iki yol sunar. Kaydetme yolu görüntüyü dosya sistemindeki bir dosyaya yazar; dosya biçimi uzantıya göre seçilir ve kodlama ayrıntıları yöntem tarafından ele alınır. Biçime dönüştürme yolu ise kodlanmış bayt akışını içeren bir Image nesnesi döndürür; bu, dosya sistemine hiç dokunmadan bir akış veya ağ çağrısına aktarmaya uygundur. Her biri farklı bir uygulamaya uyar; her ikisi de altta aynı sıkıştırma motoruna dayanır.

5.32.1. Bir dosyaya kaydetme

save() görüntüyü dosya sistemindeki bir yola yazar:

img.save("/sdcard/capture.jpg")
img.save("/sdcard/capture.bmp")
img.save("/sdcard/region.jpg", roi=(40, 60, 200, 150), quality=85)

Biçim, dosya uzantısından seçilir. Beş uzantı tanınır: .bmp bir Windows bitmap yazar (kayıpsız, sıkıştırma yok, yakalanan piksellerin bire bir aynısı); .pgm bir taşınabilir gri harita (portable graymap) yazar (kayıpsız, yalnızca gri tonlama); .ppm bir taşınabilir piksel harita (portable pixmap) yazar (kayıpsız, RGB); .jpg ve .jpeg her ikisi de bir JPEG yazar (kayıplı, sıkıştırılmış). Alıcı görüntü, seçilen kap için zaten doğru renk biçiminde olmalıdır – renkli bir görüntünün .pgm olarak kaydedilmesi bir hatadır.

roi, diğer her image modülü yönteminin roi anahtar sözcüğünün yaptığı gibi, kaydetmeyi görüntünün bir alt dikdörtgeniyle sınırlar. Varsayılan, görüntünün tamamıdır. JPEG ile sıkıştırılmış bir görüntü kaydedilirken bu anahtar sözcük yok sayılır; çünkü diskteki biçim zaten tüm çerçeveyi kapsar ve bir kırpma üzerinden yeniden kodlamak, mevcut sıkıştırılmış baytları kaydetmenin amacını boşa çıkarır.

quality, 0‘dan 100‘e kadar JPEG sıkıştırma kalitesidir ve yalnızca çıktı JPEG olduğunda anlamlıdır (kayıpsız biçimler için anahtar sözcük yok sayılır). Varsayılan değer olan 50, çoğu uygulama için doğru dengedir; 70 ile 85 arası daha yüksek görsel kalite için bant, 30 ile 50 arası küçük küçük resimler ve bant genişliği kısıtlı iletim için doğru aralık, 90 ve üzeri ise görüntünün elle inceleneceği ya da sıkıştırma yapaylıklarına duyarlı bir sonraki aşamadaki algoritmadan geçirileceği durumlar için ayrılmıştır.

Çağrının zincirlenebilmesi için alıcı görüntü döndürülür: img.save("/sdcard/x.jpg").draw_string(0, 0, "saved"). Döndürülen nesne, bellekteki aynı görüntüdür; kaydetme bir yan etkidir.

Tipik bir kullanım, yakala-ve-kaydet (capture-and-log) desenidir. Bir tetikleyici devreye girer (bir nokta (blob) tespit edilir, bir düğmeye basılır, bir zamanlayıcı dolar); betik bir çerçeve yakalar; dosya adına bir zaman damgası ekler; ve görüntüyü SD karta göndermek için save() çağrısını yapar. IDE önizlemesi çalışmaya devam eder, sonraki tetikleyici devreye girer ve kaydedilen dosyalar birikir.

5.32.2. Belleğe kodlama

Hedef dosya sistemi değil de bir ağ bağlantısı, bir seri bağlantı noktası ya da başka bir modülün girdisi olduğunda, uygulamanın kodlanmış bayt akışına diskte değil bellekte ihtiyacı vardır. to_jpeg() ve to_png() tam da bunu üretir:

encoded = img.to_jpeg(quality=80, copy=True)
bytes_to_send = encoded.bytearray()
sock.send(bytes_to_send)

Varsayılan davranış yerinde dönüştürmedir: alıcı bir JPEG (ya da PNG) görüntüsüne dönüştürülür ve aynı nesne döndürülür. copy=True ile dönüşüm, yeni ayrılmış bir yığın nesnesine yazılır; copy_to_fb=True ile çıktı çerçeve arabelleğine (frame buffer) düşer. Bu seçim, diğer her dönüştürme yönteminin sunduğunun aynısıdır – varsayılan olarak yerinde, özgün görüntü sonradan gerektiğinde ise kopyalama.

quality ve subsampling, kaydetme yolunun sunduğu aynı JPEG ayar düğmeleridir. subsampling kroma alt örnekleme şemasını seçer: image.JPEG_SUBSAMPLING_AUTO seçilen kalite için en iyisini belirler, image.JPEG_SUBSAMPLING_444 kromayı tam çözünürlükte tutar (en büyük dosya, en iyi renk doğruluğu), image.JPEG_SUBSAMPLING_422 ve image.JPEG_SUBSAMPLING_420 kroma çözünürlüğünü bir veya her iki eksende yarıya indirir (daha küçük dosyalar, tipik görüntüleme mesafelerinde görünmeyen hafif bir renk yumuşaması). Uygulamanın özel bir gereksinimi yoksa AUTO varsayılanı doğru seçimdir.

to_png() ile PNG kayıpsızdır ancak kodlaması daha yavaştır ve fotoğrafik içerik için JPEG’den daha büyük dosyalar üretir (fotoğrafik içerik, PNG’nin tahmin şemasıyla kötü sıkışır). Görüntü çizgi sanatı, bir ekran görüntüsü ya da yakalanmış bir çerçeve üzerine çizilmiş keskin kenarlı grafikler içerdiğinde PNG kullanın – kayıpsız kodlama, JPEG’in yumuşatacağı keskin kenarları korur. Aksi takdirde JPEG doğru varsayılandır.

Hem to_jpeg() hem de to_png(), diğer dönüştürme yöntemlerinin aldığı aynı çizim biçimli konumsal ve ölçek anahtar sözcüklerini kabul eder – x_scale, y_scale, roi, rgb_channel, alpha, color_palette, alpha_palette, hint – böylece aynı çağrı, kaynağın ölçeklenmiş, kırpılmış ya da palet eşlenmiş bir sürümünü tek adımda kodlayabilir. compress(), to_jpeg() yönteminin eski yazımıdır; ikisi aynı argümanları alır ve aynı sonucu üretir.

5.32.3. Sıkıştırmanın getirisi

JPEG’e karşı ham veri ödünleşiminin ardındaki sayılar üzerinden bir kez gitmeye değer.

320’ye 240 bir RGB565 çerçevesi 153.600 bayttır (QVGA’da yakalanan bir çerçeve). 640’a 480 bir çerçeve 614.400 bayttır; 1280’e 960 bir çerçeve 2.457.600 bayttır. Bunların hiçbiri bir masaüstü veya telefon ekranına kıyasla büyük değildir, ancak toplamda birkaç MB RAM’i olan, sınırlı bir yazma bant genişliğine sahip bir SD kartı ve tipik olarak USB CDC, bir UART ya da bir kablosuz modül üzerinden ılımlı hızlarda çalışan bir ana bilgisayar bağlantısı olan bir kamera bağlamında epeyce büyüktürler.

quality=50‘deki JPEG, tipik olarak fotoğrafik bir yakalanmış çerçeveyi 10 kat ile 20 kat arasında sıkıştırır: o 614 KB’lık 640’a 480 çerçeve, 30 ila 60 KB’lık kodlanmış bir bayt akışına dönüşür. quality=85‘te sıkıştırma 5 kat ile 10 kata düşer (aynı çerçeve için 60 ila 120 KB). quality=10‘da – yapaylık dolu ama hâlâ tanınabilir – sıkıştırma 30 kat ile 50 kata ulaşır (12 ila 20 KB).

Bu sayılar, kaydedilen çerçevelerle neyin pratikte yapılabilir olduğunu belirler. 10 MB/s’yi sürdüren bir SD kart yolu, quality=50 JPEG ile kodlanmış VGA içeriğinin saniyede 30 çerçevesini rahatça idare eder (yaklaşık 1 ila 2 MB/s); aynı içeriği sıkıştırılmamış olarak kaydetmek 18 MB/s’nin üzerinde gerektirir; bu da kameranın dosya sistemi yolunun karta sürdürebileceğinin ötesindedir. CDC üzerinden 1 MB/s’de JPEG ile kodlanmış çerçeveleri çeken bir USB ana bilgisayarı, kabaca saniyede 15 ila 30 çerçevede 30 ila 60 KB’lık çerçeveler alır; ham çerçeveleri aynı hızda çekerse saniyede bir ya da iki çerçeve alır.

Kısacası: sıkıştırma yöntemleri yalnızca kaydetme için bir kolaylık değildir. Yakalanan çerçeveyi, uygulamanın önemsediği çerçeve hızlarında kamera dışında kullanılabilir kılan şeydir. Doğru sıkıştırmayı seçmek – genel kayıt için JPEG kalite 50, kalite işi için 80, çizgi sanatı yakalama için PNG – önemsiz olmayan herhangi bir kamera uygulamasının rutin işinin bir parçasıdır.