После долгих прочтений и проб и ошибок я наткнулся на хорошее решение. Он предполагает изображение sRGB, преобразует его в линейное цветовое пространство для изменения размера, а затем преобразует обратно в sRGB.
Есть небольшой недостаток в том, что используется глубина цвета 8 бит на пиксель, даже когда изображение имеет линейную форму. Это приводит к потере дисперсии в более темных областях. Читая из этого сообщения о проблеме, кажется, что нет способа конвертировать в более высокую глубину, используя Pillow, к сожалению.
from PIL import Image
from PIL.ImageCms import profileToProfile
SRGB_PROFILE = 'sRGB.icc'
LINEARIZED_PROFILE = 'linearized-sRGB.icc'
im = Image.open(IN_PATH)
im = profileToProfile(im, SRGB_PROFILE, LINEARIZED_PROFILE)
im = im.resize((WIDTH, HEIGHT), Image.ANTIALIAS)
im = profileToProfile(im, LINEARIZED_PROFILE, SRGB_PROFILE)
im.save(OUT_PATH)
Вам понадобится линеаризованный цветовой профиль ICC, так как Pillow/lcms не может обойтись без него. Вы можете получить его из этого сообщения о проблеме, и автор упоминает в файле "без авторских прав, использовать свободно". Вам также понадобится профиль sRGB, который легко получить в вашей операционной системе или в Интернете.
Большая часть времени обработки уходит на вычисления преобразований из sRGB и обратно. Если вы собираетесь выполнять много этих операций, вы можете сохранить эти преобразования, чтобы повторно использовать их следующим образом:
from PIL.ImageCms import buildTransform, applyTransform
SRGB_TO_LINEARIZED = buildTransform(SRGB_PROFILE, LINEARIZED_PROFILE, 'RGB', 'RGB')
LINEARIZED_TO_SRGB = buildTransform(LINEARIZED_PROFILE, SRGB_PROFILE, 'RGB', 'RGB')
im = applyTransform(im, SRGB_TO_LINEARIZED)
im = im.resize((WIDTH, HEIGHT), Image.ANTIALIAS)
im = applyTransform(im, LINEARIZED_TO_SRGB)
Я надеюсь, что это поможет, и мне было бы интересно услышать, есть ли у кого-нибудь идеи по решению проблемы с 8-битным цветовым пространством.
person
Damian Moore
schedule
06.10.2017