Project import generated by Copybara.
GitOrigin-RevId: 73d686c40057684f8bfaca285368bf1813f9fc26
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+3
@@ -10,6 +10,9 @@
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
|
||||
<!-- For profiling -->
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ android_binary(
|
||||
"//mediapipe/modules/face_detection:face_detection_short_range.tflite",
|
||||
"//mediapipe/modules/face_landmark:face_landmark.tflite",
|
||||
"//mediapipe/modules/hand_landmark:hand_landmark_full.tflite",
|
||||
"//mediapipe/modules/hand_landmark:hand_landmark_lite.tflite",
|
||||
"//mediapipe/modules/hand_landmark:handedness.txt",
|
||||
"//mediapipe/modules/holistic_landmark:hand_recrop.tflite",
|
||||
"//mediapipe/modules/pose_detection:pose_detection.tflite",
|
||||
|
||||
@@ -80,6 +80,7 @@ cc_library(
|
||||
"//mediapipe/framework/formats:location_data_cc_proto",
|
||||
"//mediapipe/framework/port:ret_check",
|
||||
"//mediapipe/framework/port:status",
|
||||
"@com_google_absl//absl/status",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "mediapipe/examples/desktop/autoflip/autoflip_messages.pb.h"
|
||||
#include "mediapipe/examples/desktop/autoflip/calculators/content_zooming_calculator.pb.h"
|
||||
#include "mediapipe/examples/desktop/autoflip/calculators/content_zooming_calculator_state.h"
|
||||
@@ -41,6 +42,7 @@ constexpr char kFirstCropRect[] = "FIRST_CROP_RECT";
|
||||
// Can be used to control whether an animated zoom should actually performed
|
||||
// (configured through option us_to_first_rect). If provided, a non-zero integer
|
||||
// will allow the animated zoom to be used when the first detections arrive.
|
||||
// Applies to first detection only.
|
||||
constexpr char kAnimateZoom[] = "ANIMATE_ZOOM";
|
||||
// Can be used to control the maximum zoom; note that it is re-evaluated only
|
||||
// upon change of input resolution. A value of 100 disables zooming and is the
|
||||
@@ -112,6 +114,16 @@ class ContentZoomingCalculator : public CalculatorBase {
|
||||
int* pan_offset, int* height);
|
||||
// Sets max_frame_value_ and target_aspect_
|
||||
absl::Status UpdateAspectAndMax();
|
||||
// Smooth camera path
|
||||
absl::Status SmoothAndClampPath(int target_width, int target_height,
|
||||
float path_width, float path_height,
|
||||
float* path_offset_x, float* path_offset_y);
|
||||
// Compute box containing all detections.
|
||||
absl::Status GetDetectionsBox(mediapipe::CalculatorContext* cc, float* xmin,
|
||||
float* xmax, float* ymin, float* ymax,
|
||||
bool* only_required_found,
|
||||
bool* has_detections);
|
||||
|
||||
ContentZoomingCalculatorOptions options_;
|
||||
// Detection frame width/height.
|
||||
int frame_height_;
|
||||
@@ -537,68 +549,13 @@ absl::Status ContentZoomingCalculator::Process(
|
||||
UpdateForResolutionChange(cc, frame_width, frame_height));
|
||||
}
|
||||
|
||||
bool only_required_found = false;
|
||||
|
||||
// Compute the box that contains all "is_required" detections.
|
||||
float xmin = 1, ymin = 1, xmax = 0, ymax = 0;
|
||||
if (cc->Inputs().HasTag(kSalientRegions)) {
|
||||
auto detection_set = cc->Inputs().Tag(kSalientRegions).Get<DetectionSet>();
|
||||
for (const auto& region : detection_set.detections()) {
|
||||
if (!region.only_required()) {
|
||||
continue;
|
||||
}
|
||||
only_required_found = true;
|
||||
MP_RETURN_IF_ERROR(UpdateRanges(
|
||||
region, options_.detection_shift_vertical(),
|
||||
options_.detection_shift_horizontal(), &xmin, &xmax, &ymin, &ymax));
|
||||
}
|
||||
}
|
||||
|
||||
if (cc->Inputs().HasTag(kDetections)) {
|
||||
if (cc->Inputs().Tag(kDetections).IsEmpty()) {
|
||||
if (last_only_required_detection_ == 0) {
|
||||
// If no detections are available and we never had any,
|
||||
// simply return the full-image rectangle as crop-rect.
|
||||
if (cc->Outputs().HasTag(kCropRect)) {
|
||||
auto default_rect = absl::make_unique<mediapipe::Rect>();
|
||||
default_rect->set_x_center(frame_width_ / 2);
|
||||
default_rect->set_y_center(frame_height_ / 2);
|
||||
default_rect->set_width(frame_width_);
|
||||
default_rect->set_height(frame_height_);
|
||||
cc->Outputs().Tag(kCropRect).Add(default_rect.release(),
|
||||
Timestamp(cc->InputTimestamp()));
|
||||
}
|
||||
if (cc->Outputs().HasTag(kNormalizedCropRect)) {
|
||||
auto default_rect = absl::make_unique<mediapipe::NormalizedRect>();
|
||||
default_rect->set_x_center(0.5);
|
||||
default_rect->set_y_center(0.5);
|
||||
default_rect->set_width(1.0);
|
||||
default_rect->set_height(1.0);
|
||||
cc->Outputs()
|
||||
.Tag(kNormalizedCropRect)
|
||||
.Add(default_rect.release(), Timestamp(cc->InputTimestamp()));
|
||||
}
|
||||
// Also provide a first crop rect: in this case a zero-sized one.
|
||||
if (cc->Outputs().HasTag(kFirstCropRect)) {
|
||||
cc->Outputs()
|
||||
.Tag(kFirstCropRect)
|
||||
.Add(new mediapipe::NormalizedRect(),
|
||||
Timestamp(cc->InputTimestamp()));
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
} else {
|
||||
auto raw_detections = cc->Inputs()
|
||||
.Tag(kDetections)
|
||||
.Get<std::vector<mediapipe::Detection>>();
|
||||
for (const auto& detection : raw_detections) {
|
||||
only_required_found = true;
|
||||
MP_RETURN_IF_ERROR(UpdateRanges(
|
||||
detection, options_.detection_shift_vertical(),
|
||||
options_.detection_shift_horizontal(), &xmin, &xmax, &ymin, &ymax));
|
||||
}
|
||||
}
|
||||
}
|
||||
bool only_required_found = false;
|
||||
bool has_detections = true;
|
||||
MP_RETURN_IF_ERROR(GetDetectionsBox(cc, &xmin, &xmax, &ymin, &ymax,
|
||||
&only_required_found, &has_detections));
|
||||
if (!has_detections) return absl::OkStatus();
|
||||
|
||||
const bool may_start_animation = (options_.us_to_first_rect() != 0) &&
|
||||
(!cc->Inputs().HasTag(kAnimateZoom) ||
|
||||
@@ -656,7 +613,8 @@ absl::Status ContentZoomingCalculator::Process(
|
||||
path_solver_zoom_->ClearHistory();
|
||||
}
|
||||
const bool camera_active =
|
||||
is_animating || pan_state || tilt_state || zoom_state;
|
||||
is_animating || ((pan_state || tilt_state || zoom_state) &&
|
||||
!options_.disable_animations());
|
||||
// Waiting for first rect before setting any value of the camera active flag
|
||||
// so we avoid setting it to false during initialization.
|
||||
if (cc->Outputs().HasTag(kCameraActive) &&
|
||||
@@ -666,17 +624,26 @@ absl::Status ContentZoomingCalculator::Process(
|
||||
.AddPacket(MakePacket<bool>(camera_active).At(cc->InputTimestamp()));
|
||||
}
|
||||
|
||||
// Skip the path solvers to the final destination if not animating.
|
||||
const bool disable_animations =
|
||||
options_.disable_animations() && path_solver_zoom_->IsInitialized();
|
||||
if (disable_animations) {
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->SetState(height));
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->SetState(offset_y));
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->SetState(offset_x));
|
||||
}
|
||||
|
||||
// Compute smoothed zoom camera path.
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->AddObservation(
|
||||
height, cc->InputTimestamp().Microseconds()));
|
||||
float path_height;
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->GetState(&path_height));
|
||||
float path_width = path_height * target_aspect_;
|
||||
const float path_width = path_height * target_aspect_;
|
||||
|
||||
// Update pixel-per-degree value for pan/tilt.
|
||||
int target_height;
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->GetTargetPosition(&target_height));
|
||||
int target_width = target_height * target_aspect_;
|
||||
const int target_width = target_height * target_aspect_;
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->UpdatePixelsPerDegree(
|
||||
static_cast<float>(target_width) / kFieldOfView));
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->UpdatePixelsPerDegree(
|
||||
@@ -692,66 +659,16 @@ absl::Status ContentZoomingCalculator::Process(
|
||||
float path_offset_y;
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->GetState(&path_offset_y));
|
||||
|
||||
float delta_height;
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->GetDeltaState(&delta_height));
|
||||
int delta_width = delta_height * target_aspect_;
|
||||
|
||||
// Smooth centering when zooming out.
|
||||
float remaining_width = target_width - path_width;
|
||||
int width_space = frame_width_ - target_width;
|
||||
if (abs(path_offset_x - frame_width_ / 2) >
|
||||
width_space / 2 + kPixelTolerance &&
|
||||
remaining_width > kPixelTolerance) {
|
||||
float required_width =
|
||||
abs(path_offset_x - frame_width_ / 2) - width_space / 2;
|
||||
if (path_offset_x < frame_width_ / 2) {
|
||||
path_offset_x += delta_width * (required_width / remaining_width);
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->SetState(path_offset_x));
|
||||
} else {
|
||||
path_offset_x -= delta_width * (required_width / remaining_width);
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->SetState(path_offset_x));
|
||||
}
|
||||
}
|
||||
|
||||
float remaining_height = target_height - path_height;
|
||||
int height_space = frame_height_ - target_height;
|
||||
if (abs(path_offset_y - frame_height_ / 2) >
|
||||
height_space / 2 + kPixelTolerance &&
|
||||
remaining_height > kPixelTolerance) {
|
||||
float required_height =
|
||||
abs(path_offset_y - frame_height_ / 2) - height_space / 2;
|
||||
if (path_offset_y < frame_height_ / 2) {
|
||||
path_offset_y += delta_height * (required_height / remaining_height);
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->SetState(path_offset_y));
|
||||
} else {
|
||||
path_offset_y -= delta_height * (required_height / remaining_height);
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->SetState(path_offset_y));
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent box from extending beyond the image after camera smoothing.
|
||||
if (path_offset_y - ceil(path_height / 2.0) < 0) {
|
||||
path_offset_y = ceil(path_height / 2.0);
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->SetState(path_offset_y));
|
||||
} else if (path_offset_y + ceil(path_height / 2.0) > frame_height_) {
|
||||
path_offset_y = frame_height_ - ceil(path_height / 2.0);
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->SetState(path_offset_y));
|
||||
}
|
||||
|
||||
if (path_offset_x - ceil(path_width / 2.0) < 0) {
|
||||
path_offset_x = ceil(path_width / 2.0);
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->SetState(path_offset_x));
|
||||
} else if (path_offset_x + ceil(path_width / 2.0) > frame_width_) {
|
||||
path_offset_x = frame_width_ - ceil(path_width / 2.0);
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->SetState(path_offset_x));
|
||||
}
|
||||
|
||||
// Convert to top/bottom borders to remove.
|
||||
int path_top = path_offset_y - path_height / 2;
|
||||
int path_bottom = frame_height_ - (path_offset_y + path_height / 2);
|
||||
// Update path.
|
||||
MP_RETURN_IF_ERROR(SmoothAndClampPath(target_width, target_height, path_width,
|
||||
path_height, &path_offset_x,
|
||||
&path_offset_y));
|
||||
|
||||
// Transmit result downstream to scenecroppingcalculator.
|
||||
if (cc->Outputs().HasTag(kDetectedBorders)) {
|
||||
// Convert to top/bottom borders to remove.
|
||||
const int path_top = path_offset_y - path_height / 2;
|
||||
const int path_bottom = frame_height_ - (path_offset_y + path_height / 2);
|
||||
std::unique_ptr<StaticFeatures> features =
|
||||
absl::make_unique<StaticFeatures>();
|
||||
MakeStaticFeatures(path_top, path_bottom, frame_width_, frame_height_,
|
||||
@@ -798,8 +715,8 @@ absl::Status ContentZoomingCalculator::Process(
|
||||
if (cc->Outputs().HasTag(kNormalizedCropRect)) {
|
||||
std::unique_ptr<mediapipe::NormalizedRect> gpu_rect =
|
||||
absl::make_unique<mediapipe::NormalizedRect>();
|
||||
float float_frame_width = static_cast<float>(frame_width_);
|
||||
float float_frame_height = static_cast<float>(frame_height_);
|
||||
const float float_frame_width = static_cast<float>(frame_width_);
|
||||
const float float_frame_height = static_cast<float>(frame_height_);
|
||||
if (is_animating) {
|
||||
auto rect =
|
||||
GetAnimationRect(frame_width, frame_height, cc->InputTimestamp());
|
||||
@@ -829,5 +746,130 @@ absl::Status ContentZoomingCalculator::Process(
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ContentZoomingCalculator::SmoothAndClampPath(
|
||||
int target_width, int target_height, float path_width, float path_height,
|
||||
float* path_offset_x, float* path_offset_y) {
|
||||
float delta_height;
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->GetDeltaState(&delta_height));
|
||||
const int delta_width = delta_height * target_aspect_;
|
||||
|
||||
// Smooth centering when zooming out.
|
||||
const float remaining_width = target_width - path_width;
|
||||
const int width_space = frame_width_ - target_width;
|
||||
if (abs(*path_offset_x - frame_width_ / 2) >
|
||||
width_space / 2 + kPixelTolerance &&
|
||||
remaining_width > kPixelTolerance) {
|
||||
const float required_width =
|
||||
abs(*path_offset_x - frame_width_ / 2) - width_space / 2;
|
||||
if (*path_offset_x < frame_width_ / 2) {
|
||||
*path_offset_x += delta_width * (required_width / remaining_width);
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->SetState(*path_offset_x));
|
||||
} else {
|
||||
*path_offset_x -= delta_width * (required_width / remaining_width);
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->SetState(*path_offset_x));
|
||||
}
|
||||
}
|
||||
|
||||
const float remaining_height = target_height - path_height;
|
||||
const int height_space = frame_height_ - target_height;
|
||||
if (abs(*path_offset_y - frame_height_ / 2) >
|
||||
height_space / 2 + kPixelTolerance &&
|
||||
remaining_height > kPixelTolerance) {
|
||||
const float required_height =
|
||||
abs(*path_offset_y - frame_height_ / 2) - height_space / 2;
|
||||
if (*path_offset_y < frame_height_ / 2) {
|
||||
*path_offset_y += delta_height * (required_height / remaining_height);
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->SetState(*path_offset_y));
|
||||
} else {
|
||||
*path_offset_y -= delta_height * (required_height / remaining_height);
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->SetState(*path_offset_y));
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent box from extending beyond the image after camera smoothing.
|
||||
if (*path_offset_y - ceil(path_height / 2.0) < 0) {
|
||||
*path_offset_y = ceil(path_height / 2.0);
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->SetState(*path_offset_y));
|
||||
} else if (*path_offset_y + ceil(path_height / 2.0) > frame_height_) {
|
||||
*path_offset_y = frame_height_ - ceil(path_height / 2.0);
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->SetState(*path_offset_y));
|
||||
}
|
||||
|
||||
if (*path_offset_x - ceil(path_width / 2.0) < 0) {
|
||||
*path_offset_x = ceil(path_width / 2.0);
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->SetState(*path_offset_x));
|
||||
} else if (*path_offset_x + ceil(path_width / 2.0) > frame_width_) {
|
||||
*path_offset_x = frame_width_ - ceil(path_width / 2.0);
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->SetState(*path_offset_x));
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ContentZoomingCalculator::GetDetectionsBox(
|
||||
mediapipe::CalculatorContext* cc, float* xmin, float* xmax, float* ymin,
|
||||
float* ymax, bool* only_required_found, bool* has_detections) {
|
||||
if (cc->Inputs().HasTag(kSalientRegions)) {
|
||||
auto detection_set = cc->Inputs().Tag(kSalientRegions).Get<DetectionSet>();
|
||||
for (const auto& region : detection_set.detections()) {
|
||||
if (!region.only_required()) {
|
||||
continue;
|
||||
}
|
||||
*only_required_found = true;
|
||||
MP_RETURN_IF_ERROR(UpdateRanges(
|
||||
region, options_.detection_shift_vertical(),
|
||||
options_.detection_shift_horizontal(), xmin, xmax, ymin, ymax));
|
||||
}
|
||||
}
|
||||
|
||||
if (cc->Inputs().HasTag(kDetections)) {
|
||||
if (cc->Inputs().Tag(kDetections).IsEmpty()) {
|
||||
if (last_only_required_detection_ == 0) {
|
||||
// If no detections are available and we never had any,
|
||||
// simply return the full-image rectangle as crop-rect.
|
||||
if (cc->Outputs().HasTag(kCropRect)) {
|
||||
auto default_rect = absl::make_unique<mediapipe::Rect>();
|
||||
default_rect->set_x_center(frame_width_ / 2);
|
||||
default_rect->set_y_center(frame_height_ / 2);
|
||||
default_rect->set_width(frame_width_);
|
||||
default_rect->set_height(frame_height_);
|
||||
cc->Outputs().Tag(kCropRect).Add(default_rect.release(),
|
||||
Timestamp(cc->InputTimestamp()));
|
||||
}
|
||||
if (cc->Outputs().HasTag(kNormalizedCropRect)) {
|
||||
auto default_rect = absl::make_unique<mediapipe::NormalizedRect>();
|
||||
default_rect->set_x_center(0.5);
|
||||
default_rect->set_y_center(0.5);
|
||||
default_rect->set_width(1.0);
|
||||
default_rect->set_height(1.0);
|
||||
cc->Outputs()
|
||||
.Tag(kNormalizedCropRect)
|
||||
.Add(default_rect.release(), Timestamp(cc->InputTimestamp()));
|
||||
}
|
||||
// Also provide a first crop rect: in this case a zero-sized one.
|
||||
if (cc->Outputs().HasTag(kFirstCropRect)) {
|
||||
cc->Outputs()
|
||||
.Tag(kFirstCropRect)
|
||||
.Add(new mediapipe::NormalizedRect(),
|
||||
Timestamp(cc->InputTimestamp()));
|
||||
}
|
||||
*has_detections = false;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
} else {
|
||||
auto raw_detections = cc->Inputs()
|
||||
.Tag(kDetections)
|
||||
.Get<std::vector<mediapipe::Detection>>();
|
||||
for (const auto& detection : raw_detections) {
|
||||
*only_required_found = true;
|
||||
MP_RETURN_IF_ERROR(UpdateRanges(
|
||||
detection, options_.detection_shift_vertical(),
|
||||
options_.detection_shift_horizontal(), xmin, xmax, ymin, ymax));
|
||||
}
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -19,7 +19,7 @@ package mediapipe.autoflip;
|
||||
import "mediapipe/examples/desktop/autoflip/quality/kinematic_path_solver.proto";
|
||||
import "mediapipe/framework/calculator.proto";
|
||||
|
||||
// NextTag: 18
|
||||
// NextTag: 19
|
||||
message ContentZoomingCalculatorOptions {
|
||||
extend mediapipe.CalculatorOptions {
|
||||
optional ContentZoomingCalculatorOptions ext = 313091992;
|
||||
@@ -71,6 +71,12 @@ message ContentZoomingCalculatorOptions {
|
||||
// us_to_first_rect time budget.
|
||||
optional int64 us_to_first_rect_delay = 16 [default = 0];
|
||||
|
||||
// When true, this flag disables animating camera motions,
|
||||
// and cuts directly to final target position.
|
||||
// Does not apply to the first instance (first detection will still animate).
|
||||
// Use "ANIMATE_ZOOM" input stream to control the first animation.
|
||||
optional bool disable_animations = 18;
|
||||
|
||||
// Deprecated parameters
|
||||
optional KinematicOptions kinematic_options = 2 [deprecated = true];
|
||||
optional int64 min_motion_to_reframe = 4 [deprecated = true];
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ constexpr char kRegionsTag[] = "REGIONS";
|
||||
constexpr char kDetectionsTag[] = "DETECTIONS";
|
||||
|
||||
// Converts an object detection to a autoflip SignalType. Returns true if the
|
||||
// std::string label has a autoflip label.
|
||||
// string label has a autoflip label.
|
||||
bool MatchType(const std::string& label, SignalType* type) {
|
||||
if (label == "person") {
|
||||
type->set_standard(SignalType::HUMAN);
|
||||
|
||||
@@ -182,7 +182,7 @@ namespace {
|
||||
absl::Status ParseAspectRatioString(const std::string& aspect_ratio_string,
|
||||
double* aspect_ratio) {
|
||||
std::string error_msg =
|
||||
"Aspect ratio std::string must be in the format of 'width:height', e.g. "
|
||||
"Aspect ratio string must be in the format of 'width:height', e.g. "
|
||||
"'1:1' or '5:4', your input was " +
|
||||
aspect_ratio_string;
|
||||
auto pos = aspect_ratio_string.find(':');
|
||||
|
||||
@@ -4,6 +4,7 @@ constexpr float kMinVelocity = 0.5;
|
||||
|
||||
namespace mediapipe {
|
||||
namespace autoflip {
|
||||
|
||||
namespace {
|
||||
int Median(const std::deque<std::pair<uint64, int>>& positions_raw) {
|
||||
std::deque<int> positions;
|
||||
@@ -16,6 +17,7 @@ int Median(const std::deque<std::pair<uint64, int>>& positions_raw) {
|
||||
return positions[n];
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool KinematicPathSolver::IsMotionTooSmall(double delta_degs) {
|
||||
if (options_.has_min_motion_to_reframe()) {
|
||||
return abs(delta_degs) < options_.min_motion_to_reframe();
|
||||
@@ -25,7 +27,9 @@ bool KinematicPathSolver::IsMotionTooSmall(double delta_degs) {
|
||||
return abs(delta_degs) < options_.min_motion_to_reframe_lower();
|
||||
}
|
||||
}
|
||||
|
||||
void KinematicPathSolver::ClearHistory() { raw_positions_at_time_.clear(); }
|
||||
|
||||
absl::Status KinematicPathSolver::PredictMotionState(int position,
|
||||
const uint64 time_us,
|
||||
bool* state) {
|
||||
@@ -48,6 +52,9 @@ absl::Status KinematicPathSolver::PredictMotionState(int position,
|
||||
}
|
||||
|
||||
int filtered_position = Median(raw_positions_at_time_copy);
|
||||
filtered_position =
|
||||
std::clamp(filtered_position, min_location_, max_location_);
|
||||
|
||||
double delta_degs =
|
||||
(filtered_position - current_position_px_) / pixels_per_degree_;
|
||||
|
||||
@@ -59,6 +66,9 @@ absl::Status KinematicPathSolver::PredictMotionState(int position,
|
||||
// If the motion is smaller than the reframe_window and camera is moving,
|
||||
// don't use the update.
|
||||
*state = false;
|
||||
} else if (prior_position_px_ == current_position_px_ && motion_state_) {
|
||||
// Camera isn't actually moving. Likely face is past bounds.
|
||||
*state = false;
|
||||
} else {
|
||||
// Apply new position, plus the reframe window size.
|
||||
*state = true;
|
||||
@@ -66,6 +76,7 @@ absl::Status KinematicPathSolver::PredictMotionState(int position,
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status KinematicPathSolver::AddObservation(int position,
|
||||
const uint64 time_us) {
|
||||
if (!initialized_) {
|
||||
@@ -181,18 +192,22 @@ absl::Status KinematicPathSolver::AddObservation(int position,
|
||||
}
|
||||
|
||||
// Time and position updates.
|
||||
double delta_t = (time_us - current_time_) / 1000000.0;
|
||||
double delta_t_sec = (time_us - current_time_) / 1000000.0;
|
||||
if (options_.max_delta_time_sec() > 0) {
|
||||
// If updates are very infrequent, then limit the max time difference.
|
||||
delta_t_sec = fmin(delta_t_sec, options_.max_delta_time_sec());
|
||||
}
|
||||
// Time since last state/prediction update, smoothed by
|
||||
// mean_period_update_rate.
|
||||
if (mean_delta_t_ < 0) {
|
||||
mean_delta_t_ = delta_t;
|
||||
mean_delta_t_ = delta_t_sec;
|
||||
} else {
|
||||
mean_delta_t_ = mean_delta_t_ * (1 - options_.mean_period_update_rate()) +
|
||||
delta_t * options_.mean_period_update_rate();
|
||||
delta_t_sec * options_.mean_period_update_rate();
|
||||
}
|
||||
|
||||
// Observed velocity and then weighted update of this velocity.
|
||||
double observed_velocity = delta_degs / delta_t;
|
||||
// Observed velocity and then weighted update of this velocity (deg/sec).
|
||||
double observed_velocity = delta_degs / delta_t_sec;
|
||||
double update_rate = std::min(mean_delta_t_ / options_.update_rate_seconds(),
|
||||
options_.max_update_rate());
|
||||
double updated_velocity = current_velocity_deg_per_s_ * (1 - update_rate) +
|
||||
@@ -253,7 +268,8 @@ absl::Status KinematicPathSolver::GetDeltaState(float* delta_position) {
|
||||
|
||||
absl::Status KinematicPathSolver::SetState(const float position) {
|
||||
RET_CHECK(initialized_) << "SetState called before first observation added.";
|
||||
current_position_px_ = position;
|
||||
current_position_px_ = std::clamp(position, static_cast<float>(min_location_),
|
||||
static_cast<float>(max_location_));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,8 @@ class KinematicPathSolver {
|
||||
// Provides the change in position from last state.
|
||||
absl::Status GetDeltaState(float* delta_position);
|
||||
|
||||
bool IsInitialized() { return initialized_; }
|
||||
|
||||
private:
|
||||
// Tuning options.
|
||||
KinematicOptions options_;
|
||||
|
||||
@@ -31,6 +31,9 @@ message KinematicOptions {
|
||||
optional int64 filtering_time_window_us = 7 [default = 0];
|
||||
// Weighted update of average period, used for motion updates.
|
||||
optional float mean_period_update_rate = 8 [default = 0.25];
|
||||
// When set, caps the maximum time difference (seconds) calculated between new
|
||||
// updates/observations. Useful when updates come very infrequently.
|
||||
optional double max_delta_time_sec = 13;
|
||||
// Scale factor for max velocity, to be multiplied by the distance from center
|
||||
// in degrees. Cannot be used with max_velocity and must be used with
|
||||
// max_velocity_shift.
|
||||
|
||||
@@ -419,6 +419,13 @@ TEST(KinematicPathSolverTest, PassSetPosition) {
|
||||
MP_ASSERT_OK(solver.SetState(400));
|
||||
MP_ASSERT_OK(solver.GetState(&state));
|
||||
EXPECT_FLOAT_EQ(state, 400);
|
||||
// Expect to stay in bounds.
|
||||
MP_ASSERT_OK(solver.SetState(600));
|
||||
MP_ASSERT_OK(solver.GetState(&state));
|
||||
EXPECT_FLOAT_EQ(state, 500);
|
||||
MP_ASSERT_OK(solver.SetState(-100));
|
||||
MP_ASSERT_OK(solver.GetState(&state));
|
||||
EXPECT_FLOAT_EQ(state, 0);
|
||||
}
|
||||
TEST(KinematicPathSolverTest, PassBorderTest) {
|
||||
KinematicOptions options;
|
||||
|
||||
@@ -83,7 +83,7 @@ void PolynomialRegressionPathSolver::AddCostFunctionToProblem(
|
||||
const double in, const double out, Problem* problem, double* a, double* b,
|
||||
double* c, double* d, double* k) {
|
||||
// Creating a cost function, with 1D residual and 5 1D parameter blocks. This
|
||||
// is what the "1, 1, 1, 1, 1, 1" std::string below means.
|
||||
// is what the "1, 1, 1, 1, 1, 1" string below means.
|
||||
CostFunction* cost_function =
|
||||
new AutoDiffCostFunction<PolynomialResidual, 1, 1, 1, 1, 1, 1>(
|
||||
new PolynomialResidual(in, out));
|
||||
|
||||
@@ -55,7 +55,8 @@ class SceneCameraMotionAnalyzer {
|
||||
scene_camera_motion_analyzer_options)
|
||||
: options_(scene_camera_motion_analyzer_options),
|
||||
time_since_last_salient_region_us_(0),
|
||||
has_solid_color_background_(false) {}
|
||||
has_solid_color_background_(false),
|
||||
total_scene_frames_(0) {}
|
||||
|
||||
~SceneCameraMotionAnalyzer() {}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ absl::Status PrintHelloWorld() {
|
||||
ASSIGN_OR_RETURN(OutputStreamPoller poller,
|
||||
graph.AddOutputStreamPoller("out"));
|
||||
MP_RETURN_IF_ERROR(graph.StartRun({}));
|
||||
// Give 10 input packets that contains the same std::string "Hello World!".
|
||||
// Give 10 input packets that contains the same string "Hello World!".
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
MP_RETURN_IF_ERROR(graph.AddPacketToInputStream(
|
||||
"in", MakePacket<std::string>("Hello World!").At(Timestamp(i))));
|
||||
@@ -52,7 +52,7 @@ absl::Status PrintHelloWorld() {
|
||||
// Close the input stream "in".
|
||||
MP_RETURN_IF_ERROR(graph.CloseInputStream("in"));
|
||||
mediapipe::Packet packet;
|
||||
// Get the output packets std::string.
|
||||
// Get the output packets string.
|
||||
while (poller.Next(&packet)) {
|
||||
LOG(INFO) << packet.Get<std::string>();
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ objc_library(
|
||||
"//mediapipe/modules/face_geometry/data:geometry_pipeline_metadata_landmarks.binarypb",
|
||||
"//mediapipe/modules/face_landmark:face_landmark.tflite",
|
||||
],
|
||||
features = ["-layering_check"],
|
||||
sdk_frameworks = [
|
||||
"AVFoundation",
|
||||
"CoreGraphics",
|
||||
|
||||
@@ -58,6 +58,7 @@ objc_library(
|
||||
"//mediapipe/modules/face_detection:face_detection_short_range.tflite",
|
||||
"//mediapipe/modules/face_landmark:face_landmark.tflite",
|
||||
"//mediapipe/modules/hand_landmark:hand_landmark_full.tflite",
|
||||
"//mediapipe/modules/hand_landmark:hand_landmark_lite.tflite",
|
||||
"//mediapipe/modules/hand_landmark:handedness.txt",
|
||||
"//mediapipe/modules/holistic_landmark:hand_recrop.tflite",
|
||||
"//mediapipe/modules/pose_detection:pose_detection.tflite",
|
||||
|
||||
Reference in New Issue
Block a user