Python: extract a 2D array from a 3D array - python

I have a 3D numpy array (1L, 420L, 580L) the 2nd and 3rd dimension is a gray scale image that I want to display using openCV. How do I pull the 2D array from the 3D array?
I created a short routine to do this, but I bet there is a better way.
# helper function to remove 1st dimension
def pull_image(in_array):
rows = in_array.shape[1] # vertical
cols = in_array.shape[2] # horizontal
out_array = np.zeros((rows, cols), np.uint8) # create new array to hold image data
for r in xrange(rows):
for c in xrange(cols):
out_array[r, c] = in_array[:, r, c]
return out_array

If you always only have the first dimension == 1, then you could simply reshape the array...
if in_array.shape[0] == 1:
return in_array.reshape(in_array.shape[1:])
otherwise, you can use numpy's advanced list slicing...
else:
return in_array[0,:,:]

Related

How to do indexing with ndarray to mask index in numpy?

I have a 4d array to mask and a 2d array to mask index.
i should masking ndarray data using 2d array indices and i dont want to using for-loop.
how should i do?
for example,
mask_arr = np.random.rand(5,10,100)
idx_arr = np.random.randint(10, size=(5,5))
and my masking code like this using for-loop
mask_val = 0
for i in range(5):
mask_arr[i, idx_arr[i],:] = mask_val

Reshape tensor to matrix and back

I have 2 methods: One to convert 4D matrix (tensor) in a matrix and other to convert 2D matrix in 4D.
Reshaping from 4D to 2D work's well, but when I try reconvert again in a tensor, I don't achieve the same order of the elements. The methods are:
# Method to convert the tensor in a matrix
def tensor2matrix(tensor):
# rows, columns, channels and filters
r, c, ch, f = tensor[0].shape
new_dim = [r*c*ch, f] # Inferer the new matrix dims
# Transpose is necesary because the columns are the channels weights
# flattened in columns
return np.reshape(np.transpose(tensor[0], [2,0,1,3]), new_dim)
# Method to convert the matrix in a tensor
def matrix2tensor(matrix, fs):
return np.reshape(matrix, fs, order="F")
I think that the problem is in the np.transpose because when is a matrix only I can permute columns by rows... Is there anyway to back the tensor from the matrix without loops?
Consider the following changes:
Replace the two tensor[0] by tensor, to avoid
ValueError: not enough values to unpack (expected 4, got 3)
when running the example provided below
Ensure both np.reshape calls use the same order="F"
Use another np.transpose call inside matrix2tensor to undo the np.transpose from tensor2matrix
The updated code is
import numpy as np
# Method to convert the tensor in a matrix
def tensor2matrix(tensor):
# rows, columns, channels and filters
r, c, ch, f = tensor.shape
new_dim = [r*c*ch, f] # Inferer the new matrix dims
# Transpose is necesary because the columns are the channels weights
# flattened in columns
return np.reshape(np.transpose(tensor, [2,0,1,3]), new_dim, order="F")
# Method to convert the matrix in a tensor
def matrix2tensor(matrix, fs):
return np.transpose(np.reshape(matrix, fs, order="F"), [1,2,0,3])
and it can be tested like this:
x,y,z,t = 2,3,4,5
shape = (x,y,z,t)
m1 = np.arange(x*y*z*t).reshape((x*y*z, 5))
t1 = matrix2tensor(m1, shape)
m2 = tensor2matrix(t1)
assert (m1 == m2).all()
t2 = matrix2tensor(m2, shape)
assert (t1 == t2).all()

How to quickly mask different slices in my array?

I have a 3d array where all axis lengths are the same (for example (5,5,5)). I need to mask all of the array and keep certain slices in the array unmasked as per the code below. I managed to accomplish this using a for loop but I wondered if there was a faster solution out there.
array = np.reshape(np.array(np.random.rand(125)), (5,5,5))
array = ma.array(array, mask=True)
for i in range(array.shape[0]):
for j in range(array.shape[1]):
array[i, j, :].mask[i:j] = False
This allows me to sum this array with another array of the same size while ignoring the masked values.
You can create the entire mask in one step using broadcasting:
i, j, k = np.ogrid[:5, :5, :5]
mask = (i>k) | (k>=j)

Fastest way to crop a 3D array inside a 3D array with Python

I have a 3D array and a list of 3D indexes. My aim is to isolate a small 3D volume of a specific size (3x3x3 or 5x5x5 or whatever) for every index (with the index lying in the middle of the volume).
At the moment, I do this:
1) Group five 2D arrays (with the interested one in the middle, following the indexes). So having a 5xNxN array.
2) For a 5x5x5 volume, for each 2D array (0,N,N; 1,N,N..etc) of my 5xNxN array, I crop a 5x5 array around the same index.
3) Stack these five 5x5 2D arrays to obtain my small 3D volume.
Is there a fastest way to do this job?
Here an explanatory code:
arr = np.zeros((7,7,7)) #Just a 3D array
ind = [3, 3, 3] #My index
for el in range(arr.shape[0]):
if el==ind[0]:
group = arr[el-2:el+3] #it isolates a 3D volume with arr[ind[0]] in the middle
volume_3d = []
for i in group:
volume_2d = i[ind[1]-2:ind[1]+3, ind[2]-2:ind[2]+3]
volume_3d.append (volume_2d) #it builds the 3D volume
Thanks
Numpy supports slicing like this quite easily:
dim = 5
x = dim // 2
i,j,k = ind
volume_3d = arr[i-x:i+(dim-x), j-x:j+(dim-x), k-x:k+(dim-x)].copy()
# Your implementation.
dim = 5
x = dim // 2
arr = np.random.randn(7, 7, 7)
el = ind[0]
group = arr[el-x:el+(dim-x)]
volume_3d = []
for i in group:
volume_2d = i[ind[1]-x:ind[1]+(dim-x), ind[2]-x:ind[2]+(dim-x)]
volume_3d.append (volume_2d)
# Proposed in this post.
i,j,k = ind
volume_3d_2 = arr[i-x:i+(dim-x), j-x:j+(dim-x), k-x:k+(dim-x)]
print(np.array_equal(volume_3d, volume_3d_2))
True

Transform 1-D numpy array into 3D RGB array

What is the best way to transform an 1D array that contains rgb data into a 3D RGB array ?
If the array was in this order, it would be easy, (a single reshape)
RGB RGB RGB RGB...
However my array is in the form,
RRRR...GGGG....BBBB
or sometimes even,
GGGG....RRRR....BBBB (result still should be RGB not GRB)
I could of course derive some Python way to achieve this, I even did try a numpy solution, it works but It is obviously a bad solution, I wonder what is the best way, maybe a built-in numpy function ?
My solution:
for i in range(len(video_string) // 921600 - 1): # Consecutive frames iterated over.
frame = video_string[921600 * i: 921600 * (i + 1)] # One frame
array = numpy.fromstring(frame, dtype=numpy.uint8) # Numpy array from one frame.
r = array[:307200].reshape(480, 640)
g = array[307200:614400].reshape(480, 640)
b = array[614400:].reshape(480, 640)
rgb = numpy.dstack((b, r, g)) # Bring them together as 3rd dimention
Don't let the for loop confuse you, I just have frames concatenated to each other in a string, like a video, which is not a part of the question.
What did not help me: In this question, r, g, b values are already 2d arrays so not helping my situation.
Edit1: Desired array shape is 640 x 480 x 3
Reshape to 2D, transpose and then reshape back to 3D for RRRR...GGGG....BBBB form -
a1D.reshape(3,-1).T.reshape(height,-1,3) # assuming height is given
Or use reshape with Fortran order and then swap axes -
a1D.reshape(-1,height,3,order='F').swapaxes(0,1)
Sample run -
In [146]: np.random.seed(0)
In [147]: a = np.random.randint(11,99,(4,2,3)) # original rgb image
In [148]: a1D = np.ravel([a[...,0].ravel(), a[...,1].ravel(), a[...,2].ravel()])
In [149]: height = 4
In [150]: np.allclose(a, a1D.reshape(3,-1).T.reshape(height,-1,3))
Out[150]: True
In [151]: np.allclose(a, a1D.reshape(-1,height,3,order='F').swapaxes(0,1))
Out[151]: True
For GGGG....RRRR....BBBB form, simply append : [...,[1,0,2]].

Categories