Skip to content

Commit

Permalink
Reproducibility and c++11 random generator openMVG#922
Browse files Browse the repository at this point in the history
[unit test]
- Remove C-style rand from robust_estimator unit tests
- Replace with C++ uniform_int_distribution with mt19937 generator

[core] UniformSample modified template types
  - Use SamplingType as samples type since values inserted are SamplingType.
  - Keep type T instead of SamplingType for 2nd function since any type could be used.
  • Loading branch information
hugbed authored and pmoulon committed May 26, 2017
1 parent 615ec2e commit 2c65219
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 37 deletions.
12 changes: 7 additions & 5 deletions src/openMVG/robust_estimation/rand_sampling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,17 @@ namespace robust{
* \param[out] samples num_samples of numbers in [0, total_samples) is placed
* here on return.
*/
template <class RandomGeneratorT, typename SamplingType = uint32_t>
template <class RandomGeneratorT, typename SamplingType>
inline void UniformSample
(
uint32_t num_samples,
uint32_t total_samples,
RandomGeneratorT &&random_generator,
std::vector<uint32_t> *samples
std::vector<SamplingType> *samples
)
{
static_assert(std::is_integral<SamplingType>::value, "SamplingType must be an integral type");

std::uniform_int_distribution<SamplingType> distribution(0, total_samples-1);
samples->resize(0);
while (samples->size() < num_samples) {
Expand All @@ -66,13 +68,13 @@ inline void UniformSample
* \param[out] samples Output randomly picked value.
* \return true if the sampling can be performed
*/
template<class RandomGeneratorT, typename SamplingType = uint32_t>
template<typename T, class RandomGeneratorT, typename SamplingType = uint32_t>
bool UniformSample
(
const size_t num_samples,
RandomGeneratorT &&random_generator,
std::vector<SamplingType> * vec_index, // the array that provide the index (will be shuffled)
std::vector<SamplingType> * samples // output found indices
std::vector<T> * vec_index, // the array that provide the index (will be shuffled)
std::vector<T> * samples // output found indices
)
{
static_assert(std::is_integral<SamplingType>::value, "SamplingType must be an integral type");
Expand Down
24 changes: 14 additions & 10 deletions src/openMVG/robust_estimation/robust_estimator_ACRansac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ TEST(RansacLineFitter, TooFewPoints) {
// Check that the number of inliers and the model are correct.
TEST(RansacLineFitter, RealisticCase) {

const int NbPoints = 100;
const int inlierPourcentAmount = 30;
constexpr int NbPoints = 100;
constexpr double inlierRatio = 30.0 / 100.0;
Mat2X xy(2, NbPoints);

Vec2 GTModel; // y = 6.3 x + (-2.0)
Expand All @@ -181,7 +181,7 @@ TEST(RansacLineFitter, RealisticCase) {
std::normal_distribution<> d(0, 5); // More or less 5 units

//-- Simulate outliers (for the asked percentage amount of the datum)
const int nbPtToNoise = static_cast<int>(NbPoints*inlierPourcentAmount/100.0);
constexpr auto nbPtToNoise = static_cast<uint32_t>(NbPoints*inlierRatio);
vector<uint32_t> vec_samples; // Fit with unique random index
UniformSample(nbPtToNoise, NbPoints, random_generator, &vec_samples);
for(size_t i = 0; i <vec_samples.size(); ++i)
Expand All @@ -208,7 +208,7 @@ TEST(RansacLineFitter, RealisticCase) {

// Generate nbPoints along a line and add gaussian noise.
// Move some point in the dataset to create outlier contamined data
void generateLine(Mat & points, size_t nbPoints, int W, int H, float noise, float outlierPourcent)
void generateLine(Mat & points, size_t nbPoints, int W, int H, float noise, float outlierRatio)
{
points = Mat(2, nbPoints);

Expand All @@ -218,22 +218,26 @@ void generateLine(Mat & points, size_t nbPoints, int W, int H, float noise, floa
std::mt19937 random_generator(std::mt19937::default_seed);
std::normal_distribution<double> d(0, noise);

// Setup uniform distribution
std::uniform_int_distribution<int> dW(0, W);
std::uniform_int_distribution<int> dH(0, H);

for (size_t i = 0; i < nbPoints; ++i)
{
const float x = rand()%W;
auto x = static_cast<double>(dW(random_generator));
const float y = d(random_generator) + (lineEq[1] * x + lineEq[0]) + d(random_generator);
points.col(i) = Vec2(x, y);
}

// generate outlier
std::normal_distribution<double> d_outlier(0, 0.2);
const size_t count = outlierPourcent * nbPoints;
const auto count = static_cast<uint32_t>(outlierRatio * nbPoints);
std::vector<uint32_t> vec_indexes(count,0);
UniformSample(count, nbPoints, random_generator, &vec_indexes);
for (const auto & pos : vec_indexes)
{
points.col(pos) << rand()%W + d_outlier(random_generator),
rand()%H - d_outlier(random_generator);
points.col(pos) = Vec2(static_cast<double>(dW(random_generator)) + d_outlier(random_generator),
static_cast<double>(dH(random_generator)) - d_outlier(random_generator));
}
}

Expand Down Expand Up @@ -279,9 +283,9 @@ TEST(RansacLineFitter, ACRANSACSimu) {
size_t nbPoints = 2.0 * S * sqrt(2.0);
const float noise = gaussianNoiseLevel;

const float outlierPourcent = .3f;
const float outlierRatio = .3f;
Mat points;
generateLine(points, nbPoints, W, H, noise, outlierPourcent);
generateLine(points, nbPoints, W, H, noise, outlierRatio);

// Remove point that have the same coords
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,28 +92,30 @@ TEST(MaxConsensusLineFitter, TooFewPoints) {
// Check that the number of inliers and the model are correct.
TEST(MaxConsensusLineFitter, RealisticCase) {

const int NbPoints = 30;
const int inlierPourcentAmount = 30; //works with 40
constexpr int NbPoints = 30;
constexpr double inlierRatio = 30.0 / 100.0; // works with 40
Mat2X xy(2, NbPoints);

Vec2 GTModel; // y = 2x + 1
GTModel << -2.0, 6.3;

//-- Build the point list according the given model
for(int i = 0; i < NbPoints; ++i) {
xy.col(i) << i, (double)i*GTModel[1] + GTModel[0];
xy.col(i) << i, static_cast<double>(i)*GTModel[1] + GTModel[0];
}

//-- Add some noise (for the asked percentage amount)
const int nbPtToNoise = (int) NbPoints*inlierPourcentAmount/100.0;
std::vector<uint32_t> vec_samples; // Fit with unique random index
constexpr auto nbPtToNoise = static_cast<uint32_t>(NbPoints*inlierRatio);
std::vector<uint32_t> vec_samples; // fit with unique random index
std::mt19937 random_generator(std::mt19937::default_seed);
UniformSample(nbPtToNoise, NbPoints, random_generator, &vec_samples);
for(const auto index : vec_samples)
{
//Additive random noise
xy.col(index) << xy.col(index)(0)+rand()%2-3,
xy.col(index)(1)+rand()%8-6;

std::uniform_int_distribution<int> d0(-3, 2);
std::uniform_int_distribution<int> d1(-6, 8);
for(const auto index : vec_samples) {
// additive random noise
xy.col(index) << xy.col(index)(0) + static_cast<double>(d0(random_generator)),
xy.col(index)(1) + static_cast<double>(d1(random_generator));
}

LineKernel kernel(xy);
Expand Down
23 changes: 12 additions & 11 deletions src/openMVG/robust_estimation/robust_estimator_Ransac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,29 +73,30 @@ TEST(MaxConsensusLineFitter, TooFewPoints) {
// Check that the number of inliers and the model are correct.
TEST(MaxConsensusLineFitter, RealisticCase) {

const int NbPoints = 30;
const int inlierPourcentAmount = 30; //works with 40
constexpr int NbPoints = 30;
constexpr double inlierRatio = 30.0 / 100.0; // works with 40
Mat2X xy(2, NbPoints);

Vec2 GTModel; // y = 2x + 1
GTModel << -2.0, 6.3;

//-- Build the point list according the given model
for (int i = 0; i < NbPoints; ++i) {
xy.col(i) << i, (double)i*GTModel[1] + GTModel[0];
xy.col(i) << i, static_cast<double>(i)*GTModel[1] + GTModel[0];
}

//-- Add some noise (for the asked percentage amount)
const int nbPtToNoise = (int) NbPoints*inlierPourcentAmount/100.0;
std::vector<uint32_t> vec_samples; // Fit with unique random index
constexpr auto nbPtToNoise = static_cast<uint32_t>(NbPoints*inlierRatio);
std::vector<uint32_t> vec_samples; // fit with unique random index
std::mt19937 random_generator(std::mt19937::default_seed);
UniformSample(nbPtToNoise, NbPoints, random_generator, &vec_samples);
for (uint32_t i = 0; i < vec_samples.size(); ++i)
{
const size_t randomIndex = vec_samples[i];
//Additive random noise
xy.col(randomIndex) << xy.col(randomIndex)(0)+rand()%2-3,
xy.col(randomIndex)(1)+rand()%8-6;

std::uniform_int_distribution<int> d0(-3, 2);
std::uniform_int_distribution<int> d1(-6, 8);
for (const auto randomIndex : vec_samples) {
// additive random noise
xy.col(randomIndex) << xy.col(randomIndex)(0) + static_cast<double>(d0(random_generator)),
xy.col(randomIndex)(1) + static_cast<double>(d1(random_generator));
}

LineKernel kernel(xy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ TEST(LineFitter, ItWorks) {
3, 5, 7, 9, 11;
std::vector<Vec2> models;
LineKernel kernel(xy);
std::vector<uint32_t> samples(xy.cols());
std::vector<uint32_t> samples(static_cast<size_t>(xy.cols()));
std::iota(samples.begin(), samples.end(), 0);
kernel.Fit(samples, &models);
CHECK_EQUAL(1, models.size());
Expand Down

0 comments on commit 2c65219

Please sign in to comment.