I already have an array with shape (1, 224, 224), a single channel image. I want to change that to (1, 1, 224, 224). I have been trying
newarr.shape
#(1,224,224)
arr = np.array([])
np.append(arr, newarr, 1)
I always get this
IndexError: axis 1 out of bounds [0, 1). If i remove the axis as 0 , then the array gets flattened . What am I doing wrong ?
A dimension of 1 is arbitrary, so it sounds like you want to simply reshape the array. This can accomplished by:
newarr.shape = (1, 1, 244, 244)
or
newarr = newarr[None]
The only way to do an insert into a higher dimensional array is
bigger_arr = np.zeros((1, 1, 224, 224))
bigger_arr[0,...] = arr
In other words, make a target array of the right size, and assign values.
np.append is a booby trap. Avoid it.
Occasionally that's a useful way of thinking of this. But it's simpler, and quicker, to think of this as a reshape problem.
bigger_arr = arr.reshape(1,1,224,224)
bigger_arr = arr[np.newaxis,...]
arr.shape = (1,1,224,224) # a picky inplace change
bigger_arr = np.expand_dims(arr, 0)
This last one does
a.reshape(shape[:axis] + (1,) + a.shape[axis:])
which gives an idea of how to deal with dimensions programmatically.
Related
I created an array with size (256, 144, 3).
empty_windows = np.empty((256, 144, 3))
Then I want to append new elements into the array with:
for i in range(256):
for j in range(144):
empty_windows[i, j] = np.append(empty_windows[i, j], np.asarray(some_new_array)).reshape(3, )
But it doesnt work as I get the error msg:
ValueError: cannot reshape array of size 6 into shape (3,)
Is there a way of doing it? Thank you.
I hope, it will help you understanding concatenate 3dim array
import numpy as np
empty_windows = np.empty((256, 144, 3))
random_arr = np.random.randint(0, 100, size=(256, 144, 3)) # it's dimension should be same
np.concatenate([empty_windows, random_arr], axis=2) # it can concatenate into an array axis=2 defines 3rd dimension
np.empty and np.append are dangerous functions to use. They are not clones of the the empty list [] and list.append.
empty_windows = np.empty((256, 144, 3))
has made a (256,144,3) shape array with float values - they are unpredictable, but more than likely not what you want. Look at that array, or a smaller example to see for yourself. Also read, and if necessary reread, the np.empty docs. np.zeros is safer.
With scalar i,j,
empty_windows[i, j]
is a (3,) shape array, or slot.
When you np.append it with another (3,) shape, the result is a (6,) shape, with the first 3 value being those "random" values originally in empty_window. The error tells you quite clearly that it can't put a (6,) shape array into a slot that only holds (3,).
Your goal isn't clear, but you can't grow a (n,m,3) shape array to (n,m,6) by doing this kind of "row" by "row" append.
You can set the "row" with new values, as in:
empty_windows[i, j] = np.asarray(some_new_array)).reshape(3, )
At the moment I'm trying to np.ravel() my images so I can use np.append() freely, instead of using np.vstack() which many people here say it's not very fast given the loading/unloading things in memory and I worry it might slow my code down.
My idea was to just flatten the images, append them all and then use np.reshape(appended_images, [512,512,3,-1]) to create the tensor. The tensor is created all right, but upon checkup, the images aren't getting displayed, probably because one of these operations is not working the way I think it should be working.
Checking the final array im_stacked[:,:,:,0] with matplotlib returns a blank image, with a warning of values out of range. Upon inspection of only one channel of the image im_stacked[:,:,0,0] I'm faced with this:
This is just the image repeated over and over. Where is my mistake? Why is there some swapping occurring? Reshaping a single raveled image works fine.
Edit: Minimal code added
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
#Image Loading, please use a 512x512x3 image
path = "./path/to/image.png"
im = cv.imread(path)
#Flattening the image
im_raveled = np.ravel(im)
#Starting with an empty array
im_stacked = np.array([])
#For the sake of simplicity this code is just repeated three times
im_stacked = np.append(im_stacked, im_raveled)
im_stacked = np.append(im_stacked, im_raveled)
im_stacked = np.append(im_stacked, im_raveled)
#Using a 515x512x3 image, reshaping the stacked array
im_reshaped = np.reshape(im_stacked, [512,512,3,-1])
#Plotting the images after reshaping
plt.figure()
plt.subplot(1,2,1)
#Plot only the first channel of the first image
plt.imshow(im_reshaped[:,:,0,0])
plt.subplot(1,2,2)
#Plot all channels of the first image
plt.imshow(im_reshaped[:,:,:,0])
plt.show()
Make a sample 3d array:
In [25]: image = np.random.randint(0,256,(512,512,3))
The best way:
In [26]: alist = []
In [27]: for i in range(5):
...: alist.append(image)
...:
It's easy to make an array from such list:
In [28]: np.array(alist).shape
Out[28]: (5, 512, 512, 3)
If you must join them on a new last dimension, use np.stack:
In [29]: np.stack(alist,-1).shape
Out[29]: (512, 512, 3, 5)
np.stack, np.vstack, and even np.append are all covers for np.concatenate. I hate np.append, since it leads too many naive users up the wrong path. It is not an list append clone.
If you must use repeated concatenates do something like:
In [30]: arr = np.zeros((0,512,512,3),image.dtype)
In [31]: arr = np.concatenate([arr,image], axis=0)
Traceback (most recent call last):
File "<ipython-input-31-1fc945fd1c90>", line 1, in <module>
arr = np.concatenate([arr,image], axis=0)
File "<__array_function__ internals>", line 5, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 4 dimension(s) and the array at index 1 has 3 dimension(s)
oops, even with experience I have troubles getting that started.
In [32]: arr = np.concatenate([arr,image[None,...]], axis=0)
In [33]: arr.shape
Out[33]: (1, 512, 512, 3)
In [34]: arr = np.concatenate([arr,image[None,...]], axis=0)
In [35]: arr.shape
Out[35]: (2, 512, 512, 3)
Repeated concatenate is slow. concatenate takes a whole list of arrays, and should be used as such. Don't try to replicate list code in lists!
List append is easy because there's an obvious "empty" list, and you can efficiently add references to it. Arrays don't have an equivalent "empty" array. Dimensions matter, right from the start. I had to start with a (0,512,512,3) shape. If you don't know the needed dimensions, then don't take this approach.
As for your title question, this might work:
im_reshaped = np.reshape(im_stacked, [-1,512,512,3])
With the repeated np.append, you joined the ravelled arrays end to end, [(786432,),(786432,),(786432,),...]. Effectively the new dimension is a leading one, not a trailing one. It's a crude way of performing the list append and array build that I started with.
Instead of a n-dimentional array, let's take a 3D array to illustrate my question :
>>> import numpy as np
>>> arr = np.ones(24).reshape(2, 3, 4)
So I have an array of shape (2, 3, 4). I would like to concatenate/fuse the 2nd and 3rd axis together to get an array of the shape (2, 12).
Wrongly, thought I could have done it easily with np.concatenate :
>>> np.concatenate(arr, axis=1).shape
(3, 8)
I found a way to do it by a combination of np.rollaxis and np.concatenate but it is increasingly ugly as the array goes up in dimension:
>>> np.rollaxis(np.concatenate(np.rollaxis(arr, 0, 3), axis=0), 0, 2).shape
(2, 12)
Is there any simple way to accomplish this? It seems very trivial, so there must exist some function, but I cannot seem to find it.
EDIT : Indeed I could use np.reshape, which means to compute the dimensions of the axis first. Is it possible without accessing/computing the shape beforehand?
On recent python versions you can do:
anew = a.reshape(*a.shape[:k], -1, *a.shape[k+2:])
I recommend against directly assigning to .shape since it doesn't work on sufficiently noncontiguous arrays.
Let's say that you have n dimensions in your array and that you want to fuse adjacent axis i and i+1:
shape = a.shape
new_shape = list(shape[:i]) + [-1] + list(shape[i+2:])
a.shape = new_shape
I am analyzing some image represented datasets using keras. I am stuck that I have two different dimensions of images. Please see the snapshot. Features has 14637 images having dimension (10,10,3) and features2 has dimension (10,10,100)
Is there any way that I can merge/concatenate these two data together.?
If features and features2 contain the features of the same batch of images, that is features[i] is the same image of features2[i] for each i, then it would make sense to group the features in a single array using the numpy function concatenate():
newArray = np.concatenate((features, features2), axis=3)
Where 3 is the axis along which the arrays will be concatenated. In this case, you'll end up with a new array having dimension (14637, 10, 10, 103).
However, if they refer to completely different batches of images and you would like to merge them on the first axis such that the 14637 images of features2 are placed after the first 14637 image, then, there no way you can end up with an array, since numpy array are structured as matrix, non as a list of objects.
For instance, if you try to execute:
> a = np.array([[0, 1, 2]]) // shape = (1, 3)
> b = np.array([[0, 1]]) // shape = (1, 2)
> c = np.concatenate((a, b), axis=0)
Then, you'll get:
ValueError: all the input array dimensions except for the concatenation axis must match exactly
since you are concatenating along axis = 0 but axis 1's dimensions differ.
If dealing with numpy arrays, you should be able to use concatenate method and specify the axis, along which the data should be merged. Basically: np.concatenate((array_a, array_b), axis=2)
I think it would be better if you use class.
class your_class:
array_1 = []
array_2 = []
final_array = []
for x in range(len(your_previous_one_array)):
temp_class = your_class
temp_class.array_1 = your_previous_one_array
temp_class.array_2 = your_previous_two_array
final_array.append(temp_class)
I am writing a program that is suppose to be able to import numpy arrays of some higher dimension, e.g. something like an array a:
a = numpy.zeros([3,5,7,2])
Further, each dimension will correspond to some physical dimension, e.g. frequency, distance, ... and I will also import arrays with information about these dimensions, e.g. for a above:
freq = [1,2,3]
time = [0,1,2,3,4,5,6]
distance = [0,0,0,4,1]
angle = [0,180]
Clearly from this example and the signature it can be figured out that freq belong to dimension 0, time to dimension 2 and so on. But since this is not known in advance, I can take a frequency slice like
a_f1 = a[1,:,:,:]
since I do not know which dimension the frequency is indexed.
So, what I would like is to have some way to chose which dimension to index with an index; in some Python'ish code something like
a_f1 = a.get_slice([0,], [[1],])
This is suppose to return the slice with index 1 from dimension 0 and the full other dimensions.
Doing
a_p = a[0, 1:, ::2, :-1]
would then correspond to something like
a_p = a.get_slice([0, 1, 2, 3], [[0,], [1,2,3,4], [0,2,4,6], [0,]])
You can fairly easily construct a tuple of indices, using slice objects where needed, and then use this to index into your array. The basic is recipe is this:
indices = {
0: # put here whatever you want to get on dimension 0,
1: # put here whatever you want to get on dimension 1,
# leave out whatever dimensions you want to get all of
}
ix = [indices.get(dim, slice(None)) for dim in range(arr.ndim)]
arr[ix]
Here I have done it with a dictionary since I think that makes it easier to see which dimension goes with which indexer.
So with your example data:
x = np.zeros([3,5,7,2])
We do this:
indices = {0: 1}
ix = [indices.get(dim, slice(None)) for dim in range(x.ndim)]
>>> x[ix].shape
(5L, 7L, 2L)
Because your array is all zeros, I'm just showing the shape of the result to indicate that it is what we want. (Even if it weren't all zeros, it's hard to read a 3D array in text form.)
For your second example:
indices = {
0: 0,
1: slice(1, None),
2: slice(None, None, 2),
3: slice(None, -1)
}
ix = [indices.get(dim, slice(None)) for dim in range(x.ndim)]
>>> x[ix].shape
(4L, 4L, 1L)
You can see that the shape corresponds to the number of values in your a_p example. One thing to note is that the first dimension is gone, since you only specified one value for that index. The last dimension still exists, but with a length of one, because you specified a slice that happens to just get one element. (This is the same reason that some_list[0] gives you a single value, but some_list[:1] gives you a one-element list.)
You can use advanced indexing to achieve this.
The index for each dimension needs to be shaped appropriately so that the indices will broadcast correctly across the array. For example, the index for the first dimension of a 3-d array needs to be shaped (x, 1, 1) so that it will broadcast across the first dimension. The index for the second dimension of a 3-d array needs to be shaped (1, y, 1) so that it will broadcast across the second dimension.
import numpy as np
a = np.zeros([3,5,7,2])
b = a[0, 1:, ::2, :-1]
indices = [[0,], [1,2,3,4], [0,2,4,6], [0,]]
def get_aslice(a, indices):
n_dim_ = len(indices)
index_array = [np.array(thing) for thing in indices]
idx = []
# reshape the arrays by adding single-dimensional entries
# based on the position in the index array
for d, thing in enumerate(index_array):
shape = [1] * n_dim_
shape[d] = thing.shape[0]
#print(d, shape)
idx.append(thing.reshape(shape))
c = a[idx]
# to remove leading single-dimensional entries from the shape
#while c.shape[0] == 1:
# c = np.squeeze(c, 0)
# To remove all single-dimensional entries from the shape
#c = np.squeeze(c).shape
return c
For a as an input, it returns an array with shape (1,4,4,1) your a_p example has a shape of (4,4,1). If the extra dimensions need to be removed un-comment the np.squeeze lines in the function.
Now I feel silly. While reading the docs slower I noticed numpy has an indexing routine that does what you want - numpy.ix_
>>> a = numpy.zeros([3,5,7,2])
>>> indices = [[0,], [1,2,3,4], [0,2,4,6], [0,]]
>>> index_arrays = np.ix_(*indices)
>>> a_p = a[index_arrays]
>>> a_p.shape
(1, 4, 4, 1)
>>> a_p = np.squeeze(a_p)
>>> a_p.shape
(4, 4)
>>>