Я получил это изображение. Изображение 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) в первом индексе.
Если я правильно понимаю, вы хотите оставить изображение без изменений и заменить индекс розового цвета на 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')
Результат: