5.21. Skala, vänd och beskär

De föregående underavsnitten arbetade alla på pixlar på samma positioner som de startade i. Transform-familjen ändrar på det. Skalning skickar varje indatapixel till en annan utdataposition, möjligen till flera utdatapositioner samtidigt (vid uppskalning) eller till en position som delas med flera andra indatapixlar (vid nedskalning). Vändning och rotation gör samma sak genom en annan avbildning. Beskärning behåller en rektangulär delmängd av indatapixlar och kasserar resten.

Bildmodulen exponerar den familjen genom tre metoder som delar de flesta av sina argument och det mesta av sitt beteende:

  • copy() – producera en kopia av bilden, eventuellt skalad, beskuren eller omorienterad.

  • crop() – samma operation som copy, men med förväntningen att applikationen ska plocka ut en delrektangel ur källan.

  • scale() – samma igen, med förväntningen att applikationen ska ändra storlek på resultatet.

De tre delar samma argument och samma transformmaskineri; skillnaden är var resultatet hamnar som standard. copy() producerar en ny bild, medan crop() och scale() modifierar källan på plats.

5.21.1. De delade argumenten

Ett enda anrop kombinerar vilken kombination av skalning, beskärning, orientering och kanalextraktion som applikationen än begär:

x_scale och y_scale skalar indata längs den horisontella respektive vertikala axeln oberoende av varandra. Båda har standardvärdet 1.0 (ingen skalning). Olika värden för var och en ger en icke-uniform skalning – en bildruta som sträcks ut dubbelt så bred som den är hög, till exempel.

roi begränsar indata till en rektangel av källbilden och tar endast med de pixlarna genom resten av transformationen. Detta är ”beskärningsdelen” av operationen: skicka med en roi för att extrahera en delregion.

hint är ett bitfält av flaggor som väljer interpolationsmetod och eventuella orienteringsvändningar. Flera flaggor kombineras genom bitvis OR (hint=image.BILINEAR | image.HMIRROR). Flaggorna delas in i två grupper – interpolations-familjen och orienterings-familjen – som inte har något med varandra att göra men delar samma bitfält.

rgb_channel väljer en enskild kanal av en RGB565-källa. 0 betyder röd, 1 betyder grön, 2 betyder blå; resultatet kommer ut som en gråskalebild som endast innehåller den kanalen. Användbart för tröskling enbart på den röda kanalen, till exempel.

color_palette och alpha_palette mappar om pixelvärden genom en uppslagstabell på vägen ut, på samma sätt som konverteringsmetoderna to_rainbow() och to_ironbow() gör.

copy=True och copy_to_fb=True följer samma konvention som varje annan resultatproducerande metod använder – på plats som standard, copy=True allokerar ett separat resultat, copy_to_fb=True placerar resultatet i bildbufferten för IDE-förhandsgranskningen.

5.21.2. Interpolation: AREA, BILINEAR, BICUBIC

När skalning skickar varje utdatapixel till en position som inte sammanfaller med någon enskild indatapixel måste metoden välja vilket värde som ska skrivas. Tre flaggor styr hur:

image.BILINEAR interpolerar mellan de fyra närmaste indatapixlarna viktade efter sitt avstånd från utdatapositionen. Resultatet är jämnare än närmaste granne, utan synliga taggar på diagonala linjer, men den extra aritmetiken kostar omkring fyra gånger så mycket som genomgången med närmaste granne. Det rätta valet för det mesta uppskalningsarbetet och för alla icke-heltaliga skalfaktorer.

image.BICUBIC interpolerar mellan de sexton närmaste indatapixlarna med hjälp av en kubisk kurva, vilket ger ännu jämnare resultat till priset av ännu mer aritmetik. Bästa kvalitet för de kostnadskänsliga applikationer som behöver det; sällan värt den extra beräkningen för live-bildrutor som IDE:n bara kommer att visa.

image.AREA beräknar medelvärdet av varje indatapixel som faller inom utdatapixelns yta – den rätta algoritmen för nedskalning. Bilinjär och bikubisk är interpolatorer: de uppskattar ett värde mellan källpixlar, vilket är vad uppskalning behöver, men vid nedskalning täcker varje utdatapixel många källpixlar och en interpolator läser bara de få närmaste – detaljerna den hoppar över kommer tillbaka som vikning. image.AREA vägar i stället in varje täckt pixel i medelvärdet.

Standardskalningsalgoritmen utan någon hint är närmaste granne, vilket är den billigaste och det rätta svaret när källan redan har destinationens pixelupplösning.

5.21.3. Orientering: vändningar och rotationer

Orienteringsflaggorna är en liten uppsättning booleska transformationer som komponeras fritt med varandra och med interpolationsflaggorna:

  • image.VFLIP vänder bilden vertikalt (toppen blir botten).

  • image.HMIRROR speglar den horisontellt (vänster blir höger).

  • image.TRANSPOSE byter plats på x- och y-axlarna (rader blir kolumner).

De flesta rotationer kommer från att komponera dessa tre. Modulen exponerar även namngivna genvägar:

  • image.ROTATE_90 (= VFLIP | TRANSPOSE)

  • image.ROTATE_180 (= HMIRROR | VFLIP)

  • image.ROTATE_270 (= HMIRROR | TRANSPOSE)

I kod:

img.copy(hint=image.ROTATE_90, copy_to_fb=True)

5.21.4. Hantering av bildförhållande

När källans bildförhållande inte matchar rektangeln den ritas in i, avgör tre flaggor vad som ska göras med skillnaden:

image.SCALE_ASPECT_KEEP bevarar källans bildförhållande och letterboxar resultatet – källan skalas tills den får plats inuti destinationen, med tomma (noll) pixlar som fyller ut resten av destinationen. Det rätta valet när det är viktigare att hålla källan oförvrängd än att fylla hela utdatan.

image.SCALE_ASPECT_EXPAND bevarar källans bildförhållande och beskär den – källan skalas tills den fyller destinationen, med de delar som sträcker sig utanför destinationen bortklippta. Det rätta valet när det är viktigare att fylla hela utdatan än att se varje del av källan.

image.SCALE_ASPECT_IGNORE ignorerar bildförhållandet och sträcker ut källan så att den fyller destinationen, och accepterar vilken förvrängning det än medför. Det rätta valet när applikationen redan har tagit hänsyn till förvrängningen – när destinationens dimensioner i själva verket inte är en rektangel av samma scen, till exempel.

Standardvärdet (ingen bildförhållandeflagga satt) är detsamma som SCALE_ASPECT_IGNORE: sträck ut för att fylla. Applikationer som bryr sig om bildförhållande anger uttryckligen en av de tre.

5.21.5. När man ska välja vilken

De flesta storleksändringar använder scale() med ett par x_scale / y_scale och en interpolations-hint:

img.scale(x_scale=0.5, y_scale=0.5, hint=image.AREA)

De flesta rotationer använder samma anrop med hint=image.ROTATE_90 eller liknande.

Beskärning använder crop() med en icke-standard roi:

img.crop(roi=(40, 30, 200, 150))

När källan måste överleva operationen – att fånga en referensbildruta, att ta en miniatyrbild av en bildruta som är på väg att behandlas destruktivt – producerar copy() resultatet som en ny bild och lämnar källan orörd:

thumbnail = img.copy(x_scale=0.25, y_scale=0.25, hint=image.AREA)

Det standardbeteendet är den verkliga skillnaden bakom de tre namnen: scale och crop transformerar på plats, copy allokerar. Nyckelorden för resultatplacering överbryggar gapet: copy=Truescale eller crop allokerar resultatet som en separat heap-buffert i stället för att skriva över källan, och copy_to_fb=True på någon av de tre placerar det i bildbufferten för IDE-förhandsgranskningen.