5.21. Scalare, oglindire și decupare¶
Subsecțiunile anterioare au lucrat toate pe pixeli aflați în aceleași poziții în care au început. Familia de transformări schimbă acest lucru. Scalarea trimite fiecare pixel de intrare la o poziție de ieșire diferită, posibil la mai multe poziții de ieșire deodată (la mărire) sau la o poziție partajată cu mai mulți alți pixeli de intrare (la micșorare). Oglindirea și rotația fac același lucru printr-o mapare diferită. Decuparea păstrează un subset dreptunghiular de pixeli de intrare și îl elimină pe restul.
Modulul image expune această familie prin trei metode care împart majoritatea argumentelor și a comportamentului:
copy()– produce o copie a imaginii, eventual scalată, decupată sau reorientată.crop()– aceeași operație cacopy, dar cu așteptarea că aplicația va selecta un sub-dreptunghi din sursă.scale()– același lucru, cu așteptarea că aplicația va redimensiona rezultatul.
Cele trei împart aceleași argumente și aceeași mecanică de transformare; diferența este unde ajunge rezultatul în mod implicit. copy() produce o imagine nouă, în timp ce crop() și scale() modifică sursa pe loc.
5.21.2. Interpolare: AREA, BILINEAR, BICUBIC¶
Atunci când scalarea trimite fiecare pixel de ieșire la o poziție care nu se aliniază cu niciun pixel de intrare anume, metoda trebuie să aleagă ce valoare să scrie. Trei indicatori controlează modul:
image.BILINEAR interpolează între cei patru pixeli de intrare cei mai apropiați ponderați după distanța lor față de poziția de ieșire. Rezultatul este mai neted decât cel cu vecinul cel mai apropiat, fără zimți vizibili pe liniile diagonale, dar aritmetica suplimentară costă de aproximativ patru ori cât trecerea cu vecinul cel mai apropiat. Alegerea potrivită pentru majoritatea lucrărilor de mărire și pentru orice factor de scară neîntreg.
image.BICUBIC interpolează între cei șaisprezece pixeli de intrare cei mai apropiați folosind o curbă cubică, ceea ce produce rezultate și mai netede cu prețul unei aritmetici suplimentare. Cea mai bună calitate pentru aplicațiile sensibile la cost care au nevoie de ea; rareori merită calculul suplimentar pentru cadre live pe care IDE-ul le va doar afișa.
image.AREA mediază fiecare pixel de intrare care cade în interiorul amprentei pixelului de ieșire – algoritmul potrivit pentru micșorare. Interpolarea biliniară și cea bicubică sunt interpolatoare: ele estimează o valoare între pixelii sursă, ceea ce are nevoie mărirea, dar la micșorare fiecare pixel de ieșire acoperă mulți pixeli sursă, iar un interpolator citește doar pe cei câțiva mai apropiați – detaliul pe care îl omite revine ca aliere. image.AREA integrează în schimb fiecare pixel acoperit în medie.
Algoritmul de scalare implicit, fără niciun indiciu, este vecinul cel mai apropiat, care este cel mai ieftin și răspunsul corect atunci când sursa este deja la rezoluția de pixeli a destinației.
5.21.3. Orientare: oglindiri și rotații¶
Indicatorii de orientare sunt un set mic de transformări booleene care se compun liber între ele și cu indicatorii de interpolare:
image.VFLIPoglindește imaginea vertical (partea de sus devine partea de jos).image.HMIRRORo oglindește orizontal (stânga devine dreapta).image.TRANSPOSEinterschimbă axele x și y (rândurile devin coloane).
Majoritatea rotațiilor provin din compunerea acestor trei. Modulul expune de asemenea scurtături denumite:
image.ROTATE_90(=VFLIP | TRANSPOSE)image.ROTATE_180(=HMIRROR | VFLIP)image.ROTATE_270(=HMIRROR | TRANSPOSE)
În cod:
img.copy(hint=image.ROTATE_90, copy_to_fb=True)
5.21.4. Tratarea raportului de aspect¶
Atunci când raportul de aspect al sursei nu se potrivește cu dreptunghiul în care este desenată, trei indicatori decid ce să facă cu nepotrivirea:
image.SCALE_ASPECT_KEEP păstrează raportul de aspect al sursei și adaugă benzi negre rezultatului – sursa este scalată până când încape în interiorul destinației, cu pixeli goi (zero) umplând restul destinației. Alegerea potrivită atunci când păstrarea sursei nedistorsionate contează mai mult decât umplerea întregii ieșiri.
image.SCALE_ASPECT_EXPAND păstrează raportul de aspect al sursei și o decupează – sursa este scalată până când umple destinația, cu părțile care depășesc destinația tăiate. Alegerea potrivită atunci când umplerea întregii ieșiri contează mai mult decât vizualizarea fiecărei părți a sursei.
image.SCALE_ASPECT_IGNORE ignoră raportul de aspect și întinde sursa pentru a umple destinația, acceptând orice distorsiune introduce acest lucru. Alegerea potrivită atunci când aplicația a ținut deja cont de distorsiune – de exemplu, când dimensiunile destinației nu sunt de fapt un dreptunghi al aceleiași scene.
Valoarea implicită (fără niciun indicator de aspect setat) este aceeași cu SCALE_ASPECT_IGNORE: întindere pentru umplere. Aplicațiile cărora le pasă de raportul de aspect specifică explicit unul dintre cele trei.
5.21.5. Când să recurgeți la fiecare¶
Majoritatea redimensionărilor folosesc scale() cu o pereche x_scale / y_scale și un indiciu de interpolare:
img.scale(x_scale=0.5, y_scale=0.5, hint=image.AREA)
Majoritatea rotațiilor folosesc același apel cu hint=image.ROTATE_90 sau similar.
Decuparea folosește crop() cu un roi neimplicit:
img.crop(roi=(40, 30, 200, 150))
Atunci când sursa trebuie să supraviețuiască operației – la capturarea unui cadru de referință, la realizarea unei miniaturi a unui cadru care urmează să fie procesat distructiv – copy() produce rezultatul ca o imagine nouă și lasă sursa neatinsă:
thumbnail = img.copy(x_scale=0.25, y_scale=0.25, hint=image.AREA)
Acea valoare implicită este diferența reală din spatele celor trei nume: scale și crop transformă pe loc, copy alocă. Cuvintele-cheie de plasare a rezultatului fac legătura: copy=True pe scale sau crop alocă rezultatul ca un tampon separat din heap în loc să suprascrie sursa, iar copy_to_fb=True pe oricare dintre cele trei îl plasează în tamponul de cadre (frame buffer) pentru previzualizarea din IDE.