新的iTunes 11有一个非常好的查看专辑歌曲列表的视图,在专辑封面的功能中为字体和背景选择颜色。有人知道算法是怎么运作的吗?
我以专辑封面作为输入,在Mathematica中近似地使用了iTunes 11的颜色算法:
经过反复试验,我想出了一个算法,它适用于我测试过的80%的专辑。
该算法的主要工作是寻找图像的主色调。然而,找到主色的先决条件是计算两种颜色之间的可量化差异。计算两种颜色之间差异的一种方法是计算它们在RGB颜色空间中的欧几里得距离。然而,人类的颜色感知与RGB颜色空间中的距离并不是很匹配。
因此,我写了一个函数将RGB颜色(以{1,1,1}的形式)转换为YUV,这是一个更好地近似颜色感知的颜色空间:
{1,1,1}
(编辑:@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使用的算法。我写了自己的函数…
DominantColors
计算一组像素中主色的一个简单方法是将所有像素收集到颜色相似的桶中,然后找到最大的桶。
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函数。
.1
\{\{1,1,1},{0,0,0}}
RGBColor
我的实际函数DominantColorsNew添加了在过滤掉给定的其他颜色后返回到n主色的选项。它还暴露了每种颜色比较的公差:
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) &减少细节与双边过滤器
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是主色和背景色之间的最小差异(值越高,颜色组合的对比度越高)。
.2
.5
瞧!
Graphics[{background, Disk[]}] Graphics[{title, Disk[]}] Graphics[{songs, Disk[]}]
该算法具有广泛的适用性。我调整了上面的设置和容差值,使它们在我测试的80%的专辑封面上产生了一般正确的颜色。当DominantColorsNew没有找到两种颜色作为亮点返回时(即当专辑封面是单色时),会出现一些边缘情况。我的算法并没有解决这些情况,但复制iTunes的功能是微不足道的:当专辑产生的亮点少于两个时,标题会变成白色或黑色,这取决于与背景的最佳对比。然后,如果有的话,歌曲就变成了一个突出的颜色,或者标题颜色褪色到背景中。
你也可以签出ColorTunes,它是Itunes相册视图的HTML实现,它使用MMCQ(中值剪切颜色量化)算法。
Panic的Wade Cosgrove写了一个不错的博文,描述了他的算法实现,近似于iTunes中的算法。它包括Objective-C中的一个示例实现。
根据@Seth-thompson的回答和@bluedog的评论,我建立了一个小的Objective-C (Cocoa-Touch)项目来生成图像功能的配色方案。
你可以在以下网址查看项目:
https://github.com/luisespinoza/LEColorPicker
目前,LEColorPicker正在做:
那就是现在,我将检查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的形式免费获得。
colibrijs