summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormotek@chromium.org <motek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-13 08:21:46 +0000
committermotek@chromium.org <motek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-13 08:21:46 +0000
commit75f2d5a4a7e52b349703dc52a5244cda371fc334 (patch)
tree4664634ffd22847fe4f1f14ecdb2663b8971ff18
parent3f1d4939ca115110c6c98abf37666c3f95c69ebf (diff)
downloadchromium_src-75f2d5a4a7e52b349703dc52a5244cda371fc334.zip
chromium_src-75f2d5a4a7e52b349703dc52a5244cda371fc334.tar.gz
chromium_src-75f2d5a4a7e52b349703dc52a5244cda371fc334.tar.bz2
Adds a function computing image color covariance on an SkBitmap.
BUG=155269 Review URL: https://chromiumcodereview.appspot.com/12220123 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182163 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ui/gfx/color_analysis.cc68
-rw-r--r--ui/gfx/color_analysis.h4
-rw-r--r--ui/gfx/color_analysis_unittest.cc36
3 files changed, 108 insertions, 0 deletions
diff --git a/ui/gfx/color_analysis.cc b/ui/gfx/color_analysis.cc
index 2925c06..8878519 100644
--- a/ui/gfx/color_analysis.cc
+++ b/ui/gfx/color_analysis.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <vector>
+#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
@@ -399,4 +400,71 @@ SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap) {
return color;
}
+gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap) {
+ // First need basic stats to normalize each channel separately.
+ SkAutoLockPixels bitmap_lock(bitmap);
+ gfx::Matrix3F covariance = gfx::Matrix3F::Zeros();
+ if (!bitmap.getPixels())
+ return covariance;
+
+ // Assume ARGB_8888 format.
+ DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
+
+ int64_t r_sum = 0;
+ int64_t g_sum = 0;
+ int64_t b_sum = 0;
+ int64_t rr_sum = 0;
+ int64_t gg_sum = 0;
+ int64_t bb_sum = 0;
+ int64_t rg_sum = 0;
+ int64_t rb_sum = 0;
+ int64_t gb_sum = 0;
+
+ for (int y = 0; y < bitmap.height(); ++y) {
+ SkPMColor* current_color = static_cast<uint32_t*>(bitmap.getAddr32(0, y));
+ for (int x = 0; x < bitmap.width(); ++x, ++current_color) {
+ SkColor c = SkUnPreMultiply::PMColorToColor(*current_color);
+ SkColor r = SkColorGetR(c);
+ SkColor g = SkColorGetG(c);
+ SkColor b = SkColorGetB(c);
+
+ r_sum += r;
+ g_sum += g;
+ b_sum += b;
+ rr_sum += r * r;
+ gg_sum += g * g;
+ bb_sum += b * b;
+ rg_sum += r * g;
+ rb_sum += r * b;
+ gb_sum += g * b;
+ }
+ }
+
+ // Covariance (not normalized) is E(X*X.t) - m * m.t and this is how it
+ // is calculated below.
+ // Each row below represents a row of the matrix describing (co)variances
+ // of R, G and B channels with (R, G, B)
+ int pixel_n = bitmap.width() * bitmap.height();
+ covariance.set(
+ (static_cast<double>(rr_sum) / pixel_n -
+ static_cast<double>(r_sum * r_sum) / pixel_n / pixel_n),
+ (static_cast<double>(rg_sum) / pixel_n -
+ static_cast<double>(r_sum * g_sum) / pixel_n / pixel_n),
+ (static_cast<double>(rb_sum) / pixel_n -
+ static_cast<double>(r_sum * b_sum) / pixel_n / pixel_n),
+ (static_cast<double>(rg_sum) / pixel_n -
+ static_cast<double>(r_sum * g_sum) / pixel_n / pixel_n),
+ (static_cast<double>(gg_sum) / pixel_n -
+ static_cast<double>(g_sum * g_sum) / pixel_n / pixel_n),
+ (static_cast<double>(gb_sum) / pixel_n -
+ static_cast<double>(g_sum * b_sum) / pixel_n / pixel_n),
+ (static_cast<double>(rb_sum) / pixel_n -
+ static_cast<double>(r_sum * b_sum) / pixel_n / pixel_n),
+ (static_cast<double>(gb_sum) / pixel_n -
+ static_cast<double>(g_sum * b_sum) / pixel_n / pixel_n),
+ (static_cast<double>(bb_sum) / pixel_n -
+ static_cast<double>(b_sum * b_sum) / pixel_n / pixel_n));
+ return covariance;
+}
+
} // color_utils
diff --git a/ui/gfx/color_analysis.h b/ui/gfx/color_analysis.h
index 6201874..0d208f8 100644
--- a/ui/gfx/color_analysis.h
+++ b/ui/gfx/color_analysis.h
@@ -11,6 +11,7 @@
#include "base/memory/ref_counted_memory.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/ui_export.h"
+#include "ui/gfx/matrix3_f.h"
class SkBitmap;
@@ -98,6 +99,9 @@ UI_EXPORT SkColor CalculateKMeanColorOfPNG(
// reasonable defaults for |darkness_limit|, |brightness_limit| and |sampler|.
UI_EXPORT SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap);
+// Compute color covariance matrix for the input bitmap.
+UI_EXPORT gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap);
+
} // namespace color_utils
#endif // UI_GFX_COLOR_ANALYSIS_H_
diff --git a/ui/gfx/color_analysis_unittest.cc b/ui/gfx/color_analysis_unittest.cc
index b92deb4..d895369 100644
--- a/ui/gfx/color_analysis_unittest.cc
+++ b/ui/gfx/color_analysis_unittest.cc
@@ -9,6 +9,8 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/rect.h"
using color_utils::FindClosestColor;
@@ -257,3 +259,37 @@ TEST_F(ColorAnalysisTest, CalculateKMeanColorOfBitmap) {
EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color)));
EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color)));
}
+
+TEST_F(ColorAnalysisTest, ComputeColorCovarianceTrivial) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 200);
+
+ EXPECT_EQ(gfx::Matrix3F::Zeros(),
+ color_utils::ComputeColorCovariance(bitmap));
+ bitmap.allocPixels();
+ bitmap.eraseRGB(50, 150, 200);
+ gfx::Matrix3F covariance = color_utils::ComputeColorCovariance(bitmap);
+ // The answer should be all zeros.
+ EXPECT_TRUE(covariance == gfx::Matrix3F::Zeros());
+}
+
+TEST_F(ColorAnalysisTest, ComputeColorCovarianceWithCanvas) {
+ gfx::Canvas canvas(gfx::Size(250, 200), ui::SCALE_FACTOR_100P, true);
+ // The image consists of vertical stripes, with color bands set to 100
+ // in overlapping stripes 150 pixels wide.
+ canvas.FillRect(gfx::Rect(0, 0, 50, 200), SkColorSetRGB(100, 0, 0));
+ canvas.FillRect(gfx::Rect(50, 0, 50, 200), SkColorSetRGB(100, 100, 0));
+ canvas.FillRect(gfx::Rect(100, 0, 50, 200), SkColorSetRGB(100, 100, 100));
+ canvas.FillRect(gfx::Rect(150, 0, 50, 200), SkColorSetRGB(0, 100, 100));
+ canvas.FillRect(gfx::Rect(200, 0, 50, 200), SkColorSetRGB(0, 0, 100));
+
+ SkBitmap bitmap =
+ skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
+ gfx::Matrix3F covariance = color_utils::ComputeColorCovariance(bitmap);
+
+ gfx::Matrix3F expected_covariance = gfx::Matrix3F::Zeros();
+ expected_covariance.set(2400, 400, -1600,
+ 400, 2400, 400,
+ -1600, 400, 2400);
+ EXPECT_EQ(expected_covariance, covariance);
+}