【问题标题】:Scale and crop an image in python PIL without exceeding the image dimensions在 python PIL 中缩放和裁剪图像而不超出图像尺寸
【发布时间】:2019-10-13 09:03:19
【问题描述】:

我正在使用 python PIL 裁剪图像。说我的形象是这样的:

这是我用于裁剪的简单代码 sn-p:

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

这样的结果是:

我想在不超过图像尺寸的情况下,将这个裁剪后的图像按比例缩小,保持纵横比(比例宽度和高度)相同 20%,使其看起来像这样。

我应该如何扩大裁剪,以便在不超过图像边界/尺寸的情况下保持纵横比?

【问题讨论】:

  • 您实际上并没有裁剪然后缩放裁剪的部分。真的,你正在收获更大的作物,不是吗?
  • 尝试计算作物的宽度和高度,以及 x,y 中心。使用新裁剪,中心将相同,但宽度和高度将分别增加 20%,即 newwidth = 1.2 * oldwidth。

标签: python python-imaging-library crop image-scaling


【解决方案1】:

你应该计算你的作物的中心并在那里使用它。 举个例子:

crop_width = right - left
crop_height = bottom - top
crop_center_x = int(left + crop_width/2)
crop_center_y = (top + crop_height/2)

通过这种方式,您将获得与原始图像相对应的裁剪中心的 (x,y) 点。 在这种情况下,您将知道裁剪的最大宽度将是中心值与原始图像的外部边界之间的最小值减去中心本身:

im = Image.open("brad.jpg")
l = 200
t = 200
r = 300
b = 300
cropped = im.crop((l, t, r, b))

这给了你:

如果您想从同一个中心开始将其“放大”到最大,那么您将拥有:

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

因此,具有相同的中心:


编辑

如果您想保持纵横比,您应该在之前检索它(比率)并仅在结果尺寸仍适合原始图像时应用裁剪。例如,如果您想将其放大 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)

一旦获得宽度和高度值,获取裁剪的过程与上述相同。

【讨论】:

  • 这是一个不错的方法,但是当它扩大时,它会在超出图像的区域添加一个黑色补丁。您可以在此处查看我对您的方法的实现(请参阅crop_face 函数):pastebin.com/FYfs20Ba 和裁剪后的图像:ibb.co/8jwnrPP。正如您将看到的,裁剪和缩放在顶部添加了一个黑色补丁。我们如何避免这种情况?一种明显的方法是减少缩放,但我想聪明地做到这一点。仅当裁剪后的图像比例超过原始图像尺寸时,我才想减小缩放比例。
  • 当然,我的错。首先,检查应该在crop_center_x + new_width/2(高度也是)上进行,并且new_l 和new_r 需要更新为+- new_width/2。更重要的是,应该进行另一项检查,以便 new_height/2
  • @FlyingAura 我已经更新了代码,现在应该可以使用了。请注意 max_widthnew_width 之间的区别:前者是指最大宽度 PER 边,而后者是指全局作物的新宽度
  • max_width = min(x, im.size[0]-x),这里x是什么,和crop_center_x 一样吗?另外,我们在哪里使用adjusted_scale
  • 我已根据您的回答对代码进行了更改,但结果仍然相同:pastebin.com/WuEPQjbZ 我错过了什么?能否请您发布代码 sn-p?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-18
  • 1970-01-01
  • 1970-01-01
  • 2021-07-25
  • 2012-07-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多