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