SRGB-aware image resize in Pillow

后端 未结 3 1802
庸人自扰
庸人自扰 2021-02-15 14:06

Pillow\'s basic Image.resize function doesn\'t appear to have any options for SRGB-aware filtering. Is there a way to do SRGB-aware resizing in Pillow?

I could do it ma

3条回答
  •  野趣味
    野趣味 (楼主)
    2021-02-15 14:45

    After a lot of reading and trial and error I have stumbled upon a good solution. It assumes an sRGB image, converts it to linear colour space to do the resizing, then converts back to sRGB.

    There is a slight downside in that a colour depth of 8 bits per pixel is used even when the image is in it's linear form. This results in a loss of variance in darker regions. Reading from this issue post it seems there is no way to convert to a higher depth using Pillow unfortunately.

    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)
    

    You'll need a linearised ICC colour profile as Pillow/lcms can't do it without. You can get one from this issue post and the author mentions in the file "no copyright, use freely". You'll also need an sRGB profile which should be easily obtainable from your OS or online.

    Much of the processing time is taken up computing the transformations from sRGB and back again. If you are going to be doing a lot of these operations you can store these transformations to re-use them like so:

    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)
    

    I hope this helps and I'd be interested to hear if anyone has any ideas on resolving the 8 bit colour space issue.

提交回复
热议问题