Commit 75f2d5a4 authored by motek@chromium.org's avatar motek@chromium.org

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
parent 3f1d4939
......@@ -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
......@@ -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_
......@@ -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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment