crop center portion of a numpy image

社会主义新天地 提交于 2019-11-27 02:34:53

问题


Let's say I have a numpy image of some width x and height y. I have to crop the center portion of the image to width cropx and height cropy. Let's assume that cropx and cropy are positive non zero integers and less than the respective image size. What's the best way to apply the slicing for the output image?


回答1:


Something along these lines -

def crop_center(img,cropx,cropy):
    y,x = img.shape
    startx = x//2-(cropx//2)
    starty = y//2-(cropy//2)    
    return img[starty:starty+cropy,startx:startx+cropx]

Sample run -

In [45]: img
Out[45]: 
array([[88, 93, 42, 25, 36, 14, 59, 46, 77, 13, 52, 58],
       [43, 47, 40, 48, 23, 74, 12, 33, 58, 93, 87, 87],
       [54, 75, 79, 21, 15, 44, 51, 68, 28, 94, 78, 48],
       [57, 46, 14, 98, 43, 76, 86, 56, 86, 88, 96, 49],
       [52, 83, 13, 18, 40, 33, 11, 87, 38, 74, 23, 88],
       [81, 28, 86, 89, 16, 28, 66, 67, 80, 23, 95, 98],
       [46, 30, 18, 31, 73, 15, 90, 77, 71, 57, 61, 78],
       [33, 58, 20, 11, 80, 25, 96, 80, 27, 40, 66, 92],
       [13, 59, 77, 53, 91, 16, 47, 79, 33, 78, 25, 66],
       [22, 80, 40, 24, 17, 85, 20, 70, 81, 68, 50, 80]])

In [46]: crop_center(img,4,6)
Out[46]: 
array([[15, 44, 51, 68],
       [43, 76, 86, 56],
       [40, 33, 11, 87],
       [16, 28, 66, 67],
       [73, 15, 90, 77],
       [80, 25, 96, 80]])



回答2:


A more general solution based on @Divakar 's answer:

def cropND(img, bounding):
    start = tuple(map(lambda a, da: a//2-da//2, img.shape, bounding))
    end = tuple(map(operator.add, start, bounding))
    slices = tuple(map(slice, start, end))
    return img[slices]

and if we have an array a

>>> a = np.arange(100).reshape((10,10))

array([[ 0,  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, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
       [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])

We can clip it with cropND(a, (5,5)), you will get:

>>> cropND(a, (5,5))

array([[33, 34, 35, 36, 37],
       [43, 44, 45, 46, 47],
       [53, 54, 55, 56, 57],
       [63, 64, 65, 66, 67],
       [73, 74, 75, 76, 77]])

It not only works with 2D image but also 3D image.

Have a nice day.




回答3:


Thanks, Divakar.

Your answer got me going the right direction. I came up with this using negative slice offsets to count 'from the end':

def cropimread(crop, xcrop, ycrop, fn):
    "Function to crop center of an image file"
    img_pre= msc.imread(fn)
    if crop:
        ysize, xsize, chan = img_pre.shape
        xoff = (xsize - xcrop) // 2
        yoff = (ysize - ycrop) // 2
        img= img_pre[yoff:-yoff,xoff:-xoff]
    else:
        img= img_pre
    return img



回答4:


A simple modification from @Divakar 's answer that preserves the image channel:

    def crop_center(self, img, cropx, cropy):
       _, y, x = img.shape
       startx = x // 2 - (cropx // 2)
       starty = y // 2 - (cropy // 2)
       return img[:, starty:starty + cropy, startx:startx + cropx]


来源:https://stackoverflow.com/questions/39382412/crop-center-portion-of-a-numpy-image

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!