OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #ifndef UI_GFX_COLOR_ANALYSIS_H_ |
| 6 #define UI_GFX_COLOR_ANALYSIS_H_ |
| 7 #pragma once |
| 8 |
| 9 #include "base/basictypes.h" |
| 10 #include "base/compiler_specific.h" |
| 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/memory/ref_counted_memory.h" |
| 13 #include "third_party/skia/include/core/SkColor.h" |
| 14 |
| 15 namespace color_utils { |
| 16 |
| 17 // This class exposes the sampling method to the caller, which allows |
| 18 // stubbing out for things like unit tests. Might be useful to pass more |
| 19 // arguments into the GetSample method in the future (such as which |
| 20 // cluster is being worked on, etc.). |
| 21 class KMeanImageSampler { |
| 22 public: |
| 23 virtual int GetSample(int width, int height) = 0; |
| 24 |
| 25 protected: |
| 26 KMeanImageSampler(); |
| 27 virtual ~KMeanImageSampler(); |
| 28 }; |
| 29 |
| 30 // This sampler will pick a random pixel as a sample centroid. |
| 31 class RandomSampler : public KMeanImageSampler { |
| 32 public: |
| 33 RandomSampler(); |
| 34 virtual ~RandomSampler(); |
| 35 |
| 36 virtual int GetSample(int width, int height) OVERRIDE; |
| 37 }; |
| 38 |
| 39 // This sampler will pick pixels from an evenly spaced grid. |
| 40 class GridSampler : public KMeanImageSampler { |
| 41 public: |
| 42 GridSampler(); |
| 43 virtual ~GridSampler(); |
| 44 |
| 45 virtual int GetSample(int width, int height) OVERRIDE; |
| 46 |
| 47 private: |
| 48 // The number of times GetSample has been called. |
| 49 int calls_; |
| 50 }; |
| 51 |
| 52 // Returns a recommended background color for a PNG image. This color might |
| 53 // not even exist in the image, but it is typically representative of the |
| 54 // image and tinted towards the white end of the spectrum. |
| 55 // The function CalculateKMeanColorOfPNG is used to grab the KMean calculated |
| 56 // color of the image, then the color is moved to HSV space so the saturation |
| 57 // and luminance can be modified to move the color towards the white end of |
| 58 // the spectrum. The color is then moved back to RGB space and returned. |
| 59 SkColor CalculateRecommendedBgColorForPNG(scoped_refptr<RefCountedMemory> png); |
| 60 |
| 61 SkColor CalculateRecommendedBgColorForPNG(scoped_refptr<RefCountedMemory> png, |
| 62 KMeanImageSampler& sampler); |
| 63 |
| 64 // Returns an SkColor that represents the calculated dominant color in the png. |
| 65 // This uses a KMean clustering algorithm to find clusters of pixel colors in |
| 66 // RGB space. |
| 67 // |png| represents the data of a png encoded image. |
| 68 // |darkness_limit| represents the minimum sum of the RGB components that is |
| 69 // acceptable as a color choice. This can be from 0 to 765. |
| 70 // |brightness_limit| represents the maximum sum of the RGB components that is |
| 71 // acceptable as a color choice. This can be from 0 to 765. |
| 72 // |
| 73 // RGB KMean Algorithm (N clusters, M iterations): |
| 74 // TODO (dtrainor): Try moving most/some of this to HSV space? Better for |
| 75 // color comparisons/averages? |
| 76 // 1.Pick N starting colors by randomly sampling the pixels. If you see a |
| 77 // color you already saw keep sampling. After a certain number of tries |
| 78 // just remove the cluster and continue with N = N-1 clusters (for an image |
| 79 // with just one color this should devolve to N=1). These colors are the |
| 80 // centers of your N clusters. |
| 81 // TODO (dtrainor): Check to ignore colors with an alpha of 0? |
| 82 // 2.For each pixel in the image find the cluster that it is closest to in RGB |
| 83 // space. Add that pixel's color to that cluster (we keep a sum and a count |
| 84 // of all of the pixels added to the space, so just add it to the sum and |
| 85 // increment count). |
| 86 // 3.Calculate the new cluster centroids by getting the average color of all of |
| 87 // the pixels in each cluster (dividing the sum by the count). |
| 88 // 4.See if the new centroids are the same as the old centroids. |
| 89 // a) If this is the case for all N clusters than we have converged and |
| 90 // can move on. |
| 91 // b) If any centroid moved, repeat step 2 with the new centroids for up |
| 92 // to M iterations. |
| 93 // 5.Once the clusters have converged or M iterations have been tried, sort |
| 94 // the clusters by weight (where weight is the number of pixels that make up |
| 95 // this cluster). |
| 96 // 6.Going through the sorted list of clusters, pick the first cluster with the |
| 97 // largest weight that's centroid fulfills the equation |
| 98 // |darkness_limit| < SUM(R, G, B) < |brightness_limit|. Return that color. |
| 99 // If no color fulfills that requirement return the color with the largest |
| 100 // weight regardless of whether or not it fulfills the equation above. |
| 101 SkColor CalculateKMeanColorOfPNG(scoped_refptr<RefCountedMemory> png, |
| 102 uint32_t darkness_limit, |
| 103 uint32_t brightness_limit); |
| 104 |
| 105 SkColor CalculateKMeanColorOfPNG(scoped_refptr<RefCountedMemory> png, |
| 106 uint32_t darkness_limit, |
| 107 uint32_t brightness_limit, |
| 108 KMeanImageSampler& sampler); |
| 109 |
| 110 } // namespace color_utils |
| 111 |
| 112 #endif // UI_GFX_COLOR_ANALYSIS_H_ |
OLD | NEW |