RGB до ближайшего предопределенного цвета - PullRequest
13 голосов
/ 20 декабря 2010

Редактировать:

Получив ответ, я сделал эту функцию

function grabclosestcolor($r, $g, $b){
    $colors = array(array(124,12,12),array(7,7,11),array(110,224,219),array(123,123,123),array(124,177,74),array(130,86,53),array(77,77,77),array(164,124,68),array(204,196,132),array(164,148,147),array(163,123,67),array(26,122,26), array(195,195,50),array(193,193,193),array(255,248,73),array(243,243,243));
    $differencearray = array();
    foreach ($colors as $value) {
        $difference = sqrt(pow($r-$value[0],2)+pow($g-$value[1],2)+pow($b-$value[2],2));
        array_push($differencearray, $difference);
        $smallest = min($differencearray);
        $key = array_search($smallest, $differencearray);
        return $colors[$key];
        }
    }


Моя цель заключается в следующем.Я беру картинку и перебираю каждый пиксель и беру его x, y и rgb.

Вместо того, чтобы просто взять rgb, у меня есть предопределенный массив, и я ищу наиболее близкое совпадение из цвета, который язахватывается в предопределенный массив.Цель здесь - использовать только цвета из предопределенного массива.Вот мой массив цветов.

$colors = array(array(124,12,12),array(7,7,11),array(110,224,219),array(123,123,123),array(124,177,74),array(130,86,53),array(77,77,77),array(164,124,68),array(204,196,132),array(164,148,147),array(163,123,67),array(26,122,26), array(195,195,50),array(193,193,193),array(255,248,73),array(243,243,243));

, а вот мой существующий код, который проходит через все это.

$int = imagesx($im) - 1;
$int2 = imagesy($im) - 1;
$start2 = 0;
do{
    $start = 0;
    do{
        $rgb = imagecolorat($im, $start, $start2);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        $value = rgb2hex($r,$g,$b).":$start:$start2";
        array_push($colorsofimage, $value);
    } while($int > $start++);
} while($int2 > $start2++);

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

$ colorsofimage содержит массив информации о каждом пикселе с шестнадцатеричным: x: y, я хочу, чтобы это было rgb2hex (NEWFUNCTION ($ r, $г, $ б));Так что новый гекс - это 1 из предопределенного массива.

Надеюсь, вы поняли, потому что я понятия не имею, как это сделать, потому что не знаю алгоритм цвета.

Ответы [ 5 ]

16 голосов
/ 20 декабря 2010

Вы должны рассчитать расстояние до каждого цвета и выбрать наименьший.

Есть несколько способов сделать это.Простым методом будет вычисление расстояния:

sqrt((r-r1)^2+(g-g1)^2+(b-b1)^2)

Лучшим методом может быть включение взвешенных значений для вычисления расстояния, например, значений, используемых при преобразовании RGB-> YUV:

Y = 0.299 * R + 0.587 * G + 0.114 * B

в этом случае вы будете использовать

sqrt(((r - r1) * .299)^2 + ((g - g1) * .587)^2 + ((b - b1) * .114)^2)

Конечно, поскольку вам не нужны точные расстояния, просто сравнение, вы можете и, вероятно, просто пропустите квадратный корень,сделать последний расчет:

((r - r1) * .299)^2 + ((g - g1) * .587)^2 + ((b - b1) * .114)^2
11 голосов
/ 20 декабря 2010

Цветовое пространство RGB - это просто куб. В 24-битном цвете каждая сторона имеет длину 256, допуская значения от 0 до 255. Чтобы найти ближайший цвет внутри этого куба, вам нужна функция расстояния. Самым простым и интуитивно понятным является евклидово расстояние : если у вас есть цвет (r1, g1, b1) и другой цвет (r2, g2, b2), расстояние будет sqrt((r2-r1)^2 + (g2-g1)^2 + (b2-b1)^2).

Задача для вас состоит в том, чтобы найти наилучшее совпадение по всем значениям в вашем предварительно определенном массиве. Я предлагаю вам начать с перебора всех ваших значений и проверить расстояние для каждого по очереди. Обратите внимание, что для этой цели вам не нужно выполнять sqrt, достаточно просто сравнить сумму квадратов и получить преимущество, заключающееся в целочисленной математике. Мой PHP не очень хорош, но примерно вы бы сделали:

function dist($col1,$col2) {
  $delta_r = $col1[0] - $col2[0];
  $delta_g = $col1[1] - $col2[1];
  $delta_b = $col1[2] - $col2[2];
  return $delta_r * $delta_r + $delta_g * $delta_g + $delta_b * $delta_b;
} 

$closest=$colors[0];
$mindist=dist($rgb,$colors[0]);
$ncolors=sizeof($colors);
for($i = 1; $i < $ncolors; ++$i)
{
    $currdist = dist($rgb,$colors[$i]);
    if($currdist<$mindist) {
      $mindist=$currdist;
      $closest=$colors[$i];
    }
}

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

6 голосов
/ 09 марта 2016

Поскольку этот вопрос отображается в первой десятке результатов поиска goolge, вот более сложная функция, которую я написал несколько лет назад, которая давала лучшие результаты, чем существующие функции PHP.

1 голос
/ 20 декабря 2010

Рассчитайте расстояние от входного цвета до всех возможных кандидатов вашей палитры, а затем выберите тот, у которого наименьшее расстояние, в качестве того, на который его следует заменить.

Расстояние можно определить любым способом, который вам нравится;Евклидово расстояние кажется работоспособным для кубов RGB, цилиндров или конусов HSL / HSV.

0 голосов
/ 10 марта 2011

Нет смысла брать квадратный корень. Нахождение кратчайшего расстояния аналогично нахождению кратчайшего квадрата расстояния. sqrt - дорогостоящая операция, поэтому просто пропустите ее.

Конечно, действительно ли это имеет значение, зависит от того, как часто ваша программа будет выполнять эти вычисления, но все равно бессмысленно иметь их.

...