我想对一维颜色列表进行排序,以便典型人类彼此感觉“相似”的颜色彼此靠近。
显然,要获得“完美”是一个困难或可能不可能的问题,因为颜色通常用三维来描述,但这并不意味着没有一些分类方法看起来明显比其他方法更自然。 / p>
例如,按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的东西?
我还应该注意到,我知道我可以通过颜色立方体定义一个空间填充曲线,并按照沿着该曲线行进时遇到的一维顺序对它们进行排序。这将消除感知到的不连续性。但是,这不是我想要的;我想要比我想完美的小规模分组更好的整体大规模分组。
提前感谢您的帮助。
答案 0 :(得分:8)
如果要对一个维度中的颜色列表进行排序,首先必须根据要对其进行排序的指标进行排序。对我来说最有意义的是感知亮度(related question)。
我遇到了4种算法来按亮度对颜色进行排序并进行比较。结果如下。
我在循环中生成了颜色,其中仅使用了大约每400种颜色。每种颜色由2x2像素表示,颜色从最暗到最轻(从左到右,从上到下)排序。
第一张照片 - Luminance (relative)
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
第3张图片 - HSP Color Model
sqrt(0.299 * R^2 + 0.587 * G^2 + 0.114 * B^2)
4td图片 - WCAG 2.0 SC 1.4.3 relative luminance和contrast ratio公式
根据一行中的颜色数量,有时可以在第1张和第2张图片上看到图案。我从未在第3或第4算法的图片上发现任何图案。
如果我不得不选择我将使用算法3,因为它更容易实现,比第4快约33%
答案 1 :(得分:5)
如果不将3种颜色尺寸减少到单次测量,则无法执行此操作。有许多(无限)方法可以减少这些信息,但是在数学上不可能以确保减少的连续体上彼此靠近的两个数据点在它们的所有三种组件颜色中彼此接近的方式来实现这一点。值。因此,任何此类公式都可能最终将不同的颜色分组。
正如您在问题中提到的,一种方法是通过您尝试排序的数据点占用的三维颜色空间拟合复杂曲线,然后将每个数据点减少到它在曲线上最近的位置,然后沿着曲线到达该点的距离。这可行,但在每种情况下,它都是针对特定数据点集定制的解决方案(而不是通常适用的解决方案)。它也会相对昂贵(可能),并且根本不适用于不能以曲线方式很好地分布的数据集。
更简单的替代方案(不能完美地工作)将是选择两种“端点”颜色,最好是在色轮的相对两侧。因此,例如,您可以选择红色作为一种端点颜色,选择蓝色作为另一种颜色。然后,您将每个颜色数据点转换为0到1范围内的值,其中高度偏红的颜色将得到接近0的分数,高度偏蓝的颜色将获得接近1的分数。得分为。 5表示颜色中没有红色或蓝色(也称为绿色)或者具有等量的红色和蓝色(又名紫色)。这种方法并不完美,但这是你能解决这个问题的最佳方法。
答案 2 :(得分:4)
您可以采取两种方法。简单的方法是将每种颜色蒸馏成单个值,然后可以对值列表进行排序。复杂的方法取决于你必须排序的所有颜色;也许这将是一个迭代的解决方案,在试图最小化整个序列的“能量”的周围反复洗牌。
我的猜测是你想要一些看起来“足够好”的简单而快速的东西(而不是试图找出“最佳”的美学颜色),所以简单的方法就足够了。
我会说HSL是要走的路。像
这样的东西sortValue = L * 5 + S * 2 + H
假设H,S和L各自在[0,1]范围内。
答案 3 :(得分: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;
}
答案 4 :(得分:0)
这是我想出几分钟后想出来的想法。它可能是废话,或者甚至根本不起作用,但无论如何我都会吐出来。
在颜色空间d(x, y)
上定义距离函数(其中输入x
和y
是颜色,输出可能是浮点数)。您选择的距离函数可能不是非常重要。它可能是R,G和B分量差异的平方和,或者它可能是H,L和S分量差异的多项式(根据你觉得它们的重要程度不同地加权成分)是)。
然后,您可以计算列表中每种颜色的“距离”,从而有效地为您提供图表。接下来,您将计算图表的最小生成树。然后,您确定MST中存在的最长路径(没有回溯)。此路径的端点将是最终列表的端点。接下来,您尝试通过将路径中“分支”中的点放入路径本身,将树“平铺”成一条线。
嗯。如果您的MST最终以颜色空间中的近循环形状结束,那么这可能无法正常工作。但也许任何方法都会有这个问题。
答案 5 :(得分:0)
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,因此交换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
将其视为冒泡排序。这不是一个完美的算法,并且可能有更好的方法来解决这个问题,但这可能是朝着正确的方向发展的。
同时... 强>
你需要一些时髦的方式来比较你的主题。