Обнаружение уникальных цветов на изображении, видимом для глаз - PullRequest
1 голос
/ 10 января 2020

Aoa,

В настоящее время я работаю над проектом и застрял. На самом деле я хочу алгоритм для определения количества цветов на изображении, которые видны человеческому глазу. Я использовал некоторые пакеты поверх inte rnet, но они обеспечивают даже небольшие изменения цвета.

Пример: На представленном ниже изображении есть два видимых цвета, но в пакете, который я использую, показано 4 или более чем 4, и если какой-либо пакет дает точный цвет для этого изображения, то он показывает неправильный счет для изображения, имеющего несколько цветов. Example Image i used

Некоторые пакеты, которые я использовал

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

https://github.com/brianmcdo/ImagePalette

1 Ответ

1 голос
/ 13 января 2020

Не идеальная реализация (это будет медленно, особенно на больших изображениях), но мы могли бы сделать что-то вроде:

$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 уникальных цветов):

image 1

и допуск 75 Мы получаем выходные данные следующих 4 цветов:

75

С допуском 10 мы получаем следующие 8 цветов:

10

Поскольку мы l oop каждый В пикселе на изображении мы получаем значения цвета в формате 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 гораздо больше уникальных цветов

Если аналогичного значения не существует, мы помещаем sh текущее значение RGBA пикселя в наш массив $results.

После завершения выполнения кода массив $results будет содержать «уникальные» цвета. Мы можем посчитать цвета следующим образом:

echo count($results);

Это решение может использовать большую оптимизацию (оно будет очень медленным на больших изображениях с большим количеством уникальных цветов), и я проигнорировал альфа-канал в этой реализации (достаточно легко добавить в случае необходимости), но, надеюсь, это полезно для вас.

Наихудшая сложность этой реализации -

O(n<sup>2</sup>)
, которая произойдет, если каждый цвет пикселя в изображении будет уникальным, что приведет к тому, что наш массив $results будет содержать каждое предыдущее значение, поэтому каждая итерация будет содержать вложенное l oop числа пикселей в изображении (более или менее), что для большого изображения будет невероятно медленным.
...