10

I am trying to crop a numpy array [width x height x color] to a predefined smaller dimension.

I found something that should do what I want but it works only for [width x height] arrays. I don't know how to make it work for a numpy array that has an extra dimension for color.

crop center portion of a numpy image

Vic
  • 825
  • 2
  • 8
  • 12

3 Answers3

11

With numpy you can use range indexes. Say you have a list x[] (single dimension), you can index it as x[start:end] this is called a slice.

Slices can be used with higher dimensions too like

x[start1:end1, start2:end2, start3:end3]

This might be what you are looking for.

Although remember this doesn't generate a new array (ie it doesn't copy). Changes to this will reflect into x.

Thanks to @coderforlife for pointing out the error in the wrong notation I had put down before.

Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
  • 1
    This doesn't actually slice the higher dimensions, only the first dimension is sliced multiple times. `x[start1:end1, start2:end2, start3:end3]` would slice multiple dimensions. – coderforlife Jul 03 '19 at 04:29
  • 1
    @coderforlife You are absolutely correct! It's funny how I missed it. Thanks for pointing it out. I will correct it right away. – Ajay Brahmakshatriya Jul 03 '19 at 05:51
  • 2
    As of today, the changes do not get reflected in to the same array and a new array is returned (python3). – progyammer Jun 10 '20 at 06:33
  • this doesn't actually *center* crop the array – Edgar Mar 14 '21 at 22:08
7

From the question you linked to, it's just a small change in the code:

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

All that was added was another : to the end of the last line, and an (unused) c to the shape unpacking.

>>> img
array([[[ 18,   1,  17],
        [  1,  13,   3],
        [  2,  17,   2],
        [  5,   9,   3],
        [  0,   6,   0]],

       [[  1,   4,  11],
        [  7,   9,  24],
        [  5,   1,   5],
        [  7,   3,   0],
        [116,   1,  55]],

       [[  1,   4,   0],
        [  1,   1,   3],
        [  2,  11,   4],
        [ 20,   3,  33],
        [  2,   7,  10]],

       [[  3,   3,   6],
        [ 47,   5,   3],
        [  4,   0,  10],
        [  2,   1,  35],
        [  6,   0,   1]],

       [[  2,   9,   0],
        [ 17,  13,   4],
        [  3,   0,   1],
        [ 16,   1,   3],
        [ 19,   4,   0]],

       [[  8,  19,   3],
        [  9,  16,   7],
        [  0,  12,   2],
        [  4,  68,  10],
        [  4,  11,   1]],

       [[  0,   1,  14],
        [  0,   0,   4],
        [ 13,   1,   4],
        [ 11,  17,   5],
        [  7,   0,   0]]])
>>> crop_center(img,3,3)
array([[[ 1,  1,  3],
        [ 2, 11,  4],
        [20,  3, 33]],

       [[47,  5,  3],
        [ 4,  0, 10],
        [ 2,  1, 35]],

       [[17, 13,  4],
        [ 3,  0,  1],
        [16,  1,  3]]])
zbw
  • 922
  • 5
  • 13
1

numpy works for any dimensions

import numpy as np
X = np.random.normal(0.1, 1., [10,10,10])
X1 = X[2:5, 2:5, 2:5]
print(X1.shape)

last print statements results in a [3,3,3] array.

narasimman
  • 421
  • 3
  • 14