Цветные пиксели появляются при попытке сжатия изображения (включая фотографии)

Я пытаюсь сжать данное изображение, используя разложение по сингулярным значениям. Я думал, что у меня это есть, пока не заметил, что на протяжении всего процесса у меня продолжают появляться мусорные цветные пиксели.

Мусорные пиксели

Число, показанное в правом верхнем углу, показывает количество итераций, где 0 — исходное изображение.

Это распространенная ошибка? Есть что-то, что мне не хватает?

Я полагаю, что это может быть связано с моей математикой, самой. Я использую JAMA, пакет матриц Java, который обрабатывает это для меня. Ниже приведена моя реализация для каждой итерации:

for (int i = 0; i < k; i++) {    
    Matrix step = (uColumns[i].times(sValues[i])).times(vColumns[i].transpose());
    encoded = encoded.plus(step);
}

По сути, что я делаю (или пытаюсь сделать):

M = M + (s1*u1*v1^t)

Что-то явно не так с моей реализацией, или ошибка, возможно, связана с тем, как JAMA выполняет SVD? Из того, что я проверил, знак значений в матрицах U и V отличается в некоторых строках от тех, которые созданы Wolframalpha или Matlab.

Любая помощь приветствуется.

Спасибо,

Юстиан


person Justian Meyer    schedule 12.03.2012    source источник
comment
Я не знаю эту библиотеку для SVD, я использовал ее в C #, никогда не делал такого рода программы на Java, но я думаю, что это может быть просто результат сжатия. Вы сравнивали свои результаты с другими, использующими аналогичный метод сжатия?   -  person HericDenis    schedule 05.11.2012
comment
Могут ли белые пиксели быть вызваны переполнением/недополнением? Например, пиксель, который изначально был черным (0), становится -0,01 из-за сжатия с потерями, которое округляется до -1, а затем становится 255 на экране...   -  person Goblin Alchemist    schedule 20.11.2012


Ответы (1)


Это ваша картинка, разложенная на основные цвета:

Лена СВД разложена на RGB

Очевидно, вы неправильно конвертируете цвета в числа, а числа в цвета. Вы обрабатываете пиксель 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