Изменить индекс цвета палитры в Python

Я получил это изображение. Изображение PNG, в режиме P, палитра в режиме RGB. Мне нужно остаться с 16 цветами, так как я хочу, чтобы изображение было 4bpp. И мне нужно изменить его палитру, сделав розовый цвет (255, 192, 203) его первым индексом.

Палитра изображения:

{(255, 255, 232): 0, (255, 192, 203): 1, (210, 204, 147): 2, (62, 214, 108): 3, (59, 193, 95): 4, (209, 174, 99): 5, (194, 164, 92): 6, (130, 186, 185): 7, (180, 148, 83): 8, (95, 152, 121): 9, (49, 161, 88): 10, (157, 123, 59): 11, (118, 97, 55): 12, (52, 128, 119): 13, (73, 80, 63): 14, (63, 59, 47): 15}

И я хочу:

{(255, 192, 203): 0, (255, 255, 232): 1, (210, 204, 147): 2, (62, 214, 108): 3, (59, 193, 95): 4, (209, 174, 99): 5, (194, 164, 92): 6, (130, 186, 185): 7, (180, 148, 83): 8, (95, 152, 121): 9, (49, 161, 88): 10, (157, 123, 59): 11, (118, 97, 55): 12, (52, 128, 119): 13, (73, 80, 63): 14, (63, 59, 47): 15}

Я сделал для него этот код:

def change_palette(im):
    colors = im.palette.colors #get colors from palette
    if (PINK not in colors): #check there is pink (could be possible that there is not)
        return
    first = list(colors.keys())[list(colors.values()).index(0)] #colors is a dict so I get the key of the first index
    colors[first] = colors[PINK] 
    colors[PINK] = 0 #change the value of the colors
    newcolors = {}
    newcolors[PINK] = colors.pop(PINK)
    for key in colors:
        newcolors[key] = colors[key] #reorder the dict so it is in order
    colors = newcolors
    newcolors = []
    for key in colors: 
        for c in key:
            newcolors.append(c) #make it a list
    im.putpalette(newcolors) #change palette

Но это делает изображение таким.

Я пробовал это с другими методами, например, не используя палитру и меняя только цвета палитры, но это не вносит никаких изменений при сохранении изображения. Я понимаю проблему, но я не могу найти решение. Я хочу, чтобы он выглядел точно так же, но с розовым цветом (255, 192, 203) в первом индексе.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Когда мы изменяем палитру, мы переключаемся между двумя цветами:
Все пиксели с цветом (255, 255, 232) переключаются на розовый цвет (255, 192, 203), а все пиксели с розовым цветом (255, 192, 203) переключаются на цвет (255, 255, 232).

Причина в том, что значения (индекса) пикселей не изменяются. После применения новой палитры все пиксели со значением (индекса) 0 стали розовыми, а все пиксели со значением (индекса) 1 стали (255, 255, 232).

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

  • Все пиксели со значением (индекса) 0 должны быть изменены на значение 1.
  • Все пиксели со значением (индекса) 1 должны быть изменены на значение 0.

Для удобства мы можем преобразовать данные в массив NumPy и преобразовать обратно в изображение PIL:

pink_index = colors[PINK]  # Original index of pink color

... 

indexed = np.array(im)  # Convert to NumPy array to easier access.
new_indexed = indexed.copy()  # Make a copy of the NumPy array
new_indexed[indexed == 0] = pink_index  # Replace all original 0 pixels with pink_index
new_indexed[indexed == pink_index] = 0  # Replace all original pink_index pixels with 0
new_im = Image.fromarray(new_indexed)  # Convert from NumPy array to Image.
new_im.putpalette(newcolors)  # Set the palette

Полный пример кода:

from PIL import Image
import numpy as np

PINK = (255, 192, 203)

def change_palette(im):
    colors = im.palette.colors #get colors from palette
    if (PINK not in colors): #check there is pink (could be possible that there is not)
        return
    first = list(colors.keys())[list(colors.values()).index(0)] #colors is a dict so I get the key of the first index
    pink_index = colors[PINK]
    colors[first] = colors[PINK] 
    colors[PINK] = 0 #change the value of the colors
    newcolors = {}
    newcolors[PINK] = colors.pop(PINK)
    for key in colors:
        newcolors[key] = colors[key] #reorder the dict so it is in order
    colors = newcolors
    newcolors = []
    for key in colors: 
        for c in key:
            newcolors.append(c) #make it a list
    #im.putpalette(newcolors) #change palette

    indexed = np.array(im)  # Convert to NumPy array to easier access https://stackoverflow.com/a/33023875/4926757
    new_indexed = indexed.copy()  # Make a copy of the NumPy array
    new_indexed[indexed == 0] = pink_index  # Replace all original 0 pixels with pink_index
    new_indexed[indexed == pink_index] = 0  # Replace all original pink_index pixels with 0

    new_im = Image.fromarray(new_indexed)  # Convert from NumPy array to Image https://stackoverflow.com/a/39258561/4926757
    new_im.putpalette(newcolors)  # Set the palette

    return new_im


img = Image.open('original_image.png')

new_image = change_palette(img)

new_image.save('changed_image.png')

Результат:

Другие вопросы по теме