Wątek przeniesiony 2021-03-04 10:13 z Algorytmy i struktury danych przez Shalom.

bezstratna kompresja jpg?

0

Jest możliwe uzyskać bezstratną kompresję w jpg, rzeczywistego obrazu -z fotografii?

Mam taki przykład:
blue.png

png jest bezstratne: 1.3MB

po kompresji tego samego obrazka do jpg, otrzymujemy
blue.jpg

co ma około 0.7MB zaledwie, czyli prawie 2 razy mniej.

Na czym polega problem?

Odczytujemy oba te obrazki i robimy różnicę obu,
i okazuje się że nie ma żadnych różnic: różnica = black = 0, dokładnie!

O co tu chodzi?

2

No dobra ale na czym polega problem? Zaskoczyło Cię, to że zwykła kompresja danych jest gorsza od bardziej wyspecjalizowanej dla obrazu?
Kompresja JPEG ma całą masę parametrów a akurat to zdjęcie jest dla zastosowania tej kompresji wręcz idealne. Cała masa "gradiencików" w tej samej "tonacji.
Po rozbiciu na poszczególne częstotliwości za pomocą transformacji FFT uzyskamy dane wręcz cudowne dla dalszej kompresji.

Akurat ten plik można skompresować do mniej niż 100kb ( 96kB) i nadal wygląda bardzo dobrze:
Myślę, że jakby się uprzeć i dobrze pokombinować z parametrami algorytmu kompresji JPEG to 50kb wyglądało by dobrze a w 100kB byłby bezstratny.

screenshot-20210206142408.png

0

Wiem że można znacznie lepiej to skompresować, no ale nie bezstratnie!

3

Wyeksportowałem podane w pierwszym poście PNG i JPG do PNM, porównałem i jest masa różnic. JPG to format stratny i ponadto nie ma sztywno ustalonej procedury dekodowania (w sensie z dokładnością do błędów zaokrągleń podczas różnych etapów transformacji), więc różne dekodery mogą wygenerować różne dane na wyjściu (ale będą wyglądać praktycznie identycznie).

Poza tym da się skompresować bezstratnie plik JPEG i to nie o ułamek procenta, a o kilkanaście procent albo i więcej:
https://github.com/packjpg/packJPG
https://github.com/dropbox/lepton
StuffIt też ma bezstratną kompresję JPEG

0

Dziwne. U mnie było total black = 0, jeden kolor.

Ile masz tych różnic - licząc w bitach?

2

Prawdopodobnie ten PNG jest wygenerowany z tego JPEGa z użyciem konkretnego dekodera JPEG i użyłeś właśnie tego samego (z dokładnością do zaokrągleń) algorytmu dekodującego.

Różnice są takie:

piotrek@piotrek-desktop:/tmp/bezstratne$ ll
razem 6976
drwxr-xr-x  2 piotrek piotrek    4096 lut  6 14:21 ./
drwxrwxrwt 17 root    root      36864 lut  6 14:31 ../
-rw-r--r--  1 piotrek piotrek 1362153 lut  6 14:18 FAPe9B9BFZNnuHv4apdENbSGd80b6IVoMnsT11IC.png
-rw-r--r--  1 piotrek piotrek 2558455 lut  6 14:20 FAPe9B9BFZNnuHv4apdENbSGd80b6IVoMnsT11IC.pnm
-rw-r--r--  1 piotrek piotrek  606977 lut  6 14:18 hMNoQPWWaHZWwFqKiddRXS86Oh1h9AHmxfez85of.jpg
-rw-r--r--  1 piotrek piotrek 2558455 lut  6 14:21 hMNoQPWWaHZWwFqKiddRXS86Oh1h9AHmxfez85of.pnm
piotrek@piotrek-desktop:/tmp/bezstratne$ cmp --verbose *.pnm | head
     56 264 263
     57 261 262
     58 335 334
     60 257 260
     61 333 332
     64 330 327
     67 327 326
     70 327 326
     73 330 327
     74 255 256
piotrek@piotrek-desktop:/tmp/bezstratne$ cmp --verbose *.pnm | tail
2558443 176 200
2558444 344 347
2558446 315 314
2558447 355 356
2558449 325 320
2558450 346 347
2558451 341 342
2558452 307 304
2558454 353 354
2558455 323 317
piotrek@piotrek-desktop:/tmp/bezstratne$ cmp --verbose *.pnm | wc
1537512 4612536 24600192
piotrek@piotrek-desktop:/tmp/bezstratne$ 

Są też specjalne heurystyki do wykrywania JPEGów przekonwertowanych na bezstratne formaty. Niektóre programy graficzne potrafią wykryć algorytm, który był użyty do kompresji JPEG i parametry kompresji i wykonać dzięki temu możliwie najmniej stratną konwersję z powrotem na JPEG.

Tutaj jest program, który robi rzeczoną "inżynierię wsteczną": https://github.com/schnaader/precomp-cpp Potrafi zdekodować pliki (niektóre, jeśli odgadnie algorytm kompresji i będzie on odwracalny) ZIP, JPEG, MP3, PDF itd tak by dało się z powrotem przywrócić do oryginalnego formatu z dokładnością do każdego bitu. Dzięki rozpakowaniu można je potem spakować mocniejszymi algorytmami kompresji i uzyskać mniejsze pliki, kompletnie bez straty informacji.

0

JPEG-i jako takie mają milion rozszerzeń, w tym i taki do bezstratnej kompresji, ale przez ochronę patentową i ogólny bałagan ze standardami nikt o tym nie wie — już nawet kompresja arytmetyczna robi problemy, a taka np. przezroczystość nie jest obsługiwana przez nic, co bym kojarzył.

Jak chcesz mieć format o szerokim zastosowaniu, który umie dużo rzeczy (w tym m.in. i tę bezstratność, i tę przezroczystość), to WebP jest dobrym wyborem — bo nie jest chronione patentami i posiada sporo otwartych implementacji, w tym na licencji MIT i podobnych.

0

Dalsze dziwy i cuda.

Ten sam obraz po wygładzeniu:
blue7.jpg

rozmiar: 282 KB, czyli ponad 2 razy mniejszy od oryginału = 592KB!
282/592 = 48% !!! zaledwie.

0

E, nie takie rzeczy się dzieją… Robiłem kiedyś analizę, jak się kompresują mapy do gier eRPeGie:

Pokazowa mapa z DungeonFoga, 3900×2300 pikseli
(wyniki posortowane od największego do najmniejszego pliku; załącznik ze skompresowanymi wersjami do porównania — bezstratnych kopii nie wrzucałem, bo po co, a oryginał jest za wielki, by go wrzucić na Discorda…)
Orginał (bezstratny png): 17 805 739 bajtów
Bezstratny AVIF: 15 790 013 bajtów, 88,68% (785,18 s rekompresji — chodząca tragedia przy takim rozmiarze…)
Zoptymalizowany png: 10 846 355 bajtów, 60,91% (1427,38 s rekompresji — bardzo dużo)
Bezstratny webp: 8 232 574 bajtów, 46,24% (47,83 s rekompresji)
Bezstratny FLIF: 8 077 356 bajtów, 45,36% (63,68 s rekompresji)
Stratny AVIF (domyślna jakość; nie mam pojęcia jaka): 3 872 956 bajtów, 21,75% (508,67 s rekompresji)
Stratny JPEG (mozjpeg, Q75): 1 051 556 bajtów, 5,91% (2,19 s rekompresji)
Stratny AVIF (--max 35, próbuję dobić nim do JPEG-owego rozmiaru): 1 000 008 bajtów, 5,62% (505,45 s rekompresji)
Stratny webp (Q75, jpeg_like — czyli próbuje być mniejszy od JPEG-a przy podobnej jakości): 886 618 bajtów, 4,98% (19,62 s rekompresji)
Stratny AVIF (--max 40, próbuję dobić nim do JPEG-owego rozmiaru): 634 352 bajtów, 3,56% (420,25 s rekompresji)

5
kwalifika napisał(a):

Dalsze dziwy i cuda.

Ten sam obraz po wygładzeniu:
(...)

rozmiar: 282 KB, czyli ponad 2 razy mniejszy od oryginału = 592KB!
282/592 = 48% !!! zaledwie.

Wygładzanie działa mniej więcej jak filtr dolnoprzepustowy. Usuwasz informacje o wysokich częstotliwościach. Stąd nie jest dziwne, że taki obraz da się zapisać w mniejszym pliku.

Filtry dolnoprzepustowe są podstawą kompresji audio (w sensie używane w większym stopniu niż w przypadku kompresji obrazów statycznych). Dźwięk w formacie CD audio jest próbowany 44.1 kHz w 16 bitach co daje https://en.wikipedia.org/wiki/Nyquist_frequency na poziomie 22 kHz. Praktycznie żaden człowiek nie słyszy tak wysokich tonów, więc kodeki audio obcinają pasmo do kilkunastu kHz, a w skrajnych przypadkach (bardzo silna kompresja) do kilku kHz.

0

Test:
robimy obrazek całkowicie losowy, czyli wpisujemy: kolor = random.

Pakujemy to do jpg, a potem w png, zip, lub inny.
Kto wygra?

ale to nie koniec:

  1. robimy wygładzenie i powtarzamy to samo,
    bo takie wygładzenie mogę sobie potem przecież wycofać, czyli nic nie tracę - zgadza się?
3

Przykład z kompresją wyrenderowanego tekstu i (nazwijmy to) grafiki wektorowej (bo te wszystkie obwódki można tak potraktować).

Obraz w PNG:
zrzut.png

Obraz w JPEG:
zrzut.jpg

Różnica:
zrzut-różnica.png

Widać sporo szumu wysokiej częstotliwości wokół tekstu. Dałem fory JPEGowi, bo ustawiłem podpróbkowanie chrominancji. Bez tego (w sensie z chrominancją o pełnej rozdzielczości) wynik był jeszcze gorszy (przy normalizacji jakości JPEGa do tego samego rozmiaru pliku co PNG) i nawet nie trzeba było się przyglądać, żeby zobaczyć różnicę.

2

Podsumujmy dyskusję w komentarzu, żeby nie zaginęło:

Ale co to ma być? Tekst nie jest obrazem! zatem czym jest? - jak należy to zapakować do jpg? - jak odkodować? - jak porównać różnice z oryginałem?

Możesz wyrenderować tekst — zamienić go na formę wizualną czytelną dla ludzi, w postaci obrazka. To jest to, co masz w poście Wibowita wyżej. Możesz też zrobić tę akrobację, którą Ty proponujesz — mieć obrazek, którego kolejne wartości pikseli odpowiadają wartościom UTF-8 (czy tam jakim) źródłowego tekstu.

dobrze kombinujesz, pomijając to bmp; nie ma żadnego bmp! ładujesz kolory do obrazka wprost z txt (z czegokolwiek!), czyli masz np.: A = 64, B = 65, ... 255 = white, 0 = black, zatem to A = ciemno szary - jasne? ładujesz to w obrazek i kompresujesz (ale po wygładzeniu, oczywiście)

Żeby coś „załadować w obrazek”, musi mieć to format zrozumiały dla komputera (chyba że chcesz mieć to narysowane na kartce albo co?). Jednym z formatów jest BMP — jest on skrajnie prymitywny, w wersji najbardziej podstawowej to nagłówek z podstawowymi informacjami o pliku i ciąg wartości kolorów pikseli.

A czemu operacja „zróbmy z pliku tekstowego na pałę obrazek, a potem ten obrazek skompresujmy JPEG-iem” jest idiotyczna? Bo JPEG kompresuje stratnie. Różnice są mniej lub bardziej niezauważalne dla ludzi, ale i tak zmieniają wartości kolorów. Czyli — litery, które miałaś w wyjściowym tekście. Po takiej „kompresji” otrzymasz sieczkę, której nie będzie się dało zdekompresować do niczego czytelnego, bo informacje, które nam do tego są niezbędne, zostały usunięte.

2

Zrobiłem ten głupawy eksperyment z kompresją kodów ASCII za pomocą JPEG. Wyniki w załączniku: dzik.zip

Użyłem programu imagemagick. Ma opcję wczytywania i generowania całkowicie surowych danych.

$ convert -depth 8 -size 32x16 -quality 100 gray:dzik.txt dzik.jpg
$ convert -depth 8 -size 32x16 dzik.jpg gray:dzik-out.txt
0

sprawdzałeś? co mówi teoria: błąd maksymalny = 0.5 bita - tak?, co daje 1% - maks! ale błąd średni jest znacznie mniejszy - jaki? Weź te dwa obrazki i przelicz to sobie.

Dobra, to żeby nie gadać po próżnicy: bierzemy sobie 30 000 bajtowego Lorem Ipsum (załącznik lorem.txt), robimy z niego obrazem (załącznik result1.bmp) — można sobie otworzyć edytorem szesnastkowym i zobaczyć, że dalej jest to prosta operacja odwracalna — kompresujemy JPEG-iem na jakości 100% (załącznik result1.jpg), robimy z tego JPEG-a z powrotem BMP (załącznik lorem.txtresult2.bmp) i z niego z powrotem tekst (załącznik not-lorem.txt`).

Muszę wrzucić jako ZIP, żeby forum chciało przyjąć, ale wrzucę też fragmenty tekstu przed i po tej „kompresji”:kompresja.zip

Phasellus commodo, est ac tincidunt mollis, massa velit imperdiet urna, non pulvinar dui orci nec nisi. Quisque pretium gravida dui, in cursus nunc convallis vitae. Maecenas condimentum metus at nisl laoreet, eu finibus quam lobortis. Fusce ornare nisl ligula, eu elementum turpis varius quis. Pellentesque condimentum varius turpis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Duis efficitur ultrices porttitor. Donec pulvinar in lectus id ultrices. In commodo quam odio, ac laoreet lorem fringilla sed. Vestibulum tortor risus, dictum eget bibendum nec, faucibus vitae ante.

"+Ubdjo_bSaihinm91$szm4bc>np[i^tofGCHjllWfQRgN^obYliVmoMgcivjisC<?oh_D@(hdLytkklhSdY_tkR^bJSWfei_K[JKYG{{oZRKxkmxgtG5TgYulhmei^-.ZMjxlizqYibGUOesgflgkaqg\pghr)++hcZsgc?->zdy^~lA=Bnst56D6BHZziMjPnmYk^^nQZh\mWbRxpqH7@nacznt=->rfr\VKsubgpfha]Xgbcgjy+.C80Aujtor\QSwuiltbe\mmaJBCpnt#,5XjqZirjwyLVIipcfjkkmn\\PZh\IruEps]qe7;0smrdceSaOPfN^obhyuLacFX_jnyQNWf_b^WNys\ZCwpefdXg_Rc_[elou|(-+jrg\jXco[loLF?ttp_lC3R|qplqYZPSUBekX]j\gwl^jdgrjT]PosmJ@LD:Kgjrdji86,^UR~nr]}M4Vp]v^ZW_NSbWfoTufLhQpZLNoicxbnh\dY7+1udotfl|nyA5I{qa_UopZ\Vdeaolg>=?dvTWlqfz}kxmX[;,0_bp_hqa_W|siZIL{nv!#+T\cdqyPbcczl^laC;Eldn=NAXtgSsy=]cNnc]nc_W^yqxK\O=VBUfYZkbXmkbsv68BtmtbWY|rhaZA^V?xngwrs*30[hjfkz34BSWRgo^*7erZcS^\Rrecscnvh[RlZUWTTHlnZFM8htbT^Qbe\ih^67'qpfpempju]fi^if:?6xst6)AbPu{bE1Na\eMQV^exNanHjcZtgG==m|F5ZcZ{44:ljiverubsranD9Ig]{_Zoeid{{mG86?.1gd`jorho^_yn^vbu^hU@Hdq&8C]VS

No nie wiem jak Ty, @kwalifika , ale ja tego nie umiem odczytać…

2

Muszę przyznać ze @kwalifika to jest top tier troll, bo dał radę zbaitować juz tyle osób na forum że aż szkoda słow. Każdy nowy wątek to dla mnie kolejna paczka popcornu :D

0

Obrazek jpg zrobiony z tekstu:

bintxt.jpg

ciekawe czy ktoś to odczyta.
błędy są znikome: +/- 1

aha, oryginał ma rozmiar tyle co wymiary: 256 x 216 = 55296 Bytes
zatem kompresja jest marna: z 10% chyba zaledwie.

I to samo po wygładzeniu:
gauss2txt.jpg

co ma już tylko 15KB: 15/56 = 27%, niezła kompresja, wystarczy to wystarczyć. :)
i co ciekawe w tej wersji jest znacznie mniej błędów - z 10 razy mniej!

0

@Shalom:

Shalom napisał(a):

Muszę przyznać ze @kwalifika to jest top tier troll, bo dał radę zbaitować juz tyle osób na forum że aż szkoda słow. Każdy nowy wątek to dla mnie kolejna paczka popcornu :D

Temat w sumie ciekawy, pewnie dlatego tyle ludzi się wypowiedziało.

@kwalifika: może napisz coś o sobie, bo jeśli masz 14 lat to całkiem ciekawe rzeczy piszesz.
Musisz wziąć pod uwagę że niektórzy tutaj przeczytali więcej niż dwie książki i mogą znać treść nie tylko tej którą czytasz, ale i jej recenzje jak również "książki po książkach", w których autorzy przepraszają za wcześniejszą twórczość.

0

W sumie to banał odzyskać 100% tego tekstu z jpg.

Błędy są tu +/-1, zatem można kodować co 3, co nam daje 256/3 = 85 znaków - i tyle nam wystarczy!
Wtedy po odczycie wystarczy tak zrobić: c = (3c+/-1) / 3 -> poprawny kod, bezbłędny!

Natomiast w przypadku obrazków, fotek, mamy za darmo wzrost o 300% kompresji (po wycofaniu blura), bo +/-1 nie ma teraz żadnego znaczenia!!!

3
kwalifika napisał(a):

W sumie to banał odzyskać 100% tego tekstu z jpg.

To nie jest banał, bo jeszcze nie pokazałeś programu, który to robi. Nie napiszesz programu, bo nie potrafisz programować, to dla ciebie za trudne, tak samo jak logiczne myślenie.

0

Może trochę rozrywki: kompresja random!

Kompresja danych losowych jest w zasadzie niemożliwa: zero kompresji.

No to sprawdźmy to: co tu wyjdzie w wersji z wygładzaniem przed kompresją?

Warianty:
I. bitmap[i,j] = random(256);
co pakujemy do jpg/gif/zip i sprawdzamy rozmiar

II. przed zapakowaniem robimy wygładzanie: blur/gauss, haha!

finalnie porównujemy rozmiary - i co wam wychodzi?

1
kwalifika napisał(a):

finalnie porównujemy rozmiary - i co wam wychodzi?

otóż wychodzi jajco

0

@kwalifika:
Zakładam, że wyjdzie mniejszy rozmiar (nie sprawdzałem). Ale to chyba dość oczywiste. Rozmycie zmienia obraz na bardziej uporządkowany. Ekstremalne rozmycie to byłby przecież jeden uśredniony kolor.

1 użytkowników online, w tym zalogowanych: 0, gości: 1