Numpy flatten dimension function

Viewed 360

I am new to Python and am trying to extract RGB-encoded pixel labels from a numpy array. For example:

image.shape
>> (256, 256, 3)

to be converted to:

image.shape
>> (256, 256, 1)

based on a custom function. In Javascript such a function would be (the exact RGB encoding is, of course, irrelevant - but being able to use a custom function is relevant):

RGBtoVal = ([r,g,b])=>{
   r = Math.floor(r*9/255);
   g = Math.floor(g*9/255);
   b = Math.floor(b*9/255);
   if (r>0) return r+18;
   if (g>0) return r+9;
   return b;
}

I understand that reshape and squeeze are helpful in reducing the dimensionality but without a function. Also, is a numpy matrix of shape (256,256,1) the same as (256,256)?

2 Answers

In numpy you can work with vectors and you don't have to work with every pixel separatelly.

In examples I use image 4x4 with values (1,1,1)

import numpy as np

image = np.ones([4,4,3])  # image 4x4 with RGB (3 values)

print(image.shape) # (4, 4, 3)

R = image[:,:,0]  # all R values
G = image[:,:,1]  # all G values
B = image[:,:,2]  # all B values

print(R.shape) # (4, 4)
print(G.shape) # (4, 4)
print(B.shape) # (4, 4)

R = R * 9/255
G = R * 9/255
B = B * 9/255

R[ R > 0 ] += 18
G[ G > 0 ] += 9

print(R)
print(G)
print(B)

print(image)

or you can even use * 9/255 before you split to R,G,B

import numpy as np

image = np.ones([4,4,3])

print(image.shape)

image = image * 9/255

R = image[:,:,0]
G = image[:,:,1]
B = image[:,:,2]

R[ R > 0 ] += 18
G[ G > 0 ] += 9

print(R)
print(G)
print(B)

print(image)

If you want to do this in more traditional way then use numpy.apply_along_axis(func, axis, arr) with axis 2

import numpy as np

# --- fuctions ---

def function(rgb):
    #rgb = rgb * 9/255
    r, g, b = rgb

    r = r * 9/255
    g = g * 9/255
    b = b * 9/255

    if r > 0:
        r += 18
    if g > 0 :
        g += 9 

    return [r,g,b]

# --- main ---

image = np.ones([4,4,3])

print(image.shape)

image = np.apply_along_axis(function, 2, image)

print(image[:,:,0])  # R
print(image[:,:,1])  # G
print(image[:,:,2])  # B

print(image)

being able to use a custom function is relevant

Converting a three-channel image into a single-channel image through a function is straightforward. For example:

In [96]: import numpy as np

In [97]: from skimage import data

In [98]: image = data.astronaut()

In [99]: def f(img):
    ...:     r, g, b = map(np.transpose, img.T)
    ...:     return np.floor(r*9/255) + np.sqrt(g) + np.cos(b)

In [100]: x = f(image)

In [101]: image.shape
Out[101]: (512, 512, 3)

In [102]: x.shape
Out[102]: (512, 512)

is a numpy matrix of shape (256,256,1) the same as (256,256)?

No. They are arrays of different shapes.

In [103]: y = x[:, :, None]

In [104]: y.shape
Out[104]: (512, 512, 1)

In [105]: x[0, 0]    
Out[105]: 13.1044921875

In [106]: y[0, 0]
Out[106]: array([13.10449219])

In [107]: y[0, 0, 0]
Out[107]: 13.1044921875

The content of x and y is the same but x is two-dimensional whereas y is three-dimensional. It is worth noticing that indexing a three-dimensional array with just two indices yields a one-dimensional array of one element rather than a float value.

Related