【问题标题】:Detect unique colors in an image visible to eye检测肉眼可见图像中的独特颜色
【发布时间】:2020-04-28 01:37:19
【问题描述】:

哎呀,

我目前正在从事一个项目并陷入困境。实际上,我想要一种算法来检测图像中人眼可见的颜色数量。我在互联网上使用了一些软件包,但它们提供的颜色变化很小。

示例: 下面提供的图像有两种可见颜色,但我使用的包装显示 4 种或超过 4 种颜色,如果某些包装为该图像提供准确的颜色,而不是显示具有多种颜色的图像的错误计数。

我使用的一些包

http://www.coolphptools.com/color_extract#demo

https://github.com/brianmcdo/ImagePalette

【问题讨论】:

  • 您可以解释返回的颜色,看看它们是否在其他颜色的阈值内。在这种情况下,您可以对它们进行去重,只留下“肉眼可见”的颜色。
  • 大多数包都返回像素数和十六进制值,所以您能建议我们如何实现您上面所说的吗?
  • 十六进制值由 6 个字符组成。前两个是红色的,第二对是绿色的,最后一对是蓝色的。根据这 3 种颜色,您可以确定每个部分与另一个部分的接近程度。
  • 这是因为角落通常有反锯齿(谷歌如果你不知道它是什么)像素,这个效果的截图:d.bouma.dev/261piOUuBI77。所以4可能是准确的。您可以尝试对图像进行像素化以移除这些像素,并且可能仅提取构成图像 x% 以上的颜色以获得“良好”的读数,具体取决于您的用例。
  • 我认为您需要更正式地定义什么是“肉眼可见的独特颜色”,因为根据您如何定义它,结果会改变 很多

标签: laravel algorithm colors detection color-detection


【解决方案1】:

不是一个完美的实现(这会很慢,尤其是在大图像上),但我们可以这样做:

$resource = imagecreatefrompng("test.png");  // Load our image (use imagecreatefromjpeg if using jpeg)
$width = imagesx($resource); // Get image width
$height = imagesy($resource); // Get image height
$results = []; // Create empty array to hold our "unique" color results

$tolerance = 5; // The amount of variation allowed to consider a color the same

// Loop each pixel in the image
for($x = 0; $x < $width; $x++) {
  for($y = 0; $y < $height; $y++) {

    $add = true;
    $color_index = imagecolorat($resource, $x, $y);
    $color = imagecolorsforindex($resource, $color_index); // Get the color as an array

    // Push the first pixel into our results so we have something to start the comparison against
    if (count($results) == 0){
      $results[] = $color;
    } else {
      // Compare the current colour to our results using the tolerance
      foreach ($results as $i => &$result):
        $near_red = ($color['red'] > ($result['red'] - $tolerance)) && ($color['red'] < ($result['red'] + $tolerance));
        $near_green = ($color['green'] > ($result['green'] - $tolerance)) && ($color['green'] < ($result['green'] + $tolerance));
        $near_blue = ($color['blue'] > ($result['blue'] - $tolerance)) && ($color['blue'] < ($result['blue'] + $tolerance));

        if ($near_red && $near_green && $near_blue){
          // This colour is similar to another result
          $add = false;
        }

        if (!$add){
          break;
        }
      endforeach;

      if ($add){
        $results[] = $color;
      }
    }
  }
}

// Output the unique colors visually. You would probably just count($results) here
foreach($results as $item):
  $color = $item['red'] . "," . $item['green'] . "," . $item['blue'] . "," . "1";
  echo "<div style='width: 10px; height: 10px; background-color: rgba($color); display: inline-block;'></div>";
endforeach;

使用这张图片(包含 8 种独特的颜色):

75的容差我们得到以下4种颜色的输出:

10 的容差下,我们得到以下 8 种颜色:

当我们循环图像中的每个像素时,我们会得到 RGBA 格式的颜色值,例如:

[
  "red"   => 255,
  "green" => 255,
  "blue"  => 255,
  "alpha" => 255,
]

然后我们可以将当前像素与$results 数组中的每个项目进行比较,方法是加减容差并检查当前通道(红色、绿色和蓝色)是否在该范围内:

$near_red = ($color['red'] > ($result['red'] - $tolerance)) && ($color['red'] < ($result['red'] + $tolerance));

例如,如果我们当前的像素红色值为 50,而我们的容差为 5,我们将检查 $results 中是否有红色值介于 45 和 55 之间的项目。我们对绿色和蓝色执行相同操作.如果所有 3 个通道都在范围内,则意味着我们的 $results 中已经有相似的颜色,因此我们不会将当前像素颜色添加到 $results 数组中。

更大的$tolerance 值将匹配不太相似的颜色。 $tolerance 的值 0 将检查完全匹配并在我们的 $results 中产生更多独特的颜色。

如果不存在类似的值,我们将当前像素 RGBA 值推送到我们的$results 数组。

代码运行完成后,$results 数组将包含“唯一”颜色。我们可以这样计算颜色:

echo count($results);

这个解决方案可以使用很多优化(在具有很多独特颜色的大图像上会很慢),并且我在这个实现中忽略了 alpha 通道(如果需要,很容易添加)但希望对你有用。

这个实现的最坏情况复杂度是

O(n2)
如果图像中的每个像素颜色都是唯一的,就会发生这种情况,这将导致我们的 $results 数组包含每个先前的值,因此每次迭代都将包含图像中像素数的嵌套循环(或多或少),对于大图像来说,这将非常慢。

【讨论】:

  • 好吧,您的代码非常好,必须稍微调整一下,但运行良好并没有达到 100%,但似乎完全可以接受。
  • 这是一个棘手的问题,因为人眼可见是一个非常模糊的问题,但祝你好运。找到后请分享您的最终实现!
猜你喜欢
  • 2021-05-26
  • 1970-01-01
  • 2018-07-16
  • 1970-01-01
  • 1970-01-01
  • 2016-08-29
  • 1970-01-01
  • 2013-08-19
  • 2020-02-07
相关资源
最近更新 更多