From fe40729e9b249dec22197f3c8761aa040e2b33bc Mon Sep 17 00:00:00 2001 From: Sunglok Choi Date: Wed, 19 Jul 2017 10:50:53 +0900 Subject: [PATCH] Make codes compatible for Linux (pull request by goodguykor) --- CMakeLists.txt | 10 +++++++ README.md | 16 ++++++---- examples/CMakeLists.txt | 15 ++++++++++ examples/EvaluateLineFitting.cpp | 10 +++---- examples/ExampleLineFitting.cpp | 2 +- examples/ExampleMean.cpp | 21 +++++++------- rtl/Base.hpp | 16 ++-------- rtl/Evaluator.hpp | 50 +++++--------------------------- rtl/LMedS.hpp | 4 +-- rtl/Line.hpp | 30 +++++++++---------- rtl/MLESAC.hpp | 10 +++---- rtl/MSAC.hpp | 4 +-- rtl/RANSAC.hpp | 12 ++------ 13 files changed, 88 insertions(+), 112 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 examples/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a01589e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.6) +project(RTL) + +set(RTL_OUTPUT_BIN_DIR ${RTL_BINARY_DIR}/bin) + +make_directory(${RTL_OUTPUT_BIN_DIR}) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${RTL_OUTPUT_BIN_DIR}") + +add_subdirectory(examples) diff --git a/README.md b/README.md index 2db081d..a0dbbf3 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,18 @@ ## RTL: RANSAC Template Library -_RANSAC Template Library (RTL)_ is an open-source robust regression library especially with RANSAC family. -RTL aims to provide fast, accurate, and easy ways to estimate any model parameters with data contaminated with outliers. +_RANSAC Template Library (RTL)_ is an open-source robust regression tool especially with RANSAC family. +RTL aims to provide fast, accurate, and easy ways to estimate any model parameters with data contaminated with outliers (incorrect data). RTL includes recent RANSAC variants with their performance evaluation with several models with synthetic and real data. RTL is written in generic programming style (template in C++) for its further applications with user-defined models. RTL is distributed under [Simplified BSD License](http://opensource.org/licenses/BSD-2-Clause). ### What is RANSAC? -_Random sample consensus (RANSAC)_ is an iterative method to make the previous parameter estimators strong against outliers. -For example of line fitting, RANSAC enable to estimate a line parameter even though data points include incorrect point observations far from the line. +_RANdom SAmple Consensus (RANSAC)_ is an iterative method to make any parameter estimator strong against outliers. +For example of line fitting, RANSAC enable to estimate a line parameter even though data points include wrong point observations far from the true line. RANSAC is composed of two steps, hypothesis generation and hypothesis evaluation. -It was original proposed by by Fischler and Bolles in 1981, but still utilized popularly to deal with outliers. +In the first step, RANSAC estimates a line (hypothesis) from randomly sampled point data. +In the second step, RANSAC counts the number of points which support the estimated line within the given threshold. +After several iterations of two steps, the final line can be obtained as a line who got the most supporters and inliers can determined as its supporters. +RANSAC was original proposed by Fischler and Bolles in 1981, but still utilized popularly to deal with outliers. ### Example If a model estimator is defined in advance (e.g. LineEstimator), you can simply use RTL as follows. @@ -35,7 +38,8 @@ Please refer a simple example, [ExampleMean.cpp](https://github.com/sunglok/rtl/ ### Authors * [Sunglok Choi](http://sites.google.com/site/sunglok/) (sunglok AT hanmail DOT net) -* Taemin Kim +* [Deok-Hwa Kim](http://rit.kaist.ac.kr/home/dhkim) (dhkim AT rit DOT kaist DOT ac DOT kr) +* Taemin Kim (luminans AT gmail DOT com) ### Reference * Sunglok Choi, Taemin Kim, and Wonpil Yu, __Performance Evaluation of RANSAC Family__, in Proceedings of British Machine Vision Conference (BMVC), 2009 [PDF](https://sites.google.com/site/sunglok/files/Choi09_bmvc.pdf?attredirects=0) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..0f4c4e6 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,15 @@ +include_directories(${CMAKE_SOURCE_DIR}/rtl) + +if(WIN32) + set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -Ox -MP") +else() + set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -std=c++11 -O3 -fopenmp") +endif() + +option(BUILD_EXAMPLE "Example Files" true) + +if(BUILD_EXAMPLE) + add_executable ( ExampleMean ExampleMean.cpp ) + add_executable ( ExampleLineFitting ExampleLineFitting.cpp ) + add_executable ( EvaluateLineFitting EvaluateLineFitting.cpp ) +endif() diff --git a/examples/EvaluateLineFitting.cpp b/examples/EvaluateLineFitting.cpp index c178ed1..6e181ce 100644 --- a/examples/EvaluateLineFitting.cpp +++ b/examples/EvaluateLineFitting.cpp @@ -75,11 +75,11 @@ bool RunRandomExp(const char* output, AlgoPtr algoPtr[], int algoNum, LineEstima int main(void) { // Configure experiments - const Line CONFIG_MODEL_TRUTH (0.6, 0.8, -300); - const ExpVar CONFIG_EXP_DEFAULT ( 200, 0.6, 0.5); - const ExpVar CONFIG_EXP_MIN ( 100, 0.2, 0.1); - const ExpVar CONFIG_EXP_MAX (1000, 2.0, 0.9); - const ExpVar CONFIG_EXP_STEP ( 100, 0.2, 0.1); + const Line CONFIG_MODEL_TRUTH(0.6, 0.8, -300); + const ExpVar CONFIG_EXP_DEFAULT(200, 0.6, 0.5); + const ExpVar CONFIG_EXP_MIN(100, 0.2, 0.1); + const ExpVar CONFIG_EXP_MAX(1000, 2.0, 0.9); + const ExpVar CONFIG_EXP_STEP(100, 0.2, 0.1); const int CONFIG_EXP_TRIAL = 1000; const char* CONFIG_EXP_NAME1 = "LineRandom(DataNum).csv"; const char* CONFIG_EXP_NAME2 = "LineRandom(NoiseLevel).csv"; diff --git a/examples/ExampleLineFitting.cpp b/examples/ExampleLineFitting.cpp index 2048ee3..4958153 100644 --- a/examples/ExampleLineFitting.cpp +++ b/examples/ExampleLineFitting.cpp @@ -22,7 +22,7 @@ int main(void) // Determine inliers using the best model if necessary vector inliers = ransac.FindInliers(model, data, data.size()); - // Print the result + // Print the result cout << "- True Model: " << trueModel << endl; cout << "- Found Model: " << model << " (Loss: " << loss << ")" << endl; cout << "- The Number of Inliers: " << inliers.size() << " (N: " << data.size() << ")" << endl; diff --git a/examples/ExampleMean.cpp b/examples/ExampleMean.cpp index 4c0c674..74a2191 100644 --- a/examples/ExampleMean.cpp +++ b/examples/ExampleMean.cpp @@ -4,40 +4,39 @@ using namespace std; // A mean calculator -class MeanEstimator : public RTL::Estimator +class MeanEstimator : public RTL::Estimator > { public: // Calculate the mean of data at the sample indices - virtual Model ComputeModel(const Data& data, const set& samples) + virtual double ComputeModel(const vector& data, const set& samples) { - Model mean = 0; + double mean = 0; for (auto itr = samples.begin(); itr != samples.end(); itr++) mean += data[*itr]; return mean / samples.size(); } // Calculate error between the mean and given datum - virtual double ComputeError(const Model& mean, const Datum& datum) { return datum - mean; } + virtual double ComputeError(const double& mean, const double& datum) { return datum - mean; } }; // The main function int main(void) { // The given data with outliers - double data[] = { 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 100, 3.3, 3.4, 3.5 }; - int n = sizeof(data) / sizeof(double); + vector data = { 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 100, 3.3, 3.4, 3.5 }; // Find the best model using RANSAC MeanEstimator estimator; - RTL::RANSAC ransac(&estimator); + RTL::RANSAC > ransac(&estimator); double model; - double loss = ransac.FindBest(model, data, n, 1); + double loss = ransac.FindBest(model, data, data.size(), 1); // Determine inliers using the best model if necessary - vector inliers = ransac.FindInliers(model, data, n); + vector inliers = ransac.FindInliers(model, data, data.size()); - // Print the result + // Print the result cout << "- Found Model: " << model << " (Loss: " << loss << ")" << endl; - cout << "- The Number of Inliers: " << inliers.size() << " (N: " << n << ")" << endl; + cout << "- The Number of Inliers: " << inliers.size() << " (N: " << data.size() << ")" << endl; return 0; } diff --git a/rtl/Base.hpp b/rtl/Base.hpp index 5053382..0bf009b 100644 --- a/rtl/Base.hpp +++ b/rtl/Base.hpp @@ -7,31 +7,19 @@ namespace RTL { -template +template class Estimator { public: - typedef ModelT Model; - - typedef DatumT Datum; - - typedef DataT Data; - virtual Model ComputeModel(const Data& data, const std::set& samples) = 0; virtual double ComputeError(const Model& model, const Datum& datum) = 0; }; -template +template class Observer { public: - typedef ModelT Model; - - typedef DatumT Datum; - - typedef DataT Data; - virtual Data GenerateData(const Model& model, int N, std::vector& inliers, double noise = 0, double ratio = 1) = 0; }; diff --git a/rtl/Evaluator.hpp b/rtl/Evaluator.hpp index fb7741a..2acda46 100644 --- a/rtl/Evaluator.hpp +++ b/rtl/Evaluator.hpp @@ -3,11 +3,7 @@ #include "Base.hpp" #include -#ifdef _WIN32 -# include -#else -# include -#endif +#include class Score { @@ -23,16 +19,10 @@ class Score int fn; }; -template +template class Evaluator { public: - typedef ModelT Model; - - typedef DatumT Datum; - - typedef DataT Data; - Evaluator(RTL::Estimator* estimator) { assert(estimator != NULL); @@ -105,48 +95,24 @@ class StopWatch public: StopWatch() { -#ifdef _WIN32 - ::QueryPerformanceFrequency((LARGE_INTEGER*)&freq); - ::QueryPerformanceCounter((LARGE_INTEGER*)&start); -#else - start.tv_sec = start.tv_usec = 0; - gettimeofday(&start, NULL); -#endif + Start(); } bool Start(void) { -#ifdef _WIN32 - ::QueryPerformanceCounter((LARGE_INTEGER*)&start); + start = std::chrono::high_resolution_clock::now(); return true; -#else - gettimeofday(&start, NULL); -#endif } double GetElapse(void) { -#ifdef _WIN32 - assert(freq.QuadPart != 0); - LARGE_INTEGER finish; - ::QueryPerformanceCounter((LARGE_INTEGER*)&finish); - return (static_cast(finish.QuadPart - start.QuadPart) / freq.QuadPart); -#else - struct timeval finish; - gettimeofday(&finish, NULL); - return (finish.tv_sec - start.tv_sec + static_cast(finish.tv_usec - start.tv_usec) / 1000000); - -#endif + std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); + std::chrono::duration time_span = std::chrono::duration_cast>(end - start); + return static_cast(time_span.count()); } private: -#ifdef _WIN32 - LARGE_INTEGER freq; - - LARGE_INTEGER start; -#else - struct timeval start; -#endif + std::chrono::high_resolution_clock::time_point start; }; #endif // End of '__RTL_EVALUATOR__' diff --git a/rtl/LMedS.hpp b/rtl/LMedS.hpp index 86fdcc8..4642d98 100644 --- a/rtl/LMedS.hpp +++ b/rtl/LMedS.hpp @@ -7,8 +7,8 @@ namespace RTL { -template -class LMedS : public RANSAC +template +class LMedS : virtual public RANSAC { public: LMedS(Estimator* estimator) : RANSAC(estimator) { } diff --git a/rtl/Line.hpp b/rtl/Line.hpp index 90b212d..562fb71 100644 --- a/rtl/Line.hpp +++ b/rtl/Line.hpp @@ -10,7 +10,7 @@ class Point { public: Point() : x(0), y(0) { } - + Point(double _x, double _y) : x(_x), y(_y) { } friend std::ostream& operator<<(std::ostream& out, const Point& p) { return out << p.x << ", " << p.y; } @@ -30,15 +30,15 @@ class Line double a, b, c; }; -class LineEstimator : public RTL::Estimator > +class LineEstimator : virtual public RTL::Estimator > { public: - virtual Model ComputeModel(const Data& data, const std::set& samples) + virtual Line ComputeModel(const std::vector& data, const std::set& samples) { double meanX = 0, meanY = 0, meanXX = 0, meanYY = 0, meanXY = 0; for (auto itr = samples.begin(); itr != samples.end(); itr++) { - const Datum& p = data[*itr]; + const Point& p = data[*itr]; meanX += p.x; meanY += p.y; meanXX += p.x * p.x; @@ -51,11 +51,11 @@ class LineEstimator : public RTL::Estimator > meanXX /= M; meanYY /= M; meanXY /= M; - double a = meanXX - meanX*meanX; - double b = meanXY - meanX*meanY; - double d = meanYY - meanY*meanY; + double a = meanXX - meanX * meanX; + double b = meanXY - meanX * meanY; + double d = meanYY - meanY * meanY; - Model line; + Line line; if (fabs(b) > DBL_EPSILON) { // Calculate the first eigen vector of A = [a, b; b, d] @@ -76,29 +76,29 @@ class LineEstimator : public RTL::Estimator > return line; } - virtual double ComputeError(const Model& line, const Datum& point) + virtual double ComputeError(const Line& line, const Point& point) { return line.a * point.x + line.b * point.y + line.c; } }; // End of 'LineEstimator' -class LineObserver : public RTL::Observer > +class LineObserver : virtual public RTL::Observer > { public: LineObserver(Point _max = Point(640, 480), Point _min = Point(0, 0)) : RANGE_MAX(_max), RANGE_MIN(_min) { } - virtual Data GenerateData(const Model& line, int N, std::vector& inliers, double noise = 0, double ratio = 1) + virtual std::vector GenerateData(const Line& line, int N, std::vector& inliers, double noise = 0, double ratio = 1) { std::mt19937 generator; - std::uniform_real uniform(0, 1); + std::uniform_real_distribution uniform(0, 1); std::normal_distribution normal(0, 1); - Data data; + std::vector data; if (fabs(line.b) > fabs(line.a)) { for (int i = 0; i < N; i++) { - Datum point; + Point point; point.x = (RANGE_MAX.x - RANGE_MIN.x) * uniform(generator) + RANGE_MIN.x; double vote = uniform(generator); if (vote > ratio) @@ -121,7 +121,7 @@ class LineObserver : public RTL::Observer > { for (int i = 0; i < N; i++) { - Datum point; + Point point; point.y = (RANGE_MAX.y - RANGE_MIN.y) * uniform(generator) + RANGE_MIN.y; double vote = uniform(generator); if (vote > ratio) diff --git a/rtl/MLESAC.hpp b/rtl/MLESAC.hpp index 526858f..bb7a340 100644 --- a/rtl/MLESAC.hpp +++ b/rtl/MLESAC.hpp @@ -10,11 +10,11 @@ namespace RTL { -template -class MLESAC : public MSAC +template +class MLESAC : virtual public RANSAC { public: - MLESAC(Estimator* estimator) : MSAC(estimator) + MLESAC(Estimator* estimator) : RANSAC(estimator) { dataError2 = NULL; SetParamIterationEM(); @@ -32,7 +32,7 @@ class MLESAC : public MSAC protected: virtual void Initialize(const Data& data, int N) { - MSAC::Initialize(data, N); + RANSAC::Initialize(data, N); dataError2 = new double[N]; assert(dataError2 != NULL); double sigma = paramThreshold / paramSigmaScale; @@ -86,7 +86,7 @@ class MLESAC : public MSAC delete [] dataError2; dataError2 = NULL; } - MSAC::Terminate(bestModel, data, N); + RANSAC::Terminate(bestModel, data, N); } int paramIterationEM; diff --git a/rtl/MSAC.hpp b/rtl/MSAC.hpp index 556a639..834d2bf 100644 --- a/rtl/MSAC.hpp +++ b/rtl/MSAC.hpp @@ -6,8 +6,8 @@ namespace RTL { -template -class MSAC : public RANSAC +template +class MSAC : virtual public RANSAC { public: MSAC(Estimator* estimator) : RANSAC(estimator) { } diff --git a/rtl/RANSAC.hpp b/rtl/RANSAC.hpp index 1fc96dd..8e29856 100644 --- a/rtl/RANSAC.hpp +++ b/rtl/RANSAC.hpp @@ -9,16 +9,10 @@ namespace RTL { -template +template class RANSAC { public: - typedef ModelT Model; - - typedef DatumT Datum; - - typedef DataT Data; - RANSAC(Estimator* estimator) { assert(estimator != NULL); @@ -104,13 +98,13 @@ class RANSAC return true; } - virtual void Initialize(const Data& data, int N) { toolUniform = std::uniform_int(0, N - 1); } + virtual void Initialize(const Data& data, int N) { toolUniform = std::uniform_int_distribution(0, N - 1); } virtual void Terminate(const Model& bestModel, const Data& data, int N) { } std::mt19937 toolGenerator; - std::uniform_int toolUniform; + std::uniform_int_distribution toolUniform; Estimator* toolEstimator;