新的iTunes 11有一个非常好的查看专辑歌曲列表的视图,在专辑封面的功能中为字体和背景选择颜色。有人知道算法是怎么运作的吗?
我以专辑封面作为输入,在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}}),但我返回了一个Mathematica RGBColor元素,以更好地近似内置的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[]}]
笔记
The algorithm can be applied very generally. I tweaked the above settings and tolerance values to the point where they work to produce generally correct colors for ~80% of the album covers I tested. A few edge cases occur when DominantColorsNew doesn't find two colors to return for the highlights (i.e. when the album cover is monochrome). My algorithm doesn't address these cases, but it would be trivial to duplicate iTunes' functionality: when the album yields less than two highlights, the title becomes white or black depending on the best contrast with the background. Then the songs become the one highlight color if there is one, or the title color faded into the background a bit.
更多的例子
根据@Seth-thompson的回答和@bluedog的评论,我建立了一个小的Objective-C (Cocoa-Touch)项目来生成图像功能的配色方案。
你可以在以下网址查看项目:
https://github.com/luisespinoza/LEColorPicker
目前,LEColorPicker正在做:
Image is scaled to 36x36 px (this reduce the compute time). It generates a pixel array from the image. Converts the pixel array to YUV space. Gather colors as Seth Thompson's code does it. The color's sets are sorted by count. The algorithm select the three most dominant colors. The most dominant is asigned as Background. The second and third most dominants are tested using the w3c color contrast formula, to check if the colors has enought contrast with the background. If one of the text colors don't pass the test, then is asigned to white or black, depending of the Y component.
现在,我将检查ColorTunes项目(https://github.com/Dannvix/ColorTunes)和Wade Cosgrove项目的新功能。对于提高配色效果,我也有一些新的想法。
我在不同的上下文中问了同样的问题,并被指向http://charlesleifer.com/blog/using-python-and-k-means-to-find-the-dominant-colors-in-images/的一个学习算法(k Means),它使用图像中的随机起点大致做同样的事情。这样,算法就能自己找到主色调。
根据@Seth的回答,我使用PHP和Imagick实现了在图片的两个横向边界中获得主色调的算法。
https://gist.github.com/philix/5688064#file-simpleimage-php-L81
它被用来填充http://festea.com.br封面照片的背景
我只是写了一个JS库,实现了@Seth所描述的大致相同的算法。可以在github.com/arcanis/colibrijs和NPM上以colibrijs的形式免费获得。
推荐文章
- 滑动删除和“更多”按钮(就像iOS 7的邮件应用程序)
- 如何计算圆周长上的一点?
- 从整数流中找到运行中位数
- 在日历应用程序中建模重复事件的最佳方法是什么?
- 在任何情况下,您更喜欢高大o时间复杂度算法而不是低大o时间复杂度算法吗?
- 如何使用JavaScript比较软件版本号?数量(只)
- 跳跃表vs.二叉搜索树
- 如何使四舍五入百分比加起来为100%
- 是否有可能得到一个函数的所有参数作为单一对象内的函数?
- LL和LR解析之间的区别是什么?
- log(n!) = Θ(n·log(n))?
- C语言中位反转的高效算法(从MSB->LSB到LSB->MSB)
- 递归还是迭代?
- 两个长度不等的表之间的排列
- 保存图标:还是软盘?