Сортировка списка цветов в одном измерении?

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

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

Например, сортировка по RGB работает не очень хорошо, поскольку она будет сортироваться в следующем порядке, например:

(1) R = 254 G = 0 B = 0 (2) R = 254 G = 255 B = 0 (3) R = 255 G = 0 B = 0 (4) R = 255 G = 255 B = 0

Таким образом, он будет чередовать цвета красного, желтого, красного, желтого цветов, причем два "красных" по существу безукоризненно отличаются друг от друга, а два желтых также невероятно отличаются друг от друга.

Но сортировка по HLS работает намного лучше, вообще говоря, и я думаю, что HSL даже лучше этого; с или красным будет рядом друг с другом, а желтые будут рядом друг с другом.

Но у HLS/HSL есть некоторые проблемы; вещи, которые люди воспринимают как "черные", могут быть разделены далеко друг от друга, как и вещи, которые люди воспринимают как "белые".

Опять же, я понимаю, что я в значительной степени должен признать, что будут такие расколы, как это; Мне просто интересно, нашел ли кто-нибудь лучший способ, чем HLS/HSL. И я знаю, что "лучше" несколько произвольно; Я имею в виду "более естественное для обычного человека".

Например, неопределенная мысль, которую я имел, но еще не пробовал, возможно, "L - это самое главное, если она очень высокая или очень низкая", но в остальном это наименее важно. Кто-нибудь пробовал это? Хорошо ли это работает? Что конкретно вы выбрали "очень низкий" и "очень высокий"? И так далее. Или кто-нибудь нашел что-нибудь еще, что улучшило бы HSL?

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

Заранее благодарим за помощь.

Ответы

Ответ 1

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

Я наткнулся на 4 алгоритма, чтобы сортировать цвета по яркости и сравнивать их. Вот результат.

Я генерировал цвета в цикле, где использовался только примерно каждый 400-й цвет. Каждый цвет представлен 2x2 пикселями, цвета сортируются от самого темного до легкого (слева направо, сверху вниз).

1-е изображение - Яркость (относительная)

0.2126 * R + 0.7152 * G + 0.0722 * B

Второе изображение - http://www.w3.org/TR/AERT#color-contrast

0.299 * R + 0.587 * G + 0.114 * B

Третье изображение - Цветная модель HSP

sqrt(0.299 * R^2 + 0.587 * G^2 + 0.114 * B^2)

4td picture - WCAG 2.0 SC 1.4.3 относительная яркость и коэффициент контрастности

Шаблон может быть замечен на 1-м и 2-м снимках в зависимости от количества цветов в одной строке. Я никогда не видел ни одной картины на картинке с третьего или четвертого алгоритма.

Если бы мне пришлось выбирать, я бы пошел с алгоритмом номер 3, так как его намного проще реализовать и его примерно на 33% быстрее, чем 4-й

Perceived brightness algorithm comparison

Ответ 2

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

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

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

Ответ 3

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

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

Я бы сказал, что HSL - это путь. Что-то вроде

sortValue = L * 5 + S * 2 + H

предполагая, что H, S и L находятся в диапазоне [0, 1].

Ответ 4

Существует несколько стандартных методов для сокращения нескольких измерений до одного измерения с некоторым понятием "близость".

Я думаю, вы должны, в частности, проверить z-order transform.

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

Следующий код Java должен помочь вам начать работу:

    public static int zValue(int r, int g, int b) {
            return split(r) + (split(g)<<1) + (split(b)<<2);
    }

    public static int split(int a) {
            // split out the lowest 10 bits to lowest 30 bits
            a=(a|(a<<12))&00014000377;
            a=(a|(a<<8)) &00014170017;
            a=(a|(a<<4)) &00303030303;
            a=(a|(a<<2)) &01111111111;
            return a;
    }

Ответ 5

Вот идея, с которой я придумал пару минут. Это может быть дерьмо, или это может даже не работать вообще, но я все равно выплюнул.

Определите функцию расстояния в пространстве цветов, d(x, y) (где входы x и y являются цветами, а выход, возможно, является числом с плавающей запятой). Функция расстояния, которую вы выбираете, может быть не очень важна. Это может быть сумма квадратов различий в компонентах R, G и B, скажем, или это может быть многочлен от различий в компонентах H, L и S (с компонентами, по-разному взвешенными в зависимости от того, насколько важно вы чувствуете, что они есть).

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

Хм. Возможно, это не сработает, если ваш MST окажется в форме ближнего цикла в цветовом пространстве. Но, возможно, любой подход будет иметь эту проблему.

Ответ 6

 A. R=254 G=0 B=0
 B. R=254 G=255 B=0
 C. R=255 G=0 B=0
 D. R=255 G=255 B=0

Вам нужно посмотреть разницу между соседними цветами.

Разница между A и B равна 0 + 255 + 0 = 255. Разница между A и C равна 1 + 0 + 0 = 1.

Разница между A и B больше, чем A и C, поэтому A ближе к C, поэтому swap B и C.

 A. R=254 G=0 B=0 
 C. R=255 G=0 B=0
 B. R=254 G=255 B=0
 D. R=255 G=255 B=0

Разница между C и B равна 1 + 255 + 0 = 256. Разница между C и D равна 0 + 255 + 0 = 255.

Разница между C и B больше, чем C и D, поэтому C ближе к D, поэтому меняйте B и D.

A. R=254 G=0 B=0 
C. R=255 G=0 B=0
D. R=255 G=255 B=0
B. R=254 G=255 B=0

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

Также...

Вам понадобится какой-нибудь смешной способ сравнения по вашему предмету.