如何确定像素点的颜色或某种颜色对应的色调范围是多少?

How to determine color of the pixel or What degree range of Hue correspond to certain color?

是否有一些约定将HSL色环划分为度数范围来定义基本颜色?

例如,80-150 度为绿色,210-280 度为蓝色,依此类推。

我想自动检测属于某个“颜色组”的像素颜色,发现 HSL 非常适合确定色调。就我的目的而言,足以定义红色、橙色、黄色、绿色、青色、蓝色、品红色、粉红色的边界。

这样的分割有解决方案吗?

编辑

我在悬赏之前添加了更多推理和示例...

我的最终想法是根据图片的主要颜色为库存图片编制索引,这样我就可以将颜色作为一个查询参数。

我已经定义了一些边界如何划分HSL色轮:

  1-15 red
  16-50 orange
  51-72 yellow
  73-155 green
  156-185 cyan
  186-268 blue
  269-310 magenta
  311-344 pink
  345-359 red

我有一个确定像素颜色的函数:

function getPixelTone(pixel) {
  let [ hue, sat, light ] = rgbToHsl( ...pixel );
  sat   = parseInt(sat);
  light = parseInt(light);

  if ( light < 3 || sat < 50  && light < 5 ) {
    return 'black';
  }

  if ( light > 96 ) {
    return 'white';
  }

  if ( hue === 0 || isPixelGray(pixel) ) {
    return 'gray';
  }

  if ( (hue > 0 && hue < 16 ) || (hue > 344 && hue < 360 ) ) {
    if ( light > 55 ) {
      return 'pink';
    }

    if ( light < 34 || ( sat < 30 && light < 80 ) ) {
      return 'brown';
    }  

    return 'red';
  }

  if ( hue > 15 && hue < 51 ) {
    if ( light < 34 ) {
      return 'brown';
    }  
    return 'orange';
  }
  if ( hue > 50 && hue < 73 ) {
    return 'yellow';
  }
  if ( hue > 72 && hue < 156 ) {
    return 'green';
  }
  if ( hue > 155 && hue < 186 ) {
    return 'cyan';
  }
  if ( hue > 185 && hue < 269 ) {
    return 'blue';
  }
  if ( hue > 268 && hue < 311 ) {
    return 'magenta';
  }
  if ( hue > 310 && hue < 345 ) {
    return 'pink';
  }

  return 'color';

}

函数 rgbToHsl 来自模块 rgb-to-hsl,函数 isPixelGray 定义如下:

function isPixelGray(pixel) {
  if ( Math.max(pixel) - Math.min(pixel) < 3 ) {
    return true;
  }
  return false;
}

所以我的问题的全部目的是将像素量化为最简单的感知颜色之一。我认为这些颜色是:红色、橙色、黄色、绿色、青色、蓝色、品红色、粉色、棕色、黑色,以及白色,如果可以轻松确定,它还可以包括 beige

确定属于这些颜色之一的像素的最佳方法是什么?

PS 我选择 HSL 色彩空间作为基础,因为从我的角度来看,它比 RGB 更有优势。但不应该是这样。

好吧,这在很大程度上取决于您认为橙色或红色,还是黄色和绿色。看看颜色的圆圈,我会说每 15 或 30 或 60 或 90 度(取决于您要考虑的范围)您就有一个过渡。例如,从红色到黄色的过渡颜色称为橙色,但例如从黄色到绿色的过渡颜色没有名称。因此,从 0 到 15(Hue 参数)你有红色,从 15 到 45 你有橙色,从 45 到 75(或多或少)你有黄色,从 75 到 165 你有绿色,然后你有青色等。 编辑:您可以尝试使用颜色选择器,例如 Microsoft Powertoys 中的颜色选择器,它不仅会告诉您 HSV 或 RGB 或 HEX 的颜色,还会告诉您颜色名称

Color Name & Hue 是“rgb to hue name”的第一个搜索结果。这是一款完全符合您要求的网络应用程序:

With this little tool you can either enter RGB (Red-Green-Blue) values, HSB (Hue-Saturation-Brightness) numbers or a hexadecimal code for a color, to find its closest match of a named color and its corresponding hue... The list of colors comprises 1640 different color names extracted from several sources on the web.

The color name is matched to one of the following main color hues: Red, Orange, Yellow, Green, Blue, Violet, Brown, Black, Grey, and White.

ntc js的使用说明(Name that Color JavaScript):

var match = ntc.name("#6195ED");
rgb        = match[0]; // RGB value of closest match ("#6495ED")
name       = match[1]; // Color name                 ("Cornflower Blue")
shade_rgb  = match[2]; // RGB value of color's shade ("#0000FF")
shade_name = match[3]; // Color's shade              ("Blue")
exactmatch = match[4]; // True if exact color match  (false)

如果您只想要名称的 RGB 十六进制值:

// From https://www.color-blindness.com/color-name-hue-tool/js/ntc.js
  shades: [
["FF0000", "Red"],
["FFA500", "Orange"],
["FFFF00", "Yellow"],
["008000", "Green"],
["0000FF", "Blue"],
["EE82EE", "Violet"],
["A52A2A", "Brown"],
["000000", "Black"],
["808080", "Grey"],
["FFFFFF", "White"]
],

  names: [
["35312C", "Acadia", "Brown"],
["75AA94", "Acapulco", "Green"],
["C0E8D5", "Aero Blue", "Green"],

// Many colors omitted...

["DDC283", "Zombie", "Yellow"],
["A29589", "Zorba", "Brown"],
["17462E", "Zuccini", "Green"],
["CDD5D5", "Zumthor", "Grey"]
]

这里有一个色轮,当您悬停它时,它会根据像素确定最简单的颜色,它由纯 JS 制成。在函数 getColorFromWheel() 中,您获取 rba 值,然后将其转换为 hsl。当它转换为 hsl 时,函数 getColorNameFromHsl() 确定它是什么 color 然后它只显示 <div> 中的值。如果你想要更精确的颜色,你可以找到一些更精确的 rbahsl 颜色列表来命名数组并使用它。

这是一个将 rba 颜色转换为名称的库:Name that color

希望这个解决方案对您有所帮助。

function newEl(tag){return document.createElement(tag)}

window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
    var wheel = makeColorWheel(256);
    wheel.addEventListener('mousemove', getColorFromWheel);
    document.body.appendChild( wheel );
}

var convertToHsl = function convertToHsl(rgbArr) {
  var r1 = Number(rgbArr[0]) / 255, g1 = Number(rgbArr[1]) / 255, b1 = Number(rgbArr[2]) / 255;
  var maxColor = Math.max(r1,g1,b1), minColor = Math.min(r1,g1,b1);
  var L = (maxColor + minColor) / 2 , S = 0, H = 0;
  if(maxColor != minColor){
    if(L < 0.5){
      S = (maxColor - minColor) / (maxColor + minColor);
    }else{
      S = (maxColor - minColor) / (2.0 - maxColor - minColor);
    }
    if(r1 == maxColor){
      H = (g1-b1) / (maxColor - minColor);
    }else if(g1 == maxColor){
      H = 2.0 + (b1 - r1) / (maxColor - minColor);
    }else{
      H = 4.0 + (r1 - g1) / (maxColor - minColor);
    }
  }
  L = L * 100;
  S = S * 100;
  H = H * 60;
  if(H<0){
    H += 360;
  }
  return {h:H, s:S, l:L};
}

var getColorNameFromHsl = function (hsl) {
        var l = Math.floor(hsl.l), s = Math.floor(hsl.s), h = Math.floor(hsl.h);
        if (s <= 10 && l >= 90) {
            return ("White")
        } else if ((s <= 10 && l <= 70) || s === 0) {
            return ("Gray")
        } else if (l <= 15) {
            return ("Black")
        } else if ((h >= 0 && h <= 15) || h >= 346) {
            return ("Red");
        } else if (h >= 16 && h <= 35) {
            if (s < 90) {
                return ("Brown");
            } else {
                return ("Orange");
            }
        } else if (h >= 36 && h <= 54) {
            if (s < 90) {
                return ("Brown");
            } else {
                return ("Yellow");
            }
        } else if (h >= 55 && h <= 165) {
            return ("Green");
        } else if (h >= 166 && h <= 260) {
            return ("Blue")
        } else if (h >= 261 && h <= 290) {
            return ("Purple")
        } else if (h >= 291 && h <= 345) {
            return ("Pink")
        }
    }

var hsv2rgb = function(hsv) {
  var h = hsv.hue, s = hsv.sat, v = hsv.val;
  var rgb, i, data = [];
  if (s === 0) {
    rgb = [v,v,v];
  } else {
    h = h / 60;
    i = Math.floor(h);
    data = [v*(1-s), v*(1-s*(h-i)), v*(1-s*(1-(h-i)))];
    switch(i) {
      case 0:
        rgb = [v, data[2], data[0]];
        break;
      case 1:
        rgb = [data[1], v, data[0]];
        break;
      case 2:
        rgb = [data[0], v, data[2]];
        break;
      case 3:
        rgb = [data[0], data[1], v];
        break;
      case 4:
        rgb = [data[2], data[0], v];
        break;
      default:
        rgb = [v, data[0], data[1]];
        break;
    }
  }
  return rgb;
};

function clamp(min, max, val)
{
    if (val < min) return min;
    if (val > max) return max;
    return val;
}

function makeColorWheel(diameter)
{
    var can = newEl('canvas');
    var ctx = can.getContext('2d');
    can.width = diameter;
    can.height = diameter;
    var imgData = ctx.getImageData(0,0,diameter,diameter);
    var maxRange = diameter / 2;
    
    for (var y=0; y<diameter; y++)
    {
        for (var x=0; x<diameter; x++)
        {
            var xPos = x - (diameter/2);
            var yPos = (diameter-y) - (diameter/2);
            
            
            var polar = pos2polar( {x:xPos, y:yPos} );
            var sat = clamp(0,1,polar.len / ((maxRange/2)));
            var val = clamp(0,1, (maxRange-polar.len) / (maxRange/2) );
            
            var rgb = hsv2rgb( {hue:polar.ang, sat:sat, val:val} );
            
            var index = 4 * (x + y*diameter);
            imgData.data[index + 0] = rgb[0]*255;
            imgData.data[index + 1] = rgb[1]*255;
            imgData.data[index + 2] = rgb[2]*255;
            imgData.data[index + 3] = 255;
        }
    }
    ctx.putImageData(imgData, 0,0);
    return can;
}

function deg2rad(deg)
{
    return (deg / 360) * ( 2 * Math.PI );
}
function rad2deg(rad)
{
    return (rad / (Math.PI * 2)) * 360;
}

function pos2polar(inPos)
{
    var vecLen = Math.sqrt( inPos.x*inPos.x + inPos.y*inPos.y );
    var something = Math.atan2(inPos.y,inPos.x);
    while (something < 0)
        something += 2*Math.PI;
        
    return { ang: rad2deg(something), len: vecLen };
}



function getColorFromWheel(event) 
{
    var can = this;
    var ctx = can.getContext('2d');
    var color = document.getElementById('color');
    
  var x = event.layerX;
  var y = event.layerY;
  var pixel = ctx.getImageData(x, y, 1, 1);
  var data = pixel.data;
  var rgba = 'rgba(' + data[0] + ',' + data[1] +
             ',' + data[2] + ',' + (data[3] / 255) + ')';
  colorName.style.background =  rgba;
 var rgbArray = [data[0], data[1], data[2]];
 var color = getColorNameFromHsl(convertToHsl(rgbArray));
   colorName.textContent = color;
}
div {
width: 200px; 
height: 100px;
float: right;
border-radius: 25px;
text-align: center;
vertical-align: middle;
line-height: 100px; 
}
<div id="colorName" ></div>