python 使用PIL在中间裁剪图像

7vhp5slm  于 2023-02-15  发布在  Python
关注(0)|答案(8)|浏览(217)

我怎么能在中间裁剪一个图像呢?因为我知道这个长方体是一个4元组,定义了左,上,右,下像素坐标,但是我不知道怎么得到这些坐标,所以它在中间裁剪。

slsn1g29

slsn1g291#

假设您知道要裁剪到的大小(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))

如果您试图将一个小图像裁剪得更大,这将中断,但我将假设您不会尝试(或者您可以捕获这种情况,而不裁剪图像)。

wf82jlnq

wf82jlnq2#

所提出的解决方案的一个潜在问题是,在所需尺寸和旧尺寸之间存在奇怪的差异的情况下,你不能在每一边都有半个像素,你必须选择一边来放置额外的像素。
如果在水平方向上有一个奇数差,下面的代码将把额外的像素放在右边,如果在垂直方向上有一个奇数差,额外的像素放在底部。

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
hs1ihplo

hs1ihplo3#

我觉得最适合大多数应用程序的最简单的解决方案仍然缺失。公认的答案有一个像素不均匀的问题,尤其是对于ML算法,裁剪图像的像素数是至关重要的。
在下面的例子中,我想将一幅图像从中心裁剪为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))

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

之后:

图中显示了尺寸。

but5z9lq

but5z9lq4#

这是我一直在寻找的函数:

from PIL import Image
im = Image.open("test.jpg")

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

cropped_im.show()

取自another answer

quhf5bfb

quhf5bfb5#

我最初使用的是公认的答案:

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的解决方案有效,我也提出了自己的计算来解决这个问题:

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

j9per5c4

j9per5c46#

裁剪中心和周围:

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

ckocjqey7#

可能是我迟到了这个党,但至少我在这里,我想中心作物的图像转换9:16图像到16:9人像景观
这是我使用的算法:
1.将图像分成4等份
1.放弃第1部分和第4部分
1.向左设置为0,向右设置为图像宽度
代码:

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")
    • 之前:**

    • 之后:**


我希望这能有所帮助

isr3a4wc

isr3a4wc8#

您可以使用Torchvision's CenterCrop转换来实现此目的。

from PIL import Image
from torchvision.transforms import functional as F

crop_size = 256  # can be either an integer or a tuple of ints for (height, width) separately
img = Image.open(<path_to_your_image>)
cropped_img = F.center_crop(img, crop_size)

F.center_croptorch.Tensor s或PIL.Image s一起工作,并保留数据类型,即当输入为PIL.Image时,输出也为(裁剪的)PIL.Image。额外的好处是,如果输入图像大小小于请求的裁剪大小,上述转换将自动应用填充。

相关问题