检测肉眼可见的图像中的独特颜色

Detect unique colors in an image visible to eye

奥阿,

我目前正在做一个项目,stuck.Actually我想要一个算法来检测图像中人眼可见的颜色数量。我在互联网上使用了一些软件包,但它们甚至提供了很小的颜色变化。

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

我用过的一些包

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

https://github.com/brianmcdo/ImagePalette

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

$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 值将匹配不太相似的颜色。 0$tolerance 值将检查完全匹配并在我们的 $results 中产生更独特的颜色。

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

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

echo count($results);

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

此实现的最坏情况复杂度是

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