I have a numpy array of shape (100, 30, 3). I wanted to apply a function to transform the second dimension (N=30) based on the slice from third dimension.
For example, consider I am doing a machine learning and my shape is (Samples, 1D Pixels, Color Channels). Now I want to apply np.log on the 2nd color channel. Something like np.log(x, axis=1, slice_axis=2, slice_index=1) to apply log on (:,:,1). How?
For applying operations like np.log in-place, you can use the out parameter. For the problem you mentioned, np.log(x[:, : ,1], out=x[:, : ,1]).
Related
I have a 3D image which is a numpy array of shape (1314, 489, 3) and looks as follows:
Now I want to calculate the mean RGB color value of the mask (the cob without the black background). Calculating the RGB value for the whole image is easy:
print(np.mean(colormaskcutted, axis=(0, 1)))
>>[186.18434633 88.89164511 46.32022921]
But now I want this mean RGB color value only for the cob. I have a 1D boolean mask
array for the mask with this shape where one value corresponds to all of the 3 color channel values: (1314, 489)
I tried slicing the image array for the mask, as follows:
print(np.mean(colormaskcutted[boolean[:,:,0]], axis=(0, 1)))
>>124.57794089613752
But this returned only one value instead of 3 values for the RGB color.
How can I filter the 3D numpy image for a 1D boolean mask so that the mean RGB color calculation can be performed?
If your question is limited to computing the mean, you don't necessarily need to subset the image. You can simply do, e.g.
np.sum(colormaskcutted*boolean[:,:,None], axis = (0,1))/np.sum(boolean)
P.S. I've played around with indexing, you can amend your original approach as follows:
np.mean(colormaskcutted[boolean,:], axis = 0)
P.P.S. Can't resist some benchmarking. So, the summation approach takes 15.9s (1000 iterations, dimensions like in the example, old computer); the advanced indexing approach is slightly longer, at 17.7s. However, the summation can be optimized further. Using count_nonzero as per Mad Physicist suggestion marginally improves the time to 15.3s. We can also use tensordot to skip creating a temporary array:
np.tensordot(colormaskcutted, boolean, axes = [[0,1], [0,1]])/np.count_nonzero(msk)
This cuts the time to 4.5s.
My goal is to to turn a row vector into a column vector and vice versa. The documentation for numpy.ndarray.transpose says:
For a 1-D array, this has no effect. (To change between column and row vectors, first cast the 1-D array into a matrix object.)
However, when I try this:
my_array = np.array([1,2,3])
my_array_T = np.transpose(np.matrix(myArray))
I do get the wanted result, albeit in matrix form (matrix([[66],[640],[44]])), but I also get this warning:
PendingDeprecationWarning: the matrix subclass is not the recommended way to represent matrices or deal with linear algebra (see https://docs.scipy.org/doc/numpy/user/numpy-for-matlab-users.html). Please adjust your code to use regular ndarray.
my_array_T = np.transpose(np.matrix(my_array))
How can I properly transpose an ndarray then?
A 1D array is itself once transposed, contrary to Matlab where a 1D array doesn't exist and is at least 2D.
What you want is to reshape it:
my_array.reshape(-1, 1)
Or:
my_array.reshape(1, -1)
Depending on what kind of vector you want (column or row vector).
The -1 is a broadcast-like, using all possible elements, and the 1 creates the second required dimension.
If your array is my_array and you want to convert it to a column vector you can do:
my_array.reshape(-1, 1)
For a row vector you can use
my_array.reshape(1, -1)
Both of these can also be transposed and that would work as expected.
IIUC, use reshape
my_array.reshape(my_array.size, -1)
The problem is fairly simple. Given a 256x256 grayscale image, I want to return a color image with colors based on a threshold.
So I'm thinking:
img=whatever # 2D array of floats representing grayscale image
threshold=0.5
color1=[1.0,0.0,0.0]
color2=[0.0,0.0,1.0]
newImg=np.where(img>threshold,color1,color2)
Yet I get the infamous:
"ValueError: operands could not be broadcast together with shapes (500,500) (3,) (3,)"
Huh? I was really expecting that to give an array shaped (500,500,3). Why didn't it combine them??
You're misunderstanding how numpy.where works. It looks like you might be thinking that for True cells of img>threshold, where picks the entirety of color1 as a value, and for False cells, it picks the entirety of color2. Whatever it was you were thinking, that's not how it works.
numpy.where broadcasts the arguments together, and then for each cell of the first argument, picks the corresponding cell of either the second or third argument. To produce a shape-(500, 500, 3) result, the arguments would have to broadcast together to a shape of (500, 500, 3). Your inputs aren't broadcasting-compatible with each other at all.
One way to make the broadcasting work would be to add an extra length-1 dimension to the end of img>threshold:
newImg=np.where((img>threshold)[..., None],color1,color2)
If you're new to broadcasting, it may help to use numpy.broadcast_arrays to see what the result of broadcasting multiple arrays together looks like.
EDIT: I realize that I originally misinterpreted the original array dimensions as user2357112 pointed out.
To add an additional solution to your original problem that does not require numpy, use:
newImg = [[color1 if (cell > threshold) else color2 for cell in row] for row in img]
I have two (or sometimes more) matrixes, which I want to combine to a tensor. The matrixes e.g. have the shape (100, 400) and when they are combined, they should have the dimensions (2, 100, 400).
How do I do that? I tried it the same way I created matrixes from vectors, but that didn't work:
tensor = numpy.concatenate(list_of_matrixes, axis=0)
Probably you want
tensor = np.array(list_of_matrices)
np.array([...]) just loves to combine the inputs into a new array along a new axis. In fact it takes some effort to prevent that.:)
To use concatenate you need to add an axis to your arrays. axis=0 means 'join on the current 1st axis', so it would produce a (200,400) array.
np.concatentate([arr1[None,...], arr2[None,...], axis=0)
would do the the trick, or more generally
np.concatenate([arr[None,...] for arr in list_arr], axis=0)
If you look at the code for dstack, hstack, vstack you'll see that they do this sort of dimension adjustment before passing the task to concatenate.
The np.array solution is easy, but the concatenate solution is a good learning opportunity.
I'm trying to do this:
h = [0.2, 0.2, 0.2, 0.2, 0.2]
Y = np.convolve(Y, h, "same")
Y looks like this:
While doing this I get this error:
ValueError: object too deep for desired array
Why is this?
My guess is because somehow the convolve function does not see Y as a 1D array.
The Y array in your screenshot is not a 1D array, it's a 2D array with 300 rows and 1 column, as indicated by its shape being (300, 1).
To remove the extra dimension, you can slice the array as Y[:, 0]. To generally convert an n-dimensional array to 1D, you can use np.reshape(a, a.size).
Another option for converting a 2D array into 1D is flatten() function from numpy.ndarray module, with the difference that it makes a copy of the array.
np.convolve() takes one dimension array. You need to check the input and convert it into 1D.
You can use the np.ravel(), to convert the array to one dimension.
You could try using scipy.ndimage.convolve it allows convolution of multidimensional images. here is the docs
np.convolve needs a flattened array as one of it's inputs, you can use numpy.ndarray.flatten() which is quite fast, find it here.