GeometryPipelineCalculator support single face landmarks input.
PiperOrigin-RevId: 516701488
This commit is contained in:
parent
141cf843ae
commit
cafff14135
|
@ -60,6 +60,7 @@ cc_library(
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
"//mediapipe/framework/port:statusor",
|
"//mediapipe/framework/port:statusor",
|
||||||
|
"//mediapipe/tasks/cc:common",
|
||||||
"//mediapipe/tasks/cc/core:external_file_handler",
|
"//mediapipe/tasks/cc/core:external_file_handler",
|
||||||
"//mediapipe/tasks/cc/core/proto:external_file_cc_proto",
|
"//mediapipe/tasks/cc/core/proto:external_file_cc_proto",
|
||||||
"//mediapipe/tasks/cc/vision/face_geometry/libs:geometry_pipeline",
|
"//mediapipe/tasks/cc/vision/face_geometry/libs:geometry_pipeline",
|
||||||
|
@ -69,6 +70,7 @@ cc_library(
|
||||||
"//mediapipe/tasks/cc/vision/face_geometry/proto:geometry_pipeline_metadata_cc_proto",
|
"//mediapipe/tasks/cc/vision/face_geometry/proto:geometry_pipeline_metadata_cc_proto",
|
||||||
"//mediapipe/util:resource_util",
|
"//mediapipe/util:resource_util",
|
||||||
"@com_google_absl//absl/memory",
|
"@com_google_absl//absl/memory",
|
||||||
|
"@com_google_absl//absl/strings:str_format",
|
||||||
],
|
],
|
||||||
alwayslink = 1,
|
alwayslink = 1,
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,12 +18,14 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
|
#include "absl/strings/str_format.h"
|
||||||
#include "mediapipe/framework/calculator_framework.h"
|
#include "mediapipe/framework/calculator_framework.h"
|
||||||
#include "mediapipe/framework/formats/landmark.pb.h"
|
#include "mediapipe/framework/formats/landmark.pb.h"
|
||||||
#include "mediapipe/framework/port/ret_check.h"
|
#include "mediapipe/framework/port/ret_check.h"
|
||||||
#include "mediapipe/framework/port/status.h"
|
#include "mediapipe/framework/port/status.h"
|
||||||
#include "mediapipe/framework/port/status_macros.h"
|
#include "mediapipe/framework/port/status_macros.h"
|
||||||
#include "mediapipe/framework/port/statusor.h"
|
#include "mediapipe/framework/port/statusor.h"
|
||||||
|
#include "mediapipe/tasks/cc/common.h"
|
||||||
#include "mediapipe/tasks/cc/core/external_file_handler.h"
|
#include "mediapipe/tasks/cc/core/external_file_handler.h"
|
||||||
#include "mediapipe/tasks/cc/core/proto/external_file.pb.h"
|
#include "mediapipe/tasks/cc/core/proto/external_file.pb.h"
|
||||||
#include "mediapipe/tasks/cc/vision/face_geometry/calculators/geometry_pipeline_calculator.pb.h"
|
#include "mediapipe/tasks/cc/vision/face_geometry/calculators/geometry_pipeline_calculator.pb.h"
|
||||||
|
@ -41,13 +43,50 @@ static constexpr char kEnvironmentTag[] = "ENVIRONMENT";
|
||||||
static constexpr char kImageSizeTag[] = "IMAGE_SIZE";
|
static constexpr char kImageSizeTag[] = "IMAGE_SIZE";
|
||||||
static constexpr char kMultiFaceGeometryTag[] = "MULTI_FACE_GEOMETRY";
|
static constexpr char kMultiFaceGeometryTag[] = "MULTI_FACE_GEOMETRY";
|
||||||
static constexpr char kMultiFaceLandmarksTag[] = "MULTI_FACE_LANDMARKS";
|
static constexpr char kMultiFaceLandmarksTag[] = "MULTI_FACE_LANDMARKS";
|
||||||
|
static constexpr char kFaceGeometryTag[] = "FACE_GEOMETRY";
|
||||||
|
static constexpr char kFaceLandmarksTag[] = "FACE_LANDMARKS";
|
||||||
|
|
||||||
using ::mediapipe::tasks::vision::face_geometry::proto::Environment;
|
using ::mediapipe::tasks::vision::face_geometry::proto::Environment;
|
||||||
using ::mediapipe::tasks::vision::face_geometry::proto::FaceGeometry;
|
using ::mediapipe::tasks::vision::face_geometry::proto::FaceGeometry;
|
||||||
using ::mediapipe::tasks::vision::face_geometry::proto::
|
using ::mediapipe::tasks::vision::face_geometry::proto::
|
||||||
GeometryPipelineMetadata;
|
GeometryPipelineMetadata;
|
||||||
|
|
||||||
// A calculator that renders a visual effect for multiple faces.
|
absl::Status SanityCheck(CalculatorContract* cc) {
|
||||||
|
if (!(cc->Inputs().HasTag(kFaceLandmarksTag) ^
|
||||||
|
cc->Inputs().HasTag(kMultiFaceLandmarksTag))) {
|
||||||
|
return CreateStatusWithPayload(
|
||||||
|
absl::StatusCode::kInvalidArgument,
|
||||||
|
absl::StrFormat("Only one of %s and %s can be set at a time.",
|
||||||
|
kFaceLandmarksTag, kMultiFaceLandmarksTag));
|
||||||
|
}
|
||||||
|
if (!(cc->Outputs().HasTag(kFaceGeometryTag) ^
|
||||||
|
cc->Outputs().HasTag(kMultiFaceGeometryTag))) {
|
||||||
|
return CreateStatusWithPayload(
|
||||||
|
absl::StatusCode::kInvalidArgument,
|
||||||
|
absl::StrFormat("Only one of %s and %s can be set at a time.",
|
||||||
|
kFaceGeometryTag, kMultiFaceGeometryTag));
|
||||||
|
}
|
||||||
|
if (cc->Inputs().HasTag(kFaceLandmarksTag) !=
|
||||||
|
cc->Outputs().HasTag(kFaceGeometryTag)) {
|
||||||
|
return CreateStatusWithPayload(
|
||||||
|
absl::StatusCode::kInvalidArgument,
|
||||||
|
absl::StrFormat(
|
||||||
|
"%s and %s must both be set or neither be set and a time.",
|
||||||
|
kFaceLandmarksTag, kFaceGeometryTag));
|
||||||
|
}
|
||||||
|
if (cc->Inputs().HasTag(kMultiFaceLandmarksTag) !=
|
||||||
|
cc->Outputs().HasTag(kMultiFaceGeometryTag)) {
|
||||||
|
return CreateStatusWithPayload(
|
||||||
|
absl::StatusCode::kInvalidArgument,
|
||||||
|
absl::StrFormat(
|
||||||
|
"%s and %s must both be set or neither be set and a time.",
|
||||||
|
kMultiFaceLandmarksTag, kMultiFaceGeometryTag));
|
||||||
|
}
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// A calculator that renders a visual effect for multiple faces. Support single
|
||||||
|
// face landmarks or multiple face landmarks.
|
||||||
//
|
//
|
||||||
// Inputs:
|
// Inputs:
|
||||||
// IMAGE_SIZE (`std::pair<int, int>`, required):
|
// IMAGE_SIZE (`std::pair<int, int>`, required):
|
||||||
|
@ -58,8 +97,12 @@ using ::mediapipe::tasks::vision::face_geometry::proto::
|
||||||
// ratio. If used as-is, the resulting face geometry visualization should be
|
// ratio. If used as-is, the resulting face geometry visualization should be
|
||||||
// happening on a frame with the same ratio as well.
|
// happening on a frame with the same ratio as well.
|
||||||
//
|
//
|
||||||
// MULTI_FACE_LANDMARKS (`std::vector<NormalizedLandmarkList>`, required):
|
// MULTI_FACE_LANDMARKS (`std::vector<NormalizedLandmarkList>`, optional):
|
||||||
// A vector of face landmark lists.
|
// A vector of face landmark lists. If connected, the output stream
|
||||||
|
// MULTI_FACE_GEOMETRY must be connected.
|
||||||
|
// FACE_LANDMARKS (NormalizedLandmarkList, optional):
|
||||||
|
// A NormalizedLandmarkList of single face landmark lists. If connected, the
|
||||||
|
// output stream FACE_GEOMETRY must be connected.
|
||||||
//
|
//
|
||||||
// Input side packets:
|
// Input side packets:
|
||||||
// ENVIRONMENT (`proto::Environment`, required)
|
// ENVIRONMENT (`proto::Environment`, required)
|
||||||
|
@ -67,8 +110,10 @@ using ::mediapipe::tasks::vision::face_geometry::proto::
|
||||||
// as well as virtual camera parameters.
|
// as well as virtual camera parameters.
|
||||||
//
|
//
|
||||||
// Output:
|
// Output:
|
||||||
// MULTI_FACE_GEOMETRY (`std::vector<FaceGeometry>`, required):
|
// MULTI_FACE_GEOMETRY (`std::vector<FaceGeometry>`, optional):
|
||||||
// A vector of face geometry data.
|
// A vector of face geometry data if MULTI_FACE_LANDMARKS is connected .
|
||||||
|
// FACE_GEOMETRY (FaceGeometry, optional):
|
||||||
|
// A FaceGeometry of the face landmarks if FACE_LANDMARKS is connected.
|
||||||
//
|
//
|
||||||
// Options:
|
// Options:
|
||||||
// metadata_file (`ExternalFile`, optional):
|
// metadata_file (`ExternalFile`, optional):
|
||||||
|
@ -81,13 +126,21 @@ class GeometryPipelineCalculator : public CalculatorBase {
|
||||||
public:
|
public:
|
||||||
static absl::Status GetContract(CalculatorContract* cc) {
|
static absl::Status GetContract(CalculatorContract* cc) {
|
||||||
cc->InputSidePackets().Tag(kEnvironmentTag).Set<Environment>();
|
cc->InputSidePackets().Tag(kEnvironmentTag).Set<Environment>();
|
||||||
|
MP_RETURN_IF_ERROR(SanityCheck(cc));
|
||||||
cc->Inputs().Tag(kImageSizeTag).Set<std::pair<int, int>>();
|
cc->Inputs().Tag(kImageSizeTag).Set<std::pair<int, int>>();
|
||||||
cc->Inputs()
|
if (cc->Inputs().HasTag(kMultiFaceLandmarksTag)) {
|
||||||
.Tag(kMultiFaceLandmarksTag)
|
cc->Inputs()
|
||||||
.Set<std::vector<mediapipe::NormalizedLandmarkList>>();
|
.Tag(kMultiFaceLandmarksTag)
|
||||||
cc->Outputs().Tag(kMultiFaceGeometryTag).Set<std::vector<FaceGeometry>>();
|
.Set<std::vector<mediapipe::NormalizedLandmarkList>>();
|
||||||
|
cc->Outputs().Tag(kMultiFaceGeometryTag).Set<std::vector<FaceGeometry>>();
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
|
} else {
|
||||||
|
cc->Inputs()
|
||||||
|
.Tag(kFaceLandmarksTag)
|
||||||
|
.Set<mediapipe::NormalizedLandmarkList>();
|
||||||
|
cc->Outputs().Tag(kFaceGeometryTag).Set<FaceGeometry>();
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Status Open(CalculatorContext* cc) override {
|
absl::Status Open(CalculatorContext* cc) override {
|
||||||
|
@ -112,7 +165,6 @@ class GeometryPipelineCalculator : public CalculatorBase {
|
||||||
ASSIGN_OR_RETURN(geometry_pipeline_,
|
ASSIGN_OR_RETURN(geometry_pipeline_,
|
||||||
CreateGeometryPipeline(environment, metadata),
|
CreateGeometryPipeline(environment, metadata),
|
||||||
_ << "Failed to create a geometry pipeline!");
|
_ << "Failed to create a geometry pipeline!");
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,32 +173,54 @@ class GeometryPipelineCalculator : public CalculatorBase {
|
||||||
// to have a non-empty packet. In case this requirement is not met, there's
|
// to have a non-empty packet. In case this requirement is not met, there's
|
||||||
// nothing to be processed at the current timestamp.
|
// nothing to be processed at the current timestamp.
|
||||||
if (cc->Inputs().Tag(kImageSizeTag).IsEmpty() ||
|
if (cc->Inputs().Tag(kImageSizeTag).IsEmpty() ||
|
||||||
cc->Inputs().Tag(kMultiFaceLandmarksTag).IsEmpty()) {
|
(cc->Inputs().Tag(kMultiFaceLandmarksTag).IsEmpty() &&
|
||||||
|
cc->Inputs().Tag(kFaceLandmarksTag).IsEmpty())) {
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& image_size =
|
const auto& image_size =
|
||||||
cc->Inputs().Tag(kImageSizeTag).Get<std::pair<int, int>>();
|
cc->Inputs().Tag(kImageSizeTag).Get<std::pair<int, int>>();
|
||||||
const auto& multi_face_landmarks =
|
|
||||||
cc->Inputs()
|
|
||||||
.Tag(kMultiFaceLandmarksTag)
|
|
||||||
.Get<std::vector<mediapipe::NormalizedLandmarkList>>();
|
|
||||||
|
|
||||||
auto multi_face_geometry = absl::make_unique<std::vector<FaceGeometry>>();
|
if (cc->Inputs().HasTag(kMultiFaceLandmarksTag)) {
|
||||||
|
const auto& multi_face_landmarks =
|
||||||
|
cc->Inputs()
|
||||||
|
.Tag(kMultiFaceLandmarksTag)
|
||||||
|
.Get<std::vector<mediapipe::NormalizedLandmarkList>>();
|
||||||
|
|
||||||
ASSIGN_OR_RETURN(
|
auto multi_face_geometry = absl::make_unique<std::vector<FaceGeometry>>();
|
||||||
*multi_face_geometry,
|
|
||||||
geometry_pipeline_->EstimateFaceGeometry(
|
|
||||||
multi_face_landmarks, //
|
|
||||||
/*frame_width*/ image_size.first,
|
|
||||||
/*frame_height*/ image_size.second),
|
|
||||||
_ << "Failed to estimate face geometry for multiple faces!");
|
|
||||||
|
|
||||||
cc->Outputs()
|
ASSIGN_OR_RETURN(
|
||||||
.Tag(kMultiFaceGeometryTag)
|
*multi_face_geometry,
|
||||||
.AddPacket(mediapipe::Adopt<std::vector<FaceGeometry>>(
|
geometry_pipeline_->EstimateFaceGeometry(
|
||||||
multi_face_geometry.release())
|
multi_face_landmarks, //
|
||||||
.At(cc->InputTimestamp()));
|
/*frame_width*/ image_size.first,
|
||||||
|
/*frame_height*/ image_size.second),
|
||||||
|
_ << "Failed to estimate face geometry for multiple faces!");
|
||||||
|
|
||||||
|
cc->Outputs()
|
||||||
|
.Tag(kMultiFaceGeometryTag)
|
||||||
|
.AddPacket(mediapipe::Adopt<std::vector<FaceGeometry>>(
|
||||||
|
multi_face_geometry.release())
|
||||||
|
.At(cc->InputTimestamp()));
|
||||||
|
} else {
|
||||||
|
const auto& face_landmarks =
|
||||||
|
cc->Inputs()
|
||||||
|
.Tag(kMultiFaceLandmarksTag)
|
||||||
|
.Get<mediapipe::NormalizedLandmarkList>();
|
||||||
|
|
||||||
|
ASSIGN_OR_RETURN(
|
||||||
|
std::vector<FaceGeometry> multi_face_geometry,
|
||||||
|
geometry_pipeline_->EstimateFaceGeometry(
|
||||||
|
{face_landmarks}, //
|
||||||
|
/*frame_width*/ image_size.first,
|
||||||
|
/*frame_height*/ image_size.second),
|
||||||
|
_ << "Failed to estimate face geometry for multiple faces!");
|
||||||
|
|
||||||
|
cc->Outputs()
|
||||||
|
.Tag(kFaceGeometryTag)
|
||||||
|
.AddPacket(mediapipe::MakePacket<FaceGeometry>(multi_face_geometry[0])
|
||||||
|
.At(cc->InputTimestamp()));
|
||||||
|
}
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user