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

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

目前脚本获取每个像素的 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 试试。 :-)

标签: php colors


【解决方案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 个不同的变量并确定它是什么颜色要容易得多。感谢您的意见。
    猜你喜欢
    • 2011-10-28
    • 1970-01-01
    • 2018-05-31
    • 2020-10-08
    • 2017-05-28
    • 1970-01-01
    • 2015-09-29
    • 2013-09-04
    • 2011-05-08
    相关资源
    最近更新 更多