5.21. Skálázás, tükrözés és körbevágás

Az előző alfejezetek mind olyan képpontokon dolgoztak, amelyek ugyanazon a pozíción maradtak, ahol kezdtek. A transzformáció család ezen változtat. A skálázás minden bemeneti képpontot egy másik kimeneti pozícióra küld, esetleg egyszerre több kimeneti pozícióra (felskálázáskor) vagy egy több másik bemeneti képponttal megosztott pozícióra (leskálázáskor). A tükrözés és a forgatás ugyanezt teszi egy másfajta leképezéssel. A körbevágás megtartja a bemeneti képpontok egy téglalap alakú részhalmazát, a többit pedig elveti.

Az image modul ezt a családot három metóduson keresztül teszi elérhetővé, amelyek argumentumaik és viselkedésük nagy részén osztoznak:

  • copy() – a kép egy másolatának előállítása, esetleg skálázva, körbevágva vagy újraorientálva.

  • crop() – ugyanaz a művelet, mint a copy, de azzal a várakozással, hogy az alkalmazás egy al-téglalapot fog kiválasztani a forrásból.

  • scale() – ismét ugyanaz, azzal a várakozással, hogy az alkalmazás át fogja méretezni az eredményt.

A három ugyanazokon az argumentumokon és ugyanazon a transzformációs mechanizmuson osztozik; a különbség az, hogy alapértelmezés szerint hová kerül az eredmény. A copy() egy új képet állít elő, míg a crop() és a scale() helyben módosítja a forrást.

5.21.1. A közös argumentumok

Egyetlen hívás kombinálja a skálázás, körbevágás, orientáció és csatornakinyerés bármely kombinációját, amelyet az alkalmazás kér:

Az x_scale és az y_scale a bemenetet a vízszintes és függőleges tengely mentén egymástól függetlenül skálázza. Mindkettő alapértelmezett értéke 1.0 (nincs skálázás). Eltérő értékek nem egyenletes skálázást eredményeznek – például egy kétszer olyan szélesre nyújtott képkockát, mint amilyen magas.

A roi a bemenetet a forráskép egy téglalapjára korlátozza, csak azokat a képpontokat engedve tovább a transzformáció többi részén. Ez a művelet „körbevágás” része: adj meg egy roi értéket egy al-régió kinyeréséhez.

A hint egy jelzőbitekből álló bitmező, amely kiválasztja az interpolációs módszert és az esetleges orientációs tükrözéseket. Több jelzőbit bitenkénti VAGY művelettel kombinálható (hint=image.BILINEAR | image.HMIRROR). A jelzőbitek két csoportra oszlanak – az interpolációs családra és az orientációs családra –, amelyeknek semmi közük egymáshoz, de ugyanazon a bitmezőn osztoznak.

Az rgb_channel egy RGB565 forrás egyetlen csatornáját választja ki. A 0 a vöröset, az 1 a zöldet, a 2 a kéket jelenti; az eredmény egy szürkeárnyalatos képként jön ki, amely csak az adott csatornát tartalmazza. Hasznos például, ha csak a vörös csatornán szeretnél küszöbölni.

A color_palette és az alpha_palette kimenet közben egy keresőtáblán keresztül képezi le a képpontértékeket, ugyanúgy, ahogy a to_rainbow() és a to_ironbow() átalakító metódusok teszik.

A copy=True és a copy_to_fb=True ugyanazt a konvenciót követi, mint minden más eredményt előállító metódus – alapértelmezés szerint helyben, a copy=True külön eredményt foglal le, a copy_to_fb=True pedig a képkocka-pufferbe helyezi az eredményt az IDE előnézetéhez.

5.21.2. Interpoláció: AREA, BILINEAR, BICUBIC

Amikor a skálázás minden kimeneti képpontot egy olyan pozícióra küld, amely nem illeszkedik egyetlen bemeneti képponthoz sem, a metódusnak el kell döntenie, milyen értéket írjon oda. Három jelzőbit szabályozza, hogyan:

Az image.BILINEAR a négy legközelebbi bemeneti képpont között interpolál, a kimeneti pozíciótól mért távolságukkal súlyozva. Az eredmény simább, mint a legközelebbi szomszéd módszeré, az átlós vonalakon nincsenek látható lépcsőzöttségek, de a többletszámítás körülbelül négyszer annyiba kerül, mint a legközelebbi szomszéd menet. Ez a megfelelő választás a legtöbb felskálázási munkához és bármilyen nem egész skálázási tényezőhöz.

Az image.BICUBIC a tizenhat legközelebbi bemeneti képpont között interpolál egy köbös görbe segítségével, ami még simább eredményeket állít elő, ismét több számítás árán. A legjobb minőség azokhoz a költségérzékeny alkalmazásokhoz, amelyeknek szükségük van rá; ritkán éri meg a többletszámítást olyan élő képkockáknál, amelyeket az IDE csak megjelenít.

Az image.AREA minden olyan bemeneti képpontot átlagol, amely a kimeneti képpont lefedettségébe esik – ez a leskálázáshoz való helyes algoritmus. A bilineáris és a bikubikus interpolátorok: egy értéket becsülnek a forrásképpontok között, amire a felskálázásnak szüksége van, de leskálázáskor minden kimeneti képpont sok forrásképpontot fed le, és egy interpolátor csak a néhány legközelebbit olvassa be – a kihagyott részlet aliasingként tér vissza. Az image.AREA ehelyett minden lefedett képpontot beleszámol az átlagba.

Az alapértelmezett skálázási algoritmus bármilyen hint nélkül a legközelebbi szomszéd módszer, amely a legolcsóbb, és a helyes válasz, amikor a forrás már a cél képpont-felbontásán van.

5.21.3. Orientáció: tükrözések és forgatások

Az orientációs jelzőbitek logikai transzformációk egy kis halmaza, amelyek szabadon kombinálódnak egymással és az interpolációs jelzőbitekkel:

  • Az image.VFLIP függőlegesen tükrözi a képet (a teteje lent lesz).

  • Az image.HMIRROR vízszintesen tükrözi azt (a bal jobbra kerül).

  • Az image.TRANSPOSE felcseréli az x és y tengelyt (a sorok oszlopokká válnak).

A legtöbb forgatás e három kombinálásából származik. A modul elnevezett rövidítéseket is elérhetővé tesz:

  • image.ROTATE_90 (= VFLIP | TRANSPOSE)

  • image.ROTATE_180 (= HMIRROR | VFLIP)

  • image.ROTATE_270 (= HMIRROR | TRANSPOSE)

Kódban:

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

5.21.4. Képarány kezelése

Amikor a forrás képaránya nem egyezik azzal a téglalappal, amelybe rajzolják, három jelzőbit dönti el, mit kell tenni az eltéréssel:

Az image.SCALE_ASPECT_KEEP megőrzi a forrás képarányát és letterbox jelleggel jeleníti meg az eredményt – a forrás addig skálázódik, amíg el nem fér a célon belül, a cél többi részét üres (nulla) képpontok töltik ki. Ez a megfelelő választás, amikor a forrás torzítatlanul tartása fontosabb, mint a teljes kimenet kitöltése.

Az image.SCALE_ASPECT_EXPAND megőrzi a forrás képarányát és körbevágja azt – a forrás addig skálázódik, amíg ki nem tölti a célt, a célon túlnyúló részeket levágja. Ez a megfelelő választás, amikor a teljes kimenet kitöltése fontosabb, mint a forrás minden részének láthatósága.

Az image.SCALE_ASPECT_IGNORE figyelmen kívül hagyja a képarányt, és a forrást a cél kitöltéséig nyújtja, elfogadva az ezzel járó torzítást. Ez a megfelelő választás, amikor az alkalmazás már számolt a torzítással – például amikor a cél méretei valójában nem ugyanannak a jelenetnek a téglalapja.

Az alapértelmezés (nincs képaránybit beállítva) megegyezik a SCALE_ASPECT_IGNORE viselkedésével: nyújtás a kitöltéshez. Azok az alkalmazások, amelyeknek számít a képarány, kifejezetten megadják a három közül az egyiket.

5.21.5. Mikor melyiket válasszuk

A legtöbb átméretezés a scale() metódust használja egy x_scale / y_scale párral és egy interpolációs hinttel:

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

A legtöbb forgatás ugyanezt a hívást használja hint=image.ROTATE_90 vagy hasonló értékkel.

A körbevágás a crop() metódust használja egy nem alapértelmezett roi értékkel:

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

Amikor a forrásnak túl kell élnie a műveletet – egy referencia-képkocka rögzítésekor, egy olyan képkocka miniatűrjének elkészítésekor, amelyet hamarosan roncsoló módon dolgoznak fel – a copy() az eredményt új képként állítja elő, és a forrást érintetlenül hagyja:

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

Ez az alapértelmezés a valódi különbség a három név mögött: a scale és a crop helyben transzformál, a copy lefoglal. Az eredmény elhelyezését vezérlő kulcsszavak áthidalják a szakadékot: a copy=True a scale vagy a crop esetén az eredményt külön kupacpufferként foglalja le a forrás felülírása helyett, a copy_to_fb=True pedig a három bármelyikénél a képkocka-pufferbe helyezi azt az IDE előnézetéhez.