Mam wideo pochodzące ze stacjonarnej kamery. Zarówno rozdzielczość, jak i liczba klatek na sekundę są dość wysokie. Dane, które otrzymuję, są w formacie Bayera i używają 10 bitów na piksel. Ponieważ na mojej platformie nie ma 10-bitowego typu danych, oryginalne dane są przechowywane w pamięci za pomocą 16-bitowych słów. Chcę zaimplementować pewnego rodzaju bezstratną kompresję danych przed przesłaniem ich przez sieć.
- Aparat się nie porusza, więc duże części kolejnych klatek są prawie identyczne - ale wciąż nie do końca, z powodu nieuniknionego hałasu (odszumianie nie jest opcją, ponieważ powinno być bezstratne i nie powinno „tracić” nawet szumu ).
- Z powodu wysokiej liczby klatek na sekundę nawet zmieniające się części nie zmieniają się znacznie między dwoma kolejnymi klatkami.
- Wygląda jednak na to, że aparat trochę się trzęsie. Bardzo mało, ale nawet nieruchome obiekty nie są całkowicie takie w przestrzeni obrazu.
- Kompresję należy wykonać w locie, więc nie mogę zebrać wielu klatek i skompresować ich wszystkich razem, ale mogę spojrzeć 1 klatkę wstecz i użyć jej jako odniesienia.
W oparciu o powyższe, moją pierwszą myślą było spakowanie bitów danych, aby te 6 nadmiarowych bitów nie było marnowanych na każde słowo. Pomyślałem jednak, że jeśli użyję kodowania entropijnego (np. Huffman itp.), Nadmiarowość zostanie automatycznie uwzględniona, więc nie jest konieczne dodatkowe pakowanie. Więc zrobiłem następujące:
- Wziął binarną różnicę między dwiema kolejnymi ramkami. Pierwotny zakres danych wynosił 0 ~ 1023 (np. 10 bitów bez znaku). Dane różnicowe zostają podpisane, a zakres wzrasta do -1023 ~ 1023, ale zmienność danych (lub prawidłowy termin matematyczny) staje się znacznie mniejsza niż w danych oryginalnych, w rzeczywistości większość wartości, co nie dziwi, jest bliska zeru .
- Zastosowano kodowanie ryżu do różnicy. Z tego, co rozumiem, wygląda to na dobry wybór dla zestawów danych składających się głównie z małych wartości liczbowych.
To daje mi około 60% zmniejszenie rozmiaru ramek 1280x720, a mój system testowy (Linux w VirtualBox na jednym rdzeniu) może wykonać ~ 40 takich kompresji na sekundę (bez dużej optymalizacji). Nie wspaniale, ale rozsądnie, jak sądzę (a może tak?).
Czy są lepsze sposoby? Jakieś typowe błędy, które popełniłem? Jakieś ogólne kroki, które przeoczyłem? Ramki o wyższej rozdzielczości mogą być później używane - czy powinienem oczekiwać lepszych współczynników kompresji dla większych rozmiarów ramek?
UPD .:
- Użyłem tej biblioteki do kodowania Rice'a. Biblioteka jest bardzo wolna (sam autor opisuje ją jako coś do nauki, a nie do prawdziwego użytku), na przykład odczytuje i zapisuje w pętlach fragmenty jeden po drugim, co zabija wydajność. Początkowo dawało mi to tylko ~ 20 FPS, po bardzo podstawowej optymalizacji stało się 40 FPS (jak opisano powyżej), później zoptymalizowałem je trochę więcej, osiągnęło 80. To znaczy na jednym rdzeniu i7 bez wektoryzacji.
- Jeśli chodzi o wektoryzację, niestety nie mogłem wymyślić sposobu na wektoryzację kodu Rice'a (nawet nie wiem czy to w ogóle możliwe - nie mogłem znaleźć żadnych danych na temat kodu Rice'a, co mogłem znaleźć na temat kodu Huffmana sugeruje, że jest sekwencyjny i nie może być skutecznie wektoryzowany, co może dotyczyć zarówno kodu Rice, jak i innych kodów o zmiennej długości).
- Próbowałem też zupełnie innego podejścia: podziel dane na małe części (np. 64-pikselowe) i zastosuj proste tłumienie zera. Znajdujemy największą liczbę w bloku, zapisujemy liczbę bitów wymaganą do jej przedstawienia na początku bloku (w tym przypadku wymagane były 4 dodatkowe bity), a następnie zmniejsz wszystkie liczby w bloku do tej samej liczby bitów Spodziewałem się, że stopień kompresji będzie zły, ale jeśli kawałki są małe, wiele z nich nie będzie miało skoków hałasu, dlatego ich różnicę binarną można zmniejszyć do około 4 ~ 6 bitów na wartość, a tak naprawdę to tylko około 5% gorszy niż kod Rice'a, przy czym jest około dwa razy szybszy (np. 160 FPS w moim przypadku). Próbowałem wektoryzować, ale trochę wkurzam wektoryzację, więc może z tego powodu mogłem osiągnąć tylko około x1,8 dalszego przyspieszenia.
Ponieważ liczby ujemne nie mają zer wiodących, zastosowałem kodowanie zygzakowe po różnicy binarnej i przed tłumieniem Rice / zero.