I am cropping an image using python PIL. Say my image is as such:
This is the simple code snippet I use for cropping:
from PIL import Image im = Image.open(image) cropped_image = im.crop((topLeft_x, topLeft_y, bottomRight_x, bottomRight_y)) cropped_image.save("Out.jpg")
The result of this is:
I want to scale out this cropped image keeping the aspect ratio (proportionate width and height) same by say 20% to look something like this without exceeding the image dimensions.
How should I scale out the crop such that the aspect ratio is maintained while not exceeding the image boundary/ dimensions?
Advertisement
Answer
You should calculate the center of your crop and use it there on. As an example:
crop_width = right - left crop_height = bottom - top crop_center_x = int(left + crop_width/2) crop_center_y = (top + crop_height/2)
In this way you will obtain the (x,y) point which corresponds to the center of your crop w.r.t your original image. In that case, you will know that the maximum width for your crop would be the minimum between the center value and the outer bounds of the original image minus the center itself:
im = Image.open("brad.jpg") l = 200 t = 200 r = 300 b = 300 cropped = im.crop((l, t, r, b))
Which gives you:
If you want to “enlarge” it to the maximum starting from the same center, then you will have:
max_width = min(crop_center_x, im.size[0]-crop_center_x) max_height = min(crop_center_y, im.size[1]-crop_center_y) new_l = crop_center_x - max_width new_t = crop_center_x - max_height new_r = crop_center_x + max_width new_b = crop_center_x + max_height new_crop = im.crop((new_l, new_t, new_r, new_b))
which gives as a result, having the same center:
Edit
If you want to keep the aspect ratio you should retrieve it (the ratio) before and apply the crop only if the resulting size would still fit the original image. As an example, if you want to enlarge it by 20%:
ratio = crop_height/crop_width scale = 20/100 new_width = int(crop_width + (crop_width*scale)) # Here we are using the previously calculated value for max_width to # determine if the new one would be too large. # Note that the width that we calculated here (new_width) refers to both # sides of the crop, while the max_width calculated previously refers to # one side only; same for height. Sorry for the confusion. if max_width < new_width/2: new_width = int(2*max_width) new_height = int(new_width*ratio) # Do the same for the height, update width if necessary if max_height < new_height/2: new_height = int(2*max_height) new_width = int(new_height/ratio) adjusted_scale = (new_width - crop_width)/crop_width if adjusted_scale != scale: print("Scale adjusted to: {:.2f}".format(adjusted_scale)) new_l = int(crop_center_x - new_width/2) new_r = int(crop_center_x + new_width/2) new_t = int(crop_center_y - new_height/2) new_b = int(crop_center_y + new_height/2)
Once you have the width and height values the process to get the crop is the same as above.