关于python:使用PIL在中心裁剪图像

Crop an image in the centre using PIL

如何在中央裁剪图像? 因为我知道该框是一个四元组,定义了左,上,右和下像素坐标,但我不知道如何获取这些坐标,因此它会在中心裁剪。


假设您知道要裁剪的大小(new_width X new_height):

1
2
3
4
5
6
7
8
9
10
11
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))

如果您尝试裁切较大的小图像,这将中断,但我将假定您不会尝试这样做(或者您可以捕获这种情况而不裁切图像)。


所提出的解决方案的一个潜在问题是在所需尺寸和旧尺寸之间存在奇数差异的情况。每边不能有半个像素。一个人必须选择一侧以放置一个额外的像素。

如果水平方向存在奇数差异,则下面的代码会将多余的像素放在右边,如果垂直方向存在奇数差异,则多余的像素会移到底部。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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


这是我一直在寻找的功能:

1
2
3
4
5
6
7
from PIL import Image
im = Image.open("test.jpg")

crop_rectangle = (50, 50, 200, 200)
cropped_im = im.crop(crop_rectangle)

cropped_im.show()

取自另一个答案


我觉得最适合大多数应用程序的最简单解决方案仍然缺失。公认的答案存在像素不均匀的问题,尤其是对于ML算法而言,裁剪图像的像素数至关重要。

在下面的示例中,我想从中心将图像裁剪为224/100。我不在乎像素是否向左或向右移动0.5,只要输出图片始终具有定义的尺寸即可。它避免了对数学的依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
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))

输出在裁剪之前(未在代码中显示):

enter image description here

后:

enter image description here

阴影显示尺寸。


可能我参加这个聚会迟到了,但至少我在这里
我想对图像进行中心裁剪将9:16图像转换为16:9肖像以横向

这是我使用的算法:

  • 将图像分成4等份
  • 丢弃第1部分和第4部分
  • 将左设置为0,右设置为图像宽度
  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    from PIL import Image

    im = Image.open('main.jpg')
    width, height = im.size

    if height > width:
        h2 = height/2
        h4 = h2/2

        border = (0, h4, width, h4*3)

        cropped_img = im.crop(border)
        cropped_img.save("test.jpg")

    之前:

    enter image description here

    后:

    enter image description here
    我希望这有帮助


    我最初使用公认的答案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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))

    但是我遇到了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的解决方案有效,我还想出了自己的解决方案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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))

    有了接受的答案,要裁剪为180px x 101px180px x 180px图像将导致裁剪为180px x 102px的图像。

    根据我的计算,它将正确裁剪为180px x 101px


    作物中心及其周围:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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))