Cum se configurează smartphone-uri și PC-uri. Portal informativ
  • Acasă
  • Erori
  • Ce metodă de compresie folosește algoritmul jpeg? JPEG se comprimă mai bine decât GIF

Ce metodă de compresie folosește algoritmul jpeg? JPEG se comprimă mai bine decât GIF

Este ușor de calculat că o imagine color necomprimată cu o dimensiune de 2000 * 1000 pixeli va avea o dimensiune de aproximativ 6 megaocteți. Dacă vorbim de imagini obținute de la camere profesionale sau scanere de înaltă rezoluție, atunci dimensiunea acestora poate fi și mai mare. În ciuda creșterii rapide a capacității dispozitivelor de stocare, diverși algoritmi de compresie a imaginii sunt încă foarte relevanți.
Toți algoritmii existenți pot fi împărțiți în două clase mari:

  • Algoritmi de compresie fără pierderi;
  • Algoritmi de compresie cu pierderi.
Când vorbim despre compresie fără pierderi, ne referim la faptul că există un algoritm invers al algoritmului de compresie care vă permite să restaurați cu acuratețe imaginea originală. Pentru algoritmi de compresie cu pierderi algoritm invers nu exista. Există un algoritm care restabilește o imagine care nu se potrivește neapărat cu cea originală. Algoritmii de compresie și recuperare sunt selectați pentru a obține un raport de compresie ridicat, menținând în același timp calitatea vizuală a imaginii.

Algoritmi de compresie fără pierderi

Algoritmul RLE
Toți algoritmii din seria RLE se bazează pe o idee foarte simplă: grupurile repetate de elemente sunt înlocuite cu o pereche (număr de repetări, element care se repetă). Să luăm în considerare acest algoritm folosind exemplul unei secvențe de biți. Această secvență va alterna grupuri de zerouri și unu. În plus, grupurile vor avea adesea mai mult de un element. Apoi, secvența 11111 000000 11111111 00 va corespunde următorului set de numere 5 6 8 2. Aceste numere indică numărul de repetări (numărarea începe de la unii), dar și aceste numere trebuie să fie codificate. Vom presupune că numărul de repetări variază de la 0 la 7 (adică 3 biți sunt suficienți pentru a codifica numărul de repetări). Apoi, secvența considerată mai sus este codificată de următoarea secvență de numere 5 6 7 0 1 2. Este ușor de calculat că sunt necesari 21 de biți pentru a codifica secvența originală, iar în cel comprimat metoda RLEÎn formă, această secvență are 18 biți.
Deși acest algoritm este foarte simplu, eficiența sa este relativ scăzută. Mai mult, în unele cazuri, utilizarea acestui algoritm nu duce la o scădere, ci la o creștere a lungimii secvenței. De exemplu, luați în considerare următoarea secvență 111 0000 11111111 00. Secvența RL corespunzătoare arată astfel: 3 4 7 0 1 2. Lungimea secvenței originale este de 17 biți, lungimea secvenței comprimate este de 18 biți.
Acest algoritm este cel mai eficient pentru imaginile alb-negru. De asemenea, este adesea folosit ca una dintre etapele intermediare de compresie a algoritmilor mai complexi.

Dicţionar algorithms

Ideea din spatele algoritmilor de dicționar este că lanțurile de elemente ale secvenței originale sunt codificate. Această codificare folosește un dicționar special, care este obținut pe baza secvenței originale.
Există o întreagă familie de algoritmi de dicționar, dar ne vom uita la cel mai comun algoritm LZW, numit după dezvoltatorii săi Lepel, Ziv și Welch.
Dicționarul din acest algoritm este un tabel care este umplut cu lanțuri de codare pe măsură ce algoritmul rulează. Când codul comprimat este decodat, dicționarul este restaurat automat, astfel încât nu este nevoie să transmiteți dicționarul împreună cu codul comprimat.
Dicționarul este inițializat cu toate șirurile singleton, adică. primele rânduri ale dicționarului reprezintă alfabetul în care codificăm. În timpul compresiei, se face o căutare pentru cel mai lung lanț deja înregistrat în dicționar. De fiecare dată când se întâlnește un lanț care nu a fost încă scris în dicționar, acesta este adăugat acolo și iese un cod comprimat corespunzător lanțului deja scris în dicționar. În teorie, nu sunt impuse restricții cu privire la dimensiunea dicționarului, dar în practică are sens să se limiteze această dimensiune, deoarece în timp încep să apară lanțuri care nu se mai regăsesc în text. În plus, atunci când dublem dimensiunea tabelului, trebuie să alocăm un bit în plus pentru a stoca coduri comprimate. Pentru a preveni astfel de situații, se introduce un cod special, simbolizând inițializarea tabelului cu toate lanțurile cu un singur element.
Să ne uităm la un exemplu de algoritm de compresie. Vom comprima linia cuccuckoocuckoohood. Să presupunem că dicționarul va conține 32 de poziții, ceea ce înseamnă că fiecare dintre codurile sale va ocupa 5 biți. Inițial, dicționarul este completat după cum urmează:

Acest tabel există atât de partea celui care comprimă informația, cât și de partea celui care o decomprimă. Acum ne vom uita la procesul de compresie.

Tabelul arată procesul de completare a dicționarului. Este ușor de calculat că codul comprimat rezultat durează 105 biți, iar textul original (presupunând că cheltuim 4 biți pentru codificarea unui caracter) are 116 biți.
În esență, procesul de decodare se reduce la decodarea directă a codurilor și este important ca tabelul să fie inițializat în același mod ca în timpul codificării. Acum să ne uităm la algoritmul de decodare.


Putem defini complet șirul adăugat în dicționar la pasul i-a doar la i+1. Evident, linia i-a trebuie să se termine cu primul caracter al liniei i+1. Acea. Tocmai ne-am dat seama cum să restabilim un dicționar. Un oarecare interes este situația în care o secvență de forma cScSc este codificată, unde c este un caracter și S este un șir, iar cuvântul cS este deja în dicționar. La prima vedere poate părea că decodorul nu va putea rezolva această situație, dar de fapt toate liniile de acest tip trebuie să se termine întotdeauna cu același caracter cu care încep.

Algoritmi de codare statistică
Algoritmii din această serie atribuie cel mai scurt cod comprimat celor mai frecvente elemente ale secvențelor. Acestea. secvențele de aceeași lungime sunt codificate cu coduri comprimate de lungimi diferite. Mai mult, cu cât apare mai des o secvență, cu atât codul comprimat corespunzător este mai scurt.
Algoritmul Huffman
Algoritmul Huffman vă permite să construiți coduri de prefix. Vă puteți gândi la codurile de prefix ca la căi către arbore binar: un pasaj de la un nod la copilul său din stânga corespunde unui 0 în cod, iar fiului său din dreapta corespunde unui 1. Dacă etichetăm frunzele arborelui cu simbolurile de codat, obținem o reprezentare binară a arborelui codul prefixului.
Să descriem algoritmul pentru construirea unui arbore Huffman și obținerea codurilor Huffman.
  1. Caracterele alfabetului de intrare formează o listă de noduri libere. Fiecare frunză are o greutate care egală cu frecvența aspectul simbolului
  2. Sunt selectate două noduri de arbore libere cu cele mai mici greutăți
  3. Părintele lor este creat cu o greutate egală cu greutatea lor totală
  4. Părintele este adăugat la lista de noduri libere, iar cei doi copii ai săi sunt eliminați din această listă
  5. Un arc care părăsește părintele i se atribuie bitul 1, celuilalt i se atribuie bitul 0
  6. Pașii începând cu al doilea se repetă până când un singur nod liber rămâne în lista nodurilor libere. Aceasta va fi considerată rădăcina copacului.
Folosind acest algoritm, putem obține coduri Huffman pentru un alfabet dat, ținând cont de frecvența de apariție a caracterelor.
Codare aritmetică
Algoritmii de codare aritmetică codifică șiruri de elemente într-o fracție. În acest caz, se ia în considerare distribuția de frecvență a elementelor. În prezent, algoritmii de codare aritmetică sunt protejați de brevete, așa că ne vom uita doar la ideea de bază.
Să fie alfabetul nostru format din N simboluri a1,...,aN și, respectiv, frecvențele lor de apariție p1,...,pN. Să împărțim jumătatea de interval ID tabel: 0
Cei 64 de octeți rămași trebuie să umple tabelul 8x8.



Aruncă o privire mai atentă la ordinea în care sunt completate valorile tabelului. Această ordine se numește ordine în zig-zag:

Marker: SOF0 - Baseline DCT

Acest marker se numește SOF0 și înseamnă că imaginea este codificată folosind metoda de bază. Este foarte comun. Dar nu mai puțin populară pe Internet este metoda progresivă familiară, atunci când o imagine cu rezoluție scăzută este mai întâi încărcată, apoi o imagine normală. Acest lucru vă permite să înțelegeți ceea ce este afișat acolo fără să așteptați sarcina completa. Specificația definește mai multe metode, după cum mi se pare, nu foarte comune.

FF C0 00 11 08 00 10 00 10 03 01 22 00 02
11 01 03 11 01

Lungime: 17 octeți.
Precizie: 8 biți. În metoda de bază este întotdeauna 8. După cum am înțeles, aceasta este adâncimea de biți a valorilor canalului.
Înălțimea imaginii: 0x10 = 16
Lățimea figurii: 0x10 = 16
Număr de componente: 3. Cel mai adesea acestea sunt Y, Cb, Cr.

Prima componenta:
ID: 1
Diluare orizontală (H 1): 2
[_2] Subțiere verticală (V 1): 2
ID tabel de cuantizare: 0

componenta a doua:
ID: 2
Diluare orizontală (H 2): 1
[_1] Subțierea verticală (V 2): 1

componenta a treia:
ID: 3
Diluare orizontală (H 3): 1
[_1] Subțierea verticală (V 3): 1
ID tabel de cuantizare: 1

Acum uitați-vă la cum să determinați cât de subțire este o imagine. Găsim H max =2 și V max =2. Canalul i va fi subțiat de H max /H i ori orizontal și V max /V i ori vertical.

Marcator: DHT (tabelul Huffman)

Această secțiune stochează codurile și valorile obținute prin codificarea Huffman.

FF C4 00 15 00 01 01 00 00 00 00
00 00 00 00 00 00 00 00 00 00 03 02

lungime: 21 de octeți.
clasa: 0 (0 - tabelul coeficienților DC, 1 - tabelul coeficienților AC).
[_0] ID tabel: 0
Lungimea codului Huffman: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Numar de coduri:
Numărul de coduri înseamnă numărul de coduri de lungimea respectivă. Vă rugăm să rețineți că secțiunea stochează doar lungimile codurilor, nu codurile în sine. Trebuie să găsim codurile noi înșine. Deci, avem un cod de lungime 1 și unul de lungime 2. În total 2 coduri, nu mai există coduri în acest tabel.
Fiecare cod are o valoare asociată cu acesta și sunt listate în fișier după cum urmează. Valorile sunt pe un singur octet, deci citim 2 octeți.
- valoarea primului cod.
- valoarea celui de-al 2-lea cod.

Construcția unui arbore de cod Huffman

Trebuie să construim un arbore binar din tabelul primit în secțiunea DHT. Și din acest arbore recunoaștem fiecare cod. Adăugăm valorile în ordinea în care sunt indicate în tabel. Algoritmul este simplu: indiferent în ce nod ne aflăm, încercăm întotdeauna să adăugăm o valoare ramurii din stânga. Și dacă e ocupată, atunci la dreapta. Și dacă nu este loc acolo, atunci ne întoarcem la un nivel superior și încercăm de acolo. Trebuie să vă opriți la un nivel egal cu lungimea codului. Ramurile din stânga corespund valorii 0, cele din dreapta - 1.
Cometariu:
Nu trebuie să începi de sus de fiecare dată. A adăugat o valoare - reveniți la un nivel superior. Există ramura potrivită? Dacă da, urcă din nou. Dacă nu, creați o ramură dreaptă și mergeți acolo. Apoi, din acest punct, începeți să căutați pentru a adăuga următoarea valoare.

Arbori pentru toate tabelele din acest exemplu:


UPD (mulțumesc): Nodurile primului arbore (DC, id = 0) trebuie să aibă valori 0x03 și 0x02

În cercuri sunt semnificațiile codurilor, sub cercuri sunt codurile în sine (dați-mi să vă explic că le-am obținut mergând prin calea de sus la fiecare nod). Cu aceste coduri (din acest tabel și alte tabele) este codificat însuși conținutul figurii.

Marcator: SOS (Start of Scan)

Octetul din marker înseamnă „DA! În cele din urmă, am trecut direct la analizarea secțiunii de imagine codificată!” Cu toate acestea, secțiunea se numește simbolic SOS.

  FF DA 00 0C 03 01 00 02 11
03 11 00 3F 00

Lungimea părții antet (nu a întregii secțiuni): 12 octeți.
Numărul de componente de scanare. Avem 3, câte unul pentru Y, Cb, Cr.

Prima componenta:
Număr componentă a imaginii: 1 (Y)
ID tabel Huffman pentru coeficienții DC: 0
[_0] ID tabel Huffman pentru coeficienții AC: 0

componenta a doua:
Numărul componentei imaginii: 2 (Cb)

[_1]

componenta a treia:
Numărul componentei imaginii: 3 (Cr)
ID tabel Huffman pentru coeficienții DC: 1
[_1] ID-ul tabelului Huffman pentru coeficienții AC: 1

Aceste componente se alternează ciclic.

Aici se termină partea antetului, de aici până la sfârșit (marker) sunt datele codificate.


0

Aflarea coeficientului DC.
1. Citirea unei secvențe de biți (dacă întâlnim 2 octeți, atunci acesta nu este un marker, ci doar un octet). După fiecare bit, ne deplasăm de-a lungul arborelui Huffman (cu identificatorul corespunzător) de-a lungul ramurii 0 sau 1, în funcție de bitul citit. Ne oprim dacă ne aflăm la nodul final.
10 1011101110011101100001111100100

2. Luăm valoarea nodului. Dacă este egal cu 0, atunci coeficientul este egal cu 0, îl scriem în tabel și trecem la citirea altor coeficienți. În cazul nostru - 02. Această valoare este lungimea coeficientului în biți. Adică citim următorii 2 biți, acesta va fi coeficientul.
10 10 11101110011101100001111100100

3. Dacă prima cifră a valorii în reprezentare binară este 1, atunci o lăsăm așa cum este: DC_coef = valoare. În caz contrar, transformăm: DC_coef = valoare-2 valoare lungime +1 . Scriem coeficientul în tabel la începutul zigzagului - colțul din stânga sus.

Găsirea coeficienților AC.
1. Similar cu pasul 1, găsirea coeficientului DC. Continuăm să citim secvența:
10 10 1110 1110011101100001111100100

2. Luăm valoarea nodului. Dacă este 0, aceasta înseamnă că valorile rămase ale matricei trebuie să fie umplute cu zerouri. Apoi următoarea matrice este codificată. Primii care au citit până aici și îmi vor scrie despre asta într-un mesaj personal vor primi un plus în karma. În cazul nostru, valoarea nodului este 0x31.
Prima ciugulire: 0x3 - exact cam câte zerouri trebuie să adăugăm la matrice. Aceștia sunt 3 coeficienți zero.
Al doilea nibble: 0x1 - lungimea coeficientului în biți. Citiți următorul bit.
10 10 1110 1 110011101100001111100100

3. Similar cu pasul 3 de găsire a coeficientului DC.

După cum înțelegeți deja, trebuie să citiți coeficienții AC până când găsim o valoare de cod zero sau până când matricea este umplută.
În cazul nostru vom obține:
10 10 1110 1 1100 11 101 10 0 0 0 1 11110 0 100
si matrice:





Ați observat că valorile sunt completate în același model în zig-zag?
Motivul pentru utilizarea acestei ordine este simplu - deoarece cu cât valorile lui v și u sunt mai mari, cu atât coeficientul S vu este mai puțin semnificativ în transformarea cosinus discretă. Prin urmare, la rate de compresie ridicate, coeficienții nesemnificativi sunt setați la zero, reducând astfel dimensiunea fișierului.

[-4 1 1 1 0 0 0 0] [ 5 -1 1 0 0 0 0 0]
[ 0 0 1 0 0 0 0 0] [-1 -2 -1 0 0 0 0 0]
[ 0 -1 0 0 0 0 0 0] [ 0 -1 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [-1 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]

[-4 2 2 1 0 0 0 0]
[-1 0 -1 0 0 0 0 0]
[-1 -1 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]

Oh, am uitat să spun că coeficienții DC codificați nu sunt coeficienții DC în sine, ci diferențele lor între coeficienții din tabelul anterior (același canal)! Matricele trebuie corectate:
DC pentru al doilea: 2 + (-4) = -2
DC pentru a treia: -2 + 5 = 3
DC pentru al patrulea: 3 + (-4) = -1

[-2 1 1 1 0 0 0 0] [ 3 -1 1 0 0 0 0 0] [-1 2 2 1 0 0 0 0]
………

Acum totul este în ordine. Această regulă se aplică până la sfârșitul fișierului.

...și prin matrice pentru Cb și Cr:

[-1 0 0 0 0 0 0 0]
[ 1 1 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]

Deoarece există o singură matrice, coeficienții DC pot fi lăsați neatinse.

Calcule

Cuantizarea

Vă amintiți că matricea trece printr-o etapă de cuantizare? Elementele matricei trebuie înmulțite termen cu termen cu elementele matricei de cuantizare. Tot ce rămâne este să-l alegi pe cel de care ai nevoie. Mai întâi am scanat prima componentă, componenta sa imagine = 1. Componenta imagine cu acest ID folosește o matrice de cuantizare de 0 (a noastră este prima dintre două). Deci, după înmulțire:


[ 0 120 280 0 0 0 0 0]
[ 0 -130 -160 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]

În mod similar, obținem încă 3 matrice de canal Y...

[-320 110 100 160 0 0 0 0] [ 480 -110 100 0 0 0 0 0]
[ 0 0 140 0 0 0 0 0] [-120 -240 -140 0 0 0 0 0]
[ 0 -130 0 0 0 0 0 0] [ 0 -130 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [-140 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]

[-160 220 200 160 0 0 0 0]
[-120 0 -140 0 0 0 0 0]
[-140 -130 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]

...și prin matrice pentru Cb și Cr.

[-170 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 180 210 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]

Transformată cosinus discretă inversă

Formula nu trebuie să fie dificilă*. S vu este matricea noastră de coeficienți rezultată. u - coloană, v - rând. s yx - direct valorile canalului.

* În general, acest lucru nu este în întregime adevărat. Când am reușit să decodesc și să afișez pe ecran imaginea de 16x16, am luat imaginea de 600x600 (apropo, aceasta era coperta albumului preferat al lui Mind.In.A.Box - Lost Alone). Nu a funcționat imediat - au apărut diverse bug-uri. În curând am putut admira poza încărcată corect. Singurul lucru care m-a supărat cu adevărat a fost viteza de descărcare. Încă îmi amintesc că a durat 7 secunde. Dar acest lucru nu este surprinzător, dacă folosiți fără gânduri formula de mai sus, atunci pentru a calcula un canal de un pixel va trebui să găsiți 128 cosinus, 768 înmulțiri și unele adunări. Gândește-te la asta - aproape o mie de operații dificile pe un singur canal de un pixel! Din fericire, este loc de optimizare (după multe experimente, am redus timpul de încărcare la limita de precizie a cronometrului de 15 ms, iar după aceea am schimbat imaginea cu o fotografie cu o suprafață de 25 de ori mai mare. Poate voi scrie despre asta în un articol separat).

Voi scrie rezultatul calculării numai a primei matrice a canalului Y (valorile sunt rotunjite):


[ 87 72 50 36 37 55 79 95]
[-10 5 31 56 71 73 68 62]
[-87 -50 6 56 79 72 48 29]

Si restul de 2:
Cb Cr
[ 60 52 38 20 0 -18 -32 -40] [ 19 27 41 60 80 99 113 120]
[ 48 41 29 13 -3 -19 -31 -37] [ 0 6 18 34 51 66 78 85]
[ 25 20 12 2 -9 -19 -27 -32] [-27 -22 -14 -4 7 17 25 30]
[ -4 -6 -9 -13 -17 -20 -23 -25] [-43 -41 -38 -34 -30 -27 -24 -22]
[ -37 -35 -33 -29 -25 -21 -18 -17] [-35 -36 -39 -43 -47 -51 -53 -55]
[ -67 -63 -55 -44 -33 -22 -14 -10] [ -5 -9 -17 -28 -39 -50 -58 -62]
[ -90 -84 -71 -56 -39 -23 -11 -4] [ 32 26 14 -1 -18 -34 -46 -53]
[-102 -95 -81 -62 -42 -23 -9 -1] [ 58 50 36 18 -2 -20 -34 -42]

  1. Oh, mă duc și mănânc!
  2. Da, nu mă mut deloc, despre ce vorbim.
  3. Odată ce valorile de culoare YCbCr au fost obținute, tot ce rămâne este să le convertim în RGB, astfel: YCbCrToRGB(Y ij , Cb ij , Cr ij) , Y ij , Cb ij , Cr ij - matricele noastre rezultate.
  4. 4 matrice Y și câte un Cb și Cr fiecare, deoarece am subțiat canalele și 4 pixeli Y corespund unui Cb și Cr. Prin urmare, calculați astfel: YCbCrToRGB(Y ij , Cb , Cr )
Dacă ai ales 1 și 4, atunci mă bucur pentru tine. Ori ai înțeles bine, ori în curând te vei bucura de mâncare.

YCbCr la RGB

R = Y + 1,402 * Cr
G = Y - 0,34414 * Cb - 0,71414 * Cr
B = Y + 1,772 * Cb
Nu uitați să adăugați 128. Dacă valorile depășesc intervalul, atunci atribuiți valori limită. Formula este simplă, dar consumă și o parte din timpul procesorului.

Iată tabelele rezultate pentru canalele R, G, B pentru pătratul 8x8 din stânga sus al exemplului nostru:
255 248 194 148 169 215 255 255
255 238 172 115 130 178 255 255
255 208 127 59 64 112 208 255
255 223 143 74 77 120 211 255
237 192 133 83 85 118 184 222
177 161 146 132 145 162 201 217
56 73 101 126 144 147 147 141
0 17 76 126 153 146 127 108

231 185 117 72 67 113 171 217
229 175 95 39 28 76 139 189
254 192 100 31 15 63 131 185
255 207 115 46 28 71 134 185
255 241 175 125 112 145 193 230
226 210 187 173 172 189 209 225
149 166 191 216 229 232 225 220
72 110 166 216 238 231 206 186

255 255 249 203 178 224 255 255
255 255 226 170 140 187 224 255
255 255 192 123 91 138 184 238
255 255 208 139 103 146 188 239
255 255 202 152 128 161 194 232
255 244 215 200 188 205 210 227
108 125 148 172 182 184 172 167
31 69 122 172 191 183 153 134

Sfârşit

În general, nu sunt un specialist JPEG, așa că cu greu pot răspunde la toate întrebările. Doar că atunci când îmi scriam decodorul, trebuia adesea să mă confrunt cu diverse probleme de neînțeles. Și când imaginea a fost afișată incorect, nu știam unde am făcut o greșeală. Poate a interpretat incorect biții, sau poate a folosit incorect DCT. Chiar îmi lipsea un exemplu pas cu pas, așa că sper că acest articol vă va ajuta când scriu un decodor. Cred că acoperă descrierea metodei de bază, dar totuși nu o poți face singur. Vă ofer link-uri care m-au ajutat:

Fotografiile și imaginile diferă unele de altele nu numai prin conținut, ci și prin alte caracteristici „calculatorului”. De exemplu, după mărime.

Se întâmplă că par să existe două desene identice, dar unul este de trei ori mai mare decât celălalt.

Imaginile diferă și ca calitate. Cred că ai întâlnit fotografii de mai multe ori Calitate rea. Acest lucru este vizibil cu ochiul liber. De exemplu, două fotografii identice, dar una de calitate mai bună, iar cealaltă de calitate mai proastă.

Și se întâmplă ca desenul să pară lipsit de culori. Iată un exemplu.

Și formatul sau tipul fișierului este responsabil pentru toate acestea.

De fapt, imaginile vin într-o varietate de formate. Și sunt foarte, foarte mulți dintre ei. Nu le vom lua în considerare pe toate, ci vom vorbi despre cele mai comune. Acestea sunt formate precum bmp, gif, jpg, png, tiff.

Se deosebesc unul de celălalt, în primul rând, prin calitate. Iar calitatea diferă în numărul (saturația) de culori.

De exemplu, pictez o imagine folosind culori diferite. Și apoi, deodată, unele dintre ele s-au terminat și trebuie să termini de pictat cu ceea ce ai. Desigur, voi încerca să fac tot posibilul pentru ca acest lucru să nu afecteze foarte mult rezultatul, dar totuși imaginea nu va ieși așa cum mi-aș dori - mai estompată, neclară.

Așa e cu formatele de imagine. Unii lasă toate culorile, în timp ce alții le taie pe unele. Și uneori, acest lucru face ca imaginea să se deterioreze.

Acesta este un exemplu destul de dur. De fapt, totul este ceva mai complicat, dar cred că ai înțeles ideea principală.

Formate comune de imagine

BMP este un format pentru desenele realizate în programul Paint. Poate fi folosit pentru a stoca imagini desenate pe computer. Dar acest tip de fișier nu este folosit pe Internet din cauza dimensiunii mari. Deci, dacă doriți să publicați o imagine desenată în Paint pe un blog sau rețea socială, aceasta trebuie să fie de alt tip - gif, jpg sau png.

GIF este un format de imagine popular pe Internet. Le puteți salva în el fără a pierde calitatea, dar cu un număr limitat de culori - 256. GIF a câștigat o popularitate deosebită datorită faptului că poate crea imagini animate mici (în mișcare).

JPG este un format pentru fotografii și picturi cu un număr mare de culori. Puteți salva o imagine în ea atât fără pierderea calității, cât și cu pierdere.

PNG este un format modern de imagine. Se obține acest tip de imagine mărime mică si fara pierderi de calitate. Foarte comod: fișierul este mic și calitatea este bună. De asemenea, susține transparența.

TIFF - imaginile sunt de foarte bună calitate, fără compresie. Prin urmare, dimensiunea unor astfel de fișiere este uriașă. TIFF este folosit atunci când calitatea este de mare importanță. De exemplu, atunci când creați cărți de vizită, broșuri, coperți de reviste.

Ce format să alegi

  • BMP - dacă acesta este un desen realizat în Paint și îl veți păstra doar pe computer.
  • GIF - dacă o animație sau un desen cu un număr mic de culori pentru publicare pe Internet.
  • PNG - dacă aceasta este o imagine care are multe culori sau unele părți transparente.
  • JPG (jpeg) - dacă este o fotografie.
  • TIFF - imagine pentru tipărire (cărți de vizită, broșuri, postere etc.).

Bună, dragi prieteni. Astăzi vom vorbi despre ce format de imagine este cel mai bine de utilizat pe site, ce formate de fișiere grafice sunt disponibile astăzi pentru site și dacă este necesar să se urmărească noi formate grafice.

Primesc destul de multe întrebări ca aceasta, mulți dintre studenții mei mă întreabă dacă pot folosi noile formate SVG și WebP și unde este cel mai bun loc pentru a folosi aceste imagini. Desigur, puteți folosi formate noi, trebuie doar să înțelegeți ce format este cel mai potrivit pentru ce.

Astăzi, imaginile de pe un site web sunt o parte integrantă. Începând de la design graficși încărcarea imaginilor în articole, graficele însoțesc majoritatea site-urilor din rețea. Dar frumusețea are un preț

Imaginile neoptimizate sunt unul dintre factorii care încetinesc un site web, așa cum indică serviciile de verificare.

Prin urmare, va trebui întotdeauna să decideți ce format să alegeți pentru imagine. Mărimea și calitatea acestuia vor depinde de acest lucru. Și să folosești imagini dimensiune mai micăși fără a pierde calitatea, ar trebui să știi câteva lucruri.

Ce imagini pentru site-uri folosesc astăzi?

Toate imaginile pentru site-uri web sunt împărțite în:

  • raster (exemplu - JPG, JPEG, GIF, PNG),
  • vector (exemplu - SVG).

Raster Imaginile sunt formate din pixeli care stochează valori de culoare și transparență. Aceste formate includ imagini în articole, butoane, pictograme și elemente de design. Aceste imagini sunt populare în rândul dezvoltatorilor și proprietarilor de site-uri web. Principalul dezavantaj al imaginilor raster este că nu se scalează bine.

Adică, atunci când dimensiunea imaginii crește, are loc o pierdere a calității.

Vector imaginile sunt alcătuite din linii și puncte de referință. Informațiile despre imagine sunt stocate în instrucțiuni matematice de randare, ceea ce permite ca astfel de imagini să fie scalate cât de mult se dorește fără pierderea calității.

Toate aceste imagini pot și sunt folosite pe site-uri web moderne. Trebuie doar să înțelegeți asta înainte de a încărca pe site, !

Descrierea formatelor de imagine populare pentru site

Din descrierea acestor formate, veți înțelege unde și ce format este cel mai bine utilizat pe site.

JPEG

JPEG sau JPG este unul dintre cele mai populare formate de imagine pentru site-uri web. Formatul acceptă milioane de culori, ceea ce îi conferă o poziție de lider în prezentarea de fotografii și poze pe site.

Imaginile în acest format sunt optimizate destul de bine, practic fără pierderi de calitate, ceea ce vă permite să obțineți un fișier mai mic fără pierderea vizuală a calității. Trebuie amintit că fiecare optimizare ulterioară reduce calitatea.

Fișierele cu acest format sunt acceptate de toate dispozitivele și browserele, ceea ce confirmă încă o dată popularitatea și vă permite să nu vă faceți griji cu privire la problemele cu afișarea pe site-uri.

Marele dezavantaj al acestui format este lipsa de transparență. Adică nu va fi posibilă combinarea imaginilor în acest format. Pentru astfel de sarcini este mai bine să utilizați următorul format.

PNG

Acest format folosește un algoritm de compresie fără pierderi. În ceea ce privește numărul de culori și nivelul de transparență, acesta este disponibil în două tipuri: 8 și 24 de biți. Ambele susțin transparența.

8-bit nu este foarte popular, dar 24-bit este utilizat pe scară largă pentru diverse imagini Pe net. Datorită transparenței, vă permite să creați imagini combinate. Adesea folosit pentru a crea butoane și pictograme animate unde este necesar un efect de transparență.

Imaginile în format PNG pot fi optimizate și editate de mai multe ori - își va păstra calitatea originală.

Formatul este, de asemenea, acceptat de toate browserele și dispozitivele, asigurându-se că poate fi afișat pe orice ecran.

Calitatea imaginilor arată mai bună decât JPG, dar greutatea fișierului va fi mai mare. Acest lucru trebuie luat în considerare la plasarea fișierelor pe site.

GIF

Este un format de 8 biți care acceptă 256 de culori, transparență și animație. Datorită suportului unui număr mic de culori, greutatea fișierului este, de asemenea, minimă.

Formatul nu este potrivit pentru fotografii și imagini cu gamă largă culorile.

Dar este utilizat pe scară largă în crearea de bannere, butoane, pictograme și așa mai departe.

În site-urile web moderne, acest format este folosit din ce în ce mai puțin.

În continuare, să vorbim despre formatele SVG și WebP relativ recente, care nu sunt atât de populare, dar câștigă popularitate și suport și sunt perfect potrivite cerințelor privind viteza de încărcare și adaptabilitatea site-ului web.

SVG

Acesta este formatul fișiere vectoriale pe Bazat pe XML. Formatul a început să câștige popularitate destul de recent, deoarece anterior era slab acceptat în browsere. Și din cauza problemelor de afișare, nimeni nu s-a grăbit să-l folosească.

Astăzi, SVG este acceptat de toate browserele moderne. Dar problemele cu afișajul încă apar.

Acest format este cel mai des folosit pentru imagini simple, cum ar fi logo-uri, elemente de design și așa mai departe. Nu este potrivit pentru fotografii.

Formatul SVG este ușor, foarte scalabil, oferind imagini clare pe orice rezoluție a ecranului, acceptă animație, poate fi controlat prin CSS și plasat în HTML, reducând numărul de solicitări.

WebP

Un format open source dezvoltat de Google special pentru Internet. Astăzi, YouTube utilizează conversia miniaturii video în WebP.

Formatul oferă o compresie superioară și acceptă transparență. Combină beneficiile formatelor JPG și PNG fără a crește dimensiunea fișierului.

Dar, în ciuda avantajelor formatului, nu este acceptat de toate browserele, de exemplu, IE, Edge, Firefox și Safari.

Există modalități de a evita aceste restricții, dar ele împiedică utilizarea formatului peste tot.

Concluzie

Prieteni, sper că am explicat totul clar și acum știți ce format de imagine este cel mai bine să utilizați pe site și de ce nu insist să folosesc un anumit format, ci recomand o abordare integrată.

Poate că atunci când WebP va câștiga suport pe scară largă, vom trece cu toții la el și vom înlocui jpg și png pe site-urile noastre.

Să discutăm în comentarii ce formate folosiți pe site-urile dvs., ce vă place și ce nu vă place.

Asta e tot pentru azi, astept comentariile voastre.

Salutări, Maxim Zaitsev.

    CU Cele mai populare trei formate de fișiere sunt JPEG, RAW, TIFF. Uneori puteți auzi dezacorduri între fotografi - ce format de fișier este mai bun pentru fotografie, în ce format este mai bine să faceți fotografii, deoarece camerele moderne vă permit să faceți fotografiigrafică în oricare dintre aceste formate și, uneori, în mai multe simultan!

    Formatul de fișier în care este stocată o imagine este în esență un compromis între calitatea imaginii și dimensiunea fișierului.

    Probabil știți deja că o imagine raster este formată din pixeli. Modul în care este organizat un fișier raster și sub ce formă sunt stocate informațiile despre pixeli în el determină formatul fișierului. Calitatea imaginii unui fișier raster este determinată de doi parametri principali: dimensiunea pixelilor (adică numărul total de pixeli) și acuratețea culorii pixelului în reprezentarea culorii reale.Cu dimensiunea pixelilor este clar - cu cât sunt mai mulți pixeli (sau cu cât este „mai mic” pixelul), cu atât mai bine.Iar acuratețea reproducerii culorilor depinde de numărul de culori per pixel sau de adâncimea culorii.

    Adâncimea culorii (calitatea redării culorii, adâncimea de biți a imaginii) - cantitatea de memorie în numărul de biți utilizată pentru a stoca și reprezenta culoarea la codificarea unui pixel de grafică raster sau de imagine video. Numărul de biți indică numărul de gradări (pași de ton) din fiecare componentă de culoare sau, pur și simplu, numărul de culori. Adăugarea unui bit înseamnă a adăuga încă un bit la cod binar cromaticitate.

    • Culoare de 1 bit (21 = 2 culori) culoare binară, cel mai adesea reprezentată de alb-negru (sau negru și verde)
    • Culoare pe 2 biți (22 = 4 culori) CGA, scala de gri NeXTstation
    • Culoare pe 3 biți (23 = 8 culori) multe computere personale vechi cu ieșire TV
    • Culoarea pe 4 biți (24 = 16 culori) este cunoscută ca EGA și, într-o măsură mai mică, ca standard VGA de înaltă rezoluție
    • Culoare pe 5 biți (25 = 32 de culori) Chipset Amiga original
    • Culoare pe 6 biți (26 = 64 de culori) Chipset Amiga original
    • Culoare pe 8 biți (28 = 256 culori) Stații de lucru Unix vechi, VGA cu rezoluție joasă, Super VGA, AGA
    • Culoare pe 12 biți (212 = 4.096 culori) pe unele sisteme Silicon Graphics, sisteme NeXTstation și sisteme în modul Amiga HAM.

    De exemplu, lucrăm în spațiul de culoare RGB. Aceasta înseamnă că există trei canale din care se formează culoarea finală a pixelului: canalul roșu (Rad), canalul verde (verde) și canalul albastru (albastru). Să presupunem că canalele sunt pe patru biți. Aceasta înseamnă că fiecare canal are capacitatea de a afișa 16 culori. Ca rezultat, toate RGB vor fi pe 12 biți și vor putea fi afișate

    C=16x16x16=4096 culori

    Adâncimea culorii în acest caz este de 12 biți.

    Când oamenii vorbesc despre RGB pe 24 de biți, se referă la canale pe 8 biți (256 de culori fiecare) cu un număr total de opțiuni de culoare per pixel

    C=256x256x256=16777216 culori.

    Cifra este impresionantă. Acest număr de culori pentru fiecare pixel satisface cerințele celui mai pretențios fotograf.

    Câteva despre formatele în sine.

    format TIFF

    TIFF înseamnă Tagged Image File Format și este un standard pentru industria de tipărire și tipărire.

    Ca urmare, iată ce se întâmplă:

    1. Dacă camera dvs. este atât de simplă încât înregistrează doar JPEG și doriți să obțineți calitate maxima, seteaza dimensiunea maxima si compresia minima si nu te chinui cu faptul ca nu ai alte formate. În cele mai multe cazuri, o imagine RAW redată manual, se potrivește cu JPEG capturat automat de cameră.

    2. Probabil că nu ar trebui să faci fotografii în TIFF. Înregistrarea în acest format este mai dificilă, dar nu există nicio diferență vizibilă în comparație cu JPEG de înaltă calitate.

    3. Dacă aveți ocazia să faceți poze în , lucrați cu el. Vei simți singur dacă este potrivit pentru tine. În unele cazuri, numai RAW face posibilă realizarea unei fotografii unice pentru o mărire ridicată la imprimare.

    Mai rămâne o soluție, s-ar putea spune universal. Există un mod care vă permite să luați cadre în două formate simultan: RAW+ JPEG. Filmați scene importante în acest mod. Stocarea digitală modernă a informațiilor - atât cardurile de memorie, cât și hard disk-urile - fac posibil acest lucru. În acest caz, primiți un JPEG pentru a utiliza fotografia imediat, fără a pierde timp pentru revizuire. Și, dacă aveți nevoie de acest lucru, încredințați fișierul RAW unui specialist pentru procesare.

    Fotografie. Formate de fișiere.

    Este ușor de calculat că o imagine color necomprimată cu o dimensiune de 2000 * 1000 pixeli va avea o dimensiune de aproximativ 6 megaocteți. Dacă vorbim de imagini obținute de la camere profesionale sau scanere de înaltă rezoluție, atunci dimensiunea acestora poate fi și mai mare. În ciuda creșterii rapide a capacității dispozitivelor de stocare, diverși algoritmi de compresie a imaginii sunt încă foarte relevanți.
    Toți algoritmii existenți pot fi împărțiți în două clase mari:

    • Algoritmi de compresie fără pierderi;
    • Algoritmi de compresie cu pierderi.
    Când vorbim despre compresie fără pierderi, ne referim la faptul că există un algoritm invers al algoritmului de compresie care vă permite să restaurați cu acuratețe imaginea originală. Nu există un algoritm invers pentru algoritmii de compresie cu pierderi. Există un algoritm care restabilește o imagine care nu se potrivește neapărat cu cea originală. Algoritmii de compresie și recuperare sunt selectați pentru a obține un raport de compresie ridicat, menținând în același timp calitatea vizuală a imaginii.

    Algoritmi de compresie fără pierderi

    Algoritmul RLE
    Toți algoritmii din seria RLE se bazează pe o idee foarte simplă: grupurile repetate de elemente sunt înlocuite cu o pereche (număr de repetări, element care se repetă). Să luăm în considerare acest algoritm folosind exemplul unei secvențe de biți. Această secvență va alterna grupuri de zerouri și unu. În plus, grupurile vor avea adesea mai mult de un element. Apoi, secvența 11111 000000 11111111 00 va corespunde următorului set de numere 5 6 8 2. Aceste numere indică numărul de repetări (numărarea începe de la unii), dar și aceste numere trebuie să fie codificate. Vom presupune că numărul de repetări variază de la 0 la 7 (adică 3 biți sunt suficienți pentru a codifica numărul de repetări). Apoi, secvența discutată mai sus este codificată de următoarea secvență de numere 5 6 7 0 1 2. Este ușor de calculat că codificarea secvenței originale necesită 21 de biți, iar în formă comprimată RLE această secvență are 18 biți.
    Deși acest algoritm este foarte simplu, eficiența sa este relativ scăzută. Mai mult, în unele cazuri, utilizarea acestui algoritm nu duce la o scădere, ci la o creștere a lungimii secvenței. De exemplu, luați în considerare următoarea secvență 111 0000 11111111 00. Secvența RL corespunzătoare arată astfel: 3 4 7 0 1 2. Lungimea secvenței originale este de 17 biți, lungimea secvenței comprimate este de 18 biți.
    Acest algoritm este cel mai eficient pentru imaginile alb-negru. De asemenea, este adesea folosit ca una dintre etapele intermediare de compresie a algoritmilor mai complexi.

    Dicţionar algorithms

    Ideea din spatele algoritmilor de dicționar este că lanțurile de elemente ale secvenței originale sunt codificate. Această codificare folosește un dicționar special, care este obținut pe baza secvenței originale.
    Există o întreagă familie de algoritmi de dicționar, dar ne vom uita la cel mai comun algoritm LZW, numit după dezvoltatorii săi Lepel, Ziv și Welch.
    Dicționarul din acest algoritm este un tabel care este umplut cu lanțuri de codare pe măsură ce algoritmul rulează. Când codul comprimat este decodat, dicționarul este restaurat automat, astfel încât nu este nevoie să transmiteți dicționarul împreună cu codul comprimat.
    Dicționarul este inițializat cu toate șirurile singleton, adică. primele rânduri ale dicționarului reprezintă alfabetul în care codificăm. În timpul compresiei, se face o căutare pentru cel mai lung lanț deja înregistrat în dicționar. De fiecare dată când se întâlnește un lanț care nu a fost încă scris în dicționar, acesta este adăugat acolo și iese un cod comprimat corespunzător lanțului deja scris în dicționar. În teorie, nu sunt impuse restricții cu privire la dimensiunea dicționarului, dar în practică are sens să se limiteze această dimensiune, deoarece în timp încep să apară lanțuri care nu se mai regăsesc în text. În plus, atunci când dublem dimensiunea tabelului, trebuie să alocăm un bit în plus pentru a stoca coduri comprimate. Pentru a preveni astfel de situații, se introduce un cod special, simbolizând inițializarea tabelului cu toate lanțurile cu un singur element.
    Să ne uităm la un exemplu de algoritm de compresie. Vom comprima linia cuccuckoocuckoohood. Să presupunem că dicționarul va conține 32 de poziții, ceea ce înseamnă că fiecare dintre codurile sale va ocupa 5 biți. Inițial, dicționarul este completat după cum urmează:

    Acest tabel există atât de partea celui care comprimă informația, cât și de partea celui care o decomprimă. Acum ne vom uita la procesul de compresie.


    Tabelul arată procesul de completare a dicționarului. Este ușor de calculat că codul comprimat rezultat durează 105 biți, iar textul original (presupunând că cheltuim 4 biți pentru codificarea unui caracter) are 116 biți.
    În esență, procesul de decodare se reduce la decodarea directă a codurilor și este important ca tabelul să fie inițializat în același mod ca în timpul codificării. Acum să ne uităm la algoritmul de decodare.



    Putem defini complet șirul adăugat în dicționar la pasul i-a doar la i+1. Evident, linia i-a trebuie să se termine cu primul caracter al liniei i+1. Acea. Tocmai ne-am dat seama cum să restabilim un dicționar. Un oarecare interes este situația în care o secvență de forma cScSc este codificată, unde c este un caracter și S este un șir, iar cuvântul cS este deja în dicționar. La prima vedere poate părea că decodorul nu va putea rezolva această situație, dar de fapt toate liniile de acest tip trebuie să se termine întotdeauna cu același caracter cu care încep.

    Algoritmi de codare statistică
    Algoritmii din această serie atribuie cel mai scurt cod comprimat celor mai frecvente elemente ale secvențelor. Acestea. secvențele de aceeași lungime sunt codificate cu coduri comprimate de lungimi diferite. Mai mult, cu cât apare mai des o secvență, cu atât codul comprimat corespunzător este mai scurt.
    Algoritmul Huffman
    Algoritmul Huffman vă permite să construiți coduri de prefix. Ne putem gândi la coduri de prefix ca fiind căi într-un arbore binar: trecerea de la un nod la fiul său din stânga corespunde unui 0 în cod, iar fiului său din dreapta corespunde unui 1. Dacă etichetăm frunzele arborelui cu simbolurile pentru a fi codificat, obținem o reprezentare în arbore binar a codului de prefix.
    Să descriem algoritmul pentru construirea unui arbore Huffman și obținerea codurilor Huffman.
  1. Caracterele alfabetului de intrare formează o listă de noduri libere. Fiecare foaie are o greutate care este egală cu frecvența de apariție a simbolului
  2. Sunt selectate două noduri de arbore libere cu cele mai mici greutăți
  3. Părintele lor este creat cu o greutate egală cu greutatea lor totală
  4. Părintele este adăugat la lista de noduri libere, iar cei doi copii ai săi sunt eliminați din această listă
  5. Un arc care părăsește părintele i se atribuie bitul 1, celuilalt i se atribuie bitul 0
  6. Pașii începând cu al doilea se repetă până când un singur nod liber rămâne în lista nodurilor libere. Aceasta va fi considerată rădăcina copacului.
Folosind acest algoritm, putem obține coduri Huffman pentru un alfabet dat, ținând cont de frecvența de apariție a caracterelor.
Codare aritmetică
Algoritmii de codare aritmetică codifică șiruri de elemente într-o fracție. În acest caz, se ia în considerare distribuția de frecvență a elementelor. În prezent, algoritmii de codare aritmetică sunt protejați de brevete, așa că ne vom uita doar la ideea de bază.
  • Tutorial


Ați înțeles corect din titlu că aceasta nu este o descriere foarte obișnuită a algoritmului JPEG (am descris formatul fișierului în detaliu în articolul „Decodare JPEG pentru nenorociri”). În primul rând, metoda aleasă de prezentare a materialului presupune că nu știm nimic nu numai despre JPEG, ci și despre transformata Fourier și codarea Huffman. În general, ne amintim puțin din prelegeri. Tocmai au făcut poza și au început să se gândească la cum ar putea fi comprimată. Prin urmare, am încercat să exprim clar doar esența, dar în care cititorul va dezvolta o înțelegere destul de profundă și, cel mai important, intuitivă a algoritmului. Formule și calcule matematice - cel puțin, doar cele care sunt importante pentru înțelegerea a ceea ce se întâmplă.

Cunoașterea algoritmului JPEG este foarte utilă nu numai pentru compresia imaginii. Folosește teoria din prelucrare digitală semnale, analiză matematică, algebră liniară, teoria informației, în special transformata Fourier, codificare fără pierderi etc. Prin urmare, cunoștințele acumulate pot fi utile oriunde.

Dacă doriți, vă sugerez să parcurgeți și dumneavoastră aceiași pași în paralel cu articolul. Verificați în ce măsură este potrivit raționamentul de mai sus imagini diferite, încercați să faceți propriile modificări ale algoritmului. Este foarte interesant. Ca instrument, pot recomanda minunata combinație de Python + NumPy + Matplotlib + PIL(Pillow). Aproape toată munca mea (inclusiv grafica și animația) a fost făcută folosindu-le.

Atentie, trafic! O mulțime de ilustrații, grafice și animații (~ 10Mb). În mod ironic, în articolul despre JPEG sunt doar 2 imagini cu acest format din cincizeci.

Indiferent de algoritmul de compresie a informațiilor, principiul său va fi întotdeauna același - găsirea și descrierea modelelor. Cu cât mai multe modele, cu atât mai multă redundanță, cu atât mai puține informații. Arhivatorii și codificatorii sunt de obicei „adaptați” unui anumit tip de informații și știu unde să le găsească. În unele cazuri, un model este imediat vizibil, cum ar fi o imagine a unui cer albastru. Fiecare rând al reprezentării sale digitale poate fi descris destul de precis printr-o linie dreaptă.

Ne vom antrena pe pisici raton. Imaginea gri de mai sus este luată ca exemplu. Combină bine atât zonele omogene, cât și cele contrastante. Și dacă învățăm să comprimăm gri, atunci nu vor fi probleme cu culoarea.

Reprezentare vectorială

Mai întâi, să verificăm cât de dependenți sunt doi pixeli vecini. Este logic să presupunem că cel mai probabil vor fi foarte asemănătoare. Să verificăm acest lucru pentru toate perechile de imagini. Să le marchem pe planul de coordonate cu puncte, astfel încât valoarea punctului de-a lungul axei X să fie valoarea primului pixel, iar de-a lungul axei Y - al doilea. Pentru imaginea noastră care măsoară 256 x 256, obținem 256*256/2 pixeli:


În mod previzibil, majoritatea punctelor sunt situate pe sau în apropierea liniei y=x (și sunt chiar mai multe decât se poate vedea în figură, deoarece se suprapun de multe ori și, în plus, sunt translucide). Dacă da, ar fi mai ușor să lucrați rotindu-le cu 45°. Pentru a face acest lucru, trebuie să le exprimați într-un sistem de coordonate diferit.


Vectorii de bază ai noului sistem sunt evident: . Suntem forțați să împărțim la rădăcina a doi pentru a obține un sistem ortonormal (lungimile vectorilor de bază sunt egale cu unu). Se arată aici că un anumit punct p = (x, y) în noul sistem va fi reprezentat ca un punct (a 0 , a 1). Cunoscând noii coeficienți, îi putem obține cu ușurință pe cei vechi, întorcându-i. În mod evident, prima (nouă) coordonată este media, iar a doua este diferența dintre x și y (dar împărțită la rădăcina 2). Imaginați-vă că vi se cere să lăsați doar una dintre valori: fie 0, fie 1 (adică echivalați cealaltă cu zero). Este mai bine să alegeți un 0, deoarece valoarea unui 1 va fi cel mai probabil în jurul valorii de zero. Iată ce se întâmplă dacă restaurăm imaginea doar de la 0:


mărire 4x:


Această compresie nu este foarte impresionantă, să fiu sincer. Este mai bine să împărțiți în mod similar imaginea în tripleți de pixeli și să le prezentați în spațiu tridimensional.

Acesta este același grafic, dar din puncte de vedere diferite. Liniile roșii sunt axele care s-au sugerat. Ele corespund vectorilor: . Permiteți-mi să vă reamintesc că trebuie să împărțiți la niște constante, astfel încât lungimile vectorilor să devină egale cu unu. Astfel, extinzându-ne pe această bază, obținem 3 valori a 0, a 1, a 2, iar un 0 este mai important decât un 1, iar un 1 este mai important decât un 2. Dacă aruncăm un 2, atunci graficul se va „plati” în direcția vectorului e 2. Această foaie tridimensională deja destul de subțire va deveni plată. Nu va pierde atât de mult, dar vom scăpa de o treime din valori. Să comparăm imagini reconstruite din triple: (a 0 , 0, 0), (a 1 , a 2 , 0) și (a 0 , a 1 , a 2). ÎN ultima versiune Nu am aruncat nimic, așa că vom primi originalul.


mărire 4x:


Al doilea desen este deja bun. Zonele ascuțite au fost ușor netezite, dar în general imaginea s-a păstrat foarte bine. Și acum, să împărțim la patru în același mod și să determinăm vizual baza în spațiul cu patru dimensiuni... Ei bine, da. Dar puteți ghici care va fi unul dintre vectorii de bază: (1,1,1,1)/2. Prin urmare, se poate privi proiecția spațiului cu patru dimensiuni pe spațiul perpendicular pe vectorul (1,1,1,1) pentru a identifica altele. Dar aceasta nu este cea mai bună cale.
Scopul nostru este să învățăm cum să transformăm (x 0 , x 1 , ..., x n-1) în (a 0 , a 1 , ..., a n-1) astfel încât fiecare valoare a lui a i să fie mai puțin importantă decât cele anterioare. Dacă putem face acest lucru, atunci poate că ultimele valori ale secvenței pot fi aruncate cu totul. Experimentele de mai sus sugerează că este posibil. Dar nu te poți descurca fără un aparat matematic.
Deci, trebuie să transformăm punctele la o nouă bază. Dar mai întâi trebuie să găsiți o bază potrivită. Să revenim la primul experiment de împerechere. Să o luăm în considerare în general. Am definit vectorii de bază:

Am exprimat vectorul prin ele p:

sau in coordonate:

Pentru a găsi un 0 și un 1 trebuie să proiectați p pe e 0 și e 1 respectiv. Și pentru aceasta trebuie să găsiți produsul scalar

similar:

În coordonate:

Este adesea mai convenabil să se efectueze transformarea sub formă de matrice.

Apoi A = EX și X = E T A. Aceasta este o formă frumoasă și convenabilă. Matricea E se numește matrice de transformare și este ortogonală, ne vom întâlni cu ea mai târziu.

Tranziția de la vectori la funcții.

Este convenabil să lucrați cu vectori de dimensiuni mici. Cu toate acestea, dorim să găsim modele în blocuri mai mari, astfel încât în ​​loc de vectori N-dimensionali este mai convenabil să operați cu secvențele care reprezintă imaginea. Voi numi astfel de secvențe funcții discrete, deoarece următorul raționament se aplică și funcțiilor continue.
Revenind la exemplul nostru, imaginați-vă o funcție f(i), care este definită în doar două puncte: f(0)=x și f(1)=y. În mod similar, definim funcțiile de bază e 0 (i) și e 1 (i) pe baza bazelor e 0 și e 1 . Primim:

Aceasta este o concluzie foarte importantă. Acum, în expresia „extinderea unui vector în vectori ortonormali” putem înlocui cuvântul „vector” cu „funcție” și obținem expresia complet corectă „extinderea unei funcții în funcții ortonormale”. Nu contează că avem o funcție atât de scurtă, deoarece același raționament funcționează pentru un vector N-dimensional, care poate fi reprezentat ca o funcție discretă cu N valori. Și lucrul cu funcții este mai clar decât cu vectori N-dimensionali. În schimb, puteți reprezenta o astfel de funcție ca un vector. Mai mult, de obicei funcție continuă poate fi reprezentat ca un vector infinit-dimensional, deși nu în spațiul euclidian, ci în spațiul Hilbert. Dar nu vom merge acolo, ne vor interesa doar funcțiile discrete.
Iar problema noastră de a găsi o bază se transformă în problema de a găsi un sistem adecvat de funcții ortonormale. În raționamentul următor, se presupune că am determinat deja cumva un set de funcții de bază, în funcție de care vom descompune.
Să presupunem că avem o anumită funcție (reprezentată, de exemplu, prin valori) pe care vrem să o reprezentăm ca sumă a altora. Puteți reprezenta acest proces în formă vectorială. Pentru a descompune o funcție, trebuie să o „proiectați” pe funcțiile de bază una câte una. În sens vectorial, calcularea proiecției oferă o apropiere minimă a vectorului original de altul în ceea ce privește distanța. Reținând că distanța este calculată folosind teorema lui Pitagora, o reprezentare similară sub formă de funcții oferă cea mai bună aproximare pătratică medie a unei funcții față de alta. Astfel, fiecare coeficient (k) determină „apropierea” funcției. Mai formal, k*e(x) este cea mai bună aproximare pătratică medie a f(x) dintre l*e(x).
Următorul exemplu arată procesul de aproximare a unei funcții folosind doar două puncte. În dreapta este o reprezentare vectorială.


În legătură cu experimentul nostru de împărțire în perechi, putem spune că aceste două puncte (0 și 1 de-a lungul abscisei) sunt o pereche de pixeli vecini (x, y).
Același lucru, dar cu animație:


Dacă luăm 3 puncte, atunci trebuie să luăm în considerare vectori 3D, cu toate acestea, aproximarea va fi mai precisă. Și pentru o funcție discretă cu N valori, trebuie să luați în considerare vectorii N-dimensionali.
Având un set de coeficienți obținuți, puteți obține cu ușurință funcția originală prin însumarea funcțiilor de bază luate cu coeficienții corespunzători. Analiza acestor coeficienți poate dezvălui multe Informatii utile(în funcție de bază). Un caz special al acestor considerații este principiul expansiunii seriei Fourier. La urma urmei, raționamentul nostru este aplicabil oricărei baze, iar atunci când ne extindem într-o serie Fourier, este luată una complet specifică.

Transformate Fourier discrete (DFT)

În partea anterioară, am ajuns la concluzia că ar fi bine să descompunem o funcție în componentele sale. La începutul secolului al XIX-lea, Fourier s-a gândit și el la acest lucru. Adevărat, nu avea o imagine a unui raton, așa că a trebuit să studieze distribuția căldurii de-a lungul inelului metalic. Apoi a aflat că este foarte convenabil să exprime temperatura (și modificarea acesteia) în fiecare punct al inelului ca o sumă de sinusoide cu perioade diferite. „Fourier a descoperit (recomand să citești, este interesant) că a doua armonică se dezintegra de 4 ori mai repede decât prima, iar armonicile de ordin superior se diminuează cu o viteză și mai rapidă.”
În general, s-a dovedit curând că funcțiile periodice pot fi descompuse perfect în suma sinusoidelor. Și deoarece în natură există multe obiecte și procese descrise de funcții periodice, a apărut un instrument puternic pentru analiza lor.
Poate că unul dintre cele mai vizuale procese periodice este sunetul.

  • Primul grafic - ton pur cu o frecvență de 2500 herți.
  • 2 - zgomot alb. Adică zgomot cu frecvențe distribuite uniform pe toată gama.
  • 3 - suma primelor două.
Dacă mi-ar fi dat valorile ultimei funcții în acel moment în care nu știam despre seria Fourier și mi-ar fi cerut să le analizez, atunci cu siguranță aș fi fost confuz și nu aș fi putut spune nimic util. Ei bine, da, un fel de funcție, dar de unde înțelegeți că există ceva ordonat acolo? Dar dacă aș fi ghicit să ascult ultima funcție, urechea mea ar fi prins un ton pur printre zgomot. Deși nu foarte bine, deoarece în timpul generării am selectat special astfel de parametri, astfel încât pe graficul rezumat semnalul să se dizolve vizual în zgomot. Din câte am înțeles, încă nu este clar cum aparat auditiv o face. Cu toate acestea, recent a devenit clar că nu descompune sunetul în unde sinusoidale. Poate că într-o zi vom înțelege cum se întâmplă acest lucru și vor apărea algoritmi mai avansați. Ei bine, deocamdată o facem la modă veche.
De ce să nu încercați să folosiți sinusoidele ca bază? De fapt, am făcut deja asta. Să ne amintim descompunerea noastră în 3 vectori de bază și să le prezentăm pe grafic:


Da, da, știu că pare o ajustare, dar cu trei vectori este greu de așteptat la mai mult. Dar acum este clar cum să obțineți, de exemplu, 8 vectori de bază:


Nu e bun verificare complexă arată că acești vectori sunt perpendiculari pe perechi, adică ortogonali. Aceasta înseamnă că pot fi folosite ca bază. Transformarea pe o astfel de bază este cunoscută pe scară largă și se numește transformată cosinus discretă (DCT). Cred că din graficele de mai sus este clar cum se obține formula de transformare DCT:

Aceasta este încă aceeași formulă: A = EX cu o bază substituită. Vectorii de bază ai DCT specificat (sunt, de asemenea, vectori rând ai matricei E) sunt ortogonali, dar nu ortonormali. Acest lucru ar trebui reținut în timpul transformării inverse (nu mă voi opri asupra acestui lucru, dar pentru cei interesați, DCT inversă are un termen 0,5*a 0 , deoarece vectorul de bază zero este mai mare decât celelalte).
Următorul exemplu arată procesul de aproximare a subtotalurilor la valorile originale. La fiecare iterație, următoarea bază este înmulțită cu următorul coeficient și adăugată la suma intermediară (adică la fel ca în experimentele timpurii pe raton - o treime din valori, două treimi).


Dar, cu toate acestea, în ciuda unor argumente despre oportunitatea alegerii unei astfel de baze, nu există încă argumente reale. Într-adevăr, spre deosebire de sunet, fezabilitatea descompunerii unei imagini în funcții periodice este mult mai puțin evidentă. Cu toate acestea, imaginea poate fi într-adevăr prea imprevizibilă chiar și într-o zonă mică. Prin urmare, imaginea este împărțită în bucăți suficient de mici, dar nu absolut mici, pentru ca descompunerea să aibă sens. În JPEG, imaginea este „tăiată” în pătrate de 8x8. În cadrul unei astfel de piese, fotografiile sunt de obicei foarte uniforme: fundalul plus mici fluctuații. Astfel de zone sunt frumos abordate de sinusoide.
Ei bine, să spunem că acest fapt este mai mult sau mai puțin intuitiv. Dar există un sentiment rău despre tranzițiile bruște de culoare, deoarece funcțiile care se schimbă încet nu ne vor salva. Trebuie să adăugăm diverse funcții de înaltă frecvență care își fac treaba, dar apar lateral pe un fundal omogen. Să luăm o imagine de 256x256 cu două zone contrastante:


Să descompunăm fiecare rând folosind DCT, obținând astfel 256 de coeficienți pe rând.
Apoi lăsăm numai primii n coeficienți și setăm restul la zero și, prin urmare, imaginea va fi prezentată ca o sumă a primelor armonice:


Numărul din imagine este numărul de cote rămase. În prima imagine rămâne doar valoarea medie. Pe cel de-al doilea, a fost deja adăugat un sinusoid de joasă frecvență etc. Apropo, acordați atenție marginii - în ciuda tuturor celor mai bune aproximări, 2 dungi sunt vizibile clar lângă diagonală, una mai deschisă, cealaltă mai întunecată. O parte din ultima imagine a fost mărită de 4 ori:

Și, în general, dacă departe de graniță vedem un fundal uniform inițial, atunci când ne apropiem de el, amplitudinea începe să crească, atinge în cele din urmă o valoare minimă și apoi devine brusc maximă. Acest fenomen este cunoscut sub numele de efectul Gibbs.


Înălțimea acestor cocoașe, care apar în apropierea discontinuităților funcției, nu va scădea pe măsură ce crește numărul de sume ale funcțiilor. Într-o transformare discretă dispare doar atunci când aproape toți coeficienții sunt păstrați. Mai exact, devine invizibil.
Următorul exemplu este complet similar cu descompunerea triunghiurilor de mai sus, dar pe un raton real:


Când studiem DCT, se poate avea impresia falsă că doar primii câțiva coeficienți (frecvență joasă) sunt întotdeauna suficienti. Acest lucru este valabil pentru multe bucăți de fotografii, cele ale căror semnificații nu se schimbă dramatic. Cu toate acestea, la granița zonelor contrastante, valorile vor „sări” rapid și chiar ultimii coeficienți vor fi mari. Prin urmare, atunci când auziți despre proprietatea de conservare a energiei a DCT, luați în considerare faptul că se aplică multor tipuri de semnale întâlnite, dar nu tuturor. De exemplu, gândiți-vă la cum ar arăta o funcție discretă, ai cărei coeficienți de expansiune sunt egali cu zero, cu excepția ultimei. Sugestie: Gândiți-vă la descompunerea sub formă vectorială.
În ciuda deficiențelor, baza aleasă este una dintre cele mai bune din fotografiile reale. Vom vedea o mică comparație cu altele puțin mai târziu.

DCT vs orice altceva

Când am studiat problema transformărilor ortogonale, sincer să fiu, nu am fost foarte convins de argumentele că totul în jur este o sumă. vibratii armonice, așa că trebuie să descompuneți imaginile în sinusoide. Sau poate ar fi mai bune unele funcții pas? Prin urmare, am căutat rezultatele cercetării privind optimitatea DCT pe imagini reale. Faptul că „DCT este cel mai des întâlnit în aplicațiile practice datorită proprietății „compacției energetice”” este scris peste tot. Această proprietate înseamnă că cantitatea maximă de informații este conținută în primii coeficienți. Și de ce? Nu este dificil să facem cercetări: ne înarmam cu o grămadă de imagini diferite, baze cunoscute diferite și începem să calculăm abaterea standard de la imaginea reală pentru un număr diferit de coeficienți. Am gasit un mic studiu intr-un articol (imagini folosite) despre aceasta tehnica. Prezintă grafice ale dependenței energiei stocate de numărul de primii coeficienți de expansiune pentru diferite baze. Dacă te uitai la topuri, erai convins că DCT ocupă în mod constant un onorabil... um... locul 3. Cum așa? Ce fel de conversie KLT este aceasta? Lăudam DCT și apoi...
KLT
Toate transformările, cu excepția KLT, sunt transformări cu o bază constantă. Și în KLT (transformata Karhunen-Loeve) se calculează cea mai optimă bază pentru mai mulți vectori. Se calculează în așa fel încât primii coeficienți să dea cea mai mică eroare pătratică medie în total pentru toți vectorii. Am efectuat anterior lucrări similare manual, determinând vizual baza. La început pare o idee bună. Am putea, de exemplu, să împărțim imaginea în secțiuni mici și să calculăm propria bază pentru fiecare. Dar nu numai că există preocuparea de a stoca această bază, ci și operațiunea de calculare a acesteia este destul de intensivă în muncă. Dar DCT pierde doar puțin și, în plus, DCT are algoritmi de conversie rapidă.
DFT
DFT (transformată Fourier discretă) - transformare discretă Fourier. Sub acest nume, nu se face referire uneori doar la o anumită transformare, ci și la întreaga clasă de transformări discrete (DCT, DST...). Să ne uităm la formula DFT:

După cum ați putea ghici, aceasta este o transformare ortogonală cu un fel de bază complexă. Deoarece o formă atât de complexă apare puțin mai des decât de obicei, este logic să studiem derivarea ei.
Poate părea că orice semnal armonic pur (cu o frecvență întreagă) cu descompunere DCT va da un singur coeficient diferit de zero corespunzător acestei armonice. Acest lucru nu este adevărat, deoarece, pe lângă frecvență, este importantă și faza acestui semnal. De exemplu, extinderea sinusului în cosinus (în mod similar în expansiunea discretă) va fi astfel:

Atât pentru armonici pure. Ea a dat naștere la o grămadă de alții. Animația arată coeficienții DCT ai undei sinusoidali diferite faze.


Dacă ți s-a părut că coloanele se rotesc în jurul unei axe, atunci nu ți s-a părut.
Deci acum nu vom extinde pur și simplu funcția în suma sinusoidelor frecvente diferite, dar și mutat într-o anumită fază. Va fi mai convenabil să luați în considerare defazajul folosind exemplul cosinus:

O identitate trigonometrică simplă dă un rezultat important: defazajul este înlocuit cu suma sinusului și cosinusului, luate cu coeficienții cos(b) și sin(b). Aceasta înseamnă că funcțiile pot fi extinse în suma sinusurilor și cosinusurilor (fără faze). Aceasta este o formă trigonometrică comună. Cu toate acestea, complexul este folosit mult mai des. Pentru a-l obține trebuie să utilizați formula lui Euler. Pur și simplu înlocuind formulele derivate pentru sinus și cosinus, obținem:


Acum pentru o mică schimbare. Sublinierea este un număr conjugat.

Obținem egalitatea finală:

c este un coeficient complex, a cărui parte reală este egală cu coeficientul cosinus, iar partea imaginară este egală cu coeficientul sinus. Și mulțimea de puncte (cos(b), sin(b)) este un cerc. Într-o astfel de înregistrare, fiecare armonică intră în expansiune atât cu o frecvență pozitivă, cât și cu una negativă. Prin urmare, în diferite formule de analiză Fourier, însumarea sau integrarea are loc de obicei de la minus la plus infinit. Este adesea mai convenabil să efectuați calcule în această formă complexă.
Transformarea descompune semnalul în armonici cu frecvențe de la unu la N oscilații în regiunea semnalului. Dar rata de eșantionare este N pe zonă de semnal. Și conform teoremei lui Kotelnikov (alias teorema Nyquist-Shannon), frecvența de eșantionare ar trebui să fie macar de două ori mai mare decât frecvența semnalului. Dacă nu este cazul, atunci efectul este apariția unui semnal cu o frecvență falsă:


Linia punctată arată semnalul reconstruit incorect. Te-ai confruntat adesea cu acest fenomen în viață. De exemplu, mișcarea amuzantă a roților mașinii într-un videoclip sau efectul moire.
Acest lucru duce la faptul că a doua jumătate a amplitudinilor complexului N pare să fie formată din alte frecvențe. Aceste armonice false din a doua jumătate sunt imagine in oglinda ei nu o poartă primii Informații suplimentare. Astfel, rămânem cu N/2 cosinus și N/2 sinusuri (formând o bază ortogonală).
Bine, există o bază. Componentele sale sunt armonici cu un număr întreg de oscilații în regiunea semnalului, ceea ce înseamnă că valorile extreme ale armonicilor sunt egale. Mai precis, ele sunt aproape egale, deoarece ultima valoare nu este luată în întregime de la margine. Mai mult, fiecare armonică este aproape simetrică în oglindă față de centrul său. Toate aceste fenomene sunt deosebit de puternice în frecvente joase, care sunt importante pentru noi atunci când codificăm. Acest lucru este, de asemenea, rău, deoarece limitele blocurilor vor fi vizibile în imaginea comprimată. Permiteți-mi să ilustrez baza DFT cu N=8. Primele 2 rânduri sunt componente cosinus, ultimele sunt sinus:


Acordați atenție aspectului componentelor duplicate pe măsură ce frecvența crește.

Vă puteți gândi mental cum ar putea fi descompus un semnal ale cărui valori scad treptat de la o valoare maximă la început la o valoare minimă la sfârșit. O aproximare mai mult sau mai puțin adecvată ar putea fi făcută doar de armonici spre final, ceea ce nu este foarte grozav pentru noi. Figura din stânga este o aproximare a unui semnal cu un singur capăt. În dreapta - simetric:


Lucrurile sunt extrem de proaste cu primul.
Deci, poate o putem face ca în DCT - reduceți frecvențele de 2 sau de un alt număr de ori, astfel încât numărul unor oscilații să fie fracționat și limitele să fie în faze diferite? Atunci componentele vor fi non-ortogonale. Și nu e nimic de făcut în privința asta.

Ora de oră
Ce se întâmplă dacă folosim sinusuri în loc de cosinus în DCT? Vom obține Transformarea Sinusoială Discretă (DST). Dar pentru sarcina noastră, toate sunt neinteresante, deoarece ambele perioade întregi și jumătate ale sinusurilor sunt aproape de zero la granițe. Adică vom obține aproximativ aceeași descompunere inadecvată ca cea a DFT.
Revenind la DCT
Cum se simte la granițe? Amenda. Există antifaze și fără zerouri.
Toate celelalte
Transformări non-Fourier. Nu o voi descrie.
WHT - matricea constă numai din componente de pas cu valorile -1 și 1.
Haar este, de asemenea, o transformare wavelet ortogonală.
Sunt inferioare DCT, dar sunt mai ușor de calculat.

Așadar, ți-a venit ideea să vii cu propria ta transformare. Tine minte asta:

  1. Baza trebuie să fie ortogonală.
  2. Cu o bază fixă, nu poți învinge KLT pentru calitatea compresiei. Între timp, în fotografiile reale, DCT este aproape la fel de bun.
  3. Folosind exemplul DFT și DST, trebuie să vă amintiți despre granițe.
  4. Și amintiți-vă că DCT are un alt avantaj bun - lângă granițele componentelor lor, derivatele sunt egale cu zero, ceea ce înseamnă că tranziția între blocurile învecinate va fi destul de lină.
  5. Transformele Fourier au algoritmi rapizi cu complexitatea O(N*logN), spre deosebire de calculul simplu: O(N 2).
Nu va fi ușor, nu? Cu toate acestea, pentru unele tipuri de imagini este posibil să se selecteze o bază mai bună decât cea a DCT.

Transformări 2D

Acum să încercăm să facem un astfel de experiment. Să luăm, de exemplu, o bucată dintr-o imagine.


Graficul lui 3D:


Să trecem prin DCT(N=32) prin fiecare linie:


Acum vreau să-ți treci ochii prin fiecare coloană a coeficienților rezultați, adică de sus în jos. Amintiți-vă că scopul nostru este să lăsăm cât mai puține valori, eliminându-le pe cele care nu sunt semnificative. Probabil ați ghicit că valorile fiecărei coloane ale coeficienților rezultați pot fi extinse exact în același mod ca și valorile imaginii originale. Nimeni nu ne limitează în alegerea unei matrice de transformare ortogonală, dar o vom face din nou folosind DCT(N=8):


Coeficientul (0,0) sa dovedit a fi prea mare, deci este redus de 4 ori în grafic.
Deci ce s-a întâmplat?
Colțul din stânga sus reprezintă cei mai semnificativi coeficienți de expansiune a celor mai semnificativi coeficienți.
Colțul din stânga jos este cei mai nesemnificativi coeficienți de expansiune a celor mai semnificativi coeficienți.
Colțul din dreapta sus este cei mai semnificativi coeficienți de expansiune a celor mai nesemnificativi coeficienți.
Colțul din dreapta jos este cei mai nesemnificativi coeficienți de expansiune a celor mai nesemnificativi coeficienți.
Este clar că semnificația coeficienților scade dacă te deplasezi în diagonală din stânga sus la dreapta jos. Care este mai important: (0, 7) sau (7, 0)? Ce înseamnă ele?
Mai întâi, pe rânduri: A 0 = (EX T) T = XE T (transpus, întrucât formula este A=EX pentru coloane), apoi pe coloane: A=EA 0 = EXE T . Dacă calculezi cu atenție, obții formula:

Astfel, dacă un vector este descompus în sinusoide, atunci matricea este descompusă în funcții de forma cos(ax)*cos(by). Fiecare bloc 8x8 din JPEG este reprezentat ca o sumă a 64 de funcții de forma:


În Wikipedia și în alte surse, astfel de funcții sunt prezentate într-o formă mai convenabilă:


Prin urmare, coeficienții (0, 7) sau (7, 0) sunt la fel de utili.
Cu toate acestea, de fapt, aceasta este o descompunere unidimensională obișnuită în 64 de baze cu 64 de dimensiuni. Toate cele de mai sus se aplică nu numai pentru DCT, ci și pentru orice descompunere ortogonală. Procedând prin analogie, în cazul general obținem o transformare ortogonală N-dimensională.
Și iată o transformare 2D a unui raton (DCT 256x256). Din nou, cu valorile resetate la zero. Numere - numărul de coeficienți nezeroiți din toate (s-au reținut cele mai semnificative valori, situate în zona triunghiulară din colțul din stânga sus).


Amintiți-vă că coeficientul (0, 0) se numește DC, restul de 63 se numește AC.

Alegerea unei dimensiuni de bloc

Un prieten întreabă de ce JPEG folosește partiționarea 8x8. Din răspunsul votat negativ:
DCT tratează blocul ca și cum ar fi periodic și trebuie să reconstruiască saltul rezultat la granițe. Dacă luați blocuri de 64x64, cel mai probabil veți avea un salt uriaș la granițe și veți avea nevoie de o mulțime de componente de înaltă frecvență pentru a le reconstrui cu o precizie satisfăcătoare.
De exemplu, DCT funcționează bine doar pe funcțiile periodice și, dacă mergeți mare, probabil veți obține un salt uriaș la granițele blocurilor și veți avea nevoie de o mulțime de componente de înaltă frecvență pentru a-l acoperi. Nu este adevarat! Această explicație este foarte asemănătoare cu DFT, dar nu și cu DCT, deoarece acoperă perfect astfel de salturi cu primele componente.
Pe aceeași pagină este un răspuns de la MPEG FAQ, cu principalele argumente împotriva blocurilor mari:
  • Profit mic atunci când este împărțit în blocuri mari.
  • Creșterea complexității de calcul.
  • Probabilitate mare cantitate mare granițe ascuțite într-un singur bloc, ceea ce va provoca efectul Gibbs.
Îți sugerez să cercetezi asta singur. Sa incepem cu primul.


Axa orizontală arată ponderea primilor coeficienți nezeroiți. Verticală - abaterea standard a pixelilor față de original. Abaterea maximă posibilă este luată ca una. Desigur, o imagine nu este suficientă pentru un verdict. În plus, nu acționez în întregime corect, pur și simplu resetând la zero. Într-un JPEG real, în funcție de matricea de cuantizare, doar valorile mici ale componentelor de înaltă frecvență sunt zero. Prin urmare, următoarele experimente și concluzii sunt menite să scoată la suprafață principiile și modelele.
Puteți compara împărțirea în blocuri diferite cu 25% din coeficienți la stânga (de la stânga la dreapta, apoi de la dreapta la stânga):

Blocurile mari nu sunt afișate, deoarece sunt aproape imposibil de distins vizual de 32x32. Acum să ne uităm la diferența absolută cu imaginea originală (amplificată de 2 ori, altfel nimic nu este cu adevărat vizibil):

8x8 dă cel mai bun rezultat decât 4x4. O creștere suplimentară a dimensiunii nu mai oferă un avantaj clar vizibil. Deși aș lua în considerare serios 16x16 în loc de 8x8: creșterea complexității cu 33% (mai multe despre complexitate în paragraful următor) oferă o îmbunătățire mică, dar încă vizibilă pentru același număr de coeficienți. Cu toate acestea, alegerea 8x8 pare destul de rezonabilă și poate fi mijlocul de aur. JPEG a fost publicat în 1991. Cred că o astfel de compresie era foarte dificilă pentru procesoarele de atunci.

Al doilea argument. Un lucru de reținut este că creșterea dimensiunii blocului va necesita mai multe calcule. Să estimem cât. Complexitatea conversiei, așa cum știm deja destul de bine: O(N 2), deoarece fiecare coeficient este format din N termeni. Dar, în practică, se folosește un algoritm eficient de transformare rapidă Fourier (FFT). Descrierea sa depășește scopul acestui articol. Complexitatea sa: O(N*logN). Pentru o expansiune bidimensională trebuie să o utilizați de două ori de N ori. Deci complexitatea DCT 2D este O(N 2 logN). Acum să comparăm complexitatea calculării unei imagini cu un singur bloc și mai multe mici:

  • Un bloc (kN)x(kN): O((kN) 2 log(kN)) = O(k 2 N 2 log(kN))
  • k*k blocuri N*N: O(k 2 N 2 logN)
Aceasta înseamnă că, de exemplu, calculul pentru o partiție 64x64 este de două ori mai complex decât o partiție 8x8.

Al treilea argument. Dacă avem o margine ascuțită de culori în imagine, atunci acest lucru va afecta întregul bloc. Poate că ar fi mai bine ca acest bloc să fie suficient de mic, pentru că în multe blocuri învecinate probabil nu va mai exista o asemenea graniță. Cu toate acestea, departe de granițe, atenuarea are loc destul de repede. În plus, granița în sine va arăta mai bine. Să o verificăm folosind un exemplu cu un număr mare de tranziții de contrast, din nou, cu doar un sfert din coeficienți:


Deși distorsiunea blocurilor 16x16 se extinde mai mult decât cea a 8x8, inscripția este mai netedă. Prin urmare, doar primele două argumente m-au convins. Dar cumva îmi place mai mult diviziunea 16x16.

Cuantizarea

În acest moment avem o grămadă de matrice 8x8 cu coeficienți de transformare cosinus. Este timpul să scăpăm de coeficienți nesemnificativi. Există o soluție mai elegantă decât simpla resetare a ultimilor coeficienți la zero, așa cum am făcut mai sus. Nu suntem mulțumiți de această metodă, deoarece valorile fără zero sunt stocate cu o precizie excesivă, iar printre cei care au avut ghinion ar putea fi și unele destul de importante. Soluția este utilizarea unei matrice de cuantizare. Pierderile apar tocmai în această etapă. Fiecare coeficient Fourier este împărțit la numărul corespunzător din matricea de cuantizare. Să ne uităm la un exemplu. Să luăm primul bloc de la ratonul nostru și să realizăm cuantizarea. Specificația JPEG oferă o matrice standard:


Matricea standard corespunde unei calități de 50% în FastStone și IrfanView. Acest tabel a fost ales din punct de vedere al echilibrului între calitate și raportul de compresie. Cred că valoarea coeficientului DC este mai mare decât vecinii săi datorită faptului că DCT nu este normalizat și prima valoare este mai mare decât ar trebui. Coeficienții de înaltă frecvență sunt amplificați mai puternic datorită importanței lor mai mici. Cred că astfel de matrici sunt rar folosite acum, deoarece deteriorarea calității este clar vizibilă. Nimeni nu interzice utilizarea tabelului dvs. (cu valori de la 1 la 255)
În timpul decodării, are loc procesul invers - coeficienții cuantificați sunt înmulțiți termen cu termen cu valorile matricei de cuantizare. Dar, din moment ce am rotunjit valorile, nu vom putea restabili cu acuratețe coeficienții Fourier originali. Cu cât numărul de cuantizare este mai mare, cu atât eroarea este mai mare. Astfel, coeficientul reconstruit este doar cel mai apropiat multiplu.
Alt exemplu:

Iar pentru desert, luați în considerare o calitate de 5% (când codați în Fast Stone).


Când restabilim acest bloc, vom obține doar valoarea medie plus gradientul vertical (datorită valorii păstrate de -1). Dar doar două valori sunt stocate pentru acesta: 7 și -1. Situația nu este mai bună cu alte blocuri, iată imaginea restaurată:

Apropo, cam 100% calitate. După cum ați putea ghici, în acest caz matricea de cuantizare constă în întregime din unități, adică nu are loc nicio cuantizare. Cu toate acestea, din cauza rotunjirii coeficienților la cel mai apropiat număr întreg, nu putem restabili cu acuratețe imaginea originală. De exemplu, ratonul a păstrat exact 96% din pixeli, dar 4% au fost reduse cu 1/256. Desigur, astfel de „distorsiuni” nu pot fi observate vizual.
Sau puteți privi matricele de cuantizare ale diferitelor camere.

Codificarea

Înainte de a trece mai departe, trebuie să folosim exemple mai simple pentru a înțelege cum putem comprima valorile rezultate.

Exemplul 0(pentru incalzire)
Imaginează-ți o astfel de situație în care prietenul tău a uitat o foaie de hârtie cu o listă la tine acasă și acum îți cere să o dictezi la telefon (nu există alte metode de comunicare).
Listă:

  • d9rg3
  • wfr43gt
  • wfr43gt
  • d9rg3
  • d9rg3
  • d9rg3
  • wfr43gt
  • d9rg3
Cum ți-ai face sarcina mai ușoară? Nu aveți nicio dorință specială să dictați dureros toate aceste cuvinte. Dar sunt doar două și se repetă. Prin urmare, pur și simplu dictați cumva primele două cuvinte și sunteți de acord că de acum înainte veți numi „d9rg3” primul cuvânt și „wfr43gt” al doilea. Atunci va fi suficient să dictați: 1, 2, 2, 1, 1, 1, 2, 1.

Vom desemna cuvinte precum A, B, C... și le vom numi simboluri. Mai mult, orice poate fi ascuns sub simbol: o literă a alfabetului, un cuvânt sau un hipopotam în grădina zoologică. Principalul lucru este că simbolurile identice corespund unor concepte identice, iar altele diferite corespund unora diferite. Deoarece sarcina noastră este o codificare (compresie) eficientă, vom lucra cu biți, deoarece acestea sunt cele mai mici unități de reprezentare a informațiilor. Prin urmare, să scriem lista ca ABBAAABA. În loc de „primul cuvânt” și „al doilea cuvânt”, puteți folosi biții 0 și 1. Apoi ABBAAABA este codificat ca 01100010 (8 biți = 1 octet).

Exemplul 1
Codificați ABC.
Nu există nicio modalitate ca 3 caractere diferite (A, B, C) să poată fi asociate cu 2 valori posibile de biți (0 și 1). Și dacă da, atunci puteți folosi 2 biți per simbol. De exemplu:

  • A: 00
  • B:01
  • C: 10
Secvența de biți asociată unui simbol va fi numită cod. ABC va fi codificat astfel: 000110.

Exemplul 2
Codificați AAAAAABC.
Folosirea a 2 biți pe caracterul A pare puțin irosită. Ce se întâmplă dacă încerci asta:

  • C: 00

Secvență codificată: 000000100.
Evident, această opțiune nu este potrivită, deoarece nu este clar cum să decodați primii doi biți ai acestei secvențe: ca AA sau ca C? Este foarte risipitor să folosim orice separator între coduri, ne vom gândi cum să ocolim acest obstacol într-un mod diferit. Deci, eșecul se datorează faptului că codul lui C începe cu codul lui A. Dar suntem hotărâți să codificăm A cu un bit, chiar dacă B și C au câte doi. Pe baza acestei dorințe, îi dăm lui A codul 0. Apoi codurile B și C nu pot începe cu 0. Dar pot începe cu 1:
  • B: 10
  • C: 11

Secvența este codificată astfel: 0000001011. Încercați să o decodați mental. Poți face asta doar într-un singur fel.
Am dezvoltat două cerințe de codare:
  1. Cu cât greutatea unui simbol este mai mare, cu atât codul acestuia ar trebui să fie mai scurt. Si invers.
  2. Pentru decodare fără ambiguitate, un cod de caracter nu poate începe cu codul oricărui alt caracter.
Evident, ordinea personajelor nu este importantă, ne interesează doar frecvența apariției lor. Prin urmare, fiecare simbol este asociat cu un număr numit greutate. Greutatea unui simbol poate fi după cum urmează: mărime relativă, care reflectă ponderea apariției sale și absolută, egală cu numărul de caractere. Principalul lucru este că ponderile sunt proporționale cu apariția simbolurilor.

Exemplul 3
Să luăm în considerare cazul general pentru 4 simboluri cu orice pondere.

  • A:pa
  • B:pb
  • C:buc
  • D:pd
Fără pierderea generalității, punem pa ≥ pb ≥ pc ≥ pd. Există doar două opțiuni care diferă fundamental în lungimea codului:


Care este de preferat? Pentru a face acest lucru, trebuie să calculați lungimile rezultate ale mesajelor codificate:
W1 = 2*pa + 2*pb + 2*buc + 2*pd
W2 = pa + 2*pb + 3*buc + 3*pd
Dacă W1 este mai mic decât W2 (W1-W2<0), то лучше использовать первый вариант:
W1-W2 = pa - (buc+pd)< 0 =>pa< pc+pd.
Dacă C și D apar împreună mai des decât altele, atunci vârful lor comun primește cel mai scurt cod de un bit. În caz contrar, un bit merge la caracterul A. Aceasta înseamnă că uniunea de caractere se comportă ca un caracter independent și are o pondere egală cu suma caracterelor introduse.
În general, dacă p este greutatea unui caracter reprezentată de fracția de apariție a acestuia (de la 0 la 1), atunci cea mai bună lungime a codului este s=-log 2 p.
Să ne uităm la asta caz simplu(este usor sa-l imaginezi sub forma unui copac). Deci, trebuie să codificăm caractere de 2 s cu greutăți egale (1/2 s). Datorită egalității greutăților, lungimile codului vor fi aceleași. Fiecare personaj va necesita biți. Aceasta înseamnă că dacă greutatea unui simbol este 1/2 s, atunci lungimea acestuia este s. Dacă înlocuim greutatea cu p, obținem lungimea codului s=-log 2 p . Aceasta înseamnă că, dacă un caracter apare de două ori mai des decât altul, atunci lungimea codului său va fi cu un pic mai mare. Cu toate acestea, această concluzie este ușor de tras dacă vă amintiți că adăugarea unui bit vă permite să dublați numărul de opțiuni posibile.
Și încă o observație - cele două simboluri cu cele mai mici greutăți au întotdeauna cea mai mare, dar lungimi egale coduri Mai mult, bițurile lor, cu excepția ultimului, sunt aceleași. Dacă acest lucru nu ar fi adevărat, atunci cel puțin un cod ar putea fi scurtat cu 1 bit fără a rupe prefixul. Aceasta înseamnă că cele două simboluri cu cele mai mici ponderi din arborele de cod au un părinte comun la un nivel superior. Puteți vedea acest lucru în exemplele C și D de mai sus.

Exemplul 4
Să încercăm să rezolvăm următorul exemplu, pe baza concluziilor obținute în exemplul anterior.

  1. Toate simbolurile sunt sortate în ordinea descrescătoare a greutăților.
  2. Ultimele două simboluri sunt combinate într-un grup. Acestui grup i se atribuie o pondere egală cu suma greutăților acestor elemente. Acest grup participă la algoritm împreună cu simboluri și alte grupuri.
Pașii se repetă până când rămâne un singur grup. În cadrul fiecărui grup, unui caracter (sau subgrup) i se atribuie bitul 0 și un alt caracter bitul 1.
Acest algoritm se numește codare Huffman.
Ilustrația prezintă un exemplu cu 5 caractere (A: 8, B: 6, C: 5, D: 4, E: 3). În dreapta este greutatea simbolului (sau grupului).

Codificăm coeficienții

Să ne întoarcem. Acum avem multe blocuri cu 64 de coeficienți în fiecare, care trebuie salvate cumva. Cea mai simplă soluție este utilizarea unui număr fix de biți pe coeficient - evident fără succes. Să construim o histogramă a tuturor valorilor obținute (adică, dependența numărului de coeficienți de valoarea lor):


Vă rugăm să rețineți - scara este logaritmică! Puteți explica motivul apariției unui grup de valori care depășește 200? Aceștia sunt coeficienți DC. Deoarece sunt foarte diferite de celelalte, nu este de mirare că sunt codificate separat. Iată doar DC:


Rețineți că forma graficului amintește de graficele din cele mai vechi experimente de asociere și triplare a pixelilor.
În general, valorile coeficientului DC pot varia de la 0 la 2047 (mai precis de la -1024 la 1023, deoarece JPEG scade 128 din toate valorile originale, ceea ce corespunde cu scăderea a 1024 din DC) și este distribuit destul de uniform cu vârfuri mici. Deci codarea Huffman nu va ajuta prea mult aici. Și imaginați-vă cât de mare va fi arborele de codare! Și în timpul decodării va trebui să cauți semnificații în ea. E foarte scump. Ne gândim mai departe.
Coeficientul DC este valoarea medie a unui bloc de 8x8. Să ne imaginăm o tranziție de gradient (deși nu ideală), care se găsește adesea în fotografii. Valorile DC în sine vor fi diferite, dar vor reprezenta o progresie aritmetică. Aceasta înseamnă că diferența lor va fi mai mult sau mai puțin constantă. Să construim o histogramă a diferențelor:


Acest lucru este mai bine, deoarece valorile sunt în general concentrate în jurul zero (dar algoritmul Huffman va da din nou un copac prea mare). Valori mici (de valoare absolută) sunt comune, cele mari sunt rare. Și deoarece valorile mici ocupă câțiva biți (dacă eliminați zerourile de început), una dintre regulile de compresie funcționează bine: atribuiți simboluri cu greutăți mari coduri scurte(si invers). În prezent suntem limitați de nerespectarea unei alte reguli: imposibilitatea decodării fără ambiguitate. În general, această problemă poate fi rezolvată în următoarele moduri: deranjează codul delimitator, indica lungimea codului, folosește coduri de prefix (le știi deja - acesta este cazul când niciun cod nu începe cu altul). Să mergem cu a doua variantă simplă, adică fiecare coeficient (mai precis, diferența dintre cei vecini) se va scrie astfel: (lungime)(valoare), după acest semn:


Adică, valorile pozitive sunt codificate direct prin reprezentarea lor binară, iar valorile negative sunt codificate în același mod, dar cu primul 1 înlocuit cu 0. Rămâne să decideți cum să codificați lungimile. Deoarece există 12 valori posibile, se pot folosi 4 biți pentru a stoca lungimea. Dar aici este mai bine să folosiți codarea Huffman.


Există cele mai multe valori cu lungimile 4 și 6, așa că au primit cele mai scurte coduri (00 și 01).


Poate apărea întrebarea: de ce, în exemplu, valoarea 9 are codul 1111110, și nu 1111111? La urma urmei, poți ridica în siguranță „9” la un nivel superior, lângă „0”? Cert este că în JPEG nu poți folosi un cod format doar din unele - un astfel de cod este rezervat.
Mai există o caracteristică. Codurile obținute de algoritmul Huffman descris pot să nu coincidă în biți cu codurile în JPEG, deși lungimile lor vor fi aceleași. Folosind algoritmul Huffman, se obțin lungimile codurilor și se generează codurile în sine (algoritmul este simplu - începeți cu coduri scurte și adăugați-le unul câte unul în arbore cât mai la stânga posibil, păstrând proprietatea prefixului ). De exemplu, pentru arborele de deasupra lista este stocată: 0,2,3,1,1,1,1,1. Și, desigur, este stocată o listă de valori: 4,6,3,5,7,2,8,1,0,9. În timpul decodării, codurile sunt generate în același mod.

Acum totul este în ordine. Ne-am dat seama cum sunt stocate DC-urile:
[Cod Huffman pentru lungimea diferențelor DC (în biți)]
unde DC diff = curent DC - DC anterior

Să ne uităm la AC:


Deoarece graficul este foarte asemănător cu graficul pentru diferențele DC, principiul este același: [Cod Huffman pentru lungimea AC (în biți)]. Dar nu chiar! Deoarece scara de pe grafic este logaritmică, nu se observă imediat că există de aproximativ 10 ori mai multe valori zero decât valorile 2, următoarea cea mai frecventă. Acest lucru este de înțeles - nu toată lumea a supraviețuit cuantizării. Să revenim la matricea valorilor obținute în timpul etapei de cuantizare (folosind matricea de cuantizare FastStone, 90%).

Deoarece există multe grupuri de zerouri consecutive, apare o idee - să scrieți doar numărul de zerouri din grup. Acest algoritm de compresie se numește RLE (Run-length encoding). Rămâne să aflăm direcția de ocolire a „consecutivului” - cine este în spatele cui? Scrierea de la stânga la dreapta și de sus în jos nu este foarte eficientă, deoarece coeficienții non-zero sunt concentrați în colțul din stânga sus, iar cu cât mai aproape de dreapta jos, cu atât mai multe zerouri.


Prin urmare, JPEG folosește o ordine numită „Zig-zag”, care este prezentată în figura din stânga. Această metodă distinge bine grupurile de zerouri. În imaginea din dreapta există o metodă alternativă de bypass, care nu are legătură cu JPEG, dar cu un nume (dovadă) curios. Poate fi folosit în MPEG pentru compresia video întrețesată. Alegerea algoritmului de traversare nu afectează calitatea imaginii, dar poate crește numărul de grupuri codificate de zerouri, ceea ce poate afecta în cele din urmă dimensiunea fișierului.
Să ne modificăm intrarea. Pentru fiecare coeficient AC diferit de zero:
[Numărul de zerouri înainte de AC][Cod Huffman pentru lungimea AC (în biți)]
Cred că puteți spune imediat că și numărul de zerouri este perfect codificat de Huffman! Acesta este un răspuns foarte apropiat și bun. Dar se poate optimiza puțin. Imaginați-vă că avem un coeficient AC, înaintea căruia erau 7 zerouri (desigur, dacă sunt scrise în ordine în zig-zag). Aceste zerouri sunt spiritul valorilor care nu au supraviețuit cuantizării. Cel mai probabil, și coeficientul nostru a fost grav deteriorat și a devenit mic, ceea ce înseamnă că lungimea lui este mică. Aceasta înseamnă că numărul de zerouri în fața AC și lungimea AC sunt mărimi dependente. Prin urmare, scriem astfel:
[Cod Huffman pentru (Numărul de zerouri înainte de AC, lungimea AC (în biți)]
Algoritmul de codificare rămâne același: acele perechi (număr de zerouri înainte de AC, lungimea AC) care apar frecvent vor primi coduri scurte și invers.

Construim o histogramă a dependenței de cantitate pentru aceste perechi și un arbore Huffman.


„Creasta montană” lungă confirmă presupunerea noastră.

Caracteristici de implementare în JPEG:
O astfel de pereche ocupă 1 octet: 4 biți pentru numărul de zerouri și 4 biți pentru lungimea AC. 4 biți sunt valori de la 0 la 15. Pentru lungimea AC acest lucru este mai mult decât suficient, dar pot fi mai mult de 15 zerouri? Apoi se folosesc mai multe perechi. De exemplu, pentru 20 de zerouri: (15, 0)(5, AC). Adică, al 16-lea zero este codificat ca un coeficient diferit de zero. Deoarece există întotdeauna o mulțime de zerouri aproape de sfârșitul blocului, perechea (0,0) este utilizată după ultimul coeficient diferit de zero. Dacă este întâlnit în timpul decodării, atunci valorile rămase sunt 0.

Am aflat că fiecare bloc este codificat și stocat într-un fișier ca acesta:
[Cod Huffman pentru lungimea diferențelor DC]
[Cod Huffman pentru (număr de zerouri înainte de AC 1, lungimea AC 1]

[Cod Huffman pentru (numărul de zerouri înainte de AC n, lungimea AC n]
Unde AC i sunt coeficienți AC diferiti de zero.

Imagine color

Modul în care este reprezentată o imagine color depinde de modelul de culoare selectat. Soluția simplă este să folosiți RGB și să codificați fiecare canal de culoare imaginile separat. Atunci codarea nu va fi diferită de codificarea unei imagini gri, doar de 3 ori mai mult lucru. Dar compresia imaginii poate fi crescută dacă ne amintim că ochiul este mai sensibil la schimbările de luminozitate decât culorile. Aceasta înseamnă că culoarea poate fi stocată cu pierderi mai mari decât luminozitatea. RGB nu are un canal de luminozitate separat. Depinde de suma valorilor fiecărui canal. Prin urmare, cubul RGB (aceasta este o reprezentare a tuturor valorilor posibile) este pur și simplu „plasat” pe diagonală - cu cât mai sus, cu atât mai luminos. Dar nu se opresc aici - cubul este apăsat puțin din lateral și se dovedește mai mult ca un paralelipiped, dar acest lucru este doar pentru a ține cont de trăsăturile ochiului. De exemplu, este mai sensibil la verde decât la albastru. Așa a apărut modelul YCbCr.


(Imagine de la Intel.com)
Y este componenta de luminanță, Cb și Cr sunt componentele diferențelor de culoare albastru și roșu. Prin urmare, dacă doresc să comprima mai mult imaginea, atunci RGB este convertit în YCbCr, iar canalele Cb și Cr sunt subțiate. Adică, ele sunt împărțite în blocuri mici, de exemplu 2x2, 4x2, 1x2, iar toate valorile unui bloc sunt mediate. Sau, cu alte cuvinte, reduc dimensiunea imaginii pentru acest canal de 2 sau 4 ori vertical și/sau orizontal.


Fiecare bloc 8x8 este codificat (DCT + Huffman), iar secvențele codificate sunt scrise în această ordine:

Este curios că specificația JPEG nu limitează alegerea modelului, adică implementarea codificatorului poate împărți imaginea în componente de culoare (canale) în orice mod și fiecare va fi salvată separat. Sunt conștient de utilizarea în tonuri de gri (1 canal), YCbCr (3), RGB (3), YCbCrK (4), CMYK (4). Primele trei sunt susținute de aproape toată lumea, dar sunt probleme cu ultimele cu 4 canale. FastStone, GIMP le suportă corect și standard programe Windows, paint.net extrage corect toate informațiile, dar apoi aruncă al 4-lea canal negru, așa că (Antelle a spus că nu-l aruncă, citește-i comentariile) arată o imagine mai ușoară. În stânga este clasicul JPEG YCbCr, în dreapta este CMYK JPEG:



Dacă diferă în culoare, sau este vizibilă o singură imagine, atunci cel mai probabil aveți IE (orice versiune) (UPD. în comentarii spun „sau Safari”). Puteți încerca să deschideți articolul în diferite browsere.

Și încă ceva

Pe scurt despre caracteristici suplimentare.
Modul progresiv
Să descompunăm tabelele rezultate ale coeficienților DCT în suma tabelelor (aproximativ astfel (DC, -19, -22, 2, 1) = (DC, 0, 0, 0, 0) + (0, -20) , -20, 0, 0) + (0, 1, -2, 2, 1)). În primul rând, codificăm toți primii termeni (după cum am învățat deja: Huffman și traversarea în zigzag), apoi pe al doilea etc. Acest truc este util atunci când Internetul este lent, deoarece mai întâi se încarcă doar coeficienții DC, care sunt folosiți pentru construiți o imagine brută cu 8x8 „pixeli”. Apoi coeficienți AC rotunjiți pentru a rafina cifra. Apoi corecții brute la ele, apoi unele mai precise. Și așa mai departe. Coeficienții sunt rotunjiți, deoarece în etapele incipiente ale încărcării acuratețea nu este atât de importantă, dar rotunjirea are un efect pozitiv asupra lungimii codurilor, deoarece fiecare etapă folosește propriul tabel Huffman.
Modul fără pierderi
Compresie fără pierderi. Fără DCT. Se folosește predicția punctului 4 pe baza a trei învecinate. Erorile de predicție sunt codificate Huffman. După părerea mea, este folosit puțin mai des decât niciodată.
Modul ierarhic
Din imagine sunt create mai multe straturi rezoluții diferite. Primul strat grosier este codificat ca de obicei, iar apoi numai diferența (rafinamentul imaginii) dintre straturi (pretins a fi o wavelet Haar). DCT sau Lossless este folosit pentru codificare. După părerea mea, este folosit puțin mai rar decât niciodată.
Codare aritmetică
Algoritmul Huffman produce coduri optime bazate pe greutatea caracterelor, dar acest lucru este valabil doar pentru o mapare fixă ​​de la caracter la cod. Aritmetica nu are o legare atât de rigidă, care să permită utilizarea codurilor parcă cu un număr fracționar de biți. Pretinde că reduce dimensiunea fișierului cu o medie de 10% în comparație cu Huffman. Nu este răspândit din cauza problemelor legate de brevete, nu este susținut de toată lumea.

Sper că acum înțelegeți algoritmul JPEG intuitiv. Multumesc pentru lectura!

UPD
vanwin a sugerat să indice software-ul utilizat. Sunt încântat să vă anunț că totul este disponibil și gratuit:

  • Python + NumPy + Matplotlib + PIL (pernă). Instrumentul principal. L-am găsit căutând „alternativă gratuită Matlab”. Vă recomand! Chiar dacă nu ești familiarizat cu Python, în doar câteva ore vei învăța cum să faci calcule și să construiești grafice frumoase.
  • JpegSnoop. Afișează informații detaliate despre fișierul jpeg.
  • yEd. Editor de grafice.
  • Inkscape. Am făcut ilustrații în el, cum ar fi un exemplu de algoritm Huffman. Am citit mai multe lecții, s-a dovedit a fi foarte tare.
  • Editor de ecuații Daum. Căutam un editor de formule vizuale, deoarece nu mă pricep prea bine cu Latex. Daum Equation este un plugin pentru Chrome pe care l-am găsit foarte convenabil. Pe lângă atingerea mouse-ului, puteți edita Latex.
  • FastStone. Cred că nu este nevoie să-l prezint.
  • PicPick. Alternativă gratuită la SnagIt. Se așează în tavă, face o captură de ecran a ceea ce spun ei și unde o spun. Plus tot felul de bunătăți, precum rigle, pipete, raportoare etc.

Etichete: Adăugați etichete

„Implementarea algoritmilor

JPEG și JPEG2000"

Efectuat:

elev din grupa 819

Ugarov Dmitri

Principiile de funcționare ale algoritmilor JPEG și JPEG2000

1. Algoritm JPEG

JPEG (Joint Photographic Experts Group) este o metodă utilizată pe scară largă pentru comprimarea imaginilor fotografice. Formatul de fișier care conține date comprimate este de obicei numit și JPEG; Cele mai comune extensii pentru astfel de fișiere sunt .jpeg, .jfif, .jpg, .JPG sau .JPE. Cu toate acestea, dintre acestea, .jpg este cea mai populară extensie pe toate platformele.

Algoritmul JPEG este un algoritm de compresie cu pierdere de calitate.

Zona de aplicare

Formatul este un format de compresie cu pierderi, așa că este incorect să ne gândim la JPEG ca stocând date la 8 biți pe canal (24 biți pe pixel). Pe de altă parte, deoarece datele supuse comprimării de către format JPEG iar datele decomprimate sunt de obicei reprezentate în 8 biți pe canal, această terminologie este uneori folosită. Comprimarea imaginilor alb-negru semiton este, de asemenea, acceptată.

Când salvați un fișier JPEG, puteți specifica gradul de calitate și, prin urmare, gradul de compresie, care este de obicei specificat în unele unități convenționale, de exemplu, de la 1 la 100 sau de la 1 la 10. Un număr mai mare corespunde unei calități mai bune. , dar dimensiunea fișierului crește. De obicei, diferența de calitate între 90 și 100 practic nu este percepută cu ochii. Trebuie reținut că imaginea restaurată bit cu bit este întotdeauna diferită de cea originală. O concepție greșită comună este aceea Calitate JPEG identic cu partajarea informațiilor stocate.

Etape de codare

Procesul de compresie JPEG include o serie de pași:

1. Convertiți imaginea în spațiul de culoare optim;

În caz de utilizare spațiu de culoare luminozitatea/crominanța (YCbCr) realizează cel mai bun raport de compresie. În această etapă de codificare, modelul de culoare RGB este convertit în YCbCr folosind relații adecvate:

Y = 0,299*R + 0,587*G + 0,114*B

Cb = - 0,1687*R – 0,3313*G + 0,5*B

Cr = 0,5*R – 0,4187*G – 0,0813*B.
În timpul decodării, poate fi utilizată transformarea inversă corespunzătoare:
R = Y + 1,402*Cr

G = Y – 0,34414*Cb – 0,71414*Cr

B = Y + 1,772*Cb.
Notă referitoare la Y, Cb, Cr în sistemul vizual uman:

Ochiul, în special retina, are două tipuri de celule ca analizoare vizuale: celulele de vedere nocturnă, care percep doar nuanțe de gri (de la alb strălucitor la negru închis) și celulele de vedere de zi, care percep nuanța de culoare. Primele celule, care produc culoare RGB, detectează un nivel de luminozitate similar cu valoarea Y Alte celule, responsabile de percepția nuanței, determină valoarea asociată cu diferența de croma.


2. Subeșantionarea componentelor de culoare prin medierea grupurilor de pixeli;

Majoritatea informațiilor vizuale la care ochiul uman este cel mai sensibil constă în componente de înaltă frecvență, luminanță în tonuri de gri (Y) ale spațiului de culoare YCbCr. Celelalte două componente cromatice (Cb și Cr) conțin informații de culoare de înaltă frecvență la care ochiul uman este mai puțin sensibil. Prin urmare, o anumită parte a acesteia poate fi aruncată și, astfel, numărul de pixeli luați în considerare pentru canalele de culoare poate fi redus.

1) tastați 4:2:0 (când imaginea este împărțită în pătrate de 2x2 pixeli și în fiecare dintre ei toți pixelii primesc aceleași valori ale canalelor Cb și Cr, iar luminozitatea Y rămâne diferită pentru fiecare)

2) tip 4:2:2 (combinarea prin componente de cromaticitate are loc numai pe orizontală în grupuri de doi pixeli).

3) Tipul 4:4:4 înseamnă că fiecare pixel din fiecare rând are propria sa valoare unică a componentelor Y, Cb și Cr. (Fig. 1 a)

4) tip 4:2:2. Prin subeșantionarea semnalului de crominanță cu un factor de 2 orizontal, obținem dintr-un flux YCbCr 4: 4: 4 un flux YCbCr 4: 2: 2. Intrarea „4: 2: 2” înseamnă că într-o singură linie există 4 valori de luminozitate pentru 2 valori de cromaticitate (vezi Fig. 1 b). Semnalul YCbCr 4:2:2 este foarte puțin inferior în calitatea imaginii semnalului YCbCr 4:4:4, dar lățimea de bandă necesară este redusă cu 33% față de cea originală.

3. Aplicarea transformărilor cosinus discrete pentru a reduce redundanța datelor de imagine;

Etapa principală a algoritmului este transformata cosinus discretă (DCT sau DCT), care este un tip de transformată Fourier. Este folosit atunci când lucrați cu imagini în diverse scopuri, nu numai în scopuri de compresie. Trecerea la reprezentarea în frecvență a valorilor pixelilor ne permite să privim imaginea diferit, să o procesăm și, ceea ce este interesant pentru noi, să o comprimăm. Mai mult, cunoscând coeficienții de conversie, putem efectua oricând acțiunea opusă - returnarea imaginii originale.

DCT aplicat direct unui bloc (în cazul nostru 8x8 pixeli) al imaginii va arăta astfel:

unde x, y sunt coordonatele spațiale ale pixelului (0..7),

f(x,y) - valorile pixelilor macroblocului original (de exemplu, luminozitatea)

u,v - coordonatele pixelilor în reprezentarea frecvenței (0..7)

w(u) =1/SQRT(2) pentru u=0, în alte cazuri w(u)=1 (SQRT - rădăcină pătrată)

w(v) =1/SQRT(2) pentru v=0, în alte cazuri w(v)=1

Sau sub formă de matrice:

4. Cuantificarea fiecărui bloc de coeficienți DCT folosind funcții de ponderare optimizate ținând cont de percepția vizuală umană;

Transformarea cosinus discretă pregătește informații pentru compresie cu pierderi și rotunjire. Pentru fiecare element al matricei care se transformă, există un element de matrice corespunzător cuantizarea. Matricea rezultată se obține prin împărțirea fiecărui element al matricei fiind transformat la elementul corespunzător al matricei de cuantizare și apoi rotunjirea rezultatului la cel mai apropiat număr întreg. La compilarea unei matrice de cuantizare, elementele sale mari sunt situate în colțul din stânga jos, astfel încât, la împărțirea la ele, datele din acest colț după o transformare cosinus discretă (mai exact cele a căror rotunjire va fi mai puțin dureroasă) să fie rotunjite mai grosier. Respectiv informații pierdute mai puțin important pentru noi decât cel rămas.


5. Etapa de compresie secundară

Etapa finală a codificatorului JPEG este codificarea matricei rezultate.

5.1 Permutarea în zig-zag a 64 de coeficienți DCT

Deci, după ce am efectuat o transformare DCT pe un bloc de valori 8x8, avem bloc nou 8x8. Apoi, acest bloc de 8x8 este parcurs într-un model în zig-zag, astfel:

(Numerele din blocul 8x8 indică ordinea în care scanăm matricea 8x8 bidimensională)

0, 1, 5, 6,14,15,27,28,

2, 4, 7,13,16,26,29,42,

3, 8,12,17,25,30,41,43,

9,11,18,24,31,40,44,53,

10,19,23,32,39,45,52,54,

20,22,33,38,46,51,55,60,

21,34,37,47,50,56,59,61,

35,36,48,49,57,58,62,63

După cum puteți vedea, mai întâi este colțul din stânga sus (0,0), apoi valoarea de la (0,1), apoi (1,0), apoi (2,0), (1,1), (0, 2), (0,3), (1,2), (2,1), (3,0), etc.

După ce trecem în zig-zag prin matricea 8x8, avem acum un vector cu 64 de coeficienți (0..63) Ideea acestui vector în zig-zag este că ne uităm prin coeficienții DCT 8x8 în ordinea creșterii frecvențelor spațiale. Deci, obținem un vector sortat după criterii de frecvență spațială: prima valoare de pe vector (indice 0) corespunde frecvenței celei mai mici din imagine - este notat cu termenul DC. Pe măsură ce indicele vectorului crește, obținem valori corespunzătoare frecvențelor mai mari (o valoare cu indicele 63 corespunde amplitudinii celei mai înalte frecvențe din blocul 8x8). Restul coeficienților DCT sunt notați cu AC.

5.2 Codarea RunLength zero (RLE)

Acum avem un vector cu o secvență lungă de zerouri. Putem folosi acest lucru prin codificarea zerourilor consecutive. IMPORTANT: Veți vedea de ce mai târziu, dar aici omitem codificarea primului coeficient vectorial (coeficientul DC), care este codificat diferit. Considerați vectorul 64 original ca un vector 63 (acesta este un vector 64 fără primul coeficient)

Să presupunem că avem 57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0,0,0,0, doar 0,... .0

Iată cum se face compresia RLC JPEG pentru acest exemplu:

(0,57); (0,45); (4,23); (1,-30); (0,-16); (2.1); EOB

După cum puteți vedea, codificăm pentru fiecare valoare, alta decât 0, numărul de zerouri LEADING consecutive înainte de valoare, apoi adăugăm valoarea. O altă notă: EOB este forma scurtă pentru End of Block, este o valoare specială codificată (marker). Dacă am ajuns la o poziție pe un vector de la care avem doar vector zerouri până la sfârșit, vom aloca acea poziție cu un EOB și o comprimare RLC completă a vectorului cuantificat.

[Rețineți că dacă vectorul cuantificat nu este terminat cu zero (are ultimul element nu 0), nu vom avea un token EOB.]

(0,57); (0,45); (4,23); (1,-30); (0,-16); (2,1); (0,0)

Un alt lucru de BAZĂ: Să spunem undeva pe vectorul cuantizat avem:

57, optsprezece zerouri, 3, 0,0 ,0,0 2, treizeci și trei de zerouri, 895, EOB

Codarea JPG Huffman face restricția conform căreia numărul de zerouri înainte trebuie codificat ca valoare de 4 biți să nu depășească 15.

Deci exemplul anterior ar trebui codificat astfel:

(0,57); (15,0) (2,3); (4,2); (15,0) (15,0) (1,895), (0,0)

(15,0) este o valoare codificată specială care indică faptul că urmează 16 zerouri consecutive.

5.3 Pasul final - codificare Huffman

Mai întâi o notă IMPORTANTĂ: în loc să stocheze valoarea reală, standardul JPEG specifică că stocăm dimensiunea minimă de biți la care putem păstra această valoare (aceasta se numește categoria acestei valori) și apoi o reprezentare codificată în biți a acestei valori. ca aceasta:

7,..,-4,4,..,7 3 000,001,010,011,100,101,110,111

15,..,-8,8,..,15 4 0000,..,0111,1000,..,1111

31,..,-16,16,..,31 5 00000,..,01111,10000,..,11111

63,..,-32,32,..,63 6 .

127,..,-64,64,..,127 7 .

255,..,-128,128,..,255 8 .

511,..,-256,256,..,511 9 .

1023,..,-512,512,..,1023 10 .

2047,..,-1024,1024,..,2047 11 .

4095,..,-2048,2048,..,4095 12 .

8191,..,-4096,4096,..,8191 13 .

16383,..,-8192,8192,..,16383 14 .

32767,..,-16384,16384,..,32767 15 .

Ulterior, pentru exemplul anterior:

(0,57); (0,45); (4,23); (1,-30); (0,-8); (2,1); (0,0)

haideți să codificăm doar valoarea din dreapta a acestor perechi, cu excepția perechilor care sunt jetoane speciale precum (0,0) sau (dacă trebuie să avem) (15,0)

45, în mod similar, ar fi codificat ca (6.101101)

30 -> (5,00001)

Și acum, vom scrie din nou șirul de perechi:

(0,6), 111001; (0,6), 101101; (4,5), 10111; (1,5), 00001; (0,4), 0111; (2,1), 1; (0,0)

Perechile de 2 valori cuprinse între paranteze pot fi reprezentate într-un octet, deoarece, de fapt, fiecare dintre cele 2 valori poate fi reprezentată într-o bucată de 4 biți (numărul zerourilor de început este întotdeauna mai mic de 15 și la fel ca categoria [numerele codificate în fișierul JPG - în zona -32767..32767]). În acest octet, bitul înalt reprezintă numărul de zerouri precedente, iar bitul scăzut reprezintă categoria noii valori, alta decât 0.

Pasul final de codare este să codifice Huffman acest octet și apoi să înregistrezi într-un fișier JPG, ca flux de biți, codul Huffman al acestui octet, urmat de reprezentarea pe biți a acestui număr.

De exemplu, pentru octetul 6 (echivalent cu (0,6)) avem codul Huffman = 111000;

21 = (1,5) - 11111110110

4 = (0,4) - 1011

33 = (2,1) - 11011

0 = EOB= (0,0) - 1010

Fluxul de biți final scris în fișierul JPG pe disc pentru exemplul anterior este de 63 de coeficienți (rețineți că am omis primul coeficient) -

111000 111001 111000 101101 1111111110011001 10111 11111110110 00001

1011 0111 11011 1 1010
Avantaje și dezavantaje

Dezavantajele formatului includ faptul că la niveluri ridicate de compresie, structura de date bloc se face simțită, imaginea este „împărțită în pătrate” (fiecare cu dimensiunea de 8x8 pixeli). Acest efect este vizibil mai ales în zonele cu frecvență spațială scăzută (tranziții fluide ale imaginii, de exemplu, un cer senin). În zonele cu frecvență spațială mare (de exemplu, marginile contrastante ale imaginii), apar „artefacte” caracteristice - o structură neregulată de pixeli cu culoare și/sau luminozitate distorsionate. În plus, mici detalii de culoare dispar din imagine. De asemenea, nu ar trebui să uităm asta acest format nu suportă transparența.

Cu toate acestea, în ciuda deficiențelor sale, JPEG a devenit foarte răspândit datorită raportului său ridicat de compresie în raport cu alternativele care existau la momentul introducerii sale.

2. Algoritm JPEG2000

Algoritmul JPEG-2000 a fost dezvoltat de același grup de experți în fotografie care a dezvoltat JPEG. Formarea JPEG ca standard internațional a fost finalizată în 1992. În 1997, a devenit clar că era nevoie de un standard nou, mai flexibil și mai puternic, care a fost finalizat până în iarna anului 2000.

Principalele diferențe dintre algoritmul din JPEG 2000 și algoritmul din JPEG sunt următoarele:

1) Calitate mai bună a imaginii cu un grad ridicat de compresie. Sau, ceea ce este același lucru, un raport de compresie mai mare cu aceeași calitate pentru rapoarte de compresie ridicate. De fapt, aceasta înseamnă o reducere vizibilă a dimensiunii graficelor „de calitate Web” utilizate de majoritatea site-urilor.

2) Suport pentru codificarea zonelor individuale cu cea mai buna calitate. Se știe că anumite zone ale imaginii sunt critice pentru percepția umană (de exemplu, ochii dintr-o fotografie), în timp ce calitatea altora poate fi sacrificată (de exemplu, fundalul). Cu optimizarea „manuală”, rata de compresie crește până când calitatea se pierde într-o parte importantă a imaginii. Acum devine posibilă setarea calității în zonele critice, comprimând mai puternic alte zone, de ex. obținem un raport de compresie final și mai mare cu o calitate subiectiv egală a imaginii.

3) Algoritmul principal de compresie a fost înlocuit cu wavelet. Pe lângă creșterea indicată a raportului de compresie, acest lucru a făcut posibilă scăparea de blocarea de 8 pixeli care apare atunci când raportul de compresie este crescut. În plus, dezvoltarea lină a imaginii este acum inclusă inițial în standard (JPEG progresiv, utilizat în mod activ pe Internet, a apărut mult mai târziu decât JPEG).

4) Pentru a crește raportul de compresie, algoritmul folosește compresia aritmetică. Standardul JPEG includea inițial și compresia aritmetică, dar ulterior a fost înlocuită cu compresia Huffman, mai puțin eficientă, deoarece compresia aritmetică era protejată de brevete. Acum, brevetul principal a expirat și există o oportunitate de a îmbunătăți algoritmul.

5) Acceptă compresia fără pierderi. Pe lângă compresia obișnuită cu pierderi, noul JPEG va suporta acum compresia fără pierderi. Astfel, devine posibilă utilizarea JPEG pentru a comprima imagini medicale, în tipărire, salvând în același timp textul pentru recunoaștere de către sistemele OCR etc.

6) Acceptă compresia imaginilor pe un singur bit (2 culori). Pentru salvarea imaginilor pe un singur bit (desene cu cerneală, text scanat etc.), formatul GIF a fost anterior recomandat pe scară largă, deoarece compresia DCT este foarte ineficientă pentru imaginile cu tranziții clare de culoare. În JPEG, atunci când este comprimată, o imagine de 1 biți a fost convertită în 8 biți, adică crescut de 8 ori, după care s-a încercat comprimarea, adesea de mai puțin de 8 ori. Acum putem recomanda JPEG 2000 ca algoritm universal.

7) Transparența este acceptată la nivel de format. Acum va fi posibil să aplicați fără probleme un fundal atunci când creați pagini WWW nu numai în GIF, ci și în JPEG 2000. În plus, nu este acceptat doar 1 bit de transparență (pixelul este transparent/opac), ci un canal separat, care vă va permite să setați o tranziție lină de la o imagine opacă la un fundal transparent.

În plus, nivelul de format acceptă includerea informațiilor privind drepturile de autor în imagine, suportă toleranța la eroare de biți în timpul transmisiei și difuzării și poate fi solicitat pentru decompresie sau procesare fonduri externe(plug-in-uri), puteți include în imagine descrierea acestuia, informațiile de căutare etc.

Etape de codare

Procesul de compresie JPEG2000 include o serie de pași:

1. Convertiți imaginea în spațiul de culoare optim.
În această etapă de codificare, modelul de culoare RGB este convertit în YUV folosind relații adecvate:

La decomprimare, se aplică transformarea inversă corespunzătoare:

2. Transformată wavelet discretă.

Discret conversie wavelet(DWT) poate fi, de asemenea, de două tipuri - pentru cazul compresiei cu pierderi și pentru compresia fără pierderi.

Această transformare în cazul unidimensional este un produs scalar al coeficienților corespunzători și un șir de valori. Dar pentru că mulți coeficienți sunt zero, atunci transformarea wavelet directă și inversă poate fi scrisă prin următoarele formule (pentru a transforma elementele extreme ale unei linii, se utilizează extinderea acesteia cu 2 pixeli în fiecare direcție, ale căror valori sunt simetrice cu valorile elementelor liniei în raport cu pixelii săi extremi):
y(2*n + 1) = x(2*n + 1) - (int)(x(2*n) + x(2*n + 2)) / 2

y(2*n) = x(2*n) + (int)(y(2*n - 1) + y(2*n + 1) + 2) / 4

si invers

x(2*n) = y(2*n) - (int)(y(2*n - 1) + y(2*n + 1) + 2) / 4

x(2*n + 1) = y(2*n + 1) + (int)(x(2*n) + x(2*n + 2)) / 2.

3. Cuantificarea coeficienților.

La fel ca algoritmul JPEG, cuantizarea este utilizată atunci când se codifică o imagine în formatul JPEG2000. Transformarea wavelet discretă, ca și analogul său, sortează coeficienții după frecvență. Dar, spre deosebire de JPEG, în noul format există o matrice de cuantizare pentru întreaga imagine.


4. Etapa de compresie secundară

. La fel ca JPEG, ultimul pas în algoritmul de compresie în noul format este codificarea fără pierderi. Dar, spre deosebire de formatul anterior, JPEG2000 folosește un algoritm de compresie aritmetică.

Implementare software

În această lucrare, sunt implementați algoritmii JPEG și JPEG2000. Ambii algoritmi implementează codarea înainte și inversă (ultima etapă a compresiei secundare este absentă). Calculul JPEG durează destul de mult (aproximativ 30 de secunde) datorită calculului „direct” al DCT. Dacă trebuie să creșteți viteza de lucru, ar trebui să calculați inițial matricea DCT (modificările ar trebui făcute în clasa DCT).

Să trecem la program:


  1. După lansare, apare o fereastră unde

și îl puteți salva făcând clic pe butonul (2) și introducând numele dorit în caseta de dialog.

  • Cu un factor de calitate suficient de mare, imaginea se va schimba foarte mult. Dacă acesta este un algoritm JPEG, blocurile de dimensiunea 8x8 vor fi clar vizibile (în cazul algoritmului JPEG2000, nu va exista nicio diviziune de bloc).
  • Inainte de:

    După:



    Cele mai bune articole pe această temă