Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define BGR color range? Map color code to color name

I want to create color mapping, define few color names and boundaries in range of which those colors should fall. For example (BGR format),

colors = {
    'red': ((0, 0, 255), (125, 125, 255)),
    'blue': ((255, 0, 0), (255, 125, 125)),
    'yellow' ....
}

So if I receive color, let's say (255, 50, 119) I can call it blue. I want to make such mapping for at least colors of rainbow plus gray, black, white. Using Python and openCV.

The problem is that I don't really understand where to get those values for boundaries, is there kind of lowest / highest value for blue, red and so on?

like image 731
wasd Avatar asked May 23 '18 18:05

wasd


People also ask

How do you define color range?

A typical definition of a color range has no gaps in the range values, and the top value of one range is equal to the bottom value of the next range. If there are gaps in ranges, the value renders as gray. In general, the bottom value in a range is inclusive and the top value is exclusive.

How do you convert RGB values to color names in Python?

There is a program called pynche which can change RGB to colour name in English for Python. You can try to use the method ColorDB. nearest() in ColorDB.py which can do what you want.

What Colour is RGB 255 0 255?

For example, rgb(255, 0, 0) is displayed as red, because red is set to its highest value (255) and the others are set to 0. To display black, set all color parameters to 0, like this: rgb(0, 0, 0). To display white, set all color parameters to 255, like this: rgb(255, 255, 255).

What color is R 255 G 255 B 255?

RGB colorsWhite: RGB(255,255,255) Red: RGB(255,0,0)


2 Answers

I would suggest using HSV colourspace for comparing colours because it is less sensitive to variable lighting than RGB, where green in the sunlight might be rgb(20,255,10), but green in a shadow might be rgb(3,45,2), whereas both will have a very similar Hue in HSV colourspace.


So, to get started...

Create a little 10x1 numpy array and make the first pixel red, the second orange, then yellow, green, blue, indigo, violet then black, mid-grey and white. There's a table here.

Then convert to HSV colourspace and note the Hue values.

I have started some code...

#!/usr/local/bin/python3
import numpy as np
import imageio
import cv2

# Create black image 10x1
im = np.zeros([1,10,3], dtype=np.uint8)

# Fill with colours of rainbow and greys
im[0,0,:]=[255,0,0]       # red
im[0,1,:]=[255,165,0]     # orange
im[0,2,:]=[255,255,0]     # yellow
im[0,3,:]=[0,255,0]       # green
im[0,4,:]=[0,0,255]       # blue
im[0,5,:]=[75,0,130]      # indigo
im[0,6,:]=[238,130,238]   # violet
im[0,7,:]=[0,0,0]         # black
im[0,8,:]=[127,127,127]   # grey
im[0,9,:]=[255,255,255]   # white
imageio.imwrite("result.png",im)

hsv=cv2.cvtColor(im,cv2.COLOR_RGB2HSV)
print(hsv)

Check image:

enter image description here

Check colours with Imagemagick too:

convert result.png txt:

# ImageMagick pixel enumeration: 10,1,65535,srgb
0,0: (65535,0,0)  #FF0000  red
1,0: (65535,42405,0)  #FFA500  orange
2,0: (65535,65535,0)  #FFFF00  yellow
3,0: (0,65535,0)  #00FF00  lime
4,0: (0,0,65535)  #0000FF  blue
5,0: (19275,0,33410)  #4B0082  indigo
6,0: (61166,33410,61166)  #EE82EE  violet
7,0: (0,0,0)  #000000  black
8,0: (32639,32639,32639)  #7F7F7F  grey50
9,0: (65535,65535,65535)  #FFFFFF  white

Now look at the HSV array below - specifically the first column (Hue). You can see Red has a Hue=0, Orange is 19, Yellow is 30 and so on. Note too that the Black, Grey and White all have zero Saturation and Black has a low Value, Grey has a medium Value and White has a high Value.

[[[  0 255 255]
  [ 19 255 255]
  [ 30 255 255]
  [ 60 255 255]
  [120 255 255]
  [137 255 130]
  [150 116 238]
  [  0   0   0]
  [  0   0 127]
  [  0   0 255]]]

Now you can make a data-structure in Python that stores, for each colour:

  • Lowest included Hue
  • Highest included Hue
  • Name

So, you might use:

... see note at bottom for Red
14,23,"Orange"
25,35,"Yellow"
55,65,"Green"
115,125,"Blue"
...

and so on - omit Black, Grey and White from the table.


So, how do you use this?

Well, When you get a colour to check, first convert the R, G and B values to HSV and look at the resulting Saturation - which is a measure of vividness of the colour. Garish colours will have high saturation, whereas lacklustre, greyish colours will have low saturation.

So, see if the Saturation is more than say 10% of the max possible, e.g. more than 25 on a scale of 0-255.

If the Saturation is below the limit, check the Value and assign Black if Value low, Grey if middling and White if Value is high.

If the Saturation is above the limit, check if it is within the lower and upper limits of one of your recorded Hues and name it accordingly.

So the code is something like this:

def ColorNameFromRGB(R,G,B)
    # Calculate HSV from R,G,B - something like this
    # Make a single pixel from the parameters 
    onepx=np.reshape(np.array([R,G,B],dtype=np.uint8),(1,1,3))
    # Convert it to HSV
    onepxHSV=cv2.cvtColor(onepx,cv2.COLOR_RGB2HSV)
    ...
    ...
    if S<25:
        if V<85:
           return "black"
        elsif V<170:
           return "grey"
        return "white"
    # This is a saturated colour
    Iterate through colour names table and return name of entry with matching Hue

There are 2 things to be aware of:

  • There is a discontinuity in the Hue values for Red, because the HSV colour wheel is a circular wheel and the Hue value for Red is at an angle of 0, so values above 350 and below 10 are all Reds. It so happens that OpenCV scales the 0-360 range by dividing by 2, meaning it comes out as 0-180... which neatly fits in a single unsigned byte. So, for Red, you need to check for Hue greater than 175 and less than 5, say.

  • Be careful to always generate an 8-bit image when looking up colours, as the Hue values are scaled differently on 16-bit and float images.

like image 175
Mark Setchell Avatar answered Sep 27 '22 21:09

Mark Setchell


Define a distance between two colors. Then find the "closest" color name for the given color. Which definition of distance you will choose has to be guided by your requirements, because there is no "best" definition, as far as I know.

One possibility is distance in RGB space. The distance between two colors can be defined, for example, as the euclidean (L2) distance between the colors as represented by vectors in three dimensional space - distance(a,b) = (a-b).length() Alternatively, try the Manhattan (L1) metric if the result makes sense, because the euclidean distance in RGB space is more of a heuristic than a valid measurement.

Another possibility is to first convert to HSV space. Then the closest color will be the one that has the closest hue to the given color. Unless the given color has insufficient saturation, then the color is either white, gray or black, depending on the color's lightness.

like image 37
Stefan Dragnev Avatar answered Sep 27 '22 22:09

Stefan Dragnev