4

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

fullStackChris
  • 1,300
  • 1
  • 12
  • 24
  • You have got me beat. I tried to play around with the images, and i get the same loss of saturation when i load your image and save it again directly with either cv2 or pyplot. In theory nothing else is done than read the images and save the same array. I will try to look at it later if i get the chance, cause this seems wierd to me. Hopefully someone else might have the answer – Alex S Jul 26 '20 at 17:35
  • @AlexS - I appreciate the effort! I may upload a few more pairs of pictures, I realized my example isn't the most blatant for showing the loss of saturation, but even in that one you can still see it :) – fullStackChris Jul 27 '20 at 09:04
  • I get the problem. How do you show the loss of saturation if the image arrays hold the same values before and after. I have been working with images in python for a while and i have not come across this problem before. It really does intreaque me – Alex S Jul 27 '20 at 09:45

2 Answers2

2

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.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
2

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.

fullStackChris
  • 1,300
  • 1
  • 12
  • 24