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:[email protected]

你可能感兴趣的:(android)