fullStackChris
fullStackChris

Reputation: 1502

Pillow script results in image losing saturation / vibrance

I have a Python script that uses Pillow to resize an image to an Instagram sized image with blurred background from the original image.

Before and after images (both JPGs):

https://app.box.com/s/jpv2mxlncp9871zvx9ygt0be4gf0zc9q

Is this simply a function of the 'after' JPG being too small to reflect all the colors in the original image? (Instagram only allows 2048x2048 images max, my original is a JPG converted from TIF from a 24.2-megapixel RAW image taken from a Nikon DSLR). Perhaps it's all in my head, but in my opinion, the 'after' image has lost some saturation / vibrance (compare the yellow buildings and car lights for example)

Has anyone experienced similar issues? Is there some default mode in Pillow that is reducing the number of colors available? I'm thinking of adding an additional saturation step to my script, but that seems like a hack.

EDIT: Added another before / after pair of images to the link above. I also realize I can easily share the script's source (GitHub repo):

https://github.com/princefishthrower/instagramize

Upvotes: 4

Views: 799

Answers (2)

fullStackChris
fullStackChris

Reputation: 1502

As Mark Setchell pointed out, it is a matter of preserving the color profile of the image, which is possible natively in Pillow, first by retrieving the profile after opening the image:

image = Image.open('mycoolimage.jpg')
iccProfile = image.info.get('icc_profile')
iccBytes = io.BytesIO(iccProfile)
originalColorProfile = ImageCms.ImageCmsProfile(iccBytes)

and when calling save with Pillow you can pass an icc_profile:

image.save('outputimagename.jpg', icc_profile=originalColorProfile.tobytes())

(Obviously, I am doing other manipulations to image in between these two steps here. Apparently one or more of them cause the icc_profile to disappear.)

This answer was also helpful in building this solution.

I added Mountains_After_NEW.jpg for those interested to see the results of these additions.

Upvotes: 2

Mark Setchell
Mark Setchell

Reputation: 207465

The difference is that the original image contains an "ICC Colour Profile" (amongst others) which are not preserved in the output image.

You can see this most easily with exiftool:

exiftool Mountains_Before.jpg | grep -i profile

Or with ImageMagick:

magick identify -verbose Mountains_Before.jpg | grep -A999 Profiles:

Output

  Profiles:
    Profile-8bim: 92 bytes
    Profile-exif: 17796 bytes
    Profile-icc: 560 bytes
    Profile-iptc: 80 bytes
      City[1,90]: 0x00000000: 254700                                        -%G
      Created Date[2,55]: 2020-7-1
      unknown[2,62]: 2020-06-30
      unknown[2,63]: 21:11:26+00:00
      unknown[2,0]: 4
      Created Time[2,60]: 20:22:05-20:22
    Profile-xmp: 9701 bytes

If you strip the profiles from the original, you will see it too, is washed out and flatter:

magick Mountains_Before.jpg -strip NoProfile.jpg

You can extract the ICC Profile and look at out like this if that sort of thing excites you:

magick Mountains_Before.jpg profile.icc

If you did that, I guess you could re-attach the profile from the BEFORE image to the AFTER image like this:

magick Mountains_After.jpg -profile profile.icc AfterWithProfile.jpg

Keywords: Image processing, ImageMagick, profile, ICC profile, saturation, saturated, desaturated, washed out.

Upvotes: 2

Related Questions