如何确定像素的颜色或者说什么色调范围对应某种颜色?

4

有没有将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;
}

我的问题是如何将像素量化成最简单的颜色之一。我认为这些颜色应该包括红色、橙色、黄色、绿色、青色、蓝色、洋红色、粉色、棕色、黑色白色,如果可以轻易确定,也可以包括米色

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

PS:我选择了HSL颜色空间作为基础,因为从我的观点看,它比RGB更具优势。但不一定非要这样。

3个回答

3
在这里,您有一个颜色轮,用纯粹的 JS 确定像素的最简单的颜色当您悬停在其上时。在函数 getColorFromWheel()中,您获得 rba 值,然后将其转换为 hsl 。当它转换为 hsl 时,函数 getColorNameFromHsl()确定了什么颜色是,然后它只在&lt; div&gt; 中显示该值。如果您想要更精确的颜色,您可以找到更准确的 rba hsl 颜色列表到名称数组,并制作一个该功能。

这是一个库,将 rba 颜色转换为名称:名字是那个颜色

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

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>


2
“Color Name & Hue”是“rgb to hue name”搜索结果的第一个。它是一个网络应用程序,可以完全满足你的需求:
使用这个小工具,你可以输入RGB(红-绿-蓝)值、HSB(色相-饱和度-亮度)数值或颜色的十六进制代码,以找到最接近的命名颜色及其相应的色调。颜色列表包括1640种从网上多个来源提取的不同颜色名称。
颜色名称与以下主要颜色色调之一相匹配:红色、橙色、黄色、绿色、蓝色、紫色、棕色、黑色、灰色和白色。
  • 独立的颜色名称和色相工具可以在此处使用。您可以直接从浏览器开发控制台尝试ntsnts.name()
  • 相关的JS源文件是ntc.js(技术上没有许可证?)
  • 上述文件是Chirag Mehta's ntc.js的修改版本。(知识共享许可证,但缺少主要的色相分类。更多详情和使用说明。)

NTC js(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"]
]

谢谢,这个工具对我来说是新的。它比我的工具更精确,但速度要慢得多(2.4兆像素下7秒对204秒)。我会深入研究一下。 - w.k

0

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


感谢您描述我的问题 ;) - w.k
我并不是想要重新发明轮子,我希望有更好的色彩感知经验的人已经将圆形划分为具有意义的名称的段落。 - w.k

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