Scarlet
Scarlet

Reputation: 15

stack 3D images to 4D

I am trying to stack 3D images to have 4D array. I have code as:

def stack():
   x=None
   dim=(299,299)
   for file in os.listdir(path_to_folder):
        if file.endswith('.jpg'):
            img = cv2.imread(path_to_folder+ file)
            image_a = cv2.resize(img,dim, interpolation = cv2.INTER_AREA)

            img2 = cv2.imread(path_to_folder+ file)
            image_p = cv2.resize(img2,dim, interpolation = cv2.INTER_AREA)

            img3 = cv2.imread(path_to_folder+ file)
            image_n = cv2.resize(img3,dim, interpolation = cv2.INTER_AREA)

            if (x is None):
                x=[(image_a),(image_p),(image_n)]
            else:
                x[0]=np.stack((x[0], (image_a)))
                x[1]= np.stack((x[1],(image_p)))
                x[2]=np.stack((x[2],(image_n)))

    return x

I am expecting shape as:

stack=stack()
stack[0].shape
>>out: (5,299,299,3)

len(stack)
>>out: 3

but I am getting (1495,299,3). Note: for just focusing on real problem I have kept all 3 image files same. i have taken generate_triplets function from here , but in my case my images are read from folder.

Upvotes: 0

Views: 558

Answers (2)

hpaulj
hpaulj

Reputation: 231335

Modifying @Mercury's function:

In [398]: def stack(): 
     ...:     alist = [] 
     ...:     dim = (299,299) 
     ...:     for i in range(5): 
     ...:         img_a = np.random.randn(dim[0],dim[1],3) 
     ...:         img_p = np.random.randn(dim[0],dim[1],3) 
     ...:         img_n = np.random.randn(dim[0],dim[1],3) 
     ...:         alist.append([img_a, img_p, img_n]) 
     ...:     return np.array(alist) 

In [399]: stack().shape                                                                        
Out[399]: (5, 3, 299, 299, 3)

alist is a nested (5,3) list containing (299,299,3) arrays. Turned into an array it becomes 5d.

We could just transpose that, stack().transpose(1,0,2,3,4). But np.stack is a concatenate version that lets us specify a new axis:

In [400]: def stack(): 
     ...:     alist = [] 
     ...:     dim = (299,299) 
     ...:     for i in range(5): 
     ...:         img_a = np.random.randn(dim[0],dim[1],3) 
     ...:         img_p = np.random.randn(dim[0],dim[1],3) 
     ...:         img_n = np.random.randn(dim[0],dim[1],3) 
     ...:         alist.append([img_a, img_p, img_n]) 
     ...:     return np.stack(alist, axis=1) 
     ...:                                                                                      
In [401]: stack().shape                                                                        
Out[401]: (3, 5, 299, 299, 3)

Upvotes: 0

Mercury
Mercury

Reputation: 4146

There are many ways to do this, and I'll explore some of them. First of all, np.stack requires that all arrays be the same shape. You can't keep calling np.stack repeatedly like this. An easy fix is storing all images in a list, and then calling stack at the very end. Let me whip up some dummy code:

import numpy as np

def stack():
    x = [[],[],[]]
    dim = (299,299)
    for i in range(5):
        img_a = np.random.randn(dim[0],dim[1],3)
        img_p = np.random.randn(dim[0],dim[1],3)
        img_n = np.random.randn(dim[0],dim[1],3)

        x[0].append(img_a)
        x[1].append(img_p)
        x[2].append(img_n)

    x = [np.stack(im) for im in x]
    return x

stack = stack()
print(out[0].shape)

Out:

(5, 299, 299, 3)
3

If you do, however, want to stack on every iteration for some reason, you can still do it using vstack. You just have to make each 3d image a 4d image by reshaping.

import numpy as np

def stack():
    x = None
    dim = (299,299)
    for i in range(5):
        img_a = np.random.randn(dim[0],dim[1],3)
        img_p = np.random.randn(dim[0],dim[1],3)
        img_n = np.random.randn(dim[0],dim[1],3)

        if (x is None):
            x=[img_a,img_p,img_n]
        else:
            s = (-1,dim[0],dim[1],3)
            x[0]=np.vstack((x[0].reshape(s), img_a.reshape(s)))
            x[1]=np.vstack((x[1].reshape(s), img_p.reshape(s)))
            x[2]=np.vstack((x[2].reshape(s), img_n.reshape(s)))
    return x

stack = stack()
print(stack[0].shape)
print(len(stack))

Output:

(5, 299, 299, 3)
3

Upvotes: 2

Related Questions