Komprejsa obrazu - kod Huffmana

Komprejsa obrazu - kod Huffmana
ML
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:5
0

Witam

Mam zadanie, polegające na napisaniu programu kompresującego bitmapę z wykorzystaniem algorytmu Huffmana (oraz dekompresującego). Bitmapa jest 8-bitowa (8 bitów na piksel, paleta kolorów lub odcienie szarości).
Stworzyłem ogólny algorytm. Bardzo proszę o sprawdzenie toku rozumowania i wskazanie błędów :)

Kodowanie:

  1. Tworzę w programie tablicę, składającą się z 256 elementów.
  2. Z nagłówka pliku BMP odczytuję wysokość i szerokość obrazu
  3. Przechodzę do tablicy pikseli i odczytuje ją po jednym bajcie.
  4. Inkrementuję w mojej tablicy indeks, odpowiadający odczytanemu bajtowi.
  5. Gdy dochodzę do końca pliku to w tablicy mam zliczone wsytąpienia poszczególnych kolorów.
  6. Dane z tablicy "przekazuję" do algorytmu Huffmana i dla każdego indeksu (koloru) otrzymuję jego kod.
  7. Tworzę nowy plik (skompresowany) i umieszczam w jego nagłówku wysokość i szerokość obrazu.
  8. Tworzę nową paletę barw - składowe pobieram z "oryginalnej" palety, jednak zamiast indeksów daję kod.
  9. "Przepisuję" tablicę pikselów z oryginalnego obrazu, uwzględniając kody znajdujące się w nowej (skompresowanej) palecie barw.

Pozdrawiam

MateuszS
Wydaje mi sie ze jest ok (o ile dobrze wszystko zrozumialem). Napisz Huffmana optymalnie i powinno ladnie dzialac. Sam mialem podobny projekt wiec moge pomoc
BA
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 6 lat
  • Postów:36
1

Moim zdaniem w znacznej większości twój tok rozumowania jest poprawny. Nie jestem tylko pewien, po co pobierać wymiary obrazu. Jeśli nie chcesz wyświetlać skompresowanego pliku jako obrazu (chyba, że chcesz) to imo nie bardzo ma to sens.
Pozdrawiam

ML
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:5
0

Witam ponownie :)

Dziękuję za odpowiedzi.
Okazało się, że kompresowana ma być bitmapa 4-bitowa (a nie jak pisałem na początku 8-bitowa). Jest jednak pewien problem - pliki źródłowe, które mają być poddane kompresji nie zawierają palety barw, lecz każdy piksel opisywany jest za pomocą trzech bajtów (składowe kolejno B, G, R). Trochę to dziwne, bo choć obrazek jest 4-bitowy to zapisany jest jak 24-bitowy. W związku z tym w skompresowanym pliku będę musiał sam stworzyć paletę barw - i tu pojawia się problem :) Nie do końca wiem w jaki sposób to uczynić
Moim pierwszym pomysłem było stworzenie tablicy czterowymiarowej (np. int[16][4]) i dla każdego indeksu (od 0 do 15) zapisywać ilość wystąpień danego koloru (np. tab[0][0] - składowa B, tab[0][1] - składowa G, tab[0][2] - składowa R, tab[0][3] - ilość wystąpień). Nie wiem w jaki sposób można byłoby to jeszcze zrealizować?
Jeśli chodzi o samo tworzenie tablicy kolorów to trzeba chyba odczytywać po trzy bajty, następnie sprawdzać czy taka kombinacja znajduje się już w tablicy, jeśli tak to należy ją inkrementować, a jeśli nie to dopisać?

Mam nadzieję, że udało mi się wyjaśnić w miarę zrozumiale o co mi chodzi. Będę bardzo wdzięczny za wszelkie wskazówki.

Pozdrawiam

BA
Mówisz o tworzeniu palety w skompresowanym pliku, prawda?
ML
Tak, przy dekompresji będę musiał zapisać w formacie bez palety (3 bajty na piksel)
BA
To powiedz mi jeszcze, czy chcesz wyświetlać ten skompresowany plik jako obraz, czy to ma być plik w stylu .rar albo zip, który służy tylko do zmniejszenia objętości obrazu?
ML
Wyświetlanie nie jest konieczne. Ważnie jest tylko to, aby była możliwość dekompresji do pliku bmp :)
BA
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 6 lat
  • Postów:36
1

Mając te informacje powiem tak. Nie musisz zbierać palety barw ani wymiarów obrazu. Po prostu odczytuj plik bajt po bajcie i zapisuj w tablicy ilość wystąpień poszczególnych bajtów i zakoduj pojedyncze bajty Huffmanem

ML
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:5
0

Ale mając paletę barw kompresja powinna być skuteczniejsza (bo kodujemy tylko 16 wartości, a nie 48).

BA
Nie jestem w tej kwestii specem, ale wydaje mi się, że im większy potencjalny słownik, tym lepiej Huffman koduje (pod warunkiem, że prawdopodobieństwo wystąpień nie jest nadmiernie zróżnicowane)
ML
W sumie masz racje :) Mój błąd. Ale paleta, niestety, jest konieczna (takie wymagania projektu)
Azarien
"prawdopodobieństwo wystąpień nie jest nadmiernie zróżnicowane" - chyba "nie jest nadmiernie równomierne"? :-) bo przy równym p-stwie wszystkich znaków kompresja jest niemożliwa.
BA
To prawda, ale też kiedy prawdopodobieństwo wystąpienia pewnego symbolu jest bliskie 1 albo po prostu duże to Huffman jest nieefektywyny (a przynajmniej nie tak efektywny, gdy prawdopodobieństwo jest bardziej "wypośrodkowane").
ML
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:5
0

Pojawił się kolejny problem :)
Plik źródłowy zdefiniowałem jako fstream wejscie; Dane pobieram z niego bajt po bajcie, zapisując je do zmiennej typu unsigned char (wejscie >> zmienna). Niestety, gdy w pliku znajduje się bajt o wartości 0x20 to jest pomijany i odczytywany jest kolejny bajt (jest to znak spacji z ASCII). Nie wiem jak sobie z tym poradzić

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:około 9 godzin
2
Kopiuj
fstream wejscie("plik",ios::in|ios::binary);
int znak;
while((znak=wejscie.get())!=EOF) ...

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
several
  • Rejestracja:prawie 16 lat
  • Ostatnio:7 minut
2
micha_l napisał(a):

Plik źródłowy zdefiniowałem jako fstream wejscie; Dane pobieram z niego bajt po bajcie, zapisując je do zmiennej typu unsigned char (wejscie >> zmienna)

Jeśli chcesz czytać binarnie to użyj funkcji read() z flagą ios::binary.


edytowany 1x, ostatnio: several
ML
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:5
0

Dziękuję :)
Dopisanie ios::binary i używanie funkcji get(), zamiast operatora ">>" pomogło

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.