码迷,mamicode.com
首页 > 移动开发 > 详细

android5.0L版本新特性:主色提取

时间:2015-01-26 08:55:23      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:

        上一次周例会上,有关专家介绍了一下android5.0的一些新特性。其中一个是主色提取,按照产品经理的意思,下一期需求上我们最好能加上这个特性。于是乎,我们就开始研究一下这个新特性了。这个是放在support包里面的新增接口,也就是说这个接口和android版本无关。看来源码也不会太大。:-)
        先看一下google官方说明。https://developer.android.com/reference/android/support/v7/graphics/Palette.html从这个介绍页面,我们大致能够明白:这个新增接口比较简单。一个主要构造方法,传一个bitmap对象,剩下的就是get系列方法。另外,为了方便使用,google还特意新增加了一个异步的构造方法,类似imageloader。不过这里友情提醒一下,以下几个方法,返回值有可能是空,所以使用前要做一次参数有效性判断。
    /**
     * Returns the most vibrant swatch in the palette. Might be null.
     */
    public Swatch getVibrantSwatch() {
        return mVibrantSwatch;
    }

    /**
     * Returns a light and vibrant swatch from the palette. Might be null.
     */
    public Swatch getLightVibrantSwatch() {
        return mLightVibrantSwatch;
    }

    /**
     * Returns a dark and vibrant swatch from the palette. Might be null.
     */
    public Swatch getDarkVibrantSwatch() {
        return mDarkVibrantSwatch;
    }

    /**
     * Returns a muted swatch from the palette. Might be null.
     */
    public Swatch getMutedSwatch() {
        return mMutedSwatch;
    }

    /**
     * Returns a muted and light swatch from the palette. Might be null.
     */
    public Swatch getLightMutedSwatch() {
        return mLightMutedColor;
    }

    /**
     * Returns a muted and dark swatch from the palette. Might be null.
     */
    public Swatch getDarkMutedSwatch() {
        return mDarkMutedSwatch;
    }

        按理,这么好的接口,应该能够很快上手。可是在demo里发现,好多情况下,这个接口并没有取到我们想要的,也就是我们认为这附图片上最多的颜色。比如一张一眼看上去灰白占主要的图片,返回来的确是红色,或者黄色。从图片上取到的颜色,不再正常的理解范围之内。看来得研究一下源码了。
        同这个特性开放的接口一样,这个特性的实现源码也不是太复杂。package android.support.v7.graphics下面总共只有四个文件,其中一个是public class。其余的三个类中,有两个class是能力层代码。具体如下:
Palette.java 对外接口类。提供一些方法的获取,以及Swatch的定义。
ColorUtils.java 业务强相关的工具类。里面都是一些静态方法。
ColorHistogram.java 实现了颜色提取算法的能力类。
ColorCutQuantizer.java 夹在ColorHistogram.java和Palette.java中间的一个封装类。不过这个类里面提供了一套颜色分裂算法。
        这里我们先看一下ColorHistogram这个类是怎么实现主色提取的。构造方法里面传了一个像素点颜色值的数组。传入之后,对所有颜色值进行一次排序。在countDistinctColors方法里面给出了颜色的种类,在countFrequencies方法里面给出了每种颜色所占的比例/个数。这个算法很常见,第一次遇到的同学结合google的注释看起来也挺快的。

    private static int countDistinctColors(final int[] pixels) {
        if (pixels.length < 2) {
            // If we have less than 2 pixels we can stop here
            return pixels.length;
        }

        // If we have at least 2 pixels, we have a minimum of 1 color...
        int colorCount = 1;
        int currentColor = pixels[0];

        // Now iterate from the second pixel to the end, counting distinct colors
        for (int i = 1; i < pixels.length; i++) {
            // If we encounter a new color, increase the population
            if (pixels[i] != currentColor) {
                currentColor = pixels[i];
                colorCount++;
            }
        }

        return colorCount;
    }

    private void countFrequencies(final int[] pixels) {
        if (pixels.length == 0) {
            return;
        }

        int currentColorIndex = 0;
        int currentColor = pixels[0];

        mColors[currentColorIndex] = currentColor;
        mColorCounts[currentColorIndex] = 1;

        if (pixels.length == 1) {
            // If we only have one pixel, we can stop here
            return;
        }

        // Now iterate from the second pixel to the end, population distinct colors
        for (int i = 1; i < pixels.length; i++) {
            if (pixels[i] == currentColor) {
                // We've hit the same color as before, increase population
                mColorCounts[currentColorIndex]++;
            } else {
                // We've hit a new color, increase index
                currentColor = pixels[i];

                currentColorIndex++;
                mColors[currentColorIndex] = currentColor;
                mColorCounts[currentColorIndex] = 1;
            }
        }
    }
到这里一切都是正常。该提取的颜色应该都提取出来了。那只能接着向上看。ColorHistogram构造的结果,做为参数直接丢给了ColorCutQuantizer的构造方法。在这个构造方法里面我们找到了原因:
        // Now go through all of the colors and keep those which we do not want to ignore
        mColors = new int[rawColorCount];
        int validColorCount = 0;
        for (int color : rawColors) {
            if (!shouldIgnoreColor(color)) {
                mColors[validColorCount++] = color;
            }
        }

        google按照某个标准,进行了一次颜色筛选。也就是说我们直接用接口拿到的结果,是经过某个特定的业务筛选出来的。如果我们不知道这个业务,我们拿到的颜色当然就不是我们需要的颜色。将这个筛选逻辑去掉之后,拿到的主色,也就是我们需要的,图片里面最多的颜色。
        另外从google的官方说明来看,这个接口的速度非常快。在下面这个方法里面,google将图片的大小统一压缩成一个较小的图片,这个应该是处理时间快的一个重要原因:

    public static Palette generate(Bitmap bitmap, int numColors) {
        checkBitmapParam(bitmap);
        checkNumberColorsParam(numColors);

        // First we'll scale down the bitmap so it's shortest dimension is 100px
        final Bitmap scaledBitmap = scaleBitmapDown(bitmap);
       个人觉得接口层还是提供能力比较好。如果这个接口层提供两套接口:1.单单的主色提取能力,2.某套颜色提取算法。这样APP在业务层里面用起来可能会更方便一些。

android5.0L版本新特性:主色提取

标签:

原文地址:http://blog.csdn.net/maybe_windleave/article/details/43114521

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!