Initial test for TensorsToSegmentationCalculator

This test is a pass-through with no modification of the input tensor. CPU test.

PiperOrigin-RevId: 574210865
This commit is contained in:
Youchuan Hu 2023-10-17 11:20:10 -07:00 committed by Copybara-Service
parent dd215e00f5
commit de1b1b6b97
2 changed files with 195 additions and 0 deletions

View File

@ -1450,6 +1450,30 @@ cc_library(
alwayslink = 1, alwayslink = 1,
) )
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",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:calculator_runner",
"//mediapipe/framework:packet",
"//mediapipe/framework:timestamp",
"//mediapipe/framework/formats:image",
"//mediapipe/framework/formats:image_format_cc_proto",
"//mediapipe/framework/formats:image_opencv",
"//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",
"@com_google_googletest//:gtest_main",
],
)
cc_library( cc_library(
name = "tensors_dequantization_calculator", name = "tensors_dequantization_calculator",
srcs = ["tensors_dequantization_calculator.cc"], srcs = ["tensors_dequantization_calculator.cc"],

View File

@ -0,0 +1,171 @@
// 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 <memory>
#include <string>
#include <utility>
#include <vector>
#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/framework/calculator_framework.h"
#include "mediapipe/framework/calculator_runner.h"
#include "mediapipe/framework/formats/image.h"
#include "mediapipe/framework/formats/image_format.pb.h"
#include "mediapipe/framework/formats/image_opencv.h"
#include "mediapipe/framework/formats/rect.pb.h"
#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"
namespace mediapipe {
namespace {
using ::testing::SizeIs;
using ::testing::TestWithParam;
using Options = mediapipe::TensorsToSegmentationCalculatorOptions;
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<float> inputs;
std::vector<float> expected_outputs;
Options::Activation activation;
int rows;
int cols;
int channels;
};
using TensorsToSegmentationCalculatorTest = TestWithParam<FormattingTestCase>;
// Currently only useable for tests with no output resize.
TEST_P(TensorsToSegmentationCalculatorTest, ParameterizedTests) {
const FormattingTestCase& test_case = GetParam();
std::vector<float> inputs = test_case.inputs;
std::vector<float> expected_outputs = test_case.expected_outputs;
Options::Activation activation = test_case.activation;
int rows = test_case.rows;
int cols = test_case.cols;
int channels = test_case.channels;
std::string string_config = 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));
auto graph_config =
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(string_config);
std::vector<Packet> output_packets;
tool::AddVectorSink("image_as_mask", &graph_config, &output_packets);
CalculatorGraph graph;
MP_ASSERT_OK(graph.Initialize(graph_config));
MP_ASSERT_OK(graph.StartRun({}));
auto tensors = std::make_unique<std::vector<Tensor>>();
tensors->emplace_back(Tensor::ElementType::kFloat32,
Tensor::Shape{1, rows, cols, channels});
// We scope the tensor's GetCpuWriteView() call so that its lock is released
// before we pass it into the graph.
{
auto view = tensors->back().GetCpuWriteView();
float* tensor_buffer = view.buffer<float>();
for (int i = 0; i < inputs.size(); ++i) {
tensor_buffer[i] = inputs[i];
}
MP_ASSERT_OK(graph.AddPacketToInputStream(
"tensors", mediapipe::Adopt(tensors.release()).At(Timestamp(0))));
}
MP_ASSERT_OK(graph.AddPacketToInputStream(
"size",
mediapipe::Adopt(new std::pair<int, int>(rows, cols)).At(Timestamp(0))));
MP_ASSERT_OK(graph.WaitUntilIdle());
ASSERT_THAT(output_packets, SizeIs(1));
const Image& image_as_mask = output_packets[0].Get<Image>();
std::shared_ptr<cv::Mat> result_mat = formats::MatView(&image_as_mask);
EXPECT_EQ(result_mat->rows, rows);
EXPECT_EQ(result_mat->cols, cols);
EXPECT_EQ(result_mat->channels(), channels);
// Compare the real result with the expected result.
cv::Mat expected_result = cv::Mat(
rows, cols, CV_32FC1, const_cast<float*>(expected_outputs.data()));
cv::Mat diff;
cv::absdiff(*result_mat, expected_result, diff);
double max_val;
cv::minMaxLoc(diff, nullptr, &max_val);
// Expects the maximum absolute pixel-by-pixel difference is less than 1e-5.
// This delta is for passthorugh accuracy only.
EXPECT_LE(max_val, 1e-5);
MP_ASSERT_OK(graph.CloseInputStream("tensors"));
MP_ASSERT_OK(graph.CloseInputStream("size"));
MP_ASSERT_OK(graph.WaitUntilDone());
}
INSTANTIATE_TEST_SUITE_P(
TensorsToSegmentationCalculatorTests, TensorsToSegmentationCalculatorTest,
testing::ValuesIn<FormattingTestCase>({
{/*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},
/*expected_outputs=*/
{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},
/*activation=*/Options::NONE,
/*rows=*/4,
/*cols=*/4,
/*channels=*/1},
}),
[](const testing::TestParamInfo<
TensorsToSegmentationCalculatorTest::ParamType>& info) {
return info.param.test_name;
});
} // namespace
} // namespace mediapipe