S
S
Sergey Sova2014-04-24 11:58:41
PHP
Sergey Sova, 2014-04-24 11:58:41

How to determine a color close to a color from an existing list (php)?

I have a list of allowed colors. 68 colors in #rgb
And there is also a pixel color in #rrggbb.
It is necessary to determine the closest color from the existing list.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
Sergey, 2014-04-24
Protko @Fesor

We translate the number from HEX.

// писал по памяти, не уверен что заведется
$rgb = array_map($component) {

    return base_convert($component, 16, 10);
}, array_chunk(ltrim($color, '#'), 2));

And now we can calculate the distance between the colors using the formula:
By the distance we find the closest color.
Another option is to convert the color to HSV and compare the HUE components by average. If you have a large palette, it will be cheaper in terms of calculations to convert RGB to HSV once and then only read the average value.
Final variant:
// преобразует HEX в RGB
function hexToRgb($hex) 
{
    return array_map($component) {

        return base_convert($component, 16, 10);
    }, array_chunk(ltrim($hex, '#'), 2));
}

// возвращает расстояние между двумя цветами
function getDistanceFromColor($a, $b) 
{
    list($r1, $g1, $b1) = $a;
    list($r2, $g2, $b2) = $b;
    
    return sqrt(pow($r2-$r1, 2)+pow($g2-$g1, 2)+pow($b2-$b1, 2));
}

// Возвращает наиболее подходящий цвет из палитры
function getClosestColor($color, array $pallet) {
    $distances = array_map(function ($colorFromPallet) use ($color) {
         return getDistanceFromColor($color, $colorFromPallet);
    }, $pallet);
    
    ksort($distances);
    $keys = array_keys($distances);
    
    return $pallet[$keys[0]];    
}

// пример:
$color = "#ff0044";
// для примера у нас есть палитра из HEX цветов
$pallet = ["#ff0000", "#ffffff"];
// сразу переводим в RGB всю палитру
$pallet = array_map(function ($color) {
    return hexToRgb($color);
}, $pallet);

// берем самый подходящий в палитре цвет
// он вернется в формате RGB, можете потом сконвертить в HEX
$closestColor = getClosestColor($color, $pallet);

for a picture, you can make it simpler - let the getClosestColor function return the color index from the palette. This makes it easier to organize the count and we still know which color to replace with.

I
iDevArtem, 2014-04-24
@iDevArtem

Based on the answer of @Fesor and Wiki , I sketched some code (not very fast, especially for large pictures, but it has the right to life):

<?php

$result = array();
$colors = array('#ff0000', '#ffffaa', '#ff00ff', '#cde1b0', '#000000', '#ffffff', /* весь ваш список из 68 цветов */);
$sizeof = sizeof($colors);

$img = imagecreatefromjpeg("/img_path/img.jpg"); // если формат картинки jpg, jpeg
// $img = imagecreatefrompng("/img_path/img.png"); // если формат картинки png

$imgX = imagesx($img);
$imgY = imagesy($img); 

for ($x = 0; $x < $imgX; $x++) {
  for ($y = 0; $y < $imgY; $y++) { 
    $imgColor = imagecolorsforindex($img, imagecolorat($img, $x, $y));
    list($imgR, $imgG, $imgB) = array($imgColor['red'], $imgColor['green'], $imgColor['blue']);
    for ($i = 0; $i < $sizeof; $i++) {
      list($r, $g, $b) = array_map('hexdec', str_split(trim($colors[$i], '#'), 2));
      $delta = sqrt(pow($imgR-$r, 2)+pow($imgG-$g, 2)+pow($imgB-$b, 2));
      if ($delta >= 2 and $delta <= 2.5) { // 2.3 - примерно соответствует минимально различимому для человеческого глаза отличию между цветами (wiki)
        $result[$i] = $colors[$i];
      }
    }
  }
} 

print_r($result); // $result - список приближенно присутствующих цветов на картинке из списка $colors
?>

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question