PIL - дизеринг желателен, но ограничение цветовой палитры вызывает проблемы

Я новичок в Python и пытаюсь использовать PIL для выполнения задачи синтаксического анализа, которая мне нужна для проекта Arduino. Этот вопрос относится к методу Image.convert() и параметрам цветовых палитр, дизеринга и т. Д.

У меня есть оборудование, способное отображать изображения только с 16 цветами за раз (но их можно указать триплеты RGB). Итак, я хотел бы автоматизировать задачу получения произвольного изображения PNG с истинным цветом, выбора «оптимальной» 16-цветной палитры для его представления и преобразования изображения в палитру, содержащую ТОЛЬКО 16 цветов.

Я хочу использовать дизеринг. Проблема в том, что метод image.convert() выглядит немного странно. Его аргументы не полностью задокументированы (документация PIL для Image.convert ()), поэтому я не знаю, виновата ли я в этом или нет в методе ошибок.

Вот простая версия моего кода:

import Image
MyImageTrueColor = Image.new('RGB',100,100) # or whatever dimension...

# I paste some images from several other PNG files in using MyImageTrueColor.paste()

MyImageDithered = MyImageTrueColor.convert(mode='P',
    colors=16,
    dither=1
    )

На основании некоторых поисков, которые я сделал (например: Как уменьшить цветовую палитру с помощью PIL) Я бы подумал, что этот метод должен делать то, что я хочу, но не повезло. Он размывает изображение, но дает изображение с более чем 16 цветами.

На всякий случай я удалил аргумент «дизеринг». Тот же результат.

Я повторно добавил аргумент «dither = 1» и добавил аргумент Image.ADAPTIVE (как показано в ссылке выше), чтобы посмотреть, что произошло. В результате получилось изображение, содержащее 16 цветов, но БЕЗ дизеринга.

Я что-то упустил? PIL глючит? Решение, которое я придумал, заключалось в том, чтобы выполнить 2 шага, но это кажется неряшливым и ненужным. Я хочу выяснить, как это сделать правильно :-) Для полноты, вот версия моего кода, которая дает правильный результат - но делает это небрежно. (На первом этапе получается размытое изображение с> 16 цветами, а на втором - изображение, содержащее только 16 цветов.)

MyImage_intermediate = MyImageTrueColor.convert(mode='P',
    colors=16
    )
MyImageDithered = MyImage_intermediate.convert(mode='P',
    colors=16,
    dither=1,
    palette=Image.ADAPTIVE
    )

Спасибо!


person nivek    schedule 28.09.2012    source источник
comment
Ссылка, показанная выше, явно говорит, что я использую Image.ADAPTIVE, чтобы избежать дизеринга, поэтому я не уверен, что вы были удивлены тем, что добавление Image.ADAPTIVE позволило избежать дизеринга ...   -  person abarnert    schedule 28.09.2012
comment
Между прочим, я подозреваю, что дизеринг до 216 веб-цветов, а затем квантование до лучших 16 цветов для веб-палитры, как правило, даст вам гораздо худшие результаты, чем простое квантование до лучших 16 цветов для исходного изображения. Ваши тесты показывают обратное? Если да, возможно, ваш обходной путь приемлем.   -  person abarnert    schedule 28.09.2012


Ответы (1)


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

Во-первых, «официальная» бесплатная версия PIL Handbook неполна и устарела; черновая версия на http://effbot.org/imagingbook/image.htm менее неполна и устаревший.

im.convert («P», ** варианты) ⇒ изображение

То же самое, но обеспечивает лучший контроль при преобразовании изображения «RGB» в изображение с 8-битной палитрой. Доступные варианты:

дизеринг =. Управляет дизерингом. По умолчанию используется FLOYDSTEINBERG, который распределяет ошибки на соседние пиксели. Чтобы отключить дизеринг, используйте NONE.

палитра =. Управляет генерацией палитры. По умолчанию используется WEB, стандартная 216-цветная «веб-палитра». Чтобы использовать оптимизированную палитру, используйте ADAPTIVE.

цвета =. Управляет количеством цветов, используемых для палитры, когда палитра АДАПТИВНА. По умолчанию установлено максимальное значение 256 цветов.

Итак, во-первых, вы не можете использовать colors без ADAPTIVE - по очевидной причине: единственный другой выбор - WEB, который обрабатывает только фиксированную 216-цветовую палитру.

Во-вторых, вы не можете передать 1 в dither. Это могло бы сработать, если бы это было значение FLOYDSTEINBERG, но это 3. Итак, вы передаете недокументированное значение; кто знает, что это будет делать? Тем более, что при просмотре всех констант, которые звучат как возможные названия алгоритмов дизеринга, ни одна из них не имеет значения 1.

Итак, вы можете попробовать изменить его на dither=Image.FLOYDSTEINBERG (вместе с palette=Image.ADAPTIVE) и посмотреть, имеет ли это значение.

Но, глядя на код, похоже, что это не принесет никакой пользы:

if mode == "P" and palette == ADAPTIVE:
    im = self.im.quantize(colors)
    return self._new(im)

Это происходит до того, как мы перейдем к коду дизеринга. Таким образом, это точно так же, как вызов метода квантования (теперь устаревшего / закрытого).

Несколько потоков предполагают, что высокоуровневая функция convert была предназначена только для отображения «дизеринга в веб-палитре» или «сопоставления с ближайшими N цветами». Кажется, что это немного изменилось с 1.1.6 и более поздними версиями, но документация и реализация все еще не завершены. На странице http://comments.gmane.org/gmane.comp.python.image/2947 один из разработчиков рекомендует прочесть исходный код PIL / Image.py.

Итак, похоже, это то, что вам нужно сделать. Что бы Image.convert ни делал в Image.WEB режиме, вы хотите сделать это - но с палитрой, которая будет сгенерирована Image.quantize(colors), а не с веб-палитрой.

Конечно, большая часть этого происходит в коде C (под self.im.quantize, self.im.convert и т. Д.), Но вы можете сделать что-то вроде этого псевдокода:

dummy = img.convert(mode='P', paletter='ADAPTIVE', colors=16)
intermediate = img.copy()
intermediate.setpalette(dummy.palette)
dithered = intermediate._new(intermediate.im.convert('P', Image.FLOYDSTEINBERG))

Опять же, вы не можете. Возможно, вам придется посмотреть заголовки C или даже исходный код, чтобы узнать. Или, может быть, спросите в списке рассылки PIL.

PS, если вы не знакомы с внутренностями PIL, img.im - это объект визуализации C под объектом PIL Image img. По моему прошлому опыту, это неясно в первые 3 раза, когда вы просматриваете код PIL, а затем внезапно все становится намного понятнее.

person abarnert    schedule 28.09.2012
comment
Есть ли способ сопоставить изображение с произвольной палитрой? Если это так, вы можете сделать это за два прохода, первый для создания палитры, а второй для переназначения с дизерингом. - person Mark Ransom; 28.09.2012
comment
@MarkRansom: Проблема в том, что image.convert только дизеринг в веб-палитру, так что квантование выполняется только до 16 цветов, а затем дизеринг до 216, что-то противоположное тому, что он хочет. Но я думаю, что базовая библиотека C может сделать это, о чем и говорит псевдокод в конце. - person abarnert; 28.09.2012