4.16. Kép-előnézet¶
A képkocka-puffer halmaz az a hely, ahol az alkalmazás kiolvassa a képkockáit. Amíg az alkalmazás ezeken a képkockákon dolgozik, bárminek, ami a kamerához van csatlakoztatva azok előnézetéhez, szintén szüksége van minden képkocka egy másolatára. A kamera erre a célra rendelkezik egy második, dedikált pufferrel, és egyetlen szabállyal arra vonatkozóan, hogy mikor töltődik fel: valahányszor az alkalmazás meghívja a snapshot() metódust, az előző rögzített képkocka az előnézeti pufferbe másolódik, mielőtt az új képkocka visszaadásra kerül.
Az alkalmazás és az előnézet-megjelenítő soha nem versengenek ugyanazért a memóriáért. Az alkalmazás a halmazból olvassa ki a képkockáját; az előnézet-megjelenítő az előnézeti pufferből olvassa ki a képkockáját. Mindkettő párhuzamosan történik.
4.16.1. Az adatfolyam képkocka-puffer¶
Az előnézeti puffer – az adatfolyam képkocka-puffer – a RAM egyetlen rögzített méretű, a képkocka-puffer halmaztól elkülönített területe. Mérete a firmware fordítási idején van beállítva, és nem változik a framesize() vagy a pixformat() hatására. A legutóbbi OpenMV Camekben jellemzően körülbelül egy megabájt – elég nagy ahhoz, hogy egy közepes felbontású előnézetet tartalmazzon, sokkal kisebb, mint egy teljes felbontású képkocka a legnagyobb érzékelőméreteknél.
Az alkalmazás kódja nem olvassa és nem írja közvetlenül ezt a puffert; a kamera meghajtója a snapshot() mellékhatásaként tölti fel.
4.16.2. Mit tesz a pillanatkép az előnézetért¶
A snapshot() minden hívásakor, mielőtt a meghajtó visszaengedné az alkalmazás előző képkocka-pufferét a halmazba és átadná az újat, az előző képkockát átmásolja az előnézeti pufferbe – mindazzal együtt, amit az alkalmazás a feldolgozás során a tetejére rajzolt, még mindig a képen. Két ág lehetséges. Hogy melyik fut le, azt az előnézet-megjelenítő dönti el, nem a kamera: az előnézetet megnyitó fogyasztó közli a meghajtóval, hogy nyers képet vagy JPEG-et szeretne-e, és milyen nyers ablakméretet tud elfogadni.
Nyers, lekicsinyített másolat. Amikor az előnézet-megjelenítő nyers képkockákat kért, a meghajtó az előző képkockát annak natív képpontformátumában (RGB565, szürkeárnyalatos stb.) másolja át. Ha a képkocka nagyobb, mint az előnézet-megjelenítő által kért nyers ablak, a meghajtó bilineáris szűréssel lekicsinyíti, amíg bele nem fér; egyébként a képpontok változatlanul mennek át. Nincsenek tömörítési műtermékek; az előnézet-megjelenítő ugyanazokat a képpontokat látja, amelyeken az alkalmazás dolgozott.
JPEG-tömörítés. Amikor az előnézet-megjelenítő JPEG-et kért – vagy amikor a nyers másolat egyáltalán nem férne bele az adatfolyam-pufferbe –, a meghajtó az előző képkockát annak teljes felbontásában JPEG-be tömöríti az adatfolyam-pufferbe. A minőség képkockánként adaptívan van beállítva, hogy a tömörített kimenet az adatfolyam-puffer kapacitásán belül maradjon. Amikor egy képkocka belefér, a meghajtó egy lépéssel visszakúsztatja a minőséget egy felső határ felé, amely a rögzített képkocka képpontméretétől függ (a kisebb képkockáknál magasabb minőség engedélyezett; a nagyobb képkockáknál alacsonyabbra van korlátozva, hogy egy kis tartalomváltozásnál ne tudjanak túlcsordulni). Amikor egy képkocka nem fér bele, a meghajtó megfelezi az aktuális minőséget, a következő néhány tucat képkockán a csökkentett szinten tartja, hogy az új beállításnak legyen ideje beállni, és a túlcsordult képkockát kihagyja az előnézetből. Az alkalmazás ciklusa zavartalanul fut tovább; csak az előnézet-megjelenítő hagyja ki az eldobott képkockát.
Azok a képkockák, amelyeket a kamera már tömörített formátumban állít elő (a JPEG képpontformátum azokon az érzékelőkön, amelyek közvetlenül JPEG-et bocsátanak ki), mindkét ágat kihagyják: a kódolt bitfolyam változatlanul, közvetlenül az előnézeti pufferbe másolódik.
Az előnézet-megjelenítő a saját ütemezése szerint kérdez le, általában sokkal lassabban, mint ahogy a kamera rögzít, így alulmintavételezi a nyers rögzítési sebességet: csak azok a pillanatképek jelennek meg, amelyeket idejében ki tud olvasni. Ha egy friss snapshot() érkezik az előnézeti pufferbe, mielőtt az előnézet-megjelenítő kiolvasta volna az előző képkockát, a puffert még mindig zárolja az előnézet-megjelenítő, és az új előnézeti frissítés kimarad – az a felvétel elveszik az előnézeti adatfolyamból. Az alkalmazás saját képkocka-puffer halmazát ez nem érinti; a rögzített képkocka továbbra is normálisan eljut az alkalmazáshoz.
4.16.3. Az utolsó képkocka manuális kiküldése¶
Mivel az előnézet a snapshot() mellékhatásaként frissül, egy olyan szkript, amely úgy fejeződik be, hogy soha többé nem hívja meg a pillanatképet, határozatlan ideig az előnézet-megjelenítőn hagyja azt, amit utoljára küldött az előnézetbe – ami egy olyan szkript esetében, amely az első pillanatkép előtt végzi el a munkáját, majd kilép, egy üres előnézet. A image.Image.flush() (vagy a vele egyenértékű flush() a CSI objektumon) igény szerint, új képkocka rögzítése nélkül átmásolja az alkalmazás képkocka-pufferének aktuális tartalmát az adatfolyam-pufferbe:
img = csi0.snapshot()
# process the image and draw on it
img.flush() # previewer sees the annotated frame
Ugyanez a hívás akkor is hasznos, amikor egy hosszan futó művelet helyezkedik el a pillanatképek között, és az előnézet-megjelenítő egyébként végig egy elavult előnézetet mutatna.
Megjegyzés
Az előnézeti alkalmazásnak ki kell olvasnia a képkockát az adatfolyam-pufferből, mielőtt a szkript kilép. Egy flush egy rövid szkript végén csak előkészíti a képkockát; ha a szkript ezután visszaadja a vezérlést a kamerának, mielőtt az előnézet-megjelenítő lekérdezte volna, a puffer a következő futáskor újrahasználásra kerül, és az a végső képkocka elvész. A szkriptvégi előnézetekhez adjon az előnézet-megjelenítőnek egy pillanatot, hogy felvegye a képkockát (egy rövid alvás a flush után, vagy egyszerűen csak ne lépjen ki azonnal), mielőtt a szkript véget ér.