1

Temat: kompresja - wynik na 1 stronie

witam,

potrzebuje procedury dekompresujacej gdzie wynik bedzie ZAWSZE zajmowal mniej niz jedna strone pamieci - powiedzmy 200 bajtow.
dane wyjsciowe beda zawieraly TYLKO 4 rozne znaki.

pomyslalem o takiej procedurze:

|X|X|Y|Y|Y|Y|Y|Y|

X - kodowany znak
Y - ilosc powtorzen

plik wynikowy bedzie zawieral znaki w proporcjach 70% - 15% - 10% - 6%

isc w tym kierunku czy moze znacie cos lepszego?

Ostatnio edytowany przez xxl (2006-02-12 10:20:38)

http://atari.pl/hsc/ad.php?i=1.

2

Odp: kompresja - wynik na 1 stronie

Jeżeli dobrze zrozuniałem...

Cztery różne znaki w wyniku, czyli wystarczą 2 bity na opisanie jednego z nich. Bez jakichkolwiek kombinacji zysk będzie czterokrotny.


pozdrawiam,
M.

Ostatnio edytowany przez Magnus (2006-02-12 11:12:23)

3

Odp: kompresja - wynik na 1 stronie

moze to pomoze http://atariarea.krap.pl/artykuly.php?a … &id=38

*- TeBe/Madteam
3x Atari 130XE, SDX, CPU 65816, 2x VBXE, 2x IDE Plus rev. C

4

Odp: kompresja - wynik na 1 stronie

Magnus napisał/a:

Jeżeli dobrze zrozuniałem...

Cztery różne znaki w wyniku, czyli wystarczą 2 bity na opisanie jednego z nich. Bez jakichkolwiek kombinacji zysk będzie czterokrotny.

a po mojemu chodzi o to żeby był jeszcze większy.

xxl: myślę, że dobry sposób. na pewno szybki i prosty.

Hitler, Stalin, totalniak, SSman, NKWDzista, kaczor dyktator, za długo byłem w ChRL, wypowiadam się afektywnie.

5

Odp: kompresja - wynik na 1 stronie

To zalezy mocno od danych, jezeli masz powtarzajace sie mocno znaki (pisales o 70% dla najczesciej wystepujacego), to skompresowane RLE (bo to wlasciwie robisz) bedzie niezle. Ale chyba jednak mozna duzo lepiej. Zalozmy, ze masz 4 znaki: A-70%, B-15%, C-10%, D-6%. Popatrz, ze statystycznie szanse, ze sekwencja 2 znakow to jest BB 0.15 jest 0.025, dla pozostalych jeszcze nizej. A i tak kompresujesz ten znak dodajac 6 bitow licznika. Tracisz. Jezeli masz naprawde 1 znak dominujacy tak mocno jak A, sproboj zrobic RLE tylko dla takiego znaku, i moze nawet z licznikiem nie 6-bitowym a 2- lub 4- bitowym. Na oko 2 moze byc dobre - szanse, ze sekwencja 5 znakow jest AAAAA to ca. 0.17 a ze 16 to juz 0.003. Innymi slowy, sekwencje AABAACAAADBA spakowalbys tak (kazdy znak to 2 bity): A2BA2CA3DBA1. Ofkorz zamiast cyferek 1-2-3 uzywasz 0-1-2 w prawdziwych danych.
W ta strone bym radzil kombinowac.
Oczywiscie, pojawia sie pytanie, czy kompresujesz na tyle duzo danych, zeby komplikowac depacker :D
Aha, no i ofkorz Huffman tez moze tu byc ciekawy...

Ostatnio edytowany przez eru (2006-02-12 13:25:16)

: 404. Stopka not found

6

Odp: kompresja - wynik na 1 stronie

xxl: daj próbkę danych wejściowych, a najlepiej kilka.


pozdrawiam,
to-mix

7

Odp: kompresja - wynik na 1 stronie

przyklad1:
111111111111111112222222222222211222222222222221122222222222222112222322223222211222222222222221
122224444442222112222222222222211222222222222221122222222222222112222222222222211111111111111111

przyklad2:
212222222222221221222222222222122122222222222212212223222232221221222221122222122122222442222212
212222222222221221222322223222122122222222222212212222222222221221222222222222122122222222222212

@Magnus - to moze byc dobre, prosta i szybka metoda dekompresji (krotki program depakera).

niema co szalec danych wyjsciowych bedzie w sumie ok 3 kb glownie zalezalo mi na krotkiej procedurze dekompresji.

http://atari.pl/hsc/ad.php?i=1.

8

Odp: kompresja - wynik na 1 stronie

Przy takich danych na wejściu to każda metoda kompresji będzie lepsza od tego co zaproponowałem na początku :)

9

Odp: kompresja - wynik na 1 stronie

jesli chodzi o kompresje tylko jednego obrazka - rle (w twoim wykonaniu) powinno byc wystarczajace
jesli bedziesz kombinowal z tego animacje - huffmana raczej nic nie zastapi
polecam poczytac o lz77 lub o jego nieco efektywniejszej wersji - lzss (np. przykladowy kod w zalaczniku do arta wspomnianego przez tebe), albo o ponoc szybszy przy dekompresji - lzo

btw. skad mozna pobrac ten zalacznik?

Ostatnio edytowany przez jellonek (2006-02-12 15:44:07)

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

10

Odp: kompresja - wynik na 1 stronie

moze poeksperymentuj z takim algorytmem:

|x|L|L|L|L|L|L|L| |dana|
gdzie:
x - co robimy:
0 - bity L -> ile razy powtorzyc bajt "dana" (0 -> EOB - end of block)
1 - bity L -> dlugosc ciagu do skopiowania spod offsetu "dana" ustawionego wzgledem poczatku rozpakowanych danych

zaleta algorytmu - prosta dekompresja + obsluga blokow
wynik kompresji dla pierwszego przykladu to:
0x11, 0x31, 0x0f, 0x32, 0x8f, 0x0f, 0xb6, 0x0f, 0x01, 0x33, 0x89, 0x41, 0x96, 0x1f, 0x06, 0x34, 0xaa, 0x1b, 0x9b, 0x16, 0x0b, 0x31, 0x00
moglem sie machnac - recznie liczylem ;)
skompresowane 192 bajty do 23, bez zastosowania slownika (a wiec i bez potrzeby miejsca na niego ;)

tylko nie wiem jak tu program napisac by do tej postaci kompresowal - uwzgledniajac takie rzeczy jak np. konczacy/zaczynajacy rle (ktory wiadomo - jest szybszy w dekompresji)
jesli nie zalezy nam na speedzie dekompresji to mozna jeszcze w tym algorytmie conieco skompresowac ;) - np.
|x|L|L|L|L|L|D|D| |dana dla x != 0|
x = 0 -> bity L = ilos powtorzen, bity D = dana - 0x30
x = 1 -> j.w.
dekompresja bedzie wolniejsza (choc niewiele), ale za to pozwala na jeszcze lepsze upakowanie danych z twojego formatu (choc nieco komplikuje dekompresje).

wybieraj - mozliwosci jest znacznie wiecej ;)

Ostatnio edytowany przez jellonek (2006-02-12 18:51:16)

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

11

Odp: kompresja - wynik na 1 stronie

hej!

nie wiem jak bardzo krytyczna jest prędkość dekompresji... jednak możnaby się pokusić o kompresję bitową... jeżeli to jest dla twojego zastosowania odpowiednie można podejsc do problemu nieco inaczej... w przypadku takiego rozkladu danych wejściowych, należałoby zastosować jakiś kod, w którym długość słowa okreslajacego dany znak, nie jest stała. Najbardziej logicznym wydaje się zastosowanie bardzo prostego kodowania bitowego, np. możemy zastosować taki algorytm...

potrzebujeby procedury get_bit, która umożliwia pobranie jednego bitu danych ze wejścia.

1. zerujemy "index"
2. pobieramy jeden bit
3. zwiekszamy index o 1
4. sprawdzamy czy pobrany bit=1, jeżeli nie wracamy do kroku #2
5. wartość index określa jednoznacznie daną ktory pobralismy, mozemy go wykorzystac do pobrania odpowiedniej wartosci z tablicy konwersji.

reasumujac, kodowanie bedzie wygladalo mniej wiecej tak:

1: kod oznaczajacy dana #1
01: kod oznaczajacy dana #2
001: kod oznaczajacy dana #3
0001: kod oznaczajacy dana #4
itd.

jak widac ilosc bitów przeznaczonych na zakodowania kolejnego symbolu rośnie dość szybko... jednak w przypadku twojego rozkładu danych (70% będzie reprezentowane przez pojedynczy bit). Ma to szanse sporej kompresji. Musisz sprobowac w praktyce. Zreszta istnieje bardzo duzko koów o zmiennej dlugosci slowa... mozesz sprobowac poczytac troche tu:

http://en.wikipedia.org/wiki/Prefix_code

i tu:

http://en.wikipedia.org/wiki/Universal_ … ression%29

procka dekompresji moze byc dosc krotka i przy dobrej implementacji get_bit, powinna byc szybka:

get_one_byte:

 ldx #$00
loop:
 jsr get_bit ; get bit w znaczniku "C" zwraca wartosc pobranego bitu
 inx
 bcc lopp
 lda tab_cnv,x
 rts

; tutaj tablica konwersj, najczesciej wystepujace elementy powinny byc kodowane najmniejsza iloscia bitów :)
; czyli będą się znajdowały na początk u tablicy... im dalej w tablicy tym wiecej bitów potrzeba :)

tab_cnv:
 dta b($04),b($03),b($02),b($01)

get_bit:

 ; tutaj w/g twojego uznania... jest sporo sposobów :) 
 ; a implementacja zalzey od tego czy uzyjesz rejestrow, lokacji na stronie zerowej... itd.

jest to jedno z prymitywniejszych kodowań o zmiennej długości słowa... i nie wiem czy to bedzie przydatne ze wzgledu na szybkosc, jednak kompresja powinna byc efektywna dla twoich danych :)

pozdrawiam
Seban/SLIGHT

Ostatnio edytowany przez seban (2006-02-12 20:51:31)

12

Odp: kompresja - wynik na 1 stronie

Pierwsza sprawa chyba cos procenty sie popiepszyly, bo 70+15+10+6=101, a chyba powinno wyjsc 100 :) zalozylem wiec, ze jest 70+15+10+5.
Dalej: Budujemy drzewo huffmana i wychodzi nam cos takiego:

    100
   /  |
  /  30
 /   / \
 |  |  15
 |  |  | \
70 15 10 5

Oznaczmy kodowane znaki przez A(70%), B(15%), C(10%), D(5%). Przyporzadkowanie ciagow prefiksowych moze byc nastepujace:

A: 1
B: 01
C: 001
D: 000

Dalej mozemy zostosowac RLE wypelniajac do pelnych nibli, gdzie wypelnienie to ilosc powtorzen danego znaku. Jako ze kombinacji jest tylko szesnascie, to wszystkie je tu wypisze:

1000 : A
1001 : AA
1010 : AAA
1011 : AAAA
1100 : AAAAA
1101 : AAAAAA
1110 : AAAAAAA
1111 : AAAAAAAA
0100 : B
0101 : BB
0110 : BBB
0111 : BBBB
0010 : C
0011 : CC
0000 : D
0001 : DD

Kompresja banalna. (szukamy podanego tu wzorca i zastepujemy go odpowiednim kodem). Dekompresja banalna (Mozemy nawet stablicowac i to po dwa kody na raz bo ładnie mieszcza sie w bajcie: wystarczy pamietac 256 adresow rozkompresowanych ciagow terminowanych jakims 5. znakiem). Stopien kompresji bliski optymalnemu. (Huffman jest optymalny. sa nawet dowody. O RLE trudno mi tak z palca cos powiedziec). Jezeli komus sie chce optymalizowac, mozna sprobowac innego wypelnienia RLE np 3,5,6,7,8 bitow. Mozna napisac program, ktory kompresuje na dana dlugosc przykladowe/reprezentatywne dane i sprawdzic, ktora metoda daje najlepsza kompresje, z tym, ze procedury nie beda juz tak trywialne.

Recznie sie pobawilem kompresujac kodami 3,4 i 5 bitowymi oraz czystym huffmanem (czyli same kody prefiksowe bez RLE) Twoje przyklady i wyszly mi skompresowane dane o dlugosci (w bajtach):

bity   przyklad1 przyklad2

huff    32           28
3       27           30
4       22           34
5       19           38

Pierwszy przyklad zawieral duzo powtorzen, a wiec idealnie dla RLE i czym wiecej bitow tym byl bardziej zadowolony. Drugi przyklad mial mniej powtorzen i RLE na niewiele sie zdalo i najefektywniejszy okazal sie sam huffman.

Jak widac metoda jest bardzo uzaleazniona od konkretnego przykladu (chociaz 4 bity to taka chyba srednia i chyba najlepszy wybor), wiec przy odrobinie fanatyzmu kompresowac mozna wszystkimi i wybierac dla kazdego przykladu osobno metode najlepsza. Kod troche puchnie, ale stopien kompresji bedzie dobry.

Ostatnio edytowany przez laoo/ng (2006-02-12 21:27:49)

13

Odp: kompresja - wynik na 1 stronie

Pare rzeczy mi sie tu nasuwa:

1. Jak danych wejsciowych jest 3k to z samego Huffmana nawet jakbys wszystko zakodowal
1 bitem to wyjdzie ci 50% ;) czyli 1,5k a nie 200 bajtów ;)

2. Wedlug mnie takie normalne RLE jest tu bez sensu jezeli dlugości powtarzania sie
nie sa wieksze niz 4-5 bajtow, a srednie powtarzanie masz w tych granicach. Czemu ?
Bo jak dodasz 3 bity na licznik chocby to juz masz  1 bit symbolu + 3 bity licznika
co daje 4 bity tyle samo by wyszlo gdybys po prostu zakodowal 4 x 1 bit danych
czyli skrocenie wystepuje dopiero przy 5 powtorzeniach o 1 bit, oczywiscie jeżeli
stosujemy RLE tylko do tego 70% znaku a reszte normalnie. Natomiast przy
powtorzeniach krotszych (2-3) bedzie to wydluzac zamiast skracac.

3. Można by to poprawic stosując też huffmana do licznika czyli biorąc pod uwage
czestość okreslonych powtorzen, ale tez bym nie liczyl ze osiagniesz 200 bajtow ;),
no chyba że miales na mysli 3k danych wejsciowych w bajtach, a nie juz w symbolach
2bitowych, wtedy faktycznie wejsciowych bedzie 3k/4 czyli  jakies 768 bajtow czego
i tak samym huffmanem do 200 nie zmniejszysz. Z RLE jakas tam szansa jest, ale
trzeba by chyba przeanalizowac dane i zastosowac wbudowane w procedurke
dekompresji na stale dlugosci. Np. jezeli najczestsze powtorzenia beda x5 x4 i x6
(przykladowo) i ich kody beda np. 00 01 10  no to masz tam jakis skrot typu 1-3 bitow
(np. 010 oznacza 0 - kod znaku 70%ego +10 x6 czyli zastepuje 000000 itd.).
Czyli cuś jak w deflate tylko w wersji uproszczonej i zastosowane tylko do tego 70%.
Oczywiscie nadal np. wystapienia pojedyncze czy x2 , x3 nawet jeżeli beda rzadziej
wystepowac beda wydluzac zamiast skracac, wiec to zalezy jak duzo ktorych powtorzen
bedzie, ale wlasnie dlatego huffman do licznika tez. Jeszcze analiza czy np. nie oplaci
sie np. powtorzen x8 przerabiac na x4 + x4 czy x9 na x4 + x5 itp. Tak czy siak
te < 256 bajtow to dosc mizernie widze chyba ze masz tak fantastyczne dane ;).
W każdym razie bym je przeanalizowal (te wszystkie dane) i od tego bym uzależnil
jaka metode sobie wybrac.

---==<<Sc0rpi0>>==---

14

Odp: kompresja - wynik na 1 stronie

Sc0rpi0 :) Tak czytam co Ty tu napisales i czytam i czytam i mysle, ze chyba nie zrozumiales, co xxl mial na mysli ;). Otoz u xxl-a wynikdekompresji bedzie zajmowal ok 200 bajtow --- 200 zdekompresowanych symboli z ktorych kazdy bedzie bajtem 1,2,3 albo 4 (lub jakimis innymi ale bedzie ich 4), a danych wyjsciowych bedzie w sumie 3k czyli bedzie jakies 15 partii po 200 bajtow (symboli) ktore trzeba bedzie skompresowac. Wiec huffman i RLE sa tu jak najbardziej na miejscu.

No chyba ze to ja zle zrozumialem. Niech ktos mnie wtedy poprawi.

15

Odp: kompresja - wynik na 1 stronie

Jutro wkleje tu kilka zagwózdek z mojego 3d z falcona. A co tam, niech ktoś za mnie zrobi ;)

What can be asserted without proof can be dismissed without proof.

Odp: kompresja - wynik na 1 stronie

I offset sobie poradzi. Dla 'przyklad 1' będzie to 23 bajty w ciągu wyjściowym.

17

Odp: kompresja - wynik na 1 stronie

LZSS - ofset i długość na 5 bitach:
przykład 1 -> 14 bajtów,
przykład 2 -> 23 bajty.

...o ile się nie walnąłem w liczeniu :)

Ostatnio edytowany przez Magnus (2006-02-13 22:29:21)

18

Odp: kompresja - wynik na 1 stronie

No. Metoda slownikowa nadaje sie tu wysmienicie :)

19

Odp: kompresja - wynik na 1 stronie

zielony: piszesz o tym co ja napisalem? ;)
btw. jak napisalem - to sie da jeszcze o pare bajtow skrocic
ale przy obecnym zapisie - jest holernie proste do dekompresji...

Ostatnio edytowany przez jellonek (2006-02-13 21:56:17)

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

Odp: kompresja - wynik na 1 stronie

jellonek: pewnie tak, tylko przy offsecie nie ma potrzeby kodowania powtórzenia dla jednego bajtu /u Ciebie |0|L|L|L|L|L|L|L| |dana|/ bo jeśli offset dasz na -1 uzyskasz to samo: |1|L=-1|dlugość ciągu| a |0| dajesz na oznaczenie bajtu niekompresowanego (oczywiście te grupujesz po 8 by było łatwiej kompresować/dekompesować). Procedura dekompresora nawet bitowego, mieści się z powodzeniem na jednej stronie pamięci - zresztą co to dla Was :P.

21

Odp: kompresja - wynik na 1 stronie

Właśnie, jellonek, co to dla Was :P

KMK
? HEX$(6670358)

22

Odp: kompresja - wynik na 1 stronie

drac030: ale o so si chozi?

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

23

Odp: kompresja - wynik na 1 stronie

dziekuje wszystkim za pomoc, otworzyly mi sie oczy :-)

zrobilem odrobine zmodyfikowany rle (jako ze dane sa bardzo specyficzne) i tak:
przyklad1: 27 bajtów
przyklad2: 25 bajtów


---

poprawka:

przyklad1: 29 bajtow
przyklad2: 21 bajtow

Ostatnio edytowany przez xxl (2006-02-14 09:18:24)

http://atari.pl/hsc/ad.php?i=1.

24

Odp: kompresja - wynik na 1 stronie

Ale i tak moj dekompresor byl najszybszy :cool:

25

Odp: kompresja - wynik na 1 stronie

laoo - nie prawda, bo moj :P

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep