5.21. Změna měřítka, převrácení a oříznutí

Všechny předchozí podkapitoly pracovaly s pixely na stejných pozicích, kde začínaly. Rodina transformací to mění. Změna měřítka posílá každý vstupní pixel na jinou výstupní pozici, případně na několik výstupních pozic najednou (při zvětšování) nebo na pozici sdílenou s několika dalšími vstupními pixely (při zmenšování). Převracení a otáčení dělají totéž prostřednictvím jiného mapování. Oříznutí zachovává obdélníkovou podmnožinu vstupních pixelů a zbytek zahazuje.

Modul image tuto rodinu zpřístupňuje prostřednictvím tří metod, které sdílejí většinu svých argumentů a většinu svého chování:

  • copy() – vytvoří kopii obrazu, případně se změněným měřítkem, oříznutou nebo přeorientovanou.

  • crop() – stejná operace jako copy, ale s předpokladem, že aplikace ze zdroje vybere podobdélník.

  • scale() – opět totéž, s předpokladem, že aplikace změní velikost výsledku.

Tyto tři metody sdílejí stejné argumenty a stejnou transformační mechaniku; rozdíl je v tom, kam výsledek ve výchozím nastavení míří. copy() vytváří nový obraz, zatímco crop() a scale() upravují zdroj na místě.

5.21.1. Sdílené argumenty

Jediné volání kombinuje libovolnou kombinaci změny měřítka, oříznutí, orientace a extrakce kanálu, o kterou aplikace požádá:

x_scale a y_scale mění měřítko vstupu podél vodorovné a svislé osy nezávisle. Obě mají výchozí hodnotu 1.0 (žádná změna měřítka). Různé hodnoty pro každou z nich produkují nerovnoměrnou změnu měřítka – například snímek roztažený dvakrát na šířku oproti výšce.

roi omezuje vstup na obdélník zdrojového obrazu a do zbytku transformace propouští pouze tyto pixely. To je část operace zvaná „oříznutí“: předáním roi se extrahuje podoblast.

hint je bitové pole příznaků, které vybírá interpolační metodu a případné převrácení orientace. Více příznaků se kombinuje pomocí bitového OR (hint=image.BILINEAR | image.HMIRROR). Příznaky se dělí do dvou skupin – rodiny interpolace a rodiny orientace – které spolu nemají nic společného, ale sdílejí stejné bitové pole.

rgb_channel vybírá jediný kanál zdroje RGB565. 0 znamená červenou, 1 znamená zelenou, 2 znamená modrou; výsledek vychází jako obraz ve stupních šedi obsahující pouze tento kanál. Užitečné například pro prahování pouze na červeném kanálu.

color_palette a alpha_palette přemapovávají hodnoty pixelů na výstupu prostřednictvím vyhledávací tabulky, stejným způsobem jako to dělají konverzní metody to_rainbow() a to_ironbow().

copy=True a copy_to_fb=True dodržují stejnou konvenci, kterou používá každá jiná metoda produkující výsledek – na místě ve výchozím nastavení, copy=True alokuje samostatný výsledek, copy_to_fb=True umístí výsledek do snímkového bufferu (frame buffer) pro náhled v IDE.

5.21.2. Interpolace: AREA, BILINEAR, BICUBIC

Když změna měřítka posílá každý výstupní pixel na pozici, která se nezarovnává s žádným jediným vstupním pixelem, musí metoda vybrat, jakou hodnotu zapsat. Jak na to, řídí tři příznaky:

image.BILINEAR interpoluje mezi čtyřmi nejbližšími vstupními pixely vážené jejich vzdáleností od výstupní pozice. Výsledek je hladší než nejbližší soused, bez viditelného zubatění na šikmých čarách, ale aritmetika navíc stojí zhruba čtyřnásobek průchodu metodou nejbližšího souseda. Správná volba pro většinu zvětšování a pro jakýkoli neceločíselný činitel měřítka.

image.BICUBIC interpoluje mezi šestnácti nejbližšími vstupními pixely pomocí kubické křivky, což produkuje ještě hladší výsledky za cenu opět vyšší náročnosti na aritmetiku. Nejlepší kvalita pro nákladově citlivé aplikace, které ji potřebují; pro živé snímky, které IDE pouze zobrazí, zřídka stojí za výpočet navíc.

image.AREA zprůměruje každý vstupní pixel, který spadá do plochy výstupního pixelu – správný algoritmus pro zmenšování. Bilineární a bikubická jsou interpolátory: odhadují hodnotu mezi zdrojovými pixely, což je to, co zvětšování potřebuje, ale při zmenšování každý výstupní pixel pokrývá mnoho zdrojových pixelů a interpolátor přečte jen těch několik nejbližších – detail, který přeskočí, se vrátí jako aliasing. image.AREA místo toho zahrne každý pokrytý pixel do průměru.

Výchozí algoritmus změny měřítka bez jakéhokoli příznaku je nejbližší soused, což je nejlevnější a správná odpověď, když je zdroj již v pixelovém rozlišení cíle.

5.21.3. Orientace: převrácení a otočení

Příznaky orientace jsou malá sada booleovských transformací, které se volně skládají mezi sebou navzájem i s příznaky interpolace:

  • image.VFLIP převrací obraz svisle (horní část se stává spodní).

  • image.HMIRROR jej zrcadlí vodorovně (levá strana se stává pravou).

  • image.TRANSPOSE prohazuje osy x a y (řádky se stávají sloupci).

Většina otočení vzniká skládáním těchto tří. Modul také zpřístupňuje pojmenované zkratky:

  • image.ROTATE_90 (= VFLIP | TRANSPOSE)

  • image.ROTATE_180 (= HMIRROR | VFLIP)

  • image.ROTATE_270 (= HMIRROR | TRANSPOSE)

V kódu:

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

5.21.4. Zacházení s poměrem stran

Když poměr stran zdroje neodpovídá obdélníku, do kterého se vykresluje, rozhodují o tom, co s tímto nesouladem udělat, tři příznaky:

image.SCALE_ASPECT_KEEP zachovává poměr stran zdroje a výsledek letterboxuje – zdroj se zmenšuje, dokud se nevejde do cíle, přičemž zbytek cíle vyplňují prázdné (nulové) pixely. Správná volba, když je zachování nezkresleného zdroje důležitější než vyplnění celého výstupu.

image.SCALE_ASPECT_EXPAND zachovává poměr stran zdroje a ořezává jej – zdroj se zvětšuje, dokud nevyplní cíl, přičemž části, které přesahují cíl, jsou odříznuty. Správná volba, když je vyplnění celého výstupu důležitější než vidět každou část zdroje.

image.SCALE_ASPECT_IGNORE ignoruje poměr stran a roztáhne zdroj tak, aby vyplnil cíl, a přijímá jakékoli zkreslení, které to způsobí. Správná volba, když aplikace již se zkreslením počítá – například když rozměry cíle ve skutečnosti nejsou obdélníkem téže scény.

Výchozí chování (žádný nastavený příznak poměru stran) je stejné jako SCALE_ASPECT_IGNORE: roztáhnout, aby se vyplnilo. Aplikace, kterým záleží na poměru stran, výslovně určí jeden ze tří.

5.21.5. Kdy sáhnout po které

Většina změn velikosti používá scale() s dvojicí x_scale / y_scale a interpolačním hintem:

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

Většina otočení používá stejné volání s hint=image.ROTATE_90 nebo podobným.

Oříznutí používá crop() s nevýchozím roi:

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

Když musí zdroj operaci přežít – zachycení referenčního snímku, pořízení náhledu snímku, který se chystá být destruktivně zpracován – copy() produkuje výsledek jako nový obraz a zdroj nechává nedotčený:

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

Tímto výchozím nastavením je skutečný rozdíl za třemi názvy: scale a crop transformují na místě, copy alokuje. Klíčová slova pro umístění výsledku tento rozdíl překlenují: copy=True u scale nebo crop alokuje výsledek jako samostatný buffer na haldě namísto přepsání zdroje a copy_to_fb=True u kterékoli ze tří jej umístí do snímkového bufferu (frame buffer) pro náhled v IDE.