4.16. Görüntü önizlemesi¶
The framebuffer pool is where the application reads its
frames. While the application is working on those frames,
whatever is connected to the camera to preview them needs a
copy of each frame too. The camera has a second, dedicated
buffer for that purpose, and a single rule for when it gets
filled: every time the application calls
snapshot(), the previous captured frame is
copied into the preview buffer before the new frame is
handed back.
Uygulama ve önizleyici asla aynı bellek için çekişmez. Uygulama çerçevesini havuzdan okur; önizleyici çerçevesini önizleme arabelleğinden okur. Her ikisi de paralel olarak gerçekleşir.
4.16.1. Akış çerçeve arabelleği¶
Önizleme arabelleği – akış çerçeve arabelleği – çerçeve arabelleği havuzundan ayrı, sabit boyutlu tek bir RAM bölgesidir. Boyutu aygıt yazılımı (firmware) derleme zamanında belirlenir ve framesize() veya pixformat() ile değişmez. Son OpenMV Cam’lerde tipik olarak yaklaşık bir megabayttır; orta çözünürlüklü bir önizlemeyi tutacak kadar büyük, en büyük sensör boyutlarındaki tam çözünürlüklü bir çerçeveden çok daha küçük.
Uygulama kodu bu arabelleği doğrudan okumaz veya yazmaz; kamera sürücüsü onu snapshot() çağrısının bir yan etkisi olarak doldurur.
4.16.2. Anlık görüntünün önizleme için yaptıkları¶
Her snapshot() çağrısında, sürücü uygulamanın önceki çerçeve arabelleğini havuza geri bırakıp yeni olanı dağıtmadan önce, önceki çerçeveyi – işleme sırasında uygulamanın üzerine çizdiği her şey görüntüde hâlâ duruyorken – önizleme arabelleğine kopyalar. İki dal mümkündür. Hangisinin çalışacağı kamera tarafından değil, önizleyici tarafından seçilir: önizlemeyi açan tüketici, sürücüye ham görüntü mü yoksa bir JPEG mi istediğini ve hangi ham pencere boyutunu kabul edebileceğini söyler.
Ham ölçeği küçültülmüş kopya. Önizleyici ham çerçeveler istediğinde, sürücü önceki çerçeveyi kendi yerel piksel formatında (RGB565, gri tonlama vb.) kopyalar. Çerçeve, önizleyicinin istediği ham pencereden büyükse, sürücü onu sığana kadar bilineer filtreleme ile ölçeğini küçültür; aksi takdirde pikseller değişmeden geçer. Sıkıştırma artefaktı yoktur; önizleyici, uygulamanın üzerinde çalıştığı piksellerin aynısını görür.
JPEG sıkıştırması. Önizleyici JPEG istediğinde – veya ham kopya akış arabelleğine hiç sığmayacağında – sürücü önceki çerçeveyi tam çözünürlüğünde JPEG ile sıkıştırarak akış arabelleğine yazar. Kalite, sıkıştırılmış çıktının akış arabelleğinin kapasitesi içinde kalması için çerçeve başına uyarlamalı olarak ayarlanır. Bir çerçeve sığdığında, sürücü kaliteyi yakalanan çerçevenin piksel boyutuna bağlı olan bir tavana doğru her seferinde bir adım yukarı sürükler (daha küçük çerçevelere daha yüksek kaliteye izin verilir; daha büyük çerçeveler küçük bir içerik değişikliğinde taşmamaları için daha düşük sınırlanır). Bir çerçeve sığmadığında, sürücü geçerli kaliteyi yarıya indirir, yeni ayarın oturması için zaman tanımak amacıyla onu sonraki birkaç düzine çerçeve boyunca düşürülmüş seviyede tutar ve taşan çerçeveyi önizlemeden düşürür. Uygulama döngüsü etkilenmeden çalışmaya devam eder; yalnızca önizleyici düşürülen çerçeveyi kaçırır.
Kameranın zaten sıkıştırılmış bir formatta ürettiği çerçeveler (JPEG’i doğrudan yayan sensörlerdeki JPEG piksel formatı) her iki dalı da atlar: kodlanmış bit akışı, olduğu gibi doğrudan önizleme arabelleğine kopyalanır.
Önizleyici, genellikle kameranın yakaladığından çok daha yavaş olan kendi programına göre yoklama yapar, dolayısıyla ham yakalama hızını alt örnekler: yalnızca zamanında okumayı başardığı anlık görüntüler gösterilir. Önizleyici önceki çerçeveyi okumadan önce önizleme arabelleğine yeni bir snapshot() gelirse, arabellek hâlâ önizleyici tarafından kilitlidir ve yeni önizleme güncellemesi atlanır; o yakalama önizleme akışından kaybolur. Uygulamanın kendi çerçeve arabelleği havuzu etkilenmez; yakalanan çerçeve uygulamaya normal şekilde gitmeye devam eder.
4.16.3. Son çerçeveyi manuel olarak gönderme¶
Önizleme snapshot() çağrısının bir yan etkisi olarak güncellendiğinden, bir daha hiç anlık görüntü çağırmadan biten bir betik, önizleyiciye son gönderdiği şeyi süresiz olarak önizleyicinin üzerinde bırakır; bu da işini ilk anlık görüntüden önce yapıp ardından çıkan bir betik için boş bir önizleme demektir. image.Image.flush() (veya CSI nesnesindeki eşdeğeri olan flush()), yeni bir çerçeve yakalamadan, uygulamanın çerçeve arabelleğinin geçerli içeriğini talep üzerine akış arabelleğine kopyalar:
img = csi0.snapshot()
# process the image and draw on it
img.flush() # previewer sees the annotated frame
Aynı çağrı, anlık görüntüler arasında uzun süren bir işlem olduğunda ve önizleyicinin aksi takdirde tüm bu süre boyunca eski bir önizleme göstereceği durumlarda da yararlıdır.
Not
Önizleme uygulamasının, betik çıkmadan önce çerçeveyi akış arabelleğinden okuması gerekir. Kısa bir betiğin sonundaki bir flush, çerçeveyi yalnızca hazırlar; betik ardından önizleyici yoklama yapmadan önce kontrolü kameraya geri verirse, arabellek bir sonraki çalıştırmada yeniden kullanılır ve o son çerçeve kaybolur. Betik sonu önizlemeleri için, betik bitmeden önce önizleyiciye çerçeveyi alması için bir an tanıyın (flush’tan sonra kısa bir uyku veya yalnızca hemen çıkmama).