使用十六进制格式的颜色列表/数组,如下所示:
[ "#fff000", "#238923", "#aaaaa0", "#ff2300", "#2ff014", "#010203" ]
这个想法是对它进行排序/组织,使红色的在前,绿色的在后,蓝色的在后。但这还不够,因为有色调和色调,我们的想法是它们以“彩色”方式组织:
- 蓝红色(红色是主要颜色,然后是蓝色)
- 红色(红色为主色,蓝色和绿色值相同)
- 绿红色(红色是主要颜色,然后是绿色)
- 红绿
- 绿色的
- 青绿色
- 蓝调
- 布鲁斯
- 红蓝调
如您所见,它就像一个“色环”,两端相交:我将蓝色放在绿色之前表示红色,将绿色放在红色之前表示蓝色。例如:#331122(蓝红色)会出现在#330000(红-红)之前,而#331100(绿红色)会出现在#331100(绿红色)之前。排序方案将是这样的:
R G B
-------- -------- --------
RB RR RG GR GG GB BG BB BR
所以上面的列表看起来像这样:
[ "#ff2300", "#fff000", "#aaaaa0", "#2ff014", "#238923", "#010203" ]
我不能在编程语言中使用现有的排序方法,因为它不是真正的正常排序,而且不会按字母顺序排列。这就是为什么必须独立考虑三种颜色的值。他必须自己做点什么。
所以我正在寻找一个答案:
- 为大量颜色提出理论解决方案。
- 还可以使用有限数量的颜色(25-50 可用于对分页表进行排序)。
- 高效(算法顺序) - 您是否应该考虑散列/存储桶?
请注意,我在此答案中提供的代码并非旨在成为解决方案,而只是为了探索一些想法。
最初的想法
首先想到的是将每种 RGB 颜色转换为 HSV(色相、饱和度、值)表示。在此表示中,“色调”组件告诉您它是什么颜色(该值是 0 到 360 之间的实数,表示角度,即颜色空间中虚向量的方向)。“S”分量是“饱和度”,它告诉您该颜色添加了多少白色。它是一个介于 0 和 1 之间的整数,其中 0 是最小饱和度(白色),1 是最大饱和度(没有白色,纯色)。最后,V 是亮度的“值”,表示有多少黑色与颜色混合(0 表示全黑,1 表示完全没有黑色,“纯”颜色)。
我认为通过以这种方式转换每种颜色并简单地对生成的三重奏排序,它们已经按“色度相似性”分组,因为我们将首先按色调(颜色)排序,在相同颜色的情况下按饱和度排序然后是亮度。
不幸的是,结果不是我所期望的。以下 python 代码用于生成一堆随机 RGB 十六进制值:
结果列表的一些元素:
这种颜色“调色板”的图形表示,按照它们生成的相同随机顺序,如下所示:
我用这段代码得到了这个表示,以防有人想复制它:
以下函数实现将其中一个值转换为 HSV 形式:
现在我们可以要求 Python
mil_colores
使用上述函数作为排序键对序列进行排序:已经排序的前十个元素是:
这以图形方式给出了这个稍微令人失望的结果:
我们可以看到,是的......或多或少它们已按颜色分组,能够欣赏上面橙色,下面紫色的“彩虹条”......但在每个条中,顺序似乎有点随机,应该以非常接近 HUE 的值,但不同的值或饱和度最终非常接近。
第二个想法
然后我意识到我们想要的是让附近的颜色最终在一起。这迫使我们定义颜色之间距离的概念。
最后的颜色只不过是三个坐标空间中的一个点:R、G、B。因此我们可以使用它们之间的欧几里得距离(每个坐标之间的距离平方和的根)。
尽管距离现在已经很好地定义了,但实现一种接近颜色最终在一起的排列基本上是旅行商问题的另一种形式。也就是说,我们必须找到一条所有点的路径,使行进距离最小。那次旅行将是所需的颜色顺序。
由于这个问题是 NP 难的,我已经放弃了实现它
更新。反射和启发式
经过一番思考,我得出的结论是,“按距离”排序实际上只是对它们进行排序的另一种方式,不一定是最好的,因为“最好”的概念在这里没有得到很好的定义。在“接近”类别中,颜色可以单独出现,而在另一种类别中会被认为是一起出现的,例如,非常深的红色可能会“与黑色”而不是“与红色”一起出现。哪个更好?
我认为底部的问题无法解决,因为它没有很好地定义。输入颜色集实际上可以在数学上理解为 3 维空间中的一组点(这将是其分量,RGB 或 HSV)。通过要求排序,基本上我们希望将其传递给单个维度。因此这是一个投影问题。
它有点等价于在平面上绘制地球球体表面的问题。没有单一的解决方案,因此有不同的制图投影,这取决于我们优先考虑的方面。一些投影很有用,因为它们通过保持角度恒定使导航更容易。其他人则保持国家/地区的面积不变,更有助于了解它们的相对大小等。
颜色排序也会发生类似的情况。如果所有颜色都是“纯色”(在 HSV 中它们将具有 S=1 和 V=1),它们的排序将很简单,仅基于它们的“色调”,它会是这样的:
但是,如果我们还有“柔和”颜色(饱和度降低,因此更接近白色)或“深色”颜色(亮度降低,因此更接近黑色),则无处可去。给它们上色。在刚刚看到的无可挑剔的色调排列中。
这个画框显示了制造商是如何解决这个问题的:
他做了两个抽屉。饱和颜色的顶部(按色调排序)和柔和色调的底部(也按色调排序)。“深色”颜色已根据其色调穿插。例如蓝调结尾处的深蓝色。这“打破”了美丽的彩虹,因为在深蓝色之后出现了更浅的绿蓝色。此外,它只考虑了两个饱和度(两个抽屉)。可能还有很多...
这种安排比另一种更好还是更差?同样,这取决于预期的目的。艺术家可能希望将具有相同色调的颜料放在一起,而很少关心颜色之间的“rgb 距离”是否与他盒子中颜料之间的距离相匹配。
简而言之,没有明确的标准可以让一种安排优于另一种安排。
综上所述,我提出了另一种启发式方法来订购基于以下的一千种随机颜色:
这是算法(python):
这是结果:
如果我使用一万种颜色而不是一千种颜色,结果会更令人印象深刻,从这个开始:
对此:
为了表明该算法也适用于几种颜色,这些是 Alvaro 提出的:
这是结果的顺序:
如果您首先了解几件事,那么您的问题比乍看起来更容易解决。
Los algoritmos de ordenamiento para esto son ampliamente conocidos y puedes escoger entre un gran número de ellos con ventajas y desventajas entre ellos. En todos los casos es necesario poder determinar cuando un elemento tiene más precedencia que otro. En esa parte es en la que debes concentrarte.
Para comparar debes saber una cosa primero y es que los colores no se pueden representar usando un "círculo de color" como pretendes pues dependiendo del formato a usar (en tu caso RGB) siempre son una figura geométrica tridimensional. En el caso de RGB se usa un cubo como este:
Es posible usar un cilindro para representarlo teniendo en cuenta un par de cosas:
Por ejemplo el rojo puro
FF0000
es exactamente igual a este otro rojo más oscuro#BE0000
. Esto es difícil de digerir a simple vista pero si lo representas con una imagen te darás cuenta que la única diferencia es que uno es más brillante que otro, o sea que el rojo puro se encuentra más arriba en el eje vertical del cilindro de colores.Rojo puro
Rojo oscuro
Si te fijas bien te darás cuenta que esta representación coincide más menos con el modelo HSL donde el color se expresa con grados formando un círculo. En realidad ni HSL ni HSV son cilindros tampoco sino figuras formadas por conos pero el hecho que puedan representarse de forma circular es suficiente para tus propósitos.
En ambos modelos se puede deducir un par de cosas:
El blanco
#FFFFFF
, el negro#000000
y los puros grises (igual valor deR
,G
yB
) son el mismo color variando por el brillo pero que no tienen afinidad por ningún componente en particular lo que cambia es su posición en el eje vertical de acuerdo al modelo escogido.Que existen colores que a simple vista parecen negros pero en realidad son rojos, verdes, etc, pero que son muy oscuros o claros para decirlo de una manera muy sobre-simplificada.
Que no puedes decidir por un sólo parámetro, el color, sino que debes tener en cuenta otros como luminosidad, chroma o valor de acuerdo al modelo escogido. El resultado final será diferente de acuerdo a tus preferencias.
Las prioridad de colores impuesta por tu problema requiere que el violeta puro (
#ff00ff
) se encuentre el primero en la lista y este se encuentra exactamente a los 300o grados de la circunferencia de color así que lo único que debes hacer para obtener los valores que deseas es rotar 60 grados la circunferencia en sentido contrario a las manecillas del reloj.Aquí te dejo el algoritmo:
Como ves la solución es bastante simple una vez que cambias el modelo mental y comparas usando los grados de una circunferencia en lugar de usar valores de color.
Si lo pruebas con los datos de @abulafia te das cuenta que hay violetas en ambos extremos pero que los menores son los violetas que tienen un mayor componente azul que es exactamente lo que pides.
Puedes mejorar los algoritmos, el punto que me ocupa es que entiendas cuales son las partes importantes. Yo use el sort de javascript que no tiene un algoritmo definido pero al menos en Chrome usará una variante de Merge Sort llamada TimSort. En otros navegadores puede que usen Insertion sort, el resultado es realmente variable.
理想情况下,您将能够将所有三个 HSL 值转换为单个整数或字符串,并使用比比较算法更快的整数算法,如基数排序。请注意,这需要对每个 HSL 值进行额外的转换步骤,因此您需要评估使用它是否真的有好处。对于非常大的集合,好处将是显而易见的。现实情况是,数据集(最佳、平均、最坏情况、大小等)会影响每种比较算法的性能,因此您必须决定要使用哪一种。没有万无一失的答案,只有速度、复杂性和内存消耗等优点和缺点。