2

I have been given a segmentation mask: a HxW numpy array in which each location represents a pixel. The value at each location is not RGB, however; it is an arbitrary integer in the range 0-60, where the integer is simply a code representing a type of image content.

E.g. array locations whose value is 12 indicate pixels categorized as 'table'; locations whose value is 34 indicate pixels categorized as 'carpet'.

I want to load this segmentation mask into a canvas using tkinter, so I need to make an image out of it, and I need each of the values 0-60 to correspond to colors whose hues are as distinct as can be.

How do I choose these colors? How do I convert my HxW array into an RGB image?

tk421
  • 5,775
  • 6
  • 23
  • 34
JellicleCat
  • 28,480
  • 24
  • 109
  • 162

2 Answers2

3

You don't need to convert to RGB. Just use pcolor with an appropriate colormap.

It could be something as simple as this:

import matplotlib.pyplot as plt
import numpy

M = numpy.array([[1,2,3,4,5,6,7,8,9,10], [11,12,13,14,15,16,17,18,19,20]])
plt.pcolor( M , cmap = 'hsv' )
plt.show()

Added by Mark Setchell:

Tasos Papastylianou
  • 21,371
  • 2
  • 28
  • 57
  • 2
    It would be helpful to show how that looks and also to explain how to make that into something OP can load into a `TkInter` canvas. I hope you don't mind my adding the plot - just delete it if you do. – Mark Setchell Nov 27 '18 at 22:13
  • 1
    @MarkSetchell ah apologies, I missed the tkinter bit, thanks for pointing it out. I haven't done it in a while, but effectively, one can use a matplotlib object in a tkinter gui, e.g. as in this post: https://stackoverflow.com/q/4073660/4183191 Again, there would be no need to convert to RGB, just use the resulting figure in the tkinter gui. – Tasos Papastylianou Nov 27 '18 at 22:28
  • 1
    I had to use `pcolormesh` instead of `pcolor` because the former was too slow – JellicleCat Nov 28 '18 at 00:04
2

IMHO, the obvious thing to do would be to make a palettised image where you have a palette of 60 colours and an index into the palette at each location. That is very simple with PIL/Pillow.

Now you come to choosing those 60 colours. I would think of using HSL (Hue, Saturation and Lightness) colourspace. Now you need 60 different values. So you could use full Saturation and Lightness for all pixels and spread the available 360 degrees of Hue into 6 degree chunks for 60 colours. Or you could use 100% Lightness and 50% Lightness plus 100% Saturation and 50% Saturation to give you 4x as many Lightness/Saturation combinations meaning you could rotate 24 degrees of Hue for greater separation.

See here for example of how to make an image from a Numpy array, add a palette to an image and make into Pillow image and save.

I am basically suggesting a 60-entry palette, with the following values:

Hue, Saturation, Lightness
0    50%         50%
0    50%         100%
0    100%        50%
0    100%        100%
23   50%         50%
23   50%         100%
23   100%        50%
23   100%        100%
47   50%         50%
47   50%         100%
47   100%        50%
47   100%        100%
61   ...
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • I like this method, but I'm having scant luck. I'm trying the toy example `Image.fromarray([[0,1,2,3,4]], mode='P')` and am getting a single, solid color which matches the first color in my palette. – JellicleCat Nov 27 '18 at 23:21