Преобразование из 32-BPP в индексированный 8-BPP (C#)

Мне нужно взять полноцветное изображение JPG и переназначить его цвета на индексированную палитру. Палитра будет состоять из определенных цветов, заполненных из базы данных. Мне нужно сопоставить каждый цвет изображения с его «ближайшим» значением в индексе. Я уверен, что существуют разные алгоритмы сравнения и вычисления «ближайшего» значения. Нужны только библиотеки управляемого кода C#, .NET.

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


person Community    schedule 05.11.2009    source источник


Ответы (4)


Ничто не поможет вам с GDI. Похоже, что индексированные изображения — слишком отсталая технология, чтобы Microsoft могла о ней заботиться. Все, что вы можете сделать, это читать и записывать индексированные файлы изображений.

Обычно квантизация цветов в изображении выполняется в два этапа:
1) Найдите наилучшую палитру для изображения (квантизация цвета)
2) Сопоставьте исходные солоры с найденной палитрой (картографирование цвета).

Насколько я понимаю, у вас уже есть палитра в базе данных, а это значит, что самое сложное за вас уже сделано. Все, что вам нужно сделать, это сопоставить 24-битные цвета с предоставленными цветами палитры. Если у вас нет исходной палитры, вам придется вычислить ее самостоятельно, используя алгоритм квантования: наиболее известны Octree или Median Cut. Median Cut дает лучшие результаты, но медленнее и сложнее в реализации и точной настройке.

Самый простой алгоритм для сопоставления цветов в вашем случае — вычислить расстояние от вашего исходного цвета до всех цветов палитры и выбрать ближайший.

float ColorDistanceSquared(Color c1, Color c2)
{
    float deltaR = c2.R - c1.R;
    float deltaG = c2.G - c1.G;
    float deltaB = c2.B - c1.B;
    return deltaR*deltaR + deltaG*deltaG + deltaB*deltaB;
}

Вы также можете обдумать каналы, чтобы синий имел меньший вес, не переборщите с этим, иначе это даст ужасные результаты, в частности, 30/59/11 вообще не будет работать:

float ColorDistanceSquared(Color c1, Color c2)
{
    float deltaR = (c2.R - c1.R) * 3;
    float deltaG = (c2.G - c1.G) * 3;
    float deltaB = (c2.B - c1.B) * 2;
    return deltaR*deltaR + deltaG*deltaG + deltaB*deltaB;
}

Вызовите эту штуку для всех исходных цветов и цветов палитры и найдите Мин. Если вы кешируете свои результаты по мере продвижения по карте, это будет очень быстро.

Кроме того, исходный цвет редко будет соответствовать цвету палитры достаточно, чтобы не создавать полосы и однотонные области и не терять детали на вашем изображении. Чтобы избежать этого, вы можете использовать дизеринг. Самый простой алгоритм, дающий наилучшие результаты, — диффузионное сглаживание ошибок.

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

person Coincoin    schedule 09.11.2009

Этот процесс называется квантизацией. Поскольку каждый цвет представляет собой 3 упакованных значения, для решения этой проблемы вам потребуется использовать октодеревья.

Ознакомьтесь с этой статьей с примером кода.

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

person LiraNuna    schedule 05.11.2009
comment
Итак, есть ли в .NET framework встроенные библиотеки квантования? - person ; 06.11.2009
comment
Я ничего не знаю о .NET (я работаю в Linux), и я привык делать что-то сам (ТМ). Извините, я не могу предоставить больше информации. - person LiraNuna; 06.11.2009

Мне пришлось сделать это в большом проекте .NET. В рамках этого ничего нет, но эта статья быстро привела меня к решению: http://codebetter.com/blogs/brendan.tompkins/archive/2004/01/26/6103.aspx

person Nestor    schedule 06.11.2009
comment
Похоже, они только что удалили '.' на его имя. Это работает: codebetter.com/brendantompkins/2004/01/26/ - person Nestor; 28.04.2011

Слово в формате JPEG должно насторожить. Изображения, скорее всего, уже находятся в сильно квантованном цветовом пространстве, и дальнейшая передискретизация потенциально может привести к наложению изображений. Если можете, работайте с несжатыми изображениями, чтобы уменьшить этот эффект.

Ответ на ваш вопрос - да, вы можете сохранять изображения в альтернативном формате, но я не уверен, что встроенная функциональность соответствует тому, что звучит как довольно сложное требование. Если вы сможете определить цветовую палитру из коллекции изображений, вы, скорее всего, улучшите качество вывода.

Уже упомянутая запись в блоге под названием «Использование GDI+ для сохранения кристально чистых изображений GIF с помощью .NET» содержит полезные ссылки на код.

person Pekka    schedule 08.11.2009