Added rect_filter and find_optimal_rect_filter() to python API.

This commit is contained in:
Davis King 2018-03-03 18:45:16 -05:00
parent 0bdc9ce5b4
commit 49ec319ce4
1 changed files with 101 additions and 4 deletions

View File

@ -6,6 +6,7 @@
#include <pybind11/stl_bind.h>
#include "indexing.h"
#include "opaque_types.h"
#include <dlib/filtering.h>
using namespace dlib;
using namespace std;
@ -60,14 +61,32 @@ string print_rectangle_str(const rect_type& r)
return sout.str();
}
template <typename rect_type>
string print_rectangle_repr(const rect_type& r)
string print_rectangle_repr(const rectangle& r)
{
std::ostringstream sout;
sout << "rectangle(" << r.left() << "," << r.top() << "," << r.right() << "," << r.bottom() << ")";
return sout.str();
}
string print_drectangle_repr(const drectangle& r)
{
std::ostringstream sout;
sout << "drectangle(" << r.left() << "," << r.top() << "," << r.right() << "," << r.bottom() << ")";
return sout.str();
}
string print_rect_filter(const rect_filter& r)
{
std::ostringstream sout;
sout << "rect_filter(";
sout << "measurement_noise="<<r.get_left().get_measurement_noise();
sout << ", typical_acceleration="<<r.get_left().get_typical_acceleration();
sout << ", max_measurement_deviation="<<r.get_left().get_max_measurement_deviation();
sout << ")";
return sout.str();
}
rectangle add_point_to_rect(const rectangle& r, const point& p)
{
return r + p;
@ -100,6 +119,7 @@ void bind_rectangles(py::module& m)
typedef rectangle type;
py::class_<type>(m, "rectangle", "This object represents a rectangular area of an image.")
.def(py::init<long,long,long,long>(), py::arg("left"),py::arg("top"),py::arg("right"),py::arg("bottom"))
.def(py::init())
.def("area", &::area)
.def("left", &::left)
.def("top", &::top)
@ -115,7 +135,7 @@ void bind_rectangles(py::module& m)
.def("contains", &::contains_rec<type>, py::arg("rectangle"))
.def("intersect", &::intersect<type>, py::arg("rectangle"))
.def("__str__", &::print_rectangle_str<type>)
.def("__repr__", &::print_rectangle_repr<type>)
.def("__repr__", &::print_rectangle_repr)
.def("__add__", &::add_point_to_rect)
.def("__add__", &::add_rect_to_rect)
.def("__iadd__", &::iadd_point_to_rect)
@ -143,12 +163,89 @@ void bind_rectangles(py::module& m)
.def("contains", &::contains_rec<type>, py::arg("rectangle"))
.def("intersect", &::intersect<type>, py::arg("rectangle"))
.def("__str__", &::print_rectangle_str<type>)
.def("__repr__", &::print_rectangle_repr<type>)
.def("__repr__", &::print_drectangle_repr)
.def(py::self == py::self)
.def(py::self != py::self)
.def(py::pickle(&getstate<type>, &setstate<type>));
}
{
typedef rect_filter type;
py::class_<type>(m, "rect_filter",
R"asdf(
This object is a simple tool for filtering a rectangle that
measures the location of a moving object that has some non-trivial
momentum. Importantly, the measurements are noisy and the object can
experience sudden unpredictable accelerations. To accomplish this
filtering we use a simple Kalman filter with a state transition model of:
position_{i+1} = position_{i} + velocity_{i}
velocity_{i+1} = velocity_{i} + some_unpredictable_acceleration
and a measurement model of:
measured_position_{i} = position_{i} + measurement_noise
Where some_unpredictable_acceleration and measurement_noise are 0 mean Gaussian
noise sources with standard deviations of typical_acceleration and
measurement_noise respectively.
To allow for really sudden and large but infrequent accelerations, at each
step we check if the current measured position deviates from the predicted
filtered position by more than max_measurement_deviation*measurement_noise
and if so we adjust the filter's state to keep it within these bounds.
This allows the moving object to undergo large unmodeled accelerations, far
in excess of what would be suggested by typical_acceleration, without
then experiencing a long lag time where the Kalman filter has to "catches
up" to the new position. )asdf"
)
.def(py::init<double,double,double>(), py::arg("measurement_noise"), py::arg("typical_acceleration"), py::arg("max_measurement_deviation"))
.def("measurement_noise", [](const rect_filter& a){return a.get_left().get_measurement_noise();})
.def("typical_acceleration", [](const rect_filter& a){return a.get_left().get_typical_acceleration();})
.def("max_measurement_deviation", [](const rect_filter& a){return a.get_left().get_max_measurement_deviation();})
.def("__call__", [](rect_filter& f, const dlib::rectangle& r){return rectangle(f(r)); }, py::arg("rect"))
.def("__repr__", print_rect_filter)
.def(py::pickle(&getstate<type>, &setstate<type>));
}
m.def("find_optimal_rect_filter",
[](const std::vector<rectangle>& rects, const double smoothness ) { return find_optimal_rect_filter(rects, smoothness); },
py::arg("rects"),
py::arg("smoothness")=1,
"requires \n\
- rects.size() > 4 \n\
- smoothness >= 0 \n\
ensures \n\
- This function finds the \"optimal\" settings of a rect_filter based on recorded \n\
measurement data stored in rects. Here we assume that rects is a complete \n\
track history of some object's measured positions. Essentially, what we do \n\
is find the rect_filter that minimizes the following objective function: \n\
sum of abs(predicted_location[i] - measured_location[i]) + smoothness*abs(filtered_location[i]-filtered_location[i-1]) \n\
Where i is a time index. \n\
The sum runs over all the data in rects. So what we do is find the \n\
filter settings that produce smooth filtered trajectories but also produce \n\
filtered outputs that are as close to the measured positions as possible. \n\
The larger the value of smoothness the less jittery the filter outputs will \n\
be, but they might become biased or laggy if smoothness is set really high. "
/*!
requires
- rects.size() > 4
- smoothness >= 0
ensures
- This function finds the "optimal" settings of a rect_filter based on recorded
measurement data stored in rects. Here we assume that rects is a complete
track history of some object's measured positions. Essentially, what we do
is find the rect_filter that minimizes the following objective function:
sum of abs(predicted_location[i] - measured_location[i]) + smoothness*abs(filtered_location[i]-filtered_location[i-1])
Where i is a time index.
The sum runs over all the data in rects. So what we do is find the
filter settings that produce smooth filtered trajectories but also produce
filtered outputs that are as close to the measured positions as possible.
The larger the value of smoothness the less jittery the filter outputs will
be, but they might become biased or laggy if smoothness is set really high.
!*/
);
{
typedef std::vector<rectangle> type;
py::bind_vector<type>(m, "rectangles", "An array of rectangle objects.")