Это ваша картинка, разложенная на основные цвета:
Очевидно, вы неправильно конвертируете цвета в числа, а числа в цвета. Вы обрабатываете пиксель int RGB как одно числовое значение и передаете его через числовую процедуру SVD, но информация о том, что это фактически RGB, теряется.
Большинство методов сжатия изображений с потерями обеспечивают сжатие путем отбрасывания малозначащих битов. Но когда у вас есть RGB в одном int, младшие биты каждого R, G и B чередуются с более значимыми битами. При передаче пикселя в виде одного числового значения эта информация теряется, и процедура SVD эффективно интерпретирует малозначительные биты R как более значимые, чем высокозначительные биты G, и может попытаться полностью отбросить все биты G и B, потому что они хранятся "после" R бит.
Например, светло-серый пиксель (192 192 192) имеет значение RGB 0xC0C0C0. Сжатие этого значения с ошибкой 1 % может дать, например, 0xC2AE32. С точки зрения алгоритма сжатия это значение всего на 1% больше исходного, что практически незаметно. Но преобразование этого обратно в RGB дает (194,174,50). Компонент R действительно почти такой же, но G и B повреждены. Это источник "мусорных цветов" в вашей программе. Разложенное изображение показывает, что компонент R сжат правильно, компонент G становится случайным шумом при высоких уровнях сжатия, а компонент B всегда является случайным.
Еще одна проблема в вашей реализации — одиночные яркие пиксели, разбросанные по темным областям. Это, по-видимому, вызвано числовым переполнением и недостаточным числом. Например, черный пиксель (0,0,0) кодируется как 0x000000 = 0; сжатие с потерями может привести к небольшой ошибке, которая может быть положительной или отрицательной и может дать -1 = 0xFFFFFFFF; в RGB это становится (255 255 255), что является белым.
Что делать?
Если вы просто тестируете сжатие изображения SVD и достаточно использовать изображения в градациях серого, то вам следует просто взять младший байт из значения RGB, которое находится в диапазоне от 0 до 255. Соответственно, при отображении результата или записи выходного файла интерпретируйте это значение как оттенки серого или умножьте на 0x010101, чтобы получить полное значение RGB.
Если вам нужно сжать цветные изображения, вы должны запустить алгоритм SVD отдельно для компонентов R, G и B. Это самый простой способ обработки цвета, но не самый эффективный. Чтобы получить более высокое сжатие и менее заметные артефакты, лучше конвертировать из RGB в Lab (канал яркости и два канала цветности); цветность может быть сжата сильнее, так работает JPEG.
При распаковке изображения, после вычисления значений из SVD, но перед их выводом на экран или записью в файл, зажимаем все полученные значения (R, G и B) в диапазоне 0-255. Это устранит разбросанные белые точки.
person
Goblin Alchemist
schedule
20.11.2012