What is the correct way to change image channel ordering between channels first and channels last?
Asked Answered
M

6

62

I can not for the life of me figure out how to switch the image ordering. images are read in (x,x,3) format, theano requires it to be in (3,x,x) format. I tried changing the order with numpy.array([img[:,:,i] for i in range(3)])

which i guess gets the job done, but it is both ugly and i can't figure out how to reverse it to get the original image back.

Mcspadden answered 7/5, 2017 at 9:5 Comment(3)
Try img.transpose(2,0,1) or img.transpose(2,1,0).Donnelly
If you use torchvision, you can also use torchvision.transforms.ToTensor()(img). It will do that automatically for you.Backswept
But be aware that torchvision.transforms.ToTensor()(img) scales your images, and sometimes you don't want that.Laminar
B
65

I agree with @Qualia 's comment, np.moveaxis(a, source, destination) is easier to understand. This does the job:

x = np.zeros((12, 12, 3))
x.shape
#yields: 
(12, 12, 3)

x = np.moveaxis(x, -1, 0)
x.shape
#yields: 
(3, 12, 12)
Broomrape answered 7/6, 2018 at 23:44 Comment(0)
S
32

To reorder data

You can use numpy.rollaxis to roll the axis 3 to position 1 (considering you have the batch size as dimension 0).

np.rollaxis(imagesArray, 3, 1)  

But, if you're using keras, you might want to change its configuration or define it per layer. Theano doesn't require anything from you if you're using Keras.

Keras can be configured with channels first or channels last, besides allowing you to define it in every individual layer, so you don't have to change your data.

To configure keras

Find the keras.json file and change it. The file is usually installed in C:\Users\yourusername\.keras or ~/.keras depending on your OS.

Change "image_data_format": "channels_last" to "channels_first" or vice-versa, as you wish.

Usually, working with "channels_last" is less troublesome because of a great amount of other (non convolutional) functions that work only on the last axis.

Defining channel order in layers.

The Keras documentation has all information about parameters for layers, including the data_format parameter.

Sotted answered 7/5, 2017 at 16:9 Comment(1)
I find np.moveaxis more intuitive for this purpose.Singularity
T
21

If you're looking at the fastest option, go for .transpose(...). It's even faster than np.einsum.

img = np.random.random((1000, 1000, 3))
img.shape
# (1000, 1000, 3)

%timeit img.transpose(2, 0, 1)
# 385 ns ± 1.11 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit np.rollaxis(img, -1, 0)
# 2.7 µs ± 50.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit np.einsum('ijk->kij', img)
# 2.75 µs ± 31.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit np.moveaxis(img, -1, 0)
# 7.26 µs ± 57.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

np.allclose(img.transpose(2, 0, 1), np.einsum('ijk->kij', img))
# True
np.allclose(img.transpose(2, 0, 1), np.moveaxis(img, -1, 0))
# True
np.allclose(img.transpose(2, 0, 1), np.rollaxis(img,-1, 0))
# True
Ticon answered 16/6, 2020 at 20:41 Comment(0)
H
11

Using np.moveaxis is effective, but I have found that np.einsum is much faster.

x = np.zeros((12,12,3))
%timeit np.moveaxis(x,-1,0)
#yields 7.46 µs ± 312 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit np.einsum('ijk->kij',x)
#yields 1.11 µs ± 31 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Hatshepsut answered 10/1, 2020 at 21:45 Comment(0)
G
1
x = np.zeros((12, 12, 3))
y = np.rollaxis(x, 2, 0)
y.shape

(3, 12, 12)
Grote answered 8/1, 2019 at 19:28 Comment(0)
P
0

You can also use torch.permute in PyTorch:

x = torch.randn(2, 3, 5)
x.size()
torch.Size([2, 3, 5])
torch.permute(x, (2, 0, 1)).size()
torch.Size([5, 2, 3])
Pack answered 16/6, 2022 at 3:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.