From a0eda45baf82d2f4823571b786b507ca6b57f9b8 Mon Sep 17 00:00:00 2001 From: Youchuan Hu Date: Thu, 30 Nov 2023 16:14:31 -0800 Subject: [PATCH] Add TensorsToSegmentationCalculator test utilities. PiperOrigin-RevId: 586817713 --- mediapipe/calculators/tensor/BUILD | 29 ++++- ...tensors_to_segmentation_calculator_test.cc | 56 +-------- ...s_to_segmentation_calculator_test_utils.cc | 111 ++++++++++++++++++ ...rs_to_segmentation_calculator_test_utils.h | 57 +++++++++ ...segmentation_calculator_test_utils_test.cc | 50 ++++++++ 5 files changed, 249 insertions(+), 54 deletions(-) create mode 100644 mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.cc create mode 100644 mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.h create mode 100644 mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils_test.cc diff --git a/mediapipe/calculators/tensor/BUILD b/mediapipe/calculators/tensor/BUILD index 96a29089e9..6186244301 100644 --- a/mediapipe/calculators/tensor/BUILD +++ b/mediapipe/calculators/tensor/BUILD @@ -1555,12 +1555,37 @@ cc_library( ], ) +cc_library( + name = "tensors_to_segmentation_calculator_test_utils", + testonly = 1, + srcs = ["tensors_to_segmentation_calculator_test_utils.cc"], + hdrs = ["tensors_to_segmentation_calculator_test_utils.h"], + deps = [ + ":tensors_to_segmentation_calculator_cc_proto", + "//mediapipe/framework:calculator_cc_proto", + "//mediapipe/framework/port:parse_text_proto", + "@com_google_absl//absl/log:absl_log", + "@com_google_absl//absl/strings", + ], +) + +cc_test( + name = "tensors_to_segmentation_calculator_test_utils_test", + srcs = ["tensors_to_segmentation_calculator_test_utils_test.cc"], + deps = [ + ":tensors_to_segmentation_calculator_cc_proto", + ":tensors_to_segmentation_calculator_test_utils", + "//mediapipe/framework/port:gtest_main", + ], +) + cc_test( name = "tensors_to_segmentation_calculator_test", srcs = ["tensors_to_segmentation_calculator_test.cc"], deps = [ ":tensors_to_segmentation_calculator", ":tensors_to_segmentation_calculator_cc_proto", + ":tensors_to_segmentation_calculator_test_utils", "//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_runner", "//mediapipe/framework:packet", @@ -1571,10 +1596,6 @@ cc_test( "//mediapipe/framework/formats:rect_cc_proto", "//mediapipe/framework/formats:tensor", "//mediapipe/framework/port:gtest_main", - "//mediapipe/framework/port:parse_text_proto", - "@com_google_absl//absl/log", - "@com_google_absl//absl/log:absl_log", - "@com_google_absl//absl/strings", ], ) diff --git a/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test.cc b/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test.cc index e5c6b8ade9..9ac63f31ac 100644 --- a/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test.cc +++ b/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test.cc @@ -17,10 +17,8 @@ #include #include -#include "absl/log/absl_log.h" -#include "absl/log/log.h" -#include "absl/strings/substitute.h" #include "mediapipe/calculators/tensor/tensors_to_segmentation_calculator.pb.h" +#include "mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.h" #include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_runner.h" #include "mediapipe/framework/formats/image.h" @@ -30,7 +28,6 @@ #include "mediapipe/framework/formats/tensor.h" #include "mediapipe/framework/packet.h" #include "mediapipe/framework/port/gtest.h" -#include "mediapipe/framework/port/parse_text_proto.h" #include "mediapipe/framework/port/status_matchers.h" #include "mediapipe/framework/timestamp.h" @@ -40,58 +37,17 @@ namespace { using ::testing::SizeIs; using ::testing::TestWithParam; using Options = mediapipe::TensorsToSegmentationCalculatorOptions; +namespace test_utils = ::mediapipe::tensors_to_segmentation_utils; -std::string ActivationTypeToString(Options::Activation activation) { - switch (activation) { - case Options::NONE: - return "NONE"; - case Options::SIGMOID: - return "SIGMOID"; - case Options::SOFTMAX: - return "SOFTMAX"; - default: - ABSL_LOG(FATAL) << "Unknown activation type: " << activation; - return "UNKNOWN"; - } -} - -struct FormattingTestCase { - std::string test_name; - std::vector inputs; - std::vector expected_outputs; - Options::Activation activation; - int rows = 1; - int cols = 1; - int rows_new = 1; - int cols_new = 1; - int channels = 1; - double max_abs_diff = 1e-7; -}; - -using TensorsToSegmentationCalculatorTest = TestWithParam; +using TensorsToSegmentationCalculatorTest = + TestWithParam; TEST_P(TensorsToSegmentationCalculatorTest, ParameterizedTests) { const auto& [test_name, inputs, expected_outputs, activation, rows, cols, rows_new, cols_new, channels, max_abs_diff] = GetParam(); auto graph_config = - mediapipe::ParseTextProtoOrDie(absl::Substitute( - R"pb( - input_stream: "tensors" - input_stream: "size" - node { - calculator: "TensorsToSegmentationCalculator" - input_stream: "TENSORS:tensors" - input_stream: "OUTPUT_SIZE:size" - output_stream: "MASK:image_as_mask" - options: { - [mediapipe.TensorsToSegmentationCalculatorOptions.ext] { - activation: $0 - } - } - } - )pb", - ActivationTypeToString(activation))); + test_utils::CreateGraphConfigForTest(/*test_gpu=*/false, activation); std::vector output_packets; tool::AddVectorSink("image_as_mask", &graph_config, &output_packets); @@ -151,7 +107,7 @@ TEST_P(TensorsToSegmentationCalculatorTest, ParameterizedTests) { INSTANTIATE_TEST_SUITE_P( TensorsToSegmentationCalculatorTests, TensorsToSegmentationCalculatorTest, - testing::ValuesIn({ + testing::ValuesIn({ {.test_name = "NoActivationAndNoOutputResize", .inputs = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0}, diff --git a/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.cc b/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.cc new file mode 100644 index 0000000000..2fc9019c21 --- /dev/null +++ b/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.cc @@ -0,0 +1,111 @@ +// 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. + +#include "mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.h" + +#include +#include + +#include "absl/log/absl_log.h" +#include "absl/strings/substitute.h" +#include "mediapipe/calculators/tensor/tensors_to_segmentation_calculator.pb.h" +#include "mediapipe/framework/calculator.pb.h" +#include "mediapipe/framework/port/parse_text_proto.h" + +namespace mediapipe { +namespace tensors_to_segmentation_utils { + +std::string ActivationTypeToString( + const TensorsToSegmentationCalculatorOptions::Activation& activation) { + switch (activation) { + case TensorsToSegmentationCalculatorOptions::NONE: + return "NONE"; + case TensorsToSegmentationCalculatorOptions::SIGMOID: + return "SIGMOID"; + case TensorsToSegmentationCalculatorOptions::SOFTMAX: + return "SOFTMAX"; + } + ABSL_LOG(FATAL) << "Unknown activation type: " << activation; + return "UNKNOWN"; +} + +std::vector ArrayFloatToUnsignedChar( + const std::vector& array) { + std::vector result; + result.reserve(array.size()); + for (int i = 0; i < array.size(); ++i) { + result.push_back(static_cast(array[i])); + } + return result; +} + +std::vector MakeRedAlphaMatrix(const std::vector& values) { + std::vector result; + result.reserve(values.size() * 4); + for (const float& value : values) { + result.push_back(value); + result.push_back(0); + result.push_back(0); + result.push_back(value); + } + return result; +} + +// For GPU tests, the input tensor needs to be moved to GPU, using +// TensorViewRequestor. After calculation, the output needs to be moved back +// to CPU, using ToImageCalculator. The output is an ImageFrame. +mediapipe::CalculatorGraphConfig CreateGraphConfigForTest( + bool test_gpu, + const TensorsToSegmentationCalculatorOptions::Activation& activation) { + std::string pre_process = R"pb( + node { + calculator: "mediapipe.aimatter.TensorViewRequestor" + input_stream: "TENSORS:tensors" + output_stream: "TENSORS:tensors_gpu" + options { + [mediapipe.aimatter.TensorViewRequestorOptions.ext] { gpu {} } + } + } + )pb"; + std::string post_process = R"pb( + node { + calculator: "FromImageCalculator" + input_stream: "IMAGE:image_as_mask_gpu" + output_stream: "IMAGE_CPU:image_as_mask" + } + )pb"; + return mediapipe::ParseTextProtoOrDie( + absl::Substitute( + R"pb( + input_stream: "tensors" + input_stream: "size" $0 + node { + calculator: "TensorsToSegmentationCalculator" + input_stream: "TENSORS:tensors$1" + input_stream: "OUTPUT_SIZE:size" + output_stream: "MASK:image_as_mask$2" + options: { + [mediapipe.TensorsToSegmentationCalculatorOptions.ext] { + activation: $3 + gpu_origin: TOP_LEFT + } + } + } $4 + )pb", + test_gpu ? pre_process : "", test_gpu ? "_gpu" : "", + test_gpu ? "_gpu" : "", ActivationTypeToString(activation), + test_gpu ? post_process : "")); +} +} // namespace tensors_to_segmentation_utils +} // namespace mediapipe diff --git a/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.h b/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.h new file mode 100644 index 0000000000..abeda546b1 --- /dev/null +++ b/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.h @@ -0,0 +1,57 @@ +// 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_CALCULATORS_TENSOR_TENSORS_TO_SEGMENTATION_CALCULATOR_TEST_UTILS_H_ +#define MEDIAPIPE_CALCULATORS_TENSOR_TENSORS_TO_SEGMENTATION_CALCULATOR_TEST_UTILS_H_ + +#include +#include +#include +#include + +#include "mediapipe/calculators/tensor/tensors_to_segmentation_calculator.pb.h" +#include "mediapipe/framework/calculator.pb.h" + +namespace mediapipe { +namespace tensors_to_segmentation_utils { +std::string ActivationTypeToString( + const mediapipe::TensorsToSegmentationCalculatorOptions::Activation& + activation); + +std::vector ArrayFloatToUnsignedChar( + const std::vector& array); + +std::vector MakeRedAlphaMatrix(const std::vector& values); + +mediapipe::CalculatorGraphConfig CreateGraphConfigForTest( + bool test_gpu, + const mediapipe::TensorsToSegmentationCalculatorOptions::Activation& + activation); + +struct FormattingTestCase { + std::string test_name; + std::vector inputs; + std::vector expected_outputs; + mediapipe::TensorsToSegmentationCalculatorOptions::Activation activation; + int rows = 1; + int cols = 1; + int rows_new = 1; + int cols_new = 1; + int channels = 1; + double max_abs_diff = 1e-7; +}; +} // namespace tensors_to_segmentation_utils +} // namespace mediapipe + +#endif // MEDIAPIPE_CALCULATORS_TENSOR_TENSORS_TO_SEGMENTATION_CALCULATOR_TEST_UTILS_H_ diff --git a/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils_test.cc b/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils_test.cc new file mode 100644 index 0000000000..3f048c62da --- /dev/null +++ b/mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils_test.cc @@ -0,0 +1,50 @@ +// 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. + +#include "mediapipe/calculators/tensor/tensors_to_segmentation_calculator_test_utils.h" + +#include + +#include "mediapipe/calculators/tensor/tensors_to_segmentation_calculator.pb.h" +#include "mediapipe/framework/port/gtest.h" + +namespace mediapipe::tensors_to_segmentation_utils { +namespace { + +using Options = ::mediapipe::TensorsToSegmentationCalculatorOptions; + +TEST(TensorsToSegmentationCalculatorTestUtilsTest, + ActivationTypeToStringWorksCorrectly) { + EXPECT_EQ(ActivationTypeToString(Options::NONE), "NONE"); + EXPECT_EQ(ActivationTypeToString(Options::SIGMOID), "SIGMOID"); + EXPECT_EQ(ActivationTypeToString(Options::SOFTMAX), "SOFTMAX"); +} + +TEST(TensorsToSegmentationCalculatorTestUtilsTest, + ArrayFloatToUnsignedCharWorksCorrectly) { + std::vector input = {1.0, 2.0, 3.0}; + std::vector expected = {1, 2, 3}; + EXPECT_EQ(ArrayFloatToUnsignedChar(input), expected); +} + +TEST(TensorsToSegmentationCalculatorTestUtilsTest, + MakeRedAlphaMatrixWorksCorrectly) { + std::vector input = {1.0, 2.0, 3.0}; + std::vector expected = {1.0, 0.0, 0.0, 1.0, 2.0, 0.0, + 0.0, 2.0, 3.0, 0.0, 0.0, 3.0}; + EXPECT_EQ(MakeRedAlphaMatrix(input), expected); +} + +} // namespace +} // namespace mediapipe::tensors_to_segmentation_utils