5.32. Spara och komprimera¶
Varje sida hittills har arbetat med bilder på kameran: infångade i bildbufferten eller allokerade på MicroPython-heapen, manipulerade med metoderna i image-modulen, och antingen visade i IDE:ns förhandsvisning eller matade in i ett efterföljande steg i samma skript. De flesta tillämpningar behöver vid någon tidpunkt göra det motsatta: ta en bild som för tillfället finns i RAM och placera den någonstans beständigt – på SD-kortet, på en USB-värd, över ett nätverk – där något annat än kameran kan läsa den.
Image-modulen erbjuder två vägar för det arbetet. Spara-vägen skriver bilden till en fil i filsystemet, där filformatet väljs av filändelsen och kodningsdetaljerna hanteras av metoden. Till-format-vägen returnerar ett Image-objekt som innehåller den kodade byteströmmen, lämplig att skicka till ett strömnings- eller nätverksanrop utan att någonsin röra filsystemet. Var och en passar olika tillämpningar; båda bygger på samma komprimeringsmotor under huven.
5.32.1. Spara till en fil¶
save() skriver bilden till filsystemet på en sökväg:
img.save("/sdcard/capture.jpg")
img.save("/sdcard/capture.bmp")
img.save("/sdcard/region.jpg", roi=(40, 60, 200, 150), quality=85)
Formatet väljs utifrån filändelsen. Fem ändelser känns igen: .bmp skriver en Windows-bitmapp (förlustfri, ingen komprimering, byte-för-byte de infångade pixlarna); .pgm skriver en portable graymap (förlustfri, endast gråskala); .ppm skriver en portable pixmap (förlustfri, RGB); .jpg och .jpeg skriver båda en JPEG (förlustbehäftad, komprimerad). Mottagarbilden måste redan vara i rätt färgformat för den valda behållaren – en färgbild sparad som .pgm är ett fel.
roi begränsar sparandet till en delrektangel av bilden, på samma sätt som varje annan image-modulmetods roi-nyckelord gör. Standardvärdet är hela bilden. Nyckelordet ignoreras när en JPEG-komprimerad bild sparas, eftersom formen på disken redan täcker hela bildrutan och en omkodning genom en beskärning skulle motverka syftet med att spara de befintliga komprimerade byten.
quality är JPEG-komprimeringskvaliteten från 0 till 100 och är endast meningsfull när utdata är JPEG (nyckelordet ignoreras för de förlustfria formaten). Standardvärdet 50 är rätt balans för de flesta tillämpningar; 70 till 85 är bandet för högre visuell kvalitet, 30 till 50 är rätt intervall för små miniatyrer och bandbreddsbegränsad överföring, och 90 och uppåt är reserverat för fall där bilden ska granskas manuellt eller köras genom en efterföljande algoritm som är känslig för komprimeringsartefakter.
Mottagarbilden returneras så att anropet kan kedjas: img.save("/sdcard/x.jpg").draw_string(0, 0, "saved"). Det returnerade objektet är samma bild i minnet; sparandet är en sidoeffekt.
En typisk användning är mönstret fånga-och-logga. En utlösare aktiveras (en blob detekteras, en knapp trycks ned, en timer löper ut); skriptet fångar en bildruta; det lägger till en tidsstämpel i filnamnet; och det anropar save() för att skicka bilden till SD-kortet. IDE:ns förhandsvisning fortsätter köra, nästa utlösare aktiveras, och de sparade filerna ackumuleras.
5.32.2. Koda till minne¶
När destinationen inte är filsystemet utan en nätverksanslutning, en seriell port eller en annan moduls indata, behöver tillämpningen den kodade byteströmmen i minnet snarare än på disk. to_jpeg() och to_png() producerar precis det:
encoded = img.to_jpeg(quality=80, copy=True)
bytes_to_send = encoded.bytearray()
sock.send(bytes_to_send)
Standardbeteendet är konvertering på plats: mottagaren konverteras till en JPEG-bild (eller PNG-bild) och samma objekt returneras. Med copy=True skriver konverteringen till ett nyallokerat heap-objekt; med copy_to_fb=True hamnar utdata i bildbufferten. Valet är samma som varje annan konverteringsmetod erbjuder – på plats som standard, kopiera när originalet behövs efteråt.
quality och subsampling är samma JPEG-justeringsrattar som spara-vägen erbjuder. subsampling väljer schemat för krominans-subsampling: image.JPEG_SUBSAMPLING_AUTO väljer det bästa för den valda kvaliteten, image.JPEG_SUBSAMPLING_444 håller krominansen i full upplösning (störst fil, bäst färgnoggrannhet), image.JPEG_SUBSAMPLING_422 och image.JPEG_SUBSAMPLING_420 halverar krominansupplösningen längs en eller båda axlarna (mindre filer, en lätt färguppmjukning som är osynlig på typiska betraktningsavstånd). Standardvärdet AUTO är rätt val om inte tillämpningen har ett specifikt behov.
PNG via to_png() är förlustfritt men långsammare att koda och producerar större filer än JPEG för fotografiskt innehåll (fotografiskt innehåll komprimeras dåligt under PNG:s prediktionsschema). Använd PNG när bilden är streckteckning, en skärmbild eller innehåller hårdkantad grafik ritad över en infångad bildruta – den förlustfria kodningen bevarar de skarpa kanter som JPEG skulle mjuka upp. Annars är JPEG rätt standardval.
Både to_jpeg() och to_png() accepterar samma rit-positions- och skalnyckelord som andra konverteringsmetoder tar – x_scale, y_scale, roi, rgb_channel, alpha, color_palette, alpha_palette, hint – så samma anrop kan koda en skalad, beskuren eller palettmappad version av källan i ett steg. compress() är den äldre stavningen av to_jpeg(); de två tar samma argument och ger samma resultat.
5.32.3. Vad komprimering ger¶
Siffrorna bakom avvägningen mellan JPEG och rådata är värda att gå igenom en gång.
En 320-gånger-240 RGB565-bildruta är 153 600 byte (en infångad bildruta vid QVGA). En 640-gånger-480-bildruta är 614 400 byte; en 1280-gånger-960-bildruta är 2 457 600 byte. Inget av dessa är stort jämfört med en skrivbords- eller telefonskärm, men de är betydande i sammanhanget av en kamera som har några MB RAM totalt, ett SD-kort med en ändlig skrivbandbredd, och en värdlänk som vanligtvis körs över USB CDC, en UART eller en trådlös modul vid blygsamma hastigheter.
JPEG vid quality=50 komprimerar vanligtvis en fotografisk infångad bildruta med 10x till 20x: den 614 KB stora 640-gånger-480-bildrutan blir en kodad byteström på 30 till 60 KB. Vid quality=85 sjunker komprimeringen till 5x till 10x (60 till 120 KB för samma bildruta). Vid quality=10 – artefaktfylld men fortfarande igenkännbar – når komprimeringen 30x till 50x (12 till 20 KB).
Dessa siffror avgör vad som är praktiskt att göra med de sparade bildrutorna. En SD-kortsväg som upprätthåller 10 MB/s hanterar 30 bildrutor per sekund av quality=50 JPEG-kodat VGA-innehåll med marginal (omkring 1 till 2 MB/s); att spara samma innehåll okomprimerat kräver över 18 MB/s, mer än vad kamerans filsystemsväg upprätthåller mot kortet. En USB-värd som hämtar JPEG-kodade bildrutor över CDC vid 1 MB/s tar emot 30 till 60 KB-bildrutor vid ungefär 15 till 30 bildrutor per sekund; om den hämtar råa bildrutor i samma takt får den en eller två bildrutor per sekund.
Kort sagt: komprimeringsmetoderna är inte bara en bekvämlighet för att spara. De är vad som gör den infångade bildrutan användbar utanför kameran vid bildhastigheter som tillämpningen bryr sig om. Att välja rätt komprimering – JPEG-kvalitet 50 för allmän loggning, 80 för kvalitetsarbete, PNG för streckteckningsfångst – är en del av det rutinmässiga arbetet i varje icke-trivial kameratillämpning.