Folosesc elemente de pânză html5 pentru a redimensiona imaginile din browserul meu. Se pare că calitatea este foarte scăzută. Am găsit acest lucru: Dezactivați interpolare atunci când scalați un, dar nu ajută la creșterea calității.

Mai jos este codul meu css și js, precum și imaginea cu Photoshop și scalată în API-ul canvas.

Ce trebuie să fac pentru a obține o calitate optimă la scalarea unei imagini în browser?

Notă: Vreau să micșorez o imagine mare la una mică, să modific culoarea într-o pânză și să trimit rezultatul din pânză la server.

Imaginea redimensionată cu photoshop:

canvas

Imaginea redimensionată pe pânză:

Am încercat să fac downscaling în mai mulți pași, așa cum am propus în:

Aceasta este funcția pe care am folosit-o:

Iată rezultatul dacă folosesc o dimensiune în două trepte:

Iată rezultatul dacă folosesc o dimensionare cu 3 trepte:

Iată rezultatul dacă folosesc o dimensionare cu 4 trepte:

Iată rezultatul dacă folosesc o dimensionare cu 20 de trepte:

Notă: Se pare că de la 1 pas la 2 pași există o îmbunătățire majoră a calității imaginii, dar cu cât mai mulți pași adăugați procesului, cu atât imaginea devine mai neclară.

Există o modalitate de a rezolva problema prin care imaginea devine mai neclară cu cât mai mulți pași adăugați?

Edit 2013-10-04: Am încercat algoritmul GameAlchemist. Iată rezultatul în comparație cu Photoshop.

14 Răspunsuri 14

Deoarece problema dvs. este de a reduce imaginea, nu are rost să vorbiți despre interpolare - care este despre crearea de pixeli -. Problema aici este reducerea eșantionării.

Pentru a redimensiona o imagine, trebuie să transformăm fiecare pătrat de p * p pixeli din imaginea originală într-un singur pixel în imaginea de destinație.

Din motive de performanță, browserele fac o eșantionare foarte simplă: pentru a construi imaginea mai mică, vor alege doar un pixel în sursă și vor folosi valoarea acestuia pentru destinație. care „uită” câteva detalii și adaugă zgomot.

Cu toate acestea, există o excepție de la asta: din moment ce reducerea eșantionării imaginii 2X este foarte simplă de calculat (în medie 4 pixeli pentru a face unul) și este utilizată pentru pixeli retină/HiDPI, acest caz este tratat corect - browserul face uz de 4 pixeli pentru a face unu-.

DAR. dacă folosiți de mai multe ori un eșantionare de 2X, veți întâmpina problema că erorile succesive de rotunjire vor aduce prea mult zgomot.
Ce este mai rău, nu veți redimensiona întotdeauna cu o putere de două, iar redimensionarea la cea mai apropiată putere + o ultimă redimensionare este foarte zgomotoasă.

Ceea ce căutați este un eșantionare perfectă a pixelilor, adică o re-eșantionare a imaginii care va lua în considerare toți pixelii de intrare - indiferent de scară-.
Pentru a face acest lucru, trebuie să calculăm, pentru fiecare pixel de intrare, contribuția sa la unul, doi sau patru pixeli de destinație, în funcție de proiecția scalată a pixelilor de intrare, chiar în interiorul pixelilor de destinație, se suprapune peste o margine X, o margine Y sau ambele.
(O schemă ar fi frumoasă aici, dar nu am una.)

Iată un exemplu de scară a pânzei comparativ cu scara mea perfectă de pixeli pe scara 1/3 a unui zombat.

Observați că imaginea ar putea fi scalată în browserul dvs. și este .jpegizată de S.O...
Cu toate acestea, vedem că există mult mai puțin zgomot, mai ales în iarba din spatele wombatului și a ramurilor din dreapta acestuia. Zgomotul din blană îl face mai contrastat, dar se pare că are părul alb - spre deosebire de imaginea sursei-.
Imaginea corectă este mai puțin atrăgătoare, dar definitiv mai frumoasă.

Iată codul pentru a face redimensionarea perfectă a pixelilor:

Este destul de lacom de memorie, deoarece un buffer float este necesar pentru a stoca valorile intermediare ale imaginii de destinație (-> dacă numărăm pânza de rezultat, vom utiliza de 6 ori memoria imaginii sursă în acest algoritm).
De asemenea, este destul de scump, deoarece fiecare pixel sursă este utilizat indiferent de dimensiunea destinației și trebuie să plătim pentru getImageData/putImageDate, de asemenea destul de lent.
Dar nu există nicio modalitate de a fi mai rapid decât să procesați fiecare valoare sursă în acest caz, iar situația nu este atât de rea: pentru imaginea mea de 740 * 556 a unui wombat, procesarea durează între 30 și 40 ms.