Commit 991f4851 authored by Azeem Arshad's avatar Azeem Arshad Committed by Commit Bot

[ShapeDetection] Add barhopper impl for BarcodeDetection.

This CL adds BarcodeDetection and BarcodeDetectionProvider
implementations based on the barhopper barcode detection
library.

NOPRESUBMIT=true

Bug: 1093185
Change-Id: I29b233418108482ebc80bce7c34888fa2081068f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419911Reviewed-by: default avatarDirk Pranke <dpranke@google.com>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Commit-Queue: Azeem Arshad <azeemarshad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#813335}
parent d4101150
...@@ -54,6 +54,16 @@ source_set("lib") { ...@@ -54,6 +54,16 @@ source_set("lib") {
"text_detection_impl_win.cc", "text_detection_impl_win.cc",
"text_detection_impl_win.h", "text_detection_impl_win.h",
] ]
} else if (is_chromeos && is_chrome_branded) {
sources += [
"barcode_detection_impl_barhopper.cc",
"barcode_detection_impl_barhopper.h",
"barcode_detection_provider_barhopper.cc",
"barcode_detection_provider_barhopper.h",
"face_detection_provider_impl.cc",
"face_detection_provider_impl.h",
"text_detection_impl.cc",
]
} else { } else {
sources += [ sources += [
"barcode_detection_provider_impl.cc", "barcode_detection_provider_impl.cc",
...@@ -67,11 +77,16 @@ source_set("lib") { ...@@ -67,11 +77,16 @@ source_set("lib") {
configs += [ "//build/config/compiler:wexit_time_destructors" ] configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [ deps = [
"//build:branding_buildflags",
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
"//ui/gfx", "//ui/gfx",
"//ui/gfx/geometry", "//ui/gfx/geometry",
] ]
if (is_chromeos && is_chrome_branded) {
deps += [ "//third_party/barhopper:barhopper" ]
}
public_deps = [ public_deps = [
"//base", "//base",
"//media/capture", "//media/capture",
...@@ -137,6 +152,10 @@ source_set("tests") { ...@@ -137,6 +152,10 @@ source_set("tests") {
] ]
} }
if (is_chromeos && is_chrome_branded) {
sources += [ "barcode_detection_impl_barhopper_unittest.cc" ]
}
deps = [ deps = [
":lib", ":lib",
"//base", "//base",
...@@ -149,8 +168,20 @@ source_set("tests") { ...@@ -149,8 +168,20 @@ source_set("tests") {
"//ui/gl", "//ui/gl",
] ]
data = [ data = [
"//services/test/data/codabar.png",
"//services/test/data/code_39.png",
"//services/test/data/code_93.png",
"//services/test/data/code_128.png",
"//services/test/data/data_matrix.png",
"//services/test/data/ean_8.png",
"//services/test/data/ean_13.png",
"//services/test/data/itf.png",
"//services/test/data/mona_lisa.jpg", "//services/test/data/mona_lisa.jpg",
"//services/test/data/pdf417.png",
"//services/test/data/qr_code.png",
"//services/test/data/text_detection.png", "//services/test/data/text_detection.png",
"//services/test/data/the_beatles.jpg", "//services/test/data/the_beatles.jpg",
"//services/test/data/upc_a.png",
"//services/test/data/upc_e.png",
] ]
} }
...@@ -3,5 +3,6 @@ include_rules = [ ...@@ -3,5 +3,6 @@ include_rules = [
"+third_party/skia/include", "+third_party/skia/include",
"+ui/gfx/codec", "+ui/gfx/codec",
"+ui/gfx/geometry/rect_f.h", "+ui/gfx/geometry/rect_f.h",
"+ui/gl/gl_switches.h" "+ui/gl/gl_switches.h",
"+third_party/barhopper/barhopper",
] ]
// Copyright 2020 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.
#include "services/shape_detection/barcode_detection_impl_barhopper.h"
#include <stdint.h>
#include <limits>
#include <memory>
#include "base/logging.h"
#include "services/shape_detection/public/mojom/barcodedetection.mojom-shared.h"
#include "third_party/barhopper/barhopper/barcode.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/rect_f.h"
namespace shape_detection {
namespace {
gfx::RectF CornerPointsToBoundingBox(
std::vector<barhopper::Point>& corner_points) {
float xmin = std::numeric_limits<float>::infinity();
float ymin = std::numeric_limits<float>::infinity();
float xmax = -std::numeric_limits<float>::infinity();
float ymax = -std::numeric_limits<float>::infinity();
for (auto& point : corner_points) {
xmin = std::min(xmin, point.x);
ymin = std::min(ymin, point.y);
xmax = std::max(xmax, point.x);
ymax = std::max(ymax, point.y);
}
return gfx::RectF(xmin, ymin, (xmax - xmin), (ymax - ymin));
}
mojom::BarcodeFormat BarhopperFormatToMojo(barhopper::BarcodeFormat format) {
switch (format) {
case barhopper::BarcodeFormat::AZTEC:
return mojom::BarcodeFormat::AZTEC;
case barhopper::BarcodeFormat::CODE_128:
return mojom::BarcodeFormat::CODE_128;
case barhopper::BarcodeFormat::CODE_39:
return mojom::BarcodeFormat::CODE_39;
case barhopper::BarcodeFormat::CODE_93:
return mojom::BarcodeFormat::CODE_93;
case barhopper::BarcodeFormat::CODABAR:
return mojom::BarcodeFormat::CODABAR;
case barhopper::BarcodeFormat::DATA_MATRIX:
return mojom::BarcodeFormat::DATA_MATRIX;
case barhopper::BarcodeFormat::EAN_13:
return mojom::BarcodeFormat::EAN_13;
case barhopper::BarcodeFormat::EAN_8:
return mojom::BarcodeFormat::EAN_8;
case barhopper::BarcodeFormat::ITF:
return mojom::BarcodeFormat::ITF;
case barhopper::BarcodeFormat::PDF417:
return mojom::BarcodeFormat::PDF417;
case barhopper::BarcodeFormat::QR_CODE:
return mojom::BarcodeFormat::QR_CODE;
case barhopper::BarcodeFormat::UPC_A:
return mojom::BarcodeFormat::UPC_A;
case barhopper::BarcodeFormat::UPC_E:
return mojom::BarcodeFormat::UPC_E;
case barhopper::BarcodeFormat::UNRECOGNIZED:
return mojom::BarcodeFormat::UNKNOWN;
default:
NOTREACHED() << "Invalid barcode format";
return mojom::BarcodeFormat::UNKNOWN;
}
}
barhopper::RecognitionOptions GetRecognitionOptions(
const shape_detection::mojom::BarcodeDetectorOptionsPtr& options) {
barhopper::RecognitionOptions recognition_options;
if (options->formats.empty()) {
recognition_options.barcode_formats =
barhopper::BarcodeFormat::AZTEC | barhopper::BarcodeFormat::CODE_128 |
barhopper::BarcodeFormat::CODE_39 | barhopper::BarcodeFormat::CODE_93 |
barhopper::BarcodeFormat::CODABAR |
barhopper::BarcodeFormat::DATA_MATRIX |
barhopper::BarcodeFormat::EAN_13 | barhopper::BarcodeFormat::EAN_8 |
barhopper::BarcodeFormat::ITF | barhopper::BarcodeFormat::PDF417 |
barhopper::BarcodeFormat::QR_CODE | barhopper::BarcodeFormat::UPC_A |
barhopper::BarcodeFormat::UPC_E;
return recognition_options;
}
int recognition_formats = 0;
for (const auto& format : options->formats) {
switch (format) {
case mojom::BarcodeFormat::AZTEC:
recognition_formats |= barhopper::BarcodeFormat::AZTEC;
break;
case mojom::BarcodeFormat::CODE_128:
recognition_formats |= barhopper::BarcodeFormat::CODE_128;
break;
case mojom::BarcodeFormat::CODE_39:
recognition_formats |= barhopper::BarcodeFormat::CODE_39;
break;
case mojom::BarcodeFormat::CODE_93:
recognition_formats |= barhopper::BarcodeFormat::CODE_93;
break;
case mojom::BarcodeFormat::CODABAR:
recognition_formats |= barhopper::BarcodeFormat::CODABAR;
break;
case mojom::BarcodeFormat::DATA_MATRIX:
recognition_formats |= barhopper::BarcodeFormat::DATA_MATRIX;
break;
case mojom::BarcodeFormat::EAN_13:
recognition_formats |= barhopper::BarcodeFormat::EAN_13;
break;
case mojom::BarcodeFormat::EAN_8:
recognition_formats |= barhopper::BarcodeFormat::EAN_8;
break;
case mojom::BarcodeFormat::ITF:
recognition_formats |= barhopper::BarcodeFormat::ITF;
break;
case mojom::BarcodeFormat::PDF417:
recognition_formats |= barhopper::BarcodeFormat::PDF417;
break;
case mojom::BarcodeFormat::QR_CODE:
recognition_formats |= barhopper::BarcodeFormat::QR_CODE;
break;
case mojom::BarcodeFormat::UPC_E:
recognition_formats |= barhopper::BarcodeFormat::UPC_E;
break;
case mojom::BarcodeFormat::UPC_A:
recognition_formats |= barhopper::BarcodeFormat::UPC_A;
break;
case mojom::BarcodeFormat::UNKNOWN:
recognition_formats |= barhopper::BarcodeFormat::UNRECOGNIZED;
break;
}
}
recognition_options.barcode_formats = recognition_formats;
return recognition_options;
}
} // namespace
BarcodeDetectionImplBarhopper::BarcodeDetectionImplBarhopper(
mojom::BarcodeDetectorOptionsPtr options)
: recognition_options_(GetRecognitionOptions(options)) {}
BarcodeDetectionImplBarhopper::~BarcodeDetectionImplBarhopper() = default;
void BarcodeDetectionImplBarhopper::Detect(
const SkBitmap& bitmap,
shape_detection::mojom::BarcodeDetection::DetectCallback callback) {
int width = bitmap.width();
int height = bitmap.height();
auto luminances = std::make_unique<uint8_t[]>(height * width);
uint8_t* luminances_ptr = luminances.get();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
SkColor color = bitmap.getColor(x, y);
// Fast and approximate luminance calculation: (2*R + 5*G + B) / 8
uint32_t luminance =
2 * SkColorGetR(color) + 5 * SkColorGetG(color) + SkColorGetB(color);
luminances_ptr[y * width + x] = luminance / 8;
}
}
std::vector<barhopper::Barcode> barcodes;
barhopper::Barhopper::Recognize(width, height, luminances_ptr,
recognition_options_, &barcodes);
std::vector<mojom::BarcodeDetectionResultPtr> results;
for (auto& barcode : barcodes) {
auto result = shape_detection::mojom::BarcodeDetectionResult::New();
result->bounding_box = CornerPointsToBoundingBox(barcode.corner_point);
for (auto& corner_point : barcode.corner_point) {
result->corner_points.emplace_back(corner_point.x, corner_point.y);
}
result->raw_value = barcode.raw_value;
result->format = BarhopperFormatToMojo(barcode.format);
results.push_back(std::move(result));
}
std::move(callback).Run(std::move(results));
}
// static
std::vector<mojom::BarcodeFormat>
BarcodeDetectionImplBarhopper::GetSupportedFormats() {
return {mojom::BarcodeFormat::AZTEC, mojom::BarcodeFormat::CODE_128,
mojom::BarcodeFormat::CODE_39, mojom::BarcodeFormat::CODE_93,
mojom::BarcodeFormat::CODABAR, mojom::BarcodeFormat::DATA_MATRIX,
mojom::BarcodeFormat::EAN_13, mojom::BarcodeFormat::EAN_8,
mojom::BarcodeFormat::ITF, mojom::BarcodeFormat::PDF417,
mojom::BarcodeFormat::QR_CODE, mojom::BarcodeFormat::UPC_A,
mojom::BarcodeFormat::UPC_E};
}
} // namespace shape_detection
\ No newline at end of file
// Copyright 2020 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.
#ifndef SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_IMPL_BARHOPPER_H_
#define SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_IMPL_BARHOPPER_H_
#include "services/shape_detection/public/mojom/barcodedetection.mojom.h"
#include "services/shape_detection/public/mojom/barcodedetection_provider.mojom.h"
#include "third_party/barhopper/barhopper/barhopper.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace shape_detection {
class BarcodeDetectionImplBarhopper : public mojom::BarcodeDetection {
public:
explicit BarcodeDetectionImplBarhopper(
mojom::BarcodeDetectorOptionsPtr options);
BarcodeDetectionImplBarhopper(const BarcodeDetectionImplBarhopper&) = delete;
BarcodeDetectionImplBarhopper& operator=(
const BarcodeDetectionImplBarhopper&) = delete;
~BarcodeDetectionImplBarhopper() override;
// mojom::BarcodeDetection:
void Detect(const SkBitmap& bitmap,
shape_detection::mojom::BarcodeDetection::DetectCallback callback)
override;
static std::vector<shape_detection::mojom::BarcodeFormat>
GetSupportedFormats();
private:
barhopper::RecognitionOptions recognition_options_;
};
} // namespace shape_detection
#endif // SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_IMPL_BARHOPPER_H_
\ No newline at end of file
// Copyright 2020 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.
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/test/bind_test_util.h"
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/shape_detection/barcode_detection_provider_barhopper.h"
#include "services/shape_detection/public/mojom/barcodedetection.mojom.h"
#include "services/shape_detection/public/mojom/barcodedetection_provider.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/codec/png_codec.h"
namespace shape_detection {
struct TestParams {
std::string filename;
std::string expected_value;
float x;
float y;
float width;
float height;
} kTestParams[] = {{"codabar.png", "A6.2831853B", 24, 24, 448, 95},
{"code_39.png", "CHROMIUM", 20, 20, 318, 75},
{"code_93.png", "CHROMIUM", 20, 20, 216, 75},
{"code_128.png", "Chromium", 20, 20, 246, 75},
{"data_matrix.png", "Chromium", 11, 11, 53, 53},
{"ean_8.png", "62831857", 14, 10, 134, 75},
{"ean_13.png", "6283185307179", 27, 10, 190, 75},
{"itf.png", "62831853071795", 10, 10, 135, 39},
{"pdf417.png", "Chromium", 20, 20, 240, 44},
{"qr_code.png", "https://chromium.org", 40, 40, 250, 250},
{"upc_a.png", "628318530714", 23, 10, 190, 75},
{"upc_e.png", "06283186", 23, 10, 102, 75}};
class BarcodeDetectionImplBarhopperTest
: public testing::TestWithParam<struct TestParams> {
protected:
BarcodeDetectionImplBarhopperTest() = default;
BarcodeDetectionImplBarhopperTest(const BarcodeDetectionImplBarhopperTest&) =
delete;
BarcodeDetectionImplBarhopperTest& operator=(
const BarcodeDetectionImplBarhopperTest&) = delete;
~BarcodeDetectionImplBarhopperTest() override = default;
mojo::Remote<mojom::BarcodeDetection> ConnectToBarcodeDetector() {
mojo::Remote<mojom::BarcodeDetectionProvider> provider;
mojo::Remote<mojom::BarcodeDetection> barcode_service;
BarcodeDetectionProviderBarhopper::Create(
provider.BindNewPipeAndPassReceiver());
auto options = mojom::BarcodeDetectorOptions::New();
provider->CreateBarcodeDetection(
barcode_service.BindNewPipeAndPassReceiver(), std::move(options));
return barcode_service;
}
std::unique_ptr<SkBitmap> LoadTestImage(std::string filename) {
// Load image data from test directory.
base::FilePath image_path;
EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &image_path));
image_path = image_path.Append(FILE_PATH_LITERAL("services"))
.Append(FILE_PATH_LITERAL("test"))
.Append(FILE_PATH_LITERAL("data"))
.Append(FILE_PATH_LITERAL(filename));
EXPECT_TRUE(base::PathExists(image_path));
std::string image_data;
EXPECT_TRUE(base::ReadFileToString(image_path, &image_data));
std::unique_ptr<SkBitmap> image(new SkBitmap());
EXPECT_TRUE(gfx::PNGCodec::Decode(
reinterpret_cast<const uint8_t*>(image_data.data()), image_data.size(),
image.get()));
const gfx::Size size(image->width(), image->height());
const uint32_t num_bytes = size.GetArea() * 4 /* bytes per pixel */;
EXPECT_EQ(num_bytes, image->computeByteSize());
return image;
}
private:
base::test::TaskEnvironment task_environment_;
};
TEST_P(BarcodeDetectionImplBarhopperTest, Scan) {
mojo::Remote<mojom::BarcodeDetection> barcode_detector =
ConnectToBarcodeDetector();
std::unique_ptr<SkBitmap> image = LoadTestImage(GetParam().filename);
ASSERT_TRUE(image);
std::vector<mojom::BarcodeDetectionResultPtr> results;
base::RunLoop run_loop;
barcode_detector->Detect(
*image, base::BindLambdaForTesting(
[&](std::vector<mojom::BarcodeDetectionResultPtr> barcodes) {
results = std::move(barcodes);
run_loop.Quit();
}));
run_loop.Run();
EXPECT_EQ(1u, results.size());
EXPECT_EQ(GetParam().expected_value, results.front()->raw_value);
EXPECT_EQ(GetParam().x, results.front()->bounding_box.x());
EXPECT_EQ(GetParam().y, results.front()->bounding_box.y());
EXPECT_EQ(GetParam().width, results.front()->bounding_box.width());
EXPECT_EQ(GetParam().height, results.front()->bounding_box.height());
}
INSTANTIATE_TEST_SUITE_P(,
BarcodeDetectionImplBarhopperTest,
testing::ValuesIn(kTestParams));
} // namespace shape_detection
\ No newline at end of file
// Copyright 2020 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.
#include "services/shape_detection/barcode_detection_provider_barhopper.h"
#include <memory>
#include <utility>
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/shape_detection/barcode_detection_impl_barhopper.h"
#include "services/shape_detection/public/mojom/barcodedetection.mojom.h"
#include "services/shape_detection/public/mojom/barcodedetection_provider.mojom.h"
namespace shape_detection {
// static
void BarcodeDetectionProviderBarhopper::Create(
mojo::PendingReceiver<mojom::BarcodeDetectionProvider> receiver) {
mojo::MakeSelfOwnedReceiver(
std::make_unique<BarcodeDetectionProviderBarhopper>(),
std::move(receiver));
}
void BarcodeDetectionProviderBarhopper::CreateBarcodeDetection(
mojo::PendingReceiver<shape_detection::mojom::BarcodeDetection> receiver,
shape_detection::mojom::BarcodeDetectorOptionsPtr options) {
mojo::MakeSelfOwnedReceiver(
std::make_unique<BarcodeDetectionImplBarhopper>(std::move(options)),
std::move(receiver));
}
void BarcodeDetectionProviderBarhopper::EnumerateSupportedFormats(
EnumerateSupportedFormatsCallback callback) {
std::move(callback).Run(BarcodeDetectionImplBarhopper::GetSupportedFormats());
}
} // namespace shape_detection
\ No newline at end of file
// Copyright 2020 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.
#ifndef SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_PROVIDER_BARHOPPER_H_
#define SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_PROVIDER_BARHOPPER_H_
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "services/shape_detection/public/mojom/barcodedetection_provider.mojom.h"
namespace shape_detection {
// BarcodeDetectionProviderBarhopper class is a provider that binds to
// a BarcodeDetection implementation based on the barhopper library.
class BarcodeDetectionProviderBarhopper
: public mojom::BarcodeDetectionProvider {
public:
BarcodeDetectionProviderBarhopper() = default;
BarcodeDetectionProviderBarhopper(const BarcodeDetectionProviderBarhopper&) =
delete;
BarcodeDetectionProviderBarhopper& operator=(
const BarcodeDetectionProviderBarhopper&) = delete;
~BarcodeDetectionProviderBarhopper() override = default;
static void Create(
mojo::PendingReceiver<mojom::BarcodeDetectionProvider> receiver);
// mojom::BarcodeDetectionProvider:
void CreateBarcodeDetection(
mojo::PendingReceiver<shape_detection::mojom::BarcodeDetection> receiver,
shape_detection::mojom::BarcodeDetectorOptionsPtr options) override;
void EnumerateSupportedFormats(
EnumerateSupportedFormatsCallback callback) override;
};
} // namespace shape_detection
#endif // SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_PROVIDER_BARHOPPER_H_
\ No newline at end of file
...@@ -9,12 +9,16 @@ ...@@ -9,12 +9,16 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/macros.h" #include "base/macros.h"
#include "build/branding_buildflags.h"
#if defined(OS_WIN) #if defined(OS_WIN)
#include "services/shape_detection/barcode_detection_provider_impl.h" #include "services/shape_detection/barcode_detection_provider_impl.h"
#include "services/shape_detection/face_detection_provider_win.h" #include "services/shape_detection/face_detection_provider_win.h"
#elif defined(OS_MAC) #elif defined(OS_MAC)
#include "services/shape_detection/barcode_detection_provider_mac.h" #include "services/shape_detection/barcode_detection_provider_mac.h"
#include "services/shape_detection/face_detection_provider_mac.h" #include "services/shape_detection/face_detection_provider_mac.h"
#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_CHROMEOS)
#include "services/shape_detection/barcode_detection_provider_barhopper.h"
#include "services/shape_detection/face_detection_provider_impl.h"
#else #else
#include "services/shape_detection/barcode_detection_provider_impl.h" #include "services/shape_detection/barcode_detection_provider_impl.h"
#include "services/shape_detection/face_detection_provider_impl.h" #include "services/shape_detection/face_detection_provider_impl.h"
...@@ -43,6 +47,8 @@ void ShapeDetectionService::BindBarcodeDetectionProvider( ...@@ -43,6 +47,8 @@ void ShapeDetectionService::BindBarcodeDetectionProvider(
receiver.PassPipe().release().value()); receiver.PassPipe().release().value());
#elif defined(OS_MAC) #elif defined(OS_MAC)
BarcodeDetectionProviderMac::Create(std::move(receiver)); BarcodeDetectionProviderMac::Create(std::move(receiver));
#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_CHROMEOS)
BarcodeDetectionProviderBarhopper::Create(std::move(receiver));
#else #else
BarcodeDetectionProviderImpl::Create(std::move(receiver)); BarcodeDetectionProviderImpl::Create(std::move(receiver));
#endif #endif
......
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