Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0a3357151 |
+58
-93
@@ -68,108 +68,30 @@ config_setting(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# Generic MacOS.
|
||||
config_setting(
|
||||
# Note: this cannot just match "apple_platform_type": "macos" because that option
|
||||
# defaults to "macos" even when building on Linux!
|
||||
alias(
|
||||
name = "macos",
|
||||
constraint_values = [
|
||||
"@platforms//os:macos",
|
||||
],
|
||||
actual = select({
|
||||
":macos_i386": ":macos_i386",
|
||||
":macos_x86_64": ":macos_x86_64",
|
||||
":macos_arm64": ":macos_arm64",
|
||||
"//conditions:default": ":macos_i386", # Arbitrarily chosen from above.
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# MacOS x86 64-bit.
|
||||
config_setting(
|
||||
name = "macos_x86_64",
|
||||
constraint_values = [
|
||||
"@platforms//os:macos",
|
||||
"@platforms//cpu:x86_64",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# MacOS ARM64.
|
||||
config_setting(
|
||||
name = "macos_arm64",
|
||||
constraint_values = [
|
||||
"@platforms//os:macos",
|
||||
"@platforms//cpu:arm64",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# Generic iOS.
|
||||
# Note: this also matches on crosstool_top so that it does not produce ambiguous
|
||||
# selectors when used together with "android".
|
||||
config_setting(
|
||||
name = "ios",
|
||||
constraint_values = [
|
||||
"@platforms//os:ios",
|
||||
],
|
||||
values = {
|
||||
"crosstool_top": "@bazel_tools//tools/cpp:toolchain",
|
||||
"apple_platform_type": "ios",
|
||||
},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# iOS device ARM32.
|
||||
config_setting(
|
||||
name = "ios_armv7",
|
||||
constraint_values = [
|
||||
"@platforms//os:ios",
|
||||
"@platforms//cpu:arm",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# iOS device ARM64.
|
||||
config_setting(
|
||||
name = "ios_arm64",
|
||||
constraint_values = [
|
||||
"@platforms//os:ios",
|
||||
"@platforms//cpu:arm64",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# iOS device ARM64E.
|
||||
config_setting(
|
||||
name = "ios_arm64e",
|
||||
constraint_values = [
|
||||
"@platforms//os:ios",
|
||||
"@platforms//cpu:arm64e",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# iOS simulator x86 32-bit.
|
||||
config_setting(
|
||||
name = "ios_i386",
|
||||
constraint_values = [
|
||||
"@platforms//os:ios",
|
||||
"@platforms//cpu:x86_32",
|
||||
"@build_bazel_apple_support//constraints:simulator",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# iOS simulator x86 64-bit.
|
||||
config_setting(
|
||||
name = "ios_x86_64",
|
||||
constraint_values = [
|
||||
"@platforms//os:ios",
|
||||
"@platforms//cpu:x86_64",
|
||||
"@build_bazel_apple_support//constraints:simulator",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# iOS simulator ARM64.
|
||||
config_setting(
|
||||
name = "ios_sim_arm64",
|
||||
constraint_values = [
|
||||
"@platforms//os:ios",
|
||||
"@platforms//cpu:arm64",
|
||||
"@build_bazel_apple_support//constraints:simulator",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# Generic Apple.
|
||||
alias(
|
||||
name = "apple",
|
||||
actual = select({
|
||||
@@ -180,6 +102,49 @@ alias(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "macos_i386",
|
||||
values = {
|
||||
"apple_platform_type": "macos",
|
||||
"cpu": "darwin",
|
||||
},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "macos_x86_64",
|
||||
values = {
|
||||
"apple_platform_type": "macos",
|
||||
"cpu": "darwin_x86_64",
|
||||
},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "macos_arm64",
|
||||
values = {
|
||||
"apple_platform_type": "macos",
|
||||
"cpu": "darwin_arm64",
|
||||
},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
[
|
||||
config_setting(
|
||||
name = arch,
|
||||
values = {"cpu": arch},
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
for arch in [
|
||||
"ios_i386",
|
||||
"ios_x86_64",
|
||||
"ios_armv7",
|
||||
"ios_arm64",
|
||||
"ios_arm64e",
|
||||
"ios_sim_arm64",
|
||||
]
|
||||
]
|
||||
|
||||
config_setting(
|
||||
name = "windows",
|
||||
values = {"cpu": "x64_windows"},
|
||||
|
||||
@@ -381,6 +381,17 @@ cc_library(
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "clip_detection_vector_size_calculator",
|
||||
srcs = ["clip_detection_vector_size_calculator.cc"],
|
||||
deps = [
|
||||
":clip_vector_size_calculator",
|
||||
"//mediapipe/framework:calculator_framework",
|
||||
"//mediapipe/framework/formats:detection_cc_proto",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "clip_vector_size_calculator_test",
|
||||
srcs = ["clip_vector_size_calculator_test.cc"],
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2019 The MediaPipe Authors.
|
||||
//
|
||||
// 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 <vector>
|
||||
|
||||
#include "mediapipe/calculators/core/clip_vector_size_calculator.h"
|
||||
#include "mediapipe/framework/formats/detection.pb.h"
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
typedef ClipVectorSizeCalculator<::mediapipe::Detection>
|
||||
ClipDetectionVectorSizeCalculator;
|
||||
REGISTER_CALCULATOR(ClipDetectionVectorSizeCalculator);
|
||||
|
||||
} // namespace mediapipe
|
||||
@@ -112,7 +112,7 @@ class BilateralFilterCalculator : public CalculatorBase {
|
||||
REGISTER_CALCULATOR(BilateralFilterCalculator);
|
||||
|
||||
absl::Status BilateralFilterCalculator::GetContract(CalculatorContract* cc) {
|
||||
RET_CHECK_GE(cc->Inputs().NumEntries(), 1);
|
||||
CHECK_GE(cc->Inputs().NumEntries(), 1);
|
||||
|
||||
if (cc->Inputs().HasTag(kInputFrameTag) &&
|
||||
cc->Inputs().HasTag(kInputFrameTagGpu)) {
|
||||
|
||||
@@ -110,7 +110,7 @@ REGISTER_CALCULATOR(SegmentationSmoothingCalculator);
|
||||
|
||||
absl::Status SegmentationSmoothingCalculator::GetContract(
|
||||
CalculatorContract* cc) {
|
||||
RET_CHECK_GE(cc->Inputs().NumEntries(), 1);
|
||||
CHECK_GE(cc->Inputs().NumEntries(), 1);
|
||||
|
||||
cc->Inputs().Tag(kCurrentMaskTag).Set<Image>();
|
||||
cc->Inputs().Tag(kPreviousMaskTag).Set<Image>();
|
||||
|
||||
@@ -142,7 +142,7 @@ class SetAlphaCalculator : public CalculatorBase {
|
||||
REGISTER_CALCULATOR(SetAlphaCalculator);
|
||||
|
||||
absl::Status SetAlphaCalculator::GetContract(CalculatorContract* cc) {
|
||||
RET_CHECK_GE(cc->Inputs().NumEntries(), 1);
|
||||
CHECK_GE(cc->Inputs().NumEntries(), 1);
|
||||
|
||||
bool use_gpu = false;
|
||||
|
||||
|
||||
@@ -69,7 +69,6 @@ class InferenceCalculatorGlAdvancedImpl
|
||||
gpu_delegate_options);
|
||||
absl::Status ReadGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const;
|
||||
absl::Status SaveGpuCaches(tflite::gpu::TFLiteGPURunner* gpu_runner) const;
|
||||
bool UseSerializedModel() const { return use_serialized_model_; }
|
||||
|
||||
private:
|
||||
bool use_kernel_caching_ = false;
|
||||
@@ -151,6 +150,8 @@ InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::Process(
|
||||
}
|
||||
|
||||
absl::Status InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::Close() {
|
||||
MP_RETURN_IF_ERROR(
|
||||
on_disk_cache_helper_.SaveGpuCaches(tflite_gpu_runner_.get()));
|
||||
return gpu_helper_.RunInGlContext([this]() -> absl::Status {
|
||||
tflite_gpu_runner_.reset();
|
||||
return absl::OkStatus();
|
||||
@@ -225,14 +226,9 @@ InferenceCalculatorGlAdvancedImpl::GpuInferenceRunner::InitTFLiteGPURunner(
|
||||
tflite_gpu_runner_->GetOutputShapes()[i].c};
|
||||
}
|
||||
|
||||
if (on_disk_cache_helper_.UseSerializedModel()) {
|
||||
tflite_gpu_runner_->ForceOpenCLInitFromSerializedModel();
|
||||
}
|
||||
|
||||
MP_RETURN_IF_ERROR(
|
||||
on_disk_cache_helper_.ReadGpuCaches(tflite_gpu_runner_.get()));
|
||||
MP_RETURN_IF_ERROR(tflite_gpu_runner_->Build());
|
||||
return on_disk_cache_helper_.SaveGpuCaches(tflite_gpu_runner_.get());
|
||||
return tflite_gpu_runner_->Build();
|
||||
}
|
||||
|
||||
#if defined(MEDIAPIPE_ANDROID) || defined(MEDIAPIPE_CHROMIUMOS)
|
||||
|
||||
@@ -927,6 +927,7 @@ cc_test(
|
||||
"//mediapipe/framework:timestamp",
|
||||
"//mediapipe/framework/formats:detection_cc_proto",
|
||||
"//mediapipe/framework/formats:image_frame",
|
||||
"//mediapipe/framework/formats:image_frame_opencv",
|
||||
"//mediapipe/framework/formats:location",
|
||||
"//mediapipe/framework/formats:location_opencv",
|
||||
"//mediapipe/framework/port:gtest_main",
|
||||
|
||||
@@ -164,8 +164,8 @@ class PackMediaSequenceCalculator : public CalculatorBase {
|
||||
}
|
||||
}
|
||||
|
||||
RET_CHECK(cc->Outputs().HasTag(kSequenceExampleTag) ||
|
||||
cc->OutputSidePackets().HasTag(kSequenceExampleTag))
|
||||
CHECK(cc->Outputs().HasTag(kSequenceExampleTag) ||
|
||||
cc->OutputSidePackets().HasTag(kSequenceExampleTag))
|
||||
<< "Neither the output stream nor the output side packet is set to "
|
||||
"output the sequence example.";
|
||||
if (cc->Outputs().HasTag(kSequenceExampleTag)) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "mediapipe/framework/calculator_runner.h"
|
||||
#include "mediapipe/framework/formats/detection.pb.h"
|
||||
#include "mediapipe/framework/formats/image_frame.h"
|
||||
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
||||
#include "mediapipe/framework/formats/location.h"
|
||||
#include "mediapipe/framework/formats/location_opencv.h"
|
||||
#include "mediapipe/framework/port/gmock.h"
|
||||
@@ -95,8 +96,7 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoImages) {
|
||||
mpms::SetClipMediaId(test_video_id, input_sequence.get());
|
||||
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
|
||||
std::vector<uchar> bytes;
|
||||
ASSERT_TRUE(
|
||||
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
|
||||
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
|
||||
OpenCvImageEncoderCalculatorResults encoded_image;
|
||||
encoded_image.set_encoded_image(bytes.data(), bytes.size());
|
||||
encoded_image.set_width(2);
|
||||
@@ -139,8 +139,7 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoPrefixedImages) {
|
||||
mpms::SetClipMediaId(test_video_id, input_sequence.get());
|
||||
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
|
||||
std::vector<uchar> bytes;
|
||||
ASSERT_TRUE(
|
||||
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
|
||||
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
|
||||
OpenCvImageEncoderCalculatorResults encoded_image;
|
||||
encoded_image.set_encoded_image(bytes.data(), bytes.size());
|
||||
encoded_image.set_width(2);
|
||||
@@ -379,8 +378,7 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksAdditionalContext) {
|
||||
Adopt(input_sequence.release());
|
||||
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
|
||||
std::vector<uchar> bytes;
|
||||
ASSERT_TRUE(
|
||||
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
|
||||
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
|
||||
OpenCvImageEncoderCalculatorResults encoded_image;
|
||||
encoded_image.set_encoded_image(bytes.data(), bytes.size());
|
||||
auto image_ptr =
|
||||
@@ -412,8 +410,7 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksTwoForwardFlowEncodeds) {
|
||||
|
||||
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
|
||||
std::vector<uchar> bytes;
|
||||
ASSERT_TRUE(
|
||||
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
|
||||
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
|
||||
std::string test_flow_string(bytes.begin(), bytes.end());
|
||||
OpenCvImageEncoderCalculatorResults encoded_flow;
|
||||
encoded_flow.set_encoded_image(test_flow_string);
|
||||
@@ -621,8 +618,7 @@ TEST_F(PackMediaSequenceCalculatorTest, PacksBBoxWithImages) {
|
||||
}
|
||||
cv::Mat image(height, width, CV_8UC3, cv::Scalar(0, 0, 255));
|
||||
std::vector<uchar> bytes;
|
||||
ASSERT_TRUE(
|
||||
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
|
||||
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
|
||||
OpenCvImageEncoderCalculatorResults encoded_image;
|
||||
encoded_image.set_encoded_image(bytes.data(), bytes.size());
|
||||
encoded_image.set_width(width);
|
||||
@@ -771,8 +767,7 @@ TEST_F(PackMediaSequenceCalculatorTest, MissingStreamOK) {
|
||||
|
||||
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
|
||||
std::vector<uchar> bytes;
|
||||
ASSERT_TRUE(
|
||||
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
|
||||
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
|
||||
std::string test_flow_string(bytes.begin(), bytes.end());
|
||||
OpenCvImageEncoderCalculatorResults encoded_flow;
|
||||
encoded_flow.set_encoded_image(test_flow_string);
|
||||
@@ -818,8 +813,7 @@ TEST_F(PackMediaSequenceCalculatorTest, MissingStreamNotOK) {
|
||||
mpms::SetClipMediaId(test_video_id, input_sequence.get());
|
||||
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
|
||||
std::vector<uchar> bytes;
|
||||
ASSERT_TRUE(
|
||||
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
|
||||
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
|
||||
std::string test_flow_string(bytes.begin(), bytes.end());
|
||||
OpenCvImageEncoderCalculatorResults encoded_flow;
|
||||
encoded_flow.set_encoded_image(test_flow_string);
|
||||
@@ -976,8 +970,7 @@ TEST_F(PackMediaSequenceCalculatorTest, TestReconcilingAnnotations) {
|
||||
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
|
||||
std::vector<uchar> bytes;
|
||||
ASSERT_TRUE(
|
||||
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
|
||||
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
|
||||
OpenCvImageEncoderCalculatorResults encoded_image;
|
||||
encoded_image.set_encoded_image(bytes.data(), bytes.size());
|
||||
encoded_image.set_width(2);
|
||||
@@ -1028,8 +1021,7 @@ TEST_F(PackMediaSequenceCalculatorTest, TestOverwritingAndReconciling) {
|
||||
auto input_sequence = ::absl::make_unique<tf::SequenceExample>();
|
||||
cv::Mat image(2, 3, CV_8UC3, cv::Scalar(0, 0, 255));
|
||||
std::vector<uchar> bytes;
|
||||
ASSERT_TRUE(
|
||||
cv::imencode(".jpg", image, bytes, {cv::IMWRITE_HDR_COMPRESSION, 1}));
|
||||
ASSERT_TRUE(cv::imencode(".jpg", image, bytes, {80}));
|
||||
OpenCvImageEncoderCalculatorResults encoded_image;
|
||||
encoded_image.set_encoded_image(bytes.data(), bytes.size());
|
||||
int height = 2;
|
||||
|
||||
@@ -172,7 +172,7 @@ class AnnotationOverlayCalculator : public CalculatorBase {
|
||||
REGISTER_CALCULATOR(AnnotationOverlayCalculator);
|
||||
|
||||
absl::Status AnnotationOverlayCalculator::GetContract(CalculatorContract* cc) {
|
||||
RET_CHECK_GE(cc->Inputs().NumEntries(), 1);
|
||||
CHECK_GE(cc->Inputs().NumEntries(), 1);
|
||||
|
||||
bool use_gpu = false;
|
||||
|
||||
@@ -189,13 +189,13 @@ absl::Status AnnotationOverlayCalculator::GetContract(CalculatorContract* cc) {
|
||||
#if !MEDIAPIPE_DISABLE_GPU
|
||||
if (cc->Inputs().HasTag(kGpuBufferTag)) {
|
||||
cc->Inputs().Tag(kGpuBufferTag).Set<mediapipe::GpuBuffer>();
|
||||
RET_CHECK(cc->Outputs().HasTag(kGpuBufferTag));
|
||||
CHECK(cc->Outputs().HasTag(kGpuBufferTag));
|
||||
use_gpu = true;
|
||||
}
|
||||
#endif // !MEDIAPIPE_DISABLE_GPU
|
||||
if (cc->Inputs().HasTag(kImageFrameTag)) {
|
||||
cc->Inputs().Tag(kImageFrameTag).Set<ImageFrame>();
|
||||
RET_CHECK(cc->Outputs().HasTag(kImageFrameTag));
|
||||
CHECK(cc->Outputs().HasTag(kImageFrameTag));
|
||||
}
|
||||
|
||||
// Data streams to render.
|
||||
|
||||
@@ -322,30 +322,27 @@ absl::Status LandmarksToRenderDataCalculator::Process(CalculatorContext* cc) {
|
||||
options_.presence_threshold(), options_.connection_color(), thickness,
|
||||
/*normalized=*/false, render_data.get());
|
||||
}
|
||||
if (options_.render_landmarks()) {
|
||||
for (int i = 0; i < landmarks.landmark_size(); ++i) {
|
||||
const Landmark& landmark = landmarks.landmark(i);
|
||||
for (int i = 0; i < landmarks.landmark_size(); ++i) {
|
||||
const Landmark& landmark = landmarks.landmark(i);
|
||||
|
||||
if (!IsLandmarkVisibleAndPresent<Landmark>(
|
||||
landmark, options_.utilize_visibility(),
|
||||
options_.visibility_threshold(), options_.utilize_presence(),
|
||||
options_.presence_threshold())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* landmark_data_render = AddPointRenderData(
|
||||
options_.landmark_color(), thickness, render_data.get());
|
||||
if (visualize_depth) {
|
||||
SetColorSizeValueFromZ(landmark.z(), z_min, z_max,
|
||||
landmark_data_render,
|
||||
options_.min_depth_circle_thickness(),
|
||||
options_.max_depth_circle_thickness());
|
||||
}
|
||||
auto* landmark_data = landmark_data_render->mutable_point();
|
||||
landmark_data->set_normalized(false);
|
||||
landmark_data->set_x(landmark.x());
|
||||
landmark_data->set_y(landmark.y());
|
||||
if (!IsLandmarkVisibleAndPresent<Landmark>(
|
||||
landmark, options_.utilize_visibility(),
|
||||
options_.visibility_threshold(), options_.utilize_presence(),
|
||||
options_.presence_threshold())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* landmark_data_render = AddPointRenderData(
|
||||
options_.landmark_color(), thickness, render_data.get());
|
||||
if (visualize_depth) {
|
||||
SetColorSizeValueFromZ(landmark.z(), z_min, z_max, landmark_data_render,
|
||||
options_.min_depth_circle_thickness(),
|
||||
options_.max_depth_circle_thickness());
|
||||
}
|
||||
auto* landmark_data = landmark_data_render->mutable_point();
|
||||
landmark_data->set_normalized(false);
|
||||
landmark_data->set_x(landmark.x());
|
||||
landmark_data->set_y(landmark.y());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,30 +368,27 @@ absl::Status LandmarksToRenderDataCalculator::Process(CalculatorContext* cc) {
|
||||
options_.presence_threshold(), options_.connection_color(), thickness,
|
||||
/*normalized=*/true, render_data.get());
|
||||
}
|
||||
if (options_.render_landmarks()) {
|
||||
for (int i = 0; i < landmarks.landmark_size(); ++i) {
|
||||
const NormalizedLandmark& landmark = landmarks.landmark(i);
|
||||
for (int i = 0; i < landmarks.landmark_size(); ++i) {
|
||||
const NormalizedLandmark& landmark = landmarks.landmark(i);
|
||||
|
||||
if (!IsLandmarkVisibleAndPresent<NormalizedLandmark>(
|
||||
landmark, options_.utilize_visibility(),
|
||||
options_.visibility_threshold(), options_.utilize_presence(),
|
||||
options_.presence_threshold())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* landmark_data_render = AddPointRenderData(
|
||||
options_.landmark_color(), thickness, render_data.get());
|
||||
if (visualize_depth) {
|
||||
SetColorSizeValueFromZ(landmark.z(), z_min, z_max,
|
||||
landmark_data_render,
|
||||
options_.min_depth_circle_thickness(),
|
||||
options_.max_depth_circle_thickness());
|
||||
}
|
||||
auto* landmark_data = landmark_data_render->mutable_point();
|
||||
landmark_data->set_normalized(true);
|
||||
landmark_data->set_x(landmark.x());
|
||||
landmark_data->set_y(landmark.y());
|
||||
if (!IsLandmarkVisibleAndPresent<NormalizedLandmark>(
|
||||
landmark, options_.utilize_visibility(),
|
||||
options_.visibility_threshold(), options_.utilize_presence(),
|
||||
options_.presence_threshold())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* landmark_data_render = AddPointRenderData(
|
||||
options_.landmark_color(), thickness, render_data.get());
|
||||
if (visualize_depth) {
|
||||
SetColorSizeValueFromZ(landmark.z(), z_min, z_max, landmark_data_render,
|
||||
options_.min_depth_circle_thickness(),
|
||||
options_.max_depth_circle_thickness());
|
||||
}
|
||||
auto* landmark_data = landmark_data_render->mutable_point();
|
||||
landmark_data->set_normalized(true);
|
||||
landmark_data->set_x(landmark.x());
|
||||
landmark_data->set_y(landmark.y());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,10 +32,6 @@ message LandmarksToRenderDataCalculatorOptions {
|
||||
|
||||
// Color of the landmarks.
|
||||
optional Color landmark_color = 2;
|
||||
|
||||
// Whether to render landmarks as points.
|
||||
optional bool render_landmarks = 14 [default = true];
|
||||
|
||||
// Color of the connections.
|
||||
optional Color connection_color = 3;
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ cc_library(
|
||||
"//mediapipe/framework/formats:video_stream_header",
|
||||
"//mediapipe/framework/port:opencv_imgproc",
|
||||
"//mediapipe/framework/port:opencv_video",
|
||||
"//mediapipe/framework/port:ret_check",
|
||||
"//mediapipe/framework/port:status",
|
||||
"//mediapipe/framework/tool:status_util",
|
||||
],
|
||||
@@ -340,6 +341,7 @@ cc_test(
|
||||
"//mediapipe/framework/port:opencv_core",
|
||||
"//mediapipe/framework/port:parse_text_proto",
|
||||
"//mediapipe/framework/tool:test_util",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -365,6 +367,7 @@ cc_test(
|
||||
"//mediapipe/framework/port:opencv_video",
|
||||
"//mediapipe/framework/port:parse_text_proto",
|
||||
"//mediapipe/framework/tool:test_util",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -448,6 +451,7 @@ cc_test(
|
||||
"//mediapipe/framework/tool:test_util",
|
||||
"//mediapipe/util/tracking:box_tracker_cc_proto",
|
||||
"//mediapipe/util/tracking:tracking_cc_proto",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -44,9 +44,6 @@ bzl_library(
|
||||
"encode_binary_proto.bzl",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"@bazel_skylib//lib:paths",
|
||||
],
|
||||
)
|
||||
|
||||
alias(
|
||||
|
||||
@@ -64,13 +64,57 @@ class CalculatorBaseFactoryFor<
|
||||
namespace api2 {
|
||||
namespace internal {
|
||||
|
||||
MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE(
|
||||
NodeRegistrator, mediapipe::CalculatorBaseRegistry, T::kCalculatorName,
|
||||
absl::make_unique<mediapipe::internal::CalculatorBaseFactoryFor<T>>)
|
||||
// Defining a member of this type causes P to be ODR-used, which forces its
|
||||
// instantiation if it's a static member of a template.
|
||||
// Previously we depended on the pointer's value to determine whether the size
|
||||
// of a character array is 0 or 1, forcing it to be instantiated so the
|
||||
// compiler can determine the object's layout. But using it as a template
|
||||
// argument is more compact.
|
||||
template <auto* P>
|
||||
struct ForceStaticInstantiation {
|
||||
#ifdef _MSC_VER
|
||||
// Just having it as the template argument does not count as a use for
|
||||
// MSVC.
|
||||
static constexpr bool Use() { return P != nullptr; }
|
||||
char force_static[Use()];
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE(SubgraphRegistrator,
|
||||
mediapipe::SubgraphRegistry,
|
||||
T::kCalculatorName, absl::make_unique<T>)
|
||||
// Helper template for forcing the definition of a static registration token.
|
||||
template <typename T>
|
||||
struct NodeRegistrationStatic {
|
||||
static NoDestructor<mediapipe::RegistrationToken> registration;
|
||||
|
||||
static mediapipe::RegistrationToken Make() {
|
||||
return mediapipe::CalculatorBaseRegistry::Register(
|
||||
T::kCalculatorName,
|
||||
absl::make_unique<mediapipe::internal::CalculatorBaseFactoryFor<T>>);
|
||||
}
|
||||
|
||||
using RequireStatics = ForceStaticInstantiation<®istration>;
|
||||
};
|
||||
|
||||
// Static members of template classes can be defined in the header.
|
||||
template <typename T>
|
||||
NoDestructor<mediapipe::RegistrationToken>
|
||||
NodeRegistrationStatic<T>::registration(NodeRegistrationStatic<T>::Make());
|
||||
|
||||
template <typename T>
|
||||
struct SubgraphRegistrationImpl {
|
||||
static NoDestructor<mediapipe::RegistrationToken> registration;
|
||||
|
||||
static mediapipe::RegistrationToken Make() {
|
||||
return mediapipe::SubgraphRegistry::Register(T::kCalculatorName,
|
||||
absl::make_unique<T>);
|
||||
}
|
||||
|
||||
using RequireStatics = ForceStaticInstantiation<®istration>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
NoDestructor<mediapipe::RegistrationToken>
|
||||
SubgraphRegistrationImpl<T>::registration(
|
||||
SubgraphRegistrationImpl<T>::Make());
|
||||
|
||||
} // namespace internal
|
||||
|
||||
@@ -83,7 +127,14 @@ template <class Impl = void>
|
||||
class RegisteredNode;
|
||||
|
||||
template <class Impl>
|
||||
class RegisteredNode : public Node, private internal::NodeRegistrator<Impl> {};
|
||||
class RegisteredNode : public Node {
|
||||
private:
|
||||
// The member below triggers instantiation of the registration static.
|
||||
// Note that the constructor of calculator subclasses is only invoked through
|
||||
// the registration token, and so we cannot simply use the static in the
|
||||
// constructor.
|
||||
typename internal::NodeRegistrationStatic<Impl>::RequireStatics register_;
|
||||
};
|
||||
|
||||
// No-op version for backwards compatibility.
|
||||
template <>
|
||||
@@ -165,27 +216,30 @@ class NodeImpl : public RegisteredNode<Impl>, public Intf {
|
||||
// TODO: verify that the subgraph config fully implements the
|
||||
// declared interface.
|
||||
template <class Intf, class Impl>
|
||||
class SubgraphImpl : public Subgraph,
|
||||
public Intf,
|
||||
private internal::SubgraphRegistrator<Impl> {};
|
||||
class SubgraphImpl : public Subgraph, public Intf {
|
||||
private:
|
||||
typename internal::SubgraphRegistrationImpl<Impl>::RequireStatics register_;
|
||||
};
|
||||
|
||||
// This macro is used to register a calculator that does not use automatic
|
||||
// registration. Deprecated.
|
||||
#define MEDIAPIPE_NODE_IMPLEMENTATION(Impl) \
|
||||
MEDIAPIPE_REGISTER_FACTORY_FUNCTION_QUALIFIED( \
|
||||
mediapipe::CalculatorBaseRegistry, calculator_registration, \
|
||||
Impl::kCalculatorName, \
|
||||
absl::make_unique<mediapipe::internal::CalculatorBaseFactoryFor<Impl>>)
|
||||
#define MEDIAPIPE_NODE_IMPLEMENTATION(Impl) \
|
||||
static mediapipe::NoDestructor<mediapipe::RegistrationToken> \
|
||||
REGISTRY_STATIC_VAR(calculator_registration, \
|
||||
__LINE__)(mediapipe::CalculatorBaseRegistry::Register( \
|
||||
Impl::kCalculatorName, \
|
||||
absl::make_unique<mediapipe::internal::CalculatorBaseFactoryFor<Impl>>))
|
||||
|
||||
// This macro is used to register a non-split-contract calculator. Deprecated.
|
||||
#define MEDIAPIPE_REGISTER_NODE(name) REGISTER_CALCULATOR(name)
|
||||
|
||||
// This macro is used to define a subgraph that does not use automatic
|
||||
// registration. Deprecated.
|
||||
#define MEDIAPIPE_SUBGRAPH_IMPLEMENTATION(Impl) \
|
||||
MEDIAPIPE_REGISTER_FACTORY_FUNCTION_QUALIFIED( \
|
||||
mediapipe::SubgraphRegistry, subgraph_registration, \
|
||||
Impl::kCalculatorName, absl::make_unique<Impl>)
|
||||
#define MEDIAPIPE_SUBGRAPH_IMPLEMENTATION(Impl) \
|
||||
static mediapipe::NoDestructor<mediapipe::RegistrationToken> \
|
||||
REGISTRY_STATIC_VAR(subgraph_registration, \
|
||||
__LINE__)(mediapipe::SubgraphRegistry::Register( \
|
||||
Impl::kCalculatorName, absl::make_unique<Impl>))
|
||||
|
||||
} // namespace api2
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -144,23 +144,6 @@ template <typename T>
|
||||
struct WrapStatusOr<absl::StatusOr<T>> {
|
||||
using type = absl::StatusOr<T>;
|
||||
};
|
||||
|
||||
// Defining a member of this type causes P to be ODR-used, which forces its
|
||||
// instantiation if it's a static member of a template.
|
||||
// Previously we depended on the pointer's value to determine whether the size
|
||||
// of a character array is 0 or 1, forcing it to be instantiated so the
|
||||
// compiler can determine the object's layout. But using it as a template
|
||||
// argument is more compact.
|
||||
template <auto* P>
|
||||
struct ForceStaticInstantiation {
|
||||
#ifdef _MSC_VER
|
||||
// Just having it as the template argument does not count as a use for
|
||||
// MSVC.
|
||||
static constexpr bool Use() { return P != nullptr; }
|
||||
char force_static[Use()];
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
} // namespace registration_internal
|
||||
|
||||
class NamespaceAllowlist {
|
||||
@@ -413,76 +396,11 @@ class GlobalFactoryRegistry {
|
||||
new mediapipe::RegistrationToken( \
|
||||
RegistryType::Register(#name, __VA_ARGS__))
|
||||
|
||||
#define MEDIAPIPE_REGISTER_FACTORY_FUNCTION_QUALIFIED(RegistryType, var_name, \
|
||||
name, ...) \
|
||||
static auto* REGISTRY_STATIC_VAR(var_name, __LINE__) = \
|
||||
new mediapipe::RegistrationToken( \
|
||||
RegistryType::Register(name, __VA_ARGS__))
|
||||
|
||||
// TODO: migrate to the above.
|
||||
#define REGISTER_FACTORY_FUNCTION_QUALIFIED(RegistryType, var_name, name, ...) \
|
||||
static auto* REGISTRY_STATIC_VAR(var_name, __LINE__) = \
|
||||
new mediapipe::RegistrationToken( \
|
||||
RegistryType::Register(#name, __VA_ARGS__))
|
||||
|
||||
// Defines a utility registrator class which can be used to automatically
|
||||
// register factory functions.
|
||||
//
|
||||
// Example:
|
||||
// === Defining a registry ================================================
|
||||
//
|
||||
// class Component {};
|
||||
//
|
||||
// using ComponentRegistry = GlobalFactoryRegistry<std::unique_ptr<Component>>;
|
||||
//
|
||||
// === Defining a registrator =============================================
|
||||
//
|
||||
// MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE(ComponentRegistrator,
|
||||
// ComponentRegistry, T::kName,
|
||||
// absl::make_unique<T>);
|
||||
//
|
||||
// === Defining and registering a new component. ==========================
|
||||
//
|
||||
// class MyComponent : public Component,
|
||||
// private ComponentRegistrator<MyComponent> {
|
||||
// public:
|
||||
// static constexpr char kName[] = "MyComponent";
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// NOTE:
|
||||
// - MyComponent is automatically registered in ComponentRegistry by
|
||||
// "MyComponent" name.
|
||||
// - Every component is require to provide its name (T::kName here.)
|
||||
#define MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE(RegistratorName, RegistryType, \
|
||||
name, ...) \
|
||||
template <typename T> \
|
||||
struct Internal##RegistratorName { \
|
||||
static NoDestructor<mediapipe::RegistrationToken> registration; \
|
||||
\
|
||||
static mediapipe::RegistrationToken Make() { \
|
||||
return RegistryType::Register(name, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
using RequireStatics = \
|
||||
registration_internal::ForceStaticInstantiation<®istration>; \
|
||||
}; \
|
||||
/* Static members of template classes can be defined in the header. */ \
|
||||
template <typename T> \
|
||||
NoDestructor<mediapipe::RegistrationToken> \
|
||||
Internal##RegistratorName<T>::registration( \
|
||||
Internal##RegistratorName<T>::Make()); \
|
||||
\
|
||||
template <typename T> \
|
||||
class RegistratorName { \
|
||||
private: \
|
||||
/* The member below triggers instantiation of the registration static. */ \
|
||||
/* Note that the constructor of calculator subclasses is only invoked */ \
|
||||
/* through the registration token, and so we cannot simply use the */ \
|
||||
/* static in theconstructor. */ \
|
||||
typename Internal##RegistratorName<T>::RequireStatics register_; \
|
||||
};
|
||||
|
||||
} // namespace mediapipe
|
||||
|
||||
#endif // MEDIAPIPE_DEPS_REGISTRATION_H_
|
||||
|
||||
@@ -37,33 +37,29 @@ Args:
|
||||
output: The desired name of the output file. Optional.
|
||||
"""
|
||||
|
||||
load("@bazel_skylib//lib:paths.bzl", "paths")
|
||||
|
||||
PROTOC = "@com_google_protobuf//:protoc"
|
||||
|
||||
def _canonicalize_proto_path_oss(f):
|
||||
if not f.root.path:
|
||||
return struct(
|
||||
proto_path = ".",
|
||||
file_name = f.short_path,
|
||||
)
|
||||
def _canonicalize_proto_path_oss(all_protos, genfile_path):
|
||||
"""For the protos from external repository, canonicalize the proto path and the file name.
|
||||
|
||||
# `f.path` looks like "<genfiles>/external/<repo>/(_virtual_imports/<library>/)?<file_name>"
|
||||
repo_name, _, file_name = f.path[len(paths.join(f.root.path, "external") + "/"):].partition("/")
|
||||
if file_name.startswith("_virtual_imports/"):
|
||||
# This is a virtual import; move "_virtual_imports/<library>" from `repo_name` to `file_name`.
|
||||
repo_name = paths.join(repo_name, *file_name.split("/", 2)[:2])
|
||||
file_name = file_name.split("/", 2)[-1]
|
||||
return struct(
|
||||
proto_path = paths.join(f.root.path, "external", repo_name),
|
||||
file_name = file_name,
|
||||
)
|
||||
Returns:
|
||||
Proto path list and proto source file list.
|
||||
"""
|
||||
proto_paths = []
|
||||
proto_file_names = []
|
||||
for s in all_protos.to_list():
|
||||
if s.path.startswith(genfile_path):
|
||||
repo_name, _, file_name = s.path[len(genfile_path + "/external/"):].partition("/")
|
||||
|
||||
def _map_root_path(f):
|
||||
return _canonicalize_proto_path_oss(f).proto_path
|
||||
|
||||
def _map_short_path(f):
|
||||
return _canonicalize_proto_path_oss(f).file_name
|
||||
# handle virtual imports
|
||||
if file_name.startswith("_virtual_imports"):
|
||||
repo_name = repo_name + "/" + "/".join(file_name.split("/", 2)[:2])
|
||||
file_name = file_name.split("/", 2)[-1]
|
||||
proto_paths.append(genfile_path + "/external/" + repo_name)
|
||||
proto_file_names.append(file_name)
|
||||
else:
|
||||
proto_file_names.append(s.path)
|
||||
return ([" --proto_path=" + path for path in proto_paths], proto_file_names)
|
||||
|
||||
def _get_proto_provider(dep):
|
||||
"""Get the provider for protocol buffers from a dependnecy.
|
||||
@@ -94,35 +90,24 @@ def _encode_binary_proto_impl(ctx):
|
||||
sibling = textpb,
|
||||
)
|
||||
|
||||
args = ctx.actions.args()
|
||||
args.add(textpb)
|
||||
args.add(binarypb)
|
||||
args.add(ctx.executable._proto_compiler)
|
||||
args.add(ctx.attr.message_type, format = "--encode=%s")
|
||||
args.add("--proto_path=.")
|
||||
args.add_all(
|
||||
all_protos,
|
||||
map_each = _map_root_path,
|
||||
format_each = "--proto_path=%s",
|
||||
uniquify = True,
|
||||
)
|
||||
args.add_all(
|
||||
all_protos,
|
||||
map_each = _map_short_path,
|
||||
uniquify = True,
|
||||
)
|
||||
path_list, file_list = _canonicalize_proto_path_oss(all_protos, ctx.genfiles_dir.path)
|
||||
|
||||
# Note: the combination of absolute_paths and proto_path, as well as the exact
|
||||
# order of gendir before ., is needed for the proto compiler to resolve
|
||||
# import statements that reference proto files produced by a genrule.
|
||||
ctx.actions.run_shell(
|
||||
tools = depset(
|
||||
direct = [textpb, ctx.executable._proto_compiler],
|
||||
transitive = [all_protos],
|
||||
),
|
||||
tools = all_protos.to_list() + [textpb, ctx.executable._proto_compiler],
|
||||
outputs = [binarypb],
|
||||
command = "${@:3} < $1 > $2",
|
||||
arguments = [args],
|
||||
command = " ".join(
|
||||
[
|
||||
ctx.executable._proto_compiler.path,
|
||||
"--encode=" + ctx.attr.message_type,
|
||||
"--proto_path=" + ctx.genfiles_dir.path,
|
||||
"--proto_path=" + ctx.bin_dir.path,
|
||||
"--proto_path=.",
|
||||
] + path_list + file_list +
|
||||
["<", textpb.path, ">", binarypb.path],
|
||||
),
|
||||
mnemonic = "EncodeProto",
|
||||
)
|
||||
|
||||
|
||||
@@ -261,8 +261,8 @@ cc_library(
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "opencv_photo",
|
||||
hdrs = ["opencv_photo_inc.h"],
|
||||
name = "opencv_highgui",
|
||||
hdrs = ["opencv_highgui_inc.h"],
|
||||
deps = [
|
||||
":opencv_core",
|
||||
"//third_party:opencv",
|
||||
@@ -297,15 +297,6 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "opencv_highgui",
|
||||
hdrs = ["opencv_highgui_inc.h"],
|
||||
deps = [
|
||||
":opencv_core",
|
||||
"//third_party:opencv",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "opencv_videoio",
|
||||
hdrs = ["opencv_videoio_inc.h"],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 The MediaPipe Authors.
|
||||
// Copyright 2019 The MediaPipe Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef MEDIAPIPE_FRAMEWORK_PORT_OPENCV_HIGHGUI_INC_H_
|
||||
#define MEDIAPIPE_FRAMEWORK_PORT_OPENCV_HIGHGUI_INC_H_
|
||||
#ifndef MEDIAPIPE_PORT_OPENCV_HIGHGUI_INC_H_
|
||||
#define MEDIAPIPE_PORT_OPENCV_HIGHGUI_INC_H_
|
||||
|
||||
#include <opencv2/core/version.hpp>
|
||||
|
||||
@@ -25,4 +25,4 @@
|
||||
#include <opencv2/highgui.hpp>
|
||||
#endif
|
||||
|
||||
#endif // MEDIAPIPE_FRAMEWORK_PORT_OPENCV_HIGHGUI_INC_H_
|
||||
#endif // MEDIAPIPE_PORT_OPENCV_HIGHGUI_INC_H_
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 The MediaPipe Authors.
|
||||
// Copyright 2019 The MediaPipe Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 The MediaPipe Authors.
|
||||
// Copyright 2019 The MediaPipe Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -48,18 +48,6 @@ class MuxInputStreamHandler : public InputStreamHandler {
|
||||
: InputStreamHandler(std::move(tag_map), cc_manager, options,
|
||||
calculator_run_in_parallel) {}
|
||||
|
||||
private:
|
||||
CollectionItemId GetControlStreamId() const {
|
||||
return input_stream_managers_.EndId() - 1;
|
||||
}
|
||||
void RemoveOutdatedDataPackets(Timestamp timestamp) {
|
||||
const CollectionItemId control_stream_id = GetControlStreamId();
|
||||
for (CollectionItemId id = input_stream_managers_.BeginId();
|
||||
id < control_stream_id; ++id) {
|
||||
input_stream_managers_.Get(id)->ErasePacketsEarlierThan(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// In MuxInputStreamHandler, a node is "ready" if:
|
||||
// - the control stream is done (need to call Close() in this case), or
|
||||
@@ -70,15 +58,9 @@ class MuxInputStreamHandler : public InputStreamHandler {
|
||||
absl::MutexLock lock(&input_streams_mutex_);
|
||||
|
||||
const auto& control_stream =
|
||||
input_stream_managers_.Get(GetControlStreamId());
|
||||
input_stream_managers_.Get(input_stream_managers_.EndId() - 1);
|
||||
bool empty;
|
||||
*min_stream_timestamp = control_stream->MinTimestampOrBound(&empty);
|
||||
|
||||
// Data streams may contain some outdated packets which failed to be popped
|
||||
// out during "FillInputSet". (This handler doesn't sync input streams,
|
||||
// hence "FillInputSet" can be triggerred before every input stream is
|
||||
// filled with packets corresponding to the same timestamp.)
|
||||
RemoveOutdatedDataPackets(*min_stream_timestamp);
|
||||
if (empty) {
|
||||
if (*min_stream_timestamp == Timestamp::Done()) {
|
||||
// Calculator is done if the control input stream is done.
|
||||
@@ -96,6 +78,11 @@ class MuxInputStreamHandler : public InputStreamHandler {
|
||||
const auto& data_stream = input_stream_managers_.Get(
|
||||
input_stream_managers_.BeginId() + control_value);
|
||||
|
||||
// Data stream may contain some outdated packets which failed to be popped
|
||||
// out during "FillInputSet". (This handler doesn't sync input streams,
|
||||
// hence "FillInputSet" can be triggerred before every input stream is
|
||||
// filled with packets corresponding to the same timestamp.)
|
||||
data_stream->ErasePacketsEarlierThan(*min_stream_timestamp);
|
||||
Timestamp stream_timestamp = data_stream->MinTimestampOrBound(&empty);
|
||||
if (empty) {
|
||||
if (stream_timestamp <= *min_stream_timestamp) {
|
||||
@@ -124,7 +111,8 @@ class MuxInputStreamHandler : public InputStreamHandler {
|
||||
CHECK(input_set);
|
||||
absl::MutexLock lock(&input_streams_mutex_);
|
||||
|
||||
const CollectionItemId control_stream_id = GetControlStreamId();
|
||||
const CollectionItemId control_stream_id =
|
||||
input_stream_managers_.EndId() - 1;
|
||||
auto& control_stream = input_stream_managers_.Get(control_stream_id);
|
||||
int num_packets_dropped = 0;
|
||||
bool stream_is_done = false;
|
||||
@@ -152,8 +140,15 @@ class MuxInputStreamHandler : public InputStreamHandler {
|
||||
AddPacketToShard(&input_set->Get(data_stream_id), std::move(data_packet),
|
||||
stream_is_done);
|
||||
|
||||
// Discard old packets on data streams.
|
||||
RemoveOutdatedDataPackets(input_timestamp.NextAllowedInStream());
|
||||
// Discard old packets on other streams.
|
||||
// Note that control_stream_id is the last valid id.
|
||||
auto next_timestamp = input_timestamp.NextAllowedInStream();
|
||||
for (CollectionItemId id = input_stream_managers_.BeginId();
|
||||
id < control_stream_id; ++id) {
|
||||
if (id == data_stream_id) continue;
|
||||
auto& other_stream = input_stream_managers_.Get(id);
|
||||
other_stream->ErasePacketsEarlierThan(next_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -645,41 +645,5 @@ TEST(MuxInputStreamHandlerTest,
|
||||
MP_ASSERT_OK(graph.WaitUntilDone());
|
||||
}
|
||||
|
||||
TEST(MuxInputStreamHandlerTest, RemovesUnusedDataStreamPackets) {
|
||||
CalculatorGraphConfig config =
|
||||
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||
input_stream: "input0"
|
||||
input_stream: "input1"
|
||||
input_stream: "select"
|
||||
node {
|
||||
calculator: "MuxCalculator"
|
||||
input_stream: "INPUT:0:input0"
|
||||
input_stream: "INPUT:1:input1"
|
||||
input_stream: "SELECT:select"
|
||||
output_stream: "OUTPUT:output"
|
||||
input_stream_handler { input_stream_handler: "MuxInputStreamHandler" }
|
||||
}
|
||||
)pb");
|
||||
config.set_max_queue_size(1);
|
||||
config.set_report_deadlock(true);
|
||||
|
||||
CalculatorGraph graph;
|
||||
MP_ASSERT_OK(graph.Initialize(config));
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||
"select", MakePacket<int>(0).At(Timestamp(2))));
|
||||
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||
"input0", MakePacket<int>(1000).At(Timestamp(2))));
|
||||
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||
|
||||
// Add two delayed packets to the deselected input. They should be discarded
|
||||
// instead of triggering the deadlock detection (max_queue_size = 1).
|
||||
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||
"input1", MakePacket<int>(900).At(Timestamp(1))));
|
||||
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||
"input1", MakePacket<int>(900).At(Timestamp(2))));
|
||||
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -109,8 +109,9 @@ absl::Status GlContext::CreateContext(
|
||||
}
|
||||
MP_RETURN_IF_ERROR(status);
|
||||
|
||||
VLOG(1) << "Successfully created a WebGL context with major version "
|
||||
<< gl_major_version_ << " and handle " << context_;
|
||||
LOG(INFO) << "Successfully created a WebGL context with major version "
|
||||
<< gl_major_version_ << " and handle " << context_;
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,6 @@ class GlScalerCalculator : public CalculatorBase {
|
||||
bool vertical_flip_output_;
|
||||
bool horizontal_flip_output_;
|
||||
FrameScaleMode scale_mode_ = FrameScaleMode::kStretch;
|
||||
bool use_nearest_neighbor_interpolation_ = false;
|
||||
};
|
||||
REGISTER_CALCULATOR(GlScalerCalculator);
|
||||
|
||||
@@ -187,8 +186,7 @@ absl::Status GlScalerCalculator::Open(CalculatorContext* cc) {
|
||||
scale_mode_ =
|
||||
FrameScaleModeFromProto(options.scale_mode(), FrameScaleMode::kStretch);
|
||||
}
|
||||
use_nearest_neighbor_interpolation_ =
|
||||
options.use_nearest_neighbor_interpolation();
|
||||
|
||||
if (HasTagOrIndex(cc->InputSidePackets(), "OUTPUT_DIMENSIONS", 1)) {
|
||||
const auto& dimensions =
|
||||
TagOrIndex(cc->InputSidePackets(), "OUTPUT_DIMENSIONS", 1)
|
||||
@@ -299,11 +297,6 @@ absl::Status GlScalerCalculator::Process(CalculatorContext* cc) {
|
||||
glBindTexture(src2.target(), src2.name());
|
||||
}
|
||||
|
||||
if (use_nearest_neighbor_interpolation_) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
MP_RETURN_IF_ERROR(renderer->GlRender(
|
||||
src1.width(), src1.height(), dst.width(), dst.height(), scale_mode_,
|
||||
rotation_, horizontal_flip_output_, vertical_flip_output_,
|
||||
|
||||
@@ -19,7 +19,7 @@ package mediapipe;
|
||||
import "mediapipe/framework/calculator.proto";
|
||||
import "mediapipe/gpu/scale_mode.proto";
|
||||
|
||||
// Next id: 9.
|
||||
// Next id: 8.
|
||||
message GlScalerCalculatorOptions {
|
||||
extend CalculatorOptions {
|
||||
optional GlScalerCalculatorOptions ext = 166373014;
|
||||
@@ -39,7 +39,4 @@ message GlScalerCalculatorOptions {
|
||||
// Flip the output texture horizontally. This is applied after rotation.
|
||||
optional bool flip_horizontal = 5;
|
||||
optional ScaleMode.Mode scale_mode = 6;
|
||||
// Whether to use nearest neighbor interpolation. Default to use linear
|
||||
// interpolation.
|
||||
optional bool use_nearest_neighbor_interpolation = 8 [default = false];
|
||||
}
|
||||
|
||||
@@ -100,10 +100,6 @@ const GlTextureInfo& GlTextureInfoForGpuBufferFormat(GpuBufferFormat format,
|
||||
{GL_R8, GL_RED, GL_UNSIGNED_BYTE, 1},
|
||||
#endif // TARGET_OS_OSX
|
||||
}},
|
||||
{GpuBufferFormat::kOneComponent8Alpha,
|
||||
{
|
||||
{GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, 1},
|
||||
}},
|
||||
{GpuBufferFormat::kOneComponent8Red,
|
||||
{
|
||||
{GL_R8, GL_RED, GL_UNSIGNED_BYTE, 1},
|
||||
@@ -225,7 +221,6 @@ ImageFormat::Format ImageFormatForGpuBufferFormat(GpuBufferFormat format) {
|
||||
case GpuBufferFormat::kRGBA32:
|
||||
// TODO: this likely maps to ImageFormat::SRGBA
|
||||
case GpuBufferFormat::kGrayHalf16:
|
||||
case GpuBufferFormat::kOneComponent8Alpha:
|
||||
case GpuBufferFormat::kOneComponent8Red:
|
||||
case GpuBufferFormat::kTwoComponent8:
|
||||
case GpuBufferFormat::kTwoComponentHalf16:
|
||||
|
||||
@@ -43,7 +43,6 @@ enum class GpuBufferFormat : uint32_t {
|
||||
kGrayFloat32 = MEDIAPIPE_FOURCC('L', '0', '0', 'f'),
|
||||
kGrayHalf16 = MEDIAPIPE_FOURCC('L', '0', '0', 'h'),
|
||||
kOneComponent8 = MEDIAPIPE_FOURCC('L', '0', '0', '8'),
|
||||
kOneComponent8Alpha = MEDIAPIPE_FOURCC('A', '0', '0', '8'),
|
||||
kOneComponent8Red = MEDIAPIPE_FOURCC('R', '0', '0', '8'),
|
||||
kTwoComponent8 = MEDIAPIPE_FOURCC('2', 'C', '0', '8'),
|
||||
kTwoComponentHalf16 = MEDIAPIPE_FOURCC('2', 'C', '0', 'h'),
|
||||
@@ -102,7 +101,6 @@ inline OSType CVPixelFormatForGpuBufferFormat(GpuBufferFormat format) {
|
||||
return kCVPixelFormatType_OneComponent32Float;
|
||||
case GpuBufferFormat::kOneComponent8:
|
||||
return kCVPixelFormatType_OneComponent8;
|
||||
case GpuBufferFormat::kOneComponent8Alpha:
|
||||
case GpuBufferFormat::kOneComponent8Red:
|
||||
return -1;
|
||||
case GpuBufferFormat::kTwoComponent8:
|
||||
|
||||
@@ -78,21 +78,17 @@ public class AppTextureFrame implements TextureFrame {
|
||||
* Use {@link waitUntilReleasedWithGpuSync} whenever possible.
|
||||
*/
|
||||
public void waitUntilReleased() throws InterruptedException {
|
||||
GlSyncToken tokenToRelease = null;
|
||||
synchronized (this) {
|
||||
while (inUse && releaseSyncToken == null) {
|
||||
wait();
|
||||
}
|
||||
if (releaseSyncToken != null) {
|
||||
tokenToRelease = releaseSyncToken;
|
||||
releaseSyncToken.waitOnCpu();
|
||||
releaseSyncToken.release();
|
||||
inUse = false;
|
||||
releaseSyncToken = null;
|
||||
}
|
||||
}
|
||||
if (tokenToRelease != null) {
|
||||
tokenToRelease.waitOnCpu();
|
||||
tokenToRelease.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,21 +98,17 @@ public class AppTextureFrame implements TextureFrame {
|
||||
* TextureFrame.
|
||||
*/
|
||||
public void waitUntilReleasedWithGpuSync() throws InterruptedException {
|
||||
GlSyncToken tokenToRelease = null;
|
||||
synchronized (this) {
|
||||
while (inUse && releaseSyncToken == null) {
|
||||
wait();
|
||||
}
|
||||
if (releaseSyncToken != null) {
|
||||
tokenToRelease = releaseSyncToken;
|
||||
releaseSyncToken.waitOnGpu();
|
||||
releaseSyncToken.release();
|
||||
inUse = false;
|
||||
releaseSyncToken = null;
|
||||
}
|
||||
}
|
||||
if (tokenToRelease != null) {
|
||||
tokenToRelease.waitOnGpu();
|
||||
tokenToRelease.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -239,7 +239,7 @@ public final class PacketGetter {
|
||||
|
||||
/**
|
||||
* Assign the native image buffer array in given ByteBuffer array. It assumes given ByteBuffer
|
||||
* array has the same size of image list packet, and assumes the output buffer stores pixels
|
||||
* array has the the same size of image list packet, and assumes the output buffer stores pixels
|
||||
* contiguously. It returns false if this assumption does not hold.
|
||||
*
|
||||
* <p>If deepCopy is true, it assumes the given buffersArray has allocated the required size of
|
||||
|
||||
@@ -57,14 +57,3 @@ py_test(
|
||||
srcs = ["classification_dataset_test.py"],
|
||||
deps = [":classification_dataset"],
|
||||
)
|
||||
|
||||
py_library(
|
||||
name = "cache_files",
|
||||
srcs = ["cache_files.py"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "cache_files_test",
|
||||
srcs = ["cache_files_test.py"],
|
||||
deps = [":cache_files"],
|
||||
)
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
# Copyright 2023 The MediaPipe Authors.
|
||||
#
|
||||
# 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.
|
||||
"""Common TFRecord cache files library."""
|
||||
|
||||
import dataclasses
|
||||
import os
|
||||
import tempfile
|
||||
from typing import Any, Mapping, Sequence
|
||||
|
||||
import tensorflow as tf
|
||||
import yaml
|
||||
|
||||
|
||||
# Suffix of the meta data file name.
|
||||
METADATA_FILE_SUFFIX = '_metadata.yaml'
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class TFRecordCacheFiles:
|
||||
"""TFRecordCacheFiles dataclass to store and load cached TFRecord files.
|
||||
|
||||
Attributes:
|
||||
cache_prefix_filename: The cache prefix filename. This is usually provided
|
||||
as a hash of the original data source to avoid different data sources
|
||||
resulting in the same cache file.
|
||||
cache_dir: The cache directory to save TFRecord and metadata file. When
|
||||
cache_dir is None, a temporary folder will be created and will not be
|
||||
removed automatically after training which makes it can be used later.
|
||||
num_shards: Number of shards for output tfrecord files.
|
||||
"""
|
||||
|
||||
cache_prefix_filename: str = 'cache_prefix'
|
||||
cache_dir: str = dataclasses.field(default_factory=tempfile.mkdtemp)
|
||||
num_shards: int = 1
|
||||
|
||||
def __post_init__(self):
|
||||
if not self.cache_prefix_filename:
|
||||
raise ValueError('cache_prefix_filename cannot be empty.')
|
||||
if self.num_shards <= 0:
|
||||
raise ValueError(
|
||||
f'num_shards must be greater than 0, got {self.num_shards}'
|
||||
)
|
||||
|
||||
@property
|
||||
def cache_prefix(self) -> str:
|
||||
"""The cache prefix including the cache directory and the cache prefix filename."""
|
||||
return os.path.join(self.cache_dir, self.cache_prefix_filename)
|
||||
|
||||
@property
|
||||
def tfrecord_files(self) -> Sequence[str]:
|
||||
"""The TFRecord files."""
|
||||
tfrecord_files = [
|
||||
self.cache_prefix + '-%05d-of-%05d.tfrecord' % (i, self.num_shards)
|
||||
for i in range(self.num_shards)
|
||||
]
|
||||
return tfrecord_files
|
||||
|
||||
@property
|
||||
def metadata_file(self) -> str:
|
||||
"""The metadata file."""
|
||||
return self.cache_prefix + METADATA_FILE_SUFFIX
|
||||
|
||||
def get_writers(self) -> Sequence[tf.io.TFRecordWriter]:
|
||||
"""Gets an array of TFRecordWriter objects.
|
||||
|
||||
Note that these writers should each be closed using .close() when done.
|
||||
|
||||
Returns:
|
||||
Array of TFRecordWriter objects
|
||||
"""
|
||||
if not tf.io.gfile.exists(self.cache_dir):
|
||||
tf.io.gfile.makedirs(self.cache_dir)
|
||||
return [tf.io.TFRecordWriter(path) for path in self.tfrecord_files]
|
||||
|
||||
def save_metadata(self, metadata):
|
||||
"""Writes metadata to file.
|
||||
|
||||
Args:
|
||||
metadata: A dictionary of metadata content to write. Exact format is
|
||||
dependent on the specific dataset, but typically includes a 'size' and
|
||||
'label_names' entry.
|
||||
"""
|
||||
with tf.io.gfile.GFile(self.metadata_file, 'w') as f:
|
||||
yaml.dump(metadata, f)
|
||||
|
||||
def load_metadata(self) -> Mapping[Any, Any]:
|
||||
"""Reads metadata from file.
|
||||
|
||||
Returns:
|
||||
Dictionary object containing metadata
|
||||
"""
|
||||
if not tf.io.gfile.exists(self.metadata_file):
|
||||
return {}
|
||||
with tf.io.gfile.GFile(self.metadata_file, 'r') as f:
|
||||
metadata = yaml.load(f, Loader=yaml.FullLoader)
|
||||
return metadata
|
||||
|
||||
def is_cached(self) -> bool:
|
||||
"""Checks whether this CacheFiles is already cached."""
|
||||
all_cached_files = list(self.tfrecord_files) + [self.metadata_file]
|
||||
return all(tf.io.gfile.exists(f) for f in all_cached_files)
|
||||
@@ -1,77 +0,0 @@
|
||||
# Copyright 2023 The MediaPipe Authors.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import tensorflow as tf
|
||||
|
||||
from mediapipe.model_maker.python.core.data import cache_files
|
||||
|
||||
|
||||
class CacheFilesTest(tf.test.TestCase):
|
||||
|
||||
def test_tfrecord_cache_files(self):
|
||||
cf = cache_files.TFRecordCacheFiles(
|
||||
cache_prefix_filename='tfrecord',
|
||||
cache_dir='/tmp/cache_dir',
|
||||
num_shards=2,
|
||||
)
|
||||
self.assertEqual(cf.cache_prefix, '/tmp/cache_dir/tfrecord')
|
||||
self.assertEqual(
|
||||
cf.metadata_file,
|
||||
'/tmp/cache_dir/tfrecord' + cache_files.METADATA_FILE_SUFFIX,
|
||||
)
|
||||
expected_tfrecord_files = [
|
||||
'/tmp/cache_dir/tfrecord-%05d-of-%05d.tfrecord' % (i, 2)
|
||||
for i in range(2)
|
||||
]
|
||||
self.assertEqual(cf.tfrecord_files, expected_tfrecord_files)
|
||||
|
||||
# Writing TFRecord Files
|
||||
self.assertFalse(cf.is_cached())
|
||||
for tfrecord_file in cf.tfrecord_files:
|
||||
self.assertFalse(tf.io.gfile.exists(tfrecord_file))
|
||||
writers = cf.get_writers()
|
||||
for writer in writers:
|
||||
writer.close()
|
||||
for tfrecord_file in cf.tfrecord_files:
|
||||
self.assertTrue(tf.io.gfile.exists(tfrecord_file))
|
||||
self.assertFalse(cf.is_cached())
|
||||
|
||||
# Writing Metadata Files
|
||||
original_metadata = {'size': 10, 'label_names': ['label1', 'label2']}
|
||||
cf.save_metadata(original_metadata)
|
||||
self.assertTrue(cf.is_cached())
|
||||
metadata = cf.load_metadata()
|
||||
self.assertEqual(metadata, original_metadata)
|
||||
|
||||
def test_recordio_cache_files_error(self):
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, 'cache_prefix_filename cannot be empty'
|
||||
):
|
||||
cache_files.TFRecordCacheFiles(
|
||||
cache_prefix_filename='',
|
||||
cache_dir='/tmp/cache_dir',
|
||||
num_shards=2,
|
||||
)
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, 'num_shards must be greater than 0, got 0'
|
||||
):
|
||||
cache_files.TFRecordCacheFiles(
|
||||
cache_prefix_filename='tfrecord',
|
||||
cache_dir='/tmp/cache_dir',
|
||||
num_shards=0,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
tf.test.main()
|
||||
@@ -13,7 +13,7 @@
|
||||
# limitations under the License.
|
||||
"""Common classification dataset library."""
|
||||
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import List, Tuple
|
||||
|
||||
import tensorflow as tf
|
||||
|
||||
@@ -23,12 +23,8 @@ from mediapipe.model_maker.python.core.data import dataset as ds
|
||||
class ClassificationDataset(ds.Dataset):
|
||||
"""Dataset Loader for classification models."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
dataset: tf.data.Dataset,
|
||||
label_names: List[str],
|
||||
size: Optional[int] = None,
|
||||
):
|
||||
def __init__(self, dataset: tf.data.Dataset, size: int,
|
||||
label_names: List[str]):
|
||||
super().__init__(dataset, size)
|
||||
self._label_names = label_names
|
||||
|
||||
|
||||
@@ -36,14 +36,9 @@ class ClassificationDatasetTest(tf.test.TestCase):
|
||||
value: A value variable stored by the mock dataset class for testing.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
dataset: tf.data.Dataset,
|
||||
label_names: List[str],
|
||||
value: Any,
|
||||
size: int,
|
||||
):
|
||||
super().__init__(dataset=dataset, label_names=label_names, size=size)
|
||||
def __init__(self, dataset: tf.data.Dataset, size: int,
|
||||
label_names: List[str], value: Any):
|
||||
super().__init__(dataset=dataset, size=size, label_names=label_names)
|
||||
self.value = value
|
||||
|
||||
def split(self, fraction: float) -> Tuple[_DatasetT, _DatasetT]:
|
||||
@@ -57,8 +52,7 @@ class ClassificationDatasetTest(tf.test.TestCase):
|
||||
# Create data loader from sample data.
|
||||
ds = tf.data.Dataset.from_tensor_slices([[0, 1], [1, 1], [0, 0], [1, 0]])
|
||||
data = MagicClassificationDataset(
|
||||
dataset=ds, label_names=label_names, value=magic_value, size=len(ds)
|
||||
)
|
||||
dataset=ds, size=len(ds), label_names=label_names, value=magic_value)
|
||||
|
||||
# Train/Test data split.
|
||||
fraction = .25
|
||||
|
||||
@@ -56,14 +56,15 @@ class Dataset(object):
|
||||
def size(self) -> Optional[int]:
|
||||
"""Returns the size of the dataset.
|
||||
|
||||
Same functionality as calling __len__. See the __len__ method definition for
|
||||
more information.
|
||||
|
||||
Raises:
|
||||
TypeError if self._size is not set and the cardinality of self._dataset
|
||||
is INFINITE_CARDINALITY or UNKNOWN_CARDINALITY.
|
||||
Note that this function may return None becuase the exact size of the
|
||||
dataset isn't a necessary parameter to create an instance of this class,
|
||||
and tf.data.Dataset donesn't support a function to get the length directly
|
||||
since it's lazy-loaded and may be infinite.
|
||||
In most cases, however, when an instance of this class is created by helper
|
||||
functions like 'from_folder', the size of the dataset will be preprocessed,
|
||||
and this function can return an int representing the size of the dataset.
|
||||
"""
|
||||
return self.__len__()
|
||||
return self._size
|
||||
|
||||
def gen_tf_dataset(
|
||||
self,
|
||||
@@ -115,22 +116,8 @@ class Dataset(object):
|
||||
# here.
|
||||
return dataset
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Returns the number of element of the dataset.
|
||||
|
||||
If size is not set, this method will fallback to using the __len__ method
|
||||
of the tf.data.Dataset in self._dataset. Calling __len__ on a
|
||||
tf.data.Dataset instance may throw a TypeError because the dataset may
|
||||
be lazy-loaded with an unknown size or have infinite size.
|
||||
|
||||
In most cases, however, when an instance of this class is created by helper
|
||||
functions like 'from_folder', the size of the dataset will be preprocessed,
|
||||
and the _size instance variable will be already set.
|
||||
|
||||
Raises:
|
||||
TypeError if self._size is not set and the cardinality of self._dataset
|
||||
is INFINITE_CARDINALITY or UNKNOWN_CARDINALITY.
|
||||
"""
|
||||
def __len__(self):
|
||||
"""Returns the number of element of the dataset."""
|
||||
if self._size is not None:
|
||||
return self._size
|
||||
else:
|
||||
@@ -165,25 +152,15 @@ class Dataset(object):
|
||||
|
||||
Returns:
|
||||
The splitted two sub datasets.
|
||||
|
||||
Raises:
|
||||
ValueError: if the provided fraction is not between 0 and 1.
|
||||
ValueError: if this dataset does not have a set size.
|
||||
"""
|
||||
if not (fraction > 0 and fraction < 1):
|
||||
raise ValueError(f'Fraction must be between 0 and 1. Got:{fraction}')
|
||||
if not self._size:
|
||||
raise ValueError(
|
||||
'Dataset size unknown. Cannot split the dataset when '
|
||||
'the size is unknown.'
|
||||
)
|
||||
assert (fraction > 0 and fraction < 1)
|
||||
|
||||
dataset = self._dataset
|
||||
|
||||
train_size = int(self._size * fraction)
|
||||
trainset = self.__class__(dataset.take(train_size), *args, size=train_size)
|
||||
trainset = self.__class__(dataset.take(train_size), train_size, *args)
|
||||
|
||||
test_size = self._size - train_size
|
||||
testset = self.__class__(dataset.skip(train_size), *args, size=test_size)
|
||||
testset = self.__class__(dataset.skip(train_size), test_size, *args)
|
||||
|
||||
return trainset, testset
|
||||
|
||||
@@ -46,17 +46,13 @@ class BertModelSpec:
|
||||
"""
|
||||
|
||||
downloaded_files: file_util.DownloadedFiles
|
||||
hparams: hp.BaseHParams = dataclasses.field(
|
||||
default_factory=lambda: hp.BaseHParams(
|
||||
epochs=3,
|
||||
batch_size=32,
|
||||
learning_rate=3e-5,
|
||||
distribution_strategy='mirrored',
|
||||
)
|
||||
)
|
||||
model_options: bert_model_options.BertModelOptions = dataclasses.field(
|
||||
default_factory=bert_model_options.BertModelOptions
|
||||
)
|
||||
hparams: hp.BaseHParams = hp.BaseHParams(
|
||||
epochs=3,
|
||||
batch_size=32,
|
||||
learning_rate=3e-5,
|
||||
distribution_strategy='mirrored')
|
||||
model_options: bert_model_options.BertModelOptions = (
|
||||
bert_model_options.BertModelOptions())
|
||||
do_lower_case: bool = True
|
||||
tflite_input_name: Dict[str, str] = dataclasses.field(
|
||||
default_factory=lambda: _DEFAULT_TFLITE_INPUT_NAME)
|
||||
|
||||
@@ -85,5 +85,4 @@ class Dataset(classification_dataset.ClassificationDataset):
|
||||
text_label_ds = tf.data.Dataset.zip((text_ds, label_index_ds))
|
||||
|
||||
return Dataset(
|
||||
dataset=text_label_ds, label_names=label_names, size=len(texts)
|
||||
)
|
||||
dataset=text_label_ds, size=len(texts), label_names=label_names)
|
||||
|
||||
@@ -53,7 +53,7 @@ class DatasetTest(tf.test.TestCase):
|
||||
|
||||
def test_split(self):
|
||||
ds = tf.data.Dataset.from_tensor_slices(['good', 'bad', 'neutral', 'odd'])
|
||||
data = dataset.Dataset(ds, ['pos', 'neg'], 4)
|
||||
data = dataset.Dataset(ds, 4, ['pos', 'neg'])
|
||||
train_data, test_data = data.split(0.5)
|
||||
expected_train_data = [b'good', b'bad']
|
||||
expected_test_data = [b'neutral', b'odd']
|
||||
|
||||
@@ -47,14 +47,11 @@ class AverageWordEmbeddingClassifierSpec:
|
||||
"""
|
||||
|
||||
# `learning_rate` is unused for the average word embedding model
|
||||
hparams: hp.AverageWordEmbeddingHParams = dataclasses.field(
|
||||
default_factory=lambda: hp.AverageWordEmbeddingHParams(
|
||||
epochs=10, batch_size=32, learning_rate=0
|
||||
)
|
||||
)
|
||||
model_options: mo.AverageWordEmbeddingModelOptions = dataclasses.field(
|
||||
default_factory=mo.AverageWordEmbeddingModelOptions
|
||||
hparams: hp.AverageWordEmbeddingHParams = hp.AverageWordEmbeddingHParams(
|
||||
epochs=10, batch_size=32, learning_rate=0
|
||||
)
|
||||
model_options: mo.AverageWordEmbeddingModelOptions = (
|
||||
mo.AverageWordEmbeddingModelOptions())
|
||||
name: str = 'AverageWordEmbedding'
|
||||
|
||||
average_word_embedding_classifier_spec = functools.partial(
|
||||
@@ -69,7 +66,7 @@ class BertClassifierSpec(bert_model_spec.BertModelSpec):
|
||||
inherited from the BertModelSpec.
|
||||
"""
|
||||
|
||||
hparams: hp.BertHParams = dataclasses.field(default_factory=hp.BertHParams)
|
||||
hparams: hp.BertHParams = hp.BertHParams()
|
||||
|
||||
|
||||
mobilebert_classifier_spec = functools.partial(
|
||||
|
||||
@@ -115,7 +115,5 @@ class Dataset(classification_dataset.ClassificationDataset):
|
||||
', '.join(label_names),
|
||||
)
|
||||
return Dataset(
|
||||
dataset=image_label_ds,
|
||||
label_names=label_names,
|
||||
size=all_image_size,
|
||||
dataset=image_label_ds, size=all_image_size, label_names=label_names
|
||||
)
|
||||
|
||||
@@ -249,6 +249,5 @@ class Dataset(classification_dataset.ClassificationDataset):
|
||||
len(valid_hand_data), len(label_names), ','.join(label_names)))
|
||||
return Dataset(
|
||||
dataset=hand_embedding_label_ds,
|
||||
label_names=label_names,
|
||||
size=len(valid_hand_data),
|
||||
)
|
||||
label_names=label_names)
|
||||
|
||||
@@ -15,12 +15,28 @@
|
||||
|
||||
import os
|
||||
import random
|
||||
|
||||
from typing import List, Optional
|
||||
import tensorflow as tf
|
||||
import tensorflow_datasets as tfds
|
||||
|
||||
from mediapipe.model_maker.python.core.data import classification_dataset
|
||||
from mediapipe.model_maker.python.vision.core import image_utils
|
||||
|
||||
|
||||
def _create_data(
|
||||
name: str, data: tf.data.Dataset, info: tfds.core.DatasetInfo,
|
||||
label_names: List[str]
|
||||
) -> Optional[classification_dataset.ClassificationDataset]:
|
||||
"""Creates a Dataset object from tfds data."""
|
||||
if name not in data:
|
||||
return None
|
||||
data = data[name]
|
||||
data = data.map(lambda a: (a['image'], a['label']))
|
||||
size = info.splits[name].num_examples
|
||||
return Dataset(data, size, label_names)
|
||||
|
||||
|
||||
class Dataset(classification_dataset.ClassificationDataset):
|
||||
"""Dataset library for image classifier."""
|
||||
|
||||
@@ -83,5 +99,4 @@ class Dataset(classification_dataset.ClassificationDataset):
|
||||
'Load image with size: %d, num_label: %d, labels: %s.', all_image_size,
|
||||
all_label_size, ', '.join(label_names))
|
||||
return Dataset(
|
||||
dataset=image_label_ds, label_names=label_names, size=all_image_size
|
||||
)
|
||||
dataset=image_label_ds, size=all_image_size, label_names=label_names)
|
||||
|
||||
@@ -41,7 +41,7 @@ class DatasetTest(tf.test.TestCase):
|
||||
|
||||
def test_split(self):
|
||||
ds = tf.data.Dataset.from_tensor_slices([[0, 1], [1, 1], [0, 0], [1, 0]])
|
||||
data = dataset.Dataset(dataset=ds, label_names=['pos', 'neg'], size=4)
|
||||
data = dataset.Dataset(dataset=ds, size=4, label_names=['pos', 'neg'])
|
||||
train_data, test_data = data.split(fraction=0.5)
|
||||
|
||||
self.assertLen(train_data, 2)
|
||||
|
||||
@@ -52,9 +52,8 @@ class ImageClassifierTest(tf.test.TestCase, parameterized.TestCase):
|
||||
ds = tf.data.Dataset.from_generator(
|
||||
self._gen, (tf.uint8, tf.int64), (tf.TensorShape(
|
||||
[self.IMAGE_SIZE, self.IMAGE_SIZE, 3]), tf.TensorShape([])))
|
||||
data = image_classifier.Dataset(
|
||||
ds, ['cyan', 'magenta', 'yellow'], self.IMAGES_PER_CLASS * 3
|
||||
)
|
||||
data = image_classifier.Dataset(ds, self.IMAGES_PER_CLASS * 3,
|
||||
['cyan', 'magenta', 'yellow'])
|
||||
return data
|
||||
|
||||
def setUp(self):
|
||||
|
||||
@@ -54,7 +54,6 @@ py_library(
|
||||
srcs = ["dataset.py"],
|
||||
deps = [
|
||||
":dataset_util",
|
||||
"//mediapipe/model_maker/python/core/data:cache_files",
|
||||
"//mediapipe/model_maker/python/core/data:classification_dataset",
|
||||
],
|
||||
)
|
||||
@@ -74,7 +73,6 @@ py_test(
|
||||
py_library(
|
||||
name = "dataset_util",
|
||||
srcs = ["dataset_util.py"],
|
||||
deps = ["//mediapipe/model_maker/python/core/data:cache_files"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
from typing import Optional
|
||||
|
||||
import tensorflow as tf
|
||||
import yaml
|
||||
|
||||
from mediapipe.model_maker.python.core.data import cache_files
|
||||
from mediapipe.model_maker.python.core.data import classification_dataset
|
||||
from mediapipe.model_maker.python.vision.object_detector import dataset_util
|
||||
from official.vision.dataloaders import tf_example_decoder
|
||||
@@ -76,16 +76,14 @@ class Dataset(classification_dataset.ClassificationDataset):
|
||||
ValueError: If the label_name for id 0 is set to something other than
|
||||
the 'background' class.
|
||||
"""
|
||||
tfrecord_cache_files = dataset_util.get_cache_files_coco(
|
||||
data_dir, cache_dir
|
||||
)
|
||||
if not tfrecord_cache_files.is_cached():
|
||||
cache_files = dataset_util.get_cache_files_coco(data_dir, cache_dir)
|
||||
if not dataset_util.is_cached(cache_files):
|
||||
label_map = dataset_util.get_label_map_coco(data_dir)
|
||||
cache_writer = dataset_util.COCOCacheFilesWriter(
|
||||
label_map=label_map, max_num_images=max_num_images
|
||||
)
|
||||
cache_writer.write_files(tfrecord_cache_files, data_dir)
|
||||
return cls.from_cache(tfrecord_cache_files)
|
||||
cache_writer.write_files(cache_files, data_dir)
|
||||
return cls.from_cache(cache_files.cache_prefix)
|
||||
|
||||
@classmethod
|
||||
def from_pascal_voc_folder(
|
||||
@@ -136,48 +134,47 @@ class Dataset(classification_dataset.ClassificationDataset):
|
||||
Raises:
|
||||
ValueError: if the input data directory is empty.
|
||||
"""
|
||||
tfrecord_cache_files = dataset_util.get_cache_files_pascal_voc(
|
||||
data_dir, cache_dir
|
||||
)
|
||||
if not tfrecord_cache_files.is_cached():
|
||||
cache_files = dataset_util.get_cache_files_pascal_voc(data_dir, cache_dir)
|
||||
if not dataset_util.is_cached(cache_files):
|
||||
label_map = dataset_util.get_label_map_pascal_voc(data_dir)
|
||||
cache_writer = dataset_util.PascalVocCacheFilesWriter(
|
||||
label_map=label_map, max_num_images=max_num_images
|
||||
)
|
||||
cache_writer.write_files(tfrecord_cache_files, data_dir)
|
||||
cache_writer.write_files(cache_files, data_dir)
|
||||
|
||||
return cls.from_cache(tfrecord_cache_files)
|
||||
return cls.from_cache(cache_files.cache_prefix)
|
||||
|
||||
@classmethod
|
||||
def from_cache(
|
||||
cls, tfrecord_cache_files: cache_files.TFRecordCacheFiles
|
||||
) -> 'Dataset':
|
||||
def from_cache(cls, cache_prefix: str) -> 'Dataset':
|
||||
"""Loads the TFRecord data from cache.
|
||||
|
||||
Args:
|
||||
tfrecord_cache_files: The TFRecordCacheFiles object containing the already
|
||||
cached TFRecord and metadata files.
|
||||
cache_prefix: The cache prefix including the cache directory and the cache
|
||||
prefix filename, e.g: '/tmp/cache/train'.
|
||||
|
||||
Returns:
|
||||
ObjectDetectorDataset object.
|
||||
|
||||
Raises:
|
||||
ValueError if tfrecord_cache_files are not already cached.
|
||||
"""
|
||||
if not tfrecord_cache_files.is_cached():
|
||||
raise ValueError(
|
||||
'Cache files must be already cached to use the from_cache method.'
|
||||
)
|
||||
# Get TFRecord Files
|
||||
tfrecord_file_pattern = cache_prefix + '*.tfrecord'
|
||||
matched_files = tf.io.gfile.glob(tfrecord_file_pattern)
|
||||
if not matched_files:
|
||||
raise ValueError('TFRecord files are empty.')
|
||||
|
||||
metadata = tfrecord_cache_files.load_metadata()
|
||||
# Load meta_data.
|
||||
meta_data_file = cache_prefix + dataset_util.META_DATA_FILE_SUFFIX
|
||||
if not tf.io.gfile.exists(meta_data_file):
|
||||
raise ValueError("Metadata file %s doesn't exist." % meta_data_file)
|
||||
with tf.io.gfile.GFile(meta_data_file, 'r') as f:
|
||||
meta_data = yaml.load(f, Loader=yaml.FullLoader)
|
||||
|
||||
dataset = tf.data.TFRecordDataset(tfrecord_cache_files.tfrecord_files)
|
||||
dataset = tf.data.TFRecordDataset(matched_files)
|
||||
decoder = tf_example_decoder.TfExampleDecoder(regenerate_source_id=False)
|
||||
dataset = dataset.map(decoder.decode, num_parallel_calls=tf.data.AUTOTUNE)
|
||||
|
||||
label_map = metadata['label_map']
|
||||
label_map = meta_data['label_map']
|
||||
label_names = [label_map[k] for k in sorted(label_map.keys())]
|
||||
|
||||
return Dataset(
|
||||
dataset=dataset, label_names=label_names, size=metadata['size']
|
||||
dataset=dataset, size=meta_data['size'], label_names=label_names
|
||||
)
|
||||
|
||||
@@ -15,20 +15,25 @@
|
||||
|
||||
import abc
|
||||
import collections
|
||||
import dataclasses
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import tempfile
|
||||
from typing import Any, Dict, List, Mapping, Optional
|
||||
from typing import Any, Dict, List, Mapping, Optional, Sequence
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import tensorflow as tf
|
||||
import yaml
|
||||
|
||||
from mediapipe.model_maker.python.core.data import cache_files
|
||||
from official.vision.data import tfrecord_lib
|
||||
|
||||
|
||||
# Suffix of the meta data file name.
|
||||
META_DATA_FILE_SUFFIX = '_meta_data.yaml'
|
||||
|
||||
|
||||
def _xml_get(node: ET.Element, name: str) -> ET.Element:
|
||||
"""Gets a named child from an XML Element node.
|
||||
|
||||
@@ -66,9 +71,18 @@ def _get_dir_basename(data_dir: str) -> str:
|
||||
return os.path.basename(os.path.abspath(data_dir))
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class CacheFiles:
|
||||
"""Cache files for object detection."""
|
||||
|
||||
cache_prefix: str
|
||||
tfrecord_files: Sequence[str]
|
||||
meta_data_file: str
|
||||
|
||||
|
||||
def _get_cache_files(
|
||||
cache_dir: Optional[str], cache_prefix_filename: str, num_shards: int = 10
|
||||
) -> cache_files.TFRecordCacheFiles:
|
||||
) -> CacheFiles:
|
||||
"""Creates an object of CacheFiles class.
|
||||
|
||||
Args:
|
||||
@@ -82,16 +96,28 @@ def _get_cache_files(
|
||||
An object of CacheFiles class.
|
||||
"""
|
||||
cache_dir = _get_cache_dir_or_create(cache_dir)
|
||||
return cache_files.TFRecordCacheFiles(
|
||||
cache_prefix_filename=cache_prefix_filename,
|
||||
cache_dir=cache_dir,
|
||||
num_shards=num_shards,
|
||||
# The cache prefix including the cache directory and the cache prefix
|
||||
# filename, e.g: '/tmp/cache/train'.
|
||||
cache_prefix = os.path.join(cache_dir, cache_prefix_filename)
|
||||
tf.compat.v1.logging.info(
|
||||
'Cache will be stored in %s with prefix filename %s. Cache_prefix is %s'
|
||||
% (cache_dir, cache_prefix_filename, cache_prefix)
|
||||
)
|
||||
|
||||
# Cached files including the TFRecord files and the meta data file.
|
||||
tfrecord_files = [
|
||||
cache_prefix + '-%05d-of-%05d.tfrecord' % (i, num_shards)
|
||||
for i in range(num_shards)
|
||||
]
|
||||
meta_data_file = cache_prefix + META_DATA_FILE_SUFFIX
|
||||
return CacheFiles(
|
||||
cache_prefix=cache_prefix,
|
||||
tfrecord_files=tuple(tfrecord_files),
|
||||
meta_data_file=meta_data_file,
|
||||
)
|
||||
|
||||
|
||||
def get_cache_files_coco(
|
||||
data_dir: str, cache_dir: str
|
||||
) -> cache_files.TFRecordCacheFiles:
|
||||
def get_cache_files_coco(data_dir: str, cache_dir: str) -> CacheFiles:
|
||||
"""Creates an object of CacheFiles class using a COCO formatted dataset.
|
||||
|
||||
Args:
|
||||
@@ -126,9 +152,7 @@ def get_cache_files_coco(
|
||||
return _get_cache_files(cache_dir, cache_prefix_filename, num_shards)
|
||||
|
||||
|
||||
def get_cache_files_pascal_voc(
|
||||
data_dir: str, cache_dir: str
|
||||
) -> cache_files.TFRecordCacheFiles:
|
||||
def get_cache_files_pascal_voc(data_dir: str, cache_dir: str) -> CacheFiles:
|
||||
"""Gets an object of CacheFiles using a PASCAL VOC formatted dataset.
|
||||
|
||||
Args:
|
||||
@@ -157,6 +181,14 @@ def get_cache_files_pascal_voc(
|
||||
return _get_cache_files(cache_dir, cache_prefix_filename, num_shards)
|
||||
|
||||
|
||||
def is_cached(cache_files: CacheFiles) -> bool:
|
||||
"""Checks whether cache files are already cached."""
|
||||
all_cached_files = list(cache_files.tfrecord_files) + [
|
||||
cache_files.meta_data_file
|
||||
]
|
||||
return all(tf.io.gfile.exists(path) for path in all_cached_files)
|
||||
|
||||
|
||||
class CacheFilesWriter(abc.ABC):
|
||||
"""CacheFilesWriter class to write the cached files."""
|
||||
|
||||
@@ -176,22 +208,19 @@ class CacheFilesWriter(abc.ABC):
|
||||
self.label_map = label_map
|
||||
self.max_num_images = max_num_images
|
||||
|
||||
def write_files(
|
||||
self,
|
||||
tfrecord_cache_files: cache_files.TFRecordCacheFiles,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Writes TFRecord and metadata files.
|
||||
def write_files(self, cache_files: CacheFiles, *args, **kwargs) -> None:
|
||||
"""Writes TFRecord and meta_data files.
|
||||
|
||||
Args:
|
||||
tfrecord_cache_files: TFRecordCacheFiles object including a list of
|
||||
TFRecord files and the meta data yaml file to save the metadata
|
||||
including data size and label_map.
|
||||
cache_files: CacheFiles object including a list of TFRecord files and the
|
||||
meta data yaml file to save the meta_data including data size and
|
||||
label_map.
|
||||
*args: Non-keyword of parameters used in the `_get_example` method.
|
||||
**kwargs: Keyword parameters used in the `_get_example` method.
|
||||
"""
|
||||
writers = tfrecord_cache_files.get_writers()
|
||||
writers = [
|
||||
tf.io.TFRecordWriter(path) for path in cache_files.tfrecord_files
|
||||
]
|
||||
|
||||
# Writes tf.Example into TFRecord files.
|
||||
size = 0
|
||||
@@ -206,9 +235,10 @@ class CacheFilesWriter(abc.ABC):
|
||||
for writer in writers:
|
||||
writer.close()
|
||||
|
||||
# Writes metadata into metadata_file.
|
||||
metadata = {'size': size, 'label_map': self.label_map}
|
||||
tfrecord_cache_files.save_metadata(metadata)
|
||||
# Writes meta_data into meta_data_file.
|
||||
meta_data = {'size': size, 'label_map': self.label_map}
|
||||
with tf.io.gfile.GFile(cache_files.meta_data_file, 'w') as f:
|
||||
yaml.dump(meta_data, f)
|
||||
|
||||
@abc.abstractmethod
|
||||
def _get_example(self, *args, **kwargs):
|
||||
|
||||
@@ -19,6 +19,7 @@ import shutil
|
||||
from unittest import mock as unittest_mock
|
||||
|
||||
import tensorflow as tf
|
||||
import yaml
|
||||
|
||||
from mediapipe.model_maker.python.vision.core import test_utils
|
||||
from mediapipe.model_maker.python.vision.object_detector import dataset_util
|
||||
@@ -29,10 +30,13 @@ class DatasetUtilTest(tf.test.TestCase):
|
||||
|
||||
def _assert_cache_files_equal(self, cf1, cf2):
|
||||
self.assertEqual(cf1.cache_prefix, cf2.cache_prefix)
|
||||
self.assertEqual(cf1.num_shards, cf2.num_shards)
|
||||
self.assertCountEqual(cf1.tfrecord_files, cf2.tfrecord_files)
|
||||
self.assertEqual(cf1.meta_data_file, cf2.meta_data_file)
|
||||
|
||||
def _assert_cache_files_not_equal(self, cf1, cf2):
|
||||
self.assertNotEqual(cf1.cache_prefix, cf2.cache_prefix)
|
||||
self.assertNotEqual(cf1.tfrecord_files, cf2.tfrecord_files)
|
||||
self.assertNotEqual(cf1.meta_data_file, cf2.meta_data_file)
|
||||
|
||||
def _get_cache_files_and_assert_neq_fn(self, cache_files_fn):
|
||||
def get_cache_files_and_assert_neq(cf, data_dir, cache_dir):
|
||||
@@ -53,7 +57,7 @@ class DatasetUtilTest(tf.test.TestCase):
|
||||
self.assertEqual(
|
||||
cache_files.tfrecord_files[0], '/tmp/train-00000-of-00001.tfrecord'
|
||||
)
|
||||
self.assertEqual(cache_files.metadata_file, '/tmp/train_metadata.yaml')
|
||||
self.assertEqual(cache_files.meta_data_file, '/tmp/train_meta_data.yaml')
|
||||
|
||||
def test_matching_get_cache_files_coco(self):
|
||||
cache_dir = self.create_tempdir()
|
||||
@@ -114,7 +118,7 @@ class DatasetUtilTest(tf.test.TestCase):
|
||||
self.assertEqual(
|
||||
cache_files.tfrecord_files[0], '/tmp/train-00000-of-00001.tfrecord'
|
||||
)
|
||||
self.assertEqual(cache_files.metadata_file, '/tmp/train_metadata.yaml')
|
||||
self.assertEqual(cache_files.meta_data_file, '/tmp/train_meta_data.yaml')
|
||||
|
||||
def test_matching_get_cache_files_pascal_voc(self):
|
||||
cache_dir = self.create_tempdir()
|
||||
@@ -169,13 +173,13 @@ class DatasetUtilTest(tf.test.TestCase):
|
||||
cache_files = dataset_util.get_cache_files_coco(
|
||||
tasks_test_utils.get_test_data_path('coco_data'), cache_dir=tempdir
|
||||
)
|
||||
self.assertFalse(cache_files.is_cached())
|
||||
self.assertFalse(dataset_util.is_cached(cache_files))
|
||||
with open(cache_files.tfrecord_files[0], 'w') as f:
|
||||
f.write('test')
|
||||
self.assertFalse(cache_files.is_cached())
|
||||
with open(cache_files.metadata_file, 'w') as f:
|
||||
self.assertFalse(dataset_util.is_cached(cache_files))
|
||||
with open(cache_files.meta_data_file, 'w') as f:
|
||||
f.write('test')
|
||||
self.assertTrue(cache_files.is_cached())
|
||||
self.assertTrue(dataset_util.is_cached(cache_files))
|
||||
|
||||
def test_get_label_map_coco(self):
|
||||
coco_dir = tasks_test_utils.get_test_data_path('coco_data')
|
||||
@@ -199,11 +203,13 @@ class DatasetUtilTest(tf.test.TestCase):
|
||||
self.assertTrue(os.path.isfile(cache_files.tfrecord_files[0]))
|
||||
self.assertGreater(os.path.getsize(cache_files.tfrecord_files[0]), 0)
|
||||
|
||||
# Checks the metadata file
|
||||
self.assertTrue(os.path.isfile(cache_files.metadata_file))
|
||||
self.assertGreater(os.path.getsize(cache_files.metadata_file), 0)
|
||||
metadata_dict = cache_files.load_metadata()
|
||||
self.assertEqual(metadata_dict['size'], expected_size)
|
||||
# Checks the meta_data file
|
||||
self.assertTrue(os.path.isfile(cache_files.meta_data_file))
|
||||
self.assertGreater(os.path.getsize(cache_files.meta_data_file), 0)
|
||||
with tf.io.gfile.GFile(cache_files.meta_data_file, 'r') as f:
|
||||
meta_data_dict = yaml.load(f, Loader=yaml.FullLoader)
|
||||
# Size is 3 because some examples are skipped for having poor bboxes
|
||||
self.assertEqual(meta_data_dict['size'], expected_size)
|
||||
|
||||
def test_coco_cache_files_writer(self):
|
||||
tempdir = self.create_tempdir()
|
||||
|
||||
+29
-55
@@ -111,7 +111,6 @@ class TensorsToImageCalculator : public Node {
|
||||
private:
|
||||
TensorsToImageCalculatorOptions options_;
|
||||
absl::Status CpuProcess(CalculatorContext* cc);
|
||||
int tensor_position_;
|
||||
|
||||
#if !MEDIAPIPE_DISABLE_GPU
|
||||
#if MEDIAPIPE_METAL_ENABLED
|
||||
@@ -167,7 +166,6 @@ absl::Status TensorsToImageCalculator::Open(CalculatorContext* cc) {
|
||||
<< "Must specify either `input_tensor_float_range` or "
|
||||
"`input_tensor_uint_range` in the calculator options";
|
||||
}
|
||||
tensor_position_ = options_.tensor_position();
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
@@ -204,23 +202,17 @@ absl::Status TensorsToImageCalculator::CpuProcess(CalculatorContext* cc) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
const auto& input_tensors = kInputTensors(cc).Get();
|
||||
RET_CHECK_GT(input_tensors.size(), tensor_position_)
|
||||
<< "Expect input tensor at position " << tensor_position_
|
||||
<< ", but have tensors of size " << input_tensors.size();
|
||||
RET_CHECK_EQ(input_tensors.size(), 1)
|
||||
<< "Expect 1 input tensor, but have " << input_tensors.size();
|
||||
|
||||
const auto& input_tensor = input_tensors[tensor_position_];
|
||||
const auto& input_tensor = input_tensors[0];
|
||||
const int tensor_in_height = input_tensor.shape().dims[1];
|
||||
const int tensor_in_width = input_tensor.shape().dims[2];
|
||||
const int tensor_in_channels = input_tensor.shape().dims[3];
|
||||
RET_CHECK(tensor_in_channels == 3 || tensor_in_channels == 1);
|
||||
RET_CHECK_EQ(tensor_in_channels, 3);
|
||||
|
||||
auto format = mediapipe::ImageFormat::SRGB;
|
||||
if (tensor_in_channels == 1) {
|
||||
format = mediapipe::ImageFormat::GRAY8;
|
||||
}
|
||||
|
||||
auto output_frame =
|
||||
std::make_shared<ImageFrame>(format, tensor_in_width, tensor_in_height);
|
||||
auto output_frame = std::make_shared<ImageFrame>(
|
||||
mediapipe::ImageFormat::SRGB, tensor_in_width, tensor_in_height);
|
||||
cv::Mat output_matview = mediapipe::formats::MatView(output_frame.get());
|
||||
|
||||
constexpr float kOutputImageRangeMin = 0.0f;
|
||||
@@ -235,9 +227,8 @@ absl::Status TensorsToImageCalculator::CpuProcess(CalculatorContext* cc) {
|
||||
GetValueRangeTransformation(
|
||||
input_range.min(), input_range.max(),
|
||||
kOutputImageRangeMin, kOutputImageRangeMax));
|
||||
tensor_matview.convertTo(output_matview,
|
||||
CV_MAKETYPE(CV_8U, tensor_in_channels),
|
||||
transform.scale, transform.offset);
|
||||
tensor_matview.convertTo(output_matview, CV_8UC3, transform.scale,
|
||||
transform.offset);
|
||||
} else if (input_tensor.element_type() == Tensor::ElementType::kUInt8) {
|
||||
cv::Mat tensor_matview(
|
||||
cv::Size(tensor_in_width, tensor_in_height),
|
||||
@@ -248,9 +239,8 @@ absl::Status TensorsToImageCalculator::CpuProcess(CalculatorContext* cc) {
|
||||
GetValueRangeTransformation(
|
||||
input_range.min(), input_range.max(),
|
||||
kOutputImageRangeMin, kOutputImageRangeMax));
|
||||
tensor_matview.convertTo(output_matview,
|
||||
CV_MAKETYPE(CV_8U, tensor_in_channels),
|
||||
transform.scale, transform.offset);
|
||||
tensor_matview.convertTo(output_matview, CV_8UC3, transform.scale,
|
||||
transform.offset);
|
||||
} else {
|
||||
return absl::InvalidArgumentError(
|
||||
absl::Substitute("Type of tensor must be kFloat32 or kUInt8, got: $0",
|
||||
@@ -274,14 +264,10 @@ absl::Status TensorsToImageCalculator::MetalProcess(CalculatorContext* cc) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
const auto& input_tensors = kInputTensors(cc).Get();
|
||||
RET_CHECK_GT(input_tensors.size(), tensor_position_)
|
||||
<< "Expect input tensor at position " << tensor_position_
|
||||
<< ", but have tensors of size " << input_tensors.size();
|
||||
const int tensor_width = input_tensors[tensor_position_].shape().dims[2];
|
||||
const int tensor_height = input_tensors[tensor_position_].shape().dims[1];
|
||||
const int tensor_channels = input_tensors[tensor_position_].shape().dims[3];
|
||||
// TODO: Add 1 channel support.
|
||||
RET_CHECK(tensor_channels == 3);
|
||||
RET_CHECK_EQ(input_tensors.size(), 1)
|
||||
<< "Expect 1 input tensor, but have " << input_tensors.size();
|
||||
const int tensor_width = input_tensors[0].shape().dims[2];
|
||||
const int tensor_height = input_tensors[0].shape().dims[1];
|
||||
|
||||
// TODO: Fix unused variable
|
||||
[[maybe_unused]] id<MTLDevice> device = gpu_helper_.mtlDevice;
|
||||
@@ -291,8 +277,8 @@ absl::Status TensorsToImageCalculator::MetalProcess(CalculatorContext* cc) {
|
||||
[command_buffer computeCommandEncoder];
|
||||
[compute_encoder setComputePipelineState:to_buffer_program_];
|
||||
|
||||
auto input_view = mediapipe::MtlBufferView::GetReadView(
|
||||
input_tensors[tensor_position_], command_buffer);
|
||||
auto input_view =
|
||||
mediapipe::MtlBufferView::GetReadView(input_tensors[0], command_buffer);
|
||||
[compute_encoder setBuffer:input_view.buffer() offset:0 atIndex:0];
|
||||
|
||||
mediapipe::GpuBuffer output =
|
||||
@@ -369,7 +355,7 @@ absl::Status TensorsToImageCalculator::GlSetup(CalculatorContext* cc) {
|
||||
absl::StrCat(tflite::gpu::gl::GetShaderHeader(workgroup_size_), R"(
|
||||
precision highp float;
|
||||
layout(rgba8, binding = 0) writeonly uniform highp image2D output_texture;
|
||||
uniform ivec3 out_size;
|
||||
uniform ivec2 out_size;
|
||||
)");
|
||||
|
||||
const std::string shader_body = R"(
|
||||
@@ -380,11 +366,10 @@ absl::Status TensorsToImageCalculator::GlSetup(CalculatorContext* cc) {
|
||||
void main() {
|
||||
int out_width = out_size.x;
|
||||
int out_height = out_size.y;
|
||||
int out_channels = out_size.z;
|
||||
|
||||
ivec2 gid = ivec2(gl_GlobalInvocationID.xy);
|
||||
if (gid.x >= out_width || gid.y >= out_height) { return; }
|
||||
int linear_index = out_channels * (gid.y * out_width + gid.x);
|
||||
int linear_index = 3 * (gid.y * out_width + gid.x);
|
||||
|
||||
#ifdef FLIP_Y_COORD
|
||||
int y_coord = out_height - gid.y - 1;
|
||||
@@ -392,14 +377,8 @@ absl::Status TensorsToImageCalculator::GlSetup(CalculatorContext* cc) {
|
||||
int y_coord = gid.y;
|
||||
#endif // defined(FLIP_Y_COORD)
|
||||
|
||||
vec4 out_value;
|
||||
ivec2 out_coordinate = ivec2(gid.x, y_coord);
|
||||
if (out_channels == 3) {
|
||||
out_value = vec4(input_data.elements[linear_index], input_data.elements[linear_index + 1], input_data.elements[linear_index + 2], 1.0);
|
||||
} else {
|
||||
float in_value = input_data.elements[linear_index];
|
||||
out_value = vec4(in_value, in_value, in_value, 1.0);
|
||||
}
|
||||
vec4 out_value = vec4(input_data.elements[linear_index], input_data.elements[linear_index + 1], input_data.elements[linear_index + 2], 1.0);
|
||||
imageStore(output_texture, out_coordinate, out_value);
|
||||
})";
|
||||
|
||||
@@ -459,15 +438,10 @@ absl::Status TensorsToImageCalculator::GlProcess(CalculatorContext* cc) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
const auto& input_tensors = kInputTensors(cc).Get();
|
||||
RET_CHECK_GT(input_tensors.size(), tensor_position_)
|
||||
<< "Expect input tensor at position " << tensor_position_
|
||||
<< ", but have tensors of size " << input_tensors.size();
|
||||
|
||||
const auto& input_tensor = input_tensors[tensor_position_];
|
||||
const int tensor_width = input_tensor.shape().dims[2];
|
||||
const int tensor_height = input_tensor.shape().dims[1];
|
||||
const int tensor_in_channels = input_tensor.shape().dims[3];
|
||||
RET_CHECK(tensor_in_channels == 3 || tensor_in_channels == 1);
|
||||
RET_CHECK_EQ(input_tensors.size(), 1)
|
||||
<< "Expect 1 input tensor, but have " << input_tensors.size();
|
||||
const int tensor_width = input_tensors[0].shape().dims[2];
|
||||
const int tensor_height = input_tensors[0].shape().dims[1];
|
||||
|
||||
#if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||
|
||||
@@ -480,7 +454,7 @@ absl::Status TensorsToImageCalculator::GlProcess(CalculatorContext* cc) {
|
||||
glBindImageTexture(output_index, out_texture->id(), 0, GL_FALSE, 0,
|
||||
GL_WRITE_ONLY, GL_RGBA8);
|
||||
|
||||
auto read_view = input_tensor.GetOpenGlBufferReadView();
|
||||
auto read_view = input_tensors[0].GetOpenGlBufferReadView();
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, read_view.name());
|
||||
|
||||
const tflite::gpu::uint3 workload = {tensor_width, tensor_height, 1};
|
||||
@@ -488,8 +462,8 @@ absl::Status TensorsToImageCalculator::GlProcess(CalculatorContext* cc) {
|
||||
tflite::gpu::DivideRoundUp(workload, workgroup_size_);
|
||||
|
||||
glUseProgram(gl_compute_program_->id());
|
||||
glUniform3i(glGetUniformLocation(gl_compute_program_->id(), "out_size"),
|
||||
tensor_width, tensor_height, tensor_in_channels);
|
||||
glUniform2i(glGetUniformLocation(gl_compute_program_->id(), "out_size"),
|
||||
tensor_width, tensor_height);
|
||||
|
||||
MP_RETURN_IF_ERROR(gl_compute_program_->Dispatch(workgroups));
|
||||
|
||||
@@ -507,8 +481,8 @@ absl::Status TensorsToImageCalculator::GlProcess(CalculatorContext* cc) {
|
||||
|
||||
#else
|
||||
|
||||
if (!input_tensor.ready_as_opengl_texture_2d()) {
|
||||
(void)input_tensor.GetCpuReadView();
|
||||
if (!input_tensors[0].ready_as_opengl_texture_2d()) {
|
||||
(void)input_tensors[0].GetCpuReadView();
|
||||
}
|
||||
|
||||
auto output_texture =
|
||||
@@ -516,7 +490,7 @@ absl::Status TensorsToImageCalculator::GlProcess(CalculatorContext* cc) {
|
||||
gl_helper_.BindFramebuffer(output_texture); // GL_TEXTURE0
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D,
|
||||
input_tensor.GetOpenGlTexture2dReadView().name());
|
||||
input_tensors[0].GetOpenGlTexture2dReadView().name());
|
||||
|
||||
MP_RETURN_IF_ERROR(gl_renderer_->GlRender(
|
||||
tensor_width, tensor_height, output_texture.width(),
|
||||
|
||||
@@ -48,8 +48,4 @@ message TensorsToImageCalculatorOptions {
|
||||
FloatRange input_tensor_float_range = 2;
|
||||
UIntRange input_tensor_uint_range = 3;
|
||||
}
|
||||
|
||||
// Determines which output tensor to slice when there are multiple output
|
||||
// tensors available (e.g. network has multiple heads)
|
||||
optional int32 tensor_position = 4 [default = 0];
|
||||
}
|
||||
|
||||
@@ -153,11 +153,6 @@ cc_library(
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "hand_landmarks_connections",
|
||||
hdrs = ["hand_landmarks_connections.h"],
|
||||
)
|
||||
|
||||
# TODO: open source hand joints graph
|
||||
|
||||
cc_library(
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/* Copyright 2023 The MediaPipe Authors.
|
||||
|
||||
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_VISION_HAND_LANDMARKER_HAND_LANDMARKS_CONNECTIONS_H_
|
||||
#define MEDIAPIPE_TASKS_CC_VISION_HAND_LANDMARKER_HAND_LANDMARKS_CONNECTIONS_H_
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace mediapipe {
|
||||
namespace tasks {
|
||||
namespace vision {
|
||||
namespace hand_landmarker {
|
||||
|
||||
static constexpr std::array<std::array<int, 2>, 6> kHandPalmConnections{
|
||||
{{0, 1}, {0, 5}, {9, 13}, {13, 17}, {5, 9}, {0, 17}}};
|
||||
|
||||
static constexpr std::array<std::array<int, 2>, 3> kHandThumbConnections{
|
||||
{{1, 2}, {2, 3}, {3, 4}}};
|
||||
|
||||
static constexpr std::array<std::array<int, 2>, 3> kHandIndexFingerConnections{
|
||||
{{5, 6}, {6, 7}, {7, 8}}};
|
||||
|
||||
static constexpr std::array<std::array<int, 2>, 3> kHandMiddleFingerConnections{
|
||||
{{9, 10}, {10, 11}, {11, 12}}};
|
||||
|
||||
static constexpr std::array<std::array<int, 2>, 3> kHandRingFingerConnections{
|
||||
{{13, 14}, {14, 15}, {15, 16}}};
|
||||
|
||||
static constexpr std::array<std::array<int, 2>, 3> kHandPinkyFingerConnections{
|
||||
{{17, 18}, {18, 19}, {19, 20}}};
|
||||
|
||||
static constexpr std::array<std::array<int, 2>, 21> kHandConnections{
|
||||
{{0, 1}, {0, 5}, {9, 13}, {13, 17}, {5, 9}, {0, 17}, {1, 2},
|
||||
{2, 3}, {3, 4}, {5, 6}, {6, 7}, {7, 8}, {9, 10}, {10, 11},
|
||||
{11, 12}, {13, 14}, {14, 15}, {15, 16}, {17, 18}, {18, 19}, {19, 20}}};
|
||||
|
||||
} // namespace hand_landmarker
|
||||
} // namespace vision
|
||||
} // namespace tasks
|
||||
} // namespace mediapipe
|
||||
|
||||
#endif // MEDIAPIPE_TASKS_CC_VISION_HAND_LANDMARKER_HAND_LANDMARKS_CONNECTIONS_H_
|
||||
@@ -155,8 +155,3 @@ cc_library(
|
||||
"//mediapipe/tasks/cc/components/containers:landmark",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "pose_landmarks_connections",
|
||||
hdrs = ["pose_landmarks_connections.h"],
|
||||
)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/* Copyright 2023 The MediaPipe Authors.
|
||||
|
||||
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_VISION_POSE_LANDMARKER_POSE_LANDMARKS_CONNECTIONS_H_
|
||||
#define MEDIAPIPE_TASKS_CC_VISION_POSE_LANDMARKER_POSE_LANDMARKS_CONNECTIONS_H_
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace mediapipe {
|
||||
namespace tasks {
|
||||
namespace vision {
|
||||
namespace pose_landmarker {
|
||||
|
||||
static constexpr std::array<std::array<int, 2>, 34> kPoseLandmarksConnections{{
|
||||
{1, 2}, {0, 1}, {2, 3}, {3, 7}, {0, 4}, {4, 5}, {5, 6},
|
||||
{6, 8}, {9, 10}, {11, 12}, {11, 13}, {13, 15}, {15, 17}, {15, 19},
|
||||
{15, 21}, {17, 19}, {12, 14}, {14, 16}, {16, 18}, {16, 20}, {16, 22},
|
||||
{18, 20}, {11, 23}, {12, 24}, {23, 24}, {23, 25}, {24, 26}, {25, 27},
|
||||
{26, 28}, {27, 29}, {28, 30}, {29, 31}, {30, 32}, {27, 31},
|
||||
}};
|
||||
|
||||
} // namespace pose_landmarker
|
||||
} // namespace vision
|
||||
} // namespace tasks
|
||||
} // namespace mediapipe
|
||||
|
||||
#endif // MEDIAPIPE_TASKS_CC_VISION_POSE_LANDMARKER_POSE_LANDMARKS_CONNECTIONS_H_
|
||||
@@ -32,7 +32,6 @@ android_library(
|
||||
"//mediapipe/tasks/cc/core/proto:base_options_java_proto_lite",
|
||||
"//mediapipe/tasks/cc/core/proto:external_file_java_proto_lite",
|
||||
"//mediapipe/tasks/java/com/google/mediapipe/tasks/core/jni:model_resources_cache_jni",
|
||||
"//third_party:any_java_proto",
|
||||
"//third_party:autovalue",
|
||||
"@com_google_protobuf//:protobuf_javalite",
|
||||
"@maven//:com_google_guava_guava",
|
||||
|
||||
@@ -20,8 +20,6 @@ import com.google.mediapipe.proto.CalculatorProto.CalculatorGraphConfig;
|
||||
import com.google.mediapipe.proto.CalculatorProto.CalculatorGraphConfig.Node;
|
||||
import com.google.mediapipe.proto.CalculatorProto.InputStreamInfo;
|
||||
import com.google.mediapipe.calculator.proto.FlowLimiterCalculatorProto.FlowLimiterCalculatorOptions;
|
||||
import com.google.mediapipe.framework.MediaPipeException;
|
||||
import com.google.protobuf.Any;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -112,21 +110,10 @@ public abstract class TaskInfo<T extends TaskOptions> {
|
||||
*/
|
||||
CalculatorGraphConfig generateGraphConfig() {
|
||||
CalculatorGraphConfig.Builder graphBuilder = CalculatorGraphConfig.newBuilder();
|
||||
CalculatorOptions options = taskOptions().convertToCalculatorOptionsProto();
|
||||
Any anyOptions = taskOptions().convertToAnyProto();
|
||||
if (!(options == null ^ anyOptions == null)) {
|
||||
throw new MediaPipeException(
|
||||
MediaPipeException.StatusCode.INVALID_ARGUMENT.ordinal(),
|
||||
"Only one of convertTo*Proto() method should be implemented for "
|
||||
+ taskOptions().getClass());
|
||||
}
|
||||
Node.Builder taskSubgraphBuilder = Node.newBuilder().setCalculator(taskGraphName());
|
||||
if (options != null) {
|
||||
taskSubgraphBuilder.setOptions(options);
|
||||
}
|
||||
if (anyOptions != null) {
|
||||
taskSubgraphBuilder.addNodeOptions(anyOptions);
|
||||
}
|
||||
Node.Builder taskSubgraphBuilder =
|
||||
Node.newBuilder()
|
||||
.setCalculator(taskGraphName())
|
||||
.setOptions(taskOptions().convertToCalculatorOptionsProto());
|
||||
for (String outputStream : outputStreams()) {
|
||||
taskSubgraphBuilder.addOutputStream(outputStream);
|
||||
graphBuilder.addOutputStream(outputStream);
|
||||
|
||||
@@ -20,26 +20,18 @@ import com.google.mediapipe.proto.CalculatorOptionsProto.CalculatorOptions;
|
||||
import com.google.mediapipe.tasks.core.proto.AccelerationProto;
|
||||
import com.google.mediapipe.tasks.core.proto.BaseOptionsProto;
|
||||
import com.google.mediapipe.tasks.core.proto.ExternalFileProto;
|
||||
import com.google.protobuf.Any;
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
/**
|
||||
* MediaPipe Tasks options base class. Any MediaPipe task-specific options class should extend
|
||||
* {@link TaskOptions} and implement exactly one of converTo*Proto() methods.
|
||||
* {@link TaskOptions}.
|
||||
*/
|
||||
public abstract class TaskOptions {
|
||||
/**
|
||||
* Converts a MediaPipe Tasks task-specific options to a {@link CalculatorOptions} protobuf
|
||||
* message.
|
||||
*/
|
||||
public CalculatorOptions convertToCalculatorOptionsProto() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Converts a MediaPipe Tasks task-specific options to an proto3 {@link Any} message. */
|
||||
public Any convertToAnyProto() {
|
||||
return null;
|
||||
}
|
||||
public abstract CalculatorOptions convertToCalculatorOptionsProto();
|
||||
|
||||
/**
|
||||
* Converts a {@link BaseOptions} instance to a {@link BaseOptionsProto.BaseOptions} protobuf
|
||||
|
||||
@@ -24,10 +24,4 @@ export declare interface BoundingBox {
|
||||
width: number;
|
||||
/** The height of the bounding box, in pixels. */
|
||||
height: number;
|
||||
/**
|
||||
* Angle of rotation of the original non-rotated box around the top left
|
||||
* corner of the original non-rotated box, in clockwise degrees from the
|
||||
* horizontal.
|
||||
*/
|
||||
angle: number;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('convertFromDetectionProto()', () => {
|
||||
categoryName: 'foo',
|
||||
displayName: 'bar',
|
||||
}],
|
||||
boundingBox: {originX: 1, originY: 2, width: 3, height: 4, angle: 0},
|
||||
boundingBox: {originX: 1, originY: 2, width: 3, height: 4},
|
||||
keypoints: [{
|
||||
x: 5,
|
||||
y: 6,
|
||||
@@ -85,7 +85,7 @@ describe('convertFromDetectionProto()', () => {
|
||||
categoryName: '',
|
||||
displayName: '',
|
||||
}],
|
||||
boundingBox: {originX: 0, originY: 0, width: 0, height: 0, angle: 0},
|
||||
boundingBox: {originX: 0, originY: 0, width: 0, height: 0},
|
||||
keypoints: []
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,8 +42,7 @@ export function convertFromDetectionProto(source: DetectionProto): Detection {
|
||||
originX: boundingBox.getXmin() ?? 0,
|
||||
originY: boundingBox.getYmin() ?? 0,
|
||||
width: boundingBox.getWidth() ?? 0,
|
||||
height: boundingBox.getHeight() ?? 0,
|
||||
angle: 0.0,
|
||||
height: boundingBox.getHeight() ?? 0
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ import {SupportModelResourcesGraphService} from '../../../web/graph_runner/regis
|
||||
|
||||
import {WasmFileset} from './wasm_fileset';
|
||||
|
||||
// None of the MP Tasks ship bundle assets.
|
||||
const NO_ASSETS = undefined;
|
||||
|
||||
// Internal stream names for temporarily keeping memory alive, then freeing it.
|
||||
const FREE_MEMORY_STREAM = 'free_memory';
|
||||
const UNUSED_STREAM_SUFFIX = '_unused_out';
|
||||
@@ -58,8 +61,7 @@ export async function createTaskRunner<T extends TaskRunner>(
|
||||
};
|
||||
|
||||
const instance = await createMediaPipeLib(
|
||||
type, fileset.wasmLoaderPath, fileset.assetLoaderPath, canvas,
|
||||
fileLocator);
|
||||
type, fileset.wasmLoaderPath, NO_ASSETS, canvas, fileLocator);
|
||||
await instance.setOptions(options);
|
||||
return instance;
|
||||
}
|
||||
@@ -94,73 +96,65 @@ export abstract class TaskRunner {
|
||||
abstract setOptions(options: TaskRunnerOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Applies the current set of options, including optionally any base options
|
||||
* that have not been processed by the task implementation. The options are
|
||||
* applied synchronously unless a `modelAssetPath` is provided. This ensures
|
||||
* that for most use cases options are applied directly and immediately affect
|
||||
* Applies the current set of options, including any base options that have
|
||||
* not been processed by the task implementation. The options are applied
|
||||
* synchronously unless a `modelAssetPath` is provided. This ensures that
|
||||
* for most use cases options are applied directly and immediately affect
|
||||
* the next inference.
|
||||
*
|
||||
* @param options The options for the task.
|
||||
* @param loadTfliteModel Whether to load the model specified in
|
||||
* `options.baseOptions`.
|
||||
*/
|
||||
protected applyOptions(options: TaskRunnerOptions, loadTfliteModel = true):
|
||||
Promise<void> {
|
||||
if (loadTfliteModel) {
|
||||
const baseOptions: BaseOptions = options.baseOptions || {};
|
||||
protected applyOptions(options: TaskRunnerOptions): Promise<void> {
|
||||
const baseOptions: BaseOptions = options.baseOptions || {};
|
||||
|
||||
// Validate that exactly one model is configured
|
||||
if (options.baseOptions?.modelAssetBuffer &&
|
||||
options.baseOptions?.modelAssetPath) {
|
||||
throw new Error(
|
||||
'Cannot set both baseOptions.modelAssetPath and baseOptions.modelAssetBuffer');
|
||||
} else if (!(this.baseOptions.getModelAsset()?.hasFileContent() ||
|
||||
this.baseOptions.getModelAsset()?.hasFileName() ||
|
||||
options.baseOptions?.modelAssetBuffer ||
|
||||
options.baseOptions?.modelAssetPath)) {
|
||||
throw new Error(
|
||||
'Either baseOptions.modelAssetPath or baseOptions.modelAssetBuffer must be set');
|
||||
}
|
||||
|
||||
this.setAcceleration(baseOptions);
|
||||
if (baseOptions.modelAssetPath) {
|
||||
// We don't use `await` here since we want to apply most settings
|
||||
// synchronously.
|
||||
return fetch(baseOptions.modelAssetPath.toString())
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch model: ${
|
||||
baseOptions.modelAssetPath} (${response.status})`);
|
||||
} else {
|
||||
return response.arrayBuffer();
|
||||
}
|
||||
})
|
||||
.then(buffer => {
|
||||
try {
|
||||
// Try to delete file as we cannot overwite an existing file
|
||||
// using our current API.
|
||||
this.graphRunner.wasmModule.FS_unlink('/model.dat');
|
||||
} catch {
|
||||
}
|
||||
// TODO: Consider passing the model to the graph as an
|
||||
// input side packet as this might reduce copies.
|
||||
this.graphRunner.wasmModule.FS_createDataFile(
|
||||
'/', 'model.dat', new Uint8Array(buffer),
|
||||
/* canRead= */ true, /* canWrite= */ false,
|
||||
/* canOwn= */ false);
|
||||
this.setExternalFile('/model.dat');
|
||||
this.refreshGraph();
|
||||
this.onGraphRefreshed();
|
||||
});
|
||||
} else {
|
||||
this.setExternalFile(baseOptions.modelAssetBuffer);
|
||||
}
|
||||
// Validate that exactly one model is configured
|
||||
if (options.baseOptions?.modelAssetBuffer &&
|
||||
options.baseOptions?.modelAssetPath) {
|
||||
throw new Error(
|
||||
'Cannot set both baseOptions.modelAssetPath and baseOptions.modelAssetBuffer');
|
||||
} else if (!(this.baseOptions.getModelAsset()?.hasFileContent() ||
|
||||
this.baseOptions.getModelAsset()?.hasFileName() ||
|
||||
options.baseOptions?.modelAssetBuffer ||
|
||||
options.baseOptions?.modelAssetPath)) {
|
||||
throw new Error(
|
||||
'Either baseOptions.modelAssetPath or baseOptions.modelAssetBuffer must be set');
|
||||
}
|
||||
|
||||
// If there is no model to download, we can apply the setting synchronously.
|
||||
this.refreshGraph();
|
||||
this.onGraphRefreshed();
|
||||
return Promise.resolve();
|
||||
this.setAcceleration(baseOptions);
|
||||
if (baseOptions.modelAssetPath) {
|
||||
// We don't use `await` here since we want to apply most settings
|
||||
// synchronously.
|
||||
return fetch(baseOptions.modelAssetPath.toString())
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch model: ${
|
||||
baseOptions.modelAssetPath} (${response.status})`);
|
||||
} else {
|
||||
return response.arrayBuffer();
|
||||
}
|
||||
})
|
||||
.then(buffer => {
|
||||
try {
|
||||
// Try to delete file as we cannot overwite an existing file using
|
||||
// our current API.
|
||||
this.graphRunner.wasmModule.FS_unlink('/model.dat');
|
||||
} catch {
|
||||
}
|
||||
// TODO: Consider passing the model to the graph as an
|
||||
// input side packet as this might reduce copies.
|
||||
this.graphRunner.wasmModule.FS_createDataFile(
|
||||
'/', 'model.dat', new Uint8Array(buffer),
|
||||
/* canRead= */ true, /* canWrite= */ false,
|
||||
/* canOwn= */ false);
|
||||
this.setExternalFile('/model.dat');
|
||||
this.refreshGraph();
|
||||
this.onGraphRefreshed();
|
||||
});
|
||||
} else {
|
||||
// Apply the setting synchronously.
|
||||
this.setExternalFile(baseOptions.modelAssetBuffer);
|
||||
this.refreshGraph();
|
||||
this.onGraphRefreshed();
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
/** Appliest the current options to the MediaPipe graph. */
|
||||
|
||||
-2
@@ -22,6 +22,4 @@ export declare interface WasmFileset {
|
||||
wasmLoaderPath: string;
|
||||
/** The path to the Wasm binary. */
|
||||
wasmBinaryPath: string;
|
||||
/** The optional path to the asset loader script. */
|
||||
assetLoaderPath?: string;
|
||||
}
|
||||
|
||||
@@ -70,8 +70,7 @@ export abstract class VisionTaskRunner extends TaskRunner {
|
||||
* @param imageStreamName the name of the input image stream.
|
||||
* @param normRectStreamName the name of the input normalized rect image
|
||||
* stream used to provide (mandatory) rotation and (optional)
|
||||
* region-of-interest. `null` if the graph does not support normalized
|
||||
* rects.
|
||||
* region-of-interest.
|
||||
* @param roiAllowed Whether this task supports Region-Of-Interest
|
||||
* pre-processing
|
||||
*
|
||||
@@ -80,20 +79,13 @@ export abstract class VisionTaskRunner extends TaskRunner {
|
||||
constructor(
|
||||
protected override readonly graphRunner: VisionGraphRunner,
|
||||
private readonly imageStreamName: string,
|
||||
private readonly normRectStreamName: string|null,
|
||||
private readonly normRectStreamName: string,
|
||||
private readonly roiAllowed: boolean) {
|
||||
super(graphRunner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the shared options of a vision task.
|
||||
*
|
||||
* @param options The options for the task.
|
||||
* @param loadTfliteModel Whether to load the model specified in
|
||||
* `options.baseOptions`.
|
||||
*/
|
||||
override applyOptions(options: VisionTaskOptions, loadTfliteModel = true):
|
||||
Promise<void> {
|
||||
/** Configures the shared options of a vision task. */
|
||||
override applyOptions(options: VisionTaskOptions): Promise<void> {
|
||||
if ('runningMode' in options) {
|
||||
const useStreamMode =
|
||||
!!options.runningMode && options.runningMode !== 'IMAGE';
|
||||
@@ -106,7 +98,7 @@ export abstract class VisionTaskRunner extends TaskRunner {
|
||||
}
|
||||
}
|
||||
|
||||
return super.applyOptions(options, loadTfliteModel);
|
||||
return super.applyOptions(options);
|
||||
}
|
||||
|
||||
/** Sends a single image to the graph and awaits results. */
|
||||
@@ -217,13 +209,11 @@ export abstract class VisionTaskRunner extends TaskRunner {
|
||||
imageSource: ImageSource,
|
||||
imageProcessingOptions: ImageProcessingOptions|undefined,
|
||||
timestamp: number): void {
|
||||
if (this.normRectStreamName) {
|
||||
const normalizedRect =
|
||||
this.convertToNormalizedRect(imageSource, imageProcessingOptions);
|
||||
this.graphRunner.addProtoToStream(
|
||||
normalizedRect.serializeBinary(), 'mediapipe.NormalizedRect',
|
||||
this.normRectStreamName, timestamp);
|
||||
}
|
||||
const normalizedRect =
|
||||
this.convertToNormalizedRect(imageSource, imageProcessingOptions);
|
||||
this.graphRunner.addProtoToStream(
|
||||
normalizedRect.serializeBinary(), 'mediapipe.NormalizedRect',
|
||||
this.normRectStreamName, timestamp);
|
||||
this.graphRunner.addGpuBufferAsImageToStream(
|
||||
imageSource, this.imageStreamName, timestamp ?? performance.now());
|
||||
this.finishProcessing();
|
||||
|
||||
@@ -191,7 +191,7 @@ describe('FaceDetector', () => {
|
||||
categoryName: '',
|
||||
displayName: '',
|
||||
}],
|
||||
boundingBox: {originX: 0, originY: 0, width: 0, height: 0, angle: 0},
|
||||
boundingBox: {originX: 0, originY: 0, width: 0, height: 0},
|
||||
keypoints: []
|
||||
});
|
||||
});
|
||||
|
||||
@@ -210,7 +210,7 @@ describe('ObjectDetector', () => {
|
||||
categoryName: '',
|
||||
displayName: '',
|
||||
}],
|
||||
boundingBox: {originX: 0, originY: 0, width: 0, height: 0, angle: 0},
|
||||
boundingBox: {originX: 0, originY: 0, width: 0, height: 0},
|
||||
keypoints: []
|
||||
});
|
||||
});
|
||||
|
||||
@@ -152,7 +152,6 @@ cc_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//mediapipe/framework/formats:landmark_cc_proto",
|
||||
"//mediapipe/framework/port:logging",
|
||||
"//mediapipe/framework/port:opencv_core",
|
||||
"//mediapipe/framework/port:opencv_imgproc",
|
||||
],
|
||||
|
||||
+11
-34
@@ -1,6 +1,5 @@
|
||||
#include "mediapipe/util/pose_util.h"
|
||||
|
||||
#include "mediapipe/framework/port/logging.h"
|
||||
#include "mediapipe/framework/port/opencv_imgproc_inc.h"
|
||||
|
||||
namespace {
|
||||
@@ -193,7 +192,7 @@ void DrawPose(const mediapipe::NormalizedLandmarkList& pose, bool flip_y,
|
||||
}
|
||||
|
||||
void DrawFace(const mediapipe::NormalizedLandmarkList& face, bool flip_y,
|
||||
bool draw_nose, int color_style, bool reverse_color,
|
||||
bool draw_nose, bool color_style, bool reverse_color,
|
||||
int draw_line_width, cv::Mat* image) {
|
||||
const int target_width = image->cols;
|
||||
const int target_height = image->rows;
|
||||
@@ -203,26 +202,16 @@ void DrawFace(const mediapipe::NormalizedLandmarkList& face, bool flip_y,
|
||||
(flip_y ? 1.0f - lm.y() : lm.y()) * target_height);
|
||||
}
|
||||
|
||||
cv::Scalar kFaceOvalColor;
|
||||
cv::Scalar kLipsColor;
|
||||
cv::Scalar kLeftEyeColor;
|
||||
cv::Scalar kLeftEyebrowColor;
|
||||
cv::Scalar kLeftEyeIrisColor;
|
||||
cv::Scalar kRightEyeColor;
|
||||
cv::Scalar kRightEyebrowColor;
|
||||
cv::Scalar kRightEyeIrisColor;
|
||||
cv::Scalar kNoseColor;
|
||||
if (color_style == 0) {
|
||||
kFaceOvalColor = kWhiteColor;
|
||||
kLipsColor = kWhiteColor;
|
||||
kLeftEyeColor = kGreenColor;
|
||||
kLeftEyebrowColor = kGreenColor;
|
||||
kLeftEyeIrisColor = kGreenColor;
|
||||
kRightEyeColor = kRedColor;
|
||||
kRightEyebrowColor = kRedColor;
|
||||
kRightEyeIrisColor = kRedColor;
|
||||
kNoseColor = kWhiteColor;
|
||||
} else if (color_style == 1) {
|
||||
cv::Scalar kFaceOvalColor = kWhiteColor;
|
||||
cv::Scalar kLipsColor = kWhiteColor;
|
||||
cv::Scalar kLeftEyeColor = kGreenColor;
|
||||
cv::Scalar kLeftEyebrowColor = kGreenColor;
|
||||
cv::Scalar kLeftEyeIrisColor = kGreenColor;
|
||||
cv::Scalar kRightEyeColor = kRedColor;
|
||||
cv::Scalar kRightEyebrowColor = kRedColor;
|
||||
cv::Scalar kRightEyeIrisColor = kRedColor;
|
||||
cv::Scalar kNoseColor = kWhiteColor;
|
||||
if (color_style) {
|
||||
kFaceOvalColor = kWhiteColor;
|
||||
kLipsColor = kBlueColor;
|
||||
kLeftEyeColor = kCyanColor;
|
||||
@@ -232,18 +221,6 @@ void DrawFace(const mediapipe::NormalizedLandmarkList& face, bool flip_y,
|
||||
kRightEyebrowColor = kRedColor;
|
||||
kRightEyeIrisColor = kRedColor;
|
||||
kNoseColor = kYellowColor;
|
||||
} else if (color_style == 2) {
|
||||
kFaceOvalColor = kWhiteColor;
|
||||
kLipsColor = kBlueColor;
|
||||
kLeftEyeColor = kCyanColor;
|
||||
kLeftEyebrowColor = kGreenColor;
|
||||
kLeftEyeIrisColor = kRedColor;
|
||||
kRightEyeColor = kCyanColor;
|
||||
kRightEyebrowColor = kGreenColor;
|
||||
kRightEyeIrisColor = kRedColor;
|
||||
kNoseColor = kYellowColor;
|
||||
} else {
|
||||
LOG(ERROR) << "color_style not supported.";
|
||||
}
|
||||
|
||||
if (reverse_color) {
|
||||
|
||||
@@ -24,7 +24,7 @@ void DrawPose(const mediapipe::NormalizedLandmarkList& pose, bool flip_y,
|
||||
cv::Mat* image);
|
||||
|
||||
void DrawFace(const mediapipe::NormalizedLandmarkList& face, bool flip_y,
|
||||
bool draw_nose, int color_style, bool reverse_color,
|
||||
bool draw_nose, bool color_style, bool reverse_color,
|
||||
int draw_line_width, cv::Mat* image);
|
||||
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -72,6 +72,7 @@ cc_test(
|
||||
"//mediapipe/framework/formats:location",
|
||||
"//mediapipe/framework/port:gtest_main",
|
||||
"//mediapipe/framework/port:opencv_imgcodecs",
|
||||
"//mediapipe/framework/port:status",
|
||||
"@org_tensorflow//tensorflow/core:protos_all_cc",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -234,11 +234,6 @@ absl::Status TFLiteGPURunner::InitializeOpenCL(
|
||||
MP_RETURN_IF_ERROR(
|
||||
cl::NewInferenceEnvironment(env_options, &cl_environment_, &properties));
|
||||
|
||||
if (serialized_model_.empty() &&
|
||||
opencl_init_from_serialized_model_is_forced_) {
|
||||
ASSIGN_OR_RETURN(serialized_model_, GetSerializedModel());
|
||||
}
|
||||
|
||||
// Try to initialize from serialized model first.
|
||||
if (!serialized_model_.empty()) {
|
||||
absl::Status init_status = InitializeOpenCLFromSerializedModel(builder);
|
||||
@@ -275,6 +270,7 @@ absl::Status TFLiteGPURunner::InitializeOpenCLFromSerializedModel(
|
||||
}
|
||||
|
||||
absl::StatusOr<std::vector<uint8_t>> TFLiteGPURunner::GetSerializedModel() {
|
||||
RET_CHECK(runner_) << "Runner is in invalid state.";
|
||||
if (serialized_model_used_) {
|
||||
return serialized_model_;
|
||||
}
|
||||
|
||||
@@ -62,9 +62,6 @@ class TFLiteGPURunner {
|
||||
|
||||
void ForceOpenGL() { opengl_is_forced_ = true; }
|
||||
void ForceOpenCL() { opencl_is_forced_ = true; }
|
||||
void ForceOpenCLInitFromSerializedModel() {
|
||||
opencl_init_from_serialized_model_is_forced_ = true;
|
||||
}
|
||||
|
||||
absl::Status BindSSBOToInputTensor(GLuint ssbo_id, int input_id);
|
||||
absl::Status BindSSBOToOutputTensor(GLuint ssbo_id, int output_id);
|
||||
@@ -144,7 +141,6 @@ class TFLiteGPURunner {
|
||||
|
||||
bool opencl_is_forced_ = false;
|
||||
bool opengl_is_forced_ = false;
|
||||
bool opencl_init_from_serialized_model_is_forced_ = false;
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
"google-protobuf": "^3.21.2",
|
||||
"jasmine": "^4.5.0",
|
||||
"jasmine-core": "^4.5.0",
|
||||
"protobufjs": "^7.1.2",
|
||||
"protobufjs": "^7.2.4",
|
||||
"protobufjs-cli": "^1.0.2",
|
||||
"rollup": "^2.3.0",
|
||||
"ts-protoc-gen": "^0.15.0",
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
# This file allows automatically mapping flags such as '--cpu' to the more
|
||||
# modern Bazel platforms (https://bazel.build/concepts/platforms).
|
||||
|
||||
# In particular, Bazel platforms lack support for Apple for now if no such
|
||||
# mapping is put into place. It's inspired from:
|
||||
# https://github.com/bazelbuild/rules_apple/issues/1764
|
||||
|
||||
platforms:
|
||||
@build_bazel_apple_support//platforms:macos_x86_64
|
||||
--cpu=darwin_x86_64
|
||||
|
||||
@build_bazel_apple_support//platforms:macos_arm64
|
||||
--cpu=darwin_arm64
|
||||
|
||||
@build_bazel_apple_support//platforms:ios_i386
|
||||
--cpu=ios_i386
|
||||
|
||||
@build_bazel_apple_support//platforms:ios_x86_64
|
||||
--cpu=ios_x86_64
|
||||
|
||||
@build_bazel_apple_support//platforms:ios_sim_arm64
|
||||
--cpu=ios_sim_arm64
|
||||
|
||||
@build_bazel_apple_support//platforms:ios_armv7
|
||||
--cpu=ios_armv7
|
||||
|
||||
@build_bazel_apple_support//platforms:ios_arm64
|
||||
--cpu=ios_arm64
|
||||
|
||||
@build_bazel_apple_support//platforms:ios_arm64e
|
||||
--cpu=ios_arm64e
|
||||
|
||||
flags:
|
||||
--cpu=darwin_x86_64
|
||||
--apple_platform_type=macos
|
||||
@build_bazel_apple_support//platforms:macos_x86_64
|
||||
|
||||
--cpu=darwin_arm64
|
||||
--apple_platform_type=macos
|
||||
@build_bazel_apple_support//platforms:macos_arm64
|
||||
|
||||
--cpu=ios_i386
|
||||
--apple_platform_type=ios
|
||||
@build_bazel_apple_support//platforms:ios_i386
|
||||
|
||||
--cpu=ios_x86_64
|
||||
--apple_platform_type=ios
|
||||
@build_bazel_apple_support//platforms:ios_x86_64
|
||||
|
||||
--cpu=ios_sim_arm64
|
||||
--apple_platform_type=ios
|
||||
@build_bazel_apple_support//platforms:ios_sim_arm64
|
||||
|
||||
--cpu=ios_armv7
|
||||
--apple_platform_type=ios
|
||||
@build_bazel_apple_support//platforms:ios_armv7
|
||||
|
||||
--cpu=ios_arm64
|
||||
--apple_platform_type=ios
|
||||
@build_bazel_apple_support//platforms:ios_arm64
|
||||
|
||||
--cpu=ios_arm64e
|
||||
--apple_platform_type=ios
|
||||
@build_bazel_apple_support//platforms:ios_arm64e
|
||||
Vendored
-7
@@ -378,10 +378,3 @@ java_library(
|
||||
"@maven//:com_google_auto_value_auto_value_annotations",
|
||||
],
|
||||
)
|
||||
|
||||
java_proto_library(
|
||||
name = "any_java_proto",
|
||||
deps = [
|
||||
"@com_google_protobuf//:any_proto",
|
||||
],
|
||||
)
|
||||
|
||||
Vendored
+1
-1
@@ -42,7 +42,7 @@ cc_library(
|
||||
cc_library(
|
||||
name = "lib_halide_static",
|
||||
srcs = select({
|
||||
"@mediapipe//mediapipe:windows": [
|
||||
"@halide//:halide_config_windows_x86_64": [
|
||||
"bin/Release/Halide.dll",
|
||||
"lib/Release/Halide.lib",
|
||||
],
|
||||
|
||||
Vendored
+6
-6
@@ -28,13 +28,13 @@ halide_library_runtimes()
|
||||
name = target_name,
|
||||
actual = select(
|
||||
{
|
||||
"@mediapipe//mediapipe:macos_x86_64": "@macos_x86_64_halide//:%s" % target_name,
|
||||
"@mediapipe//mediapipe:macos_arm64": "@macos_arm_64_halide//:%s" % target_name,
|
||||
"@mediapipe//mediapipe:windows": "@windows_halide//:%s" % target_name,
|
||||
# Assume Linux x86_64 by default.
|
||||
# TODO: add mediapipe configs for linux to avoid assuming it's the default.
|
||||
"//conditions:default": "@linux_halide//:%s" % target_name,
|
||||
":halide_config_linux_x86_64": "@linux_halide//:%s" % target_name,
|
||||
":halide_config_macos_x86_64": "@macos_x86_64_halide//:%s" % target_name,
|
||||
":halide_config_macos_arm64": "@macos_arm_64_halide//:%s" % target_name,
|
||||
":halide_config_windows_x86_64": "@windows_halide//:%s" % target_name,
|
||||
# deliberately no //condition:default clause here
|
||||
},
|
||||
no_match_error = "Compiling Halide code requires that the build host is one of Linux x86-64, Windows x86-64, macOS x86-64, or macOS arm64.",
|
||||
),
|
||||
)
|
||||
for target_name in [
|
||||
|
||||
Vendored
+25
-12
@@ -82,22 +82,22 @@ def halide_runtime_linkopts():
|
||||
# Map of halide-target-base -> config_settings
|
||||
_HALIDE_TARGET_CONFIG_SETTINGS_MAP = {
|
||||
# Android
|
||||
"arm-32-android": ["@mediapipe//mediapipe:android_arm"],
|
||||
"arm-64-android": ["@mediapipe//mediapipe:android_arm64"],
|
||||
"x86-32-android": ["@mediapipe//mediapipe:android_x86"],
|
||||
"x86-64-android": ["@mediapipe//mediapipe:android_x86_64"],
|
||||
"arm-32-android": ["@halide//:halide_config_android_arm"],
|
||||
"arm-64-android": ["@halide//:halide_config_android_arm64"],
|
||||
"x86-32-android": ["@halide//:halide_config_android_x86_32"],
|
||||
"x86-64-android": ["@halide//:halide_config_android_x86_64"],
|
||||
# iOS
|
||||
"arm-32-ios": ["@mediapipe//mediapipe:ios_armv7"],
|
||||
"arm-64-ios": ["@mediapipe//mediapipe:ios_arm64", "@mediapipe//mediapipe:ios_arm64e"],
|
||||
"arm-32-ios": ["@halide//:halide_config_ios_arm"],
|
||||
"arm-64-ios": ["@halide//:halide_config_ios_arm64"],
|
||||
# OSX (or iOS simulator)
|
||||
"x86-32-osx": ["@mediapipe//mediapipe:ios_i386"],
|
||||
"x86-64-osx": ["@mediapipe//mediapipe:macos_x86_64", "@mediapipe//mediapipe:ios_x86_64"],
|
||||
"arm-64-osx": ["@mediapipe//mediapipe:macos_arm64"],
|
||||
"x86-32-osx": ["@halide//:halide_config_macos_x86_32", "@halide//:halide_config_ios_x86_32"],
|
||||
"x86-64-osx": ["@halide//:halide_config_macos_x86_64", "@halide//:halide_config_ios_x86_64"],
|
||||
"arm-64-osx": ["@halide//:halide_config_macos_arm64"],
|
||||
# Windows
|
||||
"x86-64-windows": ["@mediapipe//mediapipe:windows"],
|
||||
"x86-64-windows": ["@halide//:halide_config_windows_x86_64"],
|
||||
# Linux
|
||||
# TODO: add mediapipe configs for linux to avoid assuming it's the default.
|
||||
"x86-64-linux": ["//conditions:default"],
|
||||
"x86-64-linux": ["@halide//:halide_config_linux_x86_64"],
|
||||
# deliberately nothing here using //conditions:default
|
||||
}
|
||||
|
||||
_HALIDE_TARGET_MAP_DEFAULT = {
|
||||
@@ -618,6 +618,19 @@ def _standard_library_runtime_names():
|
||||
return collections.uniq([_halide_library_runtime_target_name(f) for f in _standard_library_runtime_features()])
|
||||
|
||||
def halide_library_runtimes(compatible_with = []):
|
||||
# Note that we don't use all of these combinations
|
||||
# (and some are invalid), but that's ok.
|
||||
for cpu in ["arm", "arm64", "x86_32", "x86_64"]:
|
||||
for os in ["android", "linux", "windows", "ios", "macos"]:
|
||||
native.config_setting(
|
||||
name = "halide_config_%s_%s" % (os, cpu),
|
||||
constraint_values = [
|
||||
"@platforms//os:%s" % os,
|
||||
"@platforms//cpu:%s" % cpu,
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
unused = [
|
||||
_define_halide_library_runtime(f, compatible_with = compatible_with)
|
||||
for f in _standard_library_runtime_features()
|
||||
|
||||
@@ -885,10 +885,10 @@ protobufjs-cli@^1.0.2:
|
||||
tmp "^0.2.1"
|
||||
uglify-js "^3.7.7"
|
||||
|
||||
protobufjs@^7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.2.tgz#a0cf6aeaf82f5625bffcf5a38b7cd2a7de05890c"
|
||||
integrity sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==
|
||||
protobufjs@^7.2.4:
|
||||
version "7.2.4"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.4.tgz#3fc1ec0cdc89dd91aef9ba6037ba07408485c3ae"
|
||||
integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
@@ -1130,9 +1130,9 @@ which@^2.0.1:
|
||||
isexe "^2.0.0"
|
||||
|
||||
word-wrap@~1.2.3:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
|
||||
integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
||||
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
|
||||
Reference in New Issue
Block a user