zoukankan      html  css  js  c++  java
  • Android笔记——Bitmap自动取色(纯搬运)

    2015/6/12更新:发现一个更好的,带demo

    https://github.com/MichaelEvans/ColorArt

    说明:
    这个是一个老外写的自动自动从bitmap中取主色与第二主色的工具类,稍微研究了下用法,但感觉效果一般,记录下。
    感兴趣的同学可以自行研究下,老外的代码没注释,这点给黄老师我造成的困惑不少。
    顺便附上老外的github地址:https://gist.github.com/chrisbanes/ba8e7b9ec0e40f6949c6

    大概的用法:

    1 image = (ImageView)findViewById(R.id.image);
    2 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
    3 DominantColorCalculator colorCalculator = new DominantColorCalculator(bitmap);
    4 ColorScheme scheme = colorCalculator.getColorScheme();
    5 View main = findViewById(R.id.main);
    6 View second = findViewById(R.id.second);
    7 main.setBackgroundColor(scheme.primaryText);
    8 second.setBackgroundColor(scheme.secondaryText);



    老外的核心代码,及简单解释:
    1、ColorScheme类,作用貌似是记录颜色,其中xxxtext都是Color对象

     1 /*
     2  * Copyright 2014 Chris Banes
     3  *
     4  * Licensed under the Apache License, Version 2.0 (the "License");
     5  * you may not use this file except in compliance with the License.
     6  * You may obtain a copy of the License at
     7  *
     8  *     http://www.apache.org/licenses/LICENSE-2.0
     9  *
    10  * Unless required by applicable law or agreed to in writing, software
    11  * distributed under the License is distributed on an "AS IS" BASIS,
    12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  * See the License for the specific language governing permissions and
    14  * limitations under the License.
    15  */
    16 
    17 public class ColorScheme {
    18 
    19     public final int primaryAccent;
    20     public final int secondaryAccent;
    21     public final int tertiaryAccent;
    22 
    23     public final int primaryText;
    24     public final int secondaryText;
    25 
    26     public ColorScheme(int primaryAccent, int secondaryAccent, int tertiaryAccent,
    27             int primaryText, int secondaryText) {
    28         this.primaryAccent = primaryAccent;
    29         this.secondaryAccent = secondaryAccent;
    30         this.tertiaryAccent = tertiaryAccent;
    31         this.primaryText = primaryText;
    32         this.secondaryText = secondaryText;
    33     }
    34 }



    2、ColorUtils类,有一些颜色操作的工具方法,比如颜色混合、亮暗调整、YIQ转换等等

     1 /*
     2  * Copyright 2014 Chris Banes
     3  *
     4  * Licensed under the Apache License, Version 2.0 (the "License");
     5  * you may not use this file except in compliance with the License.
     6  * You may obtain a copy of the License at
     7  *
     8  *     http://www.apache.org/licenses/LICENSE-2.0
     9  *
    10  * Unless required by applicable law or agreed to in writing, software
    11  * distributed under the License is distributed on an "AS IS" BASIS,
    12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  * See the License for the specific language governing permissions and
    14  * limitations under the License.
    15  */
    16 
    17 import android.graphics.Color;
    18 
    19 public class ColorUtils {
    20 
    21     public static int darken(final int color, float fraction) {
    22         return blendColors(Color.BLACK, color, fraction);
    23     }
    24 
    25     public static int lighten(final int color, float fraction) {
    26         return blendColors(Color.WHITE, color, fraction);
    27     }
    28 
    29     /**
    30      * @return luma value according to to YIQ color space.
    31      */
    32     public static final int calculateYiqLuma(int color) {
    33         return Math.round((299 * Color.red(color) + 587 * Color.green(color) + 114 * Color.blue(color)) / 1000f);
    34     }
    35 
    36     /**
    37      * Blend {@code color1} and {@code color2} using the given ratio.
    38      *
    39      * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
    40      *              0.0 will return {@code color2}.
    41      */
    42     public static int blendColors(int color1, int color2, float ratio) {
    43         final float inverseRatio = 1f - ratio;
    44         float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRatio);
    45         float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRatio);
    46         float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRatio);
    47         return Color.rgb((int) r, (int) g, (int) b);
    48     }
    49 
    50     public static final int changeBrightness(final int color, float fraction) {
    51         return calculateYiqLuma(color) >= 128
    52                 ? darken(color, fraction)
    53                 : lighten(color, fraction);
    54     }
    55 
    56     public static final int calculateContrast(MedianCutQuantizer.ColorNode color1,
    57             MedianCutQuantizer.ColorNode color2) {
    58         return Math.abs(ColorUtils.calculateYiqLuma(color1.getRgb())
    59                 - ColorUtils.calculateYiqLuma(color2.getRgb()));
    60     }
    61 
    62     public static final float calculateColorfulness(MedianCutQuantizer.ColorNode node) {
    63         float[] hsv = node.getHsv();
    64         return hsv[1] * hsv[2];
    65     }
    66 
    67 }



    3、和Android的Bitmap对象的接口类,构造方法中传入bitmap对象即开始转换,然后通过getColorScheme获得抓取到的颜色

      1 /*
      2  * Copyright 2014 Chris Banes
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 import android.graphics.Bitmap;
     18 import android.graphics.Color;
     19 
     20 import java.util.Arrays;
     21 import java.util.Comparator;
     22 
     23 import org.apache.chrisbanes.colorscheme.MedianCutQuantizer.ColorNode;
     24 
     25 public class DominantColorCalculator {
     26 
     27     private static final int NUM_COLORS = 10;
     28 
     29     private static final int PRIMARY_TEXT_MIN_CONTRAST = 135;
     30 
     31     private static final int SECONDARY_MIN_DIFF_HUE_PRIMARY = 120;
     32 
     33     private static final int TERTIARY_MIN_CONTRAST_PRIMARY = 20;
     34     private static final int TERTIARY_MIN_CONTRAST_SECONDARY = 90;
     35 
     36     private final MedianCutQuantizer.ColorNode[] mPalette;
     37     private final MedianCutQuantizer.ColorNode[] mWeightedPalette;
     38     private ColorScheme mColorScheme;
     39 
     40     public DominantColorCalculator(Bitmap bitmap) {
     41         final int width = bitmap.getWidth();
     42         final int height = bitmap.getHeight();
     43 
     44         final int[] rgbPixels = new int[width * height];
     45         bitmap.getPixels(rgbPixels, 0, width, 0, 0, width, height);
     46 
     47         final MedianCutQuantizer mcq = new MedianCutQuantizer(rgbPixels, NUM_COLORS);
     48 
     49         mPalette = mcq.getQuantizedColors();
     50         mWeightedPalette = weight(mPalette);
     51 
     52         findColors();
     53     }
     54 
     55     public ColorScheme getColorScheme() {
     56         return mColorScheme;
     57     }
     58 
     59     private void findColors() {
     60         final ColorNode primaryAccentColor = findPrimaryAccentColor();
     61         final ColorNode secondaryAccentColor = findSecondaryAccentColor(primaryAccentColor);
     62 
     63         final int tertiaryAccentColor = findTertiaryAccentColor(
     64                 primaryAccentColor, secondaryAccentColor);
     65 
     66         final int primaryTextColor = findPrimaryTextColor(primaryAccentColor);
     67         final int secondaryTextColor = findSecondaryTextColor(primaryAccentColor);
     68 
     69         mColorScheme = new ColorScheme(
     70                 primaryAccentColor.getRgb(),
     71                 secondaryAccentColor.getRgb(),
     72                 tertiaryAccentColor,
     73                 primaryTextColor,
     74                 secondaryTextColor);
     75     }
     76 
     77     /**
     78      * @return the first color from our weighted palette.
     79      */
     80     private ColorNode findPrimaryAccentColor() {
     81         return mWeightedPalette[0];
     82     }
     83 
     84     /**
     85      * @return the next color in the weighted palette which ideally has enough difference in hue.
     86      */
     87     private ColorNode findSecondaryAccentColor(final ColorNode primary) {
     88         final float primaryHue = primary.getHsv()[0];
     89 
     90         // Find the first color which has sufficient difference in hue from the primary
     91         for (ColorNode candidate : mWeightedPalette) {
     92             final float candidateHue = candidate.getHsv()[0];
     93 
     94             // Calculate the difference in hue, if it's over the threshold return it
     95             if (Math.abs(primaryHue - candidateHue) >= SECONDARY_MIN_DIFF_HUE_PRIMARY) {
     96                 return candidate;
     97             }
     98         }
     99 
    100         // If we get here, just return the second weighted color
    101         return mWeightedPalette[1];
    102     }
    103 
    104     /**
    105      * @return the first color from our weighted palette which has sufficient contrast from the
    106      *         primary and secondary colors.
    107      */
    108     private int findTertiaryAccentColor(final ColorNode primary, final ColorNode secondary) {
    109         // Find the first color which has sufficient contrast from both the primary & secondary
    110         for (ColorNode color : mWeightedPalette) {
    111             if (ColorUtils.calculateContrast(color, primary) >= TERTIARY_MIN_CONTRAST_PRIMARY
    112                     && ColorUtils.calculateContrast(color, secondary) >= TERTIARY_MIN_CONTRAST_SECONDARY) {
    113                 return color.getRgb();
    114             }
    115         }
    116 
    117         // We couldn't find a colour. In that case use the primary colour, modifying it's brightness
    118         // by 45%
    119         return ColorUtils.changeBrightness(secondary.getRgb(), 0.45f);
    120     }
    121 
    122     /**
    123      * @return the first color which has sufficient contrast from the primary colors.
    124      */
    125     private int findPrimaryTextColor(final ColorNode primary) {
    126         // Try and find a colour with sufficient contrast from the primary colour
    127         for (ColorNode color : mPalette) {
    128             if (ColorUtils.calculateContrast(color, primary) >= PRIMARY_TEXT_MIN_CONTRAST) {
    129                 return color.getRgb();
    130             }
    131         }
    132 
    133         // We haven't found a colour, so return black/white depending on the primary colour's
    134         // brightness
    135         return ColorUtils.calculateYiqLuma(primary.getRgb()) >= 128 ? Color.BLACK : Color.WHITE;
    136     }
    137 
    138     /**
    139      * @return return black/white depending on the primary colour's brightness
    140      */
    141     private int findSecondaryTextColor(final ColorNode primary) {
    142         return ColorUtils.calculateYiqLuma(primary.getRgb()) >= 128 ? Color.BLACK : Color.WHITE;
    143     }
    144 
    145     private static ColorNode[] weight(ColorNode[] palette) {
    146         final MedianCutQuantizer.ColorNode[] copy = Arrays.copyOf(palette, palette.length);
    147         final float maxCount = palette[0].getCount();
    148 
    149         Arrays.sort(copy, new Comparator<ColorNode>() {
    150             @Override
    151             public int compare(ColorNode lhs, ColorNode rhs) {
    152                 final float lhsWeight = calculateWeight(lhs, maxCount);
    153                 final float rhsWeight = calculateWeight(rhs, maxCount);
    154 
    155                 if (lhsWeight < rhsWeight) {
    156                     return 1;
    157                 } else if (lhsWeight > rhsWeight) {
    158                     return -1;
    159                 }
    160                 return 0;
    161             }
    162         });
    163 
    164         return copy;
    165     }
    166 
    167     private static float calculateWeight(ColorNode node, final float maxCount) {
    168         return FloatUtils.weightedAverage(
    169                 ColorUtils.calculateColorfulness(node), 2f,
    170                 (node.getCount() / maxCount), 1f
    171         );
    172     }
    173 
    174 }



    4、一个计算浮点数组平均权重平均值的工具方法类

     1 /*
     2  * Copyright 2014 Chris Banes
     3  *
     4  * Licensed under the Apache License, Version 2.0 (the "License");
     5  * you may not use this file except in compliance with the License.
     6  * You may obtain a copy of the License at
     7  *
     8  *     http://www.apache.org/licenses/LICENSE-2.0
     9  *
    10  * Unless required by applicable law or agreed to in writing, software
    11  * distributed under the License is distributed on an "AS IS" BASIS,
    12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  * See the License for the specific language governing permissions and
    14  * limitations under the License.
    15  */
    16 
    17 public class FloatUtils {
    18 
    19     public static float weightedAverage(float... values) {
    20         assert values.length % 2 == 0;
    21 
    22         float sum = 0;
    23         float sumWeight = 0;
    24 
    25         for (int i = 0; i < values.length; i += 2) {
    26             float value = values[i];
    27             float weight = values[i + 1];
    28 
    29             sum += (value * weight);
    30             sumWeight += weight;
    31         }
    32 
    33         return sum / sumWeight;
    34     }
    35 
    36 }



    5、关键类,获取位图中的颜色

      1 /**
      2  * This sample code is made available as part of the book "Digital Image
      3  * Processing - An Algorithmic Introduction using Java" by Wilhelm Burger
      4  * and Mark J. Burge, Copyright (C) 2005-2008 Springer-Verlag Berlin,
      5  * Heidelberg, New York.
      6  * Note that this code comes with absolutely no warranty of any kind.
      7  * See http://www.imagingbook.com for details and licensing conditions.
      8  *
      9  * Modified by Chris Banes.
     10  */
     11 
     12 import android.graphics.Color;
     13 import android.util.Log;
     14 
     15 import java.util.ArrayList;
     16 import java.util.Arrays;
     17 import java.util.Comparator;
     18 import java.util.List;
     19 
     20 /*
     21  * This is an implementation of Heckbert's median-cut color quantization algorithm
     22  * (Heckbert P., "Color Image Quantization for Frame Buffer Display", ACM Transactions
     23  * on Computer Graphics (SIGGRAPH), pp. 297-307, 1982).
     24  * Unlike in the original algorithm, no initial uniform (scalar) quantization is used to
     25  * for reducing the number of image colors. Instead, all colors contained in the original
     26  * image are considered in the quantization process. After the set of representative
     27  * colors has been found, each image color is mapped to the closest representative
     28  * in RGB color space using the Euclidean distance.
     29  * The quantization process has two steps: first a ColorQuantizer object is created from
     30  * a given image using one of the constructor methods provided. Then this ColorQuantizer
     31  * can be used to quantize the original image or any other image using the same set of
     32  * representative colors (color table).
     33  */
     34 
     35 public class MedianCutQuantizer {
     36 
     37     private static final String LOG_TAG = MedianCutQuantizer.class
     38             .getSimpleName();
     39 
     40     private ColorNode[] imageColors = null; // original (unique) image colors
     41     private ColorNode[] quantColors = null; // quantized colors
     42 
     43     public MedianCutQuantizer(int[] pixels, int Kmax) {
     44         quantColors = findRepresentativeColors(pixels, Kmax);
     45     }
     46 
     47     public int countQuantizedColors() {
     48         return quantColors.length;
     49     }
     50 
     51     public ColorNode[] getQuantizedColors() {
     52         return quantColors;
     53     }
     54 
     55     ColorNode[] findRepresentativeColors(int[] pixels, int Kmax) {
     56         ColorHistogram colorHist = new ColorHistogram(pixels);
     57         int K = colorHist.getNumberOfColors();
     58         ColorNode[] rCols = null;
     59 
     60         imageColors = new ColorNode[K];
     61         for (int i = 0; i < K; i++) {
     62             int rgb = colorHist.getColor(i);
     63             int cnt = colorHist.getCount(i);
     64             imageColors[i] = new ColorNode(rgb, cnt);
     65         }
     66 
     67         if (K <= Kmax) {
     68             // image has fewer colors than Kmax
     69             rCols = imageColors;
     70         } else {
     71             ColorBox initialBox = new ColorBox(0, K - 1, 0);
     72             List<ColorBox> colorSet = new ArrayList<ColorBox>();
     73             colorSet.add(initialBox);
     74             int k = 1;
     75             boolean done = false;
     76             while (k < Kmax && !done) {
     77                 ColorBox nextBox = findBoxToSplit(colorSet);
     78                 if (nextBox != null) {
     79                     ColorBox newBox = nextBox.splitBox();
     80                     colorSet.add(newBox);
     81                     k = k + 1;
     82                 } else {
     83                     done = true;
     84                 }
     85             }
     86             rCols = averageColors(colorSet);
     87         }
     88         return rCols;
     89     }
     90 
     91     public void quantizeImage(int[] pixels) {
     92         for (int i = 0; i < pixels.length; i++) {
     93             ColorNode color = findClosestColor(pixels[i]);
     94             pixels[i] = Color.rgb(color.red, color.grn, color.blu);
     95         }
     96     }
     97 
     98     ColorNode findClosestColor(int rgb) {
     99         int idx = findClosestColorIndex(rgb);
    100         return quantColors[idx];
    101     }
    102 
    103     int findClosestColorIndex(int rgb) {
    104         int red = Color.red(rgb);
    105         int grn = Color.green(rgb);
    106         int blu = Color.blue(rgb);
    107         int minIdx = 0;
    108         int minDistance = Integer.MAX_VALUE;
    109         for (int i = 0; i < quantColors.length; i++) {
    110             ColorNode color = quantColors[i];
    111             int d2 = color.distance2(red, grn, blu);
    112             if (d2 < minDistance) {
    113                 minDistance = d2;
    114                 minIdx = i;
    115             }
    116         }
    117         return minIdx;
    118     }
    119 
    120     private ColorBox findBoxToSplit(List<ColorBox> colorBoxes) {
    121         ColorBox boxToSplit = null;
    122         // from the set of splitable color boxes
    123         // select the one with the minimum level
    124         int minLevel = Integer.MAX_VALUE;
    125         for (ColorBox box : colorBoxes) {
    126             if (box.colorCount() >= 2) { // box can be split
    127                 if (box.level < minLevel) {
    128                     boxToSplit = box;
    129                     minLevel = box.level;
    130                 }
    131             }
    132         }
    133         return boxToSplit;
    134     }
    135 
    136     private ColorNode[] averageColors(List<ColorBox> colorBoxes) {
    137         int n = colorBoxes.size();
    138         ColorNode[] avgColors = new ColorNode[n];
    139         int i = 0;
    140         for (ColorBox box : colorBoxes) {
    141             avgColors[i] = box.getAverageColor();
    142             i = i + 1;
    143         }
    144         return avgColors;
    145     }
    146 
    147     // -------------- class ColorNode
    148     // -------------------------------------------
    149 
    150     public static class ColorNode {
    151 
    152         private final int red, grn, blu;
    153         private final int cnt;
    154 
    155         private float[] hsv;
    156 
    157         ColorNode(int rgb, int cnt) {
    158             this.red = Color.red(rgb);
    159             this.grn = Color.green(rgb);
    160             this.blu = Color.blue(rgb);
    161             this.cnt = cnt;
    162         }
    163 
    164         ColorNode(int red, int grn, int blu, int cnt) {
    165             this.red = red;
    166             this.grn = grn;
    167             this.blu = blu;
    168             this.cnt = cnt;
    169         }
    170 
    171         public int getRgb() {
    172             return Color.rgb(red, grn, blu);
    173         }
    174 
    175         public float[] getHsv() {
    176             if (hsv == null) {
    177                 hsv = new float[3];
    178                 Color.RGBToHSV(red, grn, blu, hsv);
    179             }
    180             return hsv;
    181         }
    182 
    183         public int getCount() {
    184             return cnt;
    185         }
    186 
    187         int distance2(int red, int grn, int blu) {
    188             // returns the squared distance between (red, grn, blu)
    189             // and this this color
    190             int dr = this.red - red;
    191             int dg = this.grn - grn;
    192             int db = this.blu - blu;
    193             return dr * dr + dg * dg + db * db;
    194         }
    195 
    196         public String toString() {
    197             return new StringBuilder(getClass().getSimpleName()).append(" #")
    198                     .append(Integer.toHexString(getRgb())).append(". count: ")
    199                     .append(cnt).toString();
    200         }
    201     }
    202 
    203     // -------------- class ColorBox -------------------------------------------
    204 
    205     class ColorBox {
    206 
    207         int lower = 0; // lower index into 'imageColors'
    208         int upper = -1; // upper index into 'imageColors'
    209         int level; // split level o this color box
    210         int count = 0; // number of pixels represented by thos color box
    211         int rmin, rmax; // range of contained colors in red dimension
    212         int gmin, gmax; // range of contained colors in green dimension
    213         int bmin, bmax; // range of contained colors in blue dimension
    214 
    215         ColorBox(int lower, int upper, int level) {
    216             this.lower = lower;
    217             this.upper = upper;
    218             this.level = level;
    219             this.trim();
    220         }
    221 
    222         int colorCount() {
    223             return upper - lower;
    224         }
    225 
    226         void trim() {
    227             // recompute the boundaries of this color box
    228             rmin = 255;
    229             rmax = 0;
    230             gmin = 255;
    231             gmax = 0;
    232             bmin = 255;
    233             bmax = 0;
    234             count = 0;
    235             for (int i = lower; i <= upper; i++) {
    236                 ColorNode color = imageColors[i];
    237                 count = count + color.cnt;
    238                 int r = color.red;
    239                 int g = color.grn;
    240                 int b = color.blu;
    241                 if (r > rmax) {
    242                     rmax = r;
    243                 }
    244                 if (r < rmin) {
    245                     rmin = r;
    246                 }
    247                 if (g > gmax) {
    248                     gmax = g;
    249                 }
    250                 if (g < gmin) {
    251                     gmin = g;
    252                 }
    253                 if (b > bmax) {
    254                     bmax = b;
    255                 }
    256                 if (b < bmin) {
    257                     bmin = b;
    258                 }
    259             }
    260         }
    261 
    262         // Split this color box at the median point along its
    263         // longest color dimension
    264         ColorBox splitBox() {
    265             if (this.colorCount() < 2) // this box cannot be split
    266             {
    267                 return null;
    268             } else {
    269                 // find longest dimension of this box:
    270                 ColorDimension dim = getLongestColorDimension();
    271 
    272                 // find median along dim
    273                 int med = findMedian(dim);
    274 
    275                 // now split this box at the median return the resulting new
    276                 // box.
    277                 int nextLevel = level + 1;
    278                 ColorBox newBox = new ColorBox(med + 1, upper, nextLevel);
    279                 this.upper = med;
    280                 this.level = nextLevel;
    281                 this.trim();
    282                 return newBox;
    283             }
    284         }
    285 
    286         // Find longest dimension of this color box (RED, GREEN, or BLUE)
    287         ColorDimension getLongestColorDimension() {
    288             int rLength = rmax - rmin;
    289             int gLength = gmax - gmin;
    290             int bLength = bmax - bmin;
    291             if (bLength >= rLength && bLength >= gLength) {
    292                 return ColorDimension.BLUE;
    293             } else if (gLength >= rLength && gLength >= bLength) {
    294                 return ColorDimension.GREEN;
    295             } else {
    296                 return ColorDimension.RED;
    297             }
    298         }
    299 
    300         // Find the position of the median in RGB space along
    301         // the red, green or blue dimension, respectively.
    302         int findMedian(ColorDimension dim) {
    303             // sort color in this box along dimension dim:
    304             Arrays.sort(imageColors, lower, upper + 1, dim.comparator);
    305             // find the median point:
    306             int half = count / 2;
    307             int nPixels, median;
    308             for (median = lower, nPixels = 0; median < upper; median++) {
    309                 nPixels = nPixels + imageColors[median].cnt;
    310                 if (nPixels >= half) {
    311                     break;
    312                 }
    313             }
    314             return median;
    315         }
    316 
    317         ColorNode getAverageColor() {
    318             int rSum = 0;
    319             int gSum = 0;
    320             int bSum = 0;
    321             int n = 0;
    322             for (int i = lower; i <= upper; i++) {
    323                 ColorNode ci = imageColors[i];
    324                 int cnt = ci.cnt;
    325                 rSum = rSum + cnt * ci.red;
    326                 gSum = gSum + cnt * ci.grn;
    327                 bSum = bSum + cnt * ci.blu;
    328                 n = n + cnt;
    329             }
    330             double nd = n;
    331             int avgRed = (int) (0.5 + rSum / nd);
    332             int avgGrn = (int) (0.5 + gSum / nd);
    333             int avgBlu = (int) (0.5 + bSum / nd);
    334             return new ColorNode(avgRed, avgGrn, avgBlu, n);
    335         }
    336 
    337         public String toString() {
    338             String s = this.getClass().getSimpleName();
    339             s = s + " lower=" + lower + " upper=" + upper;
    340             s = s + " count=" + count + " level=" + level;
    341             s = s + " rmin=" + rmin + " rmax=" + rmax;
    342             s = s + " gmin=" + gmin + " gmax=" + gmax;
    343             s = s + " bmin=" + bmin + " bmax=" + bmax;
    344             s = s + " bmin=" + bmin + " bmax=" + bmax;
    345             return s;
    346         }
    347     }
    348 
    349     // --- color dimensions ------------------------
    350 
    351     // The main purpose of this enumeration class is associate
    352     // the color dimensions with the corresponding comparators.
    353     enum ColorDimension {
    354         RED(new redComparator()), GREEN(new grnComparator()), BLUE(
    355                 new bluComparator());
    356 
    357         public final Comparator<ColorNode> comparator;
    358 
    359         ColorDimension(Comparator<ColorNode> cmp) {
    360             this.comparator = cmp;
    361         }
    362     }
    363 
    364     // --- color comparators used for sorting colors along different dimensions
    365     // ---
    366 
    367     static class redComparator implements Comparator<ColorNode> {
    368         public int compare(ColorNode colA, ColorNode colB) {
    369             return colA.red - colB.red;
    370         }
    371     }
    372 
    373     static class grnComparator implements Comparator<ColorNode> {
    374         public int compare(ColorNode colA, ColorNode colB) {
    375             return colA.grn - colB.grn;
    376         }
    377     }
    378 
    379     static class bluComparator implements Comparator<ColorNode> {
    380         public int compare(ColorNode colA, ColorNode colB) {
    381             return colA.blu - colB.blu;
    382         }
    383     }
    384 
    385     // -------- utility methods -----------
    386 
    387     void listColorNodes(ColorNode[] nodes) {
    388         int i = 0;
    389         for (ColorNode color : nodes) {
    390             Log.d(LOG_TAG, "Color Node #" + i + " " + color.toString());
    391             i++;
    392         }
    393     }
    394 
    395     static class ColorHistogram {
    396 
    397         int colorArray[] = null;
    398         int countArray[] = null;
    399 
    400         ColorHistogram(int[] color, int[] count) {
    401             this.countArray = count;
    402             this.colorArray = color;
    403         }
    404 
    405         ColorHistogram(int[] pixelsOrig) {
    406             int N = pixelsOrig.length;
    407             int[] pixelsCpy = new int[N];
    408             for (int i = 0; i < N; i++) {
    409                 // remove possible alpha components
    410                 pixelsCpy[i] = 0xFFFFFF & pixelsOrig[i];
    411             }
    412             Arrays.sort(pixelsCpy);
    413 
    414             // count unique colors:
    415             int k = -1; // current color index
    416             int curColor = -1;
    417             for (int i = 0; i < pixelsCpy.length; i++) {
    418                 if (pixelsCpy[i] != curColor) {
    419                     k++;
    420                     curColor = pixelsCpy[i];
    421                 }
    422             }
    423             int nColors = k + 1;
    424 
    425             // tabulate and count unique colors:
    426             colorArray = new int[nColors];
    427             countArray = new int[nColors];
    428             k = -1; // current color index
    429             curColor = -1;
    430             for (int i = 0; i < pixelsCpy.length; i++) {
    431                 if (pixelsCpy[i] != curColor) { // new color
    432                     k++;
    433                     curColor = pixelsCpy[i];
    434                     colorArray[k] = curColor;
    435                     countArray[k] = 1;
    436                 } else {
    437                     countArray[k]++;
    438                 }
    439             }
    440         }
    441 
    442         public int[] getColorArray() {
    443             return colorArray;
    444         }
    445 
    446         public int[] getCountArray() {
    447             return countArray;
    448         }
    449 
    450         public int getNumberOfColors() {
    451             if (colorArray == null) {
    452                 return 0;
    453             } else {
    454                 return colorArray.length;
    455             }
    456         }
    457 
    458         public int getColor(int index) {
    459             return this.colorArray[index];
    460         }
    461 
    462         public int getCount(int index) {
    463             return this.countArray[index];
    464         }
    465     }
    466 
    467 } // class MedianCut



    剩余的大家自行研究了,如果有研究出更详细的用法,记得联系黄老师哦!
    QQ:811868948
    E-Mail:halfmanhuang@gmail.com

  • 相关阅读:
    Django文档翻译:模型参考(Model Reference)
    Anthem.NET 的 "BAD RESPONSE" 问题的脚本调试技巧小结
    注意 JavaScript 中 RegExp 对象的 test 方法
    CodeProject 文章收藏 (200713)
    Django 学习纪要(1) 模版语法
    关注一下 IronPython Community Edition
    SubSonic 的字段名未转义问题修正
    Error while trying to run project: Unable to start debugging 绑定句柄无效
    Django 中自定义 tag 如何获取变量参数的值
    Karrigell 初次学习
  • 原文地址:https://www.cnblogs.com/halfmanhuang/p/3848341.html
Copyright © 2011-2022 走看看