Convert pixels to cm using Python - 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.

Related

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)

PIL resizing image

image.thumbnail((128, 128), Image.ANTIALIAS)
PIL sets the height of the new image to the size given(128 here) and calculate the width to keep the aspect ratio.
Is there a way to set width to 128 and let it calculate height to keep the aspect ratio?
well if all else fails, you can always just use python directly as the calculator:
width_ratio = image.size[0]/128.0
new_height = image.size[1]/width_ratio
According to the documentation thumbnail method:
Modifies the image to contain a thumbnail version of itself, no larger than the given size.
Try setting width to 128 and using a big number (e.g. 10000) for height.

Python Image Library Image Resolution when Resizing

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)

Need to create thumbnail, how to ensure proportions and set fixed width?

I want to create a thumbnail, and the width has to be either fixed or no bigger than 200 pixels wide (the length can be anything).
The images are either .jpg or .png or .gif
I am using python.
The reason it has to be fixed is so that it fits inside a html table cell.
To keep proportions the same, you need to multiply both the width and the height by the same scaling factor. Calculate each independently to fit inside your space, then choose the smallest of the two. You say you don't care about the height, but you might want to set a bound on it anyway in case someone feeds you a really skinny image.
In the code below, I've added two additional constraints: the resulting thumbnail width or height will always be >= 1, and the scaling factor will will always be <= 1 (so that the thumbnail isn't larger than the original).
scale_x = max_width / image_width
scale_y = max_height / image_height
scale = min(scale_x, scale_y, 1)
thumb_width = max(round(image_width * scale), 1)
thumb_height = max(round(image_height * scale), 1)
Look at PyMagick, the python interface for the ImageMagick libraries. It's fairly simple to resize an image, retaining proportion, while limiting the longest side.
edit: when I say fairly simple, I mean you can describe your resize in terms of the longest acceptable values for each side, and ImageMagick will preserve the proportions automatically.
Support suggestion of using PIL. However, the calculation is actually much simpler:
from PIL import Image as PILImage
imageObj = PILImage.open(image_filename,'r')
iwidth, iheight = imageObj.size # pixels
size_proportion = iheight / iwidth # make sure your "limiter" is the denominator
newheight = size_proportion * 200
# resize the image to (newheight, 200) and save it
Alternatively, just call out to subprocess and use ImageMagic or GraphicsMagic (i use latter) These libs give you very good scaling algorithms, are written in lower level language and are very much optimized. One extra nice thing IM and GM do is mass processing of images. Another nice thing is that in some modes you don't need to give GraphicsMagic the needed size, just give maximums, and it will scale the picture down based on whichever constraint exceeds your given maximums. Check it out.

Categories