Reputation: 96
I have an image of 3 channels. I have pixel values of 3 channels that if a pixel has these 3 values in its 3 channels then it belongs to class 'A'. For example
classes_channel = np.zeros((image.shape[0], image.shape[1], num_classes))
pixel_class_dict={'0': [128, 64, 128], '1': [230, 50, 140]} #num_classes=2
for channel in range(num_classes):
pixel_value= pixel_class_dict[str(channel)]
for i in range(image.shape[0]):
for j in range(image.shape[1]):
if list(image[i][j])==pixel_value:
classes_channel[i,j,channel]=1
Basically I want to generate an array of channels equal to number of classes with each class separate in a particular channel. Is there any efficient way to do this?
Upvotes: 1
Views: 1108
Reputation: 96
Found another solution: Here image is the image (with 3 channels) to which we want to
import numpy as np
import cv2
for class_id in pixel_class_dict:
class_color = np.array(pixel_class_dict[class_id])
classes_channel[:, :, int(class_id)] = cv2.inRange(image,class_color,class_color).astype('bool').astype('float32')
Upvotes: 1
Reputation: 13459
You could use numpy’s broadcasting to check more efficiently whether any value in the channels matches another value:
>>> a=np.arange(2*3).reshape(2,3)
>>> a
array([[0, 1, 2],
[3, 4, 5]])
>>> a == 4
array([[False, False, False],
[False, True, False]])
This way you can create binary masks. And those you can combine with boolean operators, like np.logical_and
and np.logical_or
:
>>> b = a == 4
>>> c = a == 0
>>> np.logical_and(b, c)
array([[False, False, False],
[False, False, False]])
>>> np.logical_or(b, c)
array([[ True, False, False],
[False, True, False]])
In your case, you could loop over the classes of pixel values, and compare the different channels:
>>> pixel_class_dict = {1: [18, 19, 20], 2: [9,10,11]}
>>> a = np.arange(2*4*3).reshape(2,4,3)
>>> b = np.zeros((a.shape[:2]), dtype=np.int)
>>> for pixel_class, pixel_values in pixel_class_dict.items():
... mask = np.logical_and(*(a[..., channel] == pixel_values[channel]
... for channel in range(a.shape[-1])))
... b += pixel_class*mask
...
>>> b
array([[0, 0, 0, 2],
[0, 0, 1, 0]])
This last part works because you can multiply a number with a boolean value (4*True == 4
and 3*False == 0
and because I'm assuming each of the pixel values in your dictionary is unique. If the latter doesn’t hold, you’ll sum up the class identifiers.
A slightly shorter approach would be to reshape the starting array:
>>> b = np.zeros((a.shape[:2]), dtype=np.int)
>>> a2 = a.reshape(-1, 3)
>>> for pixel_class, pixel_values in pixel_class_dict.items():
... mask = (np.all(a2 == pixel_values, axis=1)
... .reshape(b.shape))
... b += mask * pixel_class
...
>>> b
array([[0, 0, 0, 4],
[0, 0, 2, 0]])
Upvotes: 1