以编程方式确定图像的人类可读颜色(例如红色、绿色等)

Posted

技术标签:

【中文标题】以编程方式确定图像的人类可读颜色(例如红色、绿色等)【英文标题】:Programmatically determine human readable color (e.g. Red, Green, etc..) of an image 【发布时间】:2011-11-22 00:54:27 【问题描述】:

我正在尝试编写一个脚本,该脚本将以编程方式运行图像并告诉我它是原色。

目前脚本获取每个像素的 RGB 值。将它们与预定义的规则进行比较,并尝试计算每种颜色的像素数。

我的问题是脚本有点命中注定。有谁知道这样做的更好方法(可能使用更容易翻译成英文的不同颜色编码系统)或通过其 RGB 定义颜色的现有规则集?​​

<?php
$file = "8629.jpg";

$colors = array("Red" => array("rel" => true, "r" => 0.65, "g" => 0.09, "b" => 0.25, "var" => 0.3),
                "Blue" => array("rel" => true, "r" => 0.21, "g" => 0.32, "b" => 0.46, "var" => 0.3),
                "Green" => array("rel" => true, "r" => 0, "g" => 0.67,"b" =>  0.33, "var" => 0.3),
                "Black" => array("rel" => false, "r" => 0, "g" => 0,"b" =>  0, "var" => 30),
                "White" => array("rel" => false, "r" => 255, "g" => 255,"b" =>  255, "var" => 30));                 

$total = 0;

$im = imagecreatefromjpeg($file);
$size = getimagesize($file);

if (!$im) 
    exit("No image found.");


for ($x = 1; $x <= $size[0]; $x++) 
    for($y = 1; $y <= $size[1]; $y++) 
        $rgb = imagecolorat($im, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;

        $colorTotal = $r + $g + $b;

        $rRatio = $r > 0 ? $r / $colorTotal : 0;
        $gRatio = $g > 0 ? $g / $colorTotal : 0;
        $bRatio = $b > 0 ? $b / $colorTotal : 0;

        foreach($colors as $key => $color) 
            if ($color["rel"]) 
                if ((($color["r"] - $color["var"]) <= $rRatio && $rRatio <= ($color["r"] + $color["var"])) &&
                    (($color["g"] - $color["var"]) <= $gRatio && $gRatio <= ($color["g"] + $color["var"])) &&
                    (($color["b"] - $color["var"]) <= $bRatio && $bRatio <= ($color["b"] + $color["var"]))) 

                    $colourCount[$key]++;
                    $total++;
                
             else 
                if ((($color["r"] - $color["var"]) <= $r && $r <= ($color["r"] + $color["var"])) &&
                    (($color["g"] - $color["var"]) <= $g && $g <= ($color["g"] + $color["var"])) &&
                    (($color["b"] - $color["var"]) <= $b && $b <= ($color["b"] + $color["var"]))) 

                    $colourCount[$key]++;
                    $total++;
                
            
        
    


var_dump($colourCount);

foreach($colourCount as $key => $color) 
    $colourPrecent[$key] = $color / $total;


arsort($colourPrecent);
var_dump($colourPrecent);

foreach($colourPrecent as $key => $color) 
    if ($prevVal) 
        if ($color < ($prevVal - 0.1)) 
            break;
        
    

    $primary[] = $key;
    $prevVal = $color;


echo("The primary colours in this image are " . implode(" and ", $primary));

?>

【问题讨论】:

嗯,很有趣。恐怕我唯一的贡献是 this warning 关于定义“人类可读”的颜色! 考虑到真彩色图像可能使每个像素都是唯一的,除非您开始将相似的颜色“组合”在一起,否则您不会获得太多收益。也许将图像缩小到 1x1 像素并找出其主要颜色会更简单。 RGB 看起来像 least useful choice of color model here。 @Widor,脚本肯定会采用 IsGuy 参数。 ;) 在我看来HSL 将是最有用的模型,因为您可以将色相与饱和度和亮度分开。 H:0-120 = 红色,120-240 = 绿色,240-360 = 蓝色。 L:0% = 黑色,L:100% S:100% = 白色。 很高兴我能帮助丹。我已经使用各种颜色模型完成了一些工作。 HSL/HSV 是一种比 RGB 更自然的颜色分量思考方式。 HSL 还具有额外的优势,您可以使用它将颜色转换为等效的灰度,甚至计算 相关 和补充颜色。用 RGB 试试。 :-) 【参考方案1】:

解决方案是按照 Herbert 的建议将 RGB 转换为 HSL。转换为人类的功能仍然需要一些调整/完成,但这里是:

function hslToHuman($h, $s, $l) 

$colors = array();

// Gray
if ($s <= 10 && (9 <= $l && $l <= 90)) 
    $colors[] = "gray";


$l_var = $s / 16;

// White
$white_limit = 93;
if (($white_limit + $l_var) <= $l && $l <= 100) 
    $colors[] = "white";


// Black
$black_limit = 9;
if (0 <= $l && $l <= ($black_limit - $l_var)) 
    $colors[] = "black";


// If we have colorless colors stop here
if (sizeof($colors) > 0) 
    return $colors;


// Red
if (($h <= 8 || $h >= 346)) 
    $colors[] = "red";


// Orange && Brown
// TODO

// Yellow
if (40 <= $h && $h <= 65) 
    $colors[] = "yellow";


// Green
if (65 <= $h && $h <= 170) 
    $colors[] = "green";


// Blue
if (165 <= $h && $h <= 260) 
    $colors[] = "blue";


// Pink && Purple
// TODO

return $colors;

【讨论】:

【参考方案2】:

好的,所以你有一个图形库,里面一定有一个普通的东西,你平均你的照片,取任何像素,然后就完成了吗?

在这里找到的最简单的解决方案是:resize to 1x1px, get colorat :

Get image color

之后就很容易了,在某个地方找到一个人类可读的详细 rgb 列表(例如 html 颜色),将其编码为一个数组并在你的脚本中使用它 -> round() 你的 r,g,b, vals以您的数据的精度并检索颜色。

您应该确定您想要的颜色粒度并从那里开始 -> 找到您的一组命名颜色(我认为所有 8 位颜色在某处都有一个名称),然后将您的 rgb 信息减少到该值 - 或者通过减少在读取图像之前(更快)或在读取时减少颜色信息(在颜色列表方面更灵活。

一些 rgb 人类可读资源的基本示例:

http://www.w3schools.com/html/html_colornames.asp

其他:

http://chir.ag/projects/name-that-color/#2B7C97

http://r0k.us/graphics/SIHwheel.html

【讨论】:

目前最困难的部分是找到人类可读的 RGB 详细列表。脚本还需要比平均颜色更智能。如果我有一张 50/50 红色/蓝色的图像,我需要知道它是红色和蓝色的,而不是被告知它是紫色的。 您可以通过搜索“HTML 颜色”在网络上的任何地方找到 RGB 列表,您将获得一个具有特定粒度的子集(对于您似乎想要的而言绰绰有余),其中包含所有命名颜色- 添加了一个例子。关于您的多种颜色,您可以执行以下操作:调整大小为 4x4,foreach colorat,排名并测试它是否适合。如果不尝试更好的资源。 最终使用 HSL 颜色空间。在色调范围内定义颜色比尝试跟踪 3 个不同的变量并确定它是什么颜色要容易得多。感谢您的意见。

以上是关于以编程方式确定图像的人类可读颜色(例如红色、绿色等)的主要内容,如果未能解决你的问题,请参考以下文章

我想知道如何阅读 galen 框架报告生成的图像映射以进行布局测试。橙色、绿色、红色的颜色是啥意思?

web-4. 装饰页面的图像

图像中颜色的分类器

HSV 和 HLS颜色空间

如何使百分比指示器以编程方式在颤动中改变颜色?

用于合成红色、绿色和蓝色颜色通道的 CIFilter