rolling stone
rolling stone

Reputation: 13016

PIL: scale image while maintaing highest possible quality

I'm using PIL to scale images that range anywhere from 600px wide to 2400px wide down to around 200px wide. I've already incorporated Image.ANTIALIAS and set quality=95 to try and get the highest quality image possible.

However the scaled down images still have pretty poor quality compared to the originals.

Here's the code that I'm using:

# Open the original image
fp = urllib.urlopen(image_path)
img = cStringIO.StringIO(fp.read())
im = Image.open(img)
im = im.convert('RGB')

# Resize the image
resized_image = ImageOps.fit(im, size, Image.ANTIALIAS) 

# Save the image
resized_image_object = cStringIO.StringIO()
resized_image.save(resized_image_object, image_type, quality=95)

What's the best way to scale an image along these ratios while preserving as much of the image quality as possible?

I should note that my primary goal is get the maximum quality image possible. I'm not really concerned with how efficient the process is time wise.

Upvotes: 2

Views: 3173

Answers (2)

Ryan G
Ryan G

Reputation: 9560

Try a different approach. I'm not sure if this will help, but I did something similar a while back: https://stackoverflow.com/a/13211834/1339024

It may be that the original image on the urlpath is not that great quality to begin with. But if you want, try my script. I made it to shrink images in a given directory, but this portion could be of use:

parentDir = "Some\\Path"
width = 200
height = 200
cdpi = 75
cquality = 95
a = Image.open(parentDir+'\\'+imgfile) # Change this to your url type
iw,ih = a.size
if iw > width or ih > height:
    pcw = width/float(iw)
    pch = height/float(ih)
    if pcw <= pch:
        LPC = pcw
    else:
        LPC = pch
    if 'gif' in imgfile:
        a = a.convert("RGB")#,dither=Image.NONE)
        a = a.resize((int(iw*LPC),int(ih*LPC)),Image.ANTIALIAS)
        a = a.convert("P", dither=Image.NONE, palette=Image.ADAPTIVE)
        a.save(outputDir+"\\"+imgfile,dpi=(cdpi,cdpi), quality=cquality)
    else:
        a = a.resize((int(iw*LPC),int(ih*LPC)),Image.ANTIALIAS)
        a.save(outputDir+"\\"+imgfile,dpi=(cdpi,cdpi), quality=cquality)

Upvotes: 1

Eyrofire
Eyrofire

Reputation: 310

If you can't get results with the native resize options in PIL, you can manually calculate the resize pixel values by running them through your own resizing function. There are three main algorithms (that I know of) for resizing images:

  • Nearest Neighbor
  • Bilinear Interpolation
  • Bicubic Interpolation

The last one will produce the highest quality image at the longest calculation time. To do this, imagine the pixel layout of the the smaller image, then scale it up to match the larger image and think about where the new pixel locations would be over the old ones. Then for each new pixel take the average value of the 16 nearest pixels (4x4 radius around it) and use that as its new value.

The resulting values for each of the pixels in the small image will be a smooth but clear resized version of the large image.

For further reading look here: Wikipedia - Bicubic interpolation

Upvotes: 2

Related Questions