Project import generated by Copybara.
GitOrigin-RevId: c3919b8aaf432b2e4a1f0cf404b2cbfe37dad35e
This commit is contained in:
@@ -2,11 +2,24 @@
|
||||
|
||||
namespace mediapipe {
|
||||
namespace autoflip {
|
||||
namespace {
|
||||
int Median(const std::deque<std::pair<uint64, int>>& positions_raw) {
|
||||
std::deque<int> positions;
|
||||
for (const auto& position : positions_raw) {
|
||||
positions.push_back(position.second);
|
||||
}
|
||||
|
||||
size_t n = positions.size() / 2;
|
||||
nth_element(positions.begin(), positions.begin() + n, positions.end());
|
||||
return positions[n];
|
||||
}
|
||||
} // namespace
|
||||
::mediapipe::Status KinematicPathSolver::AddObservation(int position,
|
||||
const uint64 time_us) {
|
||||
if (!initialized_) {
|
||||
current_position_px_ = position;
|
||||
raw_positions_at_time_.push_front(
|
||||
std::pair<uint64, int>(time_us, position));
|
||||
current_time_ = time_us;
|
||||
initialized_ = true;
|
||||
current_velocity_deg_per_s_ = 0;
|
||||
@@ -16,13 +29,26 @@ namespace autoflip {
|
||||
<< "update_rate_seconds must be greater than 0.";
|
||||
RET_CHECK_GE(options_.min_motion_to_reframe(), options_.reframe_window())
|
||||
<< "Reframe window cannot exceed min_motion_to_reframe.";
|
||||
RET_CHECK_GE(options_.filtering_time_window_us(), 0)
|
||||
<< "update_rate_seconds must be greater than 0.";
|
||||
return ::mediapipe::OkStatus();
|
||||
}
|
||||
|
||||
RET_CHECK(current_time_ < time_us)
|
||||
<< "Observation added before a prior observations.";
|
||||
|
||||
double delta_degs = (position - current_position_px_) / pixels_per_degree_;
|
||||
raw_positions_at_time_.push_front(std::pair<uint64, int>(time_us, position));
|
||||
while (raw_positions_at_time_.size() > 1) {
|
||||
if (static_cast<int64>(raw_positions_at_time_.back().first) <
|
||||
static_cast<int64>(time_us) - options_.filtering_time_window_us()) {
|
||||
raw_positions_at_time_.pop_back();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double delta_degs = (Median(raw_positions_at_time_) - current_position_px_) /
|
||||
pixels_per_degree_;
|
||||
|
||||
// If the motion is smaller than the min, don't use the update.
|
||||
if (abs(delta_degs) < options_.min_motion_to_reframe()) {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#ifndef MEDIAPIPE_EXAMPLES_DESKTOP_AUTOFLIP_QUALITY_UNIFORM_ACCELERATION_PATH_SOLVER_H_
|
||||
#define MEDIAPIPE_EXAMPLES_DESKTOP_AUTOFLIP_QUALITY_UNIFORM_ACCELERATION_PATH_SOLVER_H_
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "mediapipe/examples/desktop/autoflip/quality/kinematic_path_solver.pb.h"
|
||||
#include "mediapipe/framework/port/integral_types.h"
|
||||
#include "mediapipe/framework/port/ret_check.h"
|
||||
@@ -61,6 +63,8 @@ class KinematicPathSolver {
|
||||
double current_position_px_;
|
||||
double current_velocity_deg_per_s_;
|
||||
uint64 current_time_;
|
||||
// History of observations (second) and their time (first).
|
||||
std::deque<std::pair<uint64, int>> raw_positions_at_time_;
|
||||
};
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -20,4 +20,6 @@ message KinematicOptions {
|
||||
// where delta_time_s is the time since the last frame.
|
||||
optional double update_rate_seconds = 5 [default = 0.20];
|
||||
optional double max_update_rate = 6 [default = 0.8];
|
||||
// History time window of observations to be median filtered.
|
||||
optional int64 filtering_time_window_us = 7 [default = 0];
|
||||
}
|
||||
|
||||
@@ -81,6 +81,46 @@ TEST(KinematicPathSolverTest, PassNotEnoughMotionSmallImg) {
|
||||
EXPECT_EQ(state, 400);
|
||||
}
|
||||
|
||||
TEST(KinematicPathSolverTest, PassEnoughMotionFiltered) {
|
||||
KinematicOptions options;
|
||||
// Set min motion to 2deg
|
||||
options.set_min_motion_to_reframe(1.0);
|
||||
options.set_update_rate(1);
|
||||
options.set_max_velocity(1000);
|
||||
options.set_filtering_time_window_us(3000000);
|
||||
// Set degrees / pixel to 16.6
|
||||
KinematicPathSolver solver(options, 0, 1000, 1000.0 / kWidthFieldOfView);
|
||||
int state;
|
||||
MP_ASSERT_OK(solver.AddObservation(500, kMicroSecInSec * 0));
|
||||
// Move target by 20px / 16.6 = 1.2deg
|
||||
MP_ASSERT_OK(solver.AddObservation(500, kMicroSecInSec * 1));
|
||||
MP_ASSERT_OK(solver.AddObservation(520, kMicroSecInSec * 2));
|
||||
MP_ASSERT_OK(solver.AddObservation(500, kMicroSecInSec * 3));
|
||||
MP_ASSERT_OK(solver.GetState(&state));
|
||||
// Expect cam to not move.
|
||||
EXPECT_EQ(state, 500);
|
||||
}
|
||||
|
||||
TEST(KinematicPathSolverTest, PassEnoughMotionNotFiltered) {
|
||||
KinematicOptions options;
|
||||
// Set min motion to 2deg
|
||||
options.set_min_motion_to_reframe(1.0);
|
||||
options.set_update_rate(1);
|
||||
options.set_max_velocity(1000);
|
||||
options.set_filtering_time_window_us(0);
|
||||
// Set degrees / pixel to 16.6
|
||||
KinematicPathSolver solver(options, 0, 1000, 1000.0 / kWidthFieldOfView);
|
||||
int state;
|
||||
MP_ASSERT_OK(solver.AddObservation(500, kMicroSecInSec * 0));
|
||||
// Move target by 20px / 16.6 = 1.2deg
|
||||
MP_ASSERT_OK(solver.AddObservation(500, kMicroSecInSec * 1));
|
||||
MP_ASSERT_OK(solver.AddObservation(520, kMicroSecInSec * 2));
|
||||
MP_ASSERT_OK(solver.AddObservation(500, kMicroSecInSec * 3));
|
||||
MP_ASSERT_OK(solver.GetState(&state));
|
||||
// Expect cam to not move.
|
||||
EXPECT_EQ(state, 519);
|
||||
}
|
||||
|
||||
TEST(KinematicPathSolverTest, PassEnoughMotionLargeImg) {
|
||||
KinematicOptions options;
|
||||
// Set min motion to 1deg
|
||||
|
||||
Reference in New Issue
Block a user