1

Let us consider a grayscale value with values in the range of [0, 255]. How can we efficiently map each value to a RGB value?

So far, I have come up with the following implementation:

# function for colorizing a label image:
def label_img_to_color(img):
    label_to_color = {
    0: [128, 64,128],
    1: [244, 35,232],
    2: [ 70, 70, 70],
    3: [102,102,156],
    4: [190,153,153],
    5: [153,153,153],
    6: [250,170, 30],
    7: [220,220,  0],
    8: [107,142, 35],
    9: [152,251,152],
    10: [ 70,130,180],
    11: [220, 20, 60],
    12: [255,  0,  0],
    13: [  0,  0,142],
    14: [  0,  0, 70],
    15: [  0, 60,100],
    16: [  0, 80,100],
    17: [  0,  0,230],
    18: [119, 11, 32],
    19: [81,  0, 81]
    }

img_height, img_width = img.shape

img_color = np.zeros((img_height, img_width, 3))
for row in range(img_height):
    for col in range(img_width):
        label = img[row, col]
        img_color[row, col] = np.array(label_to_color[label])
return img_color

However, as you can see it is not efficient as there are two "for" loops.

This question was also asked in Convert grayscale value to RGB representation?, but no efficient implementation was suggested.

Majid Azimi
  • 907
  • 1
  • 11
  • 29
  • Having two for loops is not inefficient. It is logically impossible to index over a two-dimensional data structure without having two for loops. What is inefficient is converting each label_to_color list into a np.array *inside* the for loops. Why not initialize your `label_to_color` list with np.array objects (instead of Python lists) in the `label_img_to_color` function? – Paul Cornelius May 07 '18 at 23:25
  • actually it turned out there is an efficient way to do that. Please check out the accepted answer. – Majid Azimi May 08 '18 at 23:11
  • Actually, I believe the code I provided in the answer implements some kind of double for loop on a lower level. However, for loops in python are highly inefficient compared to using numpy boolean indexing. – MattSt May 31 '18 at 10:29

2 Answers2

3

A more efficient way of doing that instead of a double for loop over all pixels could be:

rgb_img = np.zeros((*img.shape, 3)) 
for key in label_to_color.keys():
    rgb_img[img == key] = label_to_color[key]
MattSt
  • 1,024
  • 2
  • 16
  • 35
  • the color map is fixed, so using a colormap from OpenCV is not the solution. Your solution converts a grayscale image to RGB. There is no conversion of pixel values according to label_to_color table. – Majid Azimi May 08 '18 at 00:39
  • I edited my answer, let me know if this answers your question – MattSt May 08 '18 at 07:45
  • 1
    Wow! Thanks a lot. You made my day. It is super fast. Only Python complained about *img.shape saying it is a syntax error so I used img_height, img_width = img.shape rgb_img = np.zeros((img_height, img_width, 3)) instead. – Majid Azimi May 08 '18 at 23:10
0

I wrote nearly the same question, and during question review I found @MattSt's answer. For posterity, here is the question I was about to ask:

How to convert a grayscale image to RGB one, given a pixel mapping function using NumPy?

I have a dictionary which maps labels to colors. But I don't know how to efficiently convert a 2D label map to 2D color image, using the provided mapping. This works:

label_to_color = {0: [0, 0, 0], 1: [255, 0, 0], 2: [0, 0, 255], 3: [0, 128, 0]}

def label_map_to_color(label_map):
    color_map = np.empty(
        (label_map.shape[0], label_map.shape[1], 3), dtype=np.uint8
    )
    for k in range(label_map.shape[0]):
        for i in range(label_map.shape[1]):
            color_map[k, i, :] = label_to_color[(label_map[k, i])]
    return color_map

But there must be a more efficient way to accomplish this?

Dženan
  • 3,329
  • 3
  • 31
  • 44