Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Алгоритмы > Алгиритм кодирования изображения |
Автор: SwordOfDeath 7.2.2012, 21:31 | ||
Привет, Вот возникла такая задачка: Есть цветное изображение 100х100. Его нужно сжать, но для этого можно использовать только один метод. Мы можем задавать цвет не каждой точке индивидуально, а сразу непрерывной группе точек, задание цвета может быть вложенным, например в виде xml это может выглядеть вот так:
В данном примере указано всего 10 пикселей, первые пять будут белые, а последние будут черного цвета. Тоесть цвет точки можно переопределять, а степень вложенности не ограничена. Собственно задача выполнить сжатие этим методом максимально эффективно(минимальным количеством указания цвета). Тоесть если у нас к примеру 3 точки Черная, Белая, Черная. То у нас есть два варианта по очереди описать все три точки(это 3 указания цвета) либо задать глобально черный цвет а для белой точки переопределить его(это всего 2 указания цвета). Первое что мне пришло на ум это построить бинарное дерево и на каждой ветке определять самый часто встречаемый цвет. Но это явно не самый эффективный алгоритм. Сдесь должно быть что-то адаптивное... Если у вас есть какие-то идеи буду очень признателен! Спасибо! PS: Еще раз напомню. Критерий эффективности: количество указаний цвета(чем меньше тем лучше). |
Автор: Pavia 8.2.2012, 05:33 |
Так смысла сжимать нет. 14 строчек против 10. По байтно сэкономили 10 байт потратили 24 дополнительных |
Автор: SwordOfDeath 8.2.2012, 06:40 | ||
Ну я же для примера такой формат привел... В реальной задаче на указание цвета тратится 30байт... Я этот формат не придумывал и не контролирую... Просто стоит задача: используя существующие возможности сжать данные по максимуму... На данный момент: я определяю самый частоупотребляемый цвет, задаю его глобально, а потом для всех груп пикселей повторяющегося неглобального цвета переопределяю его. Можно значительно еффективней. PS. Если честно то я даже не понял вашу арифметику... Если втупую определять цвет для каждой точки получим вот такое вот:
|
Автор: tzirechnoy 8.2.2012, 12:46 |
Отсортировать точки по цвету, очевидно, после чего указывать один цвет для каждой подряд идущей группы. Это будет абсолютно минимальный вариант: ведь каждый существующий в картинке цвет должэн быть указан, а здесь он будет указан ровно один раз. |
Автор: Akina 8.2.2012, 14:37 | ||||||
tzirechnoy, он имеет в виду, что
эффективнее, чем
SwordOfDeath, а существует ли возможность задания повторяющейся группы? типа
декодируемого в 10-пиксельную группу БЧЧЧББЧЧЧБ ? |
Автор: SwordOfDeath 8.2.2012, 18:32 |
В том то и проблема... сами пиксели нужно указать полностью... 100х100 картинка будет иметь 10000 пикселей... Пиксели нельзя менять местами... они идут слева направо, сверху вниз... тоесть просто подряд... Единственный метод сжатия который я могу применить это указание цвета групе пикселей с возможностью вложености(в таком случае цвет переопределяется). Структура очень похожа на XML... Сейчас я определяю самый частоиспользуемый цвет(в картинке больше всего групп этого цвета) и задаю его глобально(оборачиваю все пиксели), а для всех остальных групп я переопределяю цвет локально(оборачиваю эту групу чем переопределяю цвет этих пикселей). Это вполне нормальное решение но этого не достаточно... Расход на указание цвета очень высок, нужно выжать максимум. |
Автор: Akina 8.2.2012, 19:50 |
SwordOfDeath, понял. Вроде бы Ваш алгоритм верен... но есть и случаи, когда он даст явно плохие результаты. Представьте кучу маленьких групп одного цвета, концентрирующихся в первой половине и редко встречающиеся во второй половине... и второго цвета, строго "наоборотного"... ведь разумнее поделить всю картинку на две части, и в каждой выбрать свой наиболее частовстречающийся цвет... Когда появляется очередной открывающий тег? когда меняется цвет (будем считать, что мы имеем дело с потоком, а не с матрицей). Можем мы на них сэкономить? только за счёт восстановления предыдущего цвета. Когда появляется очередной закрывающий тег? когда мы завершаем вложенный одноцветный блок. Можем мы на них сэкономить? нет, их будет ровно столько, сколько открывающих. Можно попробовать (возможно, в значительной степени эмпирически) разработать некий критерий, который для данного цвета в данном фрагменте (само собой, начинающемся и заканчивающемся этим цветом) даст некий "коэффициент разумности" использования данного цвета в данном фрагменте в качестве базового. Его расчёт должен учитывать количество цветов, количество фрагментов, базовый цвет в момент начала фрагмента... одно радует - при расчёте такого коэффициента группу последовательных одноцветных пикселов можно сжать в один... Насколько это реально и насколько просто - не знаю пока... думать надо, а это займёт время, причём без гарантии результата. |
Автор: SwordOfDeath 9.2.2012, 02:09 |
Akina, Мой алгоритм всегда дает результат лучше чем если бы я напрямую оборачивал абсолютно все группы пикселей(каждую своим цветом). То что вы предлагаете с разделением это все верно... можно создать рекурсивный алгоритм который будет делить все пространсво на 2 части и для каждого из них определял самый еффективный цвет. Это пожалуй максимум что я смог придумать пока. Но это просто бинарное дерево, а хочется чего-то адаптивного, как вы и предлагаете... только я пока так ничего и не придумал... Благодарен за внимание... PS Это действительно лучше рассматривать как поток. Формат проходит верификацию(скорее всего каким-то xml парсером) так что все елементы должны быть правильно открыты и закрыты, не допускается пересечение (<a><b></a></b>). Все возможные варианты хитростей я уже рассмотрел... = ) PPS Форум что-то падает постоянно... |
Автор: Mirkes 12.2.2012, 19:45 | ||
ПРЕДЛАГАЕТСЯ СРАВНЕНИЕ НЕСКОЛЬКИХ МЕТОДОВ Рассматривать будем картинки, после операции фильтрации, заменившей все подряд идущие пиксели одного цвета на один пиксел. Введем некоторые обозначения N – число смен цветов в картинке. Самая тупая оценка – N установок цвета. Метод обрамления самым распространенным цветом среди групп. Оценка качества N-k+1, где k – число групп самого распространенного цвета. Для определения максимально возможного сжатия используем метод глобального поиска минимума. Он NP полный (оценка порядка 2^N). Как следствие предлагается использовать длину картинки порядка 100 (моя машина на больших размерностях не потянет). Чисто поточный метод. Идея состоит в том, что при поступлении очередного пикселя определяется, есть ли он в стеке установленный на данный момент цветов, и, если есть, производится сброс до этого цвета, иначе – установка его в стек. Метод очень скоростной, но не самый лучший (качество его работы видно в статистике в приложенном файле). Оценка трудозатрат – N. Оконно-поточный метод. Комбинация двух методов. Задаем ширину окна, равную n. Поток режется на куски по n элементов. Производится оптимизация кодирования в окне. Для каждого окна параметрами являются – набор пикселей и ранее сформированный стек. Оценка трудозатрат на этот метод равна (N/n)*2^n. Очевидно, что при n=N он дает глобальный поиск, а при n=1 – чисто поточный. Сравнение строилось на картинках длиной в 50 пикселей, полученных случайной генерацией. Число цветов в картинках варьировалось от 5 до 20 с шагом 5. Размер n варьировался от 5 до N/2 c шагом в 5 Из статистики видно, что при n=N/2 результат почти всегда тот же, а трудозатраты на несколько порядков меньше. Трудозатраты измерены в попугаях – числе вызовов процедуры выбора варианта продолжения. Далее дело Вашего выбора что важнее – степень сжатия или время. Приложенный код довольно странный, но писался для себя
|
Автор: SwordOfDeath 14.2.2012, 23:09 |
Mirkes, Простите за поздний ответ, компьютер накрылся... Я в джаве не очень, да и с алгоритмами тоже слабо дружу... А вы я смотрю изучали алгоритмы, видимо поэтому мне сложно понять вашу мысль ) Я так понял вы предлагаете просто в лоб(перебором) подбирать самый еффективный вариант растановки цветов, а для снижения сложности предлагаете выполнять перебор только по определенному окну? Насколько я понял ваш метод вы протестировали на потоке из 100 пикселей? Тогда у нас беда... так как задача сделать это на ~10тыс. пикселей(100х100). Хотя соглашусь что ваш метод на данный момент решает задачу полностью... Но сложность слишком высока. PS Огромное спасибо за код... немного посмотрю как это на джаве выглядит. Свой алгоритм пишу на С++. |
Автор: SwordOfDeath 18.2.2012, 02:19 |
Mirkes, Огромное спасибо, а я ведь даже и не мечтал о такой существенной помощи. Воистину благодарен! (плюсик поставил!) Сейчас в голове крутится очень много всего, нужно как-то все это систематизировать. Как напишу алгоритм обязательно выложу сюда... ![]() |