4.16. Náhled obrazu¶
Fond framebufferů je místo, kde aplikace čte své snímky. Zatímco aplikace na těchto snímcích pracuje, cokoli je připojeno ke kameře pro jejich náhled potřebuje rovněž kopii každého snímku. Kamera má pro tento účel druhý, vyhrazený buffer, a jediné pravidlo pro to, kdy se naplní: pokaždé, když aplikace zavolá snapshot(), je předchozí zachycený snímek zkopírován do náhledového bufferu dříve, než je předán nový snímek.
Aplikace a náhled nikdy nesoupeří o stejnou paměť. Aplikace čte svůj snímek z fondu; náhled čte svůj snímek z náhledového bufferu. Obojí probíhá paralelně.
4.16.1. Stream framebuffer¶
Náhledový buffer – stream framebuffer – je jediná oblast RAM s pevnou velikostí, oddělená od fondu framebufferů. Jeho velikost je nastavena v době sestavení firmwaru a nemění se podle framesize() ani pixformat(). Na nedávných OpenMV Cam je typicky kolem jednoho megabajtu – dost velký pro pojmutí náhledu se středním rozlišením, mnohem menší než snímek v plném rozlišení při největších velikostech senzoru.
Kód aplikace tento buffer nečte ani do něj přímo nezapisuje; ovladač kamery jej plní jako vedlejší efekt snapshot().
4.16.2. Co snapshot dělá pro náhled¶
Při každém volání snapshot(), dříve než ovladač uvolní předchozí framebuffer aplikace zpět do fondu a předá nový, zkopíruje předchozí snímek do náhledového bufferu – spolu se vším, co na něj aplikace během zpracování nakreslila. Možné jsou dvě větve. Která z nich se spustí, vybírá náhled, nikoli kamera: konzument, který náhled otevřel, ovladači sdělí, zda chce surový obraz nebo JPEG a jakou velikost surového okna dokáže přijmout.
Surová zmenšená kopie. Když si náhled vyžádal surové snímky, ovladač zkopíruje předchozí snímek v jeho nativním pixelovém formátu (RGB565, stupně šedi atd.). Pokud je snímek větší než surové okno, které si náhled vyžádal, ovladač jej zmenší pomocí bilineárního filtrování, dokud se nevejde; jinak pixely projdou beze změny. Žádné kompresní artefakty; náhled vidí stejné pixely, na kterých aplikace pracovala.
JPEG komprese. Když si náhled vyžádal JPEG – nebo když by se surová kopie do stream bufferu vůbec nevešla – ovladač zkomprimuje předchozí snímek v jeho plném rozlišení do JPEG ve stream bufferu. Kvalita je upravována adaptivně pro každý snímek, aby komprimovaný výstup zůstal v rámci kapacity stream bufferu. Když se snímek vejde, ovladač pozvolna zvyšuje kvalitu o jeden krok směrem ke stropu, který závisí na velikosti pixelů zachyceného snímku (menším snímkům je dovolena vyšší kvalita; větší snímky jsou omezeny níže, aby nemohly přetéct při malé změně obsahu). Když se snímek nevejde, ovladač sníží aktuální kvalitu na polovinu, podrží ji na snížené úrovni po několik dalších desítek snímků, aby nové nastavení mělo čas se ustálit, a přeteklý snímek z náhledu vynechá. Smyčka aplikace běží dál nedotčena; pouze náhled o vynechaný snímek přijde.
Snímky, které kamera produkuje ve formátu, jenž je již komprimovaný (pixelový formát JPEG na senzorech, které vysílají JPEG přímo), přeskakují obě větve: zakódovaný bitový proud je zkopírován přímo do náhledového bufferu tak, jak je.
Náhled se dotazuje podle vlastního rozvrhu, obecně mnohem pomaleji, než kamera zachytává, takže podvzorkovává surovou frekvenci zachytávání: zobrazeny jsou pouze ty snímky, které stihne včas přečíst. Pokud do náhledového bufferu dorazí čerstvý snapshot() dříve, než náhled přečetl předchozí snímek, je buffer stále uzamčen náhledem a nová aktualizace náhledu je přeskočena – toto zachycení je z náhledového proudu ztraceno. Vlastní fond framebufferů aplikace zůstává nedotčen; zachycený snímek se k aplikaci stále normálně dostane.
4.16.3. Ruční odeslání posledního snímku¶
Protože je náhled aktualizován jako vedlejší efekt snapshot(), skript, který skončí, aniž by ještě jednou zavolal snapshot, ponechá cokoli, co naposledy odeslal do náhledu, sedět na náhledu donekonečna – což u skriptu, který svou práci vykoná před prvním snapshotem a poté skončí, je prázdný náhled. image.Image.flush() (nebo ekvivalentní flush() na objektu CSI) na vyžádání zkopíruje aktuální obsah framebufferu aplikace do stream bufferu, aniž by zachytil nový snímek:
img = csi0.snapshot()
# process the image and draw on it
img.flush() # previewer sees the annotated frame
Stejné volání je užitečné i tehdy, když mezi snímky probíhá dlouhotrvající operace a náhled by jinak po celou tu dobu zobrazoval zastaralý náhled.
Poznámka
Náhledová aplikace musí přečíst snímek ze stream bufferu dříve, než skript skončí. Flush na konci krátkého skriptu pouze připraví snímek; pokud skript poté vrátí řízení kameře dříve, než se náhled stihl dotázat, je buffer při dalším spuštění znovu použit a tento poslední snímek je ztracen. Pro náhledy na konci skriptu dejte náhledu chvíli na vyzvednutí snímku (krátký sleep po flush, nebo prostě neukončujte okamžitě), než skript skončí.