У меня есть видео со стационарной камеры. И разрешение, и FPS довольно высоки. Я получаю данные в формате Байера и использует 10 бит на пиксель. Поскольку на моей платформе нет 10-битного типа данных, исходные данные хранятся в памяти с использованием 16-битных слов. Я хочу реализовать какое-то сжатие данных без потерь перед их передачей по сети.
- Камера не движется, поэтому большие части последовательных кадров практически идентичны, но все же не полностью, из-за неизбежного шума (шумоподавление не вариант, так как предполагается, что он не имеет потерь и не должен «терять» даже шум ).
- Из-за высокого FPS даже части, которые меняются, мало меняются между любыми двумя последовательными кадрами.
- Впрочем, похоже, что камера тоже немного качается. Очень мало, но, тем не менее, даже неподвижные объекты не совсем так в пространстве изображения.
- Сжатие должно быть сделано на лету, поэтому я не могу собрать много кадров и сжать их все вместе, но я могу просмотреть 1 кадр назад и использовать его в качестве ссылки.
Исходя из вышеизложенного, моей первой мыслью было упаковать данные в биты, чтобы эти 6 избыточных бит не были потрачены впустую на каждое слово. Однако я подумал, что если я использую какое-то энтропийное кодирование (например, Хаффмана и т. Д.), Эта избыточность будет автоматически учтена, поэтому дополнительная упаковка не требуется. Итак, я сделал следующее:
- Взял двоичную разницу между двумя последовательными кадрами. Исходный диапазон данных был 0 ~ 1023 (например, 10-бит без знака). Разностные данные становятся подписанными, и диапазон увеличивается до -1023 ~ 1023, но разброс данных (или каков правильный математический термин) становится намного меньше, чем в исходных данных, на самом деле, большинство значений, что неудивительно, близко к нулю ,
- Прикладное рисование кодирования к разнице. Из того, что я понимаю, это выглядит как хороший выбор для наборов данных, в основном небольших числовых значений.
Это дает мне примерно 60% уменьшение размера для кадров 1280x720, и моя тестовая система (Linux в VirtualBox на одном ядре) может делать ~ 40 таких сжатий в секунду (без особой оптимизации). Не так здорово, но разумно, я думаю (или это?).
Есть ли лучшие способы? Любые распространенные ошибки, которые я сделал? Какие общие шаги я пропустил? Кадры с более высоким разрешением могут быть использованы позже - следует ли ожидать более высоких коэффициентов сжатия для больших размеров кадров?
UPD .:
- Я использовал эту библиотеку для кодирования Райса. Библиотека очень медленная (сам автор описывает ее как нечто для изучения, а не для реального использования), например, она читает и записывает биты один за другим в циклах, что снижает производительность. Первоначально он дал мне всего ~ 20 FPS, после некоторой базовой оптимизации он стал 40 FPS (как сообщалось выше), позже я оптимизировал его еще немного, он стал 80. Это на одном ядре i7 без векторизации.
- Что касается векторизации, хотя, к сожалению, я не мог придумать способ векторизации кода Райса (даже не знаю, возможен ли он вообще - не смог найти никаких данных о коде Райса, что я смог найти в коде Хаффмана, говорит о том, что он последовательный и не может быть эффективно векторизован, что может применяться к коду Райса, а также к другим кодам переменной длины).
- Я также попробовал совершенно другой подход: разбить данные на маленькие кусочки (например, по 64 пикселя за штуку) и использовать простое подавление нуля . Мы находим наибольшее число в блоке, записываем количество битов, необходимых для его представления, в начало блока (в моем случае для этого потребовалось 4 дополнительных бита), затем уменьшаем все числа в блоке до одинакового числа. биты. Я ожидал, что степень сжатия будет плохой, но если части будут маленькими, у многих из них не будет пиковых шумов, поэтому их двоичная разница может быть уменьшена до примерно 4 ~ 6 битов на значение, и это было, фактически, только примерно на 5% хуже, чем в коде Райса, но в два раза быстрее (например, 160 FPS для моего случая). Я пытался векторизовать его, но я вроде как сосал векторизацию, так что, возможно, из-за этого я мог добиться лишь примерно 1,8 увеличения скорости.
Поскольку отрицательные числа не имеют ведущих нулей, я применил зигзагообразное кодирование после двоичной разницы и до подавления Райса / нуля.
источник
Ответы:
У вас есть временное предсказание, но нет пространственного. Для лучшего сжатия ценой скорости вы должны использовать пиксели выше и слева от текущего пикселя в текущем кадре в качестве предикторов, а также пиксель в том же месте в предыдущем кадре. Причина только смотреть вверх и влево такая же, как причина только смотреть на предыдущий кадр; вы хотите полагаться только на данные, которые вы уже расшифровали, и ограничить объем их хранения.
Рисовые коды, вероятно, являются хорошим компромиссом между эффективностью и скоростью, но статический код Хаффмана (предварительно рассчитанный вами на примере видеоданных) может быть более эффективным и одинаково быстрым.
Что касается скорости, убедитесь, что ваш код становится векторизованным - либо с помощью правильных флагов компилятора и шаблонов кода, позволяющих компилятору автоматически векторизоваться, либо путем написания от руки кода с использованием векторных встроенных функций или сборок.
Наконец, возможно ли снижение до 8 бит на пиксель? Очевидно, что это оставляет сферу «без потерь», но не только уменьшит размер вашего сжатого вывода, но и с векторизованным кодом, возможно, увеличит вашу пропускную способность до 2х.
источник
x5
на разницу(x5 - x4)
?Возможно, вам лучше всего использовать существующие реализации сжатия и распаковки. Ваша существующая реализация кажется похожей на кодек HuffYUV , так что, возможно, стоит попробовать, чтобы увидеть, работает ли она достаточно хорошо для вас.
источник