internal change
PiperOrigin-RevId: 493742399
This commit is contained in:
parent
a59f0a9924
commit
a0efcb47f2
|
@ -18,6 +18,7 @@ licenses(["notice"])
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "rect",
|
name = "rect",
|
||||||
|
srcs = ["rect.cc"],
|
||||||
hdrs = ["rect.h"],
|
hdrs = ["rect.h"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,6 +42,18 @@ cc_library(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "detection_result",
|
||||||
|
srcs = ["detection_result.cc"],
|
||||||
|
hdrs = ["detection_result.h"],
|
||||||
|
deps = [
|
||||||
|
":category",
|
||||||
|
":rect",
|
||||||
|
"//mediapipe/framework/formats:detection_cc_proto",
|
||||||
|
"//mediapipe/framework/formats:location_data_cc_proto",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "embedding_result",
|
name = "embedding_result",
|
||||||
srcs = ["embedding_result.cc"],
|
srcs = ["embedding_result.cc"],
|
||||||
|
|
73
mediapipe/tasks/cc/components/containers/detection_result.cc
Normal file
73
mediapipe/tasks/cc/components/containers/detection_result.cc
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* Copyright 2022 The MediaPipe Authors. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==============================================================================*/
|
||||||
|
|
||||||
|
#include "mediapipe/tasks/cc/components/containers/detection_result.h"
|
||||||
|
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "mediapipe/framework/formats/detection.pb.h"
|
||||||
|
#include "mediapipe/framework/formats/location_data.pb.h"
|
||||||
|
#include "mediapipe/tasks/cc/components/containers/category.h"
|
||||||
|
#include "mediapipe/tasks/cc/components/containers/rect.h"
|
||||||
|
|
||||||
|
namespace mediapipe::tasks::components::containers {
|
||||||
|
|
||||||
|
constexpr int kDefaultCategoryIndex = -1;
|
||||||
|
|
||||||
|
Detection ConvertToDetectionResult(
|
||||||
|
const mediapipe::Detection& detection_proto) {
|
||||||
|
Detection detection;
|
||||||
|
for (int idx = 0; idx < detection_proto.score_size(); ++idx) {
|
||||||
|
detection.categories.push_back(
|
||||||
|
{/* index= */ detection_proto.label_id_size() > idx
|
||||||
|
? detection_proto.label_id(idx)
|
||||||
|
: kDefaultCategoryIndex,
|
||||||
|
/* score= */ detection_proto.score(idx),
|
||||||
|
/* category_name */ detection_proto.label_size() > idx
|
||||||
|
? detection_proto.label(idx)
|
||||||
|
: "",
|
||||||
|
/* display_name */ detection_proto.display_name_size() > idx
|
||||||
|
? detection_proto.display_name(idx)
|
||||||
|
: ""});
|
||||||
|
}
|
||||||
|
Rect bounding_box;
|
||||||
|
if (detection_proto.location_data().has_bounding_box()) {
|
||||||
|
mediapipe::LocationData::BoundingBox bounding_box_proto =
|
||||||
|
detection_proto.location_data().bounding_box();
|
||||||
|
bounding_box.left = bounding_box_proto.xmin();
|
||||||
|
bounding_box.top = bounding_box_proto.ymin();
|
||||||
|
bounding_box.right = bounding_box_proto.xmin() + bounding_box_proto.width();
|
||||||
|
bounding_box.bottom =
|
||||||
|
bounding_box_proto.ymin() + bounding_box_proto.height();
|
||||||
|
}
|
||||||
|
detection.bounding_box = bounding_box;
|
||||||
|
return detection;
|
||||||
|
}
|
||||||
|
|
||||||
|
DetectionResult ConvertToDetectionResult(
|
||||||
|
std::vector<mediapipe::Detection> detections_proto) {
|
||||||
|
DetectionResult detection_result;
|
||||||
|
detection_result.detections.reserve(detections_proto.size());
|
||||||
|
for (const auto& detection_proto : detections_proto) {
|
||||||
|
detection_result.detections.push_back(
|
||||||
|
ConvertToDetectionResult(detection_proto));
|
||||||
|
}
|
||||||
|
return detection_result;
|
||||||
|
}
|
||||||
|
} // namespace mediapipe::tasks::components::containers
|
52
mediapipe/tasks/cc/components/containers/detection_result.h
Normal file
52
mediapipe/tasks/cc/components/containers/detection_result.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/* Copyright 2022 The MediaPipe Authors. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==============================================================================*/
|
||||||
|
|
||||||
|
#ifndef MEDIAPIPE_TASKS_CC_COMPONENTS_CONTAINERS_DETECTION_RESULT_H_
|
||||||
|
#define MEDIAPIPE_TASKS_CC_COMPONENTS_CONTAINERS_DETECTION_RESULT_H_
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "mediapipe/framework/formats/detection.pb.h"
|
||||||
|
#include "mediapipe/tasks/cc/components/containers/category.h"
|
||||||
|
#include "mediapipe/tasks/cc/components/containers/rect.h"
|
||||||
|
|
||||||
|
namespace mediapipe::tasks::components::containers {
|
||||||
|
|
||||||
|
// Detection for a single bounding box.
|
||||||
|
struct Detection {
|
||||||
|
// A vector of detected categories.
|
||||||
|
std::vector<Category> categories;
|
||||||
|
// The bounding box location.
|
||||||
|
Rect bounding_box;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Detection results of a model.
|
||||||
|
struct DetectionResult {
|
||||||
|
// A vector of Detections.
|
||||||
|
std::vector<Detection> detections;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Utility function to convert from Detection proto to Detection struct.
|
||||||
|
Detection ConvertToDetection(const mediapipe::Detection& detection_proto);
|
||||||
|
|
||||||
|
// Utility function to convert from list of Detection proto to DetectionResult
|
||||||
|
// struct.
|
||||||
|
DetectionResult ConvertToDetectionResult(
|
||||||
|
std::vector<mediapipe::Detection> detections_proto);
|
||||||
|
|
||||||
|
} // namespace mediapipe::tasks::components::containers
|
||||||
|
#endif // MEDIAPIPE_TASKS_CC_COMPONENTS_CONTAINERS_DETECTION_RESULT_H_
|
34
mediapipe/tasks/cc/components/containers/rect.cc
Normal file
34
mediapipe/tasks/cc/components/containers/rect.cc
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/* Copyright 2022 The MediaPipe Authors. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==============================================================================*/
|
||||||
|
|
||||||
|
#include "mediapipe/tasks/cc/components/containers/rect.h"
|
||||||
|
|
||||||
|
namespace mediapipe::tasks::components::containers {
|
||||||
|
|
||||||
|
RectF ToRectF(const Rect& rect, int image_height, int image_width) {
|
||||||
|
return RectF{static_cast<float>(rect.left) / image_width,
|
||||||
|
static_cast<float>(rect.top) / image_height,
|
||||||
|
static_cast<float>(rect.right) / image_width,
|
||||||
|
static_cast<float>(rect.bottom) / image_height};
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect ToRect(const RectF& rect, int image_height, int image_width) {
|
||||||
|
return Rect{static_cast<int>(rect.left * image_width),
|
||||||
|
static_cast<int>(rect.top * image_height),
|
||||||
|
static_cast<int>(rect.right * image_width),
|
||||||
|
static_cast<int>(rect.bottom * image_height)};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mediapipe::tasks::components::containers
|
|
@ -16,20 +16,47 @@ limitations under the License.
|
||||||
#ifndef MEDIAPIPE_TASKS_CC_COMPONENTS_CONTAINERS_RECT_H_
|
#ifndef MEDIAPIPE_TASKS_CC_COMPONENTS_CONTAINERS_RECT_H_
|
||||||
#define MEDIAPIPE_TASKS_CC_COMPONENTS_CONTAINERS_RECT_H_
|
#define MEDIAPIPE_TASKS_CC_COMPONENTS_CONTAINERS_RECT_H_
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
namespace mediapipe::tasks::components::containers {
|
namespace mediapipe::tasks::components::containers {
|
||||||
|
|
||||||
|
constexpr float kRectFTolerance = 1e-4;
|
||||||
|
|
||||||
// Defines a rectangle, used e.g. as part of detection results or as input
|
// Defines a rectangle, used e.g. as part of detection results or as input
|
||||||
// region-of-interest.
|
// region-of-interest.
|
||||||
//
|
//
|
||||||
|
struct Rect {
|
||||||
|
int left;
|
||||||
|
int top;
|
||||||
|
int right;
|
||||||
|
int bottom;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(const Rect& lhs, const Rect& rhs) {
|
||||||
|
return lhs.left == rhs.left && lhs.top == rhs.top && lhs.right == rhs.right &&
|
||||||
|
lhs.bottom == rhs.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
// The coordinates are normalized wrt the image dimensions, i.e. generally in
|
// The coordinates are normalized wrt the image dimensions, i.e. generally in
|
||||||
// [0,1] but they may exceed these bounds if describing a region overlapping the
|
// [0,1] but they may exceed these bounds if describing a region overlapping the
|
||||||
// image. The origin is on the top-left corner of the image.
|
// image. The origin is on the top-left corner of the image.
|
||||||
struct Rect {
|
struct RectF {
|
||||||
float left;
|
float left;
|
||||||
float top;
|
float top;
|
||||||
float right;
|
float right;
|
||||||
float bottom;
|
float bottom;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool operator==(const RectF& lhs, const RectF& rhs) {
|
||||||
|
return abs(lhs.left - rhs.left) < kRectFTolerance &&
|
||||||
|
abs(lhs.top - rhs.top) < kRectFTolerance &&
|
||||||
|
abs(lhs.right - rhs.right) < kRectFTolerance &&
|
||||||
|
abs(lhs.bottom - rhs.bottom) < kRectFTolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF ToRectF(const Rect& rect, int image_height, int image_width);
|
||||||
|
|
||||||
|
Rect ToRect(const RectF& rect, int image_height, int image_width);
|
||||||
|
|
||||||
} // namespace mediapipe::tasks::components::containers
|
} // namespace mediapipe::tasks::components::containers
|
||||||
#endif // MEDIAPIPE_TASKS_CC_COMPONENTS_CONTAINERS_RECT_H_
|
#endif // MEDIAPIPE_TASKS_CC_COMPONENTS_CONTAINERS_RECT_H_
|
||||||
|
|
|
@ -129,13 +129,13 @@ class BaseVisionTaskApi : public tasks::core::BaseTaskApi {
|
||||||
if (roi.left >= roi.right || roi.top >= roi.bottom) {
|
if (roi.left >= roi.right || roi.top >= roi.bottom) {
|
||||||
return CreateStatusWithPayload(
|
return CreateStatusWithPayload(
|
||||||
absl::StatusCode::kInvalidArgument,
|
absl::StatusCode::kInvalidArgument,
|
||||||
"Expected Rect with left < right and top < bottom.",
|
"Expected RectF with left < right and top < bottom.",
|
||||||
MediaPipeTasksStatus::kImageProcessingInvalidArgumentError);
|
MediaPipeTasksStatus::kImageProcessingInvalidArgumentError);
|
||||||
}
|
}
|
||||||
if (roi.left < 0 || roi.top < 0 || roi.right > 1 || roi.bottom > 1) {
|
if (roi.left < 0 || roi.top < 0 || roi.right > 1 || roi.bottom > 1) {
|
||||||
return CreateStatusWithPayload(
|
return CreateStatusWithPayload(
|
||||||
absl::StatusCode::kInvalidArgument,
|
absl::StatusCode::kInvalidArgument,
|
||||||
"Expected Rect values to be in [0,1].",
|
"Expected RectF values to be in [0,1].",
|
||||||
MediaPipeTasksStatus::kImageProcessingInvalidArgumentError);
|
MediaPipeTasksStatus::kImageProcessingInvalidArgumentError);
|
||||||
}
|
}
|
||||||
normalized_rect.set_x_center((roi.left + roi.right) / 2.0);
|
normalized_rect.set_x_center((roi.left + roi.right) / 2.0);
|
||||||
|
|
|
@ -35,7 +35,8 @@ struct ImageProcessingOptions {
|
||||||
// the full image is used.
|
// the full image is used.
|
||||||
//
|
//
|
||||||
// Coordinates must be in [0,1] with 'left' < 'right' and 'top' < bottom.
|
// Coordinates must be in [0,1] with 'left' < 'right' and 'top' < bottom.
|
||||||
std::optional<components::containers::Rect> region_of_interest = std::nullopt;
|
std::optional<components::containers::RectF> region_of_interest =
|
||||||
|
std::nullopt;
|
||||||
|
|
||||||
// The rotation to apply to the image (or cropped region-of-interest), in
|
// The rotation to apply to the image (or cropped region-of-interest), in
|
||||||
// degrees clockwise.
|
// degrees clockwise.
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace {
|
||||||
using ::mediapipe::api2::Input;
|
using ::mediapipe::api2::Input;
|
||||||
using ::mediapipe::api2::Output;
|
using ::mediapipe::api2::Output;
|
||||||
using ::mediapipe::api2::builder::Source;
|
using ::mediapipe::api2::builder::Source;
|
||||||
using ::mediapipe::tasks::components::containers::Rect;
|
using ::mediapipe::tasks::components::containers::RectF;
|
||||||
using ::mediapipe::tasks::vision::utils::CalculateIOU;
|
using ::mediapipe::tasks::vision::utils::CalculateIOU;
|
||||||
using ::mediapipe::tasks::vision::utils::DuplicatesFinder;
|
using ::mediapipe::tasks::vision::utils::DuplicatesFinder;
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ absl::StatusOr<float> HandBaselineDistance(
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect CalculateBound(const NormalizedLandmarkList& list) {
|
RectF CalculateBound(const NormalizedLandmarkList& list) {
|
||||||
constexpr float kMinInitialValue = std::numeric_limits<float>::max();
|
constexpr float kMinInitialValue = std::numeric_limits<float>::max();
|
||||||
constexpr float kMaxInitialValue = std::numeric_limits<float>::lowest();
|
constexpr float kMaxInitialValue = std::numeric_limits<float>::lowest();
|
||||||
|
|
||||||
|
@ -144,10 +144,10 @@ Rect CalculateBound(const NormalizedLandmarkList& list) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate normalized non rotated face bounding box
|
// Populate normalized non rotated face bounding box
|
||||||
return Rect{/*left=*/bounding_box_left,
|
return RectF{/*left=*/bounding_box_left,
|
||||||
/*top=*/bounding_box_top,
|
/*top=*/bounding_box_top,
|
||||||
/*right=*/bounding_box_right,
|
/*right=*/bounding_box_right,
|
||||||
/*bottom=*/bounding_box_bottom};
|
/*bottom=*/bounding_box_bottom};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses IoU and distance of some corresponding hand landmarks to detect
|
// Uses IoU and distance of some corresponding hand landmarks to detect
|
||||||
|
@ -172,7 +172,7 @@ class HandDuplicatesFinder : public DuplicatesFinder {
|
||||||
const int num = multi_landmarks.size();
|
const int num = multi_landmarks.size();
|
||||||
std::vector<float> baseline_distances;
|
std::vector<float> baseline_distances;
|
||||||
baseline_distances.reserve(num);
|
baseline_distances.reserve(num);
|
||||||
std::vector<Rect> bounds;
|
std::vector<RectF> bounds;
|
||||||
bounds.reserve(num);
|
bounds.reserve(num);
|
||||||
for (const NormalizedLandmarkList& list : multi_landmarks) {
|
for (const NormalizedLandmarkList& list : multi_landmarks) {
|
||||||
ASSIGN_OR_RETURN(const float baseline_distance,
|
ASSIGN_OR_RETURN(const float baseline_distance,
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace {
|
||||||
|
|
||||||
using ::file::Defaults;
|
using ::file::Defaults;
|
||||||
using ::mediapipe::file::JoinPath;
|
using ::mediapipe::file::JoinPath;
|
||||||
using ::mediapipe::tasks::components::containers::Rect;
|
using ::mediapipe::tasks::components::containers::RectF;
|
||||||
using ::mediapipe::tasks::containers::proto::LandmarksDetectionResult;
|
using ::mediapipe::tasks::containers::proto::LandmarksDetectionResult;
|
||||||
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
||||||
using ::testing::EqualsProto;
|
using ::testing::EqualsProto;
|
||||||
|
@ -188,7 +188,7 @@ TEST_F(ImageModeTest, FailsWithRegionOfInterest) {
|
||||||
options->running_mode = core::RunningMode::IMAGE;
|
options->running_mode = core::RunningMode::IMAGE;
|
||||||
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<HandLandmarker> hand_landmarker,
|
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<HandLandmarker> hand_landmarker,
|
||||||
HandLandmarker::Create(std::move(options)));
|
HandLandmarker::Create(std::move(options)));
|
||||||
Rect roi{/*left=*/0.1, /*top=*/0, /*right=*/0.9, /*bottom=*/1};
|
RectF roi{/*left=*/0.1, /*top=*/0, /*right=*/0.9, /*bottom=*/1};
|
||||||
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
||||||
|
|
||||||
auto results = hand_landmarker->Detect(image, image_processing_options);
|
auto results = hand_landmarker->Detect(image, image_processing_options);
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace {
|
||||||
using ::mediapipe::file::JoinPath;
|
using ::mediapipe::file::JoinPath;
|
||||||
using ::mediapipe::tasks::components::containers::Category;
|
using ::mediapipe::tasks::components::containers::Category;
|
||||||
using ::mediapipe::tasks::components::containers::Classifications;
|
using ::mediapipe::tasks::components::containers::Classifications;
|
||||||
using ::mediapipe::tasks::components::containers::Rect;
|
using ::mediapipe::tasks::components::containers::RectF;
|
||||||
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
||||||
using ::testing::HasSubstr;
|
using ::testing::HasSubstr;
|
||||||
using ::testing::Optional;
|
using ::testing::Optional;
|
||||||
|
@ -472,7 +472,7 @@ TEST_F(ImageModeTest, SucceedsWithRegionOfInterest) {
|
||||||
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ImageClassifier> image_classifier,
|
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ImageClassifier> image_classifier,
|
||||||
ImageClassifier::Create(std::move(options)));
|
ImageClassifier::Create(std::move(options)));
|
||||||
// Region-of-interest around the soccer ball.
|
// Region-of-interest around the soccer ball.
|
||||||
Rect roi{/*left=*/0.45, /*top=*/0.3075, /*right=*/0.614, /*bottom=*/0.7345};
|
RectF roi{/*left=*/0.45, /*top=*/0.3075, /*right=*/0.614, /*bottom=*/0.7345};
|
||||||
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
||||||
|
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results, image_classifier->Classify(
|
MP_ASSERT_OK_AND_ASSIGN(auto results, image_classifier->Classify(
|
||||||
|
@ -526,7 +526,8 @@ TEST_F(ImageModeTest, SucceedsWithRegionOfInterestAndRotation) {
|
||||||
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ImageClassifier> image_classifier,
|
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ImageClassifier> image_classifier,
|
||||||
ImageClassifier::Create(std::move(options)));
|
ImageClassifier::Create(std::move(options)));
|
||||||
// Region-of-interest around the chair, with 90° anti-clockwise rotation.
|
// Region-of-interest around the chair, with 90° anti-clockwise rotation.
|
||||||
Rect roi{/*left=*/0.006, /*top=*/0.1763, /*right=*/0.5702, /*bottom=*/0.3049};
|
RectF roi{/*left=*/0.006, /*top=*/0.1763, /*right=*/0.5702,
|
||||||
|
/*bottom=*/0.3049};
|
||||||
ImageProcessingOptions image_processing_options{roi,
|
ImageProcessingOptions image_processing_options{roi,
|
||||||
/*rotation_degrees=*/-90};
|
/*rotation_degrees=*/-90};
|
||||||
|
|
||||||
|
@ -554,13 +555,13 @@ TEST_F(ImageModeTest, FailsWithInvalidImageProcessingOptions) {
|
||||||
ImageClassifier::Create(std::move(options)));
|
ImageClassifier::Create(std::move(options)));
|
||||||
|
|
||||||
// Invalid: left > right.
|
// Invalid: left > right.
|
||||||
Rect roi{/*left=*/0.9, /*top=*/0, /*right=*/0.1, /*bottom=*/1};
|
RectF roi{/*left=*/0.9, /*top=*/0, /*right=*/0.1, /*bottom=*/1};
|
||||||
ImageProcessingOptions image_processing_options{roi,
|
ImageProcessingOptions image_processing_options{roi,
|
||||||
/*rotation_degrees=*/0};
|
/*rotation_degrees=*/0};
|
||||||
auto results = image_classifier->Classify(image, image_processing_options);
|
auto results = image_classifier->Classify(image, image_processing_options);
|
||||||
EXPECT_EQ(results.status().code(), absl::StatusCode::kInvalidArgument);
|
EXPECT_EQ(results.status().code(), absl::StatusCode::kInvalidArgument);
|
||||||
EXPECT_THAT(results.status().message(),
|
EXPECT_THAT(results.status().message(),
|
||||||
HasSubstr("Expected Rect with left < right and top < bottom"));
|
HasSubstr("Expected RectF with left < right and top < bottom"));
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
results.status().GetPayload(kMediaPipeTasksPayload),
|
results.status().GetPayload(kMediaPipeTasksPayload),
|
||||||
Optional(absl::Cord(absl::StrCat(
|
Optional(absl::Cord(absl::StrCat(
|
||||||
|
@ -573,7 +574,7 @@ TEST_F(ImageModeTest, FailsWithInvalidImageProcessingOptions) {
|
||||||
results = image_classifier->Classify(image, image_processing_options);
|
results = image_classifier->Classify(image, image_processing_options);
|
||||||
EXPECT_EQ(results.status().code(), absl::StatusCode::kInvalidArgument);
|
EXPECT_EQ(results.status().code(), absl::StatusCode::kInvalidArgument);
|
||||||
EXPECT_THAT(results.status().message(),
|
EXPECT_THAT(results.status().message(),
|
||||||
HasSubstr("Expected Rect with left < right and top < bottom"));
|
HasSubstr("Expected RectF with left < right and top < bottom"));
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
results.status().GetPayload(kMediaPipeTasksPayload),
|
results.status().GetPayload(kMediaPipeTasksPayload),
|
||||||
Optional(absl::Cord(absl::StrCat(
|
Optional(absl::Cord(absl::StrCat(
|
||||||
|
@ -586,7 +587,7 @@ TEST_F(ImageModeTest, FailsWithInvalidImageProcessingOptions) {
|
||||||
results = image_classifier->Classify(image, image_processing_options);
|
results = image_classifier->Classify(image, image_processing_options);
|
||||||
EXPECT_EQ(results.status().code(), absl::StatusCode::kInvalidArgument);
|
EXPECT_EQ(results.status().code(), absl::StatusCode::kInvalidArgument);
|
||||||
EXPECT_THAT(results.status().message(),
|
EXPECT_THAT(results.status().message(),
|
||||||
HasSubstr("Expected Rect values to be in [0,1]"));
|
HasSubstr("Expected RectF values to be in [0,1]"));
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
results.status().GetPayload(kMediaPipeTasksPayload),
|
results.status().GetPayload(kMediaPipeTasksPayload),
|
||||||
Optional(absl::Cord(absl::StrCat(
|
Optional(absl::Cord(absl::StrCat(
|
||||||
|
@ -695,7 +696,7 @@ TEST_F(VideoModeTest, SucceedsWithRegionOfInterest) {
|
||||||
ImageClassifier::Create(std::move(options)));
|
ImageClassifier::Create(std::move(options)));
|
||||||
// Crop around the soccer ball.
|
// Crop around the soccer ball.
|
||||||
// Region-of-interest around the soccer ball.
|
// Region-of-interest around the soccer ball.
|
||||||
Rect roi{/*left=*/0.45, /*top=*/0.3075, /*right=*/0.614, /*bottom=*/0.7345};
|
RectF roi{/*left=*/0.45, /*top=*/0.3075, /*right=*/0.614, /*bottom=*/0.7345};
|
||||||
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
||||||
|
|
||||||
for (int i = 0; i < iterations; ++i) {
|
for (int i = 0; i < iterations; ++i) {
|
||||||
|
@ -837,7 +838,7 @@ TEST_F(LiveStreamModeTest, SucceedsWithRegionOfInterest) {
|
||||||
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ImageClassifier> image_classifier,
|
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ImageClassifier> image_classifier,
|
||||||
ImageClassifier::Create(std::move(options)));
|
ImageClassifier::Create(std::move(options)));
|
||||||
// Crop around the soccer ball.
|
// Crop around the soccer ball.
|
||||||
Rect roi{/*left=*/0.45, /*top=*/0.3075, /*right=*/0.614, /*bottom=*/0.7345};
|
RectF roi{/*left=*/0.45, /*top=*/0.3075, /*right=*/0.614, /*bottom=*/0.7345};
|
||||||
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
||||||
|
|
||||||
for (int i = 0; i < iterations; ++i) {
|
for (int i = 0; i < iterations; ++i) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace image_embedder {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using ::mediapipe::file::JoinPath;
|
using ::mediapipe::file::JoinPath;
|
||||||
using ::mediapipe::tasks::components::containers::Rect;
|
using ::mediapipe::tasks::components::containers::RectF;
|
||||||
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
||||||
using ::testing::HasSubstr;
|
using ::testing::HasSubstr;
|
||||||
using ::testing::Optional;
|
using ::testing::Optional;
|
||||||
|
@ -320,7 +320,7 @@ TEST_F(ImageModeTest, SucceedsWithRegionOfInterest) {
|
||||||
Image crop, DecodeImageFromFile(
|
Image crop, DecodeImageFromFile(
|
||||||
JoinPath("./", kTestDataDirectory, "burger_crop.jpg")));
|
JoinPath("./", kTestDataDirectory, "burger_crop.jpg")));
|
||||||
// Region-of-interest in "burger.jpg" corresponding to "burger_crop.jpg".
|
// Region-of-interest in "burger.jpg" corresponding to "burger_crop.jpg".
|
||||||
Rect roi{/*left=*/0, /*top=*/0, /*right=*/0.833333, /*bottom=*/1};
|
RectF roi{/*left=*/0, /*top=*/0, /*right=*/0.833333, /*bottom=*/1};
|
||||||
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
||||||
|
|
||||||
// Extract both embeddings.
|
// Extract both embeddings.
|
||||||
|
@ -388,7 +388,7 @@ TEST_F(ImageModeTest, SucceedsWithRegionOfInterestAndRotation) {
|
||||||
DecodeImageFromFile(JoinPath("./", kTestDataDirectory,
|
DecodeImageFromFile(JoinPath("./", kTestDataDirectory,
|
||||||
"burger_rotated.jpg")));
|
"burger_rotated.jpg")));
|
||||||
// Region-of-interest corresponding to burger_crop.jpg.
|
// Region-of-interest corresponding to burger_crop.jpg.
|
||||||
Rect roi{/*left=*/0, /*top=*/0, /*right=*/1, /*bottom=*/0.8333333};
|
RectF roi{/*left=*/0, /*top=*/0, /*right=*/1, /*bottom=*/0.8333333};
|
||||||
ImageProcessingOptions image_processing_options{roi,
|
ImageProcessingOptions image_processing_options{roi,
|
||||||
/*rotation_degrees=*/-90};
|
/*rotation_degrees=*/-90};
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace {
|
||||||
|
|
||||||
using ::mediapipe::Image;
|
using ::mediapipe::Image;
|
||||||
using ::mediapipe::file::JoinPath;
|
using ::mediapipe::file::JoinPath;
|
||||||
using ::mediapipe::tasks::components::containers::Rect;
|
using ::mediapipe::tasks::components::containers::RectF;
|
||||||
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
||||||
using ::testing::HasSubstr;
|
using ::testing::HasSubstr;
|
||||||
using ::testing::Optional;
|
using ::testing::Optional;
|
||||||
|
@ -299,7 +299,7 @@ TEST_F(ImageModeTest, FailsWithRegionOfInterest) {
|
||||||
|
|
||||||
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ImageSegmenter> segmenter,
|
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ImageSegmenter> segmenter,
|
||||||
ImageSegmenter::Create(std::move(options)));
|
ImageSegmenter::Create(std::move(options)));
|
||||||
Rect roi{/*left=*/0.1, /*top=*/0, /*right=*/0.9, /*bottom=*/1};
|
RectF roi{/*left=*/0.1, /*top=*/0, /*right=*/0.9, /*bottom=*/1};
|
||||||
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
||||||
|
|
||||||
auto results = segmenter->Segment(image, image_processing_options);
|
auto results = segmenter->Segment(image, image_processing_options);
|
||||||
|
|
|
@ -33,6 +33,7 @@ cc_library(
|
||||||
"//mediapipe/framework/formats:rect_cc_proto",
|
"//mediapipe/framework/formats:rect_cc_proto",
|
||||||
"//mediapipe/tasks/cc:common",
|
"//mediapipe/tasks/cc:common",
|
||||||
"//mediapipe/tasks/cc/components/calculators:score_calibration_calculator",
|
"//mediapipe/tasks/cc/components/calculators:score_calibration_calculator",
|
||||||
|
"//mediapipe/tasks/cc/components/containers:detection_result",
|
||||||
"//mediapipe/tasks/cc/core:base_options",
|
"//mediapipe/tasks/cc/core:base_options",
|
||||||
"//mediapipe/tasks/cc/core:utils",
|
"//mediapipe/tasks/cc/core:utils",
|
||||||
"//mediapipe/tasks/cc/core/proto:base_options_cc_proto",
|
"//mediapipe/tasks/cc/core/proto:base_options_cc_proto",
|
||||||
|
|
|
@ -30,6 +30,7 @@ limitations under the License.
|
||||||
#include "mediapipe/framework/formats/image.h"
|
#include "mediapipe/framework/formats/image.h"
|
||||||
#include "mediapipe/framework/formats/rect.pb.h"
|
#include "mediapipe/framework/formats/rect.pb.h"
|
||||||
#include "mediapipe/tasks/cc/common.h"
|
#include "mediapipe/tasks/cc/common.h"
|
||||||
|
#include "mediapipe/tasks/cc/components/containers/detection_result.h"
|
||||||
#include "mediapipe/tasks/cc/core/base_options.h"
|
#include "mediapipe/tasks/cc/core/base_options.h"
|
||||||
#include "mediapipe/tasks/cc/core/proto/base_options.pb.h"
|
#include "mediapipe/tasks/cc/core/proto/base_options.pb.h"
|
||||||
#include "mediapipe/tasks/cc/core/proto/inference_subgraph.pb.h"
|
#include "mediapipe/tasks/cc/core/proto/inference_subgraph.pb.h"
|
||||||
|
@ -56,6 +57,7 @@ constexpr char kSubgraphTypeName[] =
|
||||||
"mediapipe.tasks.vision.ObjectDetectorGraph";
|
"mediapipe.tasks.vision.ObjectDetectorGraph";
|
||||||
constexpr int kMicroSecondsPerMilliSecond = 1000;
|
constexpr int kMicroSecondsPerMilliSecond = 1000;
|
||||||
|
|
||||||
|
using ::mediapipe::tasks::components::containers::ConvertToDetectionResult;
|
||||||
using ObjectDetectorOptionsProto =
|
using ObjectDetectorOptionsProto =
|
||||||
object_detector::proto::ObjectDetectorOptions;
|
object_detector::proto::ObjectDetectorOptions;
|
||||||
|
|
||||||
|
@ -129,7 +131,8 @@ absl::StatusOr<std::unique_ptr<ObjectDetector>> ObjectDetector::Create(
|
||||||
Packet detections_packet =
|
Packet detections_packet =
|
||||||
status_or_packets.value()[kDetectionsOutStreamName];
|
status_or_packets.value()[kDetectionsOutStreamName];
|
||||||
Packet image_packet = status_or_packets.value()[kImageOutStreamName];
|
Packet image_packet = status_or_packets.value()[kImageOutStreamName];
|
||||||
result_callback(detections_packet.Get<std::vector<Detection>>(),
|
result_callback(ConvertToDetectionResult(
|
||||||
|
detections_packet.Get<std::vector<Detection>>()),
|
||||||
image_packet.Get<Image>(),
|
image_packet.Get<Image>(),
|
||||||
detections_packet.Timestamp().Value() /
|
detections_packet.Timestamp().Value() /
|
||||||
kMicroSecondsPerMilliSecond);
|
kMicroSecondsPerMilliSecond);
|
||||||
|
@ -144,7 +147,7 @@ absl::StatusOr<std::unique_ptr<ObjectDetector>> ObjectDetector::Create(
|
||||||
std::move(packets_callback));
|
std::move(packets_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::StatusOr<std::vector<Detection>> ObjectDetector::Detect(
|
absl::StatusOr<ObjectDetectorResult> ObjectDetector::Detect(
|
||||||
mediapipe::Image image,
|
mediapipe::Image image,
|
||||||
std::optional<core::ImageProcessingOptions> image_processing_options) {
|
std::optional<core::ImageProcessingOptions> image_processing_options) {
|
||||||
if (image.UsesGpu()) {
|
if (image.UsesGpu()) {
|
||||||
|
@ -161,10 +164,11 @@ absl::StatusOr<std::vector<Detection>> ObjectDetector::Detect(
|
||||||
ProcessImageData(
|
ProcessImageData(
|
||||||
{{kImageInStreamName, MakePacket<Image>(std::move(image))},
|
{{kImageInStreamName, MakePacket<Image>(std::move(image))},
|
||||||
{kNormRectName, MakePacket<NormalizedRect>(std::move(norm_rect))}}));
|
{kNormRectName, MakePacket<NormalizedRect>(std::move(norm_rect))}}));
|
||||||
return output_packets[kDetectionsOutStreamName].Get<std::vector<Detection>>();
|
return ConvertToDetectionResult(
|
||||||
|
output_packets[kDetectionsOutStreamName].Get<std::vector<Detection>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::StatusOr<std::vector<Detection>> ObjectDetector::DetectForVideo(
|
absl::StatusOr<ObjectDetectorResult> ObjectDetector::DetectForVideo(
|
||||||
mediapipe::Image image, int64 timestamp_ms,
|
mediapipe::Image image, int64 timestamp_ms,
|
||||||
std::optional<core::ImageProcessingOptions> image_processing_options) {
|
std::optional<core::ImageProcessingOptions> image_processing_options) {
|
||||||
if (image.UsesGpu()) {
|
if (image.UsesGpu()) {
|
||||||
|
@ -185,7 +189,8 @@ absl::StatusOr<std::vector<Detection>> ObjectDetector::DetectForVideo(
|
||||||
{kNormRectName,
|
{kNormRectName,
|
||||||
MakePacket<NormalizedRect>(std::move(norm_rect))
|
MakePacket<NormalizedRect>(std::move(norm_rect))
|
||||||
.At(Timestamp(timestamp_ms * kMicroSecondsPerMilliSecond))}}));
|
.At(Timestamp(timestamp_ms * kMicroSecondsPerMilliSecond))}}));
|
||||||
return output_packets[kDetectionsOutStreamName].Get<std::vector<Detection>>();
|
return ConvertToDetectionResult(
|
||||||
|
output_packets[kDetectionsOutStreamName].Get<std::vector<Detection>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Status ObjectDetector::DetectAsync(
|
absl::Status ObjectDetector::DetectAsync(
|
||||||
|
|
|
@ -27,6 +27,7 @@ limitations under the License.
|
||||||
#include "absl/status/statusor.h"
|
#include "absl/status/statusor.h"
|
||||||
#include "mediapipe/framework/formats/detection.pb.h"
|
#include "mediapipe/framework/formats/detection.pb.h"
|
||||||
#include "mediapipe/framework/formats/image.h"
|
#include "mediapipe/framework/formats/image.h"
|
||||||
|
#include "mediapipe/tasks/cc/components/containers/detection_result.h"
|
||||||
#include "mediapipe/tasks/cc/core/base_options.h"
|
#include "mediapipe/tasks/cc/core/base_options.h"
|
||||||
#include "mediapipe/tasks/cc/vision/core/base_vision_task_api.h"
|
#include "mediapipe/tasks/cc/vision/core/base_vision_task_api.h"
|
||||||
#include "mediapipe/tasks/cc/vision/core/image_processing_options.h"
|
#include "mediapipe/tasks/cc/vision/core/image_processing_options.h"
|
||||||
|
@ -36,6 +37,10 @@ namespace mediapipe {
|
||||||
namespace tasks {
|
namespace tasks {
|
||||||
namespace vision {
|
namespace vision {
|
||||||
|
|
||||||
|
// Alias the shared DetectionResult struct as result typo.
|
||||||
|
using ObjectDetectorResult =
|
||||||
|
::mediapipe::tasks::components::containers::DetectionResult;
|
||||||
|
|
||||||
// The options for configuring a mediapipe object detector task.
|
// The options for configuring a mediapipe object detector task.
|
||||||
struct ObjectDetectorOptions {
|
struct ObjectDetectorOptions {
|
||||||
// Base options for configuring MediaPipe Tasks, such as specifying the TfLite
|
// Base options for configuring MediaPipe Tasks, such as specifying the TfLite
|
||||||
|
@ -79,8 +84,7 @@ struct ObjectDetectorOptions {
|
||||||
// The user-defined result callback for processing live stream data.
|
// The user-defined result callback for processing live stream data.
|
||||||
// The result callback should only be specified when the running mode is set
|
// The result callback should only be specified when the running mode is set
|
||||||
// to RunningMode::LIVE_STREAM.
|
// to RunningMode::LIVE_STREAM.
|
||||||
std::function<void(absl::StatusOr<std::vector<mediapipe::Detection>>,
|
std::function<void(absl::StatusOr<ObjectDetectorResult>, const Image&, int64)>
|
||||||
const Image&, int64)>
|
|
||||||
result_callback = nullptr;
|
result_callback = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -165,7 +169,7 @@ class ObjectDetector : tasks::vision::core::BaseVisionTaskApi {
|
||||||
// underlying image data.
|
// underlying image data.
|
||||||
// TODO: Describes the output bounding boxes for gpu input
|
// TODO: Describes the output bounding boxes for gpu input
|
||||||
// images after enabling the gpu support in MediaPipe Tasks.
|
// images after enabling the gpu support in MediaPipe Tasks.
|
||||||
absl::StatusOr<std::vector<mediapipe::Detection>> Detect(
|
absl::StatusOr<ObjectDetectorResult> Detect(
|
||||||
mediapipe::Image image,
|
mediapipe::Image image,
|
||||||
std::optional<core::ImageProcessingOptions> image_processing_options =
|
std::optional<core::ImageProcessingOptions> image_processing_options =
|
||||||
std::nullopt);
|
std::nullopt);
|
||||||
|
@ -188,7 +192,7 @@ class ObjectDetector : tasks::vision::core::BaseVisionTaskApi {
|
||||||
// unrotated input frame of reference coordinates system, i.e. in `[0,
|
// unrotated input frame of reference coordinates system, i.e. in `[0,
|
||||||
// image_width) x [0, image_height)`, which are the dimensions of the
|
// image_width) x [0, image_height)`, which are the dimensions of the
|
||||||
// underlying image data.
|
// underlying image data.
|
||||||
absl::StatusOr<std::vector<mediapipe::Detection>> DetectForVideo(
|
absl::StatusOr<ObjectDetectorResult> DetectForVideo(
|
||||||
mediapipe::Image image, int64 timestamp_ms,
|
mediapipe::Image image, int64 timestamp_ms,
|
||||||
std::optional<core::ImageProcessingOptions> image_processing_options =
|
std::optional<core::ImageProcessingOptions> image_processing_options =
|
||||||
std::nullopt);
|
std::nullopt);
|
||||||
|
|
|
@ -35,6 +35,7 @@ limitations under the License.
|
||||||
#include "mediapipe/framework/port/gtest.h"
|
#include "mediapipe/framework/port/gtest.h"
|
||||||
#include "mediapipe/framework/port/parse_text_proto.h"
|
#include "mediapipe/framework/port/parse_text_proto.h"
|
||||||
#include "mediapipe/framework/port/status_matchers.h"
|
#include "mediapipe/framework/port/status_matchers.h"
|
||||||
|
#include "mediapipe/tasks/cc/components/containers/detection_result.h"
|
||||||
#include "mediapipe/tasks/cc/components/containers/rect.h"
|
#include "mediapipe/tasks/cc/components/containers/rect.h"
|
||||||
#include "mediapipe/tasks/cc/vision/core/image_processing_options.h"
|
#include "mediapipe/tasks/cc/vision/core/image_processing_options.h"
|
||||||
#include "mediapipe/tasks/cc/vision/core/running_mode.h"
|
#include "mediapipe/tasks/cc/vision/core/running_mode.h"
|
||||||
|
@ -65,10 +66,14 @@ namespace vision {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using ::mediapipe::file::JoinPath;
|
using ::mediapipe::file::JoinPath;
|
||||||
using ::mediapipe::tasks::components::containers::Rect;
|
using ::mediapipe::tasks::components::containers::ConvertToDetectionResult;
|
||||||
|
using ::mediapipe::tasks::components::containers::Detection;
|
||||||
|
using ::mediapipe::tasks::components::containers::DetectionResult;
|
||||||
|
using ::mediapipe::tasks::components::containers::RectF;
|
||||||
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
using ::mediapipe::tasks::vision::core::ImageProcessingOptions;
|
||||||
using ::testing::HasSubstr;
|
using ::testing::HasSubstr;
|
||||||
using ::testing::Optional;
|
using ::testing::Optional;
|
||||||
|
using DetectionProto = mediapipe::Detection;
|
||||||
|
|
||||||
constexpr char kTestDataDirectory[] = "/mediapipe/tasks/testdata/vision/";
|
constexpr char kTestDataDirectory[] = "/mediapipe/tasks/testdata/vision/";
|
||||||
constexpr char kMobileSsdWithMetadata[] =
|
constexpr char kMobileSsdWithMetadata[] =
|
||||||
|
@ -83,47 +88,45 @@ constexpr char kEfficientDetWithMetadata[] =
|
||||||
// Checks that the two provided `Detection` proto vectors are equal, with a
|
// Checks that the two provided `Detection` proto vectors are equal, with a
|
||||||
// tolerancy on floating-point scores to account for numerical instabilities.
|
// tolerancy on floating-point scores to account for numerical instabilities.
|
||||||
// If the proto definition changes, please also change this function.
|
// If the proto definition changes, please also change this function.
|
||||||
void ExpectApproximatelyEqual(const std::vector<Detection>& actual,
|
void ExpectApproximatelyEqual(const ObjectDetectorResult& actual,
|
||||||
const std::vector<Detection>& expected) {
|
const ObjectDetectorResult& expected) {
|
||||||
const float kPrecision = 1e-6;
|
const float kPrecision = 1e-6;
|
||||||
EXPECT_EQ(actual.size(), expected.size());
|
EXPECT_EQ(actual.detections.size(), expected.detections.size());
|
||||||
for (int i = 0; i < actual.size(); ++i) {
|
for (int i = 0; i < actual.detections.size(); ++i) {
|
||||||
const Detection& a = actual[i];
|
const Detection& a = actual.detections[i];
|
||||||
const Detection& b = expected[i];
|
const Detection& b = expected.detections[i];
|
||||||
EXPECT_THAT(a.location_data().bounding_box(),
|
EXPECT_EQ(a.bounding_box, b.bounding_box);
|
||||||
EqualsProto(b.location_data().bounding_box()));
|
EXPECT_EQ(a.categories.size(), 1);
|
||||||
EXPECT_EQ(a.label_size(), 1);
|
EXPECT_EQ(b.categories.size(), 1);
|
||||||
EXPECT_EQ(b.label_size(), 1);
|
EXPECT_EQ(a.categories[0].category_name, b.categories[0].category_name);
|
||||||
EXPECT_EQ(a.label(0), b.label(0));
|
EXPECT_NEAR(a.categories[0].score, b.categories[0].score, kPrecision);
|
||||||
EXPECT_EQ(a.score_size(), 1);
|
|
||||||
EXPECT_EQ(b.score_size(), 1);
|
|
||||||
EXPECT_NEAR(a.score(0), b.score(0), kPrecision);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Detection> GenerateMobileSsdNoImageResizingFullExpectedResults() {
|
std::vector<DetectionProto>
|
||||||
return {ParseTextProtoOrDie<Detection>(R"pb(
|
GenerateMobileSsdNoImageResizingFullExpectedResults() {
|
||||||
|
return {ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
label: "cat"
|
label: "cat"
|
||||||
score: 0.6328125
|
score: 0.6328125
|
||||||
location_data {
|
location_data {
|
||||||
format: BOUNDING_BOX
|
format: BOUNDING_BOX
|
||||||
bounding_box { xmin: 14 ymin: 197 width: 98 height: 99 }
|
bounding_box { xmin: 14 ymin: 197 width: 98 height: 99 }
|
||||||
})pb"),
|
})pb"),
|
||||||
ParseTextProtoOrDie<Detection>(R"pb(
|
ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
label: "cat"
|
label: "cat"
|
||||||
score: 0.59765625
|
score: 0.59765625
|
||||||
location_data {
|
location_data {
|
||||||
format: BOUNDING_BOX
|
format: BOUNDING_BOX
|
||||||
bounding_box { xmin: 151 ymin: 78 width: 104 height: 223 }
|
bounding_box { xmin: 151 ymin: 78 width: 104 height: 223 }
|
||||||
})pb"),
|
})pb"),
|
||||||
ParseTextProtoOrDie<Detection>(R"pb(
|
ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
label: "cat"
|
label: "cat"
|
||||||
score: 0.5
|
score: 0.5
|
||||||
location_data {
|
location_data {
|
||||||
format: BOUNDING_BOX
|
format: BOUNDING_BOX
|
||||||
bounding_box { xmin: 65 ymin: 199 width: 41 height: 101 }
|
bounding_box { xmin: 65 ymin: 199 width: 41 height: 101 }
|
||||||
})pb"),
|
})pb"),
|
||||||
ParseTextProtoOrDie<Detection>(R"pb(
|
ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
label: "dog"
|
label: "dog"
|
||||||
score: 0.48828125
|
score: 0.48828125
|
||||||
location_data {
|
location_data {
|
||||||
|
@ -263,8 +266,8 @@ TEST_F(CreateFromOptionsTest, FailsWithIllegalCallbackInImageOrVideoMode) {
|
||||||
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
||||||
options->running_mode = running_mode;
|
options->running_mode = running_mode;
|
||||||
options->result_callback =
|
options->result_callback =
|
||||||
[](absl::StatusOr<std::vector<Detection>> detections,
|
[](absl::StatusOr<ObjectDetectorResult> detections, const Image& image,
|
||||||
const Image& image, int64 timestamp_ms) {};
|
int64 timestamp_ms) {};
|
||||||
absl::StatusOr<std::unique_ptr<ObjectDetector>> object_detector =
|
absl::StatusOr<std::unique_ptr<ObjectDetector>> object_detector =
|
||||||
ObjectDetector::Create(std::move(options));
|
ObjectDetector::Create(std::move(options));
|
||||||
EXPECT_EQ(object_detector.status().code(),
|
EXPECT_EQ(object_detector.status().code(),
|
||||||
|
@ -340,34 +343,36 @@ TEST_F(ImageModeTest, Succeeds) {
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
ExpectApproximatelyEqual(
|
ExpectApproximatelyEqual(
|
||||||
results, {ParseTextProtoOrDie<Detection>(R"pb(
|
results,
|
||||||
label: "cat"
|
ConvertToDetectionResult(
|
||||||
score: 0.69921875
|
{ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
location_data {
|
label: "cat"
|
||||||
format: BOUNDING_BOX
|
score: 0.69921875
|
||||||
bounding_box { xmin: 608 ymin: 161 width: 381 height: 439 }
|
location_data {
|
||||||
})pb"),
|
format: BOUNDING_BOX
|
||||||
ParseTextProtoOrDie<Detection>(R"pb(
|
bounding_box { xmin: 608 ymin: 161 width: 381 height: 439 }
|
||||||
label: "cat"
|
})pb"),
|
||||||
score: 0.64453125
|
ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
location_data {
|
label: "cat"
|
||||||
format: BOUNDING_BOX
|
score: 0.64453125
|
||||||
bounding_box { xmin: 60 ymin: 398 width: 386 height: 196 }
|
location_data {
|
||||||
})pb"),
|
format: BOUNDING_BOX
|
||||||
ParseTextProtoOrDie<Detection>(R"pb(
|
bounding_box { xmin: 60 ymin: 398 width: 386 height: 196 }
|
||||||
label: "cat"
|
})pb"),
|
||||||
score: 0.51171875
|
ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
location_data {
|
label: "cat"
|
||||||
format: BOUNDING_BOX
|
score: 0.51171875
|
||||||
bounding_box { xmin: 256 ymin: 395 width: 173 height: 202 }
|
location_data {
|
||||||
})pb"),
|
format: BOUNDING_BOX
|
||||||
ParseTextProtoOrDie<Detection>(R"pb(
|
bounding_box { xmin: 256 ymin: 395 width: 173 height: 202 }
|
||||||
label: "cat"
|
})pb"),
|
||||||
score: 0.48828125
|
ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
location_data {
|
label: "cat"
|
||||||
format: BOUNDING_BOX
|
score: 0.48828125
|
||||||
bounding_box { xmin: 362 ymin: 191 width: 325 height: 419 }
|
location_data {
|
||||||
})pb")});
|
format: BOUNDING_BOX
|
||||||
|
bounding_box { xmin: 362 ymin: 191 width: 325 height: 419 }
|
||||||
|
})pb")}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageModeTest, SucceedsEfficientDetModel) {
|
TEST_F(ImageModeTest, SucceedsEfficientDetModel) {
|
||||||
|
@ -383,34 +388,36 @@ TEST_F(ImageModeTest, SucceedsEfficientDetModel) {
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
ExpectApproximatelyEqual(
|
ExpectApproximatelyEqual(
|
||||||
results, {ParseTextProtoOrDie<Detection>(R"pb(
|
results,
|
||||||
label: "cat"
|
ConvertToDetectionResult(
|
||||||
score: 0.7578125
|
{ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
location_data {
|
label: "cat"
|
||||||
format: BOUNDING_BOX
|
score: 0.7578125
|
||||||
bounding_box { xmin: 858 ymin: 408 width: 225 height: 187 }
|
location_data {
|
||||||
})pb"),
|
format: BOUNDING_BOX
|
||||||
ParseTextProtoOrDie<Detection>(R"pb(
|
bounding_box { xmin: 858 ymin: 408 width: 225 height: 187 }
|
||||||
label: "cat"
|
})pb"),
|
||||||
score: 0.72265625
|
ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
location_data {
|
label: "cat"
|
||||||
format: BOUNDING_BOX
|
score: 0.72265625
|
||||||
bounding_box { xmin: 67 ymin: 401 width: 399 height: 192 }
|
location_data {
|
||||||
})pb"),
|
format: BOUNDING_BOX
|
||||||
ParseTextProtoOrDie<Detection>(R"pb(
|
bounding_box { xmin: 67 ymin: 401 width: 399 height: 192 }
|
||||||
label: "cat"
|
})pb"),
|
||||||
score: 0.6289063
|
ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
location_data {
|
label: "cat"
|
||||||
format: BOUNDING_BOX
|
score: 0.6289063
|
||||||
bounding_box { xmin: 368 ymin: 210 width: 272 height: 385 }
|
location_data {
|
||||||
})pb"),
|
format: BOUNDING_BOX
|
||||||
ParseTextProtoOrDie<Detection>(R"pb(
|
bounding_box { xmin: 368 ymin: 210 width: 272 height: 385 }
|
||||||
label: "cat"
|
})pb"),
|
||||||
score: 0.5859375
|
ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
location_data {
|
label: "cat"
|
||||||
format: BOUNDING_BOX
|
score: 0.5859375
|
||||||
bounding_box { xmin: 601 ymin: 166 width: 298 height: 437 }
|
location_data {
|
||||||
})pb")});
|
format: BOUNDING_BOX
|
||||||
|
bounding_box { xmin: 601 ymin: 166 width: 298 height: 437 }
|
||||||
|
})pb")}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageModeTest, SucceedsWithoutImageResizing) {
|
TEST_F(ImageModeTest, SucceedsWithoutImageResizing) {
|
||||||
|
@ -426,7 +433,8 @@ TEST_F(ImageModeTest, SucceedsWithoutImageResizing) {
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
ExpectApproximatelyEqual(
|
ExpectApproximatelyEqual(
|
||||||
results, GenerateMobileSsdNoImageResizingFullExpectedResults());
|
results, ConvertToDetectionResult(
|
||||||
|
GenerateMobileSsdNoImageResizingFullExpectedResults()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageModeTest, SucceedsWithScoreCalibration) {
|
TEST_F(ImageModeTest, SucceedsWithScoreCalibration) {
|
||||||
|
@ -442,13 +450,14 @@ TEST_F(ImageModeTest, SucceedsWithScoreCalibration) {
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
ExpectApproximatelyEqual(
|
ExpectApproximatelyEqual(
|
||||||
results, {ParseTextProtoOrDie<Detection>(R"pb(
|
results,
|
||||||
|
ConvertToDetectionResult({ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
label: "cat"
|
label: "cat"
|
||||||
score: 0.6531269142
|
score: 0.6531269142
|
||||||
location_data {
|
location_data {
|
||||||
format: BOUNDING_BOX
|
format: BOUNDING_BOX
|
||||||
bounding_box { xmin: 14 ymin: 197 width: 98 height: 99 }
|
bounding_box { xmin: 14 ymin: 197 width: 98 height: 99 }
|
||||||
})pb")});
|
})pb")}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageModeTest, SucceedsWithScoreThresholdOption) {
|
TEST_F(ImageModeTest, SucceedsWithScoreThresholdOption) {
|
||||||
|
@ -463,11 +472,13 @@ TEST_F(ImageModeTest, SucceedsWithScoreThresholdOption) {
|
||||||
ObjectDetector::Create(std::move(options)));
|
ObjectDetector::Create(std::move(options)));
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
std::vector<Detection> full_expected_results =
|
std::vector<DetectionProto> full_expected_results =
|
||||||
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
||||||
ExpectApproximatelyEqual(results,
|
|
||||||
{full_expected_results[0], full_expected_results[1],
|
ExpectApproximatelyEqual(
|
||||||
full_expected_results[2]});
|
results, ConvertToDetectionResult({full_expected_results[0],
|
||||||
|
full_expected_results[1],
|
||||||
|
full_expected_results[2]}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageModeTest, SucceedsWithMaxResultsOption) {
|
TEST_F(ImageModeTest, SucceedsWithMaxResultsOption) {
|
||||||
|
@ -482,10 +493,11 @@ TEST_F(ImageModeTest, SucceedsWithMaxResultsOption) {
|
||||||
ObjectDetector::Create(std::move(options)));
|
ObjectDetector::Create(std::move(options)));
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
std::vector<Detection> full_expected_results =
|
std::vector<DetectionProto> full_expected_results =
|
||||||
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
||||||
ExpectApproximatelyEqual(
|
ExpectApproximatelyEqual(
|
||||||
results, {full_expected_results[0], full_expected_results[1]});
|
results, ConvertToDetectionResult(
|
||||||
|
{full_expected_results[0], full_expected_results[1]}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageModeTest, SucceedsWithAllowlistOption) {
|
TEST_F(ImageModeTest, SucceedsWithAllowlistOption) {
|
||||||
|
@ -501,9 +513,10 @@ TEST_F(ImageModeTest, SucceedsWithAllowlistOption) {
|
||||||
ObjectDetector::Create(std::move(options)));
|
ObjectDetector::Create(std::move(options)));
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
std::vector<Detection> full_expected_results =
|
std::vector<DetectionProto> full_expected_results =
|
||||||
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
||||||
ExpectApproximatelyEqual(results, {full_expected_results[3]});
|
ExpectApproximatelyEqual(
|
||||||
|
results, ConvertToDetectionResult({full_expected_results[3]}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageModeTest, SucceedsWithDenylistOption) {
|
TEST_F(ImageModeTest, SucceedsWithDenylistOption) {
|
||||||
|
@ -519,9 +532,10 @@ TEST_F(ImageModeTest, SucceedsWithDenylistOption) {
|
||||||
ObjectDetector::Create(std::move(options)));
|
ObjectDetector::Create(std::move(options)));
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
MP_ASSERT_OK_AND_ASSIGN(auto results, object_detector->Detect(image));
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
std::vector<Detection> full_expected_results =
|
std::vector<DetectionProto> full_expected_results =
|
||||||
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
||||||
ExpectApproximatelyEqual(results, {full_expected_results[3]});
|
ExpectApproximatelyEqual(
|
||||||
|
results, ConvertToDetectionResult({full_expected_results[3]}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageModeTest, SucceedsWithRotation) {
|
TEST_F(ImageModeTest, SucceedsWithRotation) {
|
||||||
|
@ -541,13 +555,14 @@ TEST_F(ImageModeTest, SucceedsWithRotation) {
|
||||||
auto results, object_detector->Detect(image, image_processing_options));
|
auto results, object_detector->Detect(image, image_processing_options));
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
ExpectApproximatelyEqual(
|
ExpectApproximatelyEqual(
|
||||||
results, {ParseTextProtoOrDie<Detection>(R"pb(
|
results,
|
||||||
|
ConvertToDetectionResult({ParseTextProtoOrDie<DetectionProto>(R"pb(
|
||||||
label: "cat"
|
label: "cat"
|
||||||
score: 0.7109375
|
score: 0.7109375
|
||||||
location_data {
|
location_data {
|
||||||
format: BOUNDING_BOX
|
format: BOUNDING_BOX
|
||||||
bounding_box { xmin: 0 ymin: 622 width: 436 height: 276 }
|
bounding_box { xmin: 0 ymin: 622 width: 436 height: 276 }
|
||||||
})pb")});
|
})pb")}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageModeTest, FailsWithRegionOfInterest) {
|
TEST_F(ImageModeTest, FailsWithRegionOfInterest) {
|
||||||
|
@ -560,7 +575,7 @@ TEST_F(ImageModeTest, FailsWithRegionOfInterest) {
|
||||||
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
||||||
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ObjectDetector> object_detector,
|
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ObjectDetector> object_detector,
|
||||||
ObjectDetector::Create(std::move(options)));
|
ObjectDetector::Create(std::move(options)));
|
||||||
Rect roi{/*left=*/0.1, /*top=*/0, /*right=*/0.9, /*bottom=*/1};
|
RectF roi{/*left=*/0.1, /*top=*/0, /*right=*/0.9, /*bottom=*/1};
|
||||||
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
ImageProcessingOptions image_processing_options{roi, /*rotation_degrees=*/0};
|
||||||
|
|
||||||
auto results = object_detector->Detect(image, image_processing_options);
|
auto results = object_detector->Detect(image, image_processing_options);
|
||||||
|
@ -619,10 +634,11 @@ TEST_F(VideoModeTest, Succeeds) {
|
||||||
for (int i = 0; i < iterations; ++i) {
|
for (int i = 0; i < iterations; ++i) {
|
||||||
MP_ASSERT_OK_AND_ASSIGN(auto results,
|
MP_ASSERT_OK_AND_ASSIGN(auto results,
|
||||||
object_detector->DetectForVideo(image, i));
|
object_detector->DetectForVideo(image, i));
|
||||||
std::vector<Detection> full_expected_results =
|
std::vector<DetectionProto> full_expected_results =
|
||||||
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
||||||
ExpectApproximatelyEqual(
|
ExpectApproximatelyEqual(
|
||||||
results, {full_expected_results[0], full_expected_results[1]});
|
results, ConvertToDetectionResult(
|
||||||
|
{full_expected_results[0], full_expected_results[1]}));
|
||||||
}
|
}
|
||||||
MP_ASSERT_OK(object_detector->Close());
|
MP_ASSERT_OK(object_detector->Close());
|
||||||
}
|
}
|
||||||
|
@ -637,9 +653,8 @@ TEST_F(LiveStreamModeTest, FailsWithCallingWrongMethod) {
|
||||||
options->base_options.model_asset_path =
|
options->base_options.model_asset_path =
|
||||||
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
||||||
options->running_mode = core::RunningMode::LIVE_STREAM;
|
options->running_mode = core::RunningMode::LIVE_STREAM;
|
||||||
options->result_callback =
|
options->result_callback = [](absl::StatusOr<ObjectDetectorResult> detections,
|
||||||
[](absl::StatusOr<std::vector<Detection>> detections, const Image& image,
|
const Image& image, int64 timestamp_ms) {};
|
||||||
int64 timestamp_ms) {};
|
|
||||||
|
|
||||||
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ObjectDetector> object_detector,
|
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ObjectDetector> object_detector,
|
||||||
ObjectDetector::Create(std::move(options)));
|
ObjectDetector::Create(std::move(options)));
|
||||||
|
@ -669,9 +684,8 @@ TEST_F(LiveStreamModeTest, FailsWithOutOfOrderInputTimestamps) {
|
||||||
options->running_mode = core::RunningMode::LIVE_STREAM;
|
options->running_mode = core::RunningMode::LIVE_STREAM;
|
||||||
options->base_options.model_asset_path =
|
options->base_options.model_asset_path =
|
||||||
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
||||||
options->result_callback =
|
options->result_callback = [](absl::StatusOr<ObjectDetectorResult> detections,
|
||||||
[](absl::StatusOr<std::vector<Detection>> detections, const Image& image,
|
const Image& image, int64 timestamp_ms) {};
|
||||||
int64 timestamp_ms) {};
|
|
||||||
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ObjectDetector> object_detector,
|
MP_ASSERT_OK_AND_ASSIGN(std::unique_ptr<ObjectDetector> object_detector,
|
||||||
ObjectDetector::Create(std::move(options)));
|
ObjectDetector::Create(std::move(options)));
|
||||||
MP_ASSERT_OK(object_detector->DetectAsync(image, 1));
|
MP_ASSERT_OK(object_detector->DetectAsync(image, 1));
|
||||||
|
@ -695,14 +709,14 @@ TEST_F(LiveStreamModeTest, Succeeds) {
|
||||||
auto options = std::make_unique<ObjectDetectorOptions>();
|
auto options = std::make_unique<ObjectDetectorOptions>();
|
||||||
options->max_results = 2;
|
options->max_results = 2;
|
||||||
options->running_mode = core::RunningMode::LIVE_STREAM;
|
options->running_mode = core::RunningMode::LIVE_STREAM;
|
||||||
std::vector<std::vector<Detection>> detection_results;
|
std::vector<ObjectDetectorResult> detection_results;
|
||||||
std::vector<std::pair<int, int>> image_sizes;
|
std::vector<std::pair<int, int>> image_sizes;
|
||||||
std::vector<int64> timestamps;
|
std::vector<int64> timestamps;
|
||||||
options->base_options.model_asset_path =
|
options->base_options.model_asset_path =
|
||||||
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
JoinPath("./", kTestDataDirectory, kMobileSsdWithMetadata);
|
||||||
options->result_callback =
|
options->result_callback =
|
||||||
[&detection_results, &image_sizes, ×tamps](
|
[&detection_results, &image_sizes, ×tamps](
|
||||||
absl::StatusOr<std::vector<Detection>> detections, const Image& image,
|
absl::StatusOr<ObjectDetectorResult> detections, const Image& image,
|
||||||
int64 timestamp_ms) {
|
int64 timestamp_ms) {
|
||||||
MP_ASSERT_OK(detections.status());
|
MP_ASSERT_OK(detections.status());
|
||||||
detection_results.push_back(std::move(detections).value());
|
detection_results.push_back(std::move(detections).value());
|
||||||
|
@ -719,11 +733,12 @@ TEST_F(LiveStreamModeTest, Succeeds) {
|
||||||
// number of iterations.
|
// number of iterations.
|
||||||
ASSERT_LE(detection_results.size(), iterations);
|
ASSERT_LE(detection_results.size(), iterations);
|
||||||
ASSERT_GT(detection_results.size(), 0);
|
ASSERT_GT(detection_results.size(), 0);
|
||||||
std::vector<Detection> full_expected_results =
|
std::vector<DetectionProto> full_expected_results =
|
||||||
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
GenerateMobileSsdNoImageResizingFullExpectedResults();
|
||||||
for (const auto& detection_result : detection_results) {
|
for (const auto& detection_result : detection_results) {
|
||||||
ExpectApproximatelyEqual(
|
ExpectApproximatelyEqual(
|
||||||
detection_result, {full_expected_results[0], full_expected_results[1]});
|
detection_result, ConvertToDetectionResult({full_expected_results[0],
|
||||||
|
full_expected_results[1]}));
|
||||||
}
|
}
|
||||||
for (const auto& image_size : image_sizes) {
|
for (const auto& image_size : image_sizes) {
|
||||||
EXPECT_EQ(image_size.first, image.width());
|
EXPECT_EQ(image_size.first, image.width());
|
||||||
|
|
|
@ -22,13 +22,13 @@ limitations under the License.
|
||||||
|
|
||||||
namespace mediapipe::tasks::vision::utils {
|
namespace mediapipe::tasks::vision::utils {
|
||||||
|
|
||||||
using ::mediapipe::tasks::components::containers::Rect;
|
using ::mediapipe::tasks::components::containers::RectF;
|
||||||
|
|
||||||
float CalculateArea(const Rect& rect) {
|
float CalculateArea(const RectF& rect) {
|
||||||
return (rect.right - rect.left) * (rect.bottom - rect.top);
|
return (rect.right - rect.left) * (rect.bottom - rect.top);
|
||||||
}
|
}
|
||||||
|
|
||||||
float CalculateIntersectionArea(const Rect& a, const Rect& b) {
|
float CalculateIntersectionArea(const RectF& a, const RectF& b) {
|
||||||
const float intersection_left = std::max<float>(a.left, b.left);
|
const float intersection_left = std::max<float>(a.left, b.left);
|
||||||
const float intersection_top = std::max<float>(a.top, b.top);
|
const float intersection_top = std::max<float>(a.top, b.top);
|
||||||
const float intersection_right = std::min<float>(a.right, b.right);
|
const float intersection_right = std::min<float>(a.right, b.right);
|
||||||
|
@ -38,7 +38,7 @@ float CalculateIntersectionArea(const Rect& a, const Rect& b) {
|
||||||
std::max<float>(intersection_right - intersection_left, 0.0);
|
std::max<float>(intersection_right - intersection_left, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
float CalculateIOU(const Rect& a, const Rect& b) {
|
float CalculateIOU(const RectF& a, const RectF& b) {
|
||||||
const float area_a = CalculateArea(a);
|
const float area_a = CalculateArea(a);
|
||||||
const float area_b = CalculateArea(b);
|
const float area_b = CalculateArea(b);
|
||||||
if (area_a <= 0 || area_b <= 0) return 0.0;
|
if (area_a <= 0 || area_b <= 0) return 0.0;
|
||||||
|
|
|
@ -27,15 +27,15 @@ limitations under the License.
|
||||||
namespace mediapipe::tasks::vision::utils {
|
namespace mediapipe::tasks::vision::utils {
|
||||||
|
|
||||||
// Calculates intersection over union for two bounds.
|
// Calculates intersection over union for two bounds.
|
||||||
float CalculateIOU(const components::containers::Rect& a,
|
float CalculateIOU(const components::containers::RectF& a,
|
||||||
const components::containers::Rect& b);
|
const components::containers::RectF& b);
|
||||||
|
|
||||||
// Calculates area for face bound
|
// Calculates area for face bound
|
||||||
float CalculateArea(const components::containers::Rect& rect);
|
float CalculateArea(const components::containers::RectF& rect);
|
||||||
|
|
||||||
// Calucates intersection area of two face bounds
|
// Calucates intersection area of two face bounds
|
||||||
float CalculateIntersectionArea(const components::containers::Rect& a,
|
float CalculateIntersectionArea(const components::containers::RectF& a,
|
||||||
const components::containers::Rect& b);
|
const components::containers::RectF& b);
|
||||||
} // namespace mediapipe::tasks::vision::utils
|
} // namespace mediapipe::tasks::vision::utils
|
||||||
|
|
||||||
#endif // MEDIAPIPE_TASKS_CC_VISION_UTILS_LANDMARKS_UTILS_H_
|
#endif // MEDIAPIPE_TASKS_CC_VISION_UTILS_LANDMARKS_UTILS_H_
|
||||||
|
|
Loading…
Reference in New Issue
Block a user