1

I have a weird question, it concerns slicing arrays and extract small thumbnail cutouts. I do have a solution, but it's a chunky for loop which runs fairly slowly on big images.

The current solution looks something like this:

import numpy as np

image = np.arange(0,10000,1).reshape(100,100) #create an image

cutouts = np.zeros((100,10,10)) #array to hold the thumbnails
l = 0

for i in range(0,10):
    for j in range(0,10): #step a (10,10) box across the image + save results
        cutouts[l,:,:] = image[(i*10):(i+1)*10, (j*10):(j+1)*10] 
        l = l+1

print(cutouts[0,:,:])

[[   0.    1.    2.    3.    4.    5.    6.    7.    8.    9.]
 [ 100.  101.  102.  103.  104.  105.  106.  107.  108.  109.]
 [ 200.  201.  202.  203.  204.  205.  206.  207.  208.  209.]
 [ 300.  301.  302.  303.  304.  305.  306.  307.  308.  309.]
 [ 400.  401.  402.  403.  404.  405.  406.  407.  408.  409.]
 [ 500.  501.  502.  503.  504.  505.  506.  507.  508.  509.]
 [ 600.  601.  602.  603.  604.  605.  606.  607.  608.  609.]
 [ 700.  701.  702.  703.  704.  705.  706.  707.  708.  709.]
 [ 800.  801.  802.  803.  804.  805.  806.  807.  808.  809.]
 [ 900.  901.  902.  903.  904.  905.  906.  907.  908.  909.]]

So, like I said, this works. But, once I get to very large images (I work in astronomy) with a couple different colour bands, it gets slow and clunky. In my dream world, I'd be able to do somethin like:

import numpy as np

image = np.arange(0,10000,1).reshape(100,100) #create an image

cutouts = image.reshape(100,10,10)

BUT, the doesn't create the right thumbnails, because it will read a whole row into the first (10,10) array, before moving onto the next one:

print(cutouts[0,:,:])

[[ 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]]

So yeah, that's the problem, am I going mad and the for loop is the best way to do it, or is there some clever way I can slice image array so that it produces the thumbnails I need.

Cheers!

AshleyNova
  • 55
  • 4
  • 1
    Is there a reason why you want to do the thumbnail creation within numpy? I'd recommend preprocessing and resizing your images with [PILLOW](https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.resize), this can also lead to more accurate thumbnails and you don't have to load a huge image into RAM each time – Taxel Aug 23 '19 at 16:42
  • Did the posted solution work for you? – Divakar Aug 26 '19 at 18:03
  • Yes, thank you! Sorry, I was away from work for the long weekend. The skimage function looks perfect. – AshleyNova Aug 28 '19 at 09:21

1 Answers1

2

Reshape to 4D, permute axes, reshape again -

H,W = 10,10 # height,width of thumbnail imgs
m,n = image.shape      
cutouts = image.reshape(m//H,H,n//W,W).swapaxes(1,2).reshape(-1,H,W)

More info on the intuition behind it.

A more compact version with scikit-image builtin : view_as_blocks -

from skimage.util.shape import view_as_blocks

cutouts = view_as_blocks(image,(H,W)).reshape(-1,H,W)

If you are okay with the intermediate 4D output, it would a view into the input image and hence virtually free on runtime. Let's verify the view-part -

In [51]: np.shares_memory(image, image.reshape(m//H,H,n//W,W))
Out[51]: True

In [52]: np.shares_memory(image, view_as_blocks(image,(H,W)))
Out[52]: True
Divakar
  • 218,885
  • 19
  • 262
  • 358