5.32. Ukládání a komprese¶
Každá dosavadní stránka pracovala s obrazy na kameře: zachycenými do snímkového bufferu (frame buffer) nebo alokovanými na haldě MicroPython, upravovanými pomocí metod modulu image a buď zobrazenými v náhledu IDE, nebo předanými do navazující fáze ve stejném skriptu. Většina aplikací musí v určitém okamžiku udělat opak: vzít obraz, který je právě v RAM, a uložit jej někam trvale – na SD kartu, na USB hostitele, přes síť – kde jej může přečíst něco jiného než kamera.
Modul image nabízí pro tuto práci dvě cesty. Cesta save zapíše obraz do souboru v souborovém systému, přičemž formát souboru je zvolen podle přípony a detaily kódování řeší daná metoda. Cesta to-format vrátí objekt Image obsahující zakódovaný proud bajtů, vhodný k předání volání pro streamování nebo síťový přenos, aniž by se kdy dotkl souborového systému. Každá se hodí pro jinou aplikaci; obě staví na stejném kompresním jádru pod nimi.
5.32.1. Ukládání do souboru¶
save() zapíše obraz do souborového systému na danou cestu:
img.save("/sdcard/capture.jpg")
img.save("/sdcard/capture.bmp")
img.save("/sdcard/region.jpg", roi=(40, 60, 200, 150), quality=85)
Formát je vybrán podle přípony souboru. Rozpoznáno je pět přípon: .bmp zapíše Windows bitmap (bezztrátový, bez komprese, pixely přesně tak, jak byly zachyceny); .pgm zapíše portable graymap (bezztrátový, pouze stupně šedi); .ppm zapíše portable pixmap (bezztrátový, RGB); .jpg i .jpeg zapíší JPEG (ztrátový, komprimovaný). Přijímající obraz již musí být ve správném barevném formátu pro zvolený kontejner – barevný obraz uložený jako .pgm je chyba.
roi omezí ukládání na dílčí obdélník obrazu, stejně jako keyword roi u každé jiné metody modulu image. Výchozí hodnotou je celý obraz. Tento keyword je při ukládání JPEG-komprimovaného obrazu ignorován, protože forma na disku již pokrývá celý snímek a opětovné zakódování přes oříznutí by zmařilo smysl uložení existujících komprimovaných bajtů.
quality je kvalita JPEG komprese od 0 do 100 a má význam pouze tehdy, je-li výstupem JPEG (pro bezztrátové formáty je tento keyword ignorován). Výchozí hodnota 50 je správnou rovnováhou pro většinu aplikací; 70 až 85 je pásmo pro vyšší vizuální kvalitu, 30 až 50 je správný rozsah pro malé náhledy a přenos s omezenou šířkou pásma a 90 a výše je vyhrazeno pro případy, kdy bude obraz prohlížen ručně nebo zpracován navazujícím algoritmem citlivým na kompresní artefakty.
Přijímající obraz je vrácen, takže lze volání řetězit: img.save("/sdcard/x.jpg").draw_string(0, 0, "saved"). Vrácený objekt je tentýž obraz v paměti; uložení je vedlejší efekt.
Typickým použitím je vzor capture-and-log (zachyť a zaloguj). Spustí se spouštěč (je detekován blob, je stisknuto tlačítko, uplyne časovač); skript zachytí snímek; připojí k názvu souboru časové razítko; a zavolá save(), aby obraz odeslal na SD kartu. Náhled IDE běží dál, spustí se další spouštěč a uložené soubory se hromadí.
5.32.2. Kódování do paměti¶
Když cílem není souborový systém, ale síťové připojení, sériový port nebo vstup jiného modulu, aplikace potřebuje zakódovaný proud bajtů v paměti místo na disku. to_jpeg() a to_png() produkují přesně to:
encoded = img.to_jpeg(quality=80, copy=True)
bytes_to_send = encoded.bytearray()
sock.send(bytes_to_send)
Výchozím chováním je převod na místě: přijímač je převeden na JPEG (nebo PNG) obraz a je vrácen tentýž objekt. S copy=True se převod zapíše do nově alokovaného objektu na haldě; s copy_to_fb=True skončí výstup ve snímkovém bufferu (frame buffer). Volba je stejná, jakou nabízí každá jiná metoda převodu – ve výchozím stavu na místě, kopie tehdy, je-li poté potřeba originál.
quality a subsampling jsou stejné ladicí prvky JPEG, jaké nabízí cesta save. subsampling volí schéma podvzorkování chromatické složky: image.JPEG_SUBSAMPLING_AUTO vybere nejlepší pro zvolenou kvalitu, image.JPEG_SUBSAMPLING_444 zachová chromatickou složku v plném rozlišení (největší soubor, nejlepší přesnost barev), image.JPEG_SUBSAMPLING_422 a image.JPEG_SUBSAMPLING_420 zmenší rozlišení chromatické složky na polovinu podél jedné nebo obou os (menší soubory, mírné změkčení barev, které je při typických pozorovacích vzdálenostech neviditelné). Výchozí hodnota AUTO je správnou volbou, pokud aplikace nemá specifickou potřebu.
PNG přes to_png() je bezztrátový, ale jeho kódování je pomalejší a pro fotografický obsah produkuje větší soubory než JPEG (fotografický obsah se pod predikčním schématem PNG komprimuje špatně). PNG použijte, když je obraz pérovkou, snímkem obrazovky nebo obsahuje grafiku s ostrými hranami nakreslenou přes zachycený snímek – bezztrátové kódování zachová ostré hrany, které by JPEG změkčil. Jinak je správnou výchozí volbou JPEG.
to_jpeg() i to_png() přijímají stejné poziční a měřítkové keyword argumenty kreslicího stylu jako jiné metody převodu – x_scale, y_scale, roi, rgb_channel, alpha, color_palette, alpha_palette, hint – takže totéž volání může v jednom kroku zakódovat zmenšenou, oříznutou nebo paletově mapovanou verzi zdroje. compress() je starší zápis metody to_jpeg(); obě berou stejné argumenty a produkují stejný výsledek.
5.32.3. Co komprese přináší¶
Čísla za kompromisem JPEG versus surová data stojí za to si jednou projít.
Snímek 320 na 240 ve formátu RGB565 má 153 600 bajtů (jeden zachycený snímek v QVGA). Snímek 640 na 480 má 614 400 bajtů; snímek 1280 na 960 má 2 457 600 bajtů. Žádné z těchto čísel nejsou velké ve srovnání s displejem stolního počítače nebo telefonu, ale jsou značné v kontextu kamery, která má celkem několik MB RAM, SD kartu s konečnou zápisovou šířkou pásma a hostitelské spojení, které typicky běží přes USB CDC, UART nebo bezdrátový modul při skromných rychlostech.
JPEG při quality=50 typicky komprimuje fotografický zachycený snímek 10x až 20x: z onoho 614KB snímku 640 na 480 se stane zakódovaný proud bajtů o velikosti 30 až 60 KB. Při quality=85 komprese klesá na 5x až 10x (60 až 120 KB pro tentýž snímek). Při quality=10 – plné artefaktů, ale stále rozpoznatelné – komprese dosahuje 30x až 50x (12 až 20 KB).
Tato čísla určují, co je prakticky možné s uloženými snímky dělat. Cesta na SD kartu s trvalou rychlostí 10 MB/s zvládne 30 snímků za sekundu obsahu JPEG zakódovaného v VGA při quality=50 s rezervou (přibližně 1 až 2 MB/s); ukládání téhož obsahu nekomprimovaně vyžaduje přes 18 MB/s, což je za hranicí toho, co cesta souborového systému kamery na kartu udrží. USB hostitel stahující JPEG zakódované snímky přes CDC rychlostí 1 MB/s přijímá snímky o velikosti 30 až 60 KB zhruba při 15 až 30 snímcích za sekundu; při stahování surových snímků stejnou rychlostí dostane jeden nebo dva snímky za sekundu.
Stručně řečeno: kompresní metody nejsou jen pohodlím pro ukládání. Jsou tím, co činí zachycený snímek použitelným mimo kameru při snímkových frekvencích, na kterých aplikaci záleží. Volba správné komprese – JPEG kvalita 50 pro obecné logování, 80 pro práci vyžadující kvalitu, PNG pro zachycení pérovek – je součástí běžné práce každé netriviální aplikace pro kameru.