How to add dimension to array to create an image in Python - python

I have converted an image into a 2-dim Array to make some analysis:
im=imageio.imread(file)
im2D=im[:,:,0]
Now I need an efficient way to turn over this step. For the moment I'm doing this with 2 for-loops but I think this is really inefficient:
NewImage=np.zeros((len(im2D),len(im2D[0]),3,dtype=int)
for x in range(len(im2D)):
for y in range(len(im2D[0])):
NewImage[x][y]=[im2D[x][y],im2D[y][y],im2D[x][y]]
NewImage=NewImage.astype(np.uint8)
Example:
imageio gives me something like this:
im=Array([[[255,255,255,255],
...
[255,255,255,255]],
[ 0, 0, 0, 0],
...
[255,255,255,255]]],dtype=uint8)
and im[:,:,0] gives me something like this:
im2D=Array([[255,...,255],
...
[ 0,...,255]],dtype=uint8)

Assuming that I understand your question correctly and your goal is to add a dimension (an additional axis) to your existing array in which you repeat the existing data three times.
Then you could use one of the following ways:
# the 2d array
arr = np.ones((5,5))
# a manually way to stack the array 3 times along a new axis
arr3d1 = np.array([arr for i in range(3)])
# even more manually (without stacked loops though)
# useful if you want to change the content eg:
arr3d2 = np.array([arr, 1/arr, 2*arr])
# use numpy's tile
arr_h=arr[None,:,:] # first prepend a new singular axis
arr3d3 = np.tile(arr_h, (3,1,1)) # repeat 3 times along first axis and keep other axes

I think I have already found a solution to avoid the for-loops:
D3->D2:
im=imageio.imread(file)
im2D=im[:,:,0]
2D->D3:
NewImage=np.zeros((len(im2D),len(im2D[0]),3,dtype=int)
NewImage[:,:,0]=im2D
NewImage[:,:,1]=im2D
NewImage[:,:,2]=im2D

Related

Merge one tensor into other tensor on specific indexes in PyTorch

Any efficient way to merge one tensor to another in Pytorch, but on specific indexes.
Here is my full problem.
I have a list of indexes of a tensor in below code xy is the original tensor.
I need to preserve the rows (those rows who are in indexes list) of xy and apply some function on elements other than those indexes (For simplicity let say the function is 'multiply them with two),
xy = torch.rand(100,4)
indexes=[1,2,55,44,66,99,3,65,47,88,99,0]
Then merge them back into the original tensor.
This is what I have done so far:
I create a mask tensor
indexes=[1,2,55,44,66,99,3,65,47,88,99,0]
xy = torch.rand(100,4)
mask=[]
for i in range(0,xy.shape[0]):
if i in indexes:
mask.append(False)
else:
mask.append(True)
print(mask)
import numpy as np
target_mask = torch.from_numpy(np.array(mask, dtype=bool))
print(target_mask.sum()) #output is 89 as these are element other than preserved.
Apply the function on masked rows
zy = xy[target_mask]
print(zy)
zy=zy*2
print(zy)
Code above is working fine and posted here to clarify the problem
Now I want to merge tensor zy into xy on specified index saved in the list indexes.
Here is the pseudocode I made, as one can see it is too complex and need 3 for loops to complete the task. and it will be too much resources wastage.
# pseudocode
for masked_row in indexes:
for xy_rows_index in xy:
if xy_rows_index= masked_row
pass
else:
take zy tensor row and replace here #another loop to read zy.
But I am not sure what is an efficient way to merge them, as I don't want to use NumPy or for loop etc. It will make the process slow, as the original tensor is too big and I am going to use GPU.
Any efficient way in Pytorch for this?
Once you have your mask you can assign updated values in place.
zy = 2 * xy[target_mask]
xy[target_mask] = zy
As for acquiring the mask I don't see a problem necessarily with your approach, though using the built-in set operations would probably be more efficient. This also gives an index tensor instead of a mask, which, depending on the number of indices being updated, may be more efficient.
i = list(set(range(len(xy)))-set(indexes))
zy = 2 * xy[i]
xy[i] = zy
Edit:
To address the comment, specifically to find the complement of indices of i we can do
i_complement = list(set(range(len(xy)))-set(i))
However, assuming indexes contains only values between 0 and len(xy)-1 then we could equivalently use i_complement = len(set(indexes)), which just removes the repeated values in indexes.

How do you print out elements from a Numpy array on new lines using a for loop?

Create an array with numpy and add elements to it. After you do this, print out all its elements on new lines.
I used the reshape function instead of a for loop. However, I know this would create problems in the long run if I changed my array values.
import numpy as np
a = np.array([0,5,69,5,1])
print(a.reshape(5,1))
How can I make this better? I think a for loop would be best in the long run but how would I implement it?
Some options to print an array "vertically" are:
print(a.reshape(-1, 1)) - You can pass -1 as one dimension,
meaning "expand this dimension to the needed extent".
print(np.expand_dims(a, axis=1)) - Add an extra dimension, at the second place,
so that each row will have a single item. Then print.
print(a[:, None]) - Yet another way of reshaping the array.
Or if you want to print just elements of a 1-D array in a column,
without any surrounding brackets, run just:
for x in a:
print(x)
You could do this:
print(a.reshape([a.shape[0], 1]))
This will work regardless of how many numbers are in your numpy array.
Alternatively, you could also do this:
[print(number) for number in a.tolist()]

Adding a 2D Array to a 3D Array

Im struggling a little with stacking two matrices on top of each other. I'm using the pyKalman package, which when updated, returns a tuple of matrices. One with an updated estimate (new_pred a 1 x 2 vector) and the corresponding covariance matrix (new_cov a 2 x 2 matrix).
After the update, I want to stack the returned values to their corresponding outputs, for a recursive smoothing of the data, through these estimates.
The following is how it is currently implemented.
for meas in onlineObservations:
(new_pred, new_cov) = kf.filter_update(states_pred[-1], cov_pred[-1], meas)
states_pred = np.vstack((states_pred, new_pred))
cov_pred = np.stack((cov_pred, new_cov), axis=0)
Which works really well for the updated estimate (the 1x2 vector), but fails when i try to add new_cov to the array called cov_pred. For good measure:
states_pred.shape = (900,2)
cov_pred.shape = (900, 2, 2)
I've tried changing the axis of "stack" to no avail. It's probably something elementary, but i've been struggling with it for the past hour, and cannot seem to find a "simple" solution.
Thanks in advance.
This should work -
cov_pred = []
for meas in onlineObservations:
(new_pred, new_cov) = kf.filter_update(states_pred[-1], cov_pred[-1], meas)
states_pred = np.vstack((states_pred, new_pred))
cov_pred.append[new_cov]
cov_pred = np.stack(cov_pred, axis=0)
But since you want to update array which you are using already in code, you should use np.concatenate
for meas in onlineObservations:
(new_pred, new_cov) = kf.filter_update(states_pred[-1], cov_pred[-1], meas)
states_pred = np.vstack((states_pred, new_pred))
cov_pred = np.concatenate((cov_pred, np.reshape(new_cov, (1,2,2))), axis=0)
I've been able to make it work by converting cov_pred to a list, and then use:
cov_pred.append(new_cov)
And then re-convert it back again after the for loop. But it seems tedious - at least if there's an even better way!
You can keep your code inside a For Loop (While Loop will also do) and use 'Auto-index Enabled' and thats it....
At the output of Loop, LabVIEW will create a 3D data exactly as your requirement.

Numpy combine all nonzero elements of one array in to another

In Numpy I have two three dimensional arrays representing images. I'm trying to create an overlay of the second image on to first so I'd like to replace all of the elements in the first array with respective elements from the second array but only when they aren't zero. Is there any easy way to do this?
This seems like a perfect use-case for np.where ...
new_arr = np.where(second == 0, first, second)
I've done the replacement out-of-place (creating a new array rather than modifying the original), but that's usually OK...
You can simply do:
zeros_idx = array2 != 0
array1[zeros_idx] = array2[zeros_idx]
Modifying the original using numpy.nonzero. Similar to answer provided by #Holt .
m = numpy.nonzero(array2)
array1[m] = array2[m]

Assume zero for subsequent dimensions when slicing an array

I have need to slice an array where I would like zero to be assumed for every dimension except the first.
Given an array:
x = numpy.zeros((3,3,3))
I would like the following behavior, but without needing to know the number of dimensions before hand:
y = a[:,0,0]
Essentially I am looking for something that would take the place of Ellipsis, but instead of expanding to the needed number of : objects, it would expand into the needed number of zeros.
Is there anything built in for this? If not, what is the best way to get the functionality that I need?
Edit:
One way to do this is to use:
y = x.ravel(0:temp.shape[0])
This works fine, however in some cases (such as mine) ravel will need to create a copy of the array instead of a view. Since I am working with large arrays, I want a more memory efficient way of doing this.
You could create a indexing tuple, like this:
x = arange(3*3*3).reshape(3,3,3)
s = (slice(None),) + (0,)*(x.ndim-1)
print x[s] # array([ 0, 9, 18])
print x[:,0,0] # array([ 0, 9, 18])
I guess you could also do:
x.transpose().flat[:3]
but I prefer the first approach, since it works for any dimension (rather than only the first), and it's obviously equally efficient to just writing x[:,0,0], since it's just a different syntax.
I usually use tom10's method, but here's another:
for i in range(x.ndim-1):
x = x[...,0]

Categories

Resources