新的 iTunes 11 有一个非常好的专辑歌曲列表视图,在专辑封面功能中为字体和背景选择颜色。有人知道算法是如何工作的吗?
7 回答
给定专辑封面作为输入,我在 Mathematica 中近似了 iTunes 11 颜色算法:
我是怎么做到的
通过反复试验,我提出了一种算法,该算法适用于我测试过的大约 80% 的专辑。
颜色差异
该算法的大部分处理寻找图像的主色。然而,找到主色的先决条件是计算两种颜色之间的可量化差异。计算两种颜色之间差异的一种方法是计算它们在 RGB 颜色空间中的欧几里得距离。然而,人类的颜色感知与 RGB 颜色空间中的距离并不能很好地匹配。
因此,我编写了一个函数来将 RGB 颜色(以 形式{1,1,1}
)转换为YUV,这是一种在近似颜色感知方面要好得多的颜色空间:
(编辑:@cormullion和@Drake指出 Mathematica 的内置 CIELAB 和 CIELUV 颜色空间同样适用……看起来我在这里重新发明了轮子)
convertToYUV[rawRGB_] :=
Module[{yuv},
yuv = {{0.299, 0.587, 0.114}, {-0.14713, -0.28886, 0.436},
{0.615, -0.51499, -0.10001}};
yuv . rawRGB
]
接下来,我编写了一个函数来使用上述转换计算颜色距离:
ColorDistance[rawRGB1_, rawRGB2_] :=
EuclideanDistance[convertToYUV @ rawRGB1, convertToYUV @ rawRGB2]
主色
我很快发现内置的 Mathematica 函数DominantColors
不允许足够细粒度的控制来近似 iTunes 使用的算法。我写了自己的函数......
计算一组像素中的主色的一种简单方法是将所有像素收集到颜色相似的桶中,然后找到最大的桶。
DominantColorSimple[pixelArray_] :=
Module[{buckets},
buckets = Gather[pixelArray, ColorDistance[#1,#2] < .1 &];
buckets = Sort[buckets, Length[#1] > Length[#2] &];
RGBColor @@ Mean @ First @ buckets
]
请注意,这.1
是必须将不同颜色视为不同颜色的容差。另请注意,虽然输入是原始三元组形式 ( ) 的像素数组,但{{1,1,1},{0,0,0}}
我返回一个 MathematicaRGBColor
元素以更好地逼近内置DominantColors
函数。
我的实际功能添加了在过滤掉给定的其他颜色后DominantColorsNew
返回主色的选项。n
它还公开了每种颜色比较的公差:
DominantColorsNew[pixelArray_, threshold_: .1, n_: 1,
numThreshold_: .2, filterColor_: 0, filterThreshold_: .5] :=
Module[
{buckets, color, previous, output},
buckets = Gather[pixelArray, ColorDistance[#1, #2] < threshold &];
If[filterColor =!= 0,
buckets =
Select[buckets,
ColorDistance[ Mean[#1], filterColor] > filterThreshold &]];
buckets = Sort[buckets, Length[#1] > Length[#2] &];
If[Length @ buckets == 0, Return[{}]];
color = Mean @ First @ buckets;
buckets = Drop[buckets, 1];
output = List[RGBColor @@ color];
previous = color;
Do[
If[Length @ buckets == 0, Return[output]];
While[
ColorDistance[(color = Mean @ First @ buckets), previous] <
numThreshold,
If[Length @ buckets != 0, buckets = Drop[buckets, 1],
Return[output]]
];
output = Append[output, RGBColor @@ color];
previous = color,
{i, n - 1}
];
output
]
算法的其余部分
首先,我调整了专辑封面 ( 36px
, 36px
) 的大小并使用双边过滤器减少了细节
image = Import["http://i.imgur.com/z2t8y.jpg"]
thumb = ImageResize[ image, 36, Resampling -> "Nearest"];
thumb = BilateralFilter[thumb, 1, .2, MaxIterations -> 2];
iTunes 通过查找专辑边缘的主要颜色来选择背景颜色。但是,它通过裁剪图像忽略了狭窄的专辑封面边框。
thumb = ImageCrop[thumb, 34];
接下来,我沿着图像的最外边缘找到了主色(使用上面的新函数),默认容差为.1
.
border = Flatten[
Join[ImageData[thumb][[1 ;; 34 ;; 33]] ,
Transpose @ ImageData[thumb][[All, 1 ;; 34 ;; 33]]], 1];
background = DominantColorsNew[border][[1]];
最后,我在整个图像中返回了 2 种主色,告诉函数也过滤掉背景色。
highlights = DominantColorsNew[Flatten[ImageData[thumb], 1], .1, 2, .2,
List @@ background, .5];
title = highlights[[1]];
songs = highlights[[2]];
上面的公差值如下:.1
是“分离”颜色之间的最小差异;.2
是众多主色之间的最小差异(较低的值可能会返回黑色和深灰色,而较高的值可确保主色的更多多样性);.5
是主色和背景之间的最小差异(较高的值将产生较高对比度的颜色组合)
瞧!
Graphics[{background, Disk[]}]
Graphics[{title, Disk[]}]
Graphics[{songs, Disk[]}]
笔记
该算法可以非常普遍地应用。我调整了上述设置和容差值,使其能够为我测试的大约 80% 的专辑封面生成通常正确的颜色。当DominantColorsNew
没有找到两种颜色来返回高亮时(即专辑封面是单色时),会出现一些边缘情况。我的算法没有解决这些情况,但复制 iTunes 的功能将是微不足道的:当专辑产生少于两个亮点时,标题会根据与背景的最佳对比度变为白色或黑色。然后歌曲成为一种突出显示颜色(如果有的话),或者标题颜色稍微淡入背景。
更多示例
在@Seth-thompson 的回答和@bluedog 的评论下,我构建了一个小的Objective-C(Cocoa-Touch)项目来生成图像功能的配色方案。
您可以在以下位置查看项目:
https://github.com/luisespinoza/LEColorPicker
目前,LEColorPicker 正在做:
- 图像缩放为 36x36 像素(这减少了计算时间)。
- 它从图像生成像素阵列。
- 将像素数组转换为 YUV 空间。
- 像 Seth Thompson 的代码那样收集颜色。
- 颜色的集合按计数排序。
- 该算法选择三种最主要的颜色。
- 最主要的被指定为背景。
- 使用 w3c 颜色对比度公式测试第二和第三个主要颜色,以检查颜色是否与背景有足够的对比度。
- 如果其中一种文本颜色未通过测试,则根据 Y 分量分配为白色或黑色。
就目前而言,我将检查 ColorTunes 项目 ( https://github.com/Dannvix/ColorTunes ) 和 Wade Cosgrove 项目的新功能。我也有一些改进配色方案结果的新想法。
Panic 的 Wade Cosgrove 写了一篇不错的博客文章,描述了他实现的一种算法,该算法近似于 iTunes 中的算法。它包括一个在 Objective-C 中的示例实现。
您还可以查看ColorTunes,它是使用 MMCQ(中值剪切颜色量化)算法的 Itunes 专辑视图的 HTML 实现。
我刚刚编写了一个 JS 库,实现了与@Seth描述的算法大致相同的算法。它在github.com/arcanis/colibrijs和 NPM上免费提供colibrijs
。
通过@Seth 的回答,我实现了算法,以使用 PHP 和 Imagick 在图片的两个横向边框中获取主色。
https://gist.github.com/philix/5688064#file-simpleimage-php-L81
我在不同的上下文中问了同样的问题,并被指向http://charlesleifer.com/blog/using-python-and-k-means-to-find-the-dominant-colors-in-images/使用图像中的随机起点粗略地做同样事情的学习算法(k 均值)。这样,算法就可以自行找到主色。