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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#pragma once
#include "gme.hpp"
#include "libvideostitch/quaternion.hpp"
#include "libvideostitch/status.hpp"
#include <map>
#include <vector>
#include <random>
namespace VideoStitch {
namespace Core {
class InputDefinition;
class PanoDefinition;
} // namespace Core
namespace Motion {
/**
* @brief Detects the global rotation of a panoramic video
* The motion model is rotational and computed from samples from
* any inputs, reprojected on the sphere.
*
* It uses the method "Least-Square Rigid Motion Using SVD" : https://igl.ethz.ch/projects/ARAP/svd_rot.pdf
* restricted to a pure rotational motion: translation is assumed to be 0 (all the points lie on the unit sphere)
*
*/
class RotationRansac {
public:
/**
* @brief RotationRansac
* @param field: the vector of quaternion pairs (from -> to).
* @param inlierThreshold: allowed angular discrepancy between a point and its reprojection (1.5° is a reasonable
* value)
* @param numIters: number of iterations of the ransac loop
* @param minConsensusSamples: minimum number of inliers for the ransac to be considered successful
* @param gen: random number generator
*/
RotationRansac(const SphericalSpace::MotionVectorField& field, double inlierThreshold, int numIters,
std::size_t minConsensusSamples, std::default_random_engine& gen)
: inlierThreshold(inlierThreshold),
minSamplesForFit(2),
numIters(numIters),
minConsensusSamples(minConsensusSamples),
field(field),
gen(gen) {}
~RotationRansac() {}
/**
* @brief Computes ransac on the motion vector field
* @param qRot: output quaternion which represents the best quaternion according to the set of inliers
* @return true if the estimation is successful, false otherwise
*/
bool ransac(Quaternion<double>& qRot);
private:
/**
* @brief find the best rotation given the list of samples of bitSet
* @return true if everything went OK, false is an error has occurred
*/
bool fit(Quaternion<double>& qRot, const std::vector<bool>& bitSet) const;
bool isConsensualSample(Quaternion<double>& qRot, SphericalSpace::MotionVector mv) const;
/**
* @brief Populate bitSet randomly with the right number of bits
* @param numBitsSets: exact number of bits to be set to 1
* @param bitSet: vector filled by this function. Must be resized prior to the call to this function
*
* @return code: true if everything was OK, false otherwise
*
*/
bool populateRandom(size_t numBitsSets, std::vector<bool>& bitSet);
const double inlierThreshold;
const std::size_t minSamplesForFit;
const int numIters;
const std::size_t minConsensusSamples;
const SphericalSpace::MotionVectorField& field;
std::default_random_engine& gen;
};
/**
* A class that detects the global motion of a panoramic video.
* The motion model is rotational and computed from samples from
* any inputs, reprojected on the sphere.
*/
class RotationalMotionModelEstimation {
public:
typedef std::map<int64_t, Quaternion<double> > MotionModel;
explicit RotationalMotionModelEstimation(const Core::PanoDefinition& panorama);
virtual ~RotationalMotionModelEstimation() {}
Status motionModel(std::vector<std::pair<ImageSpace::MotionVectorFieldTimeSeries, const Core::InputDefinition*> >&,
MotionModel&) const;
Status motionModel(std::vector<std::pair<ImageSpace::MotionVectorField, const Core::InputDefinition*> >& in, int time,
Quaternion<double>&) const;
Status motionModel(const SphericalSpace::MotionVectorFieldTimeSeries&, MotionModel&) const;
Status motionModel(const SphericalSpace::MotionVectorField&, Quaternion<double>&) const;
private:
void transform(const ImageSpace::MotionVectorField&, const Core::InputDefinition&, int time,
SphericalSpace::MotionVectorField&) const;
const Core::PanoDefinition& panorama;
RotationalMotionModelEstimation();
RotationalMotionModelEstimation(const RotationalMotionModelEstimation&);
};
} // namespace Motion
} // namespace VideoStitch