Commit e61f7919 authored by v.paturi's avatar v.paturi Committed by Commit Bot

Remove image's min size dependence on blocks count in dark mode.

With the blocks count fixed at 10, the images whose width or
height is lesser than 10 cannot be classified as it leads to
division with 0 scenarios while extracting the pixels from
the bitmap.

The blocks count is reduced when necessary depending on the
width and height of |src_rect| so that the minimum size of
the image doesn't have to be limited.

Blocks count is maintained separately for horizontal and
vertical directions as opposed to the current |kBlocksCount1D|
that is used for both directions.

A unit test is added to check the correctness and minor
refactoring is done to the test file to avoid code repetition.

Bug: 997569
Change-Id: Ib8776a033ca32f4d9b57c80d1bf7e6f0b31ecf5b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1772925
Commit-Queue: Varun Chowdhary Paturi <v.paturi@samsung.com>
Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Reviewed-by: default avatarPrashant Nevase <prashant.n@samsung.com>
Cr-Commit-Position: refs/heads/master@{#695916}
parent 32fcd489
...@@ -33,7 +33,9 @@ const float kMinOpaquePixelPercentageForForeground = 0.2; ...@@ -33,7 +33,9 @@ const float kMinOpaquePixelPercentageForForeground = 0.2;
} // namespace } // namespace
DarkModeImageClassifier::DarkModeImageClassifier() DarkModeImageClassifier::DarkModeImageClassifier()
: pixels_to_sample_(kPixelsToSample) {} : pixels_to_sample_(kPixelsToSample),
blocks_count_horizontal_(kBlocksCount1D),
blocks_count_vertical_(kBlocksCount1D) {}
DarkModeClassification DarkModeImageClassifier::Classify( DarkModeClassification DarkModeImageClassifier::Classify(
Image* image, Image* image,
...@@ -42,15 +44,6 @@ DarkModeClassification DarkModeImageClassifier::Classify( ...@@ -42,15 +44,6 @@ DarkModeClassification DarkModeImageClassifier::Classify(
if (result != DarkModeClassification::kNotClassified) if (result != DarkModeClassification::kNotClassified)
return result; return result;
// TODO(v.paturi): This is a limitation that arises because of the way
// GetSamples() is implemented. Try to get rid of this limitation.
if (src_rect.Width() <= kBlocksCount1D ||
src_rect.Height() <= kBlocksCount1D) {
result = DarkModeClassification::kDoNotApplyFilter;
image->AddDarkModeClassification(src_rect, result);
return result;
}
result = image->CheckTypeSpecificConditionsForDarkMode(src_rect, this); result = image->CheckTypeSpecificConditionsForDarkMode(src_rect, this);
if (result != DarkModeClassification::kNotClassified) { if (result != DarkModeClassification::kNotClassified) {
image->AddDarkModeClassification(src_rect, result); image->AddDarkModeClassification(src_rect, result);
...@@ -77,6 +70,12 @@ DarkModeImageClassifier::GetFeatures(Image* image, const FloatRect& src_rect) { ...@@ -77,6 +70,12 @@ DarkModeImageClassifier::GetFeatures(Image* image, const FloatRect& src_rect) {
if (pixels_to_sample_ > src_rect.Width() * src_rect.Height()) if (pixels_to_sample_ > src_rect.Width() * src_rect.Height())
pixels_to_sample_ = src_rect.Width() * src_rect.Height(); pixels_to_sample_ = src_rect.Width() * src_rect.Height();
if (blocks_count_horizontal_ > src_rect.Width())
blocks_count_horizontal_ = floor(src_rect.Width());
if (blocks_count_vertical_ > src_rect.Height())
blocks_count_vertical_ = floor(src_rect.Height());
float transparency_ratio; float transparency_ratio;
float background_ratio; float background_ratio;
Vector<SkColor> sampled_pixels; Vector<SkColor> sampled_pixels;
...@@ -97,26 +96,30 @@ void DarkModeImageClassifier::GetSamples(const SkBitmap& bitmap, ...@@ -97,26 +96,30 @@ void DarkModeImageClassifier::GetSamples(const SkBitmap& bitmap,
Vector<SkColor>* sampled_pixels, Vector<SkColor>* sampled_pixels,
float* transparency_ratio, float* transparency_ratio,
float* background_ratio) { float* background_ratio) {
int pixels_per_block = pixels_to_sample_ / (kBlocksCount1D * kBlocksCount1D); int pixels_per_block =
pixels_to_sample_ / (blocks_count_horizontal_ * blocks_count_vertical_);
int transparent_pixels = 0; int transparent_pixels = 0;
int opaque_pixels = 0; int opaque_pixels = 0;
int blocks_count = 0; int blocks_count = 0;
Vector<int> horizontal_grid(kBlocksCount1D + 1); Vector<int> horizontal_grid(blocks_count_horizontal_ + 1);
Vector<int> vertical_grid(kBlocksCount1D + 1); Vector<int> vertical_grid(blocks_count_vertical_ + 1);
for (int block = 0; block <= kBlocksCount1D; block++) {
horizontal_grid[block] = static_cast<int>( for (int block = 0; block <= blocks_count_horizontal_; block++) {
round(block * bitmap.width() / static_cast<float>(kBlocksCount1D))); horizontal_grid[block] = static_cast<int>(round(
vertical_grid[block] = static_cast<int>( block * bitmap.width() / static_cast<float>(blocks_count_horizontal_)));
round(block * bitmap.height() / static_cast<float>(kBlocksCount1D))); }
for (int block = 0; block <= blocks_count_vertical_; block++) {
vertical_grid[block] = static_cast<int>(round(
block * bitmap.height() / static_cast<float>(blocks_count_vertical_)));
} }
sampled_pixels->clear(); sampled_pixels->clear();
Vector<IntRect> foreground_blocks; Vector<IntRect> foreground_blocks;
for (int y = 0; y < kBlocksCount1D; y++) { for (int y = 0; y < blocks_count_vertical_; y++) {
for (int x = 0; x < kBlocksCount1D; x++) { for (int x = 0; x < blocks_count_horizontal_; x++) {
IntRect block(horizontal_grid[x], vertical_grid[y], IntRect block(horizontal_grid[x], vertical_grid[y],
horizontal_grid[x + 1] - horizontal_grid[x], horizontal_grid[x + 1] - horizontal_grid[x],
vertical_grid[y + 1] - vertical_grid[y]); vertical_grid[y + 1] - vertical_grid[y]);
...@@ -239,4 +242,10 @@ float DarkModeImageClassifier::ComputeColorBucketsRatio( ...@@ -239,4 +242,10 @@ float DarkModeImageClassifier::ComputeColorBucketsRatio(
max_buckets[color_mode == ColorMode::kColor]; max_buckets[color_mode == ColorMode::kColor];
} }
void DarkModeImageClassifier::ResetDataMembersToDefaults() {
pixels_to_sample_ = kPixelsToSample;
blocks_count_horizontal_ = kBlocksCount1D;
blocks_count_vertical_ = kBlocksCount1D;
}
} // namespace blink } // namespace blink
...@@ -54,6 +54,24 @@ class PLATFORM_EXPORT DarkModeImageClassifier { ...@@ -54,6 +54,24 @@ class PLATFORM_EXPORT DarkModeImageClassifier {
void SetImageType(ImageType image_type) { image_type_ = image_type; } void SetImageType(ImageType image_type) { image_type_ = image_type; }
// Functions for testing.
void SetHorizontalBlocksCount(int horizontal_blocks) {
blocks_count_horizontal_ = horizontal_blocks;
}
void SetVerticalBlocksCount(int vertical_blocks) {
blocks_count_vertical_ = vertical_blocks;
}
int HorizontalBlocksCount() { return blocks_count_horizontal_; }
int VerticalBlocksCount() { return blocks_count_vertical_; }
void ResetDataMembersToDefaults();
// End of Functions for testing.
private: private:
enum class ColorMode { kColor = 0, kGrayscale = 1 }; enum class ColorMode { kColor = 0, kGrayscale = 1 };
...@@ -86,6 +104,12 @@ class PLATFORM_EXPORT DarkModeImageClassifier { ...@@ -86,6 +104,12 @@ class PLATFORM_EXPORT DarkModeImageClassifier {
const ColorMode color_mode); const ColorMode color_mode);
int pixels_to_sample_; int pixels_to_sample_;
// Holds the number of blocks in the horizontal direction when the image is
// divided into a grid of blocks.
int blocks_count_horizontal_;
// Holds the number of blocks in the vertical direction when the image is
// divided into a grid of blocks.
int blocks_count_vertical_;
ImageType image_type_; ImageType image_type_;
}; };
......
...@@ -54,43 +54,49 @@ class FakeImageForCacheTest : public Image { ...@@ -54,43 +54,49 @@ class FakeImageForCacheTest : public Image {
class DarkModeImageClassifierTest : public testing::Test { class DarkModeImageClassifierTest : public testing::Test {
public: public:
// Loads the image from |file_name|, computes features into |features|, // Loads the image from |file_name|.
// and returns the classification result. scoped_refptr<BitmapImage> GetImage(const String& file_name) {
bool GetFeaturesAndClassification(
const String& file_name,
DarkModeImageClassifier::Features* features) {
CHECK(features);
SCOPED_TRACE(file_name); SCOPED_TRACE(file_name);
scoped_refptr<BitmapImage> image = LoadImage(file_name); String file_path = test::BlinkWebTestsDir() + file_name;
DarkModeImageClassifier dark_mode_image_classifier; scoped_refptr<SharedBuffer> image_data = test::ReadFromFile(file_path);
dark_mode_image_classifier.SetImageType( EXPECT_TRUE(image_data.get() && image_data.get()->size());
scoped_refptr<BitmapImage> image = BitmapImage::Create();
image->SetData(image_data, true);
return image;
}
// Computes features into |features|.
void GetFeatures(scoped_refptr<BitmapImage> image,
DarkModeImageClassifier::Features* features) {
CHECK(features);
dark_mode_image_classifier_.SetImageType(
DarkModeImageClassifier::ImageType::kBitmap); DarkModeImageClassifier::ImageType::kBitmap);
auto features_or_null = dark_mode_image_classifier.GetFeatures( auto features_or_null = dark_mode_image_classifier_.GetFeatures(
image.get(), FloatRect(0, 0, image->width(), image->height())); image.get(), FloatRect(0, 0, image->width(), image->height()));
CHECK(features_or_null.has_value()); CHECK(features_or_null.has_value());
(*features) = features_or_null.value(); (*features) = features_or_null.value();
}
// Returns the classification result.
bool GetClassification(const DarkModeImageClassifier::Features features) {
DarkModeClassification result = DarkModeClassification result =
dark_mode_generic_classifier_.ClassifyWithFeatures(*features); dark_mode_generic_classifier_.ClassifyWithFeatures(features);
return result == DarkModeClassification::kApplyFilter; return result == DarkModeClassification::kApplyFilter;
} }
DarkModeGenericClassifier* classifier() { DarkModeImageClassifier* image_classifier() {
return &dark_mode_generic_classifier_; return &dark_mode_image_classifier_;
} }
protected: DarkModeGenericClassifier* generic_classifier() {
scoped_refptr<BitmapImage> LoadImage(const String& file_name) { return &dark_mode_generic_classifier_;
String file_path = test::BlinkWebTestsDir() + file_name;
scoped_refptr<SharedBuffer> image_data = test::ReadFromFile(file_path);
EXPECT_TRUE(image_data.get() && image_data.get()->size());
scoped_refptr<BitmapImage> image = BitmapImage::Create();
image->SetData(image_data, true);
return image;
} }
protected:
ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler> ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
platform_; platform_;
DarkModeImageClassifier dark_mode_image_classifier_;
DarkModeGenericClassifier dark_mode_generic_classifier_; DarkModeGenericClassifier dark_mode_generic_classifier_;
}; };
...@@ -102,9 +108,13 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) { ...@@ -102,9 +108,13 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
// Color Buckets Ratio: Low // Color Buckets Ratio: Low
// Decision Tree: Apply // Decision Tree: Apply
// Neural Network: NA // Neural Network: NA
EXPECT_TRUE(GetFeaturesAndClassification("/images/resources/grid-large.png",
&features)); // The data members of DarkModeImageClassifier have to be reset for every
EXPECT_EQ(classifier()->ClassifyUsingDecisionTreeForTesting(features), // image as the same classifier object is used for all the tests.
image_classifier()->ResetDataMembersToDefaults();
GetFeatures(GetImage("/images/resources/grid-large.png"), &features);
EXPECT_TRUE(GetClassification(features));
EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
DarkModeClassification::kApplyFilter); DarkModeClassification::kApplyFilter);
EXPECT_FALSE(features.is_colorful); EXPECT_FALSE(features.is_colorful);
EXPECT_FALSE(features.is_svg); EXPECT_FALSE(features.is_svg);
...@@ -117,9 +127,10 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) { ...@@ -117,9 +127,10 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
// Color Buckets Ratio: Medium // Color Buckets Ratio: Medium
// Decision Tree: Can't Decide // Decision Tree: Can't Decide
// Neural Network: Apply // Neural Network: Apply
EXPECT_FALSE(GetFeaturesAndClassification("/images/resources/apng08-ref.png", image_classifier()->ResetDataMembersToDefaults();
&features)); GetFeatures(GetImage("/images/resources/apng08-ref.png"), &features);
EXPECT_EQ(classifier()->ClassifyUsingDecisionTreeForTesting(features), EXPECT_FALSE(GetClassification(features));
EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
DarkModeClassification::kNotClassified); DarkModeClassification::kNotClassified);
EXPECT_FALSE(features.is_colorful); EXPECT_FALSE(features.is_colorful);
EXPECT_FALSE(features.is_svg); EXPECT_FALSE(features.is_svg);
...@@ -132,9 +143,10 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) { ...@@ -132,9 +143,10 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
// Color Buckets Ratio: Low // Color Buckets Ratio: Low
// Decision Tree: Apply // Decision Tree: Apply
// Neural Network: NA. // Neural Network: NA.
EXPECT_TRUE(GetFeaturesAndClassification( image_classifier()->ResetDataMembersToDefaults();
"/images/resources/twitter_favicon.ico", &features)); GetFeatures(GetImage("/images/resources/twitter_favicon.ico"), &features);
EXPECT_EQ(classifier()->ClassifyUsingDecisionTreeForTesting(features), EXPECT_TRUE(GetClassification(features));
EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
DarkModeClassification::kApplyFilter); DarkModeClassification::kApplyFilter);
EXPECT_TRUE(features.is_colorful); EXPECT_TRUE(features.is_colorful);
EXPECT_FALSE(features.is_svg); EXPECT_FALSE(features.is_svg);
...@@ -147,9 +159,11 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) { ...@@ -147,9 +159,11 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
// Color Buckets Ratio: High // Color Buckets Ratio: High
// Decision Tree: Do Not Apply // Decision Tree: Do Not Apply
// Neural Network: NA. // Neural Network: NA.
EXPECT_FALSE(GetFeaturesAndClassification( image_classifier()->ResetDataMembersToDefaults();
"/images/resources/blue-wheel-srgb-color-profile.png", &features)); GetFeatures(GetImage("/images/resources/blue-wheel-srgb-color-profile.png"),
EXPECT_EQ(classifier()->ClassifyUsingDecisionTreeForTesting(features), &features);
EXPECT_FALSE(GetClassification(features));
EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
DarkModeClassification::kDoNotApplyFilter); DarkModeClassification::kDoNotApplyFilter);
EXPECT_TRUE(features.is_colorful); EXPECT_TRUE(features.is_colorful);
EXPECT_FALSE(features.is_svg); EXPECT_FALSE(features.is_svg);
...@@ -162,9 +176,10 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) { ...@@ -162,9 +176,10 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
// Color Buckets Ratio: Medium // Color Buckets Ratio: Medium
// Decision Tree: Apply // Decision Tree: Apply
// Neural Network: NA. // Neural Network: NA.
EXPECT_TRUE(GetFeaturesAndClassification( image_classifier()->ResetDataMembersToDefaults();
"/images/resources/ycbcr-444-float.jpg", &features)); GetFeatures(GetImage("/images/resources/ycbcr-444-float.jpg"), &features);
EXPECT_EQ(classifier()->ClassifyUsingDecisionTreeForTesting(features), EXPECT_TRUE(GetClassification(features));
EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
DarkModeClassification::kApplyFilter); DarkModeClassification::kApplyFilter);
EXPECT_TRUE(features.is_colorful); EXPECT_TRUE(features.is_colorful);
EXPECT_FALSE(features.is_svg); EXPECT_FALSE(features.is_svg);
...@@ -201,4 +216,41 @@ TEST_F(DarkModeImageClassifierTest, Caching) { ...@@ -201,4 +216,41 @@ TEST_F(DarkModeImageClassifierTest, Caching) {
EXPECT_EQ(image->GetMapSize(), 3); EXPECT_EQ(image->GetMapSize(), 3);
} }
TEST_F(DarkModeImageClassifierTest, BlocksCount) {
scoped_refptr<BitmapImage> image =
GetImage("/images/resources/grid-large.png");
DarkModeImageClassifier::Features features;
image_classifier()->ResetDataMembersToDefaults();
// When the horizontal and vertical blocks counts are lesser than the
// image dimensions, they should remain unaltered.
image_classifier()->SetHorizontalBlocksCount((int)(image->width() - 1));
image_classifier()->SetVerticalBlocksCount((int)(image->height() - 1));
GetFeatures(image, &features);
EXPECT_EQ(image_classifier()->HorizontalBlocksCount(),
(int)(image->width() - 1));
EXPECT_EQ(image_classifier()->VerticalBlocksCount(),
(int)(image->height() - 1));
// When the horizontal and vertical blocks counts are lesser than the
// image dimensions, they should remain unaltered.
image_classifier()->SetHorizontalBlocksCount((int)(image->width()));
image_classifier()->SetVerticalBlocksCount((int)(image->height()));
GetFeatures(image, &features);
EXPECT_EQ(image_classifier()->HorizontalBlocksCount(),
(int)(image->width()));
EXPECT_EQ(image_classifier()->VerticalBlocksCount(),
(int)(image->height()));
// When the horizontal and vertical blocks counts are greater than the
// image dimensions, they should be reduced.
image_classifier()->SetHorizontalBlocksCount((int)(image->width() + 1));
image_classifier()->SetVerticalBlocksCount((int)(image->height() + 1));
GetFeatures(image, &features);
EXPECT_EQ(image_classifier()->HorizontalBlocksCount(),
floor(image->width()));
EXPECT_EQ(image_classifier()->VerticalBlocksCount(),
floor(image->height()));
}
} // namespace blink } // namespace blink
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