Продолжение: «Сортировка» цветов по различимости.

Исходный вопрос

Если вам даны N максимально удаленных цветов (и некоторая соответствующая метрика расстояния), можете ли вы придумать способ отсортировать эти цвета в некотором порядке, чтобы первые M также были достаточно близки к тому, чтобы быть максимально отличным набором?

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

Рандомизация - это нормально, но, конечно, не оптимально.

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

Ответов (9)

Эта проблема называется квантованием цвета и имеет много хорошо известных алгоритмов: http://en.wikipedia.org/wiki/Color_quantization Я знаю людей, которые реализовали подход октодерева с хорошим эффектом.

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

Вы можете просто отсортировать цвета-кандидаты на основе максимального или минимального расстояния до любого из цветов индекса.

Используя евклидово цветовое расстояние:

public double colordistance(Color color0, Color color1) {
    int c0 = color0.getRGB();
    int c1 = color1.getRGB();
    return distance(((c0>>16)&0xFF), ((c0>>8)&0xFF), (c0&0xFF), ((c1>>16)&0xFF), ((c1>>8)&0xFF), (c1&0xFF));
}

public double distance(int r1, int g1, int b1, int r2, int g2, int b2) {
    int dr = (r1 - r2);
    int dg = (g1 - g2);
    int db = (b1 - b2);
    return Math.sqrt(dr * dr + dg * dg + db * db);
}

Хотя вы можете заменить его чем угодно. Ему просто нужна процедура цветового расстояния.

public void colordistancesort(Color[] candidateColors, Color[] indexColors) {
    double current;

    double distance[] = new double[candidateColors.length];
    for (int j = 0; j < candidateColors.length; j++) {
        distance[j] = -1;
        for (int k = 0; k < indexColors.length; k++) {
            current = colordistance(indexColors[k], candidateColors[j]);
            if ((distance[j] == -1) || (current < distance[j])) {
                distance[j] = current;
            }
        }
    }

    //just sorts.
    for (int j = 0; j < candidateColors.length; j++) {
        for (int k = j + 1; k < candidateColors.length; k++) {
            if (distance[j] > distance[k]) {
                double d = distance[k];
                distance[k] = distance[j];
                distance[j] = d;

                Color m = candidateColors[k];
                candidateColors[k] = candidateColors[j];
                candidateColors[j] = m;
            }
        }
    }
}

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

Например, вот один из способов сделать то, что вы хотите.

  1. Рассчитайте расстояние (см. Другой пост ) от каждого цвета до всех остальных цветов.
  2. Суммируйте расстояния для каждого цвета, это дает вам представление о том, насколько далеко этот цвет от всех остальных цветов в целом.
  3. Упорядочить список по расстоянию, спускаясь вниз

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

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

Вы имеете в виду, что из набора N цветов вам нужно выбрать M цветов, где M <N, таким образом, чтобы M было наилучшим представлением N цветов в пространстве M?

В качестве лучшего примера уменьшите истинный цвет (24-битное цветовое пространство) до 8-битного отображаемого цветового пространства (GIF?).

Для этого существуют алгоритмы квантования, такие как алгоритм Adaptive Spatial Subdivision , используемый ImageMagic.

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

Если вам нужно что-то еще, то я не понял вашего вопроса :)

Вы можете разделить их в формате RGB HEX, чтобы вы могли сравнить R с R другого цвета, то же самое с G и B.

Тот же формат, что и HTML

XX XX XX
RR GG BB

00 00 00 = black
ff ff ff = white
ff 00 00 = red
00 ff 00 = green
00 00 ff = blue

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

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

Преобразование в sRGB и обратно может быть проблемой, но в вашем случае это действительно может упростить алгоритм, и в качестве бонуса он в основном будет работать и для дальтоников!

Если я правильно понимаю вопрос, вы хотите получить подмножество M цветов с наибольшим средним расстоянием между цветами, учитывая некоторую функцию расстояния d .

Другими словами, рассматривая исходный набор из N цветов как большой неориентированный граф, в котором все цвета связаны, вы хотите найти самый длинный путь, который посещает любые M узлов.

Боюсь, что решение проблем с NP-полным графом намного выше моих возможностей, но вы можете попробовать запустить простую физическую симуляцию:

  1. Сгенерировать M случайных точек в цветовом пространстве
  2. Рассчитайте расстояние между каждой точкой
  3. Рассчитайте векторы отталкивания для каждой точки, которая будет перемещать ее от всех других точек (используя 1 / ( расстояние ^ 2) в качестве величины вектора)
  4. Суммируйте векторы отталкивания для каждой точки
  5. Обновите положение каждой точки в соответствии с суммированными векторами отталкивания
  6. Ограничьте любые координаты за пределами границ (например, отрицательную или большую яркость)
  7. Повторите с шага 2, пока точки не стабилизируются.
  8. Для каждой точки выберите ближайший цвет из исходного набора N

Это далеко не эффективно, но для малых M может быть достаточно эффективным и даст почти оптимальные результаты.

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

  1. Начнем с двух списков. CandidateColors, который изначально содержит ваши отдельные цвета, и SortedColors, который изначально пуст.
  2. Выберите любой цвет, удалите его из CandidateColors и поместите в SortedColors. Это первый цвет, который будет наиболее распространенным, так что это хорошее место для выбора цвета, который хорошо сочетается с вашим приложением.
  3. Для каждого цвета в CandidateColors рассчитайте его общее расстояние. Общее расстояние - это сумма расстояний от CandidateColor до каждого из цветов в SortedColors.
  4. Удалите цвет с наибольшим общим расстоянием от CandidateColors и добавьте его в конец SortedColors.
  5. Если CandidateColors не пустой, вернитесь к шагу 3.

Этот жадный алгоритм должен дать вам хорошие результаты.