Python Image Library Image Resolution when Resizing - python

I am trying to shrink some jpeg images from 24X36 inches to 11X16.5 inches using the python image library. Since PIL deals in pixels this should mean scaling from 7200X 4800 pixels to 3300 X2200 pixels, with my resolution set at 200 pixels/inch, however when I run my script PIL changes the resolution to 72 pixels/inch and I end up with a larger image than i had before.
import Image
im = Image.open("image.jpg")
if im.size == (7200, 4800):
out = im.resize((3300,2200), Image.ANTIALIAS)
elif im.size == (4800,7200):
out = im.resize((2200,3300), Image.ANTIALIAS)
out.show()
Is there a way to mantain my image resolution when I'm resizing my images?
thanks for any help!

To preserve the DPI, you need to specify it when saving; the info attribute is not always preserved across image manipulations:
dpi = im.info['dpi'] # Warning, throws KeyError if no DPI was set to begin with
# resize, etc.
out.save("out.jpg", dpi=dpi)

Related

Convert pixels to cm using Python

I would like to know what am I doing wrong with this code :
if self.digital:
im = Image.open(os.path.join(folder, filename))
width, height = im.size
image_info["width"] = round(width / 37.79527559055, 0)
I would like to use this code to convert the pixel size of a picture into centimeters, but I don't understand why it returns me this issue :
Python311\Lib\site-packages\PIL\Image.py:3167: DecompressionBombWarning: Image size (130437549 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack.
I don't want to use DPI, in my script 1cm = 37.79527559055 pixels.
I'm going to use a temporary list to write pixels value in then convert but I would like to know if there is a faster way or not, and why exactly is it making a zip bomb.
Thanks !
The issue is that the image you are trying to open is too large and its decompression would consume a lot of memory, which can be a potential security risk (known as "Decompression bomb"). To avoid this, you can increase the maximum size limit of the image in PIL by modifying the Image.MAX_IMAGE_PIXELS attribute:
Image.MAX_IMAGE_PIXELS = None # No Limit
It is important to consider the memory usage and performance of your script when using large images.
Regarding the conversion of pixels to centimeters, using a fixed number of pixels per centimeter is not the recommended approach as it depends on the display resolution and the physical size of the display. Instead, you should use the DPI (dots per inch) information embedded in the image file to perform the conversion. You can retrieve the DPI information using the 'info' attribute of the Image object and then use it to calculate the size in centimeters.
Here is an example of how you could do the conversion with DPI information:
from PIL import Image
im = Image.open(os.path.join(folder, filename))
width, height = im.size
dpi = im.info.get("dpi", (72, 72))
width_cm = width / dpi[0] * 2.54
height_cm = height / dpi[1] * 2.54
image_info["width_cm"] = width_cm
image_info["height_cm"] = height_cm
You can resize the image to a smaller size before processing it. You can use the Image.thumbnail() method provided by PIL to resize the image.

python how to resize(shrink) image without losing quality

I want to resize png picture 476x402 to 439x371, and I used resize method of PIL(image) or opencv, however, it will loss some sharp. After resize, The picture becomes blurred.
How to resize(shrink) image without losing sharpness with use python?
from skimage import transform, data, io
from PIL import Image
import os
import cv2
infile = 'D:/files/script/org/test.png'
outfile = 'D:/files/script/out/test.png'
''' PIL'''
def fixed_size1(width, height):
im = Image.open(infile)
out = im.resize((width, height),Image.ANTIALIAS)
out.save(outfile)
''' open cv'''
def fixed_size2(width, height):
img_array = cv2.imread(infile)
new_array = cv2.resize(img_array, (width, height), interpolation=cv2.INTER_CUBIC)
cv2.imwrite(outfile, new_array)
def fixed_size3(width, height):
img = io.imread(infile)
dst = transform.resize(img, (439, 371))
io.imsave(outfile, dst)
fixed_size2(371, 439)
src:476x402
resized:439x371
How can you pack 2000 pixels into a box that only holds 1800? You can't.
Putting the same amount of information (stored as pixels in your source image) into a smaller pixelarea only works by
throwing away pixels (i.e. discarding single values or by cropping an image which is not what you want to do)
blending neighbouring pixels into some kind of weighted average and replace say 476 pixels with slightly altered 439 pixels
That is exactly what happens when resizing images. Some kind of algorithm (interpolation=cv2.INTER_CUBIC, others here) tweaks the pixel values to merge/average them so you do not loose too much of information.
You can try to change the algorithm or you can apply further postprocessing ("sharpening") to enrich the contrasts again.
Upon storing the image, certain formats do "lossy" storage to minimize file size (JPG) others are lossless (PNG, TIFF, JPG2000, ...) which further might blur your image if you choose a lossy image format.
See
Shrink/resize an image without interpolation
How can I sharpen an image in OpenCV?

Resizing JPG using PIL.resize gives a completely black image

I'm using PIL to resize a JPG. I'm expecting the same image, resized as output, but instead I get a correctly sized black box. The new image file is completely devoid of any information, just an empty file. Here is an excerpt for my script:
basewidth = 300
img = Image.open(path_to_image)
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize))
img.save(dir + "/the_image.jpg")
I've tried resizing with Image.LANCZOS as the second argument, (defaults to Image.NEAREST with 1 argument), but it didn't make a difference. I'm running Python3 on Ubunutu 16.04. Any ideas on why the image file is empty?
I also encountered the same issue when trying to resize an image with transparent background. The "resize" works after I add a white background to the image.
Code to add a white background then resize the image:
from PIL import Image
im = Image.open("path/to/img")
if im.mode == 'RGBA':
alpha = im.split()[3]
bgmask = alpha.point(lambda x: 255-x)
im = im.convert('RGB')
im.paste((255,255,255), None, bgmask)
im = im.resize((new_width, new_height), Image.ANTIALIAS)
ref:
Other's code for making thumbnail
Python: Image resizing: keep proportion - add white background
The simplest way to get to the bottom of this is to post your image! Failing that, we can check the various aspects of your image.
So, import Numpy and PIL, open your image and convert it to a Numpy ndarray, you can then inspect its characteristics:
import numpy as np
from PIL import Image
# Open image
img = Image.open('unhappy.jpg')
# Convert to Numpy Array
n = np.array(img)
Now you can print and inspect the following things:
n.shape # we are expecting something like (1580, 1725, 3)
n.dtype # we expect dtype('uint8')
n.max() # if there's white in the image, we expect 255
n.min() # if there's black in the image, we expect 0
n.mean() # we expect some value between 50-200 for most images

My method doesn't resize the width and the height of images it just resize the size

My method doesn't resize the width and the height of the image it just resize the size of it.
I used a python library which is PIL.
import PIL
from PIL import Image
def resizeImg(img):
mywidth = 320
wpercent = (mywidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((mywidth,hsize), PIL.Image.ANTIALIAS)
return img
The image was in 1MB now it's just 130KB, is that normal? I was expecting to get different width and height.
Yeah this looks normal.
What you're doing is that you are actually resampling the image.
If your input image as a horizontal pixel size superior to 320 pixels, you are effectively reducing the definition (number of pixels) hence the inferior file size.
If you don't want to change the definition but only want to change the printing/display size for example you might consider scaling the dpi.
This can be be done when saving by doing something like this :
img.save(filepath, format=fmt, dpi=(dpi, dpi))
You have to calculate the horizontal and vertical dpi value as desired.
This won't change the file size.

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.
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
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)

Categories