5.32. Tallentaminen ja pakkaus¶
Jokainen tähänastinen sivu on käsitellyt kamerassa olevia kuvia: kaapattu kehyspuskuriin tai varattu MicroPythonin keolle, käsitelty image-moduulin metodeilla ja joko näytetty IDE:n esikatselussa tai syötetty saman skriptin myöhempään vaiheeseen. Useimpien sovellusten täytyy jossain vaiheessa tehdä päinvastoin: ottaa kuva, joka on parhaillaan RAM-muistissa, ja sijoittaa se johonkin pysyvään paikkaan – SD-kortille, USB-isäntään tai verkkoon – josta jokin muu kuin kamera voi lukea sen.
Image-moduuli tarjoaa kaksi reittiä tähän työhön. Tallennusreitti kirjoittaa kuvan tiedostoon tiedostojärjestelmään niin, että tiedostomuoto valitaan tarkenteen perusteella ja koodauksen yksityiskohdat hoidetaan metodissa. Muotoon-muuntoreitti palauttaa Image-objektin, joka sisältää koodatun tavuvirran ja sopii välitettäväksi suoratoisto- tai verkkokutsulle koskettamatta lainkaan tiedostojärjestelmää. Kumpikin sopii eri sovellukseen; molemmat rakentuvat saman pakkausmoottorin päälle.
5.32.1. Tallentaminen tiedostoon¶
save() kirjoittaa kuvan tiedostojärjestelmään polkuun:
img.save("/sdcard/capture.jpg")
img.save("/sdcard/capture.bmp")
img.save("/sdcard/region.jpg", roi=(40, 60, 200, 150), quality=85)
Tiedostomuoto valitaan tiedostotarkenteen perusteella. Viisi tarkennetta tunnistetaan: .bmp kirjoittaa Windows-bittikartan (häviötön, ei pakkausta, tavu tavulta kaapatut pikselit); .pgm kirjoittaa portable graymap -muodon (häviötön, vain harmaasävy); .ppm kirjoittaa portable pixmap -muodon (häviötön, RGB); .jpg ja .jpeg kirjoittavat molemmat JPEG-kuvan (häviöllinen, pakattu). Vastaanottavan kuvan on jo oltava valitulle säiliölle oikeassa väriformaatissa – värikuvan tallentaminen muotoon .pgm on virhe.
roi rajaa tallennuksen kuvan osasuorakulmioon samalla tavalla kuin jokaisen muun image-moduulin metodin roi-avainsana. Oletuksena on koko kuva. Avainsana ohitetaan tallennettaessa JPEG-pakattua kuvaa, koska levyllä oleva muoto kattaa jo koko kehyksen ja rajauksen kautta uudelleenkoodaaminen tekisi tyhjäksi olemassa olevien pakattujen tavujen tallentamisen tarkoituksen.
quality on JPEG-pakkauksen laatu välillä 0–100 ja sillä on merkitystä vain, kun tuloste on JPEG (häviöttömissä muodoissa avainsana ohitetaan). Oletusarvo 50 on oikea tasapaino useimmille sovelluksille; 70–85 on alue korkeammalle visuaaliselle laadulle, 30–50 on oikea väli pienille pikkukuville ja kaistanleveysrajoitteiselle siirrolle, ja 90 ja siitä ylöspäin on varattu tapauksiin, joissa kuvaa tarkastellaan käsin tai se ajetaan pakkausartefakteille herkän myöhemmän algoritmin läpi.
Vastaanottava kuva palautetaan, joten kutsu ketjuuntuu: img.save("/sdcard/x.jpg").draw_string(0, 0, "saved"). Palautettu objekti on sama muistinsisäinen kuva; tallennus on sivuvaikutus.
Tyypillinen käyttö on kaappaa-ja-kirjaa-malli. Liipaisin laukeaa (blob havaitaan, painiketta painetaan, ajastin umpeutuu); skripti kaappaa kehyksen; se lisää tiedostonimeen aikaleiman; ja se kutsuu save() työntääkseen kuvan SD-kortille. IDE:n esikatselu jatkaa toimintaansa, seuraava liipaisin laukeaa ja tallennetut tiedostot kertyvät.
5.32.2. Koodaaminen muistiin¶
Kun kohde ei ole tiedostojärjestelmä vaan verkkoyhteys, sarjaportti tai toisen moduulin syöte, sovellus tarvitsee koodatun tavuvirran muistissa eikä levyllä. to_jpeg() ja to_png() tuottavat juuri sen:
encoded = img.to_jpeg(quality=80, copy=True)
bytes_to_send = encoded.bytearray()
sock.send(bytes_to_send)
Oletustoiminta on muunnos paikalleen: vastaanottaja muunnetaan JPEG- (tai PNG-) kuvaksi ja sama objekti palautetaan. Asetuksella copy=True muunnos kirjoitetaan vasta varattuun keko-objektiin; asetuksella copy_to_fb=True tuloste päätyy kehyspuskuriin. Valinta on sama, jonka mikä tahansa muu muunnosmetodi tarjoaa – oletuksena paikalleen, kopiointi silloin kun alkuperäistä tarvitaan jälkeenpäin.
quality ja subsampling ovat samat JPEG-säätönupit, jotka tallennusreitti tarjoaa. subsampling valitsee krominanssin alinäytteistysmenetelmän: image.JPEG_SUBSAMPLING_AUTO valitsee parhaan valitulle laadulle, image.JPEG_SUBSAMPLING_444 säilyttää krominanssin täydessä resoluutiossa (suurin tiedosto, paras väritarkkuus), image.JPEG_SUBSAMPLING_422 ja image.JPEG_SUBSAMPLING_420 puolittavat krominanssin resoluution yhdellä tai molemmilla akseleilla (pienemmät tiedostot, lievää värin pehmenemistä, joka on näkymätöntä tavanomaisilla katseluetäisyyksillä). Oletusarvo AUTO on oikea valinta, ellei sovelluksella ole erityistarvetta.
PNG metodin to_png() kautta on häviötön, mutta hitaampi koodata ja tuottaa valokuvasisällölle suurempia tiedostoja kuin JPEG (valokuvasisältö pakkautuu huonosti PNG:n ennustusmenetelmällä). Käytä PNG:tä, kun kuva on viivapiirros, näyttökuva tai sisältää kaapatun kehyksen päälle piirrettyä teräväreunaista grafiikkaa – häviötön koodaus säilyttää terävät reunat, jotka JPEG pehmentäisi. Muutoin JPEG on oikea oletus.
Sekä to_jpeg() että to_png() hyväksyvät samat piirtotyyliset positionaaliset ja skaalausavainsanat kuin muut muunnosmetodit – x_scale, y_scale, roi, rgb_channel, alpha, color_palette, alpha_palette, hint – joten sama kutsu voi koodata skaalatun, rajatun tai palettikartoitetun version lähteestä yhdellä askeleella. compress() on metodin to_jpeg() vanha kirjoitusasu; molemmat ottavat samat argumentit ja tuottavat saman tuloksen.
5.32.3. Mitä pakkaus tuo¶
JPEG-vastaan-raaka-kompromissin takana olevat luvut kannattaa käydä kertaalleen läpi.
320 kertaa 240 RGB565 -kehys on 153 600 tavua (yksi kaapattu kehys QVGA-koossa). 640 kertaa 480 -kehys on 614 400 tavua; 1280 kertaa 960 -kehys on 2 457 600 tavua. Mikään näistä ei ole suuri verrattuna pöytäkoneen tai puhelimen näyttöön, mutta ne ovat huomattavia sellaisen kameran kontekstissa, jolla on yhteensä muutama megatavu RAM-muistia, SD-kortti rajallisella kirjoituskaistalla ja isäntäyhteys, joka tyypillisesti toimii USB CDC:n, UARTin tai langattoman moduulin yli vaatimattomilla nopeuksilla.
JPEG asetuksella quality=50 pakkaa tyypillisesti valokuvamaisen kaapatun kehyksen 10-20-kertaisesti: tuosta 614 kt:n 640 kertaa 480 -kehyksestä tulee 30-60 kt:n koodattu tavuvirta. Asetuksella quality=85 pakkaus laskee 5-10-kertaiseksi (60-120 kt samalle kehykselle). Asetuksella quality=10 – artefaktien täyttämä mutta yhä tunnistettava – pakkaus yltää 30-50-kertaiseksi (12-20 kt).
Nuo luvut määräävät, mikä on käytännöllistä tehdä tallennetuilla kehyksillä. SD-korttireitti, joka ylläpitää 10 Mt/s, käsittelee 30 kehystä sekunnissa quality=50-asetuksella JPEG-koodattua VGA-sisältöä reilusti varaa jättäen (noin 1-2 Mt/s); saman sisällön tallentaminen pakkaamattomana vaatii yli 18 Mt/s, mikä ylittää sen, mitä kameran tiedostojärjestelmäreitti ylläpitää kortille. USB-isäntä, joka vetää JPEG-koodattuja kehyksiä CDC:n yli nopeudella 1 Mt/s, vastaanottaa 30-60 kt:n kehyksiä noin 15-30 kehyksen sekuntivauhdilla; raakojen kehysten vetäminen samalla nopeudella saa yhden tai kaksi kehystä sekunnissa.
Lyhyesti: pakkausmetodit eivät ole vain mukavuus tallentamista varten. Ne ovat se, mikä tekee kaapatusta kehyksestä käyttökelpoisen kameran ulkopuolella niillä kehysnopeuksilla, joista sovellus välittää. Oikean pakkauksen valitseminen – JPEG-laatu 50 yleiseen kirjaamiseen, 80 laatutyöhön, PNG viivapiirroskaappaukseen – on osa minkä tahansa ei-triviaalin kamerasovelluksen rutiinityötä.