1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#include "opticalFlow.hpp"
#include "gme.hpp"
#include <algorithm>
#include <sstream>
namespace VideoStitch {
namespace Motion {
template <class iterT>
iterT random_unique(iterT begin, iterT end, size_t num_random) {
size_t left = std::distance(begin, end);
while (num_random--) {
iterT r = begin;
std::advance(r, rand() % left);
std::swap(*begin, *r);
++begin;
--left;
}
return begin;
}
struct float2MagnitudeCompareDescendingOrder {
bool operator()(const Motion::ImageSpace::MotionVector& lhs, const Motion::ImageSpace::MotionVector& rhs) const {
return lhs.magnitude2() > rhs.magnitude2();
}
};
float OpticalFlow::computeMedianMagnitude2() const {
if (field.empty()) {
return 0.0f;
}
Motion::ImageSpace::MotionVectorField fieldCopy(field);
float2MagnitudeCompareDescendingOrder cmp;
nth_element(fieldCopy.begin(), fieldCopy.begin() + fieldCopy.size() / 2, fieldCopy.end(), cmp);
return fieldCopy[fieldCopy.size() / 2].magnitude2();
}
std::string OpticalFlow::toString() const {
std::ostringstream oss;
oss << input << ":" << frame << ":";
oss << computeMedianMagnitude2() << ":";
std::vector<float> magnitudes2;
for (auto motionVector : field) {
magnitudes2.push_back(motionVector.magnitude2());
}
std::sort(magnitudes2.begin(), magnitudes2.end());
for (auto mag : magnitudes2) {
oss << mag << ",";
}
return oss.str();
}
void OpticalFlow::applyFactor(float factor) {
for (std::size_t i = 0; i < field.size(); ++i) {
field[i].from.x *= factor;
field[i].from.y *= factor;
field[i].to.x *= factor;
field[i].to.y *= factor;
}
}
void OpticalFlow::sampleMotionVectors(std::size_t nbSamplesToKeep) {
if (nbSamplesToKeep >= field.size()) {
return;
}
random_unique(field.begin(), field.end(), nbSamplesToKeep);
field.resize(nbSamplesToKeep);
}
void OpticalFlow::filterSmallMotions(double epsilon) {
field.erase(std::remove_if(field.begin(), field.end(),
[&](const Motion::ImageSpace::MotionVector& x) { return x.magnitude2() < epsilon; }),
field.end());
}
} // end namespace Motion
} // end namespace VideoStitch