При сжатии изображения появляются цветные пиксели (включая фото) - PullRequest
5 голосов
/ 12 марта 2012

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

Garbage pixels

Число, показанное в правом верхнем углу, показывает количество итераций, где 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.

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

Спасибо,

Justian

1 Ответ

3 голосов
/ 20 ноября 2012

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

Lena SVD decomposed to 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. Это устранит разбросанные белые точки.

...