如何定义BGR颜色范围?将颜色代码映射到颜色名称。

8

我想创建颜色映射,定义几个颜色名称和范围内的边界,使这些颜色符合要求。例如(BGR格式),

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

如果我收到颜色,比如(255, 50, 119),我可以称之为蓝色。我想为彩虹的至少七种颜色以及灰色、黑色和白色制作这样的映射。使用 Python 和 OpenCV。

问题在于我不太明白如何获取边界的值,蓝色、红色等颜色是否有最低/最高值?


最好使用HSV颜色空间进行调整。 - Jeru Luke
2个回答

7
我建议使用HSV颜色空间来比较颜色,因为它对变化的光照不太敏感,而RGB则很敏感。例如阳光下的绿色可能是rgb(20,255,10),而阴影中的绿色可能是rgb(3,45,2),但在HSV颜色空间中,两者的色调非常相似。
那么,开始操作吧...
创建一个小的10x1 numpy数组,并使第一个像素为红色、第二个为橙色、然后是黄色、绿色、蓝色、靛蓝色、紫罗兰色、黑色、灰色和白色。这里有一个表格:链接
然后转换到HSV颜色空间并注意色调值。
下面是一些初始代码...
#!/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)

请查看图片:

在此输入图片描述

使用Imagemagick也可以检查颜色:

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

现在看一下下面的HSV数组 - 特别是第一列(色相)。您可以看到红色的色相为0,橙色为19,黄色为30等。还要注意黑色、灰色和白色都具有零饱和度,黑色具有较低的亮度,灰色具有中等的亮度,而白色具有较高的亮度

[[[  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]]]

现在你可以在Python中创建一个数据结构,用于存储每种颜色的以下信息:
  • 最低色调
  • 最高色调
  • 名称
因此,你可以使用以下代码:
... see note at bottom for Red
14,23,"Orange"
25,35,"Yellow"
55,65,"Green"
115,125,"Blue"
...

等等,从表格中省略黑色、灰色和白色。


那么,你要如何使用它呢?

好的,当你得到一个要检查的颜色时,首先将 R、G 和 B 值转换为HSV,然后查看结果中的饱和度 - 这是颜色鲜艳程度的一种度量。花哨的颜色会有很高的饱和度,而缺乏光泽、带灰色调的颜色会有较低的饱和度。

因此,看看饱和度是否超过了最大可能值的 10%,例如在 0-255 的范围内超过了 25。

如果饱和度低于限制,请检查亮度并根据亮度的高低分配黑色、灰色或白色。

如果饱和度超过了限制,请检查它是否在你记录的色相的下限和上限之间,并相应地命名。

因此,代码大致如下:

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

需要注意的有两点:

  • 由于HSV(Hue, Saturation, Value)颜色轮是一个圆形,而红色的Hue值位于0度,因此Red颜色的Hue值存在不连续性。在OpenCV中,将0-360范围缩小一半(即除以2),因此范围为0-180,能够很好地适配单个无符号字节。因此,对于红色,应检查Hue大于175且小于5。

  • 在查找颜色时,请确保始终生成8位图像,因为16位和浮点图像的Hue值比例不同。


2
定义两个颜色之间的距离,然后找到给定颜色的“最近”颜色名称。您选择哪种距离定义必须根据您的要求进行指导,因为据我所知,没有“最佳”定义。
一种可能性是在RGB空间中测量距离。例如,可以将两种颜色之间的距离定义为表示三维空间中向量的颜色之间的欧几里得(L2)距离 - distance(a,b) = (a-b).length() 或者尝试曼哈顿(L1)度量,如果结果有意义的话,因为在RGB空间中的欧几里得距离更像是一种启发式而不是有效的测量方法。
另一个可能性是首先转换为HSV空间。那么,最接近的颜色将是具有与给定颜色最接近色调的颜色。除非给定的颜色饱和度不足,否则颜色是白色、灰色或黑色,具体取决于颜色的亮度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接