Crop an image in the centre using PIL

后端 未结 7 1233
闹比i
闹比i 2021-01-31 03:41

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 co

相关标签:
7条回答
  • 2021-01-31 04:12

    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.

    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.*.

    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.

    0 讨论(0)
  • 2021-01-31 04:13

    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
    
    0 讨论(0)
  • 2021-01-31 04:16

    May be i am late to this party but at least i am here I want to center crop the image convert 9:16 image to 16:9 portrait to landscape

    This is the algo i used :

    1. divide image in 4 equal parts
    2. discard part 1 and part four
    3. Set left to 0, right to width of image

    code :

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

    before :

    after:

    I hope this helps

    0 讨论(0)
  • 2021-01-31 04:17

    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

    0 讨论(0)
  • 2021-01-31 04:24

    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

    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:

    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 180px to be cropped to 180px x 101px will result in a cropped image to 180px x 102px.

    With my calculation, it will be correctly cropped to 180px x 101px

    0 讨论(0)
  • 2021-01-31 04:30

    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))
    
    0 讨论(0)
提交回复
热议问题