导语
上一篇,我们用很长篇幅解释了运行的方式和逻辑,但是没有涉及到是如何筛选匹配出合适的颜色
这一篇重点就说Palette 是如何去匹配颜色的
问题
1.Palette 是如何给出各种颜色模式的,是根据什么规则去返回的
2.Palette 为什么会返回空的Swatch ,什么情况下会返回
代码解析
看看Palette 是如何匹配颜色的,先看看generateScoredTarget方法
private Swatch generateScoredTarget(final Target target) {
final Swatch maxScoreSwatch = getMaxScoredSwatchForTarget(target);
if (maxScoreSwatch != null && target.isExclusive()) {
mUsedColors.append(maxScoreSwatch.getRgb(), true);
}
return maxScoreSwatch;
}
这里能看到关键代码是getMaxScoredSwatchForTarget() 方法
其中mUsedColors 是Palette 用来记录某一个颜色是否已经被处理过
现在看看getMaxScoredSwatchForTarget()
@Nullable
private Swatch getMaxScoredSwatchForTarget(final Target target) {
float maxScore = 0;
Swatch maxScoreSwatch = null;
for (int i = 0, count = mSwatches.size(); i < count; i++) {
final Swatch swatch = mSwatches.get(i);
if (shouldBeScoredForTarget(swatch, target)) {
final float score = generateScore(swatch, target);
if (maxScoreSwatch == null || score > maxScore) {
maxScoreSwatch = swatch;
maxScore = score;
}
}
}
return maxScoreSwatch;
}
在这里,Palette 遍历了所有的Swatch ,并且使用shouldBeScoredForTarget 方法对target 进行筛选
我们能看到target 使用了很多参数值
为了简略后续的描述
我们如下定义
target 对应方法名 | 简略名 | 解释 |
---|---|---|
getMinimumSaturation | S[min] | 指的是饱和度最小值 |
getTargetSaturation | S[target] | 值得是饱和度目标值 |
getMaximumSaturation | S[max] | 饱和度最大值 |
getMinimumLightness | L[min] | 指的是明度最小值 |
getTargetLightness | L[target] | 值得是明度目标值 |
getMaximumLightness | L[max] | 明度最大值 |
getSaturationWeight | W[S] | 是指明度权重 |
getLightnessWeight | W[L] | 指亮度权重 |
getPopulationWeight | W[POP] | 指加值权重 |
private boolean shouldBeScoredForTarget(final Swatch swatch, final Target target) {
final float hsl[] = swatch.getHsl();
return hsl[1] >= target.getMinimumSaturation() && hsl[1] <= target.getMaximumSaturation()
&& hsl[2] >= target.getMinimumLightness() && hsl[2] <= target.getMaximumLightness()
&& !mUsedColors.get(swatch.getRgb());
}
很简单,比对这个颜色是否处于 target ,S 和 L 的最大和最小颜色范围内,并且此颜色没有被使用过(mUsedColors)
然后调用generateScore 开始进行分值计算
private float generateScore(Swatch swatch, Target target) {
final float[] hsl = swatch.getHsl();
float saturationScore = 0;
float luminanceScore = 0;
float populationScore = 0;
final int maxPopulation = mDominantSwatch != null ? mDominantSwatch.getPopulation() : 1;
if (target.getSaturationWeight() > 0) {
saturationScore = target.getSaturationWeight()
* (1f - Math.abs(hsl[1] - target.getTargetSaturation()));
}
if (target.getLightnessWeight() > 0) {
luminanceScore = target.getLightnessWeight()
* (1f - Math.abs(hsl[2] - target.getTargetLightness()));
}
if (target.getPopulationWeight() > 0) {
populationScore = target.getPopulationWeight()
* (swatch.getPopulation() / (float) maxPopulation);
}
return saturationScore + luminanceScore + populationScore;
}
这段代码可以分三份理解,
计算S(明度) 和L(亮度)的分值
** W[S/L] x(1 - 当前颜色和目标的差值)**
根据公式可以得出,权重相同的情况下,明度/亮度和目标差值差距越小,越符合,得分越高
另外还有一个浮动加权
在上一篇帖子中有提到 在Palette 创建的时候调用findDominantSwatch 计算到的,整个图片中出现最多的颜色值,所以maxPopulation 这个参数值在这里指的是出现颜色最多的个数
所以populationScore 最终是 由
W[POP] x(当前颜色的个数除最多的颜色)
得出的
也就是说,当前颜色在图片中出现越多,在权重恒定的情况下 得出的分值越高
最终的结果是将此Swatch 计算出来的分值返回出去
在getMaxScoredSwatchForTarget 方法中,将找到分值最大的Swatch 返回出去,作为target 的结果
以上,是整个target 的计算过程也就完成,这里整理出一份Palette 各个Target 的默认值提供参考
target | S[min] | S[target] | S[max] | L[min] | L[target] | L[max] | W[S] | W[L] | W[POP] |
---|---|---|---|---|---|---|---|---|---|
lightVibrant | 0.35 | 1 | 1 | 0.55 | 0.74 | 1 | 0.24 | 0.52 | 0.24 |
vibrant | 0.35 | 1 | 1 | 0.3 | 0.5 | 0.7 | 0.24 | 0.52 | 0.24 |
darkVibrant | 0.35 | 1 | 1 | 0 | 0.26 | 0.45 | 0.24 | 0.52 | 0.24 |
lightMuted | 0 | 0.3 | 0.4 | 0.55 | 0.74 | 1 | 0.24 | 0.52 | 0.24 |
muted | 0 | 0.3 | 0.4 | 0.3 | 0.5 | 0.7 | 0.24 | 0.52 | 0.24 |
darkMuted | 0 | 0.3 | 0.4 | 0 | 0.26 | 0.45 | 0.24 | 0.52 | 0.24 |
疑问回答
1.Palette 是如何给出各种颜色模式的,是根据什么规则去返回的
答:根据各个明度 亮度 值,通过和和预设目标值的差计算出总分,最终得分高则返回出去
2.Palette 为什么会返回空的Swatch ,什么情况下会返回
答:在代码中能发现,getMaxScoredSwatchForTarget() 方法在遍历时,有可能没有找到在预设范围内的颜色值这种结果下可能会返回空的Swatch
Palette 运行总结
扩展
-
根据系统默认的几种模式,都没有给出权重部分的修改,并且整体值都相对固定
所以我们可以根据自己实际需求去自定义各个参数值。
至于这些值palette 为何要如此设置,这些涉及到颜色基础的问题,你可以和你们家美工聊聊看。
反正我一个码农,也是没看懂的了。毕竟简单应用默认足够了 -
根据代码的逻辑,可以发现,他的颜色比分始终和最多的一个颜色值有关。
可以假设这种情况
左边绿色渐变色, #93f593 向右渐变为03f929
蓝色部分RGB值是 #00a7aa 对应HSL 是 180 1 0.62
右边紫红色RGB 值是 #ad71ae 对应HSL 是 299 0.35 0.56
蓝色命中 vibrant
紫色命中 muted
但是实际上,我们整个眼前看到的最多的颜色是渐变绿色
所以问题就来了
假设有一张图片,他很丰富的颜色,但是角落或背景有几个相对大的色块,但是整体是由某一个颜色渐变或者同一个色度构成的图
所以最终产生的图片会和实际想要的结果有很大偏差
或者Palette 可以扩展一下,加入H 色度的比对,需要的是相近的色度的他们归类为同一个颜色这样或许会更加贴近实际人眼的感官