Android调色板颜色之间的区别

21

编辑

为了更好地了解Android调色板类,我决定制作一个简单的应用程序来测试其中一些功能-如果你感兴趣,可以在Play商店上找到这个应用程序:https://play.google.com/store/apps/details?id=com.tonyw.sampleapps.palettecolorextraction。基本上它只有图片和Palette类提取的颜色(下面提到),您也可以添加自己的图片进行测试。您可以在Github上找到我的源代码:https://github.com/tony-w/PaletteColorExtraction

屏幕截图 一些图片及其相应的提取颜色 另一张带有提取颜色的图片 根据背景颜色提取的标题和正文文本颜色

原始帖子

可以有人描述一下使用Android的调色板类从位图中提取颜色的差异吗?
  • 充满活力
  • 充满活力(深色)
  • 充满活力(浅色)
  • 柔和
  • 柔和(深色)
  • 柔和(浅色)
这只是柔和颜色比充满活力的颜色更暗淡吗? 暗色和亮色是否应该更好地匹配Lollipop的深色和浅色材料设计主题?
1个回答

43
这是一个非常好的问题。如果您查看源代码,您可以看到不同的样本是从分析图像上的像素的HSL颜色配置文件中选择的,基于亮度、饱和度和种群(图像中由样本表示的像素数目)的目标范围。它使用加权平均计算,首选亮度,然后是饱和度,最后是种群
一般来说,鲜艳的颜色比柔和的颜色更饱和,深色更暗,而浅色更浅。您使用哪一种取决于您想要的整体效果。
克里斯·班恩斯在他的博客中写道“ Vibrant和Dark Vibrant是开发人员主要使用的样式”,但实际上并不像那么简单。

我找到的一个例子是Google IO 2014中Romain Guy的示例应用中的applyPalette方法,但代码假定各种色板已经被找到(可能是因为他在处理已知的图像)。

根据图像的不同,有些调色板类型可能无法被找到,因此务必在代码中考虑到这种可能性。

例如,您可以尝试按特定顺序从调色板中获取调色板,例如对于暗色主题,您可以尝试获取Vibrant Dark,然后是Muted Dark,最后回退到某个默认颜色。

如果您想要更可预测的东西,也可以像这样抓取最常出现的颜色:

public static Palette.Swatch getDominantSwatch(Palette palette) {
    // find most-represented swatch based on population
    return Collections.max(palette.getSwatches(), new Comparator<Palette.Swatch>() {
        @Override
        public int compare(Palette.Swatch sw1, Palette.Swatch sw2) {
            return Integer.compare(sw1.getPopulation(), sw2.getPopulation());
        }
    });
}

每个样本的HSL值也是可访问的,因此您可以编写类似的例程来选择最饱和的样本,例如不是主色的那个。

使用自定义目标

除了 Palette.Target 定义的 6 个目标外,我发现定义一些自定义目标也很有用,这些目标具有不同的权重、目标亮度和饱和度值,以增加找到有用颜色的几率。

例如,您可以要求 Palette 的量化器包含一个符合当前筛选条件的最主要颜色样本,其目标如下:

public static final Target DOMINANT;

static {
    DOMINANT = new Target.Builder().setPopulationWeight(1f)
                                   .setSaturationWeight(0f)
                                   .setLightnessWeight(0f)
                                   .setExclusive(false)
                                   .build();
}

你可以获取一些有用的色块,它们将亮度放在比原始标准更高的优先级上,就像这样:

public static final Target DARK;
public static final Target LIGHT;
public static final Target NEUTRAL;

static {
    DARK = new Target.Builder().setMinimumLightness(0f)
                               .setTargetLightness(0.26f)
                               .setMaximumLightness(0.5f)
                               .setMinimumSaturation(0.1f)
                               .setTargetSaturation(0.6f)
                               .setMaximumSaturation(1f)
                               .setPopulationWeight(0.18f)
                               .setSaturationWeight(0.22f)
                               .setLightnessWeight(0.60f)
                               .setExclusive(false)
                               .build();

    LIGHT = new Target.Builder().setMinimumLightness(0.50f)
                                .setTargetLightness(0.74f)
                                .setMaximumLightness(1.0f)
                                .setMinimumSaturation(0.1f)
                                .setTargetSaturation(0.7f)
                                .setMaximumSaturation(1f)
                                .setPopulationWeight(0.18f)
                                .setSaturationWeight(0.22f)
                                .setLightnessWeight(0.60f)
                                .setExclusive(false)
                                .build();

    NEUTRAL = new Target.Builder().setMinimumLightness(0.20f)
                                  .setTargetLightness(0.5f)
                                  .setMaximumLightness(0.8f)
                                  .setMinimumSaturation(0.1f)
                                  .setTargetSaturation(0.6f)
                                  .setMaximumSaturation(1f)
                                  .setPopulationWeight(0.18f)
                                  .setSaturationWeight(0.22f)
                                  .setLightnessWeight(0.60f)
                                  .setExclusive(false)
                                  .build();
}

当定制的目标生成后,您可以使用Palette.getSwatchForTarget访问找到的调色板,例如:

Palette.Swatch neutral = Palette.getSwatchForTarget(NEUTRAL);

请注意默认过滤器
默认情况下,调色板具有一个Palette.Filter,它拒绝非常接近黑色或白色的颜色,以及非常接近红色I线的颜色,我认为这是指对于红色色盲的人来说很难辨别的等时线颜色。
我的理论是,它拒绝接近白色和接近黑色的颜色,以帮助防止它们在饱和度高的情况下被选择为“饱和”颜色。
然而,该过滤器的结果是,如果图像完全由几乎白色和/或几乎黑色的像素组成,则找不到任何样本,并且倾向于避免选择具有粉红色调的颜色。
但是,可以使用Palette.Builder.clearFilters()删除此过滤器,并使用Palette.Builder.addFilter()添加自己的过滤器。
在我的代码中,如果第一次尝试没有返回任何样本,则选择进行第二次生成调色板。
Palette palette = new Palette.Builder(bitmap).addTarget(DOMINANT)
                                             .addTarget(DARK)
                                             .addTarget(LIGHT)
                                             .addTarget(NEUTRAL)
                                             .generate();
if(palette.getSwatches().isEmpty()) {
    Log.v(TAG, "Getting alternate (UNFILTERED) palette.");
    palette = new Palette.Builder(bitmap).addTarget(DOMINANT)
                                         .addTarget(DARK)
                                         .addTarget(LIGHT)
                                         .addTarget(NEUTRAL)
                                         .clearFilters() /// allow isBlack(), isWhite(), isNearRedILine()
                                         .generate();
}

链接多个尝试可以在大多数情况下保留默认过滤器的有用性,但仍允许您查找默认完全拒绝的图像的色板。

2
非常好的答案,谢谢!我也很感激在找不到色板时提供备选方案的想法。 :) - Tony Wickham
从palette-v7:25.0.0版本开始,现在有一个方便的方法叫做getDominantSwatch - 不再需要实现自定义方法了。答案的其余部分仍然有效和良好! - David Doyle
@DavidDoyle 是的,没错!他们添加了一个等效的方法来选择人口最多的色块。然而,我必须承认在我的代码中,我发现使用主色块目标(用人口权重1f和其他权重0f)更有效,因为它可以找到一个更显著的颜色,并不仅是在符合其他目标标准(如VIBRANT,MUTED等)的色块中选择人口最多的那个。 - Lorne Laliberte
1
@DavidDoyle 调用 getDominantSwatch 将返回在从图像中选择的色板中具有最高人口数量的色板...而使用目标将确定整个图像的主要颜色。两者都是有效的并且有其用途,但我发现不那么限制性的方法(使用目标)通常更适合我需要整体主导颜色的情况,例如作为临时图像背景。 - Lorne Laliberte

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接