С sRGB-понимают изменение размера изображения в подушку


Основная подушка Image.resize функция, по-видимому, не имеет никаких опций для sRGB-aware фильтрации. Есть ли способ сделать SRGB-сознательное изменение размера в подушке?

Я мог бы сделать это вручную, преобразовав изображение в float и применив преобразование SRGB самостоятельно...но я надеюсь, что есть встроенный способ.

3 6

3 ответа:

В итоге я реализовал sRGB-aware resize, используя следующую процедуру. Он принимает 8-битное изображение RGB и целевой размер и фильтр повторной дискретизации.

from PIL import Image
import numpy as np

def SRGBResize(im, size, filter):
    # Convert to numpy array of float
    arr = np.array(im, dtype=np.float32) / 255.0
    # Convert sRGB -> linear
    arr = np.where(arr <= 0.04045, arr/12.92, ((arr+0.055)/1.055)**2.4)
    # Resize using PIL
    arrOut = np.zeros((size[1], size[0], arr.shape[2]))
    for i in range(arr.shape[2]):
        chan = Image.fromarray(arr[:,:,i])
        chan = chan.resize(size, filter)
        arrOut[:,:,i] = np.array(chan)
    # Convert linear -> sRGB
    arrOut = np.where(arrOut <= 0.0031308, 12.92*arrOut, 1.055*arrOut**(1.0/2.4) - 0.055)
    # Convert to 8-bit
    arrOut = np.uint8(np.rint(arrOut * 255.0))
    # Convert back to PIL
    return Image.fromarray(arrOut)

После долгого чтения и проб и ошибок я наткнулся на хорошее решение. Он принимает изображение sRGB, преобразует его в линейное цветовое пространство для изменения размера, а затем преобразует обратно в sRGB.

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

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 не может обойтись без него. Вы можете получить один из этого выпуска post и автор упоминает в файле "нет авторских прав, использовать свободно". Вам также понадобится профиль 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-битного цветового пространства.

99% реализаций изменения размера изображения не получат sRGB правильно (что, к сожалению, составляет 99,9% материала изображения), а те, кто это делает, обычно делают это правильно по умолчанию и дают вам возможность отказаться от gamma de/encoding.

[самоуверенный режим включен, читайте внимательно]

IOW, если нет возможности, вам, вероятно, придется добавить код самостоятельно - или просто использовать pamscale. Если библиотека не получает sRGB правильно, у нее все равно будут другие недостатки.

[самоуверенный режим выключен]

Ты можно ли де / кодировать себя, как описано в

Http://www.imagemagick.org/discourse-server/viewtopic.php?t=15955

Но с первого взгляда кажется, что подушка не способна на этот трюк.