numpy with python: convert 3d array to 2d

Question:

Say that I have a color image, and naturally this will be represented by a 3-dimensional array in python, say of shape (n x m x 3) and call it img.

I want a new 2-d array, call it “narray” to have a shape (3,nxm), such that each row of this array contains the “flattened” version of R,G,and B channel respectively. Moreover, it should have the property that I can easily reconstruct back any of the original channel by something like

narray[0,].reshape(img.shape[0:2])    #so this should reconstruct back the R channel.

The question is how can I construct the “narray” from “img”? The simple img.reshape(3,-1) does not work as the order of the elements are not desirable for me.

Thanks

Asked By: wudanao

||

Answers:

You need to use np.transpose to rearrange dimensions. Now, n x m x 3 is to be converted to 3 x (n*m), so send the last axis to the front and shift right the order of the remaining axes (0,1). Finally , reshape to have 3 rows. Thus, the implementation would be –

img.transpose(2,0,1).reshape(3,-1)

Sample run –

In [16]: img
Out[16]: 
array([[[155,  33, 129],
        [161, 218,   6]],

       [[215, 142, 235],
        [143, 249, 164]],

       [[221,  71, 229],
        [ 56,  91, 120]],

       [[236,   4, 177],
        [171, 105,  40]]])

In [17]: img.transpose(2,0,1).reshape(3,-1)
Out[17]: 
array([[155, 161, 215, 143, 221,  56, 236, 171],
       [ 33, 218, 142, 249,  71,  91,   4, 105],
       [129,   6, 235, 164, 229, 120, 177,  40]])
Answered By: Divakar

[ORIGINAL ANSWER]

Let’s say we have an array img of size m x n x 3 to transform into an array new_img of size 3 x (m*n)

Initial Solution:

new_img = img.reshape((img.shape[0]*img.shape[1]), img.shape[2])
new_img = new_img.transpose()

[EDITED ANSWER]

Flaw: The reshape starts from the first dimension and reshapes the remainder, this solution has the potential to mix the values from the third dimension. Which in the case of images could be semantically incorrect.

Adapted Solution:

# Dimensions: [m, n, 3]
new_img = new_img.transpose()
# Dimensions: [3, n, m]
new_img = img.reshape(img.shape[0], (img.shape[1]*img.shape[2]))

Strict Solution:

# Dimensions: [m, n, 3]
new_img = new_img.transpose((2, 0, 1))
# Dimensions: [3, m, n]
new_img = img.reshape(img.shape[0], (img.shape[1]*img.shape[2]))

The strict is a better way forward to account for the order of dimensions, while the results from the Adapted and Strict will be identical in terms of the values (set(new_img[0,...])), however with the order shuffled.

Answered By: o12d10

If you have the scikit module installed, then you can use the rgb2grey (or rgb2gray) to make a photo from color to gray (from 3D to 2D)

from skimage import io, color

lina_color = io.imread(path+img)
lina_gray = color.rgb2gray(lina_color)

In [33]: lina_color.shape
Out[33]: (1920, 1280, 3)

In [34]: lina_gray.shape
Out[34]: (1920, 1280)
Answered By: Harry