Introduce LandmarksTransformationCalculator
PiperOrigin-RevId: 569050686
This commit is contained in:
parent
66a279418c
commit
9edb4cd753
|
@ -1575,3 +1575,44 @@ cc_test(
|
||||||
"@com_google_absl//absl/status",
|
"@com_google_absl//absl/status",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
mediapipe_proto_library(
|
||||||
|
name = "landmarks_transformation_calculator_proto",
|
||||||
|
srcs = ["landmarks_transformation_calculator.proto"],
|
||||||
|
deps = [
|
||||||
|
"//mediapipe/framework:calculator_options_proto",
|
||||||
|
"//mediapipe/framework:calculator_proto",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "landmarks_transformation_calculator",
|
||||||
|
srcs = ["landmarks_transformation_calculator.cc"],
|
||||||
|
hdrs = ["landmarks_transformation_calculator.h"],
|
||||||
|
deps = [
|
||||||
|
":landmarks_transformation_calculator_cc_proto",
|
||||||
|
"//mediapipe/framework:calculator_framework",
|
||||||
|
"//mediapipe/framework/api2:node",
|
||||||
|
"//mediapipe/framework/formats:landmark_cc_proto",
|
||||||
|
"//mediapipe/framework/port:ret_check",
|
||||||
|
"//mediapipe/framework/port:statusor",
|
||||||
|
],
|
||||||
|
alwayslink = 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "landmarks_transformation_calculator_test",
|
||||||
|
srcs = ["landmarks_transformation_calculator_test.cc"],
|
||||||
|
deps = [
|
||||||
|
":landmarks_transformation_calculator",
|
||||||
|
":landmarks_transformation_calculator_cc_proto",
|
||||||
|
"//mediapipe/framework:calculator_framework",
|
||||||
|
"//mediapipe/framework:calculator_runner",
|
||||||
|
"//mediapipe/framework:packet",
|
||||||
|
"//mediapipe/framework/formats:landmark_cc_proto",
|
||||||
|
"//mediapipe/framework/port:gtest_main",
|
||||||
|
"//mediapipe/framework/port:parse_text_proto",
|
||||||
|
"//mediapipe/framework/port:status_matchers",
|
||||||
|
"@com_google_absl//absl/strings",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
// 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/util/landmarks_transformation_calculator.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "mediapipe/calculators/util/landmarks_transformation_calculator.pb.h"
|
||||||
|
#include "mediapipe/framework/api2/node.h"
|
||||||
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/formats/landmark.pb.h"
|
||||||
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
|
#include "mediapipe/framework/port/statusor.h"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
namespace api2 {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
StatusOr<LandmarkList> NormalizeTranslation(const LandmarkList& in_landmarks) {
|
||||||
|
RET_CHECK_GT(in_landmarks.landmark_size(), 0);
|
||||||
|
|
||||||
|
double x_sum = 0.0f;
|
||||||
|
double y_sum = 0.0f;
|
||||||
|
double z_sum = 0.0f;
|
||||||
|
for (auto& in_landmark : in_landmarks.landmark()) {
|
||||||
|
x_sum += in_landmark.x();
|
||||||
|
y_sum += in_landmark.y();
|
||||||
|
z_sum += in_landmark.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
float x_mean = x_sum / in_landmarks.landmark_size();
|
||||||
|
float y_mean = y_sum / in_landmarks.landmark_size();
|
||||||
|
float z_mean = z_sum / in_landmarks.landmark_size();
|
||||||
|
|
||||||
|
LandmarkList out_landmarks;
|
||||||
|
for (auto& in_landmark : in_landmarks.landmark()) {
|
||||||
|
auto* out_landmark = out_landmarks.add_landmark();
|
||||||
|
*out_landmark = in_landmark;
|
||||||
|
out_landmark->set_x(in_landmark.x() - x_mean);
|
||||||
|
out_landmark->set_y(in_landmark.y() - y_mean);
|
||||||
|
out_landmark->set_z(in_landmark.z() - z_mean);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out_landmarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusOr<LandmarkList> FlipAxis(
|
||||||
|
const LandmarkList& in_landmarks,
|
||||||
|
const LandmarksTransformationCalculatorOptions::FlipAxis& options) {
|
||||||
|
float x_mul = options.flip_x() ? -1 : 1;
|
||||||
|
float y_mul = options.flip_y() ? -1 : 1;
|
||||||
|
float z_mul = options.flip_z() ? -1 : 1;
|
||||||
|
|
||||||
|
LandmarkList out_landmarks;
|
||||||
|
for (auto& in_landmark : in_landmarks.landmark()) {
|
||||||
|
auto* out_landmark = out_landmarks.add_landmark();
|
||||||
|
*out_landmark = in_landmark;
|
||||||
|
out_landmark->set_x(in_landmark.x() * x_mul);
|
||||||
|
out_landmark->set_y(in_landmark.y() * y_mul);
|
||||||
|
out_landmark->set_z(in_landmark.z() * z_mul);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out_landmarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class LandmarksTransformationCalculatorImpl
|
||||||
|
: public NodeImpl<LandmarksTransformationCalculator> {
|
||||||
|
public:
|
||||||
|
static absl::Status UpdateContract(CalculatorContract* cc) {
|
||||||
|
// Check that if options input stream is connected there should be no static
|
||||||
|
// options in calculator. Currently there is no such functionality, so we'll
|
||||||
|
// just check for the number of transforms.
|
||||||
|
if (kInOptions(cc).IsConnected()) {
|
||||||
|
RET_CHECK_EQ(cc->Options<LandmarksTransformationCalculatorOptions>()
|
||||||
|
.transformation_size(),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
absl::Status Open(CalculatorContext* cc) override {
|
||||||
|
options_ = cc->Options<LandmarksTransformationCalculatorOptions>();
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
absl::Status Process(CalculatorContext* cc) override {
|
||||||
|
if (kInLandmarks(cc).IsEmpty()) {
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get transformation options for either calculator parameters or input
|
||||||
|
// stream. Input stream has higher priority.
|
||||||
|
LandmarksTransformationCalculatorOptions options;
|
||||||
|
if (kInOptions(cc).IsConnected()) {
|
||||||
|
// If input stream is connected but is empty - use no transformations and
|
||||||
|
// return landmarks as is.
|
||||||
|
if (!kInOptions(cc).IsEmpty()) {
|
||||||
|
options = kInOptions(cc).Get();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
options = options_;
|
||||||
|
}
|
||||||
|
|
||||||
|
LandmarkList landmarks = kInLandmarks(cc).Get();
|
||||||
|
|
||||||
|
for (auto& transformation : options.transformation()) {
|
||||||
|
if (transformation.has_normalize_translation()) {
|
||||||
|
ASSIGN_OR_RETURN(landmarks, NormalizeTranslation(landmarks));
|
||||||
|
} else if (transformation.has_flip_axis()) {
|
||||||
|
ASSIGN_OR_RETURN(landmarks,
|
||||||
|
FlipAxis(landmarks, transformation.flip_axis()));
|
||||||
|
} else {
|
||||||
|
RET_CHECK_FAIL() << "Unknown landmarks transformation";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kOutLandmarks(cc).Send(std::move(landmarks));
|
||||||
|
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LandmarksTransformationCalculatorOptions options_;
|
||||||
|
};
|
||||||
|
MEDIAPIPE_NODE_IMPLEMENTATION(LandmarksTransformationCalculatorImpl);
|
||||||
|
|
||||||
|
} // namespace api2
|
||||||
|
} // namespace mediapipe
|
|
@ -0,0 +1,62 @@
|
||||||
|
// 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_UTIL_LANDMARKS_TRANSFORMATION_CALCULATOR_H_
|
||||||
|
#define MEDIAPIPE_CALCULATORS_UTIL_LANDMARKS_TRANSFORMATION_CALCULATOR_H_
|
||||||
|
|
||||||
|
#include "mediapipe/calculators/util/landmarks_transformation_calculator.pb.h"
|
||||||
|
#include "mediapipe/framework/api2/node.h"
|
||||||
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/formats/landmark.pb.h"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
namespace api2 {
|
||||||
|
|
||||||
|
// A calculator to transform landmarks.
|
||||||
|
//
|
||||||
|
// Input:
|
||||||
|
// LANDMARKS - LandmarkList
|
||||||
|
// Landmarks to transform.
|
||||||
|
//
|
||||||
|
// Output:
|
||||||
|
// LANDMARKS - LandmarkList
|
||||||
|
// Transformed landmarks.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// node {
|
||||||
|
// calculator: "LandmarksTransformationCalculator"
|
||||||
|
// input_stream: "LANDMARKS:in_landmarks"
|
||||||
|
// output_stream: "LANDMARKS:out_landmarks"
|
||||||
|
// options: {
|
||||||
|
// [mediapipe.LandmarksTransformationCalculatorOptions.ext] {
|
||||||
|
// transformation: { normalize_translation: {} }
|
||||||
|
// transformation: { flip_axis: { flip_x: true } }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
class LandmarksTransformationCalculator : public NodeIntf {
|
||||||
|
public:
|
||||||
|
static constexpr Input<mediapipe::LandmarkList> kInLandmarks{"LANDMARKS"};
|
||||||
|
static constexpr Input<
|
||||||
|
mediapipe::LandmarksTransformationCalculatorOptions>::Optional kInOptions{
|
||||||
|
"OPTIONS"};
|
||||||
|
static constexpr Output<mediapipe::LandmarkList> kOutLandmarks{"LANDMARKS"};
|
||||||
|
MEDIAPIPE_NODE_INTERFACE(LandmarksTransformationCalculator, kInLandmarks,
|
||||||
|
kInOptions, kOutLandmarks);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api2
|
||||||
|
} // namespace mediapipe
|
||||||
|
|
||||||
|
#endif // MEDIAPIPE_CALCULATORS_UTIL_LANDMARKS_TRANSFORMATION_CALCULATOR_H_
|
|
@ -0,0 +1,45 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package mediapipe;
|
||||||
|
|
||||||
|
import "mediapipe/framework/calculator.proto";
|
||||||
|
|
||||||
|
message LandmarksTransformationCalculatorOptions {
|
||||||
|
extend CalculatorOptions {
|
||||||
|
optional LandmarksTransformationCalculatorOptions ext = 421309928;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize translation so that center of mass is in (0, 0, 0).
|
||||||
|
message NormalizeTranslation {}
|
||||||
|
|
||||||
|
// Flip axis by multiplying coordinates along it by `-1`.
|
||||||
|
message FlipAxis {
|
||||||
|
optional bool flip_x = 1 [default = false];
|
||||||
|
optional bool flip_y = 2 [default = false];
|
||||||
|
optional bool flip_z = 3 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
message Transformation {
|
||||||
|
oneof transformation {
|
||||||
|
NormalizeTranslation normalize_translation = 1;
|
||||||
|
FlipAxis flip_axis = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transformations applied in given order.
|
||||||
|
repeated Transformation transformation = 1;
|
||||||
|
}
|
|
@ -0,0 +1,167 @@
|
||||||
|
// 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 <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/strings/substitute.h"
|
||||||
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
|
#include "mediapipe/framework/calculator_runner.h"
|
||||||
|
#include "mediapipe/framework/formats/landmark.pb.h"
|
||||||
|
#include "mediapipe/framework/packet.h"
|
||||||
|
#include "mediapipe/framework/port/gmock.h"
|
||||||
|
#include "mediapipe/framework/port/gtest.h"
|
||||||
|
#include "mediapipe/framework/port/parse_text_proto.h"
|
||||||
|
#include "mediapipe/framework/port/status_matchers.h"
|
||||||
|
|
||||||
|
namespace mediapipe {
|
||||||
|
namespace api2 {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using Node = ::mediapipe::CalculatorGraphConfig::Node;
|
||||||
|
|
||||||
|
Landmark CreateLandmark(float x, float y, float z) {
|
||||||
|
Landmark lmk;
|
||||||
|
lmk.set_x(x);
|
||||||
|
lmk.set_y(y);
|
||||||
|
lmk.set_z(z);
|
||||||
|
return lmk;
|
||||||
|
}
|
||||||
|
|
||||||
|
Landmark CreateLandmark(float x, float y, float z, float visibility,
|
||||||
|
float presence) {
|
||||||
|
Landmark lmk;
|
||||||
|
lmk.set_x(x);
|
||||||
|
lmk.set_y(y);
|
||||||
|
lmk.set_z(z);
|
||||||
|
lmk.set_visibility(visibility);
|
||||||
|
lmk.set_presence(presence);
|
||||||
|
return lmk;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LandmarksTransformationestCase {
|
||||||
|
std::string test_name;
|
||||||
|
std::string transformations;
|
||||||
|
std::vector<Landmark> in_landmarks;
|
||||||
|
std::vector<Landmark> out_landmarks;
|
||||||
|
};
|
||||||
|
|
||||||
|
using LandmarksTransformationest =
|
||||||
|
::testing::TestWithParam<LandmarksTransformationestCase>;
|
||||||
|
|
||||||
|
TEST_P(LandmarksTransformationest, LandmarksTransformationest) {
|
||||||
|
const LandmarksTransformationestCase& tc = GetParam();
|
||||||
|
|
||||||
|
// Prepare graph.
|
||||||
|
mediapipe::CalculatorRunner runner(ParseTextProtoOrDie<Node>(absl::Substitute(
|
||||||
|
R"(
|
||||||
|
calculator: "LandmarksTransformationCalculator"
|
||||||
|
input_stream: "LANDMARKS:in_landmarks"
|
||||||
|
output_stream: "LANDMARKS:out_landmarks"
|
||||||
|
options: {
|
||||||
|
[mediapipe.LandmarksTransformationCalculatorOptions.ext] {
|
||||||
|
$0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
tc.transformations)));
|
||||||
|
|
||||||
|
// In landmarks.
|
||||||
|
LandmarkList in_landmarks;
|
||||||
|
for (auto& lmk : tc.in_landmarks) {
|
||||||
|
*in_landmarks.add_landmark() = lmk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send landmarks to the graph.
|
||||||
|
runner.MutableInputs()
|
||||||
|
->Tag("LANDMARKS")
|
||||||
|
.packets.push_back(MakePacket<LandmarkList>(std::move(in_landmarks))
|
||||||
|
.At(mediapipe::Timestamp(0)));
|
||||||
|
|
||||||
|
// Run the graph.
|
||||||
|
MP_ASSERT_OK(runner.Run());
|
||||||
|
|
||||||
|
const auto& output_packets = runner.Outputs().Tag("LANDMARKS").packets;
|
||||||
|
EXPECT_EQ(1, output_packets.size());
|
||||||
|
|
||||||
|
const auto& out_landmarks = output_packets[0].Get<LandmarkList>();
|
||||||
|
EXPECT_EQ(out_landmarks.landmark_size(), tc.out_landmarks.size());
|
||||||
|
for (int i = 0; i < out_landmarks.landmark_size(); ++i) {
|
||||||
|
auto& lmk = out_landmarks.landmark(i);
|
||||||
|
auto& exp_lmk = tc.out_landmarks[i];
|
||||||
|
EXPECT_EQ(lmk.x(), exp_lmk.x()) << "Unexpected lmk[" << i << "].x";
|
||||||
|
EXPECT_EQ(lmk.y(), exp_lmk.y()) << "Unexpected lmk[" << i << "].y";
|
||||||
|
EXPECT_EQ(lmk.z(), exp_lmk.z()) << "Unexpected lmk[" << i << "].z";
|
||||||
|
if (exp_lmk.has_visibility()) {
|
||||||
|
EXPECT_EQ(lmk.visibility(), exp_lmk.visibility())
|
||||||
|
<< "Unexpected lmk[" << i << "].visibility";
|
||||||
|
}
|
||||||
|
if (exp_lmk.has_presence()) {
|
||||||
|
EXPECT_EQ(lmk.presence(), exp_lmk.presence())
|
||||||
|
<< "Unexpected lmk[" << i << "].presence";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
LandmarksTransformationests, LandmarksTransformationest,
|
||||||
|
testing::ValuesIn<LandmarksTransformationestCase>({
|
||||||
|
{"NoTransformations",
|
||||||
|
"",
|
||||||
|
{CreateLandmark(1, 2, 3), CreateLandmark(4, 5, 6)},
|
||||||
|
{CreateLandmark(1, 2, 3), CreateLandmark(4, 5, 6)}},
|
||||||
|
|
||||||
|
{"NormalizeTranslation_OneLandmark",
|
||||||
|
"transformation: { normalize_translation: {} }",
|
||||||
|
{CreateLandmark(2, 2, 2)},
|
||||||
|
{CreateLandmark(0, 0, 0)}},
|
||||||
|
{"NormalizeTranslation_TwoLandmarks",
|
||||||
|
"transformation: { normalize_translation: {} }",
|
||||||
|
{CreateLandmark(2, 2, 2), CreateLandmark(4, 4, 4)},
|
||||||
|
{CreateLandmark(-1, -1, -1), CreateLandmark(1, 1, 1)}},
|
||||||
|
{"NormalizeTranslation_ThreeLandmarks",
|
||||||
|
"transformation: { normalize_translation: {} }",
|
||||||
|
{CreateLandmark(2, 2, 2), CreateLandmark(4, 4, 4),
|
||||||
|
CreateLandmark(9, 9, 9)},
|
||||||
|
{CreateLandmark(-3, -3, -3), CreateLandmark(-1, -1, -1),
|
||||||
|
CreateLandmark(4, 4, 4)}},
|
||||||
|
{"NormalizeTranslation_VisibilityAndPresence",
|
||||||
|
"transformation: { normalize_translation: {} }",
|
||||||
|
{CreateLandmark(0, 0, 0, 4, 5)},
|
||||||
|
{CreateLandmark(0, 0, 0, 4, 5)}},
|
||||||
|
|
||||||
|
{"FlipAxis_X",
|
||||||
|
"transformation: { flip_axis: { flip_x: true } }",
|
||||||
|
{CreateLandmark(2, 2, 2)},
|
||||||
|
{CreateLandmark(-2, 2, 2)}},
|
||||||
|
{"FlipAxis_Y",
|
||||||
|
"transformation: { flip_axis: { flip_y: true } }",
|
||||||
|
{CreateLandmark(2, 2, 2)},
|
||||||
|
{CreateLandmark(2, -2, 2)}},
|
||||||
|
{"FlipAxis_Z",
|
||||||
|
"transformation: { flip_axis: { flip_z: true } }",
|
||||||
|
{CreateLandmark(2, 2, 2)},
|
||||||
|
{CreateLandmark(2, 2, -2)}},
|
||||||
|
{"FlipAxis_VisibilityAndPresence",
|
||||||
|
"transformation: { flip_axis: { flip_x: true } }",
|
||||||
|
{CreateLandmark(0, 0, 0, 4, 5)},
|
||||||
|
{CreateLandmark(0, 0, 0, 4, 5)}},
|
||||||
|
}),
|
||||||
|
[](const testing::TestParamInfo<LandmarksTransformationest::ParamType>&
|
||||||
|
info) { return info.param.test_name; });
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace api2
|
||||||
|
} // namespace mediapipe
|
Loading…
Reference in New Issue
Block a user