在一个维度上对颜色列表进行排序?

17

我想对一个一维颜色列表进行排序,以便人们通常认为相似的颜色彼此靠近。

显然,这是一个难以或者说不可能完美解决的问题,因为颜色通常用三个维度来描述,但这并不意味着没有一些排序方法比其他方法更自然。

例如,按照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
我们大概需要多少种颜色?您需要一个算法,还是基于表格或桶的方法就足够了? - Swingline Rage
5个回答

11
如果您想在一维中对颜色列表进行排序,首先必须决定按什么指标进行排序。对我来说,最有意义的是感知亮度(相关问题)。
我找到了4种按亮度排序颜色的算法并进行了比较。这是结果。
我循环生成颜色,每400个颜色使用一次。每种颜色由2x2个像素表示,颜色从最暗到最亮排序(从左到右,从上到下)。
第一张图片 - 相对亮度
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图片 - WCAG 2.0 SC 1.4.3 相对亮度对比度比例 公式

根据一行中颜色数量的不同,第一张和第二张图片有时会出现模式。我从第三个或第四个算法生成的图片中从未发现过任何模式。

如果我必须选择,我会选择第三个算法,因为它更容易实现,速度比第四个算法快约33%。

Perceived brightness algorithm comparison


6

有几种标准技术可以将多个维度缩减为单个维度,并具有某种“接近度”概念。

我认为你应该特别查看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;
    }

1
值得注意的是,这种方法也非常快,因为您可以使用位运算来实现它。 - mikera
1
值得注意的是,希尔伯特曲线可能是一个很好的替代方案。 - mikera
虽然已经很晚了,但对于那些更好奇希尔伯特曲线如何释放到颜色排序的人,请参见(特别是名为“希尔伯特排序”的部分)http://www.alanzucconi.com/2015/09/30/colour-sorting/。 - Zimm3r
惊人的结果。 - Déjà vu

6
您不能不将三个颜色维度缩减为单一测量而达成此目的。有许多(无限)方法可以减少这些信息,但从数学上讲,无法以确保在缩小的连续体上相邻两个数据点的所有三个组成颜色值均相近的方式来进行此操作。因此,任何此类公式都可能会将不相似的颜色分组在一起。
正如您在问题中提到的,一种进行此类操作的方法是通过您尝试排序的数据点所占据的三维颜色空间拟合一个复杂的曲线,然后将每个数据点缩小到其在曲线上最近的位置,再缩小到该位置沿曲线的距离。这种方法是可行的,但在每种情况下,它都是针对特定数据点集量身定制的解决方案(而不是普遍适用的解决方案)。它也可能相对昂贵,并且在数据集没有以弯曲线形式分布的情况下根本无法使用。
更简单的替代方法(无法完美运作)是选择两种“端点”颜色,最好分别位于色轮的两侧。例如,您可以选择红色作为一个端点颜色,蓝色作为另一个端点颜色。然后,将每个颜色数据点转换为从0到1的比例值,其中高度红色的颜色得分接近于0,而高度蓝色的颜色得分接近于1。得分为0.5表示颜色中既没有红色也没有蓝色(又名绿色),或者红色和蓝色的数量相等(又名紫色)。这种方法不是完美的,但对于此问题,它是您能够做到的最好的办法。

5
有两种方法可以采用。简单的方法是将每个颜色提炼成一个单一的值,然后可以对这些值进行排序。复杂的方法取决于您需要排序的所有颜色;也许这将是一个迭代解决方案,不断地重新排列颜色,试图最小化整个序列的“能量”。
我猜你想要的是一些简单快速的东西,看起来“足够好”(而不是试图找出“最佳”的美学颜色排序),所以简单的方法就足够了。
我会选择HSL。类似这样:
sortValue = L * 5 + S * 2 + H

假设H、S和L都在[0, 1]范围内。

2
你是自己想出来的还是有参考资料可以给我? - Sander

1

这是我思考了几分钟后想出来的一个点子。它可能很糟糕,甚至可能根本行不通,但我还是要说出来。

在颜色空间上定义一个距离函数d(x, y)(其中输入xy是颜色,输出可能是一个浮点数)。你选择的距离函数可能并不是非常重要。它可以是R、G和B分量差的平方和,或者它可以是H、L和S分量差的多项式(根据你认为它们的重要性来不同加权)。

然后,你计算每个颜色在列表中与其他颜色之间的“距离”,这实际上给你一个图。接下来,计算图的最小生成树。然后,识别出你的MST中存在的最长路径(没有回溯)。这条路径的端点将成为最终列表的端点。接下来,你尝试通过将路径之外的“分支”点引入路径本身,将树“展平”成一条线。

嗯,如果你的MST以近似环形的形状结束,这种方法可能效果不佳。但也许任何方法都会遇到这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接