File: color_analysis.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (205 lines) | stat: -rw-r--r-- 8,021 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_GFX_COLOR_ANALYSIS_H_
#define UI_GFX_COLOR_ANALYSIS_H_

#include <stdint.h>

#include <optional>
#include <vector>

#include "base/component_export.h"
#include "base/containers/span.h"
#include "base/functional/callback_forward.h"
#include "third_party/skia/include/core/SkColor.h"

class SkBitmap;

namespace gfx {
class Rect;
}  // namespace gfx

namespace color_utils {

struct HSL;

// This class exposes the sampling method to the caller, which allows
// stubbing out for things like unit tests. Might be useful to pass more
// arguments into the GetSample method in the future (such as which
// cluster is being worked on, etc.).
//
// Note: Samplers should be deterministic, as the same image may be analyzed
// twice with two sampler instances and the results displayed side-by-side
// to the user.
class COMPONENT_EXPORT(GFX) KMeanImageSampler {
 public:
  virtual int GetSample(int width, int height) = 0;

 protected:
  KMeanImageSampler();
  virtual ~KMeanImageSampler();
};

// This sampler will pick pixels from an evenly spaced grid.
class COMPONENT_EXPORT(GFX) GridSampler : public KMeanImageSampler {
 public:
  GridSampler();
  ~GridSampler() override;

  int GetSample(int width, int height) override;

 private:
  // The number of times GetSample has been called.
  int calls_;
};

// Returns the color in an ARGB |image| that is closest in RGB-space to the
// provided |color|. Exported for testing.
COMPONENT_EXPORT(GFX)
SkColor FindClosestColor(base::span<const uint8_t> image,
                         int width,
                         int height,
                         SkColor color);

// Returns an SkColor that represents the calculated dominant color in the
// image. This uses a KMean clustering algorithm to find clusters of pixel
// colors in RGB space.
// |png|/|bitmap| represents the data of a png/bitmap encoded image.
// |lower_bound| represents the minimum bound of HSL values to allow.
// |upper_bound| represents the maximum bound of HSL values to allow.
// See color_utils::IsWithinHSLRange() for description of these bounds.
//
// RGB KMean Algorithm (N clusters, M iterations):
// 1.Pick N starting colors by randomly sampling the pixels. If you see a
//   color you already saw keep sampling. After a certain number of tries
//   just remove the cluster and continue with N = N-1 clusters (for an image
//   with just one color this should devolve to N=1). These colors are the
//   centers of your N clusters.
// 2.For each pixel in the image find the cluster that it is closest to in RGB
//   space. Add that pixel's color to that cluster (we keep a sum and a count
//   of all of the pixels added to the space, so just add it to the sum and
//   increment count).
// 3.Calculate the new cluster centroids by getting the average color of all of
//   the pixels in each cluster (dividing the sum by the count).
// 4.See if the new centroids are the same as the old centroids.
//     a) If this is the case for all N clusters than we have converged and
//        can move on.
//     b) If any centroid moved, repeat step 2 with the new centroids for up
//        to M iterations.
// 5.Once the clusters have converged or M iterations have been tried, sort
//   the clusters by weight (where weight is the number of pixels that make up
//   this cluster).
// 6.Going through the sorted list of clusters, pick the first cluster with the
//   largest weight that's centroid falls between |lower_bound| and
//   |upper_bound|. Return that color.
//   If no color fulfills that requirement return the color with the largest
//   weight regardless of whether or not it fulfills the equation above.
COMPONENT_EXPORT(GFX)
SkColor CalculateKMeanColorOfPNG(base::span<const uint8_t> png,
                                 const HSL& lower_bound,
                                 const HSL& upper_bound,
                                 KMeanImageSampler* sampler);
// Computes a dominant color using the above algorithm and reasonable defaults
// for |lower_bound|, |upper_bound| and |sampler|.
COMPONENT_EXPORT(GFX)
SkColor CalculateKMeanColorOfPNG(base::span<const uint8_t> png);

// Computes a dominant color for the first |height| rows of |bitmap| using the
// above algorithm and a reasonable default sampler. If |find_closest| is true,
// the returned color will be the closest color to the true K-mean color that
// actually appears in the image; if false, the true color is returned
// regardless of whether it actually appears.
COMPONENT_EXPORT(GFX)
SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap,
                                    int height,
                                    const HSL& lower_bound,
                                    const HSL& upper_bound,
                                    bool find_closest);

// Computes a dominant color using the above algorithm and reasonable defaults
// for |lower_bound|, |upper_bound| and |sampler|.
COMPONENT_EXPORT(GFX)
SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap);

// These enums specify general values to look for when calculating prominent
// colors from an image. For example, a "light vibrant" prominent color would
// tend to be brighter and more saturated. The best combination of color
// attributes depends on how you plan to apply the color.
enum class LumaRange {
  ANY,
  LIGHT,
  NORMAL,
  DARK,
};

enum class SaturationRange {
  ANY,
  VIBRANT,
  MUTED,
};

struct ColorProfile {
  ColorProfile() = default;
  ColorProfile(LumaRange l, SaturationRange s) : luma(l), saturation(s) {}

  LumaRange luma = LumaRange::DARK;
  SaturationRange saturation = SaturationRange::MUTED;
};

// A color value with an associated weight.
struct Swatch {
  Swatch() : Swatch(SK_ColorTRANSPARENT, 0) {}

  Swatch(SkColor color, size_t population)
      : color(color), population(population) {}

  SkColor color;

  // The population correlates to a count, so it should be 1 or greater.
  size_t population;

  bool operator==(const Swatch& other) const {
    return color == other.color && population == other.population;
  }
};

// Used to filter colors from swatches. Called with the candidate color and will
// return true if the color should be allowed.
using ColorSwatchFilter = base::RepeatingCallback<bool(const SkColor&)>;

// The maximum number of pixels to consider when generating swatches.
COMPONENT_EXPORT(GFX) extern const int kMaxConsideredPixelsForSwatches;

// Returns a vector of |Swatch| that represent the prominent colors of the
// bitmap within |region|. The |max_swatches| is the maximum number of swatches.
// For landscapes, good values are in the range 12-16. For images which are
// largely made up of people's faces then this value should be increased to
// 24-32. |filter| is an optional filter that can filter out unwanted colors.
// This is an implementation of the Android Palette API:
// https://developer.android.com/reference/android/support/v7/graphics/Palette
COMPONENT_EXPORT(GFX)
std::vector<Swatch> CalculateColorSwatches(
    const SkBitmap& bitmap,
    size_t max_swatches,
    const gfx::Rect& region,
    std::optional<ColorSwatchFilter> filter);

// Returns a vector of RGB colors that represents the bitmap based on the
// |color_profiles| provided. For each value, if a value is succesfully
// calculated, the calculated value is fully opaque. For failure, the calculated
// value is transparent. |region| can be provided to select a specific area of
// the bitmap. |filter| is an optional filter that can filter out unwanted
// colors. If |filter| is not provided then we will filter out uninteresting
// colors.
COMPONENT_EXPORT(GFX)
std::vector<Swatch> CalculateProminentColorsOfBitmap(
    const SkBitmap& bitmap,
    const std::vector<ColorProfile>& color_profiles,
    gfx::Rect* region,
    ColorSwatchFilter filter);

}  // namespace color_utils

#endif  // UI_GFX_COLOR_ANALYSIS_H_