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