Commit 621a4e6a authored by Ramin Halavati's avatar Ramin Halavati Committed by Commit Bot

Neural Network added to High Contrast classifier.

A tfNative generated neural network is added to High Contrast classifier
to make a better decision for images which are not decidable using the
decision tree.

Bug: 685242
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: I4c30f785d7ca65d129fb09902b748978dd6de4f6
Reviewed-on: https://chromium-review.googlesource.com/753588Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Commit-Queue: Ramin Halavati <rhalavati@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517387}
parent 215894f0
...@@ -1086,6 +1086,8 @@ jumbo_component("platform") { ...@@ -1086,6 +1086,8 @@ jumbo_component("platform") {
"graphics/gpu/SharedGpuContext.h", "graphics/gpu/SharedGpuContext.h",
"graphics/gpu/WebGLImageConversion.cpp", "graphics/gpu/WebGLImageConversion.cpp",
"graphics/gpu/WebGLImageConversion.h", "graphics/gpu/WebGLImageConversion.h",
"graphics/highcontrast/highcontrast_classifier.cc",
"graphics/highcontrast/highcontrast_classifier.h",
"graphics/paint/ClipDisplayItem.cpp", "graphics/paint/ClipDisplayItem.cpp",
"graphics/paint/ClipDisplayItem.h", "graphics/paint/ClipDisplayItem.h",
"graphics/paint/ClipPaintPropertyNode.cpp", "graphics/paint/ClipPaintPropertyNode.cpp",
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "platform/graphics/HighContrastImageClassifier.h" #include "platform/graphics/HighContrastImageClassifier.h"
#include "base/rand_util.h" #include "base/rand_util.h"
#include "platform/graphics/highcontrast/highcontrast_classifier.h"
#include "third_party/WebKit/Source/platform/geometry/IntRect.h" #include "third_party/WebKit/Source/platform/geometry/IntRect.h"
#include "third_party/skia/include/utils/SkNullCanvas.h" #include "third_party/skia/include/utils/SkNullCanvas.h"
...@@ -41,6 +42,10 @@ const int kPixelsToSample = 1000; ...@@ -41,6 +42,10 @@ const int kPixelsToSample = 1000;
const int kBlocksCount1D = 10; const int kBlocksCount1D = 10;
const int kMinImageSizeForClassification1D = 24; const int kMinImageSizeForClassification1D = 24;
// Decision tree lower and upper thresholds for grayscale and color images.
const float kLowColorCountThreshold[2] = {0.8125, 0.015137};
const float kHighColorCountThreshold[2] = {1, 0.025635};
} // namespace } // namespace
namespace blink { namespace blink {
...@@ -253,7 +258,7 @@ bool HighContrastImageClassifier::IsBlockBackground( ...@@ -253,7 +258,7 @@ bool HighContrastImageClassifier::IsBlockBackground(
// 1: Ratio of the number of bucketed colors used in the image to all // 1: Ratio of the number of bucketed colors used in the image to all
// possiblities. Color buckets are represented with 4 bits per color channel. // possiblities. Color buckets are represented with 4 bits per color channel.
// 2: Ratio of transparent area to the whole image. // 2: Ratio of transparent area to the whole image.
// 3: Ratio of the brackground area to the whole image. // 3: Ratio of the background area to the whole image.
void HighContrastImageClassifier::GetFeatures( void HighContrastImageClassifier::GetFeatures(
const std::vector<SkColor>& sampled_pixels, const std::vector<SkColor>& sampled_pixels,
const float transparency_ratio, const float transparency_ratio,
...@@ -316,18 +321,46 @@ float HighContrastImageClassifier::ComputeColorBucketsRatio( ...@@ -316,18 +321,46 @@ float HighContrastImageClassifier::ComputeColorBucketsRatio(
max_buckets[color_mode == ColorMode::kColor]; max_buckets[color_mode == ColorMode::kColor];
} }
HighContrastClassification HighContrastImageClassifier::ClassifyImage( HighContrastClassification
HighContrastImageClassifier::ClassifyImageUsingDecisionTree(
const std::vector<float>& features) { const std::vector<float>& features) {
bool result = false; DCHECK_EQ(features.size(), 4u);
int is_color = features[0] > 0;
float color_count_ratio = features[1];
float low_color_count_threshold = kLowColorCountThreshold[is_color];
float high_color_count_threshold = kHighColorCountThreshold[is_color];
// Very few colors means it's not a photo, apply the filter.
if (color_count_ratio < low_color_count_threshold)
return HighContrastClassification::kApplyHighContrastFilter;
// Too many colors means it's probably photorealistic, do not apply it.
if (color_count_ratio > high_color_count_threshold)
return HighContrastClassification::kDoNotApplyHighContrastFilter;
// Shallow decision tree trained by C4.5. // In-between, decision tree cannot give a precise result.
if (features.size() >= 2) { return HighContrastClassification::kNotClassified;
float threshold = (features[0] == 0) ? 0.8125 : 0.0166; }
result = features[1] < threshold;
HighContrastClassification HighContrastImageClassifier::ClassifyImage(
const std::vector<float>& features) {
DCHECK_EQ(features.size(), 4u);
HighContrastClassification result = ClassifyImageUsingDecisionTree(features);
// If decision tree cannot decide, we use a neural network to decide whether
// to filter or not based on all the features.
if (result == HighContrastClassification::kNotClassified) {
highcontrast_tfnative_model::FixedAllocations nn_temp;
float nn_out;
highcontrast_tfnative_model::Inference(&features[0], &nn_out, &nn_temp);
result = nn_out > 0
? HighContrastClassification::kApplyHighContrastFilter
: HighContrastClassification::kDoNotApplyHighContrastFilter;
} }
return result ? HighContrastClassification::kApplyHighContrastFilter return result;
: HighContrastClassification::kDoNotApplyHighContrastFilter;
} }
} // namespace blink } // namespace blink
...@@ -29,6 +29,11 @@ class PLATFORM_EXPORT HighContrastImageClassifier { ...@@ -29,6 +29,11 @@ class PLATFORM_EXPORT HighContrastImageClassifier {
void SetRandomGeneratorForTesting() { use_testing_random_generator_ = true; } void SetRandomGeneratorForTesting() { use_testing_random_generator_ = true; }
HighContrastClassification ClassifyImageUsingDecisionTreeForTesting(
const std::vector<float>& features) {
return ClassifyImageUsingDecisionTree(features);
}
private: private:
enum class ColorMode { kColor = 0, kGrayscale = 1 }; enum class ColorMode { kColor = 0, kGrayscale = 1 };
...@@ -76,6 +81,12 @@ class PLATFORM_EXPORT HighContrastImageClassifier { ...@@ -76,6 +81,12 @@ class PLATFORM_EXPORT HighContrastImageClassifier {
// Returns a random number in range [min, max). // Returns a random number in range [min, max).
int GetRandomInt(const int min, const int max); int GetRandomInt(const int min, const int max);
// Decides if the filter should be applied to the image or not, only using the
// decision tree. Returns 'kNotClassified' if decision tree cannot give a
// trustable answer.
HighContrastClassification ClassifyImageUsingDecisionTree(
const std::vector<float>&);
bool use_testing_random_generator_; bool use_testing_random_generator_;
int testing_random_generator_seed_; int testing_random_generator_seed_;
}; };
......
...@@ -39,12 +39,14 @@ class HighContrastImageClassifierTest : public ::testing::Test { ...@@ -39,12 +39,14 @@ class HighContrastImageClassifierTest : public ::testing::Test {
} }
} }
HighContrastImageClassifier* classifier() { return &classifier_; }
protected: protected:
scoped_refptr<BitmapImage> LoadImage(const std::string& file_name) { scoped_refptr<BitmapImage> LoadImage(const std::string& file_name) {
String file_path = testing::BlinkRootDir(); String file_path = testing::BlinkRootDir();
file_path.append(file_name.c_str()); file_path.append(file_name.c_str());
scoped_refptr<SharedBuffer> image_data = testing::ReadFromFile(file_path); scoped_refptr<SharedBuffer> image_data = testing::ReadFromFile(file_path);
EXPECT_TRUE(image_data.get()); EXPECT_TRUE(image_data.get() && image_data.get()->size());
scoped_refptr<BitmapImage> image = BitmapImage::Create(); scoped_refptr<BitmapImage> image = BitmapImage::Create();
image->SetData(image_data, true); image->SetData(image_data, true);
...@@ -60,15 +62,60 @@ TEST_F(HighContrastImageClassifierTest, FeaturesAndClassification) { ...@@ -60,15 +62,60 @@ TEST_F(HighContrastImageClassifierTest, FeaturesAndClassification) {
std::vector<float> features; std::vector<float> features;
// Test Case 1: // Test Case 1:
// Grayscale
// Color Buckets Ratio: Low
// Decision Tree: Apply
// Neural Network: NA
EXPECT_TRUE(GetFeaturesAndClassification(
"/LayoutTests/images/resources/grid-large.png", &features));
EXPECT_EQ(classifier()->ClassifyImageUsingDecisionTreeForTesting(features),
HighContrastClassification::kApplyHighContrastFilter);
AssertFeaturesEqual(features, {0.0f, 0.1875f, 0.0f, 0.1f});
// Test Case 2:
// Grayscale
// Color Buckets Ratio: Medium
// Decision Tree: Can't Decide
// Neural Network: Apply
EXPECT_TRUE(GetFeaturesAndClassification(
"/LayoutTests/images/resources/apng08-ref.png", &features));
EXPECT_EQ(classifier()->ClassifyImageUsingDecisionTreeForTesting(features),
HighContrastClassification::kNotClassified);
AssertFeaturesEqual(features, {0.0f, 0.8125f, 0.409f, 0.59f});
// Test Case 3:
// Color
// Color Buckets Ratio: Low
// Decision Tree: Apply
// Neural Network: NA.
EXPECT_TRUE(GetFeaturesAndClassification(
"/LayoutTests/images/resources/count-down-color-test.png", &features));
EXPECT_EQ(classifier()->ClassifyImageUsingDecisionTreeForTesting(features),
HighContrastClassification::kApplyHighContrastFilter);
AssertFeaturesEqual(features, {1.0f, 0.0134277f, 0.0f, 0.43f});
// Test Case 4:
// Color
// Color Buckets Ratio: High
// Decision Tree: Do Not Apply
// Neural Network: NA.
EXPECT_FALSE(GetFeaturesAndClassification( EXPECT_FALSE(GetFeaturesAndClassification(
"/LayoutTests/images/resources/blue-wheel-srgb-color-profile.png", "/LayoutTests/images/resources/blue-wheel-srgb-color-profile.png",
&features)); &features));
EXPECT_EQ(classifier()->ClassifyImageUsingDecisionTreeForTesting(features),
HighContrastClassification::kDoNotApplyHighContrastFilter);
AssertFeaturesEqual(features, {1.0f, 0.03027f, 0.0f, 0.24f}); AssertFeaturesEqual(features, {1.0f, 0.03027f, 0.0f, 0.24f});
// Test Case 2: // Test Case 5:
// Color
// Color Buckets Ratio: Medium
// Decision Tree: Can't Decide
// Neural Network: Apply.
EXPECT_TRUE(GetFeaturesAndClassification( EXPECT_TRUE(GetFeaturesAndClassification(
"/LayoutTests/images/resources/grid-large.png", &features)); "/LayoutTests/images/resources/ycbcr-444-float.jpg", &features));
AssertFeaturesEqual(features, {0.0f, 0.1875f, 0.0f, 0.1f}); EXPECT_EQ(classifier()->ClassifyImageUsingDecisionTreeForTesting(features),
HighContrastClassification::kNotClassified);
AssertFeaturesEqual(features, {1.0f, 0.0166016f, 0.0f, 0.59f});
} }
} // namespace blink } // namespace blink
# HighContrast Classifier
These files are automatically generated using tfNative from a neural network
trained by TensorFlow, to provide a classifier for High Contrast mode in cases
that decision making is not possible based on color counts.
\ No newline at end of file
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file is automatically generated using tfNative from a neural network,
// trained by TensorFlow. Please do not edit.
#include <cstdint>
namespace highcontrast_tfnative_model {
struct alignas(16) FixedAllocations {
float alloc0[10];
int32_t alloc0_shape[2];
float alloc1[10];
int32_t alloc1_shape[2];
};
extern int32_t input0Shape[2];
extern int32_t logits_MatMul_merged_with_dnn_logits_BiasAdd0Shape[2];
void Inference(
const float* __restrict input0 /* shape: 1,4 */,
float* __restrict logits_MatMul_merged_with_dnn_logits_BiasAdd0 /* shape:
1,1 */
,
FixedAllocations* __restrict fixed);
} // namespace highcontrast_tfnative_model
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