Python 使用 PIL 在中心裁剪图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16646183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Crop an image in the centre using PIL
提问by user2401069
How can I crop an image in the center? Because I know that the box is a 4-tuple defining the left, upper, right, and lower pixel coordinate but I don't know how to get these coordinates so it crops in the center.
如何在中心裁剪图像?因为我知道该框是一个定义左、上、右和下像素坐标的 4 元组,但我不知道如何获取这些坐标,因此它会在中心进行裁剪。
采纳答案by Chris Clarke
Assuming you know the size you would like to crop to (new_width X new_height):
假设您知道要裁剪到的尺寸 (new_width X new_height):
import Image
im = Image.open(<your image>)
width, height = im.size # Get dimensions
left = (width - new_width)/2
top = (height - new_height)/2
right = (width + new_width)/2
bottom = (height + new_height)/2
# Crop the center of the image
im = im.crop((left, top, right, bottom))
This will break if you attempt to crop a small image larger, but I'm going to assume you won't be trying that (Or that you can catch that case and not crop the image).
如果您尝试将小图像裁剪得更大,这会中断,但我假设您不会尝试这样做(或者您可以捕捉到这种情况而不是裁剪图像)。
回答by Dean Pospisil
One potential problem with the proposed solution is in the case there is an odd difference between the desired size, and old size. You can't have a half pixel on each side. One has to choose a side to put an extra pixel on.
所提出的解决方案的一个潜在问题是在所需大小和旧大小之间存在奇怪差异的情况下。每边不能有半个像素。必须选择一侧放置额外的像素。
If there is an odd difference for the horizontal the code below will put the extra pixel to the right, and if there is and odd difference on the vertical the extra pixel goes to the bottom.
如果水平方向有奇数差异,下面的代码会将额外的像素放在右侧,如果垂直方向有奇数差异,额外的像素会放在底部。
import numpy as np
def center_crop(img, new_width=None, new_height=None):
width = img.shape[1]
height = img.shape[0]
if new_width is None:
new_width = min(width, height)
if new_height is None:
new_height = min(width, height)
left = int(np.ceil((width - new_width) / 2))
right = width - int(np.floor((width - new_width) / 2))
top = int(np.ceil((height - new_height) / 2))
bottom = height - int(np.floor((height - new_height) / 2))
if len(img.shape) == 2:
center_cropped_img = img[top:bottom, left:right]
else:
center_cropped_img = img[top:bottom, left:right, ...]
return center_cropped_img
回答by penduDev
This is the function I was looking for:
这是我一直在寻找的功能:
from PIL import Image
im = Image.open("test.jpg")
crop_rectangle = (50, 50, 200, 200)
cropped_im = im.crop(crop_rectangle)
cropped_im.show()
Taken from another answer
取自另一个答案
回答by Mendi Barel
Crop center and around:
裁剪中心及周边:
def im_crop_around(img, xc, yc, w, h):
img_width, img_height = img.size # Get dimensions
left, right = xc - w / 2, xc + w / 2
top, bottom = yc - h / 2, yc + h / 2
left, top = round(max(0, left)), round(max(0, top))
right, bottom = round(min(img_width - 0, right)), round(min(img_height - 0, bottom))
return img.crop((left, top, right, bottom))
def im_crop_center(img, w, h):
img_width, img_height = img.size
left, right = (img_width - w) / 2, (img_width + w) / 2
top, bottom = (img_height - h) / 2, (img_height + h) / 2
left, top = round(max(0, left)), round(max(0, top))
right, bottom = round(min(img_width - 0, right)), round(min(img_height - 0, bottom))
return img.crop((left, top, right, bottom))
回答by maxalmond
I feel like the simplest solution that is most suitable for most applications is still missing. The accepted answer has an issue with uneven pixels and especially for ML algorithms, the pixel count of the cropped image is paramount.
我觉得最适合大多数应用程序的最简单的解决方案仍然缺失。公认的答案存在像素不均匀的问题,尤其是对于 ML 算法,裁剪图像的像素数至关重要。
In the following example, I would like to crop an image to 224/100, from the center. I do not care if the pixels are shifted to the left or right by 0.5, as long as the output picture will always be of the defined dimensions. It avoids the reliance on math.*.
在以下示例中,我想将图像从中心裁剪为 224/100。我不在乎像素向左还是向右移动 0.5,只要输出图片始终具有定义的尺寸即可。它避免了对数学的依赖。*。
from PIL import Image
import matplotlib.pyplot as plt
im = Image.open("test.jpg")
left = int(im.size[0]/2-224/2)
upper = int(im.size[1]/2-100/2)
right = left +224
lower = upper + 100
im_cropped = im.crop((left, upper,right,lower))
print(im_cropped.size)
plt.imshow(np.asarray(im_cropped))
The output is before cropping (not shown in code):
输出是裁剪前的(代码中未显示):
after:
后:
The touples show the dimensions.
元组显示尺寸。
回答by Andrew T
I originally used the accepted answer:
我最初使用了公认的答案:
import Image
im = Image.open(<your image>)
width, height = im.size # Get dimensions
left = (width - new_width)/2
top = (height - new_height)/2
right = (width + new_width)/2
bottom = (height + new_height)/2
# Crop the center of the image
im = im.crop((left, top, right, bottom))
But I came into the problem mentioned by Dean Pospisil
但是我遇到了 Dean Pospisil 提到的问题
One potential problem with the proposed solution is in the case there is an odd difference between the desired size, and old size. You can't have a half pixel on each side. One has to choose a side to put an extra pixel on.
所提出的解决方案的一个潜在问题是在所需大小和旧大小之间存在奇怪差异的情况下。每边不能有半个像素。必须选择一侧放置额外的像素。
Dean Pospisil's solution works, I also came up with my own calculation to fix this:
Dean Pospisil 的解决方案有效,我也想出了自己的计算来解决这个问题:
import Image
im = Image.open(<your image>)
width, height = im.size # Get dimensions
left = round((width - new_width)/2)
top = round((height - new_height)/2)
x_right = round(width - new_width) - left
x_bottom = round(height - new_height) - top
right = width - x_right
bottom = height - x_bottom
# Crop the center of the image
im = im.crop((left, top, right, bottom))
With the accepted answer, an image of 180px x 180pxto be cropped to 180px x 101pxwill result in a cropped image to 180px x 102px.
使用已接受的答案,180px x 180px要裁剪为的图像180px x 101px将导致裁剪为 的图像180px x 102px。
With my calculation, it will be correctly cropped to 180px x 101px
通过我的计算,它将被正确裁剪为 180px x 101px


