diff options
author | motek@chromium.org <motek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-13 08:21:46 +0000 |
---|---|---|
committer | motek@chromium.org <motek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-13 08:21:46 +0000 |
commit | 75f2d5a4a7e52b349703dc52a5244cda371fc334 (patch) | |
tree | 4664634ffd22847fe4f1f14ecdb2663b8971ff18 | |
parent | 3f1d4939ca115110c6c98abf37666c3f95c69ebf (diff) | |
download | chromium_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.cc | 68 | ||||
-rw-r--r-- | ui/gfx/color_analysis.h | 4 | ||||
-rw-r--r-- | ui/gfx/color_analysis_unittest.cc | 36 |
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); +} |