diff --git a/gui/qt/bgslibrary_gui.pro b/gui/qt/bgslibrary_gui.pro
index 53caf04b50b841cedfaa92d8725824370ccabef7..615e30dcf23acded22c6842363c40bd1ebb7d35c 100644
--- a/gui/qt/bgslibrary_gui.pro
+++ b/gui/qt/bgslibrary_gui.pro
@@ -127,7 +127,7 @@ SOURCES += bgslibrary_gui.cpp\
     ../../src/algorithms/MultiLayer/LocalBinaryPattern.cpp \
     ../../src/algorithms/PBAS/PBAS.cpp \
     ../../src/algorithms/SigmaDelta/sdLaMa091.cpp \
-    ../../src/algorithms/T2F/FuzzyUtils.cpp \
+    ../../src/tools/FuzzyUtils.cpp \
     ../../src/algorithms/T2F/MRF.cpp \
     ../../src/algorithms/T2F/T2FGMM.cpp \
     ../../src/algorithms/T2F/T2FMRF.cpp \
@@ -239,7 +239,7 @@ HEADERS  += mainwindow.h \
     ../../src/algorithms/MultiLayer/OpenCvLegacyIncludes.h \
     ../../src/algorithms/PBAS/PBAS.h \
     ../../src/algorithms/SigmaDelta/sdLaMa091.h \
-    ../../src/algorithms/T2F/FuzzyUtils.h \
+    ../../src/tools/FuzzyUtils.h \
     ../../src/algorithms/T2F/MRF.h \
     ../../src/algorithms/T2F/T2FGMM.h \
     ../../src/algorithms/T2F/T2FMRF.h \
@@ -249,7 +249,7 @@ HEADERS  += mainwindow.h \
     ../../src/algorithms/VuMeter/TBackgroundVuMeter.h \
     ../../src/algorithms/AdaptiveBackgroundLearning.h \
     ../../src/algorithms/AdaptiveSelectiveBackgroundLearning.h \
-    ../../src/algorithms/bgslibrary.h \
+    ../../src/algorithms/algorithms.h \
     ../../src/algorithms/DPAdaptiveMedian.h \
     ../../src/algorithms/DPEigenbackground.h \
     ../../src/algorithms/DPGrimsonGMM.h \
diff --git a/src/FrameProcessor.cpp b/src/FrameProcessor.cpp
index ab47cda08804cb56772d6a3ce939fce3fecb9b26..38eb71f989b0852abc85281cfde80507e558a832 100644
--- a/src/FrameProcessor.cpp
+++ b/src/FrameProcessor.cpp
@@ -159,7 +159,7 @@ namespace bgslibrary
       codeBook = std::make_shared<CodeBook>();
 
     if (enableForegroundMaskAnalysis)
-      foregroundMaskAnalysis = std::make_shared<ForegroundMaskAnalysis>();
+      foregroundMaskAnalysis = std::make_shared<tools::ForegroundMaskAnalysis>();
   }
   
   void FrameProcessor::process(const std::string name, const std::shared_ptr<IBGS> &bgs, const cv::Mat &img_input, cv::Mat &img_bgs)
diff --git a/src/FrameProcessor.h b/src/FrameProcessor.h
index 8c0b10f1c9d7db0ff6f95c20b189669a62f2d3a2..1eec6d601918556f62e1926d8b5735a996778e58 100644
--- a/src/FrameProcessor.h
+++ b/src/FrameProcessor.h
@@ -202,7 +202,7 @@ namespace bgslibrary
     std::shared_ptr<CodeBook> codeBook;
     bool enableCodeBook = false;
     
-    std::shared_ptr<ForegroundMaskAnalysis> foregroundMaskAnalysis;
+    std::shared_ptr<tools::ForegroundMaskAnalysis> foregroundMaskAnalysis;
     bool enableForegroundMaskAnalysis = false;
 
   public:
diff --git a/src/algorithms/CodeBook.h b/src/algorithms/CodeBook.h
index 3fc8ff90f6e23bd56b0700d257c45ab18f44403d..512d59bdbebfae780509f6ecfe27229aa835299b 100644
--- a/src/algorithms/CodeBook.h
+++ b/src/algorithms/CodeBook.h
@@ -8,18 +8,28 @@ namespace bgslibrary
 {
   namespace algorithms
   {
-    struct codeword {
-      float min;
-      float max;
-      float f;
-      float l;
-      int first;
-      int last;
-      bool isStale;
-    };
+    namespace codebook {
+      struct codeword {
+        float min;
+        float max;
+        float f;
+        float l;
+        int first;
+        int last;
+        bool isStale;
+      };
+    }
 
     class CodeBook : public IBGS
     {
+    public:
+      typedef codebook::codeword codeword;
+
+      CodeBook();
+      ~CodeBook();
+
+      void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
     private:
       static const int Tdel = 200;
       static const int Tadd = 150;
@@ -34,13 +44,6 @@ namespace bgslibrary
       std::vector<codeword> **cbMain;
       std::vector<codeword> **cbCache;
 
-    public:
-      CodeBook();
-      ~CodeBook();
-
-      void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
-
-    private:
       void initializeCodebook(int w, int h);
       void update_cb(const cv::Mat& frame);
       void fg_cb(const cv::Mat& frame, cv::Mat& fg);
diff --git a/src/algorithms/DPAdaptiveMedian.h b/src/algorithms/DPAdaptiveMedian.h
index 953f35fe73c8d4b17a2d515c51832973e582670f..fbad2da636f3553c842ee5ff5ebe9d0beca80f56 100644
--- a/src/algorithms/DPAdaptiveMedian.h
+++ b/src/algorithms/DPAdaptiveMedian.h
@@ -6,8 +6,6 @@
 #include "IBGS.h"
 #include "dp/AdaptiveMedianBGS.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -16,15 +14,15 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage* frame;
-      RgbImage frame_data;
-      AdaptiveMedianParams params;
-      AdaptiveMedianBGS bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
       int threshold;
       int samplingRate;
       int learningFrames;
+      IplImage* frame;
+      dp::RgbImage frame_data;
+      dp::AdaptiveMedianParams params;
+      dp::AdaptiveMedianBGS bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
 
     public:
       DPAdaptiveMedian();
diff --git a/src/algorithms/DPEigenbackground.h b/src/algorithms/DPEigenbackground.h
index 34b1457c6e98e70b39a268a8a7d1f1e07d680403..0d9b18dff20b25c6448e64429cfa5cb9a50fce71 100644
--- a/src/algorithms/DPEigenbackground.h
+++ b/src/algorithms/DPEigenbackground.h
@@ -7,8 +7,6 @@
 
 #include "dp/Eigenbackground.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,17 +15,15 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage* frame;
-      RgbImage frame_data;
-
-      EigenbackgroundParams params;
-      Eigenbackground bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       int threshold;
       int historySize;
       int embeddedDim;
+      IplImage* frame;
+      dp::RgbImage frame_data;
+      dp::EigenbackgroundParams params;
+      dp::Eigenbackground bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
 
     public:
       DPEigenbackground();
diff --git a/src/algorithms/DPGrimsonGMM.h b/src/algorithms/DPGrimsonGMM.h
index 2fa5bff3d3a7cb48f6caf597d450c8a84373f581..6d3d3e3edc5133ebc654cd14898e0a8fb6824ef1 100644
--- a/src/algorithms/DPGrimsonGMM.h
+++ b/src/algorithms/DPGrimsonGMM.h
@@ -7,8 +7,6 @@
 
 #include "dp/GrimsonGMM.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,17 +15,15 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage* frame;
-      RgbImage frame_data;
-
-      GrimsonParams params;
-      GrimsonGMM bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       double threshold;
       double alpha;
       int gaussians;
+      IplImage* frame;
+      dp::RgbImage frame_data;
+      dp::GrimsonParams params;
+      dp::GrimsonGMM bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
 
     public:
       DPGrimsonGMM();
diff --git a/src/algorithms/DPMean.h b/src/algorithms/DPMean.h
index 6c3cdd7f5572c29cef7f5af0256fbdb39cceb09c..311906f13329ca0f4a987f5ff59def959104427e 100644
--- a/src/algorithms/DPMean.h
+++ b/src/algorithms/DPMean.h
@@ -7,8 +7,6 @@
 
 #include "dp/MeanBGS.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,17 +15,15 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage* frame;
-      RgbImage frame_data;
-
-      MeanParams params;
-      MeanBGS bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       int threshold;
       double alpha;
       int learningFrames;
+      IplImage* frame;
+      dp::RgbImage frame_data;
+      dp::MeanParams params;
+      dp::MeanBGS bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
 
     public:
       DPMean();
diff --git a/src/algorithms/DPPratiMediod.h b/src/algorithms/DPPratiMediod.h
index 8833016a406865b41edfbb59f07c0ea10aba1470..eb93683ac93acee4fa32ab4db18c8d88cd1813bb 100644
--- a/src/algorithms/DPPratiMediod.h
+++ b/src/algorithms/DPPratiMediod.h
@@ -7,8 +7,6 @@
 
 #include "dp/PratiMediodBGS.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,18 +15,16 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage* frame;
-      RgbImage frame_data;
-
-      PratiParams params;
-      PratiMediodBGS bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       int threshold;
       int samplingRate;
       int historySize;
       int weight;
+      IplImage* frame;
+      dp::RgbImage frame_data;
+      dp::PratiParams params;
+      dp::PratiMediodBGS bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
 
     public:
       DPPratiMediod();
diff --git a/src/algorithms/DPTexture.cpp b/src/algorithms/DPTexture.cpp
index 0448a797497165e9e23f4ee33edd438f77582fac..e56ca87090125d1510aa2abfe30f97383f1a64fa 100644
--- a/src/algorithms/DPTexture.cpp
+++ b/src/algorithms/DPTexture.cpp
@@ -4,9 +4,9 @@
 
 using namespace bgslibrary::algorithms;
 
-DPTexture::DPTexture():
-  IBGS(quote(DPTexture)), 
-  // enableFiltering(true)
+DPTexture::DPTexture() :
+  IBGS(quote(DPTexture))
+  //, enableFiltering(true)
 {
   debug_construction(DPTexture);
   initLoadSaveConfig(algorithmName);
@@ -29,7 +29,8 @@ void DPTexture::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &
 {
   init(img_input, img_output, img_bgmodel);
 
-  frame = new IplImage(img_input);
+  //frame = new IplImage(img_input);
+  frame = cvCloneImage(&(IplImage)img_input);
 
   if (firstTime) {
     width = img_input.size().width;
@@ -47,20 +48,20 @@ void DPTexture::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &
     cvZero(tempMask.Ptr());
 
     // create background model
-    bgModel = new TextureArray[size];
+    bgModel = new dp::TextureArray[size];
     texture = cvCreateImage(cvSize(width, height), 8, 3);
     cvZero(texture.Ptr());
     modeArray = new unsigned char[size];
-    curTextureHist = new TextureHistogram[size];
+    curTextureHist = new dp::TextureHistogram[size];
 
     // initialize background model
     bgs.LBP(image, texture);
     bgs.Histogram(texture, curTextureHist);
-    for (int y = REGION_R + TEXTURE_R; y < height - REGION_R - TEXTURE_R; ++y) 
-      for (int x = REGION_R + TEXTURE_R; x < width - REGION_R - TEXTURE_R; ++x) {
+    for (int y = dp::REGION_R + dp::TEXTURE_R; y < height - dp::REGION_R - dp::TEXTURE_R; ++y) {
+      for (int x = dp::REGION_R + dp::TEXTURE_R; x < width - dp::REGION_R - dp::TEXTURE_R; ++x) {
         int index = x + y*width;
-        for (int m = 0; m < NUM_MODES; ++m) {
-          for (int i = 0; i < NUM_BINS; ++i) {
+        for (int m = 0; m < dp::NUM_MODES; ++m) {
+          for (int i = 0; i < dp::NUM_BINS; ++i) {
             bgModel[index].mode[m].r[i] = curTextureHist[index].r[i];
             bgModel[index].mode[m].g[i] = curTextureHist[index].g[i];
             bgModel[index].mode[m].b[i] = curTextureHist[index].b[i];
@@ -79,7 +80,7 @@ void DPTexture::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &
   // perform background subtraction
   bgs.LBP(image, texture);
   bgs.Histogram(texture, curTextureHist);
-  bgs.BgsCompare(bgModel, curTextureHist, modeArray, THRESHOLD, fgMask);
+  bgs.BgsCompare(bgModel, curTextureHist, modeArray, dp::THRESHOLD, fgMask);
 
   //if(enableFiltering)
   //{
diff --git a/src/algorithms/DPTexture.h b/src/algorithms/DPTexture.h
index a908687a138ba1d4cf151a0a950db02b04f17f7c..b78dffeca593a7fae41486d9262b4248eb0ffc9e 100644
--- a/src/algorithms/DPTexture.h
+++ b/src/algorithms/DPTexture.h
@@ -5,6 +5,11 @@
 #include "opencv2/core/version.hpp"
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
+// opencv legacy includes
+#include "opencv2/core/core_c.h"
+#include "opencv2/core/types_c.h"
+#include "opencv2/imgproc/imgproc_c.h"
+
 #include "dp/TextureBGS.h"
 //#include "ConnectedComponents.h"
 
@@ -18,15 +23,15 @@ namespace bgslibrary
       int width;
       int height;
       int size;
-      TextureBGS bgs;
-      IplImage* frame;
-      RgbImage image;
-      BwImage fgMask;
-      BwImage tempMask;
-      TextureArray* bgModel;
-      RgbImage texture;
       unsigned char* modeArray;
-      TextureHistogram* curTextureHist;
+      IplImage* frame;
+      dp::TextureBGS bgs;
+      dp::RgbImage image;
+      dp::BwImage fgMask;
+      dp::BwImage tempMask;
+      dp::TextureArray* bgModel;
+      dp::RgbImage texture;
+      dp::TextureHistogram* curTextureHist;
       //ConnectedComponents cc;
       //CBlobResult largeBlobs;
       //IplConvKernel* dilateElement;
diff --git a/src/algorithms/DPWrenGA.h b/src/algorithms/DPWrenGA.h
index 0fe1e6c7a8f8b87fd21146b5d8beb8195032cb33..4be0d8ca907677df681ef9ece231c5f4ceb41d09 100644
--- a/src/algorithms/DPWrenGA.h
+++ b/src/algorithms/DPWrenGA.h
@@ -7,8 +7,6 @@
 
 #include "dp/WrenGA.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,17 +15,15 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage* frame;
-      RgbImage frame_data;
-
-      WrenParams params;
-      WrenGA bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       double threshold;
       double alpha;
       int learningFrames;
+      IplImage* frame;
+      dp::RgbImage frame_data;
+      dp::WrenParams params;
+      dp::WrenGA bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
 
     public:
       DPWrenGA();
diff --git a/src/algorithms/DPZivkovicAGMM.h b/src/algorithms/DPZivkovicAGMM.h
index 4100ee63521190e234e5fd6288b5dcfd4db8c800..ca2c1a6e2e210f42de1a8bff3fa8f3c43cc141fa 100644
--- a/src/algorithms/DPZivkovicAGMM.h
+++ b/src/algorithms/DPZivkovicAGMM.h
@@ -7,8 +7,6 @@
 
 #include "dp/ZivkovicAGMM.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,17 +15,15 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage* frame;
-      RgbImage frame_data;
-
-      ZivkovicParams params;
-      ZivkovicAGMM bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       double threshold;
       double alpha;
       int gaussians;
+      IplImage* frame;
+      dp::RgbImage frame_data;
+      dp::ZivkovicParams params;
+      dp::ZivkovicAGMM bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
 
     public:
       DPZivkovicAGMM();
diff --git a/src/algorithms/FuzzyChoquetIntegral.cpp b/src/algorithms/FuzzyChoquetIntegral.cpp
index b9140bfd17296af8d98ed483a8df5f05ba3f535d..90dfe6eaee5f6cc8f90f44f14de280dc26ee862e 100644
--- a/src/algorithms/FuzzyChoquetIntegral.cpp
+++ b/src/algorithms/FuzzyChoquetIntegral.cpp
@@ -128,10 +128,9 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output
 
 #ifndef MEX_COMPILE_FLAG
     if (showOutput) {
-      cvShowImage(algorithmName + "_LBP_IN", lbp_input_f1);
-      cvShowImage(algorithmName + "_LBP_BG", lbp_background_f1);
-      cvShowImage(algorithmName + "_FG_PROB", integral_choquet_f1);
-
+      cv::imshow(algorithmName + "_LBP_IN", cv::cvarrToMat(lbp_input_f1));
+      cv::imshow(algorithmName + "_LBP_BG", cv::cvarrToMat(lbp_background_f1));
+      cv::imshow(algorithmName + "_FG_PROB", cv::cvarrToMat(integral_choquet_f1));
       cv::imshow(algorithmName + "_BG", img_background);
       cv::imshow(algorithmName + "_FG", img_foreground);
     }
diff --git a/src/algorithms/FuzzyChoquetIntegral.h b/src/algorithms/FuzzyChoquetIntegral.h
index ba348dbeaebd1daaf9fd3bd983373bf56be432a9..992f65148b61a15579b020a3f69aa6679920a3e0 100644
--- a/src/algorithms/FuzzyChoquetIntegral.h
+++ b/src/algorithms/FuzzyChoquetIntegral.h
@@ -5,7 +5,7 @@
 #include "opencv2/core/version.hpp"
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-#include "T2F/FuzzyUtils.h"
+#include "../tools/FuzzyUtils.h"
 
 namespace bgslibrary
 {
@@ -13,9 +13,15 @@ namespace bgslibrary
   {
     class FuzzyChoquetIntegral : public IBGS
     {
+    public:
+      FuzzyChoquetIntegral();
+      ~FuzzyChoquetIntegral();
+
+      typedef bgslibrary::tools::FuzzyUtils FuzzyUtils;
+      void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
     private:
-      long long frameNumber;
-      
+      long frameNumber;
       int framesToLearn;
       double alphaLearn;
       double alphaUpdate;
@@ -23,17 +29,9 @@ namespace bgslibrary
       int option;
       bool smooth;
       double threshold;
-
       FuzzyUtils fu;
       cv::Mat img_background_f3;
-
-    public:
-      FuzzyChoquetIntegral();
-      ~FuzzyChoquetIntegral();
-
-      void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
-
-    private:
+      
       void save_config(cv::FileStorage &fs);
       void load_config(cv::FileStorage &fs);
     };
diff --git a/src/algorithms/FuzzySugenoIntegral.cpp b/src/algorithms/FuzzySugenoIntegral.cpp
index 03f63fa57ef71cb954235f3b52f1d2c223f03ab5..5ac009af330383cec02cedacf156c84708949908 100644
--- a/src/algorithms/FuzzySugenoIntegral.cpp
+++ b/src/algorithms/FuzzySugenoIntegral.cpp
@@ -127,10 +127,9 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output,
 
 #ifndef MEX_COMPILE_FLAG
     if (showOutput) {
-      cvShowImage(algorithmName + "_LBP_IN", lbp_input_f1);
-      cvShowImage(algorithmName + "_LBP_BG", lbp_background_f1);
-      cvShowImage(algorithmName + "_FG_PROB", integral_sugeno_f1);
-
+      cv::imshow(algorithmName + "_LBP_IN", cv::cvarrToMat(lbp_input_f1));
+      cv::imshow(algorithmName + "_LBP_BG", cv::cvarrToMat(lbp_background_f1));
+      cv::imshow(algorithmName + "_FG_PROB", cv::cvarrToMat(integral_sugeno_f1));
       cv::imshow(algorithmName + "_BG", img_background);
       cv::imshow(algorithmName + "_FG", img_foreground);
     }
diff --git a/src/algorithms/FuzzySugenoIntegral.h b/src/algorithms/FuzzySugenoIntegral.h
index ed680a3cfc753a53c6f5029e0eeb11af2c75d59e..fefd11be42bcea2e44d7045971d1ec155d1c3827 100644
--- a/src/algorithms/FuzzySugenoIntegral.h
+++ b/src/algorithms/FuzzySugenoIntegral.h
@@ -5,7 +5,7 @@
 #include "opencv2/core/version.hpp"
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-#include "T2F/FuzzyUtils.h"
+#include "../tools/FuzzyUtils.h"
 
 namespace bgslibrary
 {
@@ -13,9 +13,15 @@ namespace bgslibrary
   {
     class FuzzySugenoIntegral : public IBGS
     {
-    private:
-      long long frameNumber;
+    public:
+      FuzzySugenoIntegral();
+      ~FuzzySugenoIntegral();
 
+      typedef bgslibrary::tools::FuzzyUtils FuzzyUtils;
+      void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+    private:
+      long frameNumber;
       int framesToLearn;
       double alphaLearn;
       double alphaUpdate;
@@ -23,17 +29,9 @@ namespace bgslibrary
       int option;
       bool smooth;
       double threshold;
-
-      FuzzyUtils fu;
       cv::Mat img_background_f3;
+      FuzzyUtils fu;
 
-    public:
-      FuzzySugenoIntegral();
-      ~FuzzySugenoIntegral();
-
-      void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
-
-    private:
       void save_config(cv::FileStorage &fs);
       void load_config(cv::FileStorage &fs);
     };
diff --git a/src/algorithms/IMBS/IMBS.cpp b/src/algorithms/IMBS/IMBS.cpp
index acf3c5b6a08345f6154b33b83fe875077a79ee67..bab74da8deb60b83f84b49a64d6869c085ca45c5 100644
--- a/src/algorithms/IMBS/IMBS.cpp
+++ b/src/algorithms/IMBS/IMBS.cpp
@@ -1,5 +1,6 @@
 #include "IMBS.hpp"
 
+using namespace bgslibrary::algorithms::imbs;
 using namespace std;
 using namespace cv;
 
diff --git a/src/algorithms/IMBS/IMBS.hpp b/src/algorithms/IMBS/IMBS.hpp
index 7a89949e6a2a8d62e5b72e10bafef3f2d800f2e9..9ddc66fac1b27bdf7ec92b9ad73b8cbb677419a6 100644
--- a/src/algorithms/IMBS/IMBS.hpp
+++ b/src/algorithms/IMBS/IMBS.hpp
@@ -12,169 +12,173 @@
 #include <opencv2/imgproc/imgproc_c.h>
 #include <opencv2/highgui/highgui_c.h>
 
-using namespace cv;
-using namespace std;
-
-class BackgroundSubtractorIMBS
+namespace bgslibrary
 {
-public:
-  //! the default constructor
-  BackgroundSubtractorIMBS();
-  //! the full constructor
-  BackgroundSubtractorIMBS(double fps,
-    unsigned int fgThreshold = 15,
-    unsigned int associationThreshold = 5,
-    double samplingPeriod = 500.,
-    unsigned int minBinHeight = 2,
-    unsigned int numSamples = 30,
-    double alpha = 0.65,
-    double beta = 1.15,
-    double tau_s = 60.,
-    double tau_h = 40.,
-    double minArea = 30.,
-    double persistencePeriod = 10000.,
-    bool morphologicalFiltering = false
-  );
-  //! the destructor
-  ~BackgroundSubtractorIMBS();
-  //! the update operator
-  void apply(InputArray image, OutputArray fgmask, double learningRate = -1.);
-
-  //! computes a background image which shows only the highest bin for each pixel
-  void getBackgroundImage(OutputArray backgroundImage) const;
-
-  //! re-initiaization method
-  void initialize(Size frameSize, int frameType);
-
-private:
-  //method for creating the background model
-  void createBg(unsigned int bg_sample_number);
-  //method for updating the background model
-  void updateBg();
-  //method for computing the foreground mask
-  void getFg();
-  //method for suppressing shadows and highlights
-  void hsvSuppression();
-  //method for refining foreground mask
-  void filterFg();
-  //method for filtering out blobs smaller than a given area
-  void areaThresholding();
-  //method for getting the current time
-  double getTimestamp();
-  //method for converting from RGB to HSV
-  Mat convertImageRGBtoHSV(const Mat& imageRGB);
-  //method for changing the bg in case of sudden changes
-  void changeBg();
-
-  //current input RGB frame
-  Mat frame;
-  vector<Mat> frameBGR;
-  //frame size
-  Size frameSize;
-  //frame type
-  int frameType;
-  //total number of pixels in frame
-  unsigned int numPixels;
-  //current background sample
-  Mat bgSample;
-  vector<Mat> bgSampleBGR;
-  //current background image which shows only the highest bin for each pixel
-  //(just for displaying purposes)
-  Mat bgImage;
-  //current foreground mask
-  Mat fgmask;
-
-  Mat fgfiltered;
-
-  //number of fps
-  double fps;
-  //time stamp in milliseconds (ms)
-  double timestamp;
-  //previous time stamp in milliseconds (ms)
-  double prev_timestamp;
-  double initial_tick_count;
-  //initial message to be shown until the first bg model is ready
-  Mat initialMsgGray;
-  Mat initialMsgRGB;
-
-  //struct for modeling the background values for a single pixel
-  typedef struct Bins {
-    void initialize(unsigned int numSamples) {
-      binValues = new Vec3b[numSamples];
-      binHeights = new uchar[numSamples];
-      isFg = new bool[numSamples];
-    }
-    ~Bins() {
-      if (binValues)  { delete[] binValues; }
-      if (binHeights) { delete[] binHeights; }
-      if (isFg)       { delete[] isFg; }
+  namespace algorithms
+  {
+    namespace imbs
+    {
+      class BackgroundSubtractorIMBS
+      {
+      public:
+        //! the default constructor
+        BackgroundSubtractorIMBS();
+        //! the full constructor
+        BackgroundSubtractorIMBS(double fps,
+          unsigned int fgThreshold = 15,
+          unsigned int associationThreshold = 5,
+          double samplingPeriod = 500.,
+          unsigned int minBinHeight = 2,
+          unsigned int numSamples = 30,
+          double alpha = 0.65,
+          double beta = 1.15,
+          double tau_s = 60.,
+          double tau_h = 40.,
+          double minArea = 30.,
+          double persistencePeriod = 10000.,
+          bool morphologicalFiltering = false
+        );
+        //! the destructor
+        ~BackgroundSubtractorIMBS();
+        //! the update operator
+        void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = -1.);
+
+        //! computes a background image which shows only the highest bin for each pixel
+        void getBackgroundImage(cv::OutputArray backgroundImage) const;
+
+        //! re-initiaization method
+        void initialize(cv::Size frameSize, int frameType);
+
+      private:
+        //method for creating the background model
+        void createBg(unsigned int bg_sample_number);
+        //method for updating the background model
+        void updateBg();
+        //method for computing the foreground mask
+        void getFg();
+        //method for suppressing shadows and highlights
+        void hsvSuppression();
+        //method for refining foreground mask
+        void filterFg();
+        //method for filtering out blobs smaller than a given area
+        void areaThresholding();
+        //method for getting the current time
+        double getTimestamp();
+        //method for converting from RGB to HSV
+        cv::Mat convertImageRGBtoHSV(const cv::Mat& imageRGB);
+        //method for changing the bg in case of sudden changes
+        void changeBg();
+
+        //current input RGB frame
+        cv::Mat frame;
+        std::vector<cv::Mat> frameBGR;
+        //frame size
+        cv::Size frameSize;
+        //frame type
+        int frameType;
+        //total number of pixels in frame
+        unsigned int numPixels;
+        //current background sample
+        cv::Mat bgSample;
+        std::vector<cv::Mat> bgSampleBGR;
+        //current background image which shows only the highest bin for each pixel
+        //(just for displaying purposes)
+        cv::Mat bgImage;
+        //current foreground mask
+        cv::Mat fgmask;
+        cv::Mat fgfiltered;
+        //number of fps
+        double fps;
+        //time stamp in milliseconds (ms)
+        double timestamp;
+        //previous time stamp in milliseconds (ms)
+        double prev_timestamp;
+        double initial_tick_count;
+        //initial message to be shown until the first bg model is ready
+        cv::Mat initialMsgGray;
+        cv::Mat initialMsgRGB;
+
+        //struct for modeling the background values for a single pixel
+        typedef struct Bins {
+          void initialize(unsigned int numSamples) {
+            binValues = new cv::Vec3b[numSamples];
+            binHeights = new uchar[numSamples];
+            isFg = new bool[numSamples];
+          }
+          ~Bins() {
+            if (binValues)  { delete[] binValues; }
+            if (binHeights) { delete[] binHeights; }
+            if (isFg)       { delete[] isFg; }
+          }
+          cv::Vec3b* binValues;
+          uchar* binHeights;
+          bool* isFg;
+        } Bins;
+        Bins* bgBins;
+
+      public:
+        //struct for modeling the background values for the entire frame
+        typedef struct BgModel {
+          void initialize(unsigned int maxBgBins) {
+            values = new cv::Vec3b[maxBgBins];
+            isValid = new bool[maxBgBins];
+            isValid[0] = false;
+            isFg = new bool[maxBgBins];
+            counter = new uchar[maxBgBins];
+          }
+          ~BgModel() {
+            if (values)  { delete[] values; }
+            if (isValid) { delete[] isValid; }
+            if (isFg)    { delete[] isFg; }
+            if (counter) { delete[] counter; }
+          }
+          cv::Vec3b* values;
+          bool* isValid;
+          bool* isFg;
+          uchar* counter;
+        } BgModel;
+      private:
+        BgModel* bgModel;
+
+        //SHADOW SUPPRESSION PARAMETERS
+        float alpha;
+        float beta;
+        uchar tau_s;
+        uchar tau_h;
+
+        unsigned int minBinHeight;
+        unsigned int numSamples;
+        unsigned int samplingPeriod;
+        unsigned long prev_bg_frame_time;
+        unsigned int bg_frame_counter;
+        unsigned int associationThreshold;
+        unsigned int maxBgBins;
+        unsigned int nframes;
+
+        double minArea;
+        bool bg_reset;
+        unsigned int persistencePeriod;
+        bool prev_area;
+        bool sudden_change;
+        unsigned int fgThreshold;
+        uchar SHADOW_LABEL;
+        uchar PERSISTENCE_LABEL;
+        uchar FOREGROUND_LABEL;
+        //persistence map
+        unsigned int* persistenceMap;
+        cv::Mat persistenceImage;
+
+        bool morphologicalFiltering;
+
+      public:
+        unsigned int getMaxBgBins() {
+          return maxBgBins;
+        }
+        unsigned int getFgThreshold() {
+          return fgThreshold;
+        }
+        void getBgModel(BgModel bgModel_copy[], unsigned int size);
+      };
     }
-    Vec3b* binValues;
-    uchar* binHeights;
-    bool* isFg;
-  } Bins;
-  Bins* bgBins;
-
-public:
-  //struct for modeling the background values for the entire frame
-  typedef struct BgModel {
-    void initialize(unsigned int maxBgBins) {
-      values = new Vec3b[maxBgBins];
-      isValid = new bool[maxBgBins];
-      isValid[0] = false;
-      isFg = new bool[maxBgBins];
-      counter = new uchar[maxBgBins];
-    }
-    ~BgModel() {
-      if (values)  { delete[] values; }
-      if (isValid) { delete[] isValid; }
-      if (isFg)    { delete[] isFg; }
-      if (counter) { delete[] counter; }
-    }
-    Vec3b* values;
-    bool* isValid;
-    bool* isFg;
-    uchar* counter;
-  } BgModel;
-private:
-  BgModel* bgModel;
-
-  //SHADOW SUPPRESSION PARAMETERS
-  float alpha;
-  float beta;
-  uchar tau_s;
-  uchar tau_h;
-
-  unsigned int minBinHeight;
-  unsigned int numSamples;
-  unsigned int samplingPeriod;
-  unsigned long prev_bg_frame_time;
-  unsigned int bg_frame_counter;
-  unsigned int associationThreshold;
-  unsigned int maxBgBins;
-  unsigned int nframes;
-
-  double minArea;
-  bool bg_reset;
-  unsigned int persistencePeriod;
-  bool prev_area;
-  bool sudden_change;
-  unsigned int fgThreshold;
-  uchar SHADOW_LABEL;
-  uchar PERSISTENCE_LABEL;
-  uchar FOREGROUND_LABEL;
-  //persistence map
-  unsigned int* persistenceMap;
-  Mat persistenceImage;
-
-  bool morphologicalFiltering;
-
-public:
-  unsigned int getMaxBgBins() {
-    return maxBgBins;
-  }
-  unsigned int getFgThreshold() {
-    return fgThreshold;
   }
-  void getBgModel(BgModel bgModel_copy[], unsigned int size);
-};
+}
diff --git a/src/algorithms/IndependentMultimodal.cpp b/src/algorithms/IndependentMultimodal.cpp
index e5a69701ab0f98c7e6c024426bc03c4917ba05df..10d3ccaba2497d565aeec55facdd710bfd14ae3f 100644
--- a/src/algorithms/IndependentMultimodal.cpp
+++ b/src/algorithms/IndependentMultimodal.cpp
@@ -9,7 +9,7 @@ IndependentMultimodal::IndependentMultimodal() :
 {
   debug_construction(IndependentMultimodal);
   initLoadSaveConfig(algorithmName);
-  pIMBS = new BackgroundSubtractorIMBS(fps);
+  pIMBS = new imbs::BackgroundSubtractorIMBS(fps);
 }
 
 IndependentMultimodal::~IndependentMultimodal() {
diff --git a/src/algorithms/IndependentMultimodal.h b/src/algorithms/IndependentMultimodal.h
index 2bbdbcfbb81642c563092aee0d6bffcab54e605a..6dc654da5e02dcca98f2121a36090cbbf7bb06a0 100644
--- a/src/algorithms/IndependentMultimodal.h
+++ b/src/algorithms/IndependentMultimodal.h
@@ -14,7 +14,7 @@ namespace bgslibrary
     class IndependentMultimodal : public IBGS
     {
     private:
-      BackgroundSubtractorIMBS* pIMBS;
+      imbs::BackgroundSubtractorIMBS* pIMBS;
       int fps;
 
     public:
diff --git a/src/algorithms/KDE.cpp b/src/algorithms/KDE.cpp
index e438ee7568dc577a4101de8107e7e2c4533a942f..ac6832a1dcf63dec35f79c8901ca42dbd97c9229 100644
--- a/src/algorithms/KDE.cpp
+++ b/src/algorithms/KDE.cpp
@@ -12,7 +12,7 @@ KDE::KDE() :
 {
   debug_construction(KDE);
   initLoadSaveConfig(algorithmName);
-  p = new NPBGSubtractor;
+  p = new kde::NPBGSubtractor;
 }
 
 KDE::~KDE() {
@@ -65,11 +65,11 @@ void KDE::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bg
     }
 
     // Now, we can subtract the background
-    ((NPBGSubtractor*)p)->NBBGSubtraction(img_input.data, FGImage, FilteredFGImage, DisplayBuffers);
+    ((kde::NPBGSubtractor*)p)->NBBGSubtraction(img_input.data, FGImage, FilteredFGImage, DisplayBuffers);
 
     // At each frame also you can call the update function to adapt the bg
     // here you pass a mask where pixels with true value will be masked out of the update.
-    ((NPBGSubtractor*)p)->Update(FGImage);
+    ((kde::NPBGSubtractor*)p)->Update(FGImage);
 
     img_foreground.data = FGImage;
   }
diff --git a/src/algorithms/KDE.h b/src/algorithms/KDE.h
index 91e9fa181e325dc7925a2778c6edf9ca595ff70d..d0eee8ab46be6fd7a5acd3536013e8f6da205ca0 100644
--- a/src/algorithms/KDE.h
+++ b/src/algorithms/KDE.h
@@ -14,7 +14,7 @@ namespace bgslibrary
     class KDE : public IBGS
     {
     private:
-      NPBGSubtractor *p;
+      kde::NPBGSubtractor *p;
       int rows;
       int cols;
       int color_channels;
diff --git a/src/algorithms/KDE/KernelTable.cpp b/src/algorithms/KDE/KernelTable.cpp
index 0ab243b50e9d1ab5848def743fcbccfb390f07d2..0b796556458185b3aa0dfb2f37201bdc7b31ef92 100644
--- a/src/algorithms/KDE/KernelTable.cpp
+++ b/src/algorithms/KDE/KernelTable.cpp
@@ -2,7 +2,11 @@
 
 #include "KernelTable.h"
 
-#define PI 3.14159
+#ifndef PI
+#define PI 3.141592653589793f
+#endif
+
+using namespace bgslibrary::algorithms::kde;
 
 KernelLUTable::KernelLUTable()
 {
diff --git a/src/algorithms/KDE/KernelTable.h b/src/algorithms/KDE/KernelTable.h
index cf18a3e89e163ee1b47f652cdd440eedc8f02e7d..98d6c67adde1060f74c494b3f2b3b32429835234 100644
--- a/src/algorithms/KDE/KernelTable.h
+++ b/src/algorithms/KDE/KernelTable.h
@@ -2,19 +2,28 @@
 
 #include <iostream>
 
-class KernelLUTable
+namespace bgslibrary
 {
-public:
-  double minsegma;
-  double maxsegma;
-  int segmabins;
-  int tablehalfwidth;
-  double *kerneltable;
-  double *kernelsums;
+  namespace algorithms
+  {
+    namespace kde
+    {
+      class KernelLUTable
+      {
+      public:
+        double minsegma;
+        double maxsegma;
+        int segmabins;
+        int tablehalfwidth;
+        double *kerneltable;
+        double *kernelsums;
 
-public:
-  KernelLUTable();
-  ~KernelLUTable();
+      public:
+        KernelLUTable();
+        ~KernelLUTable();
 
-  KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmamax, int Segmabins);
-};
+        KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmamax, int Segmabins);
+      };
+    }
+  }
+}
diff --git a/src/algorithms/KDE/NPBGSubtractor.cpp b/src/algorithms/KDE/NPBGSubtractor.cpp
index bcc4b0908fd841771c98a3255172847b5d59fc77..812fffcb19147a9a79a88d0e55136b582b56828d 100644
--- a/src/algorithms/KDE/NPBGSubtractor.cpp
+++ b/src/algorithms/KDE/NPBGSubtractor.cpp
@@ -9,1101 +9,1111 @@
 //static char THIS_FILE[]=__FILE__;
 //#define new DEBUG_NEW
 //#endif
+//using namespace bgslibrary::algorithms::kde;
 
-void BGR2SnGnRn(unsigned char * in_image,
-  unsigned char * out_image,
-  unsigned int rows,
-  unsigned int cols)
+namespace bgslibrary
 {
-  unsigned int i;
-  unsigned int r2, r3;
-  unsigned int r, g, b;
-  double s;
-
-  for (i = 0; i < rows*cols * 3; i += 3)
+  namespace algorithms
   {
-    b = in_image[i];
-    g = in_image[i + 1];
-    r = in_image[i + 2];
-
-    // calculate color ratios
-    s = (double)255 / (double)(b + g + r + 30);
+    namespace kde
+    {
+      void BGR2SnGnRn(unsigned char * in_image,
+        unsigned char * out_image,
+        unsigned int rows,
+        unsigned int cols)
+      {
+        unsigned int i;
+        unsigned int r2, r3;
+        unsigned int r, g, b;
+        double s;
 
-    r2 = (unsigned int)((g + 10) * s);
-    r3 = (unsigned int)((r + 10) * s);
+        for (i = 0; i < rows*cols * 3; i += 3)
+        {
+          b = in_image[i];
+          g = in_image[i + 1];
+          r = in_image[i + 2];
 
-    out_image[i] = (unsigned char)(((unsigned int)b + g + r) / 3);
-    out_image[i + 1] = (unsigned char)(r2 > 255 ? 255 : r2);
-    out_image[i + 2] = (unsigned char)(r3 > 255 ? 255 : r3);
-  }
-}
+          // calculate color ratios
+          s = (double)255 / (double)(b + g + r + 30);
 
-void UpdateDiffHist(unsigned char * image1, unsigned char * image2, DynamicMedianHistogram * pHist)
-{
-  unsigned int j;
-  int bin, diff;
+          r2 = (unsigned int)((g + 10) * s);
+          r3 = (unsigned int)((r + 10) * s);
 
-  unsigned int  imagesize = pHist->imagesize;
-  unsigned char histbins = pHist->histbins;
-  unsigned char *pAbsDiffHist = pHist->Hist;
-
-  int histbins_1 = histbins - 1;
+          out_image[i] = (unsigned char)(((unsigned int)b + g + r) / 3);
+          out_image[i + 1] = (unsigned char)(r2 > 255 ? 255 : r2);
+          out_image[i + 2] = (unsigned char)(r3 > 255 ? 255 : r3);
+        }
+      }
 
-  for (j = 0; j < imagesize; j++)
-  {
-    diff = (int)image1[j] - (int)image2[j];
-    diff = abs(diff);
-    // update histogram
-    bin = (diff < histbins ? diff : histbins_1);
-    pAbsDiffHist[j*histbins + bin]++;
-  }
-}
+      void UpdateDiffHist(unsigned char * image1, unsigned char * image2, DynamicMedianHistogram * pHist)
+      {
+        unsigned int j;
+        int bin, diff;
 
-void FindHistMedians(DynamicMedianHistogram * pAbsDiffHist)
-{
-  unsigned char * Hist = pAbsDiffHist->Hist;
-  unsigned char * MedianBins = pAbsDiffHist->MedianBins;
-  unsigned char * AccSum = pAbsDiffHist->AccSum;
-  unsigned char histsum = pAbsDiffHist->histsum;
-  unsigned char histbins = pAbsDiffHist->histbins;
-  unsigned int imagesize = pAbsDiffHist->imagesize;
-
-  int sum;
-  int bin;
-  unsigned int histindex;
-  unsigned char medianCount = histsum / 2;
-  unsigned int j;
-
-  // find medians
-  for (j = 0; j < imagesize; j++)
-  {
-    // find the median
-    bin = 0;
-    sum = 0;
+        unsigned int  imagesize = pHist->imagesize;
+        unsigned char histbins = pHist->histbins;
+        unsigned char *pAbsDiffHist = pHist->Hist;
 
-    histindex = j*histbins;
+        int histbins_1 = histbins - 1;
 
-    while (sum < medianCount)
-    {
-      sum += Hist[histindex + bin];
-      bin++;
-    }
+        for (j = 0; j < imagesize; j++)
+        {
+          diff = (int)image1[j] - (int)image2[j];
+          diff = abs(diff);
+          // update histogram
+          bin = (diff < histbins ? diff : histbins_1);
+          pAbsDiffHist[j*histbins + bin]++;
+        }
+      }
 
-    bin--;
+      void FindHistMedians(DynamicMedianHistogram * pAbsDiffHist)
+      {
+        unsigned char * Hist = pAbsDiffHist->Hist;
+        unsigned char * MedianBins = pAbsDiffHist->MedianBins;
+        unsigned char * AccSum = pAbsDiffHist->AccSum;
+        unsigned char histsum = pAbsDiffHist->histsum;
+        unsigned char histbins = pAbsDiffHist->histbins;
+        unsigned int imagesize = pAbsDiffHist->imagesize;
+
+        int sum;
+        int bin;
+        unsigned int histindex;
+        unsigned char medianCount = histsum / 2;
+        unsigned int j;
+
+        // find medians
+        for (j = 0; j < imagesize; j++)
+        {
+          // find the median
+          bin = 0;
+          sum = 0;
 
-    MedianBins[j] = bin;
-    AccSum[j] = sum;
-  }
-}
+          histindex = j*histbins;
 
-DynamicMedianHistogram BuildAbsDiffHist(unsigned char * pSequence,
-  unsigned int rows,
-  unsigned int cols,
-  unsigned int color_channels,
-  unsigned int SequenceLength,
-  unsigned int histbins)
-{
+          while (sum < medianCount)
+          {
+            sum += Hist[histindex + bin];
+            bin++;
+          }
 
-  unsigned int imagesize = rows*cols*color_channels;
-  unsigned int i;
+          bin--;
 
-  DynamicMedianHistogram Hist;
+          MedianBins[j] = bin;
+          AccSum[j] = sum;
+        }
+      }
 
-  unsigned char *pAbsDiffHist = new unsigned char[rows*cols*color_channels*histbins];
-  unsigned char *pMedianBins = new unsigned char[rows*cols*color_channels];
-  unsigned char *pMedianFreq = new unsigned char[rows*cols*color_channels];
-  unsigned char *pAccSum = new unsigned char[rows*cols*color_channels];
+      DynamicMedianHistogram BuildAbsDiffHist(unsigned char * pSequence,
+        unsigned int rows,
+        unsigned int cols,
+        unsigned int color_channels,
+        unsigned int SequenceLength,
+        unsigned int histbins)
+      {
 
-  memset(pAbsDiffHist, 0, rows*cols*color_channels*histbins);
+        unsigned int imagesize = rows*cols*color_channels;
+        unsigned int i;
 
-  Hist.Hist = pAbsDiffHist;
-  Hist.MedianBins = pMedianBins;
-  Hist.MedianFreq = pMedianFreq;
-  Hist.AccSum = pAccSum;
-  Hist.histbins = histbins;
-  Hist.imagesize = rows*cols*color_channels;
-  Hist.histsum = SequenceLength - 1;
+        DynamicMedianHistogram Hist;
 
-  unsigned char *image1, *image2;
-  for (i = 1; i < SequenceLength; i++)
-  {
-    // find diff between frame i,i-1;
-    image1 = pSequence + (i - 1)*imagesize;
-    image2 = pSequence + (i)*imagesize;
+        unsigned char *pAbsDiffHist = new unsigned char[rows*cols*color_channels*histbins];
+        unsigned char *pMedianBins = new unsigned char[rows*cols*color_channels];
+        unsigned char *pMedianFreq = new unsigned char[rows*cols*color_channels];
+        unsigned char *pAccSum = new unsigned char[rows*cols*color_channels];
 
-    UpdateDiffHist(image1, image2, &Hist);
-  }
+        memset(pAbsDiffHist, 0, rows*cols*color_channels*histbins);
 
-  FindHistMedians(&Hist);
+        Hist.Hist = pAbsDiffHist;
+        Hist.MedianBins = pMedianBins;
+        Hist.MedianFreq = pMedianFreq;
+        Hist.AccSum = pAccSum;
+        Hist.histbins = histbins;
+        Hist.imagesize = rows*cols*color_channels;
+        Hist.histsum = SequenceLength - 1;
 
-  return Hist;
-}
+        unsigned char *image1, *image2;
+        for (i = 1; i < SequenceLength; i++)
+        {
+          // find diff between frame i,i-1;
+          image1 = pSequence + (i - 1)*imagesize;
+          image2 = pSequence + (i)*imagesize;
 
-void EstimateSDsFromAbsDiffHist(DynamicMedianHistogram * pAbsDiffHist,
-  unsigned char * pSDs,
-  unsigned int imagesize,
-  double MinSD,
-  double MaxSD,
-  unsigned int kernelbins)
-{
-  double v;
-  double kernelbinfactor = (kernelbins - 1) / (MaxSD - MinSD);
-  int medianCount;
-  int sum;
-  int bin;
-  unsigned int histindex;
-  unsigned int j;
-  unsigned int x1, x2;
-
-  unsigned char *Hist = pAbsDiffHist->Hist;
-  unsigned char *MedianBins = pAbsDiffHist->MedianBins;
-  unsigned char *AccSum = pAbsDiffHist->AccSum;
-  unsigned char histsum = pAbsDiffHist->histsum;
-  unsigned char histbins = pAbsDiffHist->histbins;
-
-  medianCount = (histsum) / 2;
-
-  for (j = 0; j < imagesize; j++)
-  {
-    histindex = j*histbins;
+          UpdateDiffHist(image1, image2, &Hist);
+        }
 
-    bin = MedianBins[j];
-    sum = AccSum[j];
+        FindHistMedians(&Hist);
 
-    x1 = sum - Hist[histindex + bin];
-    x2 = sum;
+        return Hist;
+      }
 
-    // interpolate to get the median
-    // x1 < 50 % < x2
+      void EstimateSDsFromAbsDiffHist(DynamicMedianHistogram * pAbsDiffHist,
+        unsigned char * pSDs,
+        unsigned int imagesize,
+        double MinSD,
+        double MaxSD,
+        unsigned int kernelbins)
+      {
+        double v;
+        double kernelbinfactor = (kernelbins - 1) / (MaxSD - MinSD);
+        int medianCount;
+        int sum;
+        int bin;
+        unsigned int histindex;
+        unsigned int j;
+        unsigned int x1, x2;
+
+        unsigned char *Hist = pAbsDiffHist->Hist;
+        unsigned char *MedianBins = pAbsDiffHist->MedianBins;
+        unsigned char *AccSum = pAbsDiffHist->AccSum;
+        unsigned char histsum = pAbsDiffHist->histsum;
+        unsigned char histbins = pAbsDiffHist->histbins;
+
+        medianCount = (histsum) / 2;
+
+        for (j = 0; j < imagesize; j++)
+        {
+          histindex = j*histbins;
 
-    v = 1.04 * ((double)bin - (double)(x2 - medianCount) / (double)(x2 - x1));
-    v = (v <= MinSD ? MinSD : v);
+          bin = MedianBins[j];
+          sum = AccSum[j];
 
-    // convert sd to kernel table bin
+          x1 = sum - Hist[histindex + bin];
+          x2 = sum;
 
-    bin = (int)(v >= MaxSD ? kernelbins - 1 : floor((v - MinSD)*kernelbinfactor + .5));
+          // interpolate to get the median
+          // x1 < 50 % < x2
 
-    assert(bin >= 0 && bin < kernelbins);
+          v = 1.04 * ((double)bin - (double)(x2 - medianCount) / (double)(x2 - x1));
+          v = (v <= MinSD ? MinSD : v);
 
-    pSDs[j] = bin;
-  }
-}
+          // convert sd to kernel table bin
 
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
+          bin = (int)(v >= MaxSD ? kernelbins - 1 : floor((v - MinSD)*kernelbinfactor + .5));
 
-NPBGSubtractor::NPBGSubtractor() {}
+          assert(bin >= 0 && bin < kernelbins);
 
-NPBGSubtractor::~NPBGSubtractor()
-{
-  delete AbsDiffHist.Hist;
-  delete AbsDiffHist.MedianBins;
-  delete AbsDiffHist.MedianFreq;
-  delete AbsDiffHist.AccSum;
-  delete KernelTable;
-  delete BGModel->SDbinsImage;
-  delete BGModel;
-  delete Pimage1;
-  delete Pimage2;
-  delete tempFrame;
-  delete imageindex->List;
-  delete imageindex;
-}
+          pSDs[j] = bin;
+        }
+      }
 
-int NPBGSubtractor::Intialize(unsigned int prows,
-  unsigned int pcols,
-  unsigned int pcolor_channels,
-  unsigned int SequenceLength,
-  unsigned int pTimeWindowSize,
-  unsigned char pSDEstimationFlag,
-  unsigned char pUseColorRatiosFlag)
-{
+      //////////////////////////////////////////////////////////////////////
+      // Construction/Destruction
+      //////////////////////////////////////////////////////////////////////
 
-  rows = prows;
-  cols = pcols;
-  color_channels = pcolor_channels;
-  imagesize = rows*cols*color_channels;
-  SdEstimateFlag = pSDEstimationFlag;
-  UseColorRatiosFlag = pUseColorRatiosFlag;
-  //SampleSize = SequenceLength;
+      NPBGSubtractor::NPBGSubtractor() {}
 
-  AdaptBGFlag = FALSE;
-  //
-  SubsetFlag = TRUE;
+      NPBGSubtractor::~NPBGSubtractor()
+      {
+        delete AbsDiffHist.Hist;
+        delete AbsDiffHist.MedianBins;
+        delete AbsDiffHist.MedianFreq;
+        delete AbsDiffHist.AccSum;
+        delete KernelTable;
+        delete BGModel->SDbinsImage;
+        delete BGModel;
+        delete Pimage1;
+        delete Pimage2;
+        delete tempFrame;
+        delete imageindex->List;
+        delete imageindex;
+      }
 
-  UpdateSDRate = 0;
+      int NPBGSubtractor::Intialize(unsigned int prows,
+        unsigned int pcols,
+        unsigned int pcolor_channels,
+        unsigned int SequenceLength,
+        unsigned int pTimeWindowSize,
+        unsigned char pSDEstimationFlag,
+        unsigned char pUseColorRatiosFlag)
+      {
 
-  BGModel = new NPBGmodel(rows, cols, color_channels, SequenceLength, pTimeWindowSize, 500);
+        rows = prows;
+        cols = pcols;
+        color_channels = pcolor_channels;
+        imagesize = rows*cols*color_channels;
+        SdEstimateFlag = pSDEstimationFlag;
+        UseColorRatiosFlag = pUseColorRatiosFlag;
+        //SampleSize = SequenceLength;
 
-  Pimage1 = new double[rows*cols];
-  Pimage2 = new double[rows*cols];
+        AdaptBGFlag = FALSE;
+        //
+        SubsetFlag = TRUE;
 
-  tempFrame = new unsigned char[rows*cols * 3];
+        UpdateSDRate = 0;
 
-  imageindex = new ImageIndex;
-  imageindex->List = new unsigned int[rows*cols];
+        BGModel = new NPBGmodel(rows, cols, color_channels, SequenceLength, pTimeWindowSize, 500);
 
-  // error checking
-  if (BGModel == NULL)
-    return 0;
+        Pimage1 = new double[rows*cols];
+        Pimage2 = new double[rows*cols];
 
-  return 1;
-}
+        tempFrame = new unsigned char[rows*cols * 3];
 
-void NPBGSubtractor::AddFrame(unsigned char *ImageBuffer)
-{
-  if (UseColorRatiosFlag && color_channels == 3)
-    BGR2SnGnRn(ImageBuffer, ImageBuffer, rows, cols);
+        imageindex = new ImageIndex;
+        imageindex->List = new unsigned int[rows*cols];
 
-  BGModel->AddFrame(ImageBuffer);
-}
+        // error checking
+        if (BGModel == NULL)
+          return 0;
 
-void NPBGSubtractor::Estimation()
-{
-  int SampleSize = BGModel->SampleSize;
+        return 1;
+      }
 
-  memset(BGModel->TemporalMask, 0, rows*cols*BGModel->TemporalBufferLength);
+      void NPBGSubtractor::AddFrame(unsigned char *ImageBuffer)
+      {
+        if (UseColorRatiosFlag && color_channels == 3)
+          BGR2SnGnRn(ImageBuffer, ImageBuffer, rows, cols);
 
-  //BGModel->AccMask= new unsigned int [rows*cols];
-  memset(BGModel->AccMask, 0, rows*cols * sizeof(unsigned int));
+        BGModel->AddFrame(ImageBuffer);
+      }
 
-  unsigned char *pSDs = new unsigned char[rows*cols*color_channels];
+      void NPBGSubtractor::Estimation()
+      {
+        int SampleSize = BGModel->SampleSize;
 
-  //DynamicMedianHistogram AbsDiffHist;
+        memset(BGModel->TemporalMask, 0, rows*cols*BGModel->TemporalBufferLength);
 
-  int Abshistbins = 20;
+        //BGModel->AccMask= new unsigned int [rows*cols];
+        memset(BGModel->AccMask, 0, rows*cols * sizeof(unsigned int));
 
-  TimeIndex = 0;
+        unsigned char *pSDs = new unsigned char[rows*cols*color_channels];
 
-  // estimate standard deviations
+        //DynamicMedianHistogram AbsDiffHist;
 
-  if (SdEstimateFlag)
-  {
-    AbsDiffHist = BuildAbsDiffHist(BGModel->Sequence, rows, cols, color_channels, SampleSize, Abshistbins);
-    EstimateSDsFromAbsDiffHist(&AbsDiffHist, pSDs, imagesize, SEGMAMIN, SEGMAMAX, SEGMABINS);
-  }
-  else
-  {
-    unsigned int bin;
-    bin = (unsigned int)floor(((DEFAULTSEGMA - SEGMAMIN)*SEGMABINS) / (SEGMAMAX - SEGMAMIN));
-    memset(pSDs, bin, rows*cols*color_channels * sizeof(unsigned char));
-  }
+        int Abshistbins = 20;
 
-  BGModel->SDbinsImage = pSDs;
+        TimeIndex = 0;
 
-  // Generate the Kernel
-  KernelTable = new KernelLUTable(KERNELHALFWIDTH, SEGMAMIN, SEGMAMAX, SEGMABINS);
-}
+        // estimate standard deviations
 
-/*********************************************************************/
+        if (SdEstimateFlag)
+        {
+          AbsDiffHist = BuildAbsDiffHist(BGModel->Sequence, rows, cols, color_channels, SampleSize, Abshistbins);
+          EstimateSDsFromAbsDiffHist(&AbsDiffHist, pSDs, imagesize, SEGMAMIN, SEGMAMAX, SEGMABINS);
+        }
+        else
+        {
+          unsigned int bin;
+          bin = (unsigned int)floor(((DEFAULTSEGMA - SEGMAMIN)*SEGMABINS) / (SEGMAMAX - SEGMAMIN));
+          memset(pSDs, bin, rows*cols*color_channels * sizeof(unsigned char));
+        }
 
-void BuildImageIndex(unsigned char * Image,
-  ImageIndex * imageIndex,
-  unsigned int rows,
-  unsigned int cols)
-{
-  unsigned int i, j;
-  unsigned int r, c;
-  unsigned int * image_list;
+        BGModel->SDbinsImage = pSDs;
 
-  j = cols + 1;
-  i = 0;
-  image_list = imageIndex->List;
+        // Generate the Kernel
+        KernelTable = new KernelLUTable(KERNELHALFWIDTH, SEGMAMIN, SEGMAMAX, SEGMABINS);
+      }
 
-  for (r = 1; r < rows - 1; r++)
-  {
-    for (c = 1; c < cols - 1; c++)
-    {
-      if (Image[j])
-        image_list[i++] = j;
+      /*********************************************************************/
 
-      j++;
-    }
-    j += 2;
-  }
+      void BuildImageIndex(unsigned char * Image,
+        ImageIndex * imageIndex,
+        unsigned int rows,
+        unsigned int cols)
+      {
+        unsigned int i, j;
+        unsigned int r, c;
+        unsigned int * image_list;
 
-  imageIndex->cnt = i;
-}
+        j = cols + 1;
+        i = 0;
+        image_list = imageIndex->List;
 
-/*********************************************************************/
+        for (r = 1; r < rows - 1; r++)
+        {
+          for (c = 1; c < cols - 1; c++)
+          {
+            if (Image[j])
+              image_list[i++] = j;
 
-void HystExpandOperatorIndexed(unsigned char * inImage,
-  ImageIndex * inIndex,
-  double * Pimage,
-  double hyst_th,
-  unsigned char * outImage,
-  ImageIndex * outIndex,
-  unsigned int urows,
-  unsigned int ucols)
-{
-  unsigned int * in_list;
-  unsigned int in_cnt;
-  unsigned int * out_list;
+            j++;
+          }
+          j += 2;
+        }
 
-  int rows, cols;
+        imageIndex->cnt = i;
+      }
 
-  int Nbr[9];
-  unsigned int i, j;
-  unsigned int k;
-  unsigned int idx;
+      /*********************************************************************/
 
-  rows = (int)urows;
-  cols = (int)ucols;
+      void HystExpandOperatorIndexed(unsigned char * inImage,
+        ImageIndex * inIndex,
+        double * Pimage,
+        double hyst_th,
+        unsigned char * outImage,
+        ImageIndex * outIndex,
+        unsigned int urows,
+        unsigned int ucols)
+      {
+        unsigned int * in_list;
+        unsigned int in_cnt;
+        unsigned int * out_list;
 
-  in_cnt = inIndex->cnt;
-  in_list = inIndex->List;
+        int rows, cols;
 
-  Nbr[0] = -cols - 1;
-  Nbr[1] = -cols;
-  Nbr[2] = -cols + 1;
-  Nbr[3] = -1;
-  Nbr[4] = 0;
-  Nbr[5] = 1;
-  Nbr[6] = cols - 1;
-  Nbr[7] = cols;
-  Nbr[8] = cols + 1;
+        int Nbr[9];
+        unsigned int i, j;
+        unsigned int k;
+        unsigned int idx;
 
-  memset(outImage, 0, rows*cols);
+        rows = (int)urows;
+        cols = (int)ucols;
 
-  out_list = outIndex->List;
-  k = 0;
+        in_cnt = inIndex->cnt;
+        in_list = inIndex->List;
 
-  for (i = 0; i < in_cnt; i++)
-  {
-    for (j = 0; j < 9; j++)
-    {
-      idx = in_list[i] + Nbr[j];
+        Nbr[0] = -cols - 1;
+        Nbr[1] = -cols;
+        Nbr[2] = -cols + 1;
+        Nbr[3] = -1;
+        Nbr[4] = 0;
+        Nbr[5] = 1;
+        Nbr[6] = cols - 1;
+        Nbr[7] = cols;
+        Nbr[8] = cols + 1;
 
-      if (Pimage[idx] < hyst_th)
-        outImage[idx] = 255;
-    }
-  }
+        memset(outImage, 0, rows*cols);
 
-  // build index for out image
-  BuildImageIndex(outImage, outIndex, urows, ucols);
-}
+        out_list = outIndex->List;
+        k = 0;
 
-/*********************************************************************/
+        for (i = 0; i < in_cnt; i++)
+        {
+          for (j = 0; j < 9; j++)
+          {
+            idx = in_list[i] + Nbr[j];
 
-void HystShrinkOperatorIndexed(unsigned char * inImage,
-  ImageIndex * inIndex,
-  double * Pimage,
-  double hyst_th,
-  unsigned char * outImage,
-  ImageIndex * outIndex,
-  unsigned int urows,
-  unsigned int ucols)
-{
-  unsigned int * in_list;
-  unsigned int in_cnt;
-  unsigned int * out_list;
+            if (Pimage[idx] < hyst_th)
+              outImage[idx] = 255;
+          }
+        }
 
-  int rows, cols;
+        // build index for out image
+        BuildImageIndex(outImage, outIndex, urows, ucols);
+      }
 
-  int Nbr[9];
-  unsigned int i, j;
-  unsigned int k, idx;
+      /*********************************************************************/
 
-  rows = (int)urows;
-  cols = (int)ucols;
+      void HystShrinkOperatorIndexed(unsigned char * inImage,
+        ImageIndex * inIndex,
+        double * Pimage,
+        double hyst_th,
+        unsigned char * outImage,
+        ImageIndex * outIndex,
+        unsigned int urows,
+        unsigned int ucols)
+      {
+        unsigned int * in_list;
+        unsigned int in_cnt;
+        unsigned int * out_list;
 
-  in_cnt = inIndex->cnt;
-  in_list = inIndex->List;
+        int rows, cols;
 
-  Nbr[0] = -cols - 1;
-  Nbr[1] = -cols;
-  Nbr[2] = -cols + 1;
-  Nbr[3] = -1;
-  Nbr[4] = 0;
-  Nbr[5] = 1;
-  Nbr[6] = cols - 1;
-  Nbr[7] = cols;
-  Nbr[8] = cols + 1;
+        int Nbr[9];
+        unsigned int i, j;
+        unsigned int k, idx;
 
-  memset(outImage, 0, rows*cols);
+        rows = (int)urows;
+        cols = (int)ucols;
 
-  out_list = outIndex->List;
-  k = 0;
+        in_cnt = inIndex->cnt;
+        in_list = inIndex->List;
 
-  for (i = 0; i < in_cnt; i++)
-  {
-    idx = in_list[i];
-    j = 0;
+        Nbr[0] = -cols - 1;
+        Nbr[1] = -cols;
+        Nbr[2] = -cols + 1;
+        Nbr[3] = -1;
+        Nbr[4] = 0;
+        Nbr[5] = 1;
+        Nbr[6] = cols - 1;
+        Nbr[7] = cols;
+        Nbr[8] = cols + 1;
 
-    while (j < 9 && inImage[idx + Nbr[j]])
-      j++;
+        memset(outImage, 0, rows*cols);
 
-    if (j >= 9 || Pimage[idx] <= hyst_th)
-      outImage[idx] = 255;
-  }
+        out_list = outIndex->List;
+        k = 0;
 
-  BuildImageIndex(outImage, outIndex, rows, cols);
-}
+        for (i = 0; i < in_cnt; i++)
+        {
+          idx = in_list[i];
+          j = 0;
 
-/*********************************************************************/
+          while (j < 9 && inImage[idx + Nbr[j]])
+            j++;
 
-void ExpandOperatorIndexed(unsigned char * inImage,
-  ImageIndex * inIndex,
-  unsigned char * outImage,
-  ImageIndex * outIndex,
-  unsigned int urows,
-  unsigned int ucols)
-{
-  unsigned int * in_list;
-  unsigned int in_cnt;
-  unsigned int * out_list;
+          if (j >= 9 || Pimage[idx] <= hyst_th)
+            outImage[idx] = 255;
+        }
 
-  int rows, cols;
+        BuildImageIndex(outImage, outIndex, rows, cols);
+      }
 
-  int Nbr[9];
-  unsigned int i, j;
-  unsigned int k;
-  unsigned int idx;
+      /*********************************************************************/
 
-  rows = (int)urows;
-  cols = (int)ucols;
+      void ExpandOperatorIndexed(unsigned char * inImage,
+        ImageIndex * inIndex,
+        unsigned char * outImage,
+        ImageIndex * outIndex,
+        unsigned int urows,
+        unsigned int ucols)
+      {
+        unsigned int * in_list;
+        unsigned int in_cnt;
+        unsigned int * out_list;
 
-  in_cnt = inIndex->cnt;
-  in_list = inIndex->List;
+        int rows, cols;
 
-  Nbr[0] = -cols - 1;
-  Nbr[1] = -cols;
-  Nbr[2] = -cols + 1;
-  Nbr[3] = -1;
-  Nbr[4] = 0;
-  Nbr[5] = 1;
-  Nbr[6] = cols - 1;
-  Nbr[7] = cols;
-  Nbr[8] = cols + 1;
+        int Nbr[9];
+        unsigned int i, j;
+        unsigned int k;
+        unsigned int idx;
 
+        rows = (int)urows;
+        cols = (int)ucols;
 
-  memset(outImage, 0, rows*cols);
+        in_cnt = inIndex->cnt;
+        in_list = inIndex->List;
 
+        Nbr[0] = -cols - 1;
+        Nbr[1] = -cols;
+        Nbr[2] = -cols + 1;
+        Nbr[3] = -1;
+        Nbr[4] = 0;
+        Nbr[5] = 1;
+        Nbr[6] = cols - 1;
+        Nbr[7] = cols;
+        Nbr[8] = cols + 1;
 
-  out_list = outIndex->List;
-  k = 0;
-  for (i = 0; i < in_cnt; i++)
-    for (j = 0; j < 9; j++) {
-      idx = in_list[i] + Nbr[j];
-      outImage[idx] = 255;
-    }
 
+        memset(outImage, 0, rows*cols);
 
-  // build index for out image
 
-  BuildImageIndex(outImage, outIndex, rows, cols);
+        out_list = outIndex->List;
+        k = 0;
+        for (i = 0; i < in_cnt; i++)
+          for (j = 0; j < 9; j++) {
+            idx = in_list[i] + Nbr[j];
+            outImage[idx] = 255;
+          }
 
-}
 
-/*********************************************************************/
+        // build index for out image
 
-void ShrinkOperatorIndexed(unsigned char * inImage,
-  ImageIndex * inIndex,
-  unsigned char * outImage,
-  ImageIndex * outIndex,
-  unsigned int urows,
-  unsigned int ucols)
-{
+        BuildImageIndex(outImage, outIndex, rows, cols);
 
-  unsigned int * in_list;
-  unsigned int in_cnt;
-  unsigned int * out_list;
+      }
 
-  int rows, cols;
+      /*********************************************************************/
 
-  int Nbr[9];
-  unsigned int i, j;
-  unsigned int k, idx;
+      void ShrinkOperatorIndexed(unsigned char * inImage,
+        ImageIndex * inIndex,
+        unsigned char * outImage,
+        ImageIndex * outIndex,
+        unsigned int urows,
+        unsigned int ucols)
+      {
 
-  rows = (int)urows;
-  cols = (int)ucols;
+        unsigned int * in_list;
+        unsigned int in_cnt;
+        unsigned int * out_list;
 
-  in_cnt = inIndex->cnt;
-  in_list = inIndex->List;
+        int rows, cols;
 
-  Nbr[0] = -cols - 1;
-  Nbr[1] = -cols;
-  Nbr[2] = -cols + 1;
-  Nbr[3] = -1;
-  Nbr[4] = 0;
-  Nbr[5] = 1;
-  Nbr[6] = cols - 1;
-  Nbr[7] = cols;
-  Nbr[8] = cols + 1;
+        int Nbr[9];
+        unsigned int i, j;
+        unsigned int k, idx;
 
+        rows = (int)urows;
+        cols = (int)ucols;
 
-  memset(outImage, 0, rows*cols);
+        in_cnt = inIndex->cnt;
+        in_list = inIndex->List;
 
-  out_list = outIndex->List;
-  k = 0;
-  for (i = 0; i < in_cnt; i++) {
-    idx = in_list[i];
-    j = 0;
+        Nbr[0] = -cols - 1;
+        Nbr[1] = -cols;
+        Nbr[2] = -cols + 1;
+        Nbr[3] = -1;
+        Nbr[4] = 0;
+        Nbr[5] = 1;
+        Nbr[6] = cols - 1;
+        Nbr[7] = cols;
+        Nbr[8] = cols + 1;
 
-    while (j < 9 && inImage[idx + Nbr[j]]) {
-      j++;
-    }
 
-    if (j >= 9) {
-      outImage[idx] = 255;
-    }
-  }
+        memset(outImage, 0, rows*cols);
 
-  BuildImageIndex(outImage, outIndex, rows, cols);
-}
+        out_list = outIndex->List;
+        k = 0;
+        for (i = 0; i < in_cnt; i++) {
+          idx = in_list[i];
+          j = 0;
 
-/*********************************************************************/
+          while (j < 9 && inImage[idx + Nbr[j]]) {
+            j++;
+          }
 
-void NoiseFilter_o(unsigned char * Image,
-  unsigned char * ResultIm,
-  int rows,
-  int cols,
-  unsigned char th)
-{
-  /* assuming input is 1 for on, 0 for off */
+          if (j >= 9) {
+            outImage[idx] = 255;
+          }
+        }
 
+        BuildImageIndex(outImage, outIndex, rows, cols);
+      }
 
-  int r, c;
-  unsigned char *p, *n, *nw, *ne, *e, *w, *s, *sw, *se;
-  unsigned int v;
-  unsigned int TH;
+      /*********************************************************************/
 
-  unsigned char * ResultPtr;
+      void NoiseFilter_o(unsigned char * Image,
+        unsigned char * ResultIm,
+        int rows,
+        int cols,
+        unsigned char th)
+      {
+        /* assuming input is 1 for on, 0 for off */
 
-  TH = 255 * th;
 
-  memset(ResultIm, 0, rows*cols);
+        int r, c;
+        unsigned char *p, *n, *nw, *ne, *e, *w, *s, *sw, *se;
+        unsigned int v;
+        unsigned int TH;
 
-  p = Image + cols + 1;
-  ResultPtr = ResultIm + cols + 1;
+        unsigned char * ResultPtr;
 
-  for (r = 1; r < rows - 1; r++)
-  {
-    for (c = 1; c < cols - 1; c++)
-    {
-      if (*p)
-      {
-        n = p - cols;
-        ne = n + 1;
-        nw = n - 1;
-        e = p + 1;
-        w = p - 1;
-        s = p + cols;
-        se = s + 1;
-        sw = s - 1;
-
-        v = (unsigned int)*nw + *n + *ne + *w + *e + *sw + *s + *se;
-
-        if (v >= TH)
-          *ResultPtr = 255;
-        else
-          *ResultPtr = 0;
-      }
-      p++;
-      ResultPtr++;
-    }
-    p += 2;
-    ResultPtr += 2;
-  }
-}
+        TH = 255 * th;
 
-/*********************************************************************/
+        memset(ResultIm, 0, rows*cols);
 
-void NPBGSubtractor::SequenceBGUpdate_Pairs(unsigned char * image,
-  unsigned char * Mask)
-{
-  unsigned int i, ic;
-  unsigned char * pSequence = BGModel->Sequence;
-  unsigned char * PixelQTop = BGModel->PixelQTop;
-  //unsigned int Top = BGModel->Top;
-  unsigned int rate;
+        p = Image + cols + 1;
+        ResultPtr = ResultIm + cols + 1;
 
-  int TemporalBufferTop = (int)BGModel->TemporalBufferTop;
-  unsigned char * pTemporalBuffer = BGModel->TemporalBuffer;
-  unsigned char * pTemporalMask = BGModel->TemporalMask;
-  int TemporalBufferLength = BGModel->TemporalBufferLength;
+        for (r = 1; r < rows - 1; r++)
+        {
+          for (c = 1; c < cols - 1; c++)
+          {
+            if (*p)
+            {
+              n = p - cols;
+              ne = n + 1;
+              nw = n - 1;
+              e = p + 1;
+              w = p - 1;
+              s = p + cols;
+              se = s + 1;
+              sw = s - 1;
+
+              v = (unsigned int)*nw + *n + *ne + *w + *e + *sw + *s + *se;
+
+              if (v >= TH)
+                *ResultPtr = 255;
+              else
+                *ResultPtr = 0;
+            }
+            p++;
+            ResultPtr++;
+          }
+          p += 2;
+          ResultPtr += 2;
+        }
+      }
 
-  unsigned int * AccMask = BGModel->AccMask;
-  unsigned int ResetMaskTh = BGModel->ResetMaskTh;
+      /*********************************************************************/
 
-  unsigned char *pAbsDiffHist = AbsDiffHist.Hist;
-  unsigned char histbins = AbsDiffHist.histbins;
-  int histbins_1 = histbins - 1;
+      void NPBGSubtractor::SequenceBGUpdate_Pairs(unsigned char * image,
+        unsigned char * Mask)
+      {
+        unsigned int i, ic;
+        unsigned char * pSequence = BGModel->Sequence;
+        unsigned char * PixelQTop = BGModel->PixelQTop;
+        //unsigned int Top = BGModel->Top;
+        unsigned int rate;
 
-  int TimeWindowSize = BGModel->TimeWindowSize;
-  int SampleSize = BGModel->SampleSize;
+        int TemporalBufferTop = (int)BGModel->TemporalBufferTop;
+        unsigned char * pTemporalBuffer = BGModel->TemporalBuffer;
+        unsigned char * pTemporalMask = BGModel->TemporalMask;
+        int TemporalBufferLength = BGModel->TemporalBufferLength;
 
-  int TemporalBufferNext;
+        unsigned int * AccMask = BGModel->AccMask;
+        unsigned int ResetMaskTh = BGModel->ResetMaskTh;
 
-  unsigned int imagebuffersize = rows*cols*color_channels;
-  unsigned int imagespatialsize = rows*cols;
+        unsigned char *pAbsDiffHist = AbsDiffHist.Hist;
+        unsigned char histbins = AbsDiffHist.histbins;
+        int histbins_1 = histbins - 1;
 
-  unsigned char mask;
+        int TimeWindowSize = BGModel->TimeWindowSize;
+        int SampleSize = BGModel->SampleSize;
 
-  unsigned int histindex;
-  unsigned char diff;
-  unsigned char bin;
+        int TemporalBufferNext;
 
-  static int TBCount = 0;
+        unsigned int imagebuffersize = rows*cols*color_channels;
+        unsigned int imagespatialsize = rows*cols;
 
-  unsigned char * pTBbase1, *pTBbase2;
-  unsigned char * pModelbase1, *pModelbase2;
+        unsigned char mask;
 
-  rate = TimeWindowSize / SampleSize;
-  rate = (rate > 2) ? rate : 2;
+        unsigned int histindex;
+        unsigned char diff;
+        unsigned char bin;
 
+        static int TBCount = 0;
 
-  TemporalBufferNext = (TemporalBufferTop + 1)
-    % TemporalBufferLength;
+        unsigned char * pTBbase1, *pTBbase2;
+        unsigned char * pModelbase1, *pModelbase2;
 
-  // pointers to Masks : Top and Next
-  unsigned char * pTMaskTop = pTemporalMask + TemporalBufferTop*imagespatialsize;
-  unsigned char * pTMaskNext = pTemporalMask + TemporalBufferNext*imagespatialsize;
+        rate = TimeWindowSize / SampleSize;
+        rate = (rate > 2) ? rate : 2;
 
-  // pointers to TB frames: Top and Next
-  unsigned char * pTBTop = pTemporalBuffer + TemporalBufferTop*imagebuffersize;
-  unsigned char * pTBNext = pTemporalBuffer + TemporalBufferNext*imagebuffersize;
 
-  if (((TimeIndex) % rate == 0) && TBCount >= TemporalBufferLength)
-  {
-    for (i = 0, ic = 0; i < imagespatialsize; i++, ic += color_channels)
-    {
-      mask = *(pTMaskTop + i) || *(pTMaskNext + i);
+        TemporalBufferNext = (TemporalBufferTop + 1)
+          % TemporalBufferLength;
 
-      if (!mask)
-      {
-        // pointer to TB pixels to be added to the model
-        pTBbase1 = pTBTop + ic;
-        pTBbase2 = pTBNext + ic;
+        // pointers to Masks : Top and Next
+        unsigned char * pTMaskTop = pTemporalMask + TemporalBufferTop*imagespatialsize;
+        unsigned char * pTMaskNext = pTemporalMask + TemporalBufferNext*imagespatialsize;
 
-        // pointers to Model pixels to be replaced
-        pModelbase1 = pSequence + PixelQTop[i] * imagebuffersize + ic;
-        pModelbase2 = pSequence + ((PixelQTop[i] + 1) % SampleSize)*imagebuffersize + ic;
+        // pointers to TB frames: Top and Next
+        unsigned char * pTBTop = pTemporalBuffer + TemporalBufferTop*imagebuffersize;
+        unsigned char * pTBNext = pTemporalBuffer + TemporalBufferNext*imagebuffersize;
 
-        // update Deviation Histogram
-        if (SdEstimateFlag)
+        if (((TimeIndex) % rate == 0) && TBCount >= TemporalBufferLength)
         {
-          if (color_channels == 1)
+          for (i = 0, ic = 0; i < imagespatialsize; i++, ic += color_channels)
           {
-            histindex = i*histbins;
-
-            // add new pair from temporal buffer
-            diff = (unsigned char)abs((int)*pTBbase1 - (int)*pTBbase2);
-            bin = (diff < histbins ? diff : histbins_1);
-            pAbsDiffHist[histindex + bin]++;
-
-
-            // remove old pair from the model
-            diff = (unsigned char)abs((int)*pModelbase1 - (int)*pModelbase2);
-            bin = (diff < histbins ? diff : histbins_1);
-            pAbsDiffHist[histindex + bin]--;
+            mask = *(pTMaskTop + i) || *(pTMaskNext + i);
+
+            if (!mask)
+            {
+              // pointer to TB pixels to be added to the model
+              pTBbase1 = pTBTop + ic;
+              pTBbase2 = pTBNext + ic;
+
+              // pointers to Model pixels to be replaced
+              pModelbase1 = pSequence + PixelQTop[i] * imagebuffersize + ic;
+              pModelbase2 = pSequence + ((PixelQTop[i] + 1) % SampleSize)*imagebuffersize + ic;
+
+              // update Deviation Histogram
+              if (SdEstimateFlag)
+              {
+                if (color_channels == 1)
+                {
+                  histindex = i*histbins;
+
+                  // add new pair from temporal buffer
+                  diff = (unsigned char)abs((int)*pTBbase1 - (int)*pTBbase2);
+                  bin = (diff < histbins ? diff : histbins_1);
+                  pAbsDiffHist[histindex + bin]++;
+
+
+                  // remove old pair from the model
+                  diff = (unsigned char)abs((int)*pModelbase1 - (int)*pModelbase2);
+                  bin = (diff < histbins ? diff : histbins_1);
+                  pAbsDiffHist[histindex + bin]--;
+                }
+                else
+                {
+                  // color
+
+                  // add new pair from temporal buffer
+                  histindex = ic*histbins;
+                  diff = abs(*pTBbase1 -
+                    *pTBbase2);
+                  bin = (diff < histbins ? diff : histbins_1);
+                  pAbsDiffHist[histindex + bin]++;
+
+                  histindex += histbins;
+                  diff = abs(*(pTBbase1 + 1) -
+                    *(pTBbase2 + 1));
+                  bin = (diff < histbins ? diff : histbins_1);
+                  pAbsDiffHist[histindex + bin]++;
+
+                  histindex += histbins;
+                  diff = abs(*(pTBbase1 + 2) -
+                    *(pTBbase2 + 2));
+                  bin = (diff < histbins ? diff : histbins_1);
+                  pAbsDiffHist[histindex + bin]++;
+
+                  // remove old pair from the model
+                  histindex = ic*histbins;
+
+                  diff = abs(*pModelbase1 -
+                    *pModelbase2);
+                  bin = (diff < histbins ? diff : histbins_1);
+                  pAbsDiffHist[histindex + bin]--;
+
+                  histindex += histbins;
+                  diff = abs(*(pModelbase1 + 1) -
+                    *(pModelbase2 + 1));
+                  bin = (diff < histbins ? diff : histbins_1);
+                  pAbsDiffHist[histindex + bin]--;
+
+                  histindex += histbins;
+                  diff = abs(*(pModelbase1 + 2) -
+                    *(pModelbase2 + 2));
+                  bin = (diff < histbins ? diff : histbins_1);
+                  pAbsDiffHist[histindex + bin]--;
+                }
+              }
+
+              // add new pair into the model
+              memcpy(pModelbase1, pTBbase1, color_channels * sizeof(unsigned char));
+
+              memcpy(pModelbase2, pTBbase2, color_channels * sizeof(unsigned char));
+
+              PixelQTop[i] = (PixelQTop[i] + 2) % SampleSize;
+            }
           }
-          else
-          {
-            // color
-
-            // add new pair from temporal buffer
-            histindex = ic*histbins;
-            diff = abs(*pTBbase1 -
-              *pTBbase2);
-            bin = (diff < histbins ? diff : histbins_1);
-            pAbsDiffHist[histindex + bin]++;
-
-            histindex += histbins;
-            diff = abs(*(pTBbase1 + 1) -
-              *(pTBbase2 + 1));
-            bin = (diff < histbins ? diff : histbins_1);
-            pAbsDiffHist[histindex + bin]++;
-
-            histindex += histbins;
-            diff = abs(*(pTBbase1 + 2) -
-              *(pTBbase2 + 2));
-            bin = (diff < histbins ? diff : histbins_1);
-            pAbsDiffHist[histindex + bin]++;
-
-            // remove old pair from the model
-            histindex = ic*histbins;
-
-            diff = abs(*pModelbase1 -
-              *pModelbase2);
-            bin = (diff < histbins ? diff : histbins_1);
-            pAbsDiffHist[histindex + bin]--;
-
-            histindex += histbins;
-            diff = abs(*(pModelbase1 + 1) -
-              *(pModelbase2 + 1));
-            bin = (diff < histbins ? diff : histbins_1);
-            pAbsDiffHist[histindex + bin]--;
-
-            histindex += histbins;
-            diff = abs(*(pModelbase1 + 2) -
-              *(pModelbase2 + 2));
-            bin = (diff < histbins ? diff : histbins_1);
-            pAbsDiffHist[histindex + bin]--;
-          }
-        }
+        } // end if (sampling event)
 
-        // add new pair into the model
-        memcpy(pModelbase1, pTBbase1, color_channels * sizeof(unsigned char));
+        // update temporal buffer
+        // add new frame to Temporal buffer.
+        memcpy(pTBTop, image, imagebuffersize);
 
-        memcpy(pModelbase2, pTBbase2, color_channels * sizeof(unsigned char));
+        // update AccMask
+        // update new Mask with information in AccMask
 
-        PixelQTop[i] = (PixelQTop[i] + 2) % SampleSize;
-      }
-    }
-  } // end if (sampling event)
-
-  // update temporal buffer
-  // add new frame to Temporal buffer.
-  memcpy(pTBTop, image, imagebuffersize);
-
-  // update AccMask
-  // update new Mask with information in AccMask
-
-  for (i = 0; i < rows*cols; i++)
-  {
-    if (Mask[i])
-      AccMask[i]++;
-    else
-      AccMask[i] = 0;
-
-    if (AccMask[i] > ResetMaskTh)
-      Mask[i] = 0;
-  }
-
-  // add new mask
-  memcpy(pTMaskTop, Mask, imagespatialsize);
-
-  // advance Temporal buffer pointer
-  TemporalBufferTop = (TemporalBufferTop + 1) % TemporalBufferLength;
-
-  BGModel->TemporalBufferTop = TemporalBufferTop;
-
-  TBCount++;
+        for (i = 0; i < rows*cols; i++)
+        {
+          if (Mask[i])
+            AccMask[i]++;
+          else
+            AccMask[i] = 0;
 
-  // estimate SDs
+          if (AccMask[i] > ResetMaskTh)
+            Mask[i] = 0;
+        }
 
-  if (SdEstimateFlag && UpdateSDRate && ((TimeIndex) % UpdateSDRate == 0))
-  {
-    double MaxSD = KernelTable->maxsegma;
-    double MinSD = KernelTable->minsegma;
-    int KernelBins = KernelTable->segmabins;
+        // add new mask
+        memcpy(pTMaskTop, Mask, imagespatialsize);
 
-    unsigned char * pSDs = BGModel->SDbinsImage;
+        // advance Temporal buffer pointer
+        TemporalBufferTop = (TemporalBufferTop + 1) % TemporalBufferLength;
 
-    FindHistMedians(&(AbsDiffHist));
-    EstimateSDsFromAbsDiffHist(&(AbsDiffHist), pSDs, imagebuffersize, MinSD, MaxSD, KernelBins);
-  }
+        BGModel->TemporalBufferTop = TemporalBufferTop;
 
-  TimeIndex++;
-}
+        TBCount++;
 
-/*********************************************************************/
+        // estimate SDs
 
-void DisplayPropabilityImageWithThresholding(double * Pimage,
-  unsigned char * DisplayImage,
-  double Threshold,
-  unsigned int rows,
-  unsigned int cols)
-{
-  double p;
+        if (SdEstimateFlag && UpdateSDRate && ((TimeIndex) % UpdateSDRate == 0))
+        {
+          double MaxSD = KernelTable->maxsegma;
+          double MinSD = KernelTable->minsegma;
+          int KernelBins = KernelTable->segmabins;
 
-  for (unsigned int i = 0; i < rows*cols; i++)
-  {
-    p = Pimage[i];
+          unsigned char * pSDs = BGModel->SDbinsImage;
 
-    DisplayImage[i] = (p > Threshold) ? 0 : 255;
-  }
-}
+          FindHistMedians(&(AbsDiffHist));
+          EstimateSDsFromAbsDiffHist(&(AbsDiffHist), pSDs, imagebuffersize, MinSD, MaxSD, KernelBins);
+        }
 
-/*********************************************************************/
+        TimeIndex++;
+      }
 
-void NPBGSubtractor::NPBGSubtraction_Subset_Kernel(
-  unsigned char * image,
-  unsigned char * FGImage,
-  unsigned char * FilteredFGImage)
-{
-  unsigned int i, j;
-  unsigned char *pSequence = BGModel->Sequence;
+      /*********************************************************************/
 
-  unsigned int SampleSize = BGModel->SampleSize;
+      void DisplayPropabilityImageWithThresholding(double * Pimage,
+        unsigned char * DisplayImage,
+        double Threshold,
+        unsigned int rows,
+        unsigned int cols)
+      {
+        double p;
 
-  double *kerneltable = KernelTable->kerneltable;
-  int KernelHalfWidth = KernelTable->tablehalfwidth;
-  //double *KernelSum = KernelTable->kernelsums;
-  double KernelMaxSigma = KernelTable->maxsegma;
-  double KernelMinSigma = KernelTable->minsegma;
-  int KernelBins = KernelTable->segmabins;
-  unsigned char * SDbins = BGModel->SDbinsImage;
+        for (unsigned int i = 0; i < rows*cols; i++)
+        {
+          p = Pimage[i];
 
-  //unsigned char * SaturationImage = FilteredFGImage;
+          DisplayImage[i] = (p > Threshold) ? 0 : 255;
+        }
+      }
 
-  // default sigmas .. to be removed.
-  double sigma1;
-  double sigma2;
-  double sigma3;
+      /*********************************************************************/
 
-  sigma1 = 2.25;
-  sigma2 = 2.25;
-  sigma3 = 2.25;
+      void NPBGSubtractor::NPBGSubtraction_Subset_Kernel(
+        unsigned char * image,
+        unsigned char * FGImage,
+        unsigned char * FilteredFGImage)
+      {
+        unsigned int i, j;
+        unsigned char *pSequence = BGModel->Sequence;
 
-  double p;
-  double th;
+        unsigned int SampleSize = BGModel->SampleSize;
 
-  double alpha;
+        double *kerneltable = KernelTable->kerneltable;
+        int KernelHalfWidth = KernelTable->tablehalfwidth;
+        //double *KernelSum = KernelTable->kernelsums;
+        double KernelMaxSigma = KernelTable->maxsegma;
+        double KernelMinSigma = KernelTable->minsegma;
+        int KernelBins = KernelTable->segmabins;
+        unsigned char * SDbins = BGModel->SDbinsImage;
 
-  alpha = AlphaValue;
+        //unsigned char * SaturationImage = FilteredFGImage;
 
-  /* intialize FG image */
+        // default sigmas .. to be removed.
+        double sigma1;
+        double sigma2;
+        double sigma3;
 
-  memset(FGImage, 0, rows*cols);
+        sigma1 = 2.25;
+        sigma2 = 2.25;
+        sigma3 = 2.25;
 
-  //Threshold=1;
-  th = Threshold * SampleSize;
+        double p;
+        double th;
 
-  double sum = 0, kernel1, kernel2, kernel3;
-  int k, g;
+        double alpha;
 
+        alpha = AlphaValue;
 
-  if (color_channels == 1)
-  {
-    // gray scale
+        /* intialize FG image */
 
-    int kernelbase;
+        memset(FGImage, 0, rows*cols);
 
-    for (i = 0; i < rows*cols; i++)
-    {
-      kernelbase = SDbins[i] * (2 * KernelHalfWidth + 1);
-      sum = 0;
-      j = 0;
+        //Threshold=1;
+        th = Threshold * SampleSize;
 
-      while (j < SampleSize && sum < th)
-      {
-        g = pSequence[j*imagesize + i];
-        k = g - image[i] + KernelHalfWidth;
-        sum += kerneltable[kernelbase + k];
-        j++;
-      }
+        double sum = 0, kernel1, kernel2, kernel3;
+        int k, g;
 
-      p = sum / j;
-      Pimage1[i] = p;
-    }
-  }
-  else if (UseColorRatiosFlag && SubsetFlag)
-  {
-    // color ratios
 
-    unsigned int ig;
-    int base;
+        if (color_channels == 1)
+        {
+          // gray scale
 
-    int kernelbase1;
-    int kernelbase2;
-    int kernelbase3;
+          int kernelbase;
 
-    unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1;
+          for (i = 0; i < rows*cols; i++)
+          {
+            kernelbase = SDbins[i] * (2 * KernelHalfWidth + 1);
+            sum = 0;
+            j = 0;
+
+            while (j < SampleSize && sum < th)
+            {
+              g = pSequence[j*imagesize + i];
+              k = g - image[i] + KernelHalfWidth;
+              sum += kerneltable[kernelbase + k];
+              j++;
+            }
+
+            p = sum / j;
+            Pimage1[i] = p;
+          }
+        }
+        else if (UseColorRatiosFlag && SubsetFlag)
+        {
+          // color ratios
 
-    double beta = 3.0;    // minimum bound on the range.
-    double betau = 100.0;
+          unsigned int ig;
+          int base;
 
-    double beta_over_alpha = beta / alpha;
-    double betau_over_alpha = betau / alpha;
+          int kernelbase1;
+          int kernelbase2;
+          int kernelbase3;
 
+          unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1;
 
-    double brightness_lowerbound = 1 - alpha;
-    double brightness_upperbound = 1 + alpha;
-    int x1, x2;
-    unsigned int SubsampleCount;
+          double beta = 3.0;    // minimum bound on the range.
+          double betau = 100.0;
 
-    for (i = 0, ig = 0; i < imagesize; i += 3, ig++)
-    {
-      kernelbase1 = SDbins[i] * kerneltablewidth;
-      kernelbase2 = SDbins[i + 1] * kerneltablewidth;
-      kernelbase3 = SDbins[i + 2] * kerneltablewidth;
+          double beta_over_alpha = beta / alpha;
+          double betau_over_alpha = betau / alpha;
 
-      sum = 0;
-      j = 0;
-      SubsampleCount = 0;
 
-      while (j < SampleSize && sum < th)
-      {
-        base = j*imagesize + i;
-        g = pSequence[base];
+          double brightness_lowerbound = 1 - alpha;
+          double brightness_upperbound = 1 + alpha;
+          int x1, x2;
+          unsigned int SubsampleCount;
 
-        if (g < beta_over_alpha)
-        {
-          x1 = (int)(g - beta);
-          x2 = (int)(g + beta);
-        }
-        else if (g > betau_over_alpha)
-        {
-          x1 = (int)(g - betau);
-          x2 = (int)(g + betau);
+          for (i = 0, ig = 0; i < imagesize; i += 3, ig++)
+          {
+            kernelbase1 = SDbins[i] * kerneltablewidth;
+            kernelbase2 = SDbins[i + 1] * kerneltablewidth;
+            kernelbase3 = SDbins[i + 2] * kerneltablewidth;
+
+            sum = 0;
+            j = 0;
+            SubsampleCount = 0;
+
+            while (j < SampleSize && sum < th)
+            {
+              base = j*imagesize + i;
+              g = pSequence[base];
+
+              if (g < beta_over_alpha)
+              {
+                x1 = (int)(g - beta);
+                x2 = (int)(g + beta);
+              }
+              else if (g > betau_over_alpha)
+              {
+                x1 = (int)(g - betau);
+                x2 = (int)(g + betau);
+              }
+              else
+              {
+                x1 = (int)(g*brightness_lowerbound + 0.5);
+                x2 = (int)(g*brightness_upperbound + 0.5);
+              }
+
+              if (x1 < image[i] && image[i] < x2)
+              {
+                g = pSequence[base + 1];
+                k = (g - image[i + 1]) + KernelHalfWidth;
+                kernel2 = kerneltable[kernelbase2 + k];
+
+                g = pSequence[base + 2];
+                k = (g - image[i + 2]) + KernelHalfWidth;
+                kernel3 = kerneltable[kernelbase3 + k];
+
+                sum += kernel2*kernel3;
+
+                SubsampleCount++;
+              }
+              j++;
+            }
+
+            p = sum / j;
+            Pimage1[ig] = p;
+          }
         }
-        else
+        else if (UseColorRatiosFlag && !SubsetFlag)
         {
-          x1 = (int)(g*brightness_lowerbound + 0.5);
-          x2 = (int)(g*brightness_upperbound + 0.5);
-        }
+          // color ratios
 
-        if (x1 < image[i] && image[i] < x2)
-        {
-          g = pSequence[base + 1];
-          k = (g - image[i + 1]) + KernelHalfWidth;
-          kernel2 = kerneltable[kernelbase2 + k];
+          unsigned int ig;
+          int base;
+          int bin;
 
-          g = pSequence[base + 2];
-          k = (g - image[i + 2]) + KernelHalfWidth;
-          kernel3 = kerneltable[kernelbase3 + k];
+          int kernelbase1;
+          int kernelbase2;
+          int kernelbase3;
 
-          sum += kernel2*kernel3;
+          unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1;
 
-          SubsampleCount++;
-        }
-        j++;
-      }
+          int gmin, gmax;
+          double gfactor;
 
-      p = sum / j;
-      Pimage1[ig] = p;
-    }
-  }
-  else if (UseColorRatiosFlag && !SubsetFlag)
-  {
-    // color ratios
+          gmax = 200;
+          gmin = 10;
 
-    unsigned int ig;
-    int base;
-    int bin;
+          gfactor = (KernelMaxSigma - KernelMinSigma) / (double)(gmax - gmin);
 
-    int kernelbase1;
-    int kernelbase2;
-    int kernelbase3;
+          for (i = 0, ig = 0; i < imagesize; i += 3, ig++)
+          {
 
-    unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1;
+            bin = (int)floor(((alpha * 16 - KernelMinSigma)*KernelBins) / (KernelMaxSigma - KernelMinSigma));
 
-    int gmin, gmax;
-    double gfactor;
+            kernelbase1 = bin*kerneltablewidth;
+            kernelbase2 = SDbins[i + 1] * kerneltablewidth;
+            kernelbase3 = SDbins[i + 2] * kerneltablewidth;
 
-    gmax = 200;
-    gmin = 10;
+            sum = 0;
+            j = 0;
 
-    gfactor = (KernelMaxSigma - KernelMinSigma) / (double)(gmax - gmin);
+            while (j < SampleSize && sum < th)
+            {
+              base = j*imagesize + i;
+              g = pSequence[base];
 
-    for (i = 0, ig = 0; i < imagesize; i += 3, ig++)
-    {
+              if (g < gmin)
+                bin = 0;
+              else if (g > gmax)
+                bin = KernelBins - 1;
+              else
+                bin = (int)((g - gmin) * gfactor + 0.5);
 
-      bin = (int)floor(((alpha * 16 - KernelMinSigma)*KernelBins) / (KernelMaxSigma - KernelMinSigma));
+              kernelbase1 = bin*kerneltablewidth;
 
-      kernelbase1 = bin*kerneltablewidth;
-      kernelbase2 = SDbins[i + 1] * kerneltablewidth;
-      kernelbase3 = SDbins[i + 2] * kerneltablewidth;
+              k = (g - image[i]) + KernelHalfWidth;
+              kernel1 = kerneltable[kernelbase1 + k];
 
-      sum = 0;
-      j = 0;
+              g = pSequence[base + 1];
+              k = (g - image[i + 1]) + KernelHalfWidth;
+              kernel2 = kerneltable[kernelbase2 + k];
 
-      while (j < SampleSize && sum < th)
-      {
-        base = j*imagesize + i;
-        g = pSequence[base];
-
-        if (g < gmin)
-          bin = 0;
-        else if (g > gmax)
-          bin = KernelBins - 1;
-        else
-          bin = (int)((g - gmin) * gfactor + 0.5);
+              g = pSequence[base + 2];
+              k = (g - image[i + 2]) + KernelHalfWidth;
+              kernel3 = kerneltable[kernelbase3 + k];
 
-        kernelbase1 = bin*kerneltablewidth;
+              sum += kernel1*kernel2*kernel3;
+              j++;
+            }
 
-        k = (g - image[i]) + KernelHalfWidth;
-        kernel1 = kerneltable[kernelbase1 + k];
+            p = sum / j;
+            Pimage1[ig] = p;
+          }
+        }
+        else // RGB color
+        {
+          unsigned int ig;
+          int base;
 
-        g = pSequence[base + 1];
-        k = (g - image[i + 1]) + KernelHalfWidth;
-        kernel2 = kerneltable[kernelbase2 + k];
+          int kernelbase1;
+          int kernelbase2;
+          int kernelbase3;
+          unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1;
 
-        g = pSequence[base + 2];
-        k = (g - image[i + 2]) + KernelHalfWidth;
-        kernel3 = kerneltable[kernelbase3 + k];
+          for (i = 0, ig = 0; i < imagesize; i += 3, ig++)
+          {
+            // used extimated kernel width to access the right kernel
+            kernelbase1 = SDbins[i] * kerneltablewidth;
+            kernelbase2 = SDbins[i + 1] * kerneltablewidth;
+            kernelbase3 = SDbins[i + 2] * kerneltablewidth;
+
+            sum = 0;
+            j = 0;
+            while (j < SampleSize && sum < th)
+            {
+              base = j*imagesize + i;
+              g = pSequence[base];
+              k = (g - image[i]) + KernelHalfWidth;
+              kernel1 = kerneltable[kernelbase1 + k];
+
+              g = pSequence[base + 1];
+              k = (g - image[i + 1]) + KernelHalfWidth;
+              kernel2 = kerneltable[kernelbase2 + k];
+
+              g = pSequence[base + 2];
+              k = (g - image[i + 2]) + KernelHalfWidth;
+              kernel3 = kerneltable[kernelbase3 + k];
+
+              sum += kernel1*kernel2*kernel3;
+              j++;
+            }
+
+            p = sum / j;
+            Pimage1[ig] = p;
+          }
+        }
 
-        sum += kernel1*kernel2*kernel3;
-        j++;
+        DisplayPropabilityImageWithThresholding(Pimage1, FGImage, Threshold, rows, cols);
       }
 
-      p = sum / j;
-      Pimage1[ig] = p;
-    }
-  }
-  else // RGB color
-  {
-    unsigned int ig;
-    int base;
-
-    int kernelbase1;
-    int kernelbase2;
-    int kernelbase3;
-    unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1;
+      /*********************************************************************/
 
-    for (i = 0, ig = 0; i < imagesize; i += 3, ig++)
-    {
-      // used extimated kernel width to access the right kernel
-      kernelbase1 = SDbins[i] * kerneltablewidth;
-      kernelbase2 = SDbins[i + 1] * kerneltablewidth;
-      kernelbase3 = SDbins[i + 2] * kerneltablewidth;
-
-      sum = 0;
-      j = 0;
-      while (j < SampleSize && sum < th)
+      void NPBGSubtractor::NBBGSubtraction(unsigned char * Frame,
+        unsigned char * FGImage,
+        unsigned char * FilteredFGImage,
+        unsigned char ** DisplayBuffers)
       {
-        base = j*imagesize + i;
-        g = pSequence[base];
-        k = (g - image[i]) + KernelHalfWidth;
-        kernel1 = kerneltable[kernelbase1 + k];
+        if (UseColorRatiosFlag)
+          BGR2SnGnRn(Frame, tempFrame, rows, cols);
+        else
+          memcpy(tempFrame, Frame, rows*cols*color_channels);
 
-        g = pSequence[base + 1];
-        k = (g - image[i + 1]) + KernelHalfWidth;
-        kernel2 = kerneltable[kernelbase2 + k];
+        NPBGSubtraction_Subset_Kernel(tempFrame, FGImage, FilteredFGImage);
+        /*NoiseFilter_o(FGImage,DisplayBuffers[3],rows,cols,4);
+        BuildImageIndex(DisplayBuffers[3],imageindex,rows,cols);
 
-        g = pSequence[base + 2];
-        k = (g - image[i + 2]) + KernelHalfWidth;
-        kernel3 = kerneltable[kernelbase3 + k];
+        ExpandOperatorIndexed(DisplayBuffers[3],imageindex,DisplayBuffers[4],imageindex,rows,cols);
+        ShrinkOperatorIndexed(DisplayBuffers[4],imageindex,FilteredFGImage,imageindex,rows,cols);
 
-        sum += kernel1*kernel2*kernel3;
-        j++;
+        memset(DisplayBuffers[3],0,rows*cols);*/
       }
 
-      p = sum / j;
-      Pimage1[ig] = p;
+      void NPBGSubtractor::Update(unsigned char * FGMask)
+      {
+        if (UpdateBGFlag)
+          SequenceBGUpdate_Pairs(tempFrame, FGMask);
+      }
     }
   }
-
-  DisplayPropabilityImageWithThresholding(Pimage1, FGImage, Threshold, rows, cols);
-}
-
-/*********************************************************************/
-
-void NPBGSubtractor::NBBGSubtraction(unsigned char * Frame,
-  unsigned char * FGImage,
-  unsigned char * FilteredFGImage,
-  unsigned char ** DisplayBuffers)
-{
-  if (UseColorRatiosFlag)
-    BGR2SnGnRn(Frame, tempFrame, rows, cols);
-  else
-    memcpy(tempFrame, Frame, rows*cols*color_channels);
-
-  NPBGSubtraction_Subset_Kernel(tempFrame, FGImage, FilteredFGImage);
-  /*NoiseFilter_o(FGImage,DisplayBuffers[3],rows,cols,4);
-  BuildImageIndex(DisplayBuffers[3],imageindex,rows,cols);
-
-  ExpandOperatorIndexed(DisplayBuffers[3],imageindex,DisplayBuffers[4],imageindex,rows,cols);
-  ShrinkOperatorIndexed(DisplayBuffers[4],imageindex,FilteredFGImage,imageindex,rows,cols);
-
-  memset(DisplayBuffers[3],0,rows*cols);*/
-}
-
-void NPBGSubtractor::Update(unsigned char * FGMask)
-{
-  if (UpdateBGFlag)
-    SequenceBGUpdate_Pairs(tempFrame, FGMask);
 }
diff --git a/src/algorithms/KDE/NPBGSubtractor.h b/src/algorithms/KDE/NPBGSubtractor.h
index fbe8664e96b7bb46c25abe443a333d5ab13eef7a..837fc85cb36a4aaa353ee9396ccfa6404e73ec5f 100644
--- a/src/algorithms/KDE/NPBGSubtractor.h
+++ b/src/algorithms/KDE/NPBGSubtractor.h
@@ -3,93 +3,102 @@
 #include "NPBGmodel.h"
 #include "KernelTable.h"
 
-#define FALSE 0
-#define TRUE 1
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace kde
+    {
+      const int FALSE = 0;
+      const int TRUE = 1;
 
-// kernal look up table settings
-#define 	KERNELHALFWIDTH 255
-#define 	SEGMAMAX 36.5
-#define	  SEGMAMIN 0.5
-#define		SEGMABINS 80
-#define		DEFAULTSEGMA 1.0
+      // kernal look up table settings
+      const int KERNELHALFWIDTH = 255;
+      const float SEGMAMAX = 36.5;
+      const float SEGMAMIN = 0.5;
+      const int SEGMABINS = 80;
+      const float DEFAULTSEGMA = 1.0;
 
-typedef struct
-{
-  unsigned char *Hist;
-  unsigned char *MedianBins;
-  unsigned char *MedianFreq;
-  unsigned char *AccSum;
-  unsigned char histbins;
-  unsigned char histsum;
-  unsigned int  imagesize;
-} DynamicMedianHistogram;
+      typedef struct
+      {
+        unsigned char *Hist;
+        unsigned char *MedianBins;
+        unsigned char *MedianFreq;
+        unsigned char *AccSum;
+        unsigned char histbins;
+        unsigned char histsum;
+        unsigned int  imagesize;
+      } DynamicMedianHistogram;
 
-typedef struct
-{
-  unsigned int cnt;
-  unsigned int *List;
-} ImageIndex;
+      typedef struct
+      {
+        unsigned int cnt;
+        unsigned int *List;
+      } ImageIndex;
 
-class NPBGSubtractor
-{
-private:
-  unsigned int rows;
-  unsigned int cols;
-  unsigned int color_channels;
-  unsigned int imagesize;
-  // flags
-  unsigned char UpdateBGFlag;
-  unsigned char SdEstimateFlag;
-  unsigned char UseColorRatiosFlag;
-  unsigned char AdaptBGFlag;
-  unsigned char SubsetFlag;
-  //
-  int UpdateSDRate;
-  double Threshold;
-  double AlphaValue;
-  unsigned int TimeIndex;
-  ImageIndex  *imageindex;
-  unsigned char *tempFrame;
-  KernelLUTable *KernelTable;
-  NPBGmodel *BGModel;
-  DynamicMedianHistogram AbsDiffHist;
-  double *Pimage1;
-  double *Pimage2;
-  //
-  void NPBGSubtraction_Subset_Kernel(unsigned char * image, unsigned char * FGImage, unsigned char * FilteredFGImage);
-  void SequenceBGUpdate_Pairs(unsigned char * image, unsigned char * Mask);
+      class NPBGSubtractor
+      {
+      private:
+        unsigned int rows;
+        unsigned int cols;
+        unsigned int color_channels;
+        unsigned int imagesize;
+        // flags
+        unsigned char UpdateBGFlag;
+        unsigned char SdEstimateFlag;
+        unsigned char UseColorRatiosFlag;
+        unsigned char AdaptBGFlag;
+        unsigned char SubsetFlag;
+        //
+        int UpdateSDRate;
+        double Threshold;
+        double AlphaValue;
+        unsigned int TimeIndex;
+        ImageIndex  *imageindex;
+        unsigned char *tempFrame;
+        KernelLUTable *KernelTable;
+        NPBGmodel *BGModel;
+        DynamicMedianHistogram AbsDiffHist;
+        double *Pimage1;
+        double *Pimage2;
+        //
+        void NPBGSubtraction_Subset_Kernel(unsigned char * image, unsigned char * FGImage, unsigned char * FilteredFGImage);
+        void SequenceBGUpdate_Pairs(unsigned char * image, unsigned char * Mask);
 
-public:
-  NPBGSubtractor();
-  virtual ~NPBGSubtractor();
-  //~NPBGSubtractor();
+      public:
+        NPBGSubtractor();
+        virtual ~NPBGSubtractor();
+        //~NPBGSubtractor();
 
-  int Intialize(unsigned int rows,
-    unsigned int cols,
-    unsigned int color_channels,
-    unsigned int SequenceLength,
-    unsigned int TimeWindowSize,
-    unsigned char SDEstimationFlag,
-    unsigned char UseColorRatiosFlag);
+        int Intialize(unsigned int rows,
+          unsigned int cols,
+          unsigned int color_channels,
+          unsigned int SequenceLength,
+          unsigned int TimeWindowSize,
+          unsigned char SDEstimationFlag,
+          unsigned char UseColorRatiosFlag);
 
-  void AddFrame(unsigned char * ImageBuffer);
+        void AddFrame(unsigned char * ImageBuffer);
 
-  void Estimation();
+        void Estimation();
 
-  void NBBGSubtraction(unsigned char *Frame,
-    unsigned char *FGImage,
-    unsigned char *FilteredFGImage,
-    unsigned char **DisplayBuffers);
+        void NBBGSubtraction(unsigned char *Frame,
+          unsigned char *FGImage,
+          unsigned char *FilteredFGImage,
+          unsigned char **DisplayBuffers);
 
-  void Update(unsigned char *);
+        void Update(unsigned char *);
 
-  void SetThresholds(double th, double alpha)
-  {
-    Threshold = th;
-    AlphaValue = alpha;
-  };
+        void SetThresholds(double th, double alpha)
+        {
+          Threshold = th;
+          AlphaValue = alpha;
+        };
 
-  void SetUpdateFlag(unsigned int bgflag) {
-    UpdateBGFlag = bgflag;
-  };
-};
+        void SetUpdateFlag(unsigned int bgflag) {
+          UpdateBGFlag = bgflag;
+        };
+      };
+    }
+  }
+}
diff --git a/src/algorithms/KDE/NPBGmodel.cpp b/src/algorithms/KDE/NPBGmodel.cpp
index f4bd2728cc90c186993d9fd24c02a9504ddbd5de..4e5b3cc9a37850d6c72bcd0dc575ab60caa8118a 100644
--- a/src/algorithms/KDE/NPBGmodel.cpp
+++ b/src/algorithms/KDE/NPBGmodel.cpp
@@ -2,26 +2,23 @@
 
 #include "NPBGmodel.h"
 
-#ifdef _DEBUG
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-//#define new DEBUG_NEW
-#endif
+//#ifdef _DEBUG
+//#undef THIS_FILE
+//static char THIS_FILE[] = __FILE__;
+////#define new DEBUG_NEW
+//#endif
 
-NPBGmodel::NPBGmodel()
-{
-  std::cout << "NPBGmodel()" << std::endl;
-}
+using namespace bgslibrary::algorithms::kde;
 
-NPBGmodel::~NPBGmodel()
-{
+NPBGmodel::NPBGmodel() {}
+
+NPBGmodel::~NPBGmodel() {
   delete Sequence;
   delete PixelQTop;
   delete TemporalBuffer;
   delete TemporalMask;
   delete AccMask;
   //delete SDbinsImage;
-  std::cout << "~NPBGmodel()" << std::endl;
 }
 
 NPBGmodel::NPBGmodel(unsigned int Rows,
@@ -31,8 +28,6 @@ NPBGmodel::NPBGmodel(unsigned int Rows,
   unsigned int pTimeWindowSize,
   unsigned int bg_suppression_time)
 {
-  std::cout << "NPBGmodel()" << std::endl;
-
   imagesize = Rows*Cols*ColorChannels;
 
   rows = Rows;
diff --git a/src/algorithms/KDE/NPBGmodel.h b/src/algorithms/KDE/NPBGmodel.h
index fc95adf67644c783c40ba7abec77d6a933815c7c..02a1f731b83e19adaa714c546fda6dc6e62655c5 100644
--- a/src/algorithms/KDE/NPBGmodel.h
+++ b/src/algorithms/KDE/NPBGmodel.h
@@ -2,51 +2,60 @@
 
 #include <iostream>
 
-class NPBGmodel
+namespace bgslibrary
 {
-private:
-  unsigned char *Sequence;
-  unsigned int SampleSize;
-  unsigned int TimeWindowSize;
-
-  unsigned int rows, cols, color_channels;
-  unsigned int imagesize;
-
-  unsigned int Top;
-  unsigned char *PixelQTop;
-
-  //unsigned int *PixelUpdateCounter;
-
-  unsigned char *SDbinsImage;
-
-  unsigned char *TemporalBuffer;
-  unsigned char TemporalBufferLength;
-  unsigned char TemporalBufferTop;
-  unsigned char *TemporalBufferMask;
-
-  unsigned char *TemporalMask;
-  unsigned char TemporalMaskLength;
-  unsigned char TemporalMaskTop;
-
-  unsigned int *AccMask;
-  unsigned int ResetMaskTh;	// Max continous duration a pixel can be detected before
-  // it is forced to be updated...
-
-  double *weights;
-
-public:
-  NPBGmodel();
-  //~NPBGmodel();
-  virtual ~NPBGmodel();
-
-  NPBGmodel(unsigned int Rows,
-    unsigned int Cols,
-    unsigned int ColorChannels,
-    unsigned int Length,
-    unsigned int pTimeWindowSize,
-    unsigned int bg_suppression_time);
-
-  void AddFrame(unsigned char *ImageBuffer);
-
-  friend class NPBGSubtractor;
-};
+  namespace algorithms
+  {
+    namespace kde
+    {
+      class NPBGmodel
+      {
+      private:
+        unsigned char *Sequence;
+        unsigned int SampleSize;
+        unsigned int TimeWindowSize;
+
+        unsigned int rows, cols, color_channels;
+        unsigned int imagesize;
+
+        unsigned int Top;
+        unsigned char *PixelQTop;
+
+        //unsigned int *PixelUpdateCounter;
+
+        unsigned char *SDbinsImage;
+
+        unsigned char *TemporalBuffer;
+        unsigned char TemporalBufferLength;
+        unsigned char TemporalBufferTop;
+        unsigned char *TemporalBufferMask;
+
+        unsigned char *TemporalMask;
+        unsigned char TemporalMaskLength;
+        unsigned char TemporalMaskTop;
+
+        unsigned int *AccMask;
+        unsigned int ResetMaskTh;	// Max continous duration a pixel can be detected before
+        // it is forced to be updated...
+
+        double *weights;
+
+      public:
+        NPBGmodel();
+        //~NPBGmodel();
+        virtual ~NPBGmodel();
+
+        NPBGmodel(unsigned int Rows,
+          unsigned int Cols,
+          unsigned int ColorChannels,
+          unsigned int Length,
+          unsigned int pTimeWindowSize,
+          unsigned int bg_suppression_time);
+
+        void AddFrame(unsigned char *ImageBuffer);
+
+        friend class NPBGSubtractor;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBAdaptiveSOM.cpp b/src/algorithms/LBAdaptiveSOM.cpp
index a43e55acbc03a7316d75b20a94b29fd0fcf4ec48..b051ed54e035be32f5ce9d84cc68acb44fb72411 100644
--- a/src/algorithms/LBAdaptiveSOM.cpp
+++ b/src/algorithms/LBAdaptiveSOM.cpp
@@ -29,7 +29,7 @@ void LBAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M
     int w = cvGetSize(frame).width;
     int h = cvGetSize(frame).height;
 
-    m_pBGModel = new BGModelSom(w, h);
+    m_pBGModel = new lb::BGModelSom(w, h);
     m_pBGModel->InitModel(frame);
   }
 
diff --git a/src/algorithms/LBAdaptiveSOM.h b/src/algorithms/LBAdaptiveSOM.h
index e1648960b2cd3104936eb952bd8726c8f1f6bd21..7141f91e0fcda5cd0b831c28883835a111774cb7 100644
--- a/src/algorithms/LBAdaptiveSOM.h
+++ b/src/algorithms/LBAdaptiveSOM.h
@@ -7,9 +7,6 @@
 
 #include "lb/BGModelSom.h"
 
-using namespace lb_library;
-using namespace lb_library::AdaptiveSOM;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,7 +14,7 @@ namespace bgslibrary
     class LBAdaptiveSOM : public IBGS
     {
     private:
-      BGModel* m_pBGModel;
+      lb::BGModel* m_pBGModel;
       int sensitivity;
       int trainingSensitivity;
       int learningRate;
diff --git a/src/algorithms/LBFuzzyAdaptiveSOM.cpp b/src/algorithms/LBFuzzyAdaptiveSOM.cpp
index 1eadf750568ff78c6a8b736f31cf62f6a9442039..a4feed6d131ed665184b36bc64ca5dc2aeac9544 100644
--- a/src/algorithms/LBFuzzyAdaptiveSOM.cpp
+++ b/src/algorithms/LBFuzzyAdaptiveSOM.cpp
@@ -28,7 +28,7 @@ void LBFuzzyAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output,
     int w = cvGetSize(frame).width;
     int h = cvGetSize(frame).height;
 
-    m_pBGModel = new BGModelFuzzySom(w, h);
+    m_pBGModel = new lb::BGModelFuzzySom(w, h);
     m_pBGModel->InitModel(frame);
   }
 
diff --git a/src/algorithms/LBFuzzyAdaptiveSOM.h b/src/algorithms/LBFuzzyAdaptiveSOM.h
index 6c9b4421de0d2fefe20d4b797f53f119455b4cfd..9c45382913d35ca941b05f2cc29be89b1216fb6c 100644
--- a/src/algorithms/LBFuzzyAdaptiveSOM.h
+++ b/src/algorithms/LBFuzzyAdaptiveSOM.h
@@ -7,9 +7,6 @@
 
 #include "lb/BGModelFuzzySom.h"
 
-using namespace lb_library;
-using namespace lb_library::FuzzyAdaptiveSOM;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,7 +14,7 @@ namespace bgslibrary
     class LBFuzzyAdaptiveSOM : public IBGS
     {
     private:
-      BGModel* m_pBGModel;
+      lb::BGModel* m_pBGModel;
       int sensitivity;
       int trainingSensitivity;
       int learningRate;
diff --git a/src/algorithms/LBFuzzyGaussian.cpp b/src/algorithms/LBFuzzyGaussian.cpp
index 95171913a037280b14984c358497c171140d9368..c501848815ad4b6ae9a717d2658e37d3785c8dc4 100644
--- a/src/algorithms/LBFuzzyGaussian.cpp
+++ b/src/algorithms/LBFuzzyGaussian.cpp
@@ -28,7 +28,7 @@ void LBFuzzyGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv:
     int w = cvGetSize(frame).width;
     int h = cvGetSize(frame).height;
 
-    m_pBGModel = new BGModelFuzzyGauss(w, h);
+    m_pBGModel = new lb::BGModelFuzzyGauss(w, h);
     m_pBGModel->InitModel(frame);
   }
 
diff --git a/src/algorithms/LBFuzzyGaussian.h b/src/algorithms/LBFuzzyGaussian.h
index 7a48b71b650353c69ffebe86577c04def7df7a8b..3725fda48aff1e7641d85e28d4d514a2883f36a6 100644
--- a/src/algorithms/LBFuzzyGaussian.h
+++ b/src/algorithms/LBFuzzyGaussian.h
@@ -7,9 +7,6 @@
 
 #include "lb/BGModelFuzzyGauss.h"
 
-using namespace lb_library;
-using namespace lb_library::FuzzyGaussian;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,7 +14,7 @@ namespace bgslibrary
     class LBFuzzyGaussian : public IBGS
     {
     private:
-      BGModel* m_pBGModel;
+      lb::BGModel* m_pBGModel;
       int sensitivity;
       int bgThreshold;
       int learningRate;
diff --git a/src/algorithms/LBMixtureOfGaussians.cpp b/src/algorithms/LBMixtureOfGaussians.cpp
index b04e0f63fb166584605aaf5b3e6d9b7efc56f257..219cd1b9f5dabcb370abfa618b3f3dc78430c4e4 100644
--- a/src/algorithms/LBMixtureOfGaussians.cpp
+++ b/src/algorithms/LBMixtureOfGaussians.cpp
@@ -28,7 +28,7 @@ void LBMixtureOfGaussians::process(const cv::Mat &img_input, cv::Mat &img_output
     int w = cvGetSize(frame).width;
     int h = cvGetSize(frame).height;
 
-    m_pBGModel = new BGModelMog(w, h);
+    m_pBGModel = new lb::BGModelMog(w, h);
     m_pBGModel->InitModel(frame);
   }
 
diff --git a/src/algorithms/LBMixtureOfGaussians.h b/src/algorithms/LBMixtureOfGaussians.h
index 0a5cf76c88a14a17c5fe2c109b0d73c459452fc3..b4211561ba04442c6b5ed0a6effd43b4fa6821bb 100644
--- a/src/algorithms/LBMixtureOfGaussians.h
+++ b/src/algorithms/LBMixtureOfGaussians.h
@@ -7,9 +7,6 @@
 
 #include "lb/BGModelMog.h"
 
-using namespace lb_library;
-using namespace lb_library::MixtureOfGaussians;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,7 +14,7 @@ namespace bgslibrary
     class LBMixtureOfGaussians : public IBGS
     {
     private:
-      BGModel* m_pBGModel;
+      lb::BGModel* m_pBGModel;
       int sensitivity;
       int bgThreshold;
       int learningRate;
diff --git a/src/algorithms/LBP_MRF.cpp b/src/algorithms/LBP_MRF.cpp
index 1b2266e1adb3a49e06d4e234f2a1bb8696f490ff..e0d4c64977688cccf415075cb1f0c2ca27682b95 100644
--- a/src/algorithms/LBP_MRF.cpp
+++ b/src/algorithms/LBP_MRF.cpp
@@ -10,8 +10,8 @@ LBP_MRF::LBP_MRF() :
 {
   debug_construction(LBP_MRF);
   initLoadSaveConfig(algorithmName);
-  Detector = new MotionDetection();
-  Detector->SetMode(MotionDetection::md_LBPHistograms);
+  Detector = new lbp_mrf::MotionDetection();
+  Detector->SetMode(lbp_mrf::MotionDetection::md_LBPHistograms);
 }
 
 LBP_MRF::~LBP_MRF() {
@@ -25,8 +25,8 @@ void LBP_MRF::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &im
   init(img_input, img_output, img_bgmodel);
 
   IplImage TempImage(img_input);
-  MEImage InputImage(img_input.cols, img_input.rows, img_input.channels());
-  MEImage OutputImage(img_input.cols, img_input.rows, img_input.channels());
+  lbp_mrf::MEImage InputImage(img_input.cols, img_input.rows, img_input.channels());
+  lbp_mrf::MEImage OutputImage(img_input.cols, img_input.rows, img_input.channels());
 
   InputImage.SetIplImage((void*)&TempImage);
 
diff --git a/src/algorithms/LBP_MRF.h b/src/algorithms/LBP_MRF.h
index 5e199a1c3211c30ec72b8c2ba6a9d7bd790fbc1f..0edb3873155940fa683ba053a095a0f12380f479 100644
--- a/src/algorithms/LBP_MRF.h
+++ b/src/algorithms/LBP_MRF.h
@@ -14,7 +14,7 @@ namespace bgslibrary
     class LBP_MRF : public IBGS
     {
     private:
-      MotionDetection* Detector;
+      lbp_mrf::MotionDetection* Detector;
       cv::Mat img_segmentation;
 
     public:
diff --git a/src/algorithms/LBP_MRF/MEDefs.cpp b/src/algorithms/LBP_MRF/MEDefs.cpp
index 07486dc8c4024a75493456208816b4552f0f73cb..726221fe68e96b81cdcd0c8562b8064e10f39295 100644
--- a/src/algorithms/LBP_MRF/MEDefs.cpp
+++ b/src/algorithms/LBP_MRF/MEDefs.cpp
@@ -2,19 +2,28 @@
 
 #include "MEDefs.hpp"
 
-float MERound(float number)
-{
-  double FracPart = 0.0;
-  double IntPart = 0.0;
-  float Ret = 0.0;
+//using namespace bgslibrary::algorithms::lbp_mrf;
 
-  FracPart = modf((double)number, &IntPart);
-  if (number >= 0)
+namespace bgslibrary
+{
+  namespace algorithms
   {
-    Ret = (float)(FracPart >= 0.5 ? IntPart + 1 : IntPart);
-  }
-  else {
-    Ret = (float)(FracPart <= -0.5 ? IntPart - 1 : IntPart);
+    namespace lbp_mrf
+    {
+      float MERound(float number)
+      {
+        double FracPart = 0.0;
+        double IntPart = 0.0;
+        float Ret = 0.0;
+
+        FracPart = modf((double)number, &IntPart);
+        if (number >= 0)
+          Ret = (float)(FracPart >= 0.5 ? IntPart + 1 : IntPart);
+        else
+          Ret = (float)(FracPart <= -0.5 ? IntPart - 1 : IntPart);
+
+        return Ret;
+      }
+    }
   }
-  return Ret;
 }
diff --git a/src/algorithms/LBP_MRF/MEDefs.hpp b/src/algorithms/LBP_MRF/MEDefs.hpp
index 0c955e17560ff1ccbfeff55715f51dee0e21b1ee..5092f87f0a07e2c9180fb8c718e9d55aa52974cc 100644
--- a/src/algorithms/LBP_MRF/MEDefs.hpp
+++ b/src/algorithms/LBP_MRF/MEDefs.hpp
@@ -1,54 +1,60 @@
 #pragma once
 
- /// Pi value
-#ifndef ME_PI_VALUE
-#define ME_PI_VALUE 3.14159265
-#endif
-
-/*! Process state */
-typedef enum {
-  ps_Min = 0,                /*!< Minimum value */
-  ps_Uninitialized = ps_Min, /*!< Uninitialized state */
-  ps_Initialized,            /*!< Initialized state */
-  ps_InProgress,             /*!< In progress state */
-  ps_Successful,             /*!< Successful state */
-  ps_Max = ps_Successful     /*!< Maximum value */
-} MEProcessStateType;
-
-template <typename T>
-const T& MEMin(const T& a, const T& b)
-{
-  if (a < b)
-    return a;
-  return b;
-}
-
-template <typename T>
-const T& MEMax(const T& a, const T& b)
+namespace bgslibrary
 {
-  if (a < b)
-    return b;
-  return a;
+  namespace algorithms
+  {
+    namespace lbp_mrf
+    {
+      const double ME_PI_VALUE = 3.14159265;
+      
+      /*! Process state */
+      typedef enum {
+        ps_Min = 0,                /*!< Minimum value */
+        ps_Uninitialized = ps_Min, /*!< Uninitialized state */
+        ps_Initialized,            /*!< Initialized state */
+        ps_InProgress,             /*!< In progress state */
+        ps_Successful,             /*!< Successful state */
+        ps_Max = ps_Successful     /*!< Maximum value */
+      } MEProcessStateType;
+
+      template <typename T>
+      const T& MEMin(const T& a, const T& b)
+      {
+        if (a < b)
+          return a;
+        return b;
+      }
+
+      template <typename T>
+      const T& MEMax(const T& a, const T& b)
+      {
+        if (a < b)
+          return b;
+        return a;
+      }
+
+      template <typename T>
+      const T& MEBound(const T& min, const T& val, const T& max)
+      {
+        return MEMax(min, MEMin(max, val));
+      }
+
+      /*!
+      * @brief Round a float number
+      *
+      * @param number number to round
+      *
+      * @return New float number
+      *
+      * This method rounds a float number, if the fraction is .5 or lower
+      * then it rounds down, otherwise up.
+      *
+      */
+
+      float MERound(float number);
+
+      /** @} */
+    }
+  }
 }
-
-template <typename T>
-const T& MEBound(const T& min, const T& val, const T& max)
-{
-  return MEMax(min, MEMin(max, val));
-}
-
-/*!
- * @brief Round a float number
- *
- * @param number number to round
- *
- * @return New float number
- *
- * This method rounds a float number, if the fraction is .5 or lower
- * then it rounds down, otherwise up.
- *
- */
-
-float MERound(float number);
-
-/** @} */
diff --git a/src/algorithms/LBP_MRF/MEHistogram.cpp b/src/algorithms/LBP_MRF/MEHistogram.cpp
index ec5ce1a533e493ec549da8e4fca56ccbf54a98a0..8e5cde351ec3141f412527575dc73a605020059b 100644
--- a/src/algorithms/LBP_MRF/MEHistogram.cpp
+++ b/src/algorithms/LBP_MRF/MEHistogram.cpp
@@ -1,4 +1,5 @@
 #include <opencv2/opencv.hpp>
+// opencv legacy includes
 #include <opencv2/core/core_c.h>
 #include <opencv2/imgproc/types_c.h>
 #include <opencv2/imgproc/imgproc_c.h>
@@ -7,17 +8,15 @@
 #include "MEDefs.hpp"
 #include "MEImage.hpp"
 
-MEHistogram::MEHistogram()
-{
+using namespace bgslibrary::algorithms::lbp_mrf;
+
+MEHistogram::MEHistogram() {
   Clear();
 }
 
-MEHistogram::~MEHistogram()
-{
-}
+MEHistogram::~MEHistogram(){}
 
-void MEHistogram::Clear()
-{
+void MEHistogram::Clear() {
   memset(&HistogramData, 0, 256 * sizeof(int));
 }
 
diff --git a/src/algorithms/LBP_MRF/MEHistogram.hpp b/src/algorithms/LBP_MRF/MEHistogram.hpp
index be8453e503b383727e6801bc71a8cf7f7dbc3359..9ae3a022bf743db172845dde550cb06baa663d39 100644
--- a/src/algorithms/LBP_MRF/MEHistogram.hpp
+++ b/src/algorithms/LBP_MRF/MEHistogram.hpp
@@ -1,317 +1,326 @@
 #pragma once
 
-class MEImage;
-
-/**
- * MEHistogram
- * @brief The class provides basic histogram operations
- */
-class MEHistogram
-{
-public:
-
-  /// Types of histogram calculation
-  typedef enum {
-    h_Min = 0,           /*!< Minimum value */
-    h_Overwrite = h_Min, /*!< Overwrite */
-    h_Add,               /*!< Add */
-    h_Max = h_Add        /*!< Maximum value */
-  } HistogramType;
-
-  /// Types of histogram stretching
-  typedef enum {
-    s_Min = 0,          /*!< Minimum value */
-    s_OwnMode = s_Min,  /*!< Own mode */
-    s_GimpMode,         /*!< Gimp mode */
-    s_Max = s_GimpMode  /*!< Maximum value */
-  } StretchType;
-
-  /// Constructor of class
-  MEHistogram();
-  /// Destructor of class
-  ~MEHistogram();
-
-  /*!
-   * @brief Clear histogram data
-   *
-   * Clear histogram data.
-   *
-   */
-
-  void Clear();
-
-  /*!
-   * @brief Equality (==) operator
-   *
-   * @param histogram Histogram to be compared
-   *
-   * @return True if the two histograms are equal.
-   *
-   * Compare two histograms.
-   *
-   */
-
-  bool operator==(MEHistogram& histogram) const;
-
-  /*!
-   * @brief Calculate the histogram of one color channel
-   *
-   * @param image Given image for the calculations
-   * @param channel Selected color channel for calculation (Range: 1..x)
-   * @param mode The mode of calculation.
-   *
-   * The method calculates the histograms of a color channel.
-   * There is two different type of the function:
-   *
-   * - h_Add: Add the data to the existing histogram.
-   * - h_Overwrite: Clear the histogram data before the
-   * calculation.
-   *
-   */
-
-  void Calculate(MEImage& image, int channel, HistogramType mode);
-
-  /*!
-   * @brief Calculate the average histogram of an image
-   *
-   * @param image Given image for the calculations
-   * @param mode Histogram calculation mode
-   *
-   * The method calculates the average histogram of an image.
-   *
-   */
-
-  void Calculate(MEImage& image, HistogramType mode = h_Overwrite);
-
-  /*!
-   * @brief Calculate the histogram of an image region
-   *
-   * @param image Given image for the calculations
-   * @param channel Selected color channel for calculation (Range: 1..x)
-   * @param x0 x0 coordinate of the region
-   * @param y0 y0 coordinate of the region
-   * @param x1 x1 coordinate of the region
-   * @param y1 y1 coordinate of the region
-   *
-   * The method calculates the average histogram of an image region
-   * (x0,y0)-(x1,y1).
-   *
-   */
-
-  void Calculate(MEImage& image, int channel, int x0, int y0, int x1, int y1);
-
-  /*!
-   * @brief Get the index of maximum value of the histogram
-   *
-   * @return Index number
-   *
-   * Function gives an index value back where is the highest
-   * peak of the histogram.
-   *
-   */
-
-  int GetPeakIndex() const;
-
-  /*!
-   * @brief Get the lowest histogram index with an threshold value
-   *
-   * @param threshold Specified threshold (in percent: 0..100 %)
-   *
-   * @return Index number
-   *
-   * Function gives the lowest index back whose value reaches
-   * an threshold value calculated by (counted pixel number /
-   * 10*threshold / 100).
-   *
-   */
-
-  int GetLowestLimitIndex(int threshold) const;
-
-  /*!
-   * @brief Get the highest histogram index with an threshold value
-   *
-   * @param threshold Specified threshold (in percent: 0..100 %)
-   *
-   * @return Index number
-   *
-   * Function gives the highest index back whose value reaches
-   * an threshold value calculated by (counted pixel number /
-   * 10*threshold / 100).
-   *
-   */
-
-  int GetHighestLimitIndex(int threshold) const;
-
-  /*!
-   * @brief Get the amount of the histogram values in an interval
-   *
-   * @param minindex Minimal index of the interval
-   * @param maxindex Maximal index of the interval
-   *
-   * @return Amount of the values
-   *
-   * Function calculates the amount of the histogram values
-   * in a given interval.
-   *
-   */
-
-  int GetPowerAmount(int min_index, int max_index) const;
-
-  /*!
-   * @brief Get index value of the centroid point of the histogram
-   *
-   * @return Index number
-   *
-   * Function calculates the centre of area of the histogram and
-   * gives the index number back.
-   *
-   */
-
-  int GetCentroidIndex() const;
-
-  /*!
-   * @brief Stretch the histogram
-   *
-   * @param mode Mode of the histogram stretching
-   *
-   * @return True if successful, otherwise false.
-   *
-   * The function selects and stretches the main power
-   * interval of the histogram. The following calculation
-   * modes are available:
-   *
-   * - s_OwnMode: The calculation of the power
-   * interval is selected by functions Histogram::GetHistogramLowestLimitIndex()
-   * and Histogram::GetHistogramHighestLimitIndex() where the
-   * threshold is 20, 10, 5, 2, 1 in order. The power range will
-   * be selected if the length is at least 52 long or the used
-   * threshold reaches the 1 value.
-   * - s_GimpMode: The minimum index of power interval is
-   * specified by the first fulfilled abs(percentage[i]-0.006) <
-   * fabs(percentage[i+1]-0.006) where the percentage[i] means
-   * the amount of the histogram values in the interval [0, i].
-   * The maximum index is specified by the first fulfilled
-   * (from the end of the histogram) abs(percentage[i]-0.006) <
-   * fabs(percentage[i-1]-0.006) where the percentage[i] means
-   * the amount of the histogram values in the interval [i, 255].
-   *
-   * The stretch operation is rejected if the power interval is
-   * less than 10 or less than 20 and the percentage[min_index, max_index]
-   * / percentage[0, 255] < 0.2.
-   *
-   */
-
-  bool Stretch(StretchType mode);
-
-  /// Histogram spectrum
-  int HistogramData[256];
-};
-
-
-/**
- * MEHistogramTransform
- * @brief The class provides histogram operations
- */
-class MEHistogramTransform
+namespace bgslibrary
 {
-public:
-  /// Types of histogram processing
-  typedef enum {
-    p_Min = 0,                   /*!< Minimum value */
-    p_SeparateChannels = p_Min, /*!< Separate channels */
-    p_Average,                   /*!< Average */
-    p_Max = p_Average           /*!< Maximum value */
-  } ProcessingType;
-
-  /// Types of histogram transformations
-  typedef enum {
-    t_Min = 0,             /*!< Minimum value */
-    t_Continuous = t_Min, /*!< Continuous */
-    t_Discrete,            /*!< Discrete */
-    t_Max = t_Discrete    /*!< Maximum value */
-  } TransformType;
-
-  /// Constructor of class
-  MEHistogramTransform();
-  /// Destructor of class
-  ~MEHistogramTransform();
-
-  /*!
-   * @brief Histogram stretching an image
-   *
-   * @param image Source image to stretch
-   *
-   * The function stretches the histogram of the given image with
-   * default parameters: process the color channels separately
-   * and continuously.
-   *
-   */
-
-  void HistogramStretch(MEImage& image);
-
-  /*!
-   * @brief Histogram stretching with specified parameters
-   *
-   * @param image Source image to stretch
-   * @param time_mode Mode of the histogram stretching
-   *
-   * The function transformations the histogram of the image.
-   * There is some different possibilities to make the operation:
-   *
-   * - t_Continuous: The function always stretches the
-   * image at each call of the method.
-   * - t_Discrete: A histogram is calculated at the first
-   * call of the function and all further images will be
-   * stretched by this initial histogram.
-   *
-   */
-
-  void HistogramStretch(MEImage& image, TransformType time_mode);
-
-  /*!
-   * @brief Histogram equalization on an image
-   *
-   * @param image Source image to equalize
-   *
-   * The source image is transformed by histogram
-   * equalization.
-   *
-   */
-
-  void HistogramEqualize(MEImage& image);
-
-  /*!
-   * @brief Set the process mode of the histogram transformation
-   *
-   * @param new_channel_mode New mode of processing channels
-   * @param new_stretch_mode New mode of histogram stretching
-   *
-   * The process mode of histogram transformation can be
-   * set by this method. Two process modes are available for
-   * processing channels:
-   *
-   * - p_SeparateChannels: The class processes the color channels
-   * separately.
-   * - p_Average: The color channels are averaged
-   * in the histogram operations.
-   *
-   * Two process modes are usable for histogram stretching:
-   * s_OwnMode and s_GimpMode. See Histogram::Stretch()
-   * for more details.
-   *
-   */
-
-  void SetStretchProcessingMode(ProcessingType new_channel_mode, MEHistogram::StretchType new_stretch_mode);
-
-private:
-  /// Type of the process of histograms
-  ProcessingType ChannelMode;
-  /// Stretch mode
-  MEHistogram::StretchType StretchMode;
-  /// Histograms for red, green and blue color channels
-  MEHistogram RedChannel, GreenChannel, BlueChannel;
-  /// Histogram for average calculation
-  MEHistogram AverageChannel;
-  /// Continuous histogram stretch is done already
-  bool DiscreteStretchingDone;
-};
+  namespace algorithms
+  {
+    namespace lbp_mrf
+    {
+      class MEImage;
+
+      /**
+       * MEHistogram
+       * @brief The class provides basic histogram operations
+       */
+      class MEHistogram
+      {
+      public:
+
+        /// Types of histogram calculation
+        typedef enum {
+          h_Min = 0,           /*!< Minimum value */
+          h_Overwrite = h_Min, /*!< Overwrite */
+          h_Add,               /*!< Add */
+          h_Max = h_Add        /*!< Maximum value */
+        } HistogramType;
+
+        /// Types of histogram stretching
+        typedef enum {
+          s_Min = 0,          /*!< Minimum value */
+          s_OwnMode = s_Min,  /*!< Own mode */
+          s_GimpMode,         /*!< Gimp mode */
+          s_Max = s_GimpMode  /*!< Maximum value */
+        } StretchType;
+
+        /// Constructor of class
+        MEHistogram();
+        /// Destructor of class
+        ~MEHistogram();
+
+        /*!
+        * @brief Clear histogram data
+        *
+        * Clear histogram data.
+        *
+        */
+
+        void Clear();
+
+        /*!
+        * @brief Equality (==) operator
+        *
+        * @param histogram Histogram to be compared
+        *
+        * @return True if the two histograms are equal.
+        *
+        * Compare two histograms.
+        *
+        */
+
+        bool operator==(MEHistogram& histogram) const;
+
+        /*!
+        * @brief Calculate the histogram of one color channel
+        *
+        * @param image Given image for the calculations
+        * @param channel Selected color channel for calculation (Range: 1..x)
+        * @param mode The mode of calculation.
+        *
+        * The method calculates the histograms of a color channel.
+        * There is two different type of the function:
+        *
+        * - h_Add: Add the data to the existing histogram.
+        * - h_Overwrite: Clear the histogram data before the
+        * calculation.
+        *
+        */
+
+        void Calculate(MEImage& image, int channel, HistogramType mode);
+
+        /*!
+        * @brief Calculate the average histogram of an image
+        *
+        * @param image Given image for the calculations
+        * @param mode Histogram calculation mode
+        *
+        * The method calculates the average histogram of an image.
+        *
+        */
+
+        void Calculate(MEImage& image, HistogramType mode = h_Overwrite);
+
+        /*!
+        * @brief Calculate the histogram of an image region
+        *
+        * @param image Given image for the calculations
+        * @param channel Selected color channel for calculation (Range: 1..x)
+        * @param x0 x0 coordinate of the region
+        * @param y0 y0 coordinate of the region
+        * @param x1 x1 coordinate of the region
+        * @param y1 y1 coordinate of the region
+        *
+        * The method calculates the average histogram of an image region
+        * (x0,y0)-(x1,y1).
+        *
+        */
+
+        void Calculate(MEImage& image, int channel, int x0, int y0, int x1, int y1);
+
+        /*!
+        * @brief Get the index of maximum value of the histogram
+        *
+        * @return Index number
+        *
+        * Function gives an index value back where is the highest
+        * peak of the histogram.
+        *
+        */
+
+        int GetPeakIndex() const;
+
+        /*!
+        * @brief Get the lowest histogram index with an threshold value
+        *
+        * @param threshold Specified threshold (in percent: 0..100 %)
+        *
+        * @return Index number
+        *
+        * Function gives the lowest index back whose value reaches
+        * an threshold value calculated by (counted pixel number /
+        * 10*threshold / 100).
+        *
+        */
+
+        int GetLowestLimitIndex(int threshold) const;
+
+        /*!
+        * @brief Get the highest histogram index with an threshold value
+        *
+        * @param threshold Specified threshold (in percent: 0..100 %)
+        *
+        * @return Index number
+        *
+        * Function gives the highest index back whose value reaches
+        * an threshold value calculated by (counted pixel number /
+        * 10*threshold / 100).
+        *
+        */
+
+        int GetHighestLimitIndex(int threshold) const;
+
+        /*!
+        * @brief Get the amount of the histogram values in an interval
+        *
+        * @param minindex Minimal index of the interval
+        * @param maxindex Maximal index of the interval
+        *
+        * @return Amount of the values
+        *
+        * Function calculates the amount of the histogram values
+        * in a given interval.
+        *
+        */
+
+        int GetPowerAmount(int min_index, int max_index) const;
+
+        /*!
+        * @brief Get index value of the centroid point of the histogram
+        *
+        * @return Index number
+        *
+        * Function calculates the centre of area of the histogram and
+        * gives the index number back.
+        *
+        */
+
+        int GetCentroidIndex() const;
+
+        /*!
+        * @brief Stretch the histogram
+        *
+        * @param mode Mode of the histogram stretching
+        *
+        * @return True if successful, otherwise false.
+        *
+        * The function selects and stretches the main power
+        * interval of the histogram. The following calculation
+        * modes are available:
+        *
+        * - s_OwnMode: The calculation of the power
+        * interval is selected by functions Histogram::GetHistogramLowestLimitIndex()
+        * and Histogram::GetHistogramHighestLimitIndex() where the
+        * threshold is 20, 10, 5, 2, 1 in order. The power range will
+        * be selected if the length is at least 52 long or the used
+        * threshold reaches the 1 value.
+        * - s_GimpMode: The minimum index of power interval is
+        * specified by the first fulfilled abs(percentage[i]-0.006) <
+        * fabs(percentage[i+1]-0.006) where the percentage[i] means
+        * the amount of the histogram values in the interval [0, i].
+        * The maximum index is specified by the first fulfilled
+        * (from the end of the histogram) abs(percentage[i]-0.006) <
+        * fabs(percentage[i-1]-0.006) where the percentage[i] means
+        * the amount of the histogram values in the interval [i, 255].
+        *
+        * The stretch operation is rejected if the power interval is
+        * less than 10 or less than 20 and the percentage[min_index, max_index]
+        * / percentage[0, 255] < 0.2.
+        *
+        */
+
+        bool Stretch(StretchType mode);
+
+        /// Histogram spectrum
+        int HistogramData[256];
+      };
+
+
+      /**
+       * MEHistogramTransform
+       * @brief The class provides histogram operations
+       */
+      class MEHistogramTransform
+      {
+      public:
+        /// Types of histogram processing
+        typedef enum {
+          p_Min = 0,                   /*!< Minimum value */
+          p_SeparateChannels = p_Min, /*!< Separate channels */
+          p_Average,                   /*!< Average */
+          p_Max = p_Average           /*!< Maximum value */
+        } ProcessingType;
+
+        /// Types of histogram transformations
+        typedef enum {
+          t_Min = 0,             /*!< Minimum value */
+          t_Continuous = t_Min, /*!< Continuous */
+          t_Discrete,            /*!< Discrete */
+          t_Max = t_Discrete    /*!< Maximum value */
+        } TransformType;
+
+        /// Constructor of class
+        MEHistogramTransform();
+        /// Destructor of class
+        ~MEHistogramTransform();
+
+        /*!
+        * @brief Histogram stretching an image
+        *
+        * @param image Source image to stretch
+        *
+        * The function stretches the histogram of the given image with
+        * default parameters: process the color channels separately
+        * and continuously.
+        *
+        */
+
+        void HistogramStretch(MEImage& image);
+
+        /*!
+        * @brief Histogram stretching with specified parameters
+        *
+        * @param image Source image to stretch
+        * @param time_mode Mode of the histogram stretching
+        *
+        * The function transformations the histogram of the image.
+        * There is some different possibilities to make the operation:
+        *
+        * - t_Continuous: The function always stretches the
+        * image at each call of the method.
+        * - t_Discrete: A histogram is calculated at the first
+        * call of the function and all further images will be
+        * stretched by this initial histogram.
+        *
+        */
+
+        void HistogramStretch(MEImage& image, TransformType time_mode);
+
+        /*!
+        * @brief Histogram equalization on an image
+        *
+        * @param image Source image to equalize
+        *
+        * The source image is transformed by histogram
+        * equalization.
+        *
+        */
+
+        void HistogramEqualize(MEImage& image);
+
+        /*!
+        * @brief Set the process mode of the histogram transformation
+        *
+        * @param new_channel_mode New mode of processing channels
+        * @param new_stretch_mode New mode of histogram stretching
+        *
+        * The process mode of histogram transformation can be
+        * set by this method. Two process modes are available for
+        * processing channels:
+        *
+        * - p_SeparateChannels: The class processes the color channels
+        * separately.
+        * - p_Average: The color channels are averaged
+        * in the histogram operations.
+        *
+        * Two process modes are usable for histogram stretching:
+        * s_OwnMode and s_GimpMode. See Histogram::Stretch()
+        * for more details.
+        *
+        */
+
+        void SetStretchProcessingMode(ProcessingType new_channel_mode, MEHistogram::StretchType new_stretch_mode);
+
+      private:
+        /// Type of the process of histograms
+        ProcessingType ChannelMode;
+        /// Stretch mode
+        MEHistogram::StretchType StretchMode;
+        /// Histograms for red, green and blue color channels
+        MEHistogram RedChannel, GreenChannel, BlueChannel;
+        /// Histogram for average calculation
+        MEHistogram AverageChannel;
+        /// Continuous histogram stretch is done already
+        bool DiscreteStretchingDone;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBP_MRF/MEImage.cpp b/src/algorithms/LBP_MRF/MEImage.cpp
index 71d66debc89083bcf2b49c6433301250774d862d..0928871d3d4bb6be0bd4a2df26ca9c42949f447c 100644
--- a/src/algorithms/LBP_MRF/MEImage.cpp
+++ b/src/algorithms/LBP_MRF/MEImage.cpp
@@ -1,1391 +1,1403 @@
 #include <opencv2/opencv.hpp>
+// opencv legacy includes
 #include <opencv2/imgproc/types_c.h>
 #include <opencv2/imgproc/imgproc_c.h>
 
 #include "MEImage.hpp"
 #include "MEDefs.hpp"
 
+//using namespace bgslibrary::algorithms::lbp_mrf;
+
 #define ME_CAST_TO_IPLIMAGE(image_ptr) ((IplImage*)image_ptr)
 #define ME_RELEASE_IPLIMAGE(image_ptr) \
   cvReleaseImage((IplImage**)&image_ptr); \
   image_ptr = NULL;
 
- // RGB to YUV transform
-const float RGBtoYUVMatrix[3][3] =
-{ { 0.299, 0.587, 0.114 },
- { -0.147, -0.289, 0.436 },
- { 0.615, -0.515, -0.100 } };
-
-// RGB to YIQ transform
-const float RGBtoYIQMatrix[3][3] =
-{ { 0.299, 0.587, 0.114 },
- { 0.596, -0.274, -0.322 },
- { 0.212, -0.523, 0.311 } };
-
-MEImage::MEImage(int width, int height, int layers) : cvImg(NULL)
-{
-  _Init(width, height, layers);
-}
-
-MEImage::MEImage(const MEImage& other) : cvImg(NULL)
+namespace bgslibrary
 {
-  _Copy(other);
-}
-
-MEImage::~MEImage()
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg))
+  namespace algorithms
   {
-    ME_RELEASE_IPLIMAGE(cvImg);
-  }
-}
-
-void MEImage::Clear()
-{
-  cvSetZero(ME_CAST_TO_IPLIMAGE(cvImg));
-}
-
-void MEImage::GetLayer(MEImage& new_layer, int layer_number) const
-{
-  int LayerNumber = layer_number;
+    namespace lbp_mrf
+    {
+      // RGB to YUV transform
+      const float RGBtoYUVMatrix[3][3] =
+      { { 0.299, 0.587, 0.114 },
+       { -0.147, -0.289, 0.436 },
+       { 0.615, -0.515, -0.100 } };
+
+      // RGB to YIQ transform
+      const float RGBtoYIQMatrix[3][3] =
+      { { 0.299, 0.587, 0.114 },
+       { 0.596, -0.274, -0.322 },
+       { 0.212, -0.523, 0.311 } };
+
+      MEImage::MEImage(int width, int height, int layers) : cvImg(NULL)
+      {
+        _Init(width, height, layers);
+      }
 
-  if ((new_layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width) ||
-    (new_layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) ||
-    (new_layer.GetLayers() != 1))
-  {
-    new_layer.Realloc(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height, 1);
-  }
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber)
-  {
-    printf("The given layer number is too large (%d > %d)\n",
-      LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      MEImage::MEImage(const MEImage& other) : cvImg(NULL)
+      {
+        _Copy(other);
+      }
 
-    LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
-  }
-  if (LayerNumber <= 0)
-  {
-    printf("The given layer number is too small (%d <= 0)\n", LayerNumber);
-    LayerNumber = 1;
-  }
+      MEImage::~MEImage()
+      {
+        if (ME_CAST_TO_IPLIMAGE(cvImg))
+        {
+          ME_RELEASE_IPLIMAGE(cvImg);
+        }
+      }
 
-  cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber);
-  cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), (IplImage*)new_layer.GetIplImage(), NULL);
-  cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0);
-}
+      void MEImage::Clear()
+      {
+        cvSetZero(ME_CAST_TO_IPLIMAGE(cvImg));
+      }
 
-void MEImage::SetLayer(MEImage& layer, int layer_number)
-{
-  int LayerNumber = layer_number;
+      void MEImage::GetLayer(MEImage& new_layer, int layer_number) const
+      {
+        int LayerNumber = layer_number;
 
-  if (layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
-    layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height)
-  {
-    printf("The dimensions of the layer and "
-      "destination image is different (%dx%d <> %dx%d)\n",
-      layer.GetWidth(), layer.GetHeight(), ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height);
-    return;
-  }
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber)
-  {
-    printf("The given layer number is too large (%d > %d)\n",
-      LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
-  }
-  if (LayerNumber <= 0)
-  {
-    printf("The given layer number is too small (%d <= 0)\n", LayerNumber);
-    LayerNumber = 1;
-  }
-  if (layer.GetLayers() != 1)
-  {
-    printf("The layer image has not one color channel (1 != %d)\n",
-      layer.GetLayers());
-    return;
-  }
-  cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber);
-  cvCopy((IplImage*)layer.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg), NULL);
-  cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0);
-}
+        if ((new_layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width) ||
+          (new_layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) ||
+          (new_layer.GetLayers() != 1))
+        {
+          new_layer.Realloc(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height, 1);
+        }
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber)
+        {
+          printf("The given layer number is too large (%d > %d)\n",
+            LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
 
-void MEImage::CopyImageData(unsigned char* data)
-{
-  memcpy(ME_CAST_TO_IPLIMAGE(cvImg)->imageData, data, ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-}
+          LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
+        }
+        if (LayerNumber <= 0)
+        {
+          printf("The given layer number is too small (%d <= 0)\n", LayerNumber);
+          LayerNumber = 1;
+        }
 
-void* MEImage::GetIplImage() const
-{
-  return (void*)ME_CAST_TO_IPLIMAGE(cvImg);
-}
+        cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber);
+        cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), (IplImage*)new_layer.GetIplImage(), NULL);
+        cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0);
+      }
 
-void MEImage::SetIplImage(void* image)
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg))
-  {
-    ME_RELEASE_IPLIMAGE(cvImg);
-  }
-  cvImg = cvCloneImage((IplImage*)image);
-  // Correct the origin of the image
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->origin == 1)
-  {
-    MirrorVertical();
-    ME_CAST_TO_IPLIMAGE(cvImg)->origin = 0;
-  }
-}
+      void MEImage::SetLayer(MEImage& layer, int layer_number)
+      {
+        int LayerNumber = layer_number;
 
-bool MEImage::operator==(const MEImage& image)
-{
-  return Equal(image);
-}
+        if (layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+          layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height)
+        {
+          printf("The dimensions of the layer and "
+            "destination image is different (%dx%d <> %dx%d)\n",
+            layer.GetWidth(), layer.GetHeight(), ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height);
+          return;
+        }
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber)
+        {
+          printf("The given layer number is too large (%d > %d)\n",
+            LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
+        }
+        if (LayerNumber <= 0)
+        {
+          printf("The given layer number is too small (%d <= 0)\n", LayerNumber);
+          LayerNumber = 1;
+        }
+        if (layer.GetLayers() != 1)
+        {
+          printf("The layer image has not one color channel (1 != %d)\n",
+            layer.GetLayers());
+          return;
+        }
+        cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber);
+        cvCopy((IplImage*)layer.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg), NULL);
+        cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0);
+      }
 
-bool MEImage::operator!=(const MEImage& image)
-{
-  return !operator==(image);
-}
+      void MEImage::CopyImageData(unsigned char* data)
+      {
+        memcpy(ME_CAST_TO_IPLIMAGE(cvImg)->imageData, data, ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      }
 
-MEImage& MEImage::operator=(const MEImage& other_image)
-{
-  if (&other_image == this)
-    return *this;
+      void* MEImage::GetIplImage() const
+      {
+        return (void*)ME_CAST_TO_IPLIMAGE(cvImg);
+      }
 
-  _Copy(other_image);
-  return *this;
-}
+      void MEImage::SetIplImage(void* image)
+      {
+        if (ME_CAST_TO_IPLIMAGE(cvImg))
+        {
+          ME_RELEASE_IPLIMAGE(cvImg);
+        }
+        cvImg = cvCloneImage((IplImage*)image);
+        // Correct the origin of the image
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->origin == 1)
+        {
+          MirrorVertical();
+          ME_CAST_TO_IPLIMAGE(cvImg)->origin = 0;
+        }
+      }
 
-int MEImage::GetWidth() const
-{
-  return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : 0;
-}
+      bool MEImage::operator==(const MEImage& image)
+      {
+        return Equal(image);
+      }
 
-int MEImage::GetRowWidth() const
-{
-  return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->widthStep : 0;
-}
+      bool MEImage::operator!=(const MEImage& image)
+      {
+        return !operator==(image);
+      }
 
-int MEImage::GetHeight() const
-{
-  return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : 0;
-}
+      MEImage& MEImage::operator=(const MEImage& other_image)
+      {
+        if (&other_image == this)
+          return *this;
 
-int MEImage::GetLayers() const
-{
-  return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->nChannels : 0;
-}
+        _Copy(other_image);
+        return *this;
+      }
 
-int MEImage::GetPixelDataNumber() const
-{
-  return ME_CAST_TO_IPLIMAGE(cvImg) ? GetWidth()*GetHeight()*GetLayers() : 0;
-}
+      int MEImage::GetWidth() const
+      {
+        return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : 0;
+      }
 
-unsigned char* MEImage::GetImageData() const
-{
-  return ME_CAST_TO_IPLIMAGE(cvImg) ? (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData : NULL;
-}
+      int MEImage::GetRowWidth() const
+      {
+        return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->widthStep : 0;
+      }
 
-void MEImage::SetData(unsigned char* image_data, int width, int height, int channels)
-{
-  _Init(width, height, channels);
+      int MEImage::GetHeight() const
+      {
+        return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : 0;
+      }
 
-  for (int y = height - 1; y >= 0; --y)
-  {
-    int Start = GetRowWidth()*y;
-    int Start2 = width*channels*y;
+      int MEImage::GetLayers() const
+      {
+        return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->nChannels : 0;
+      }
 
-    memcpy(&ME_CAST_TO_IPLIMAGE(cvImg)->imageData[Start], &image_data[Start2], width*channels);
-  }
-}
+      int MEImage::GetPixelDataNumber() const
+      {
+        return ME_CAST_TO_IPLIMAGE(cvImg) ? GetWidth()*GetHeight()*GetLayers() : 0;
+      }
 
-float MEImage::GetRatio() const
-{
-  return ME_CAST_TO_IPLIMAGE(cvImg) ? (float)ME_CAST_TO_IPLIMAGE(cvImg)->height / (float)ME_CAST_TO_IPLIMAGE(cvImg)->width : 0.0;
-}
+      unsigned char* MEImage::GetImageData() const
+      {
+        return ME_CAST_TO_IPLIMAGE(cvImg) ? (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData : NULL;
+      }
 
-void MEImage::Realloc(int width, int height)
-{
-  Realloc(width, height, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-}
+      void MEImage::SetData(unsigned char* image_data, int width, int height, int channels)
+      {
+        _Init(width, height, channels);
 
-void MEImage::Realloc(int width, int height, int layers)
-{
-  _Init(width, height, layers);
-}
+        for (int y = height - 1; y >= 0; --y)
+        {
+          int Start = GetRowWidth()*y;
+          int Start2 = width*channels*y;
 
-void MEImage::Resize(int new_width, int new_height)
-{
-  if (new_height < 1)
-  {
-    printf("Invalid new height: %d < 1\n", new_height);
-    return;
-  }
-  if (new_width < 1)
-  {
-    printf("Invalid new width: %d < 1\n", new_width);
-    return;
-  }
-  IplImage* TempImg = cvCreateImage(cvSize(new_width, new_height), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          memcpy(&ME_CAST_TO_IPLIMAGE(cvImg)->imageData[Start], &image_data[Start2], width*channels);
+        }
+      }
 
-  cvResize(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_INTER_NN);
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
+      float MEImage::GetRatio() const
+      {
+        return ME_CAST_TO_IPLIMAGE(cvImg) ? (float)ME_CAST_TO_IPLIMAGE(cvImg)->height / (float)ME_CAST_TO_IPLIMAGE(cvImg)->width : 0.0;
+      }
 
+      void MEImage::Realloc(int width, int height)
+      {
+        Realloc(width, height, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      }
 
-void MEImage::ResizeScaleX(int new_width)
-{
-  if (new_width < 1)
-  {
-    printf("Invalid new width: %d < 1\n", new_width);
-    return;
-  }
-  Resize(new_width, (int)((float)new_width*GetRatio()));
-}
+      void MEImage::Realloc(int width, int height, int layers)
+      {
+        _Init(width, height, layers);
+      }
 
-void MEImage::ResizeScaleY(int new_height)
-{
-  if (new_height < 1)
-  {
-    printf("Invalid new height: %d < 1\n", new_height);
-    return;
-  }
-  Resize((int)((float)new_height * 1 / GetRatio()), new_height);
-}
+      void MEImage::Resize(int new_width, int new_height)
+      {
+        if (new_height < 1)
+        {
+          printf("Invalid new height: %d < 1\n", new_height);
+          return;
+        }
+        if (new_width < 1)
+        {
+          printf("Invalid new width: %d < 1\n", new_width);
+          return;
+        }
+        IplImage* TempImg = cvCreateImage(cvSize(new_width, new_height), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
 
-void MEImage::MirrorHorizontal()
-{
-  cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 1);
-}
+        cvResize(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_INTER_NN);
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
 
-void MEImage::MirrorVertical()
-{
-  cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 0);
-}
 
-void MEImage::Crop(int x1, int y1, int x2, int y2)
-{
-  int NewX1 = x1;
-  int NewY1 = y1;
-  int NewX2 = x2;
-  int NewY2 = y2;
-
-  NewX1 = (NewX1 < 0) ? 0 : NewX1;
-  NewX1 = (NewX1 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX1;
-  NewY1 = (NewY1 < 0) ? 0 : NewY1;
-  NewY1 = (NewY1 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY1;
-
-  NewX2 = (NewX2 < 0) ? 0 : NewX2;
-  NewX2 = (NewX2 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX2;
-  NewY2 = (NewY2 < 0) ? 0 : NewY2;
-  NewY2 = (NewY2 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY2;
-
-  if ((NewX2 - NewX1) <= 0)
-  {
-    printf("Invalid new width: %d <= 0\n", NewX2 - NewX1);
-    return;
-  }
-  if ((NewY2 - NewY1) <= 0)
-  {
-    printf("Invalid new height: %d <= 0\n", NewY2 - NewY1);
-    return;
-  }
-  IplImage* TempImg = cvCreateImage(cvSize(NewX2 - NewX1, NewY2 - NewY1), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      void MEImage::ResizeScaleX(int new_width)
+      {
+        if (new_width < 1)
+        {
+          printf("Invalid new width: %d < 1\n", new_width);
+          return;
+        }
+        Resize(new_width, (int)((float)new_width*GetRatio()));
+      }
 
-  cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX1, NewY1, NewX2 - NewX1, NewY2 - NewY1));
-  cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), TempImg);
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
+      void MEImage::ResizeScaleY(int new_height)
+      {
+        if (new_height < 1)
+        {
+          printf("Invalid new height: %d < 1\n", new_height);
+          return;
+        }
+        Resize((int)((float)new_height * 1 / GetRatio()), new_height);
+      }
 
-void MEImage::CopyImageInside(int x, int y, MEImage& source_image)
-{
-  int NewX = x;
-  int NewY = y;
-  int PasteLengthX = source_image.GetWidth();
-  int PasteLengthY = source_image.GetHeight();
+      void MEImage::MirrorHorizontal()
+      {
+        cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 1);
+      }
 
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != source_image.GetLayers())
-  {
-    if (source_image.GetLayers() == 1 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3)
-    {
-      source_image.ConvertGrayscaleToRGB();
-    }
-    if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1 && source_image.GetLayers() == 3)
-    {
-      source_image.ConvertToGrayscale(g_OpenCV);
-    }
-  }
-  if (NewX < 0)
-    NewX = 0;
-  if (NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width)
-    NewX = ME_CAST_TO_IPLIMAGE(cvImg)->width;
-  if (NewY < 0)
-    NewY = 0;
-  if (NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height)
-    NewY = ME_CAST_TO_IPLIMAGE(cvImg)->height;
-  if (NewX + PasteLengthX > ME_CAST_TO_IPLIMAGE(cvImg)->width)
-    PasteLengthX = ME_CAST_TO_IPLIMAGE(cvImg)->width - NewX;
-  if (NewY + PasteLengthY > ME_CAST_TO_IPLIMAGE(cvImg)->height)
-    PasteLengthY = ME_CAST_TO_IPLIMAGE(cvImg)->height - NewY;
-
-  if (PasteLengthX != source_image.GetWidth() ||
-    PasteLengthY != source_image.GetHeight())
-  {
-    source_image.Resize(PasteLengthX, PasteLengthY);
-  }
-  cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX, NewY, PasteLengthX, PasteLengthY));
-  cvCopy((IplImage*)source_image.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg));
-  cvResetImageROI(ME_CAST_TO_IPLIMAGE(cvImg));
-}
+      void MEImage::MirrorVertical()
+      {
+        cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 0);
+      }
 
-void MEImage::Erode(int iterations)
-{
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
-    ME_CAST_TO_IPLIMAGE(cvImg)->height),
-    8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      void MEImage::Crop(int x1, int y1, int x2, int y2)
+      {
+        int NewX1 = x1;
+        int NewY1 = y1;
+        int NewX2 = x2;
+        int NewY2 = y2;
+
+        NewX1 = (NewX1 < 0) ? 0 : NewX1;
+        NewX1 = (NewX1 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX1;
+        NewY1 = (NewY1 < 0) ? 0 : NewY1;
+        NewY1 = (NewY1 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY1;
+
+        NewX2 = (NewX2 < 0) ? 0 : NewX2;
+        NewX2 = (NewX2 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX2;
+        NewY2 = (NewY2 < 0) ? 0 : NewY2;
+        NewY2 = (NewY2 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY2;
+
+        if ((NewX2 - NewX1) <= 0)
+        {
+          printf("Invalid new width: %d <= 0\n", NewX2 - NewX1);
+          return;
+        }
+        if ((NewY2 - NewY1) <= 0)
+        {
+          printf("Invalid new height: %d <= 0\n", NewY2 - NewY1);
+          return;
+        }
+        IplImage* TempImg = cvCreateImage(cvSize(NewX2 - NewX1, NewY2 - NewY1), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
 
-  cvErode(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations);
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
+        cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX1, NewY1, NewX2 - NewX1, NewY2 - NewY1));
+        cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), TempImg);
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
 
-void MEImage::Dilate(int iterations)
-{
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
-    ME_CAST_TO_IPLIMAGE(cvImg)->height),
-    8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      void MEImage::CopyImageInside(int x, int y, MEImage& source_image)
+      {
+        int NewX = x;
+        int NewY = y;
+        int PasteLengthX = source_image.GetWidth();
+        int PasteLengthY = source_image.GetHeight();
 
-  cvDilate(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations);
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != source_image.GetLayers())
+        {
+          if (source_image.GetLayers() == 1 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3)
+          {
+            source_image.ConvertGrayscaleToRGB();
+          }
+          if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1 && source_image.GetLayers() == 3)
+          {
+            source_image.ConvertToGrayscale(g_OpenCV);
+          }
+        }
+        if (NewX < 0)
+          NewX = 0;
+        if (NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width)
+          NewX = ME_CAST_TO_IPLIMAGE(cvImg)->width;
+        if (NewY < 0)
+          NewY = 0;
+        if (NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height)
+          NewY = ME_CAST_TO_IPLIMAGE(cvImg)->height;
+        if (NewX + PasteLengthX > ME_CAST_TO_IPLIMAGE(cvImg)->width)
+          PasteLengthX = ME_CAST_TO_IPLIMAGE(cvImg)->width - NewX;
+        if (NewY + PasteLengthY > ME_CAST_TO_IPLIMAGE(cvImg)->height)
+          PasteLengthY = ME_CAST_TO_IPLIMAGE(cvImg)->height - NewY;
+
+        if (PasteLengthX != source_image.GetWidth() ||
+          PasteLengthY != source_image.GetHeight())
+        {
+          source_image.Resize(PasteLengthX, PasteLengthY);
+        }
+        cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX, NewY, PasteLengthX, PasteLengthY));
+        cvCopy((IplImage*)source_image.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg));
+        cvResetImageROI(ME_CAST_TO_IPLIMAGE(cvImg));
+      }
 
-void MEImage::Smooth()
-{
-  SmoothAdvanced(s_Median, 3);
-}
+      void MEImage::Erode(int iterations)
+      {
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+          ME_CAST_TO_IPLIMAGE(cvImg)->height),
+          8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
 
-void MEImage::SmoothAdvanced(SmoothType filtermode, int filtersize)
-{
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+        cvErode(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations);
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
 
-  switch (filtermode)
-  {
-  case s_Blur:
-    cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_BLUR, filtersize, filtersize, 0);
-    break;
-  case s_Median:
-    cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0);
-    break;
-  case s_Gaussian:
-    cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GAUSSIAN, filtersize, filtersize, 0);
-    break;
-  default:
-    cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0);
-    break;
-  }
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
+      void MEImage::Dilate(int iterations)
+      {
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+          ME_CAST_TO_IPLIMAGE(cvImg)->height),
+          8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
 
-void MEImage::Canny()
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
-  {
-    ConvertToGrayscale(g_OpenCV);
-  }
+        cvDilate(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations);
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
 
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-  cvCanny(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 800, 1100, 5);
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
+      void MEImage::Smooth()
+      {
+        SmoothAdvanced(s_Median, 3);
+      }
 
-void MEImage::Laplace()
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1)
-  {
-    ConvertToGrayscale(g_OpenCV);
-  }
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
-    ME_CAST_TO_IPLIMAGE(cvImg)->height),
-    IPL_DEPTH_16S, 1);
-  cvLaplace(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 3);
-  cvConvertScale(TempImg, ME_CAST_TO_IPLIMAGE(cvImg), 1, 0);
-  ME_RELEASE_IPLIMAGE(cvImg);
-}
+      void MEImage::SmoothAdvanced(SmoothType filtermode, int filtersize)
+      {
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+          ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
 
-void MEImage::Quantize(int levels)
-{
-  if (levels <= 0)
-  {
-    printf("Level number is too small (%d <= 0)\n", levels);
-    return;
-  }
-  if (levels > 256)
-  {
-    printf("Level number is too large (%d > 256)\n", levels);
-    return;
-  }
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        switch (filtermode)
+        {
+        case s_Blur:
+          cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_BLUR, filtersize, filtersize, 0);
+          break;
+        case s_Median:
+          cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0);
+          break;
+        case s_Gaussian:
+          cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GAUSSIAN, filtersize, filtersize, 0);
+          break;
+        default:
+          cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0);
+          break;
+        }
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
 
-  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i)
-  {
-    ImageData[i] = ImageData[i] / (256 / levels)*(256 / levels);
-  }
-}
+      void MEImage::Canny()
+      {
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
+        {
+          ConvertToGrayscale(g_OpenCV);
+        }
 
-void MEImage::Threshold(int threshold_limit)
-{
-  if (threshold_limit < 0)
-  {
-    printf("Threshold number is too small (%d <= 0)\n", threshold_limit);
-    return;
-  }
-  if (threshold_limit > 255)
-  {
-    printf("Threshold number is too large (%d > 255)\n", threshold_limit);
-    return;
-  }
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+          ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+        cvCanny(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 800, 1100, 5);
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
 
-  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i)
-  {
-    if (ImageData[i] < threshold_limit)
-    {
-      ImageData[i] = 0;
-    }
-  }
-}
+      void MEImage::Laplace()
+      {
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1)
+        {
+          ConvertToGrayscale(g_OpenCV);
+        }
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+          ME_CAST_TO_IPLIMAGE(cvImg)->height),
+          IPL_DEPTH_16S, 1);
+        cvLaplace(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 3);
+        cvConvertScale(TempImg, ME_CAST_TO_IPLIMAGE(cvImg), 1, 0);
+        ME_RELEASE_IPLIMAGE(cvImg);
+      }
 
-void MEImage::AdaptiveThreshold()
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1)
-  {
-    ConvertToGrayscale(g_OpenCV);
-  }
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-  cvAdaptiveThreshold(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 25,
-    CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, -7);
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
+      void MEImage::Quantize(int levels)
+      {
+        if (levels <= 0)
+        {
+          printf("Level number is too small (%d <= 0)\n", levels);
+          return;
+        }
+        if (levels > 256)
+        {
+          printf("Level number is too large (%d > 256)\n", levels);
+          return;
+        }
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
 
-void MEImage::ThresholdByMask(MEImage& mask_image)
-{
-  if (mask_image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
-    mask_image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height)
-  {
-    printf("Image properties are different\n");
-    return;
-  }
-  if (mask_image.GetLayers() != 3 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3)
-  {
-    mask_image.ConvertGrayscaleToRGB();
-  }
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  unsigned char* MaskImageData = mask_image.GetImageData();
+        for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i)
+        {
+          ImageData[i] = ImageData[i] / (256 / levels)*(256 / levels);
+        }
+      }
 
-  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i)
-  {
-    if (MaskImageData[i] == 0)
-    {
-      ImageData[i] = 0;
-    }
-  }
-}
+      void MEImage::Threshold(int threshold_limit)
+      {
+        if (threshold_limit < 0)
+        {
+          printf("Threshold number is too small (%d <= 0)\n", threshold_limit);
+          return;
+        }
+        if (threshold_limit > 255)
+        {
+          printf("Threshold number is too large (%d > 255)\n", threshold_limit);
+          return;
+        }
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
 
-void MEImage::ColorSpace(ColorSpaceConvertType mode)
-{
-  IplImage* TempImg = NULL;
-  unsigned char* ImageData = NULL;
-  int WidthStep = 0;
-  int RowStart = 0;
+        for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i)
+        {
+          if (ImageData[i] < threshold_limit)
+          {
+            ImageData[i] = 0;
+          }
+        }
+      }
 
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1)
-  {
-    printf("No sense to convert: source image is greyscale\n");
-    ConvertGrayscaleToRGB();
-  }
-  switch (mode)
-  {
-  case csc_RGBtoXYZCIED65:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
-      ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2XYZ);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_XYZCIED65toRGB:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
-      ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_XYZ2RGB);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_RGBtoHSV:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
-      ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HSV);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_HSVtoRGB:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
-      ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HSV2RGB);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_RGBtoHLS:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HLS);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_HLStoRGB:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HLS2RGB);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_RGBtoCIELab:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Lab);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_CIELabtoRGB:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Lab2RGB);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_RGBtoCIELuv:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Luv);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_CIELuvtoRGB:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Luv2RGB);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case csc_RGBtoYUV:
-    ComputeColorSpace(csc_RGBtoYUV);
-    break;
-
-  case csc_RGBtoYIQ:
-    ComputeColorSpace(csc_RGBtoYIQ);
-    break;
-
-  case csc_RGBtorgI:
-    ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-    WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
-    RowStart = 0;
-    for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-    {
-      for (int x = (ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) * 3; x >= 0; x -= 3)
+      void MEImage::AdaptiveThreshold()
       {
-        int r = 0;
-        int g = 0;
-        int I = 0;
-
-        I = (int)ImageData[RowStart + x] + (int)ImageData[RowStart + x + 1] + (int)ImageData[RowStart + x + 2];
-        r = (int)((float)ImageData[RowStart + x] / I * 255);
-        g = (int)((float)ImageData[RowStart + x + 1] / I * 255);
-        ImageData[RowStart + x] = (unsigned char)r;
-        ImageData[RowStart + x + 1] = (unsigned char)g;
-        ImageData[RowStart + x + 2] = (unsigned char)(I / 3);
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1)
+        {
+          ConvertToGrayscale(g_OpenCV);
+        }
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+          ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+        cvAdaptiveThreshold(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 25,
+          CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, -7);
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
       }
-      RowStart += WidthStep;
-    }
-    break;
 
-  default:
-    break;
-  }
-}
+      void MEImage::ThresholdByMask(MEImage& mask_image)
+      {
+        if (mask_image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+          mask_image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height)
+        {
+          printf("Image properties are different\n");
+          return;
+        }
+        if (mask_image.GetLayers() != 3 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3)
+        {
+          mask_image.ConvertGrayscaleToRGB();
+        }
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        unsigned char* MaskImageData = mask_image.GetImageData();
 
-void MEImage::ConvertToGrayscale(GrayscaleType grayscale_mode)
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1)
-  {
-    printf("Image is already grayscale\n");
-    return;
-  }
-  IplImage* TempImg = NULL;
-  unsigned char* ImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  unsigned char* ImageData = NULL;
+        for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i)
+        {
+          if (MaskImageData[i] == 0)
+          {
+            ImageData[i] = 0;
+          }
+        }
+      }
 
-  switch (grayscale_mode)
-  {
-  case g_Average:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1);
-    ImageData = (unsigned char*)TempImg->imageData;
+      void MEImage::ColorSpace(ColorSpaceConvertType mode)
+      {
+        IplImage* TempImg = NULL;
+        unsigned char* ImageData = NULL;
+        int WidthStep = 0;
+        int RowStart = 0;
 
-    for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 3; i >= 0; i -= 3)
-    {
-      ImageData[i / 3] = (ImgData[i] + ImgData[i + 1] + ImgData[i + 2]) / 3;
-    }
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  case g_OpenCV:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1);
-    cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2GRAY);
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
-
-  default:
-    break;
-  }
-}
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1)
+        {
+          printf("No sense to convert: source image is greyscale\n");
+          ConvertGrayscaleToRGB();
+        }
+        switch (mode)
+        {
+        case csc_RGBtoXYZCIED65:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+            ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2XYZ);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_XYZCIED65toRGB:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+            ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_XYZ2RGB);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_RGBtoHSV:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+            ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HSV);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_HSVtoRGB:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+            ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HSV2RGB);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_RGBtoHLS:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HLS);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_HLStoRGB:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HLS2RGB);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_RGBtoCIELab:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Lab);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_CIELabtoRGB:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Lab2RGB);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_RGBtoCIELuv:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Luv);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_CIELuvtoRGB:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Luv2RGB);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case csc_RGBtoYUV:
+          ComputeColorSpace(csc_RGBtoYUV);
+          break;
+
+        case csc_RGBtoYIQ:
+          ComputeColorSpace(csc_RGBtoYIQ);
+          break;
+
+        case csc_RGBtorgI:
+          ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+          WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+          RowStart = 0;
+          for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+          {
+            for (int x = (ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) * 3; x >= 0; x -= 3)
+            {
+              int r = 0;
+              int g = 0;
+              int I = 0;
+
+              I = (int)ImageData[RowStart + x] + (int)ImageData[RowStart + x + 1] + (int)ImageData[RowStart + x + 2];
+              r = (int)((float)ImageData[RowStart + x] / I * 255);
+              g = (int)((float)ImageData[RowStart + x + 1] / I * 255);
+              ImageData[RowStart + x] = (unsigned char)r;
+              ImageData[RowStart + x + 1] = (unsigned char)g;
+              ImageData[RowStart + x + 2] = (unsigned char)(I / 3);
+            }
+            RowStart += WidthStep;
+          }
+          break;
 
-void MEImage::ConvertGrayscaleToRGB()
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1)
-  {
-    return;
-  }
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 3);
+        default:
+          break;
+        }
+      }
 
-  cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GRAY2RGB);
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
+      void MEImage::ConvertToGrayscale(GrayscaleType grayscale_mode)
+      {
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1)
+        {
+          printf("Image is already grayscale\n");
+          return;
+        }
+        IplImage* TempImg = NULL;
+        unsigned char* ImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        unsigned char* ImageData = NULL;
 
-void MEImage::ConvertBGRToRGB()
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3)
-  {
-    return;
-  }
-  cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), ME_CAST_TO_IPLIMAGE(cvImg), CV_RGB2BGR);
-}
+        switch (grayscale_mode)
+        {
+        case g_Average:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1);
+          ImageData = (unsigned char*)TempImg->imageData;
 
-void MEImage::LBP(LBPType mode)
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
-  {
-    ConvertToGrayscale(g_OpenCV);
-  }
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1);
-  unsigned char* TempImgData = (unsigned char*)TempImg->imageData;
-  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
-  int WidthStep_2 = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2;
-
-  cvSetZero(TempImg);
-  switch (mode)
-  {
-  case lbp_Normal:
-    for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 2) - 1; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1; --i)
-    {
-      TempImgData[i] =
-        (ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) +
-        ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 2) +
-        ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 4) +
-        ((ImageData[i] <= ImageData[i - 1]) * 8) +
-        ((ImageData[i] <= ImageData[i + 1]) * 16) +
-        ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) * 32) +
-        ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 64) +
-        ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 128);
-    }
-    break;
+          for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 3; i >= 0; i -= 3)
+          {
+            ImageData[i / 3] = (ImgData[i] + ImgData[i + 1] + ImgData[i + 2]) / 3;
+          }
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        case g_OpenCV:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1);
+          cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2GRAY);
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        default:
+          break;
+        }
+      }
 
-  case lbp_Special:
-    for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 3) - 2; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2 + 2; --i)
-    {
-      int CenterPixel = (ImageData[i + 1] + ImageData[i - 1] +
-        ImageData[i - WidthStep] + ImageData[i + WidthStep]) / 4;
-      TempImgData[i] = ((CenterPixel <= (ImageData[i - (WidthStep_2)-2] +
-        ImageData[i - (WidthStep_2)-1] +
-        ImageData[i - WidthStep - 2] +
-        ImageData[i - WidthStep - 1]) / 4)) +
-        ((CenterPixel <= (ImageData[i - WidthStep] +
-          ImageData[i - (WidthStep_2)]) / 2) * 2) +
-          ((CenterPixel <= ((ImageData[i - (WidthStep_2)+2] +
-            ImageData[i - (WidthStep_2)+1] +
-            ImageData[i - WidthStep + 2] +
-            ImageData[i - WidthStep + 1]) / 4)) * 4) +
-            ((CenterPixel <= (ImageData[i - 1] +
-              ImageData[i - 2]) / 2) * 8) +
-              ((CenterPixel <= (ImageData[i + 1] +
-                ImageData[i + 2]) / 2) * 16) +
-                ((CenterPixel <= ((ImageData[i + (WidthStep_2)-2] +
-                  ImageData[i + (WidthStep_2)-1] +
-                  ImageData[i + WidthStep - 2] +
-                  ImageData[i + WidthStep - 1]) / 4)) * 32) +
-                  ((CenterPixel <= (ImageData[i + WidthStep] +
-                    ImageData[i - WidthStep_2]) / 2) * 64) +
-                    ((CenterPixel <= ((ImageData[i + (WidthStep_2)+2] +
-                      ImageData[i + (WidthStep_2)+1] +
-                      ImageData[i + WidthStep + 2] +
-                      ImageData[i + WidthStep + 1]) / 4)) * 128);
-    }
-    break;
+      void MEImage::ConvertGrayscaleToRGB()
+      {
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1)
+        {
+          return;
+        }
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 3);
 
-  default:
-    break;
-  }
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
+        cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GRAY2RGB);
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
 
-void MEImage::Binarize(int threshold)
-{
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+      void MEImage::ConvertBGRToRGB()
+      {
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3)
+        {
+          return;
+        }
+        cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), ME_CAST_TO_IPLIMAGE(cvImg), CV_RGB2BGR);
+      }
 
-  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i)
-  {
-    if (ImageData[i] >= threshold)
-    {
-      ImageData[i] = 255;
-    }
-    else {
-      ImageData[i] = 0;
-    }
-  }
-}
+      void MEImage::LBP(LBPType mode)
+      {
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
+        {
+          ConvertToGrayscale(g_OpenCV);
+        }
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1);
+        unsigned char* TempImgData = (unsigned char*)TempImg->imageData;
+        int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+        int WidthStep_2 = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2;
+
+        cvSetZero(TempImg);
+        switch (mode)
+        {
+        case lbp_Normal:
+          for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 2) - 1; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1; --i)
+          {
+            TempImgData[i] =
+              (ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) +
+              ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 2) +
+              ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 4) +
+              ((ImageData[i] <= ImageData[i - 1]) * 8) +
+              ((ImageData[i] <= ImageData[i + 1]) * 16) +
+              ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) * 32) +
+              ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 64) +
+              ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 128);
+          }
+          break;
 
-void MEImage::Subtract(MEImage& source, SubtractModeType mode)
-{
-  if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
-    source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
-    source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
-  {
-    printf("Image properties are different.\n");
-    return;
-  }
-  unsigned char* ImageData = NULL;
-  unsigned char* DstData = NULL;
-  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
-  int RowStart = 0;
+        case lbp_Special:
+          for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 3) - 2; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2 + 2; --i)
+          {
+            int CenterPixel = (ImageData[i + 1] + ImageData[i - 1] +
+              ImageData[i - WidthStep] + ImageData[i + WidthStep]) / 4;
+            TempImgData[i] = ((CenterPixel <= (ImageData[i - (WidthStep_2)-2] +
+              ImageData[i - (WidthStep_2)-1] +
+              ImageData[i - WidthStep - 2] +
+              ImageData[i - WidthStep - 1]) / 4)) +
+              ((CenterPixel <= (ImageData[i - WidthStep] +
+                ImageData[i - (WidthStep_2)]) / 2) * 2) +
+                ((CenterPixel <= ((ImageData[i - (WidthStep_2)+2] +
+                  ImageData[i - (WidthStep_2)+1] +
+                  ImageData[i - WidthStep + 2] +
+                  ImageData[i - WidthStep + 1]) / 4)) * 4) +
+                  ((CenterPixel <= (ImageData[i - 1] +
+                    ImageData[i - 2]) / 2) * 8) +
+                    ((CenterPixel <= (ImageData[i + 1] +
+                      ImageData[i + 2]) / 2) * 16) +
+                      ((CenterPixel <= ((ImageData[i + (WidthStep_2)-2] +
+                        ImageData[i + (WidthStep_2)-1] +
+                        ImageData[i + WidthStep - 2] +
+                        ImageData[i + WidthStep - 1]) / 4)) * 32) +
+                        ((CenterPixel <= (ImageData[i + WidthStep] +
+                          ImageData[i - WidthStep_2]) / 2) * 64) +
+                          ((CenterPixel <= ((ImageData[i + (WidthStep_2)+2] +
+                            ImageData[i + (WidthStep_2)+1] +
+                            ImageData[i + WidthStep + 2] +
+                            ImageData[i + WidthStep + 1]) / 4)) * 128);
+          }
+          break;
 
-  switch (mode)
-  {
-  case sub_Normal:
-    ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-    DstData = source.GetImageData();
-    RowStart = 0;
+        default:
+          break;
+        }
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
 
-    for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-    {
-      for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
+      void MEImage::Binarize(int threshold)
       {
-        ImageData[RowStart + x] =
-          ImageData[RowStart + x] - DstData[RowStart + x] < 0 ? 0 :
-          ImageData[RowStart + x] - DstData[RowStart + x];
-      }
-      RowStart += WidthStep;
-    }
-    break;
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
 
-  case sub_Absolut:
-    ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-    DstData = source.GetImageData();
-    RowStart = 0;
+        for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i)
+        {
+          if (ImageData[i] >= threshold)
+          {
+            ImageData[i] = 255;
+          }
+          else {
+            ImageData[i] = 0;
+          }
+        }
+      }
 
-    for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-    {
-      for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
+      void MEImage::Subtract(MEImage& source, SubtractModeType mode)
       {
-        ImageData[RowStart + x] = ImageData[RowStart + x] -
-          DstData[RowStart + x] < 0 ? -ImageData[RowStart + x] +
-          DstData[RowStart + x] : ImageData[RowStart + x] - DstData[RowStart + x];
-      }
-      RowStart += WidthStep;
-    }
-    break;
+        if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+          source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+          source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+        {
+          printf("Image properties are different.\n");
+          return;
+        }
+        unsigned char* ImageData = NULL;
+        unsigned char* DstData = NULL;
+        int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+        int RowStart = 0;
 
-  default:
-    break;
-  }
-}
+        switch (mode)
+        {
+        case sub_Normal:
+          ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+          DstData = source.GetImageData();
+          RowStart = 0;
 
-void MEImage::Multiple(MEImage& source, MultiplicationType mode)
-{
-  if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
-    source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
-    source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
-  {
-    printf("Image properties are different.\n");
-    return;
-  }
-  float Result = 0.0;
-  IplImage* TempImg = NULL;
-  unsigned char* ImageData = NULL;
-  unsigned char* ImageData2 = NULL;
-  unsigned char* ImageData3 = NULL;
-  unsigned char* DstData = NULL;
-
-  switch (mode)
-  {
-  case m_Normal:
-    Result = 0;
-    ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-    DstData = source.GetImageData();
+          for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+          {
+            for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
+            {
+              ImageData[RowStart + x] =
+                ImageData[RowStart + x] - DstData[RowStart + x] < 0 ? 0 :
+                ImageData[RowStart + x] - DstData[RowStart + x];
+            }
+            RowStart += WidthStep;
+          }
+          break;
 
-    for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i)
-    {
-      if ((ImageData[i] >= 128) && (DstData[i] >= 128))
-      {
-        Result = (float)ImageData[i] / 128 * (float)DstData[i] / 128;
+        case sub_Absolut:
+          ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+          DstData = source.GetImageData();
+          RowStart = 0;
 
-        if (Result >= 1)
-        {
-          ImageData[i] = 255;
-        }
-        else {
-          ImageData[i] = 0;
+          for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+          {
+            for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
+            {
+              ImageData[RowStart + x] = ImageData[RowStart + x] -
+                DstData[RowStart + x] < 0 ? -ImageData[RowStart + x] +
+                DstData[RowStart + x] : ImageData[RowStart + x] - DstData[RowStart + x];
+            }
+            RowStart += WidthStep;
+          }
+          break;
+
+        default:
+          break;
         }
       }
-      else {
-        ImageData[i] = 0;
-      }
-    }
-    break;
-
-  case m_Neighbourhood:
-    TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-      ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    ImageData2 = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-    DstData = source.GetImageData();
-    ImageData3 = (unsigned char*)TempImg->imageData;
-
-    for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-      for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x)
-        for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l)
-        {
-          if (((DstData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels +
-            x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255) ||
-            (ImageData2[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels +
-              x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255)) &&
-              (NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3) &&
-            (source.NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3))
+
+      void MEImage::Multiple(MEImage& source, MultiplicationType mode)
+      {
+        if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+          source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+          source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+        {
+          printf("Image properties are different.\n");
+          return;
+        }
+        float Result = 0.0;
+        IplImage* TempImg = NULL;
+        unsigned char* ImageData = NULL;
+        unsigned char* ImageData2 = NULL;
+        unsigned char* ImageData3 = NULL;
+        unsigned char* DstData = NULL;
+
+        switch (mode)
+        {
+        case m_Normal:
+          Result = 0;
+          ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+          DstData = source.GetImageData();
+
+          for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i)
           {
-            ImageData3[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels +
-              x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] = 255;
+            if ((ImageData[i] >= 128) && (DstData[i] >= 128))
+            {
+              Result = (float)ImageData[i] / 128 * (float)DstData[i] / 128;
+
+              if (Result >= 1)
+              {
+                ImageData[i] = 255;
+              }
+              else {
+                ImageData[i] = 0;
+              }
+            }
+            else {
+              ImageData[i] = 0;
+            }
           }
+          break;
+
+        case m_Neighbourhood:
+          TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+            ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          ImageData2 = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+          DstData = source.GetImageData();
+          ImageData3 = (unsigned char*)TempImg->imageData;
+
+          for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+            for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x)
+              for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l)
+              {
+                if (((DstData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels +
+                  x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255) ||
+                  (ImageData2[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels +
+                    x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255)) &&
+                    (NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3) &&
+                  (source.NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3))
+                {
+                  ImageData3[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels +
+                    x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] = 255;
+                }
+              }
+          ME_RELEASE_IPLIMAGE(cvImg);
+          cvImg = TempImg;
+          break;
+
+        default:
+          break;
         }
-    ME_RELEASE_IPLIMAGE(cvImg);
-    cvImg = TempImg;
-    break;
+      }
 
-  default:
-    break;
-  }
-}
+      void MEImage::Addition(MEImage& source, AdditionType mode)
+      {
+        if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+          source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+          source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+        {
+          printf("Image properties are different.\n");
+          return;
+        }
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        unsigned char* DstData = source.GetImageData();
 
-void MEImage::Addition(MEImage& source, AdditionType mode)
-{
-  if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
-    source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
-    source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
-  {
-    printf("Image properties are different.\n");
-    return;
-  }
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  unsigned char* DstData = source.GetImageData();
+        switch (mode)
+        {
+        case a_Average:
+          for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i)
+          {
+            ImageData[i] = (ImageData[i] + DstData[i]) / 2;
+          }
+          break;
 
-  switch (mode)
-  {
-  case a_Average:
-    for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i)
-    {
-      ImageData[i] = (ImageData[i] + DstData[i]) / 2;
-    }
-    break;
+        case a_Union:
+          for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i)
+          {
+            if (DstData[i] > ImageData[i])
+            {
+              ImageData[i] = DstData[i];
+            }
+          }
+          break;
 
-  case a_Union:
-    for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i)
-    {
-      if (DstData[i] > ImageData[i])
-      {
-        ImageData[i] = DstData[i];
+        default:
+          break;
+        }
       }
-    }
-    break;
 
-  default:
-    break;
-  }
-}
-
-void MEImage::EliminateSinglePixels()
-{
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  unsigned char* DstData = (unsigned char*)TempImg->imageData;
-  int sum = 0;
-  int xy = 0;
-  int ywidth = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
-
-  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x)
-    {
-      xy = y*ywidth + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
-
-      for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l)
+      void MEImage::EliminateSinglePixels()
       {
-        if ((ImageData[xy + l] > 0) && (x > 0) && (y > 0) && (x < ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) && (y < ME_CAST_TO_IPLIMAGE(cvImg)->height - 1))
-        {
-          sum = (ImageData[xy - ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
-            (ImageData[xy - ywidth + l] > 0) +
-            (ImageData[xy - ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
-            (ImageData[xy - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
-            (ImageData[xy + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
-            (ImageData[xy + ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
-            (ImageData[xy + ywidth + l] > 0) +
-            (ImageData[xy + ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0);
-
-          if (sum > 3)
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+          ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        unsigned char* DstData = (unsigned char*)TempImg->imageData;
+        int sum = 0;
+        int xy = 0;
+        int ywidth = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+
+        for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+          for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x)
           {
-            DstData[xy + l] = 255;
-          }
-          else {
-            DstData[xy + l] = 0;
+            xy = y*ywidth + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
+
+            for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l)
+            {
+              if ((ImageData[xy + l] > 0) && (x > 0) && (y > 0) && (x < ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) && (y < ME_CAST_TO_IPLIMAGE(cvImg)->height - 1))
+              {
+                sum = (ImageData[xy - ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
+                  (ImageData[xy - ywidth + l] > 0) +
+                  (ImageData[xy - ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
+                  (ImageData[xy - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
+                  (ImageData[xy + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
+                  (ImageData[xy + ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) +
+                  (ImageData[xy + ywidth + l] > 0) +
+                  (ImageData[xy + ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0);
+
+                if (sum > 3)
+                {
+                  DstData[xy + l] = 255;
+                }
+                else {
+                  DstData[xy + l] = 0;
+                }
+              }
+              else {
+                DstData[xy + l] = 0;
+              }
+            }
           }
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
+
+      float MEImage::DifferenceAreas(MEImage& reference, int difference) const
+      {
+        if (reference.GetWidth() != GetWidth() ||
+          reference.GetHeight() != GetHeight() ||
+          reference.GetLayers() != GetLayers())
+        {
+          printf("Image dimensions or channels are different\n");
+          return -1.0;
         }
-        else {
-          DstData[xy + l] = 0;
+        float PixelDiff = 0.0;
+        int Pixels = 0;
+        unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        unsigned char* RefImgData = reference.GetImageData();
+        int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+        int RowStart = 0;
+
+        for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+        {
+          for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
+          {
+            if (abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]) > difference)
+              Pixels++;
+          }
+          RowStart += WidthStep;
         }
+        PixelDiff = (float)Pixels / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep) * 100;
+        return PixelDiff;
       }
-    }
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
-}
-
-float MEImage::DifferenceAreas(MEImage& reference, int difference) const
-{
-  if (reference.GetWidth() != GetWidth() ||
-    reference.GetHeight() != GetHeight() ||
-    reference.GetLayers() != GetLayers())
-  {
-    printf("Image dimensions or channels are different\n");
-    return -1.0;
-  }
-  float PixelDiff = 0.0;
-  int Pixels = 0;
-  unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  unsigned char* RefImgData = reference.GetImageData();
-  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
-  int RowStart = 0;
-
-  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-  {
-    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
-    {
-      if (abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]) > difference)
-        Pixels++;
-    }
-    RowStart += WidthStep;
-  }
-  PixelDiff = (float)Pixels / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep) * 100;
-  return PixelDiff;
-}
 
-int MEImage::AverageDifference(MEImage& reference) const
-{
-  if (reference.GetWidth() != GetWidth() ||
-    reference.GetHeight() != GetHeight() ||
-    reference.GetLayers() != GetLayers())
-  {
-    printf("Image dimensions or channels are different\n");
-    return -1;
-  }
-  int Difference = 0;
-  unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  unsigned char* RefImgData = reference.GetImageData();
-  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
-  int RowStart = 0;
+      int MEImage::AverageDifference(MEImage& reference) const
+      {
+        if (reference.GetWidth() != GetWidth() ||
+          reference.GetHeight() != GetHeight() ||
+          reference.GetLayers() != GetLayers())
+        {
+          printf("Image dimensions or channels are different\n");
+          return -1;
+        }
+        int Difference = 0;
+        unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        unsigned char* RefImgData = reference.GetImageData();
+        int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+        int RowStart = 0;
 
-  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-  {
-    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
-    {
-      Difference += abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]);
-    }
-    RowStart += WidthStep;
-  }
-  Difference = Difference / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep);
-  return Difference;
-}
+        for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+        {
+          for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
+          {
+            Difference += abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]);
+          }
+          RowStart += WidthStep;
+        }
+        Difference = Difference / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep);
+        return Difference;
+      }
 
-void MEImage::Minimum(MEImage& image)
-{
-  if (image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
-    image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
-    image.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
-  {
-    printf("Image properties are different\n");
-    return;
-  }
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  unsigned char* SecData = image.GetImageData();
-  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
-  int RowStart = 0;
+      void MEImage::Minimum(MEImage& image)
+      {
+        if (image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+          image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+          image.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+        {
+          printf("Image properties are different\n");
+          return;
+        }
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        unsigned char* SecData = image.GetImageData();
+        int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+        int RowStart = 0;
 
-  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-  {
-    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
-    {
-      ImageData[RowStart + x] = ImageData[RowStart + x] > SecData[RowStart + x] ?
-        SecData[RowStart + x] : ImageData[RowStart + x];
-    }
-    RowStart += WidthStep;
-  }
-}
+        for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+        {
+          for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
+          {
+            ImageData[RowStart + x] = ImageData[RowStart + x] > SecData[RowStart + x] ?
+              SecData[RowStart + x] : ImageData[RowStart + x];
+          }
+          RowStart += WidthStep;
+        }
+      }
 
-float MEImage::AverageBrightnessLevel() const
-{
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
-  int RowStart = 0;
-  int BrightnessLevel = 0;
+      float MEImage::AverageBrightnessLevel() const
+      {
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+        int RowStart = 0;
+        int BrightnessLevel = 0;
 
-  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-  {
-    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
-    {
-      BrightnessLevel += (int)ImageData[RowStart + x];
-    }
-    RowStart += WidthStep;
-  }
-  return BrightnessLevel / (GetWidth()*GetHeight()*GetLayers());
-}
+        for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+        {
+          for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
+          {
+            BrightnessLevel += (int)ImageData[RowStart + x];
+          }
+          RowStart += WidthStep;
+        }
+        return BrightnessLevel / (GetWidth()*GetHeight()*GetLayers());
+      }
 
-bool MEImage::Equal(const MEImage& reference) const
-{
-  return Equal(reference, 1);
-}
+      bool MEImage::Equal(const MEImage& reference) const
+      {
+        return Equal(reference, 1);
+      }
 
-bool MEImage::Equal(const MEImage& reference, int maxabsdiff) const
-{
-  bool Ret = true;
+      bool MEImage::Equal(const MEImage& reference, int maxabsdiff) const
+      {
+        bool Ret = true;
 
-  if (reference.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
-    reference.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
-    reference.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
-  {
-    printf("Image properties are different\n");
-    return false;
-  }
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  unsigned char* RefData = reference.GetImageData();
-  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
-  int RowStart = 0;
+        if (reference.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+          reference.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+          reference.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+        {
+          printf("Image properties are different\n");
+          return false;
+        }
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        unsigned char* RefData = reference.GetImageData();
+        int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+        int RowStart = 0;
 
-  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
-  {
-    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
-    {
-      if (abs(ImageData[RowStart + x] - RefData[RowStart + x]) >= maxabsdiff)
-      {
-        Ret = false;
+        for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y)
+        {
+          for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x)
+          {
+            if (abs(ImageData[RowStart + x] - RefData[RowStart + x]) >= maxabsdiff)
+            {
+              Ret = false;
+              return Ret;
+            }
+          }
+          RowStart += WidthStep;
+        }
         return Ret;
       }
-    }
-    RowStart += WidthStep;
-  }
-  return Ret;
-}
 
-unsigned char MEImage::GrayscalePixel(int x, int y) const
-{
-  int NewX = x;
-  int NewY = y;
+      unsigned char MEImage::GrayscalePixel(int x, int y) const
+      {
+        int NewX = x;
+        int NewY = y;
 
-  NewX = NewX < 0 ? 0 : NewX;
-  NewX = NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 : NewX;
-  NewY = NewY < 0 ? 0 : NewY;
-  NewY = NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 : NewY;
+        NewX = NewX < 0 ? 0 : NewX;
+        NewX = NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 : NewX;
+        NewY = NewY < 0 ? 0 : NewY;
+        NewY = NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 : NewY;
 
-  float Sum = 0;
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        float Sum = 0;
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
 
-  for (int l = 0; l < ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; l++)
-  {
-    Sum = Sum + (int)ImageData[NewY*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + NewX*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l];
-  }
-  Sum = Sum / ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
-  return (unsigned char)(Sum);
-}
+        for (int l = 0; l < ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; l++)
+        {
+          Sum = Sum + (int)ImageData[NewY*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + NewX*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l];
+        }
+        Sum = Sum / ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
+        return (unsigned char)(Sum);
+      }
 
-int MEImage::NeighbourhoodCounter(int startx, int starty,
-  NeighbourhoodType neighbourhood) const
-{
-  int IterX = 0;
-  int IterY = 0;
-  int Counter = 0;
+      int MEImage::NeighbourhoodCounter(int startx, int starty,
+        NeighbourhoodType neighbourhood) const
+      {
+        int IterX = 0;
+        int IterY = 0;
+        int Counter = 0;
 
-  // Determine the iteration numbers
-  switch (neighbourhood)
-  {
-  case n_2x2:
-    IterX = 2;
-    IterY = 2;
-    break;
-
-  case n_3x3:
-    IterX = 3;
-    IterY = 3;
-    break;
-
-  case n_3x2:
-    IterX = 2;
-    IterY = 3;
-    break;
-
-  case n_5x5:
-    IterX = 5;
-    IterY = 5;
-    break;
-
-  case n_7x7:
-    IterX = 7;
-    IterY = 7;
-    break;
-
-  default:
-    IterX = 3;
-    IterY = 3;
-    break;
-  }
+        // Determine the iteration numbers
+        switch (neighbourhood)
+        {
+        case n_2x2:
+          IterX = 2;
+          IterY = 2;
+          break;
+
+        case n_3x3:
+          IterX = 3;
+          IterY = 3;
+          break;
+
+        case n_3x2:
+          IterX = 2;
+          IterY = 3;
+          break;
+
+        case n_5x5:
+          IterX = 5;
+          IterY = 5;
+          break;
+
+        case n_7x7:
+          IterX = 7;
+          IterY = 7;
+          break;
+
+        default:
+          IterX = 3;
+          IterY = 3;
+          break;
+        }
 
-  int NewStartX = startx;
-  int NewStartY = starty;
+        int NewStartX = startx;
+        int NewStartY = starty;
 
-  NewStartX = startx < 0 ? 0 : startx;
-  NewStartX = startx >= ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX ? ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX - 1 : startx;
-  NewStartY = starty < 0 ? 0 : starty;
-  NewStartY = starty >= ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY ? ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY - 1 : starty;
+        NewStartX = startx < 0 ? 0 : startx;
+        NewStartX = startx >= ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX ? ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX - 1 : startx;
+        NewStartY = starty < 0 ? 0 : starty;
+        NewStartY = starty >= ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY ? ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY - 1 : starty;
 
-  int Value = 0;
-  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        int Value = 0;
+        unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
 
-  for (int x = NewStartX; x < NewStartX + IterX; x++)
-    for (int y = NewStartY; y < NewStartY + IterY; y++)
-    {
-      Value = ((int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels] +
-        (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 1] +
-        (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 2]) / 3;
+        for (int x = NewStartX; x < NewStartX + IterX; x++)
+          for (int y = NewStartY; y < NewStartY + IterY; y++)
+          {
+            Value = ((int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels] +
+              (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 1] +
+              (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 2]) / 3;
+
+            if (Value == 255)
+            {
+              Counter++;
+            }
+          }
+        return Counter;
+      }
 
-      if (Value == 255)
+      void MEImage::GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y)
       {
-        Counter++;
-      }
-    }
-  return Counter;
-}
+        int Results[8];
+        int DiagonalMaskSize = (int)((float)mask_size / sqrtf(2));
 
-void MEImage::GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y)
-{
-  int Results[8];
-  int DiagonalMaskSize = (int)((float)mask_size / sqrtf(2));
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
+        {
+          ConvertToGrayscale(g_OpenCV);
+        }
+        if (smooth)
+        {
+          SmoothAdvanced(s_Gaussian, mask_size * 3 - (mask_size * 3 - 1) % 2);
+        }
 
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
-  {
-    ConvertToGrayscale(g_OpenCV);
-  }
-  if (smooth)
-  {
-    SmoothAdvanced(s_Gaussian, mask_size * 3 - (mask_size * 3 - 1) % 2);
-  }
+        Results[0] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y - mask_size);
+        Results[1] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize);
+        Results[2] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + mask_size, y);
+        Results[3] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y + DiagonalMaskSize);
+        Results[4] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y + mask_size);
+        Results[5] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - DiagonalMaskSize, y + DiagonalMaskSize);
+        Results[6] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - mask_size, y);
+        Results[7] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize);
+
+        result_x = (DiagonalMaskSize*Results[1] + mask_size*Results[2] +
+          DiagonalMaskSize*Results[3] - DiagonalMaskSize*Results[5] -
+          mask_size*Results[6] + DiagonalMaskSize*Results[7]) / 256;
+        result_y = (-mask_size*Results[0] - DiagonalMaskSize*Results[1] +
+          DiagonalMaskSize*Results[3] + mask_size*Results[4] +
+          DiagonalMaskSize*Results[5] - DiagonalMaskSize*Results[7]) / 256;
+      }
 
-  Results[0] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y - mask_size);
-  Results[1] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize);
-  Results[2] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + mask_size, y);
-  Results[3] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y + DiagonalMaskSize);
-  Results[4] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y + mask_size);
-  Results[5] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - DiagonalMaskSize, y + DiagonalMaskSize);
-  Results[6] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - mask_size, y);
-  Results[7] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize);
-
-  result_x = (DiagonalMaskSize*Results[1] + mask_size*Results[2] +
-    DiagonalMaskSize*Results[3] - DiagonalMaskSize*Results[5] -
-    mask_size*Results[6] + DiagonalMaskSize*Results[7]) / 256;
-  result_y = (-mask_size*Results[0] - DiagonalMaskSize*Results[1] +
-    DiagonalMaskSize*Results[3] + mask_size*Results[4] +
-    DiagonalMaskSize*Results[5] - DiagonalMaskSize*Results[7]) / 256;
-}
+      void MEImage::GradientVisualize(int vector_x, int vector_y)
+      {
+        if (vector_x <= 0)
+        {
+          printf("vectorx: wrong parameter (%d <= 0)\n", vector_x);
+          return;
+        }
+        if (vector_y <= 0)
+        {
+          printf("vectory: wrong parameter (%d <= 0)\n", vector_y);
+          return;
+        }
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
+        {
+          ConvertToGrayscale(g_OpenCV);
+        }
 
-void MEImage::GradientVisualize(int vector_x, int vector_y)
-{
-  if (vector_x <= 0)
-  {
-    printf("vectorx: wrong parameter (%d <= 0)\n", vector_x);
-    return;
-  }
-  if (vector_y <= 0)
-  {
-    printf("vectory: wrong parameter (%d <= 0)\n", vector_y);
-    return;
-  }
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
-  {
-    ConvertToGrayscale(g_OpenCV);
-  }
+        int masksize = (ME_CAST_TO_IPLIMAGE(cvImg)->width < ME_CAST_TO_IPLIMAGE(cvImg)->height) ?
+          ME_CAST_TO_IPLIMAGE(cvImg)->width / (vector_x + 1) :
+          ME_CAST_TO_IPLIMAGE(cvImg)->height / (vector_y + 1);
 
-  int masksize = (ME_CAST_TO_IPLIMAGE(cvImg)->width < ME_CAST_TO_IPLIMAGE(cvImg)->height) ?
-    ME_CAST_TO_IPLIMAGE(cvImg)->width / (vector_x + 1) :
-    ME_CAST_TO_IPLIMAGE(cvImg)->height / (vector_y + 1);
+        SmoothAdvanced(s_Gaussian, masksize * 2 - 1);
+        for (int i = 1; i < vector_x; i++)
+          for (int i1 = 1; i1 < vector_y; i1++)
+          {
+            int Resultx = 0, Resulty = 0;
+            int x = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->width*i / (vector_x)));
+            int y = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->height*i1 / (vector_y)));
 
-  SmoothAdvanced(s_Gaussian, masksize * 2 - 1);
-  for (int i = 1; i < vector_x; i++)
-    for (int i1 = 1; i1 < vector_y; i1++)
-    {
-      int Resultx = 0, Resulty = 0;
-      int x = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->width*i / (vector_x)));
-      int y = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->height*i1 / (vector_y)));
+            GradientVector(false, x, y, (int)(0.707*masksize), Resultx, Resulty);
 
-      GradientVector(false, x, y, (int)(0.707*masksize), Resultx, Resulty);
+            CvPoint Point1;
+            CvPoint Point2;
 
-      CvPoint Point1;
-      CvPoint Point2;
+            Point1.x = x - Resultx / 2;
+            Point1.y = y - Resulty / 2;
+            Point2.x = x + Resultx / 2;
+            Point2.y = y + Resulty / 2;
+            cvLine(ME_CAST_TO_IPLIMAGE(cvImg), Point1, Point2, CV_RGB(255, 255, 255), 1, 8);
+          }
+      }
 
-      Point1.x = x - Resultx / 2;
-      Point1.y = y - Resulty / 2;
-      Point2.x = x + Resultx / 2;
-      Point2.y = y + Resulty / 2;
-      cvLine(ME_CAST_TO_IPLIMAGE(cvImg), Point1, Point2, CV_RGB(255, 255, 255), 1, 8);
-    }
-}
+      bool MEImage::_Copy(const MEImage& other_image)
+      {
+        if (&other_image == this)
+          return true;
 
-bool MEImage::_Copy(const MEImage& other_image)
-{
-  if (&other_image == this)
-    return true;
+        if (ME_CAST_TO_IPLIMAGE(cvImg))
+        {
+          ME_RELEASE_IPLIMAGE(cvImg);
+        }
+        cvImg = cvCloneImage((IplImage*)other_image.GetIplImage());
+        return true;
+      }
 
-  if (ME_CAST_TO_IPLIMAGE(cvImg))
-  {
-    ME_RELEASE_IPLIMAGE(cvImg);
-  }
-  cvImg = cvCloneImage((IplImage*)other_image.GetIplImage());
-  return true;
-}
+      void MEImage::_Init(int width, int height, int layers)
+      {
+        if (width < 1)
+        {
+          printf("Given width for the new image is too small (%d <= 0)\n", width);
+          return;
+        }
+        if (height < 1)
+        {
+          printf("Given height for the new image is (%d <= 0)\n", height);
+          return;
+        }
+        if ((layers != 1) && (layers != 3))
+        {
+          printf("Only one or three (%d != 1 or 3) layer allowed\n", layers);
+          return;
+        }
 
-void MEImage::_Init(int width, int height, int layers)
-{
-  if (width < 1)
-  {
-    printf("Given width for the new image is too small (%d <= 0)\n", width);
-    return;
-  }
-  if (height < 1)
-  {
-    printf("Given height for the new image is (%d <= 0)\n", height);
-    return;
-  }
-  if ((layers != 1) && (layers != 3))
-  {
-    printf("Only one or three (%d != 1 or 3) layer allowed\n", layers);
-    return;
-  }
+        if (ME_CAST_TO_IPLIMAGE(cvImg))
+        {
+          ME_RELEASE_IPLIMAGE(cvImg);
+        }
+        cvImg = cvCreateImage(cvSize(width, height), 8, layers);
+      }
 
-  if (ME_CAST_TO_IPLIMAGE(cvImg))
-  {
-    ME_RELEASE_IPLIMAGE(cvImg);
-  }
-  cvImg = cvCreateImage(cvSize(width, height), 8, layers);
-}
+      void MEImage::ComputeColorSpace(ColorSpaceConvertType mode)
+      {
+        if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3)
+        {
+          printf("Image has to have three color channels (%d != 3)\n", ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+          return;
+        }
+        IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+          ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
 
-void MEImage::ComputeColorSpace(ColorSpaceConvertType mode)
-{
-  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3)
-  {
-    printf("Image has to have three color channels (%d != 3)\n", ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
-    return;
-  }
-  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
-    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+        for (int i = 0; i < 3; i++)
+          for (int i1 = 0; i1 < 3; i1++)
+          {
+            if (mode == csc_RGBtoYUV)
+              TransformMatrix[i][i1] = RGBtoYUVMatrix[i][i1];
+            if (mode == csc_RGBtoYIQ)
+              TransformMatrix[i][i1] = RGBtoYIQMatrix[i][i1];
+          }
+        float x = 0.0;
+        float y = 0.0;
+        float z = 0.0;
+        float xmin = 0.0;
+        float xmax = 0.0;
+        float ymin = 0.0;
+        float ymax = 0.0;
+        float zmin = 0.0;
+        float zmax = 0.0;
+
+        if (mode == csc_RGBtoYUV)
+        {
+          xmin = 0.0;
+          xmax = 255.0;
+          ymin = -111.18;
+          ymax = 111.18;
+          zmin = -156.825;
+          zmax = 156.825;
+        }
+        if (mode == csc_RGBtoYIQ)
+        {
+          xmin = 0.0;
+          xmax = 255.0;
+          ymin = -151.98;
+          ymax = 151.98;
+          zmin = -133.365;
+          zmax = 133.365;
+        }
+        unsigned char* SrcData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+        unsigned char* DstData = (unsigned char*)TempImg->imageData;
 
-  for (int i = 0; i < 3; i++)
-    for (int i1 = 0; i1 < 3; i1++)
-    {
-      if (mode == csc_RGBtoYUV)
-        TransformMatrix[i][i1] = RGBtoYUVMatrix[i][i1];
-      if (mode == csc_RGBtoYIQ)
-        TransformMatrix[i][i1] = RGBtoYIQMatrix[i][i1];
+        for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; i -= 3)
+        {
+          x = (float)SrcData[i] * TransformMatrix[0][0] +
+            (float)SrcData[i + 1] * TransformMatrix[0][1] +
+            (float)SrcData[i + 2] * TransformMatrix[0][2];
+          y = (float)SrcData[i] * TransformMatrix[1][0] +
+            (float)SrcData[i + 1] * TransformMatrix[1][1] +
+            (float)SrcData[i + 2] * TransformMatrix[1][2];
+          z = (float)SrcData[i] * TransformMatrix[2][0] +
+            (float)SrcData[i + 1] * TransformMatrix[2][1] +
+            (float)SrcData[i + 2] * TransformMatrix[2][2];
+
+          x = xmax - xmin != 0.0 ? 255.0 : (x - xmin) / (xmax - xmin)*255.0;
+          y = ymax - ymin != 0.0 ? 255.0 : (y - xmin) / (ymax - ymin)*255.0;
+          z = zmax - zmin != 0.0 ? 255.0 : (z - xmin) / (zmax - zmin)*255.0;
+
+          DstData[i] = (unsigned char)MEBound(0, (int)x, 255);
+          DstData[i + 1] = (unsigned char)MEBound(0, (int)y, 255);
+          DstData[i + 2] = (unsigned char)MEBound(0, (int)z, 255);
+        }
+        ME_RELEASE_IPLIMAGE(cvImg);
+        cvImg = TempImg;
+      }
     }
-  float x = 0.0;
-  float y = 0.0;
-  float z = 0.0;
-  float xmin = 0.0;
-  float xmax = 0.0;
-  float ymin = 0.0;
-  float ymax = 0.0;
-  float zmin = 0.0;
-  float zmax = 0.0;
-
-  if (mode == csc_RGBtoYUV)
-  {
-    xmin = 0.0;
-    xmax = 255.0;
-    ymin = -111.18;
-    ymax = 111.18;
-    zmin = -156.825;
-    zmax = 156.825;
-  }
-  if (mode == csc_RGBtoYIQ)
-  {
-    xmin = 0.0;
-    xmax = 255.0;
-    ymin = -151.98;
-    ymax = 151.98;
-    zmin = -133.365;
-    zmax = 133.365;
-  }
-  unsigned char* SrcData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
-  unsigned char* DstData = (unsigned char*)TempImg->imageData;
-
-  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; i -= 3)
-  {
-    x = (float)SrcData[i] * TransformMatrix[0][0] +
-      (float)SrcData[i + 1] * TransformMatrix[0][1] +
-      (float)SrcData[i + 2] * TransformMatrix[0][2];
-    y = (float)SrcData[i] * TransformMatrix[1][0] +
-      (float)SrcData[i + 1] * TransformMatrix[1][1] +
-      (float)SrcData[i + 2] * TransformMatrix[1][2];
-    z = (float)SrcData[i] * TransformMatrix[2][0] +
-      (float)SrcData[i + 1] * TransformMatrix[2][1] +
-      (float)SrcData[i + 2] * TransformMatrix[2][2];
-
-    x = xmax - xmin != 0.0 ? 255.0 : (x - xmin) / (xmax - xmin)*255.0;
-    y = ymax - ymin != 0.0 ? 255.0 : (y - xmin) / (ymax - ymin)*255.0;
-    z = zmax - zmin != 0.0 ? 255.0 : (z - xmin) / (zmax - zmin)*255.0;
-
-    DstData[i] = (unsigned char)MEBound(0, (int)x, 255);
-    DstData[i + 1] = (unsigned char)MEBound(0, (int)y, 255);
-    DstData[i + 2] = (unsigned char)MEBound(0, (int)z, 255);
   }
-  ME_RELEASE_IPLIMAGE(cvImg);
-  cvImg = TempImg;
 }
diff --git a/src/algorithms/LBP_MRF/MEImage.hpp b/src/algorithms/LBP_MRF/MEImage.hpp
index 7094912f368ab0d0a85ab88872e80867b71aa2de..b9ba1fccf8b855629d4098ddb6f7ccdc9f4e410b 100644
--- a/src/algorithms/LBP_MRF/MEImage.hpp
+++ b/src/algorithms/LBP_MRF/MEImage.hpp
@@ -1,968 +1,977 @@
 #pragma once
 
-/**
- * MEImage
- * @brief Basic image functions
- */
-class MEImage
+namespace bgslibrary
 {
-public:
-  /// Types of LBP operator
-  typedef enum {
-    lbp_Min = 0,          /*!< Minimum value */
-    lbp_Normal = lbp_Min, /*!< Normal LBP pattern */
-    lbp_Special,          /*!< Special LBP pattern */
-    lbp_Max = lbp_Special /*!< Maximum value */
-  } LBPType;
-
-  /// Types of image subtraction
-  typedef enum {
-    sub_Min = 0,          /*!< Minimum value */
-    sub_Normal = sub_Min, /*!< Normal */
-    sub_Absolut,          /*!< Absolut */
-    sub_Max = sub_Absolut /*!< Maximum value */
-  } SubtractModeType;
-
-  /// Types of image addition
-  typedef enum {
-    a_Min = 0,         /*!< Minimum value */
-    a_Average = a_Min, /*!< Average */
-    a_Union,           /*!< Union */
-    a_Max = a_Union    /*!< Maximum value */
-  } AdditionType;
-
-  /// Types of image multiplication
-  typedef enum {
-    m_Min = 0,              /*!< Minimum value */
-    m_Normal = m_Min,       /*!< Normal */
-    m_Neighbourhood,        /*!< Neighbourhood */
-    m_Max = m_Neighbourhood /*!< Maximum value */
-  } MultiplicationType;
-
-  /// Types of grayscale conversation
-  typedef enum {
-    g_Min = 0,         /*!< Minimum value */
-    g_Average = g_Min, /*!< Average */
-    g_OpenCV,          /*!< OpenCV */
-    g_Max = g_OpenCV   /*!< Maximum value */
-  } GrayscaleType;
-
-  /// Types of pixel neighbourhoods
-  typedef enum {
-    n_Min = 0,     /*!< Minimum value */
-    n_2x2 = n_Min, /*!< 2x2 */
-    n_3x2,         /*!< 3x2 */
-    n_3x3,         /*!< 3x3 */
-    n_5x5,         /*!< 5x5 */
-    n_7x7,         /*!< 7x7 */
-    n_Max = n_7x7  /*!< Maximum value */
-  } NeighbourhoodType;
-
-  /// Types of special pixels
-  typedef enum {
-    p_Min = 0,         /*!< Minimum value */
-    p_Minimum = p_Min, /*!< Minimum */
-    p_Maximum,         /*!< Maximum */
-    p_Counter,         /*!< Counter */
-    p_Max = p_Counter  /*!< Maximum value */
-  } PixelType;
-
-  /// Types of smooth operation
-  typedef enum {
-    s_Min = 0,       /*!< Minimum value */
-    s_Blur = s_Min,  /*!< Blur */
-    s_Gaussian,      /*!< Gaussian */
-    s_Median,        /*!< Medium */
-    s_Max = s_Median /*!< Maximum value */
-  } SmoothType;
-
-  /// Types of color space conversions
-  typedef enum {
-    csc_Min = 0,                  /*!< Minimum value */
-    csc_RGBtoXYZCIED65 = csc_Min, /*!< RGB to XYZCIED65 */
-    csc_XYZCIED65toRGB,           /*!< XYZCIED65 to RGB */
-    csc_RGBtoHSV,                 /*!< RGB to HSV */
-    csc_HSVtoRGB,                 /*!< HSV to RGB */
-    csc_RGBtoHLS,                 /*!< RGB to HLS */
-    csc_HLStoRGB,                 /*!< HLS to RGB */
-    csc_RGBtoCIELab,              /*!< RGB to CIELab */
-    csc_CIELabtoRGB,              /*!< CIELab to RGB */
-    csc_RGBtoCIELuv,              /*!< RGB to CIELuv */
-    csc_CIELuvtoRGB,              /*!< CIELuv to RGB */
-    csc_RGBtoYUV,                 /*!< RGB to YUV */
-    csc_RGBtoYIQ,                 /*!< RGB to YIQ */
-    csc_RGBtorgI,                 /*!< RGB to rgI */
-    csc_Max = csc_RGBtorgI        /*!< Maximum value */
-  } ColorSpaceConvertType;
-
-  /*!
-   * @brief Class constructor
-   *
-   * @param width Image width
-   * @param height Image height
-   * @param layers Layers
-   *
-   * Class constructor with the possibility to specify the image width,
-   * height and the layers. The default options are 16x16x1.
-   *
-   */
-
-  MEImage(int width = 16, int height = 16, int layers = 1);
-
-  /*!
-   * @brief Class constructor
-   *
-   * @param other Other image
-   *
-   * Class constructor with the possibility to specify the image width,
-   * height and the layers. The default options are 16x16x1.
-   *
-   */
-
-  MEImage(const MEImage& other);
-  /// Destructor of class
-  ~MEImage();
-
-  /*
-  -------------------------------------------------------------------
-                          Basic functions
-  -------------------------------------------------------------------
-  */
-
-  /*!
-   * @brief Clear image
-   *
-   * This function clears image by filling all image data with zero
-   * value.
-   *
-   */
-
-  void Clear();
-
-  /*!
-   * @brief Get an color layer of image
-   *
-   * @param new_layer new image of layer
-   * @param layernumber number of layer which will be copied
-   *
-   * Copy an image layer (R, G or B) to @a new_layer image. @a new_layer has to
-   * have only one color layer (greyscale). If @a new_layer is not
-   * greyscale or it has got different width or height like source image
-   * than function reallocates it with appropriate features before
-   * copying image data.
-   *
-   */
-
-  void GetLayer(MEImage& new_layer, int layernumber) const;
-
-  /*!
-   * @brief Copy a new color layer to image
-   *
-   * @param new_layer image data of new color layer
-   * @param layernumber number of layer where image data will copy
-   *
-   * Copy a new image layer from @a new_layer image. @a new_layer has to
-   * have only one color layer (greyscale). If @a new_layer is not
-   * greyscale or it has got different width or height like source image
-   * than function halts with an error message.
-   *
-   */
-
-  void SetLayer(MEImage& new_layer, int layernumber);
-
-  /*!
-   * @brief Copy image data to a pointer
-   *
-   * @param data pointer where image data will be copied
-   *
-   * Function in order to acquire image data to an external
-   * (unsigned char*) pointer.
-   *
-   */
-
-  void CopyImageData(unsigned char* data);
-
-  /*!
-   * @brief Get a pointer to the internal IplImage
-   *
-   * @return Pointer to the IplImage
-   *
-   * This function returns the internal IplImage of the class. The
-   * image data can not be modified.
-   *
-   */
-
-  void* GetIplImage() const;
-
-  /*!
-   * @brief Set the internal IplImage
-   *
-   * @param image Pointer to the IplImage
-   *
-   * This function sets the internal IplImage of the class.
-   *
-   */
-
-  void SetIplImage(void* image);
-
-  /*!
-   * @brief Handle operator == for MEImage
-   *
-   * @param image image to check
-   *
-   * @return true if the images are equal otherwise false.
-   *
-   * The operator checks the equality of two images.
-   *
-   */
-
-  bool operator==(const MEImage& image);
-
-  /*!
-   * @brief Handle operator != for MEImage
-   *
-   * @param image image to check
-   *
-   * @return true if the images are not equal otherwise false.
-   *
-   * The operator checks the non-equality of two images.
-   *
-   */
-
-  bool operator!=(const MEImage& image);
-
-  /*!
-   * @brief Handle operator = for MEImage
-   *
-   * @param other_image image to copy operation
-   *
-   * @return Reference to the actual instance.
-   *
-   * Copy image data to @a other_image image. Function calls only
-   * _Copy() directly.
-   *
-   */
-
-  MEImage& operator=(const MEImage& other_image);
-
-  /*!
-   * @brief Get the width of the image
-   *
-   * @return Width of the image
-   *
-   * Get the width of the image.
-   *
-   */
-
-  int GetWidth() const;
-
-  /*!
-   * @brief Get the height of the image
-   *
-   * @return Height of the image
-   *
-   * Get the height of the image.
-   */
-
-  int GetHeight() const;
-
-  /*!
-   * @brief Get the length of a pixel row of the image
-   *
-   * @return Length of a pixel row
-   *
-   * Get the row width of the image.
-   *
-   */
-
-  int GetRowWidth() const;
-
-  /*!
-   * @brief Get the number of color layers of the image
-   *
-   * @return Number of color layer of the image
-   *
-   * Get the number of color layer of the image.
-   *
-   */
-
-  int GetLayers() const;
-
-  /*!
-   * @brief Get the number of the image pixel data
-   *
-   * @return Number of the image pixel data
-   *
-   * Get the number of the image pixel data.
-   *
-   */
-
-  int GetPixelDataNumber() const;
-
-  /*!
-   * @brief Get the image data
-   *
-   * @return Pointer to the image data
-   *
-   * Get a pointer to the image.
-   *
-   */
-
-  unsigned char* GetImageData() const;
-
-  /*!
-   * @brief Set the image data
-   *
-   * @param image_data New image data
-   * @param width New image width
-   * @param height New image height
-   * @param channels New image color channels
-   *
-   * Get a pointer to the image.
-   *
-   */
-
-  void SetData(unsigned char* image_data, int width, int height, int channels);
-
-  /*!
-   * @brief Get ratio of image width and height
-   *
-   * @return float ratio of image dimensions
-   *
-   * Function calculates ratio of image width and height with
-   * following equation: ratio = height / width.
-   */
-
-  float GetRatio() const;
-
-  /*
-  -------------------------------------------------------------------
-                       Basic image manipulation
-  -------------------------------------------------------------------
-  */
-
-  /*!
-   * @brief Reallocate image data
-   *
-   * @param width New width of the image
-   * @param height New height of the image
-   *
-   * Image data will be reallocated with new dimensions @a width
-   * and @a height. Number of color channels is not changed.
-   *
-   */
-
-  void Realloc(int width, int height);
-
-  /*!
-   * @brief Reallocate image data
-   *
-   * @param width New width of the image
-   * @param height New height of the image
-   * @param layers Number of color channels of the image
-   *
-   * Image data will be reallocated with new dimensions @a width,
-   * @a height and new number of color channels @a layers.
-   *
-   */
-
-  void Realloc(int width, int height, int layers);
-
-  /*!
-   * @brief Resize image
-   *
-   * @param newwidth new width of image
-   * @param newheight new height of image
-   *
-   * Resize image to @a newwidth width and @a newheight
-   * height dimensions.
-   *
-   */
-
-  void Resize(int newwidth, int newheight);
-
-  /*!
-   * @brief Resize image with new width
-   *
-   * @param newwidth new width of image
-   *
-   * Image is resized with only new width information therefore
-   * fit to original ratio.
-   *
-   */
-
-  void ResizeScaleX(int newwidth);
-
-  /*!
-   * @brief Resize image with new height
-   *
-   * @param newheight new height of image
-   *
-   * Image is resized with only new height information therefore
-   * fit to original ratio.
-   *
-   */
-
-  void ResizeScaleY(int newheight);
-
-  /*!
-   * @brief Reverse image in horizontal direction
-   *
-   * Function makes a mirror transformation on image in horizontal
-   * direction.
-   *
-   */
-
-  void MirrorHorizontal();
-
-  /*!
-   * @brief Reverse image in vertical direction
-   *
-   * Function makes a mirror transformation on image in vertical
-   * direction.
-   *
-   */
-
-  void MirrorVertical();
-
-  /*!
-   * @brief Crop image
-   *
-   * @param x1, y1 coordinates of top-left point of rectangle
-   * @param x2, y2 coordinates of bottom-right point of rectangle
-   *
-   * Crop the image in a smaller piece whose dimensions are
-   * specified as a rectangle. Top-left and bottom-right
-   * coordinates of rectangle are (x1, y1) and (x2, y2) wherefrom
-   * comes that the width of the new image is x2-x1 and height is
-   * y2-y1.
-   *
-   */
-
-  void Crop(int x1, int y1, int x2, int y2);
-
-  /*!
-   * @brief Copy all image data from an other picture
-   *
-   * @param x0 x coordinate to paste the new image data
-   * @param y0 y coordinate to paste the new image data
-   * @param source_image source image
-   *
-   * Function copies all image data from @a source_image
-   * to the given coordinate (x0,y0).
-   *
-   */
-
-  void CopyImageInside(int x0, int y0, MEImage& source_image);
-
-  /*
-  -------------------------------------------------------------------
-                     Image processing functions
-  -------------------------------------------------------------------
-  */
-
-  /*!
-   * @brief Erode function
-   *
-   * @param iterations iterations of erode method
-   *
-   * Method makes an erode filter on an image @a iterations
-   * times with standard 3x3 matrix size.
-   *
-   */
-
-  void Erode(int iterations);
-
-  /*!
-   * @brief Dilate function
-   *
-   * @param iterations iterations of dilate method
-   *
-   * Method makes an dilate filter on an image
-   * @a iterations times with standard 3x3 matrix size.
-   *
-   */
-
-  void Dilate(int iterations);
-
-  /*!
-   * @brief Smooth function
-   *
-   * Method smooths with median filter and standard 3x3 matrix size.
-   * (Median filter works fine and fast.)
-   *
-   */
-
-  void Smooth();
-
-  /*!
-   * @brief Smooth function with defined parameters
-   *
-   * @param filtermode type of smooth method
-   * @param filtersize the size of the convolution matrix
-   *
-   * Method smooths with median filter and the given matrix
-   * size (@a filtersize x @a filtersize). There are more
-   * types of smooth function (@a filtermode):
-   *
-   * - s_Blur: Blur filter.
-   * - s_Gaussian: Gaussian filter.
-   * - s_Median: Median filter.
-   *
-   */
-
-  void SmoothAdvanced(SmoothType filtermode, int filtersize);
-
-  /*!
-   * @brief Canny function
-   *
-   * Canny operator is usable for edge detection. Function makes
-   * this operation with standard 3x3 matrix
-   * size. Canny has two threshold value which are set to zero
-   * in this function by default.
-   *
-   */
-
-  void Canny();
-
-  /*!
-   * @brief Laplace function
-   *
-   * Laplace operator is usable for edge detection like Canny.
-   * This function makes a laplace filter with
-   * standard 3x3 matrix size. After calculating destination image will
-   * be converted from 16 bit back to 8 bit.
-   *
-   */
-
-  void Laplace();
-
-  /*!
-   * @brief Image quantisation
-   *
-   * @param levels level of quantisation
-   *
-   * Quantize an image with @a levels level. It means by 16
-   * level color range 0-255 quantizes to 0-15, by 4 level to 0-63 etc.
-   *
-   */
-
-  void Quantize(int levels);
-
-  /*!
-   * @brief Threshold a picture
-   *
-   * @param threshold_limit limit for threshold
-   *
-   * Threshold an image with @a threshold_limit limit. Value range
-   * of @a threshold_limit is between 0-255. E.g. by value 160 functions
-   * will eliminate all color values under 160 with black color
-   * (color value zero).
-   *
-   */
-
-  void Threshold(int threshold_limit);
-
-  /*!
-   * @brief Adaptive threshold function
-   *
-   * This function does adaptive threshold function.
-   *
-   */
-
-  void AdaptiveThreshold();
-
-  /*!
-   * @brief Threshold a picture by a mask image
-   *
-   * @param mask_image mask image for thresholding
-   *
-   * Threshold an image with a mask image @a mask_image.
-   *
-   */
-
-  void ThresholdByMask(MEImage& mask_image);
-
-  /*!
-   * @brief Convert an image into a new color space
-   *
-   * @param transformation Definition of color transformation
-   *
-   * This function converts an image from a specified color space
-   * to an other.
-   * Current supported conversions (@a transformation):
-   * - csc_RGBtoXYZCIED65: RGB to XYZ (D65 reference light),
-   * - csc_XYZCIED65toRGB: XYZ to RGB (D65 reference light),
-   * - csc_RGBtoHSV: RGB to HSV,
-   * - csc_HSVtoRGB: HSV to RGB,
-   * - csc_RGBtoHLS: RGB to HSV,
-   * - csc_HLStoRGB: HSV to RGB,
-   * - csc_RGBtoCIELab: RGB to CIELab,
-   * - csc_CIELabtoRGB: CIELuv to RGB,
-   * - csc_RGBtoCIELuv: RGB to CIELuv,
-   * - csc_CIELuvtoRGB: CIELuv to RGB,
-   * - csc_RGBtoYUV: RGB to YUV color space,
-   * - csc_RGBtoYIQ: RGB to YIQ color space.
-   *
-   */
-
-  void ColorSpace(ColorSpaceConvertType transformation);
-
-  /*!
-   * @brief Convert an image to grayscale
-   *
-   * @param grayscale_mode mode of grayscale conversation
-   *
-   * The function converts the image to grayscale version
-   * (one color channel after the conversion). There is four
-   * different ways to convert the image to grayscale what we
-   * can define with @a grayscale_mode:
-   *
-   *  - g_Average: It computes the average grayscale
-   * values of the pixels with arithmetical average.
-   *  - g_OpenCV: It computes the average grayscale
-   * values by help of the values of the Y channel.
-   *
-   */
-
-  void ConvertToGrayscale(GrayscaleType grayscale_mode = g_OpenCV);
-
-  /*!
-   * @brief Convert a grayscale image to RGB
-   *
-   * The function converts the grayscale image to RGB version.
-   * (It copies the info from a single color channel to
-   * three color channel.)
-   *
-   */
-
-  void ConvertGrayscaleToRGB();
-
-  /*!
-   * @brief Change the red and blue components of every pixels
-   *
-   * Function changes the red component with the blue of
-   * every pixels. (Simple conversion from RGB->BGR.)
-   *
-   */
-
-  void ConvertBGRToRGB();
-
-  /*!
-   * @brief Compute an LBP filter on the image
-   *
-   * @param mode The LBP operator type
-   *
-   * The function converts the image to binary version over the
-   * threshold value.
-   *
-   */
-
-  void LBP(LBPType mode = lbp_Special);
-
-  /*!
-   * @brief Binarize an image
-   *
-   * @param threshold Threshold value
-   *
-   * The function converts the image to binary version over the
-   * threshold value.
-   *
-   */
-
-  void Binarize(int threshold);
-
-  /*!
-   * @brief Subtract an image from the internal picture
-   *
-   * @param source Source image for subtraction
-   * @param mode Calculation mode of difference feature
-   *
-   * Function generates a difference image between two image:
-   * the internal picture of this class and @a source_image.
-   * The calculation mode is determined by @a mode parameter.
-   * Function supports the following modes:
-   *
-   *  - sub_Normal: Simple subtraction between each
-   * correspondent pixel (per color channels). The result values
-   * are converted to absolute value and normalized to
-   * range 0-255.
-   *
-   */
-
-  void Subtract(MEImage& source, SubtractModeType mode);
-
-  /*!
-   * @brief Multiple an image with the internal picture
-   *
-   * @param source Second source image for multiplication
-   * @param mode Multiplication mode
-   *
-   * Function multiples an image with the internal image of this class and
-   * the result is stored in the internal image. The implemented calculation
-   * modes:
-   *
-   *  - m_Normal: It multiples the corresponding pixel values
-   * of the two images. The original pixel values are divided by 128 and
-   * multiplied together. If the result is at least 1 then the new pixel value
-   * is 255 otherwise 0.
-   *  - m_Neighbourhood: It multiples all pixel values of its
-   * 3x3 neighbourhood separately (see the method at MULTIPLICATION_NORMAL)
-   * and the new pixel value is 255 if at least two pixel is active in the
-   * 3x3 neighbourhood otherwise 0.
-   *
-   */
-
-  void Multiple(MEImage& source, MultiplicationType mode);
-
-  /*!
-   * @brief Addition of an image and the internal picture
-   *
-   * @param source second source image for addition method
-   * @param mode the declaration of the used addition mode
-   *
-   * Function makes an addition operation between an image and the internal
-   * image of this class and the result is stored in the internal image.
-   * Supported modes:
-   *
-   *  - a_Average: It sums the average of the corresponding pixels
-   * of each pictures.
-   *  - a_Union: It sums the union of the corresponding pixels
-   * of each pictures.
-   *
-   */
-
-  void Addition(MEImage& source, AdditionType mode);
-
-  /*!
-   * @brief Eliminate the single pixels from a binary image
-   *
-   * Function eliminates such a pixels which do not have neighbour pixels with
-   * 255 value in a 3x3 neighbourhood. The image should be converted to binary
-   * version.
-   *
-   */
-
-  void EliminateSinglePixels();
-
-  /*!
-   * @brief Calculate an area difference feature between two images
-   *
-   * @param reference Reference image
-   * @param difference Difference
-   *
-   * @return The percentage of image areas representing the conditions
-   *
-   * Function calculates a similarity feature between two pictures.
-   * Counts the number of the pixels whose intensity difference is
-   * higher than @a difference. (Range: 0..100)
-   *
-   */
-
-  float DifferenceAreas(MEImage& reference, int difference) const;
-
-  /*!
-   * @brief Calculate an average difference between two images
-   *
-   * @param reference Reference image
-   *
-   * @return Average difference of the pixels
-   *
-   * Function calculates a similarity feature between
-   * two images. It returns a simple sum of the absolute difference
-   * of each pixel in the two images and averaged by the pixel number.
-   * (Range: 0..255)
-   *
-   */
-
-  int AverageDifference(MEImage& reference) const;
-
-  /*!
-   * @brief Calculate minimum of image data
-   *
-   * @param image Second image
-   *
-   * Function calculates the minimum of current and given image.
-   *
-   */
-
-  void Minimum(MEImage& image);
-
-  /*!
-   * @brief Calculate average brightness level
-   *
-   * @return Brightness level in range 0-255.
-   *
-   * Function calculates the average brightness level of the image.
-   *
-   */
-
-  float AverageBrightnessLevel() const;
-
-  /*!
-   * @brief Check the equalization with a reference image
-   *
-   * @param reference Reference image
-   *
-   * @return true in case of binary equalization, otherwise false.
-   *
-   * Function calculates the binary difference between
-   * the image and the reference image.
-   *
-   */
-
-  bool Equal(const MEImage& reference) const;
-
-  /*!
-   * @brief Check the equalization with a reference image
-   *
-   * @param reference Reference image
-   * @param maxabsdiff Maximal absolute difference
-   *
-   * @return true in case of equalization, otherwise false.
-   *
-   * Function checks the difference between the image and
-   * the reference image. Two pixels are equal in a range of
-   * a maximal absolute difference.
-   *
-   */
-
-  bool Equal(const MEImage& reference, int maxabsdiff) const;
-
-  /*!
-   * @brief Get the grayscale value of a pixel
-   *
-   * @param x X coordinate of the pixel
-   * @param y Y coordinate of the pixel
-   *
-   * @return grayscale value of the pixel
-   *
-   * The method gives the grayscale value of a pixel back. If
-   * the image has 3 color channels (e.g. RGB) then Y value of
-   * YIQ/YUV color space will be calculated otherwise normal
-   * averaged grayscale value.
-   *
-   */
-
-  unsigned char GrayscalePixel(int x, int y) const;
-
-  /*!
-   * @brief Count the number of neighbourhood pixels with maximum intensity
-   *
-   * @param startx X coordinate of the top-left pixel
-   * @param starty Y coordinate of the top-left pixel
-   * @param neighbourhood Specific subset of pixels
-   *
-   * @return number of the pixels with maximum intensity.
-   *
-   * The method counts the number of the pixels with maximum
-   * intensity (255) in a specified subset of pixels.
-   * The grayscale values of the pixels are used in the counter
-   * process. The following neighbourhood forms are allowed with
-   * the @a neighbourhood parameter:
-   *
-   *  - n_2X2: Simple 2x2 matrix.
-   *  - n_3X3: Simple 3x3 matrix.
-   *  - n_3x2: Simple 3x2 matrix.
-   *
-   */
-
-  int NeighbourhoodCounter(int startx, int starty, NeighbourhoodType neighbourhood) const;
-
-  /*!
-   * @brief Calculate the gradient vector in a point
-   *
-   * @param smooth compute smooth filter
-   * @param x X coordinate of the point
-   * @param y Y coordinate of the point
-   * @param mask_size The mask size to calculate the gradient
-   *
-   * @param result_x X component of the calculated vector
-   * @param result_y Y component of the calculated vector
-   *
-   * The method calculates the gradient vector in a given point.
-   * The image is preprocessed with a Gauss filter to smooth the
-   * image content. The filter size of the Gauss filter depends on
-   * mask size of the gradient vector: filter size = mask size*3.
-   * Eight points are assigned to the initial point to compute
-   * a vector sum: (x, y-mask_size), (x+mask_size/√2, y-mask_size/√2),
-   * (x+mask_size, y), (x+mask_size/√2, y+mask_size/√2), (x, y+mask_size),
-   * (x-mask_size/√2, y+mask_size/√2), (x-mask_size, y), (x-mask_size/√2, y-mask_size/√2).
-   * The lengths of all vectors equalize with the mask size.
-   * After that each vector is multiplied with the gradient difference between
-   * its two end points. The results are summarized and normalized by
-   * the mask size.
-   *
-   */
-
-  void GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y);
-
-  /*!
-   * @brief Visualize gradient vectors
-   *
-   * @param vector_x Number of points horizontally
-   * @param vector_y Number of points vertically
-   *
-   * This function draws a wire (@a vector_x * @a vector_y) with
-   * gradient vectors.
-   *
-   */
-
-  void GradientVisualize(int vector_x, int vector_y);
-
-private:
-
-  /*
-  -------------------------------------------------------------------
-                          Internal methods
-  -------------------------------------------------------------------
-  */
-
-  /*!
-   * @brief Copy image data
-   *
-   * @param other_image Input image with new image data
-   *
-   * @return true if it is successful, otherwise false.
-   *
-   * Copy image data from @a other_image to MEImage image data.
-   *
-   */
-
-  bool _Copy(const MEImage& other_image);
-
-  /*!
-   * @brief Inherent initialization function
-   *
-   * @param width Width of the image
-   * @param height Height of the image
-   * @param layer Number of color channels of the image
-   *
-   * Initialization function of MEImage class which allocates
-   * memory to internal MEImage image and sets its properties.
-   *
-   */
-
-  void _Init(int width, int height, int layer);
-
-  /*!
-   * @brief Compute an image to a different color space
-   *
-   * @param mode Mode of the conversion
-   *
-   * Currently, the internal function allows to use a few
-   * mode to convert an image between color spaces.
-   * Current supported conversions (@a mode):
-   * - RGBtoYUV: RGB to YUV color space,
-   * - RGBtoYIQ: RGB to YIQ color space.
-   *
-   */
-
-  void ComputeColorSpace(ColorSpaceConvertType mode);
-
-private:
-  /// This matrix stores the matrix of the actual color space transform
-  float TransformMatrix[3][3];
-  /// The OpenCV image which contains the image data
-  void* cvImg;
-};
+  namespace algorithms
+  {
+    namespace lbp_mrf
+    {
+      /**
+       * MEImage
+       * @brief Basic image functions
+       */
+      class MEImage
+      {
+      public:
+        /// Types of LBP operator
+        typedef enum {
+          lbp_Min = 0,          /*!< Minimum value */
+          lbp_Normal = lbp_Min, /*!< Normal LBP pattern */
+          lbp_Special,          /*!< Special LBP pattern */
+          lbp_Max = lbp_Special /*!< Maximum value */
+        } LBPType;
+
+        /// Types of image subtraction
+        typedef enum {
+          sub_Min = 0,          /*!< Minimum value */
+          sub_Normal = sub_Min, /*!< Normal */
+          sub_Absolut,          /*!< Absolut */
+          sub_Max = sub_Absolut /*!< Maximum value */
+        } SubtractModeType;
+
+        /// Types of image addition
+        typedef enum {
+          a_Min = 0,         /*!< Minimum value */
+          a_Average = a_Min, /*!< Average */
+          a_Union,           /*!< Union */
+          a_Max = a_Union    /*!< Maximum value */
+        } AdditionType;
+
+        /// Types of image multiplication
+        typedef enum {
+          m_Min = 0,              /*!< Minimum value */
+          m_Normal = m_Min,       /*!< Normal */
+          m_Neighbourhood,        /*!< Neighbourhood */
+          m_Max = m_Neighbourhood /*!< Maximum value */
+        } MultiplicationType;
+
+        /// Types of grayscale conversation
+        typedef enum {
+          g_Min = 0,         /*!< Minimum value */
+          g_Average = g_Min, /*!< Average */
+          g_OpenCV,          /*!< OpenCV */
+          g_Max = g_OpenCV   /*!< Maximum value */
+        } GrayscaleType;
+
+        /// Types of pixel neighbourhoods
+        typedef enum {
+          n_Min = 0,     /*!< Minimum value */
+          n_2x2 = n_Min, /*!< 2x2 */
+          n_3x2,         /*!< 3x2 */
+          n_3x3,         /*!< 3x3 */
+          n_5x5,         /*!< 5x5 */
+          n_7x7,         /*!< 7x7 */
+          n_Max = n_7x7  /*!< Maximum value */
+        } NeighbourhoodType;
+
+        /// Types of special pixels
+        typedef enum {
+          p_Min = 0,         /*!< Minimum value */
+          p_Minimum = p_Min, /*!< Minimum */
+          p_Maximum,         /*!< Maximum */
+          p_Counter,         /*!< Counter */
+          p_Max = p_Counter  /*!< Maximum value */
+        } PixelType;
+
+        /// Types of smooth operation
+        typedef enum {
+          s_Min = 0,       /*!< Minimum value */
+          s_Blur = s_Min,  /*!< Blur */
+          s_Gaussian,      /*!< Gaussian */
+          s_Median,        /*!< Medium */
+          s_Max = s_Median /*!< Maximum value */
+        } SmoothType;
+
+        /// Types of color space conversions
+        typedef enum {
+          csc_Min = 0,                  /*!< Minimum value */
+          csc_RGBtoXYZCIED65 = csc_Min, /*!< RGB to XYZCIED65 */
+          csc_XYZCIED65toRGB,           /*!< XYZCIED65 to RGB */
+          csc_RGBtoHSV,                 /*!< RGB to HSV */
+          csc_HSVtoRGB,                 /*!< HSV to RGB */
+          csc_RGBtoHLS,                 /*!< RGB to HLS */
+          csc_HLStoRGB,                 /*!< HLS to RGB */
+          csc_RGBtoCIELab,              /*!< RGB to CIELab */
+          csc_CIELabtoRGB,              /*!< CIELab to RGB */
+          csc_RGBtoCIELuv,              /*!< RGB to CIELuv */
+          csc_CIELuvtoRGB,              /*!< CIELuv to RGB */
+          csc_RGBtoYUV,                 /*!< RGB to YUV */
+          csc_RGBtoYIQ,                 /*!< RGB to YIQ */
+          csc_RGBtorgI,                 /*!< RGB to rgI */
+          csc_Max = csc_RGBtorgI        /*!< Maximum value */
+        } ColorSpaceConvertType;
+
+        /*!
+        * @brief Class constructor
+        *
+        * @param width Image width
+        * @param height Image height
+        * @param layers Layers
+        *
+        * Class constructor with the possibility to specify the image width,
+        * height and the layers. The default options are 16x16x1.
+        *
+        */
+
+        MEImage(int width = 16, int height = 16, int layers = 1);
+
+        /*!
+        * @brief Class constructor
+        *
+        * @param other Other image
+        *
+        * Class constructor with the possibility to specify the image width,
+        * height and the layers. The default options are 16x16x1.
+        *
+        */
+
+        MEImage(const MEImage& other);
+        /// Destructor of class
+        ~MEImage();
+
+        /*
+        -------------------------------------------------------------------
+                                Basic functions
+        -------------------------------------------------------------------
+        */
+
+        /*!
+        * @brief Clear image
+        *
+        * This function clears image by filling all image data with zero
+        * value.
+        *
+        */
+
+        void Clear();
+
+        /*!
+        * @brief Get an color layer of image
+        *
+        * @param new_layer new image of layer
+        * @param layernumber number of layer which will be copied
+        *
+        * Copy an image layer (R, G or B) to @a new_layer image. @a new_layer has to
+        * have only one color layer (greyscale). If @a new_layer is not
+        * greyscale or it has got different width or height like source image
+        * than function reallocates it with appropriate features before
+        * copying image data.
+        *
+        */
+
+        void GetLayer(MEImage& new_layer, int layernumber) const;
+
+        /*!
+        * @brief Copy a new color layer to image
+        *
+        * @param new_layer image data of new color layer
+        * @param layernumber number of layer where image data will copy
+        *
+        * Copy a new image layer from @a new_layer image. @a new_layer has to
+        * have only one color layer (greyscale). If @a new_layer is not
+        * greyscale or it has got different width or height like source image
+        * than function halts with an error message.
+        *
+        */
+
+        void SetLayer(MEImage& new_layer, int layernumber);
+
+        /*!
+        * @brief Copy image data to a pointer
+        *
+        * @param data pointer where image data will be copied
+        *
+        * Function in order to acquire image data to an external
+        * (unsigned char*) pointer.
+        *
+        */
+
+        void CopyImageData(unsigned char* data);
+
+        /*!
+        * @brief Get a pointer to the internal IplImage
+        *
+        * @return Pointer to the IplImage
+        *
+        * This function returns the internal IplImage of the class. The
+        * image data can not be modified.
+        *
+        */
+
+        void* GetIplImage() const;
+
+        /*!
+        * @brief Set the internal IplImage
+        *
+        * @param image Pointer to the IplImage
+        *
+        * This function sets the internal IplImage of the class.
+        *
+        */
+
+        void SetIplImage(void* image);
+
+        /*!
+        * @brief Handle operator == for MEImage
+        *
+        * @param image image to check
+        *
+        * @return true if the images are equal otherwise false.
+        *
+        * The operator checks the equality of two images.
+        *
+        */
+
+        bool operator==(const MEImage& image);
+
+        /*!
+        * @brief Handle operator != for MEImage
+        *
+        * @param image image to check
+        *
+        * @return true if the images are not equal otherwise false.
+        *
+        * The operator checks the non-equality of two images.
+        *
+        */
+
+        bool operator!=(const MEImage& image);
+
+        /*!
+        * @brief Handle operator = for MEImage
+        *
+        * @param other_image image to copy operation
+        *
+        * @return Reference to the actual instance.
+        *
+        * Copy image data to @a other_image image. Function calls only
+        * _Copy() directly.
+        *
+        */
+
+        MEImage& operator=(const MEImage& other_image);
+
+        /*!
+        * @brief Get the width of the image
+        *
+        * @return Width of the image
+        *
+        * Get the width of the image.
+        *
+        */
+
+        int GetWidth() const;
+
+        /*!
+        * @brief Get the height of the image
+        *
+        * @return Height of the image
+        *
+        * Get the height of the image.
+        */
+
+        int GetHeight() const;
+
+        /*!
+        * @brief Get the length of a pixel row of the image
+        *
+        * @return Length of a pixel row
+        *
+        * Get the row width of the image.
+        *
+        */
+
+        int GetRowWidth() const;
+
+        /*!
+        * @brief Get the number of color layers of the image
+        *
+        * @return Number of color layer of the image
+        *
+        * Get the number of color layer of the image.
+        *
+        */
+
+        int GetLayers() const;
+
+        /*!
+        * @brief Get the number of the image pixel data
+        *
+        * @return Number of the image pixel data
+        *
+        * Get the number of the image pixel data.
+        *
+        */
+
+        int GetPixelDataNumber() const;
+
+        /*!
+        * @brief Get the image data
+        *
+        * @return Pointer to the image data
+        *
+        * Get a pointer to the image.
+        *
+        */
+
+        unsigned char* GetImageData() const;
+
+        /*!
+        * @brief Set the image data
+        *
+        * @param image_data New image data
+        * @param width New image width
+        * @param height New image height
+        * @param channels New image color channels
+        *
+        * Get a pointer to the image.
+        *
+        */
+
+        void SetData(unsigned char* image_data, int width, int height, int channels);
+
+        /*!
+        * @brief Get ratio of image width and height
+        *
+        * @return float ratio of image dimensions
+        *
+        * Function calculates ratio of image width and height with
+        * following equation: ratio = height / width.
+        */
+
+        float GetRatio() const;
+
+        /*
+        -------------------------------------------------------------------
+                            Basic image manipulation
+        -------------------------------------------------------------------
+        */
+
+        /*!
+        * @brief Reallocate image data
+        *
+        * @param width New width of the image
+        * @param height New height of the image
+        *
+        * Image data will be reallocated with new dimensions @a width
+        * and @a height. Number of color channels is not changed.
+        *
+        */
+
+        void Realloc(int width, int height);
+
+        /*!
+        * @brief Reallocate image data
+        *
+        * @param width New width of the image
+        * @param height New height of the image
+        * @param layers Number of color channels of the image
+        *
+        * Image data will be reallocated with new dimensions @a width,
+        * @a height and new number of color channels @a layers.
+        *
+        */
+
+        void Realloc(int width, int height, int layers);
+
+        /*!
+        * @brief Resize image
+        *
+        * @param newwidth new width of image
+        * @param newheight new height of image
+        *
+        * Resize image to @a newwidth width and @a newheight
+        * height dimensions.
+        *
+        */
+
+        void Resize(int newwidth, int newheight);
+
+        /*!
+        * @brief Resize image with new width
+        *
+        * @param newwidth new width of image
+        *
+        * Image is resized with only new width information therefore
+        * fit to original ratio.
+        *
+        */
+
+        void ResizeScaleX(int newwidth);
+
+        /*!
+        * @brief Resize image with new height
+        *
+        * @param newheight new height of image
+        *
+        * Image is resized with only new height information therefore
+        * fit to original ratio.
+        *
+        */
+
+        void ResizeScaleY(int newheight);
+
+        /*!
+        * @brief Reverse image in horizontal direction
+        *
+        * Function makes a mirror transformation on image in horizontal
+        * direction.
+        *
+        */
+
+        void MirrorHorizontal();
+
+        /*!
+        * @brief Reverse image in vertical direction
+        *
+        * Function makes a mirror transformation on image in vertical
+        * direction.
+        *
+        */
+
+        void MirrorVertical();
+
+        /*!
+        * @brief Crop image
+        *
+        * @param x1, y1 coordinates of top-left point of rectangle
+        * @param x2, y2 coordinates of bottom-right point of rectangle
+        *
+        * Crop the image in a smaller piece whose dimensions are
+        * specified as a rectangle. Top-left and bottom-right
+        * coordinates of rectangle are (x1, y1) and (x2, y2) wherefrom
+        * comes that the width of the new image is x2-x1 and height is
+        * y2-y1.
+        *
+        */
+
+        void Crop(int x1, int y1, int x2, int y2);
+
+        /*!
+        * @brief Copy all image data from an other picture
+        *
+        * @param x0 x coordinate to paste the new image data
+        * @param y0 y coordinate to paste the new image data
+        * @param source_image source image
+        *
+        * Function copies all image data from @a source_image
+        * to the given coordinate (x0,y0).
+        *
+        */
+
+        void CopyImageInside(int x0, int y0, MEImage& source_image);
+
+        /*
+        -------------------------------------------------------------------
+                          Image processing functions
+        -------------------------------------------------------------------
+        */
+
+        /*!
+        * @brief Erode function
+        *
+        * @param iterations iterations of erode method
+        *
+        * Method makes an erode filter on an image @a iterations
+        * times with standard 3x3 matrix size.
+        *
+        */
+
+        void Erode(int iterations);
+
+        /*!
+        * @brief Dilate function
+        *
+        * @param iterations iterations of dilate method
+        *
+        * Method makes an dilate filter on an image
+        * @a iterations times with standard 3x3 matrix size.
+        *
+        */
+
+        void Dilate(int iterations);
+
+        /*!
+        * @brief Smooth function
+        *
+        * Method smooths with median filter and standard 3x3 matrix size.
+        * (Median filter works fine and fast.)
+        *
+        */
+
+        void Smooth();
+
+        /*!
+        * @brief Smooth function with defined parameters
+        *
+        * @param filtermode type of smooth method
+        * @param filtersize the size of the convolution matrix
+        *
+        * Method smooths with median filter and the given matrix
+        * size (@a filtersize x @a filtersize). There are more
+        * types of smooth function (@a filtermode):
+        *
+        * - s_Blur: Blur filter.
+        * - s_Gaussian: Gaussian filter.
+        * - s_Median: Median filter.
+        *
+        */
+
+        void SmoothAdvanced(SmoothType filtermode, int filtersize);
+
+        /*!
+        * @brief Canny function
+        *
+        * Canny operator is usable for edge detection. Function makes
+        * this operation with standard 3x3 matrix
+        * size. Canny has two threshold value which are set to zero
+        * in this function by default.
+        *
+        */
+
+        void Canny();
+
+        /*!
+        * @brief Laplace function
+        *
+        * Laplace operator is usable for edge detection like Canny.
+        * This function makes a laplace filter with
+        * standard 3x3 matrix size. After calculating destination image will
+        * be converted from 16 bit back to 8 bit.
+        *
+        */
+
+        void Laplace();
+
+        /*!
+        * @brief Image quantisation
+        *
+        * @param levels level of quantisation
+        *
+        * Quantize an image with @a levels level. It means by 16
+        * level color range 0-255 quantizes to 0-15, by 4 level to 0-63 etc.
+        *
+        */
+
+        void Quantize(int levels);
+
+        /*!
+        * @brief Threshold a picture
+        *
+        * @param threshold_limit limit for threshold
+        *
+        * Threshold an image with @a threshold_limit limit. Value range
+        * of @a threshold_limit is between 0-255. E.g. by value 160 functions
+        * will eliminate all color values under 160 with black color
+        * (color value zero).
+        *
+        */
+
+        void Threshold(int threshold_limit);
+
+        /*!
+        * @brief Adaptive threshold function
+        *
+        * This function does adaptive threshold function.
+        *
+        */
+
+        void AdaptiveThreshold();
+
+        /*!
+        * @brief Threshold a picture by a mask image
+        *
+        * @param mask_image mask image for thresholding
+        *
+        * Threshold an image with a mask image @a mask_image.
+        *
+        */
+
+        void ThresholdByMask(MEImage& mask_image);
+
+        /*!
+        * @brief Convert an image into a new color space
+        *
+        * @param transformation Definition of color transformation
+        *
+        * This function converts an image from a specified color space
+        * to an other.
+        * Current supported conversions (@a transformation):
+        * - csc_RGBtoXYZCIED65: RGB to XYZ (D65 reference light),
+        * - csc_XYZCIED65toRGB: XYZ to RGB (D65 reference light),
+        * - csc_RGBtoHSV: RGB to HSV,
+        * - csc_HSVtoRGB: HSV to RGB,
+        * - csc_RGBtoHLS: RGB to HSV,
+        * - csc_HLStoRGB: HSV to RGB,
+        * - csc_RGBtoCIELab: RGB to CIELab,
+        * - csc_CIELabtoRGB: CIELuv to RGB,
+        * - csc_RGBtoCIELuv: RGB to CIELuv,
+        * - csc_CIELuvtoRGB: CIELuv to RGB,
+        * - csc_RGBtoYUV: RGB to YUV color space,
+        * - csc_RGBtoYIQ: RGB to YIQ color space.
+        *
+        */
+
+        void ColorSpace(ColorSpaceConvertType transformation);
+
+        /*!
+        * @brief Convert an image to grayscale
+        *
+        * @param grayscale_mode mode of grayscale conversation
+        *
+        * The function converts the image to grayscale version
+        * (one color channel after the conversion). There is four
+        * different ways to convert the image to grayscale what we
+        * can define with @a grayscale_mode:
+        *
+        *  - g_Average: It computes the average grayscale
+        * values of the pixels with arithmetical average.
+        *  - g_OpenCV: It computes the average grayscale
+        * values by help of the values of the Y channel.
+        *
+        */
+
+        void ConvertToGrayscale(GrayscaleType grayscale_mode = g_OpenCV);
+
+        /*!
+        * @brief Convert a grayscale image to RGB
+        *
+        * The function converts the grayscale image to RGB version.
+        * (It copies the info from a single color channel to
+        * three color channel.)
+        *
+        */
+
+        void ConvertGrayscaleToRGB();
+
+        /*!
+        * @brief Change the red and blue components of every pixels
+        *
+        * Function changes the red component with the blue of
+        * every pixels. (Simple conversion from RGB->BGR.)
+        *
+        */
+
+        void ConvertBGRToRGB();
+
+        /*!
+        * @brief Compute an LBP filter on the image
+        *
+        * @param mode The LBP operator type
+        *
+        * The function converts the image to binary version over the
+        * threshold value.
+        *
+        */
+
+        void LBP(LBPType mode = lbp_Special);
+
+        /*!
+        * @brief Binarize an image
+        *
+        * @param threshold Threshold value
+        *
+        * The function converts the image to binary version over the
+        * threshold value.
+        *
+        */
+
+        void Binarize(int threshold);
+
+        /*!
+        * @brief Subtract an image from the internal picture
+        *
+        * @param source Source image for subtraction
+        * @param mode Calculation mode of difference feature
+        *
+        * Function generates a difference image between two image:
+        * the internal picture of this class and @a source_image.
+        * The calculation mode is determined by @a mode parameter.
+        * Function supports the following modes:
+        *
+        *  - sub_Normal: Simple subtraction between each
+        * correspondent pixel (per color channels). The result values
+        * are converted to absolute value and normalized to
+        * range 0-255.
+        *
+        */
+
+        void Subtract(MEImage& source, SubtractModeType mode);
+
+        /*!
+        * @brief Multiple an image with the internal picture
+        *
+        * @param source Second source image for multiplication
+        * @param mode Multiplication mode
+        *
+        * Function multiples an image with the internal image of this class and
+        * the result is stored in the internal image. The implemented calculation
+        * modes:
+        *
+        *  - m_Normal: It multiples the corresponding pixel values
+        * of the two images. The original pixel values are divided by 128 and
+        * multiplied together. If the result is at least 1 then the new pixel value
+        * is 255 otherwise 0.
+        *  - m_Neighbourhood: It multiples all pixel values of its
+        * 3x3 neighbourhood separately (see the method at MULTIPLICATION_NORMAL)
+        * and the new pixel value is 255 if at least two pixel is active in the
+        * 3x3 neighbourhood otherwise 0.
+        *
+        */
+
+        void Multiple(MEImage& source, MultiplicationType mode);
+
+        /*!
+        * @brief Addition of an image and the internal picture
+        *
+        * @param source second source image for addition method
+        * @param mode the declaration of the used addition mode
+        *
+        * Function makes an addition operation between an image and the internal
+        * image of this class and the result is stored in the internal image.
+        * Supported modes:
+        *
+        *  - a_Average: It sums the average of the corresponding pixels
+        * of each pictures.
+        *  - a_Union: It sums the union of the corresponding pixels
+        * of each pictures.
+        *
+        */
+
+        void Addition(MEImage& source, AdditionType mode);
+
+        /*!
+        * @brief Eliminate the single pixels from a binary image
+        *
+        * Function eliminates such a pixels which do not have neighbour pixels with
+        * 255 value in a 3x3 neighbourhood. The image should be converted to binary
+        * version.
+        *
+        */
+
+        void EliminateSinglePixels();
+
+        /*!
+        * @brief Calculate an area difference feature between two images
+        *
+        * @param reference Reference image
+        * @param difference Difference
+        *
+        * @return The percentage of image areas representing the conditions
+        *
+        * Function calculates a similarity feature between two pictures.
+        * Counts the number of the pixels whose intensity difference is
+        * higher than @a difference. (Range: 0..100)
+        *
+        */
+
+        float DifferenceAreas(MEImage& reference, int difference) const;
+
+        /*!
+        * @brief Calculate an average difference between two images
+        *
+        * @param reference Reference image
+        *
+        * @return Average difference of the pixels
+        *
+        * Function calculates a similarity feature between
+        * two images. It returns a simple sum of the absolute difference
+        * of each pixel in the two images and averaged by the pixel number.
+        * (Range: 0..255)
+        *
+        */
+
+        int AverageDifference(MEImage& reference) const;
+
+        /*!
+        * @brief Calculate minimum of image data
+        *
+        * @param image Second image
+        *
+        * Function calculates the minimum of current and given image.
+        *
+        */
+
+        void Minimum(MEImage& image);
+
+        /*!
+        * @brief Calculate average brightness level
+        *
+        * @return Brightness level in range 0-255.
+        *
+        * Function calculates the average brightness level of the image.
+        *
+        */
+
+        float AverageBrightnessLevel() const;
+
+        /*!
+        * @brief Check the equalization with a reference image
+        *
+        * @param reference Reference image
+        *
+        * @return true in case of binary equalization, otherwise false.
+        *
+        * Function calculates the binary difference between
+        * the image and the reference image.
+        *
+        */
+
+        bool Equal(const MEImage& reference) const;
+
+        /*!
+        * @brief Check the equalization with a reference image
+        *
+        * @param reference Reference image
+        * @param maxabsdiff Maximal absolute difference
+        *
+        * @return true in case of equalization, otherwise false.
+        *
+        * Function checks the difference between the image and
+        * the reference image. Two pixels are equal in a range of
+        * a maximal absolute difference.
+        *
+        */
+
+        bool Equal(const MEImage& reference, int maxabsdiff) const;
+
+        /*!
+        * @brief Get the grayscale value of a pixel
+        *
+        * @param x X coordinate of the pixel
+        * @param y Y coordinate of the pixel
+        *
+        * @return grayscale value of the pixel
+        *
+        * The method gives the grayscale value of a pixel back. If
+        * the image has 3 color channels (e.g. RGB) then Y value of
+        * YIQ/YUV color space will be calculated otherwise normal
+        * averaged grayscale value.
+        *
+        */
+
+        unsigned char GrayscalePixel(int x, int y) const;
+
+        /*!
+        * @brief Count the number of neighbourhood pixels with maximum intensity
+        *
+        * @param startx X coordinate of the top-left pixel
+        * @param starty Y coordinate of the top-left pixel
+        * @param neighbourhood Specific subset of pixels
+        *
+        * @return number of the pixels with maximum intensity.
+        *
+        * The method counts the number of the pixels with maximum
+        * intensity (255) in a specified subset of pixels.
+        * The grayscale values of the pixels are used in the counter
+        * process. The following neighbourhood forms are allowed with
+        * the @a neighbourhood parameter:
+        *
+        *  - n_2X2: Simple 2x2 matrix.
+        *  - n_3X3: Simple 3x3 matrix.
+        *  - n_3x2: Simple 3x2 matrix.
+        *
+        */
+
+        int NeighbourhoodCounter(int startx, int starty, NeighbourhoodType neighbourhood) const;
+
+        /*!
+        * @brief Calculate the gradient vector in a point
+        *
+        * @param smooth compute smooth filter
+        * @param x X coordinate of the point
+        * @param y Y coordinate of the point
+        * @param mask_size The mask size to calculate the gradient
+        *
+        * @param result_x X component of the calculated vector
+        * @param result_y Y component of the calculated vector
+        *
+        * The method calculates the gradient vector in a given point.
+        * The image is preprocessed with a Gauss filter to smooth the
+        * image content. The filter size of the Gauss filter depends on
+        * mask size of the gradient vector: filter size = mask size*3.
+        * Eight points are assigned to the initial point to compute
+        * a vector sum: (x, y-mask_size), (x+mask_size/√2, y-mask_size/√2),
+        * (x+mask_size, y), (x+mask_size/√2, y+mask_size/√2), (x, y+mask_size),
+        * (x-mask_size/√2, y+mask_size/√2), (x-mask_size, y), (x-mask_size/√2, y-mask_size/√2).
+        * The lengths of all vectors equalize with the mask size.
+        * After that each vector is multiplied with the gradient difference between
+        * its two end points. The results are summarized and normalized by
+        * the mask size.
+        *
+        */
+
+        void GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y);
+
+        /*!
+        * @brief Visualize gradient vectors
+        *
+        * @param vector_x Number of points horizontally
+        * @param vector_y Number of points vertically
+        *
+        * This function draws a wire (@a vector_x * @a vector_y) with
+        * gradient vectors.
+        *
+        */
+
+        void GradientVisualize(int vector_x, int vector_y);
+
+      private:
+
+        /*
+        -------------------------------------------------------------------
+                                Internal methods
+        -------------------------------------------------------------------
+        */
+
+        /*!
+        * @brief Copy image data
+        *
+        * @param other_image Input image with new image data
+        *
+        * @return true if it is successful, otherwise false.
+        *
+        * Copy image data from @a other_image to MEImage image data.
+        *
+        */
+
+        bool _Copy(const MEImage& other_image);
+
+        /*!
+        * @brief Inherent initialization function
+        *
+        * @param width Width of the image
+        * @param height Height of the image
+        * @param layer Number of color channels of the image
+        *
+        * Initialization function of MEImage class which allocates
+        * memory to internal MEImage image and sets its properties.
+        *
+        */
+
+        void _Init(int width, int height, int layer);
+
+        /*!
+        * @brief Compute an image to a different color space
+        *
+        * @param mode Mode of the conversion
+        *
+        * Currently, the internal function allows to use a few
+        * mode to convert an image between color spaces.
+        * Current supported conversions (@a mode):
+        * - RGBtoYUV: RGB to YUV color space,
+        * - RGBtoYIQ: RGB to YIQ color space.
+        *
+        */
+
+        void ComputeColorSpace(ColorSpaceConvertType mode);
+
+      private:
+        /// This matrix stores the matrix of the actual color space transform
+        float TransformMatrix[3][3];
+        /// The OpenCV image which contains the image data
+        void* cvImg;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBP_MRF/MotionDetection.cpp b/src/algorithms/LBP_MRF/MotionDetection.cpp
index 59dde1583bacc2979f55bedff492891d06a53e4a..b434806ad248ddfce5a28d5abe809a00c337ab24 100644
--- a/src/algorithms/LBP_MRF/MotionDetection.cpp
+++ b/src/algorithms/LBP_MRF/MotionDetection.cpp
@@ -9,1454 +9,1461 @@
 #include "MEHistogram.hpp"
 #include "MEImage.hpp"
 
-using namespace ck;
-
-// Pyramid picture for the tracking
-IplImage *HUOFPyramid;
-// Pyramid picture for the tracking
-IplImage *HUOFPrevPyramid;
-
-// Struct for histogram update data of a pixel
-struct MEPixelDataType
-{
-  float BackgroundRate;
-  int LifeCycle;
-  float *Weights;
-  bool *BackgroundHistogram;
-  float **Histograms;
-  float *PreviousHistogram;
-};
-
-MotionDetection::MotionDetection(DetectorType mode) :
-  MDMode(md_NotDefined), MDDataState(ps_Uninitialized), Frames(0), ReadyMask(false),
-  HUColorSpace(MEImage::csc_RGBtoCIELuv), HULBPMode(MEImage::lbp_Special),
-  HUHistogramsPerPixel(3), HUHistogramArea(5), HUHistogramBins(8),
-  HUImageWidth(-1), HUImageHeight(-1), HULBPPixelData(NULL),
-  HUPrThres(0.75), HUBackgrThres(0.95), HUHistLRate(0.01), HUWeightsLRate(0.01),
-  HUSamplePixels(-1), HUDesiredSamplePixels(-1), HUMinCutWeight(8.0),
-  HUOFDataState(ps_Uninitialized), HUOFPointsNumber(-1),
-  HUOFCamMovementX(0), MaxTrackedPoints(0), HUOFFrames(-1),
-  HUOFCamMovement(false)
-{
-  HUOFPyramid = NULL;
-  HUOFPrevPyramid = NULL;
-  HUOFPoints[0] = NULL;
-  HUOFPoints[1] = NULL;
-  SetMode(mode);
-}
-
-MotionDetection::~MotionDetection()
+namespace bgslibrary
 {
-  if (MDMode != md_NotDefined)
+  namespace algorithms
   {
-    ReleaseData();
-  }
-}
+    namespace lbp_mrf
+    {
+      // Pyramid picture for the tracking
+      IplImage *HUOFPyramid;
+      // Pyramid picture for the tracking
+      IplImage *HUOFPrevPyramid;
 
-void MotionDetection::SetMode(DetectorType newmode)
-{
-  if (MDMode != md_NotDefined && MDMode != newmode)
-  {
-    ReleaseData();
-    Frames = 0;
-    HUOFFrames = -1;
-    HUOFCamMovement = false;
-    HUOFCamMovementX = 0;
-    ReadyMask = false;
-  }
+      // Struct for histogram update data of a pixel
+      struct MEPixelDataType
+      {
+        float BackgroundRate;
+        int LifeCycle;
+        float *Weights;
+        bool *BackgroundHistogram;
+        float **Histograms;
+        float *PreviousHistogram;
+      };
+
+      MotionDetection::MotionDetection(DetectorType mode) :
+        MDMode(md_NotDefined), MDDataState(ps_Uninitialized), Frames(0), ReadyMask(false),
+        HUColorSpace(MEImage::csc_RGBtoCIELuv), HULBPMode(MEImage::lbp_Special),
+        HUHistogramsPerPixel(3), HUHistogramArea(5), HUHistogramBins(8),
+        HUImageWidth(-1), HUImageHeight(-1), HULBPPixelData(NULL),
+        HUPrThres(0.75), HUBackgrThres(0.95), HUHistLRate(0.01), HUWeightsLRate(0.01),
+        HUSamplePixels(-1), HUDesiredSamplePixels(-1), HUMinCutWeight(8.0),
+        HUOFDataState(ps_Uninitialized), HUOFPointsNumber(-1),
+        HUOFCamMovementX(0), MaxTrackedPoints(0), HUOFFrames(-1),
+        HUOFCamMovement(false)
+      {
+        HUOFPyramid = NULL;
+        HUOFPrevPyramid = NULL;
+        HUOFPoints[0] = NULL;
+        HUOFPoints[1] = NULL;
+        SetMode(mode);
+      }
 
-  switch (newmode)
-  {
-  case md_LBPHistograms:
-    MDMode = md_LBPHistograms;
-    break;
+      MotionDetection::~MotionDetection()
+      {
+        if (MDMode != md_NotDefined)
+        {
+          ReleaseData();
+        }
+      }
 
-  case md_DLBPHistograms:
-    MDMode = md_DLBPHistograms;
-    break;
+      void MotionDetection::SetMode(DetectorType newmode)
+      {
+        if (MDMode != md_NotDefined && MDMode != newmode)
+        {
+          ReleaseData();
+          Frames = 0;
+          HUOFFrames = -1;
+          HUOFCamMovement = false;
+          HUOFCamMovementX = 0;
+          ReadyMask = false;
+        }
 
-  default:
-    MDMode = md_LBPHistograms;
-    break;
-  }
-}
+        switch (newmode)
+        {
+        case md_LBPHistograms:
+          MDMode = md_LBPHistograms;
+          break;
 
-float MotionDetection::GetParameter(ParametersType param) const
-{
-  float ret = 0.0;
+        case md_DLBPHistograms:
+          MDMode = md_DLBPHistograms;
+          break;
 
-  switch (param)
-  {
-  case mdp_HUProximityThreshold:
-    ret = (float)HUPrThres;
-    break;
+        default:
+          MDMode = md_LBPHistograms;
+          break;
+        }
+      }
 
-  case mdp_HUBackgroundThreshold:
-    ret = (float)HUBackgrThres;
-    break;
+      float MotionDetection::GetParameter(ParametersType param) const
+      {
+        float ret = 0.0;
 
-  case mdp_HUHistogramLearningRate:
-    ret = (float)HUHistLRate;
-    break;
+        switch (param)
+        {
+        case mdp_HUProximityThreshold:
+          ret = (float)HUPrThres;
+          break;
 
-  case mdp_HUWeightsLearningRate:
-    ret = (float)HUWeightsLRate;
-    break;
+        case mdp_HUBackgroundThreshold:
+          ret = (float)HUBackgrThres;
+          break;
 
-  case mdp_HUMinCutWeight:
-    ret = (float)HUMinCutWeight;
-    break;
+        case mdp_HUHistogramLearningRate:
+          ret = (float)HUHistLRate;
+          break;
 
-  case mdp_HUDesiredSamplePixels:
-    ret = (float)HUDesiredSamplePixels;
-    break;
+        case mdp_HUWeightsLearningRate:
+          ret = (float)HUWeightsLRate;
+          break;
 
-  case mdp_HUHistogramsPerPixel:
-    ret = (float)HUHistogramsPerPixel;
-    break;
+        case mdp_HUMinCutWeight:
+          ret = (float)HUMinCutWeight;
+          break;
 
-  case mdp_HUHistogramArea:
-    ret = (float)HUHistogramArea;
-    break;
+        case mdp_HUDesiredSamplePixels:
+          ret = (float)HUDesiredSamplePixels;
+          break;
 
-  case mdp_HUHistogramBins:
-    ret = (float)HUHistogramBins;
-    break;
+        case mdp_HUHistogramsPerPixel:
+          ret = (float)HUHistogramsPerPixel;
+          break;
 
-  case mdp_HUColorSpace:
-    ret = (float)HUColorSpace;
-    break;
+        case mdp_HUHistogramArea:
+          ret = (float)HUHistogramArea;
+          break;
 
-  case mdp_HULBPMode:
-    ret = (float)HULBPMode;
-    break;
+        case mdp_HUHistogramBins:
+          ret = (float)HUHistogramBins;
+          break;
 
-  default:
-    break;
-  }
-  return ret;
-}
+        case mdp_HUColorSpace:
+          ret = (float)HUColorSpace;
+          break;
 
-void MotionDetection::SetParameter(ParametersType param, float value)
-{
-  switch (param)
-  {
-  case mdp_HUProximityThreshold:
-    HUPrThres = (float)value;
-    break;
+        case mdp_HULBPMode:
+          ret = (float)HULBPMode;
+          break;
 
-  case mdp_HUBackgroundThreshold:
-    HUBackgrThres = (float)value;
-    break;
+        default:
+          break;
+        }
+        return ret;
+      }
 
-  case mdp_HUHistogramLearningRate:
-    HUHistLRate = (float)value;
-    break;
+      void MotionDetection::SetParameter(ParametersType param, float value)
+      {
+        switch (param)
+        {
+        case mdp_HUProximityThreshold:
+          HUPrThres = (float)value;
+          break;
 
-  case mdp_HUWeightsLearningRate:
-    HUWeightsLRate = (float)value;
-    break;
+        case mdp_HUBackgroundThreshold:
+          HUBackgrThres = (float)value;
+          break;
 
-  case mdp_HUMinCutWeight:
-    HUMinCutWeight = (float)value;
-    break;
+        case mdp_HUHistogramLearningRate:
+          HUHistLRate = (float)value;
+          break;
 
-  case mdp_HUDesiredSamplePixels:
-    HUDesiredSamplePixels = (int)value;
-    break;
+        case mdp_HUWeightsLearningRate:
+          HUWeightsLRate = (float)value;
+          break;
 
-  case mdp_HUHistogramsPerPixel:
-    HUHistogramsPerPixel = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramsPerPixel;
-    break;
+        case mdp_HUMinCutWeight:
+          HUMinCutWeight = (float)value;
+          break;
 
-  case mdp_HUHistogramArea:
-    HUHistogramArea = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramArea;
-    break;
+        case mdp_HUDesiredSamplePixels:
+          HUDesiredSamplePixels = (int)value;
+          break;
 
-  case mdp_HUHistogramBins:
-    HUHistogramBins = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramBins;
-    break;
+        case mdp_HUHistogramsPerPixel:
+          HUHistogramsPerPixel = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramsPerPixel;
+          break;
 
-  case mdp_HUColorSpace:
-    HUColorSpace = (MDDataState == ps_Uninitialized) ? (int)value : HUColorSpace;
-    break;
+        case mdp_HUHistogramArea:
+          HUHistogramArea = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramArea;
+          break;
 
-  case mdp_HULBPMode:
-    HULBPMode = (MDDataState == ps_Uninitialized) ? (int)value : HULBPMode;
-    break;
+        case mdp_HUHistogramBins:
+          HUHistogramBins = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramBins;
+          break;
 
-  default:
-    break;
-  }
-}
+        case mdp_HUColorSpace:
+          HUColorSpace = (MDDataState == ps_Uninitialized) ? (int)value : HUColorSpace;
+          break;
 
-void MotionDetection::DetectMotions(MEImage& image)
-{
-  switch (MDMode)
-  {
-  case md_LBPHistograms:
-  case md_DLBPHistograms:
-    DetectMotionsHU(image);
-    break;
+        case mdp_HULBPMode:
+          HULBPMode = (MDDataState == ps_Uninitialized) ? (int)value : HULBPMode;
+          break;
 
-  default:
-    break;
-  }
-}
+        default:
+          break;
+        }
+      }
 
-void MotionDetection::GetMotionsMask(MEImage& mask_image)
-{
-  if (ReadyMask)
-  {
-    mask_image = MaskImage;
-  }
+      void MotionDetection::DetectMotions(MEImage& image)
+      {
+        switch (MDMode)
+        {
+        case md_LBPHistograms:
+        case md_DLBPHistograms:
+          DetectMotionsHU(image);
+          break;
 
-  switch (MDMode)
-  {
-  case md_LBPHistograms:
-  case md_DLBPHistograms:
-    GetMotionsMaskHU(MaskImage);
-    break;
+        default:
+          break;
+        }
+      }
 
-  default:
-    break;
-  }
+      void MotionDetection::GetMotionsMask(MEImage& mask_image)
+      {
+        if (ReadyMask)
+        {
+          mask_image = MaskImage;
+        }
 
-  ReadyMask = true;
-  mask_image = MaskImage;
-}
+        switch (MDMode)
+        {
+        case md_LBPHistograms:
+        case md_DLBPHistograms:
+          GetMotionsMaskHU(MaskImage);
+          break;
 
-void MotionDetection::CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives,
-  int& ttnegatives, int& ttpositives)
-{
-  if (MDDataState != ps_Successful)
-  {
-    printf("No data for calculation.\n");
-    return;
-  }
+        default:
+          break;
+        }
 
-  if (referenceimage.GetLayers() != 1)
-    referenceimage.ConvertToGrayscale(MEImage::g_OpenCV);
+        ReadyMask = true;
+        mask_image = MaskImage;
+      }
 
-  referenceimage.Binarize(1);
+      void MotionDetection::CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives,
+        int& ttnegatives, int& ttpositives)
+      {
+        if (MDDataState != ps_Successful)
+        {
+          printf("No data for calculation.\n");
+          return;
+        }
 
-  MEImage mask_image;
+        if (referenceimage.GetLayers() != 1)
+          referenceimage.ConvertToGrayscale(MEImage::g_OpenCV);
 
-  GetMotionsMask(mask_image);
+        referenceimage.Binarize(1);
 
-  if ((mask_image.GetWidth() != referenceimage.GetWidth()) ||
-    (mask_image.GetHeight() != referenceimage.GetHeight()))
-  {
-    printf("Different resolutions of mask<->reference image.\n");
-    return;
-  }
+        MEImage mask_image;
 
-  unsigned char* RefMaskImgData = referenceimage.GetImageData();
-  unsigned char* MaskImgData = mask_image.GetImageData();
-  int RowStart = 0;
-  int RowWidth = referenceimage.GetRowWidth();
+        GetMotionsMask(mask_image);
 
-  int TrueNegatives = 0;
-  int TruePositives = 0;
-  int TotalTrueNegatives = 0;
-  int TotalTruePositives = 0;
+        if ((mask_image.GetWidth() != referenceimage.GetWidth()) ||
+          (mask_image.GetHeight() != referenceimage.GetHeight()))
+        {
+          printf("Different resolutions of mask<->reference image.\n");
+          return;
+        }
 
-  int ImageFrame = 0;
+        unsigned char* RefMaskImgData = referenceimage.GetImageData();
+        unsigned char* MaskImgData = mask_image.GetImageData();
+        int RowStart = 0;
+        int RowWidth = referenceimage.GetRowWidth();
 
-  if (MDMode == md_LBPHistograms || md_DLBPHistograms)
-  {
-    ImageFrame = HUHistogramArea / 2;
-  }
+        int TrueNegatives = 0;
+        int TruePositives = 0;
+        int TotalTrueNegatives = 0;
+        int TotalTruePositives = 0;
 
-  for (int y = referenceimage.GetHeight() - ImageFrame - 1; y >= ImageFrame; --y)
-  {
-    for (int x = referenceimage.GetWidth() - ImageFrame - 1; x >= ImageFrame; --x)
-    {
-      TrueNegatives +=
-        (RefMaskImgData[RowStart + x] == 0) &&
-        (MaskImgData[RowStart + x] == 0);
-      TotalTrueNegatives += (RefMaskImgData[RowStart + x] == 0);
-      TruePositives +=
-        (RefMaskImgData[RowStart + x] == 255) &&
-        (MaskImgData[RowStart + x] == 255);
-      TotalTruePositives += (RefMaskImgData[RowStart + x] == 255);
-    }
-    RowStart += RowWidth;
-  }
+        int ImageFrame = 0;
 
-  tnegatives = TrueNegatives;
-  ttnegatives = TotalTrueNegatives;
-  tpositives = TruePositives;
-  ttpositives = TotalTruePositives;
-}
+        if (MDMode == md_LBPHistograms || md_DLBPHistograms)
+        {
+          ImageFrame = HUHistogramArea / 2;
+        }
 
-void MotionDetection::ReleaseData()
-{
-  if (MDMode == md_LBPHistograms || MDMode == md_DLBPHistograms)
-  {
-    ReleaseHUData();
-  }
-}
+        for (int y = referenceimage.GetHeight() - ImageFrame - 1; y >= ImageFrame; --y)
+        {
+          for (int x = referenceimage.GetWidth() - ImageFrame - 1; x >= ImageFrame; --x)
+          {
+            TrueNegatives +=
+              (RefMaskImgData[RowStart + x] == 0) &&
+              (MaskImgData[RowStart + x] == 0);
+            TotalTrueNegatives += (RefMaskImgData[RowStart + x] == 0);
+            TruePositives +=
+              (RefMaskImgData[RowStart + x] == 255) &&
+              (MaskImgData[RowStart + x] == 255);
+            TotalTruePositives += (RefMaskImgData[RowStart + x] == 255);
+          }
+          RowStart += RowWidth;
+        }
 
-void MotionDetection::InitHUData(int imagewidth, int imageheight)
-{
-  if ((HUImageWidth != imagewidth - HUHistogramArea + 1) ||
-    (HUImageHeight != imageheight - HUHistogramArea + 1) ||
-    (MDDataState == ps_Uninitialized))
-  {
-    if (MDDataState != ps_Uninitialized)
-    {
-      ReleaseHUData();
-    }
+        tnegatives = TrueNegatives;
+        ttnegatives = TotalTrueNegatives;
+        tpositives = TruePositives;
+        ttpositives = TotalTruePositives;
+      }
 
-    MDDataState = ps_Initialized;
+      void MotionDetection::ReleaseData()
+      {
+        if (MDMode == md_LBPHistograms || MDMode == md_DLBPHistograms)
+        {
+          ReleaseHUData();
+        }
+      }
 
-    HUImageWidth = imagewidth - HUHistogramArea + 1;
-    HUImageHeight = imageheight - HUHistogramArea + 1;
+      void MotionDetection::InitHUData(int imagewidth, int imageheight)
+      {
+        if ((HUImageWidth != imagewidth - HUHistogramArea + 1) ||
+          (HUImageHeight != imageheight - HUHistogramArea + 1) ||
+          (MDDataState == ps_Uninitialized))
+        {
+          if (MDDataState != ps_Uninitialized)
+          {
+            ReleaseHUData();
+          }
 
-    HULBPPixelData = new MEPixelDataType**[HUImageWidth / 2];
+          MDDataState = ps_Initialized;
 
-    for (int i = 0; i < HUImageWidth / 2; ++i)
-    {
-      HULBPPixelData[i] = new MEPixelDataType*[HUImageHeight];
-    }
+          HUImageWidth = imagewidth - HUHistogramArea + 1;
+          HUImageHeight = imageheight - HUHistogramArea + 1;
 
-    for (int i = 0; i < HUImageWidth / 2; ++i)
-      for (int i1 = 0; i1 < HUImageHeight; ++i1)
-      {
-        HULBPPixelData[i][i1] = new MEPixelDataType;
-        HULBPPixelData[i][i1]->Weights = new float[HUHistogramsPerPixel];
-        HULBPPixelData[i][i1]->BackgroundHistogram = new bool[HUHistogramsPerPixel];
-        HULBPPixelData[i][i1]->Histograms = new float*[HUHistogramsPerPixel];
-        for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
-          HULBPPixelData[i][i1]->Histograms[i2] = new float[HUHistogramBins];
-        HULBPPixelData[i][i1]->PreviousHistogram = new float[HUHistogramBins];
-      }
+          HULBPPixelData = new MEPixelDataType**[HUImageWidth / 2];
 
-    // Allocate auxiliary variables
-    HUMaskColumnAddDel = new int*[HUHistogramArea];
-    for (int i = 0; i < HUHistogramArea; ++i)
-      HUMaskColumnAddDel[i] = new int[2];
+          for (int i = 0; i < HUImageWidth / 2; ++i)
+          {
+            HULBPPixelData[i] = new MEPixelDataType*[HUImageHeight];
+          }
 
-    HUMaskRowAddDel = new int*[HUHistogramArea];
-    for (int i = 0; i < HUHistogramArea; ++i)
-      HUMaskRowAddDel[i] = new int[2];
+          for (int i = 0; i < HUImageWidth / 2; ++i)
+            for (int i1 = 0; i1 < HUImageHeight; ++i1)
+            {
+              HULBPPixelData[i][i1] = new MEPixelDataType;
+              HULBPPixelData[i][i1]->Weights = new float[HUHistogramsPerPixel];
+              HULBPPixelData[i][i1]->BackgroundHistogram = new bool[HUHistogramsPerPixel];
+              HULBPPixelData[i][i1]->Histograms = new float*[HUHistogramsPerPixel];
+              for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+                HULBPPixelData[i][i1]->Histograms[i2] = new float[HUHistogramBins];
+              HULBPPixelData[i][i1]->PreviousHistogram = new float[HUHistogramBins];
+            }
 
-    // Generate sample mask
-    SetSampleMaskHU(sm_Circle, HUDesiredSamplePixels);
+          // Allocate auxiliary variables
+          HUMaskColumnAddDel = new int*[HUHistogramArea];
+          for (int i = 0; i < HUHistogramArea; ++i)
+            HUMaskColumnAddDel[i] = new int[2];
 
-    // Init HU optical flow data
-    if (MDMode == md_DLBPHistograms)
-      InitHUOFData(imagewidth, imageheight);
+          HUMaskRowAddDel = new int*[HUHistogramArea];
+          for (int i = 0; i < HUHistogramArea; ++i)
+            HUMaskRowAddDel[i] = new int[2];
 
-    ClearHUData();
-  }
-}
+          // Generate sample mask
+          SetSampleMaskHU(sm_Circle, HUDesiredSamplePixels);
 
-void MotionDetection::InitHUOFData(int imagewidth, int imageheight)
-{
-  if (HUOFDataState != ps_Uninitialized)
-  {
-    ReleaseHUOFData();
-  }
+          // Init HU optical flow data
+          if (MDMode == md_DLBPHistograms)
+            InitHUOFData(imagewidth, imageheight);
 
-  if (HUOFDataState == ps_Uninitialized)
-  {
-    HUOFPointsNumber = imagewidth*imageheight / 1000;
-    HUOFPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1);
-    HUOFPrevPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1);
-    HUOFPoints[0] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[0][0]));
-    HUOFPoints[1] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[1][0]));
-  }
-}
+          ClearHUData();
+        }
+      }
 
-void MotionDetection::ReleaseHUData()
-{
-  if (MDDataState != ps_Uninitialized)
-  {
-    for (int i = 0; i < HUImageWidth / 2; i++)
-      for (int i1 = 0; i1 < HUImageHeight; i1++)
+      void MotionDetection::InitHUOFData(int imagewidth, int imageheight)
       {
-        delete[] HULBPPixelData[i][i1]->PreviousHistogram;
-        for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
-          delete[] HULBPPixelData[i][i1]->Histograms[i2];
-        delete[] HULBPPixelData[i][i1]->Histograms;
-        delete[] HULBPPixelData[i][i1]->BackgroundHistogram;
-        delete[] HULBPPixelData[i][i1]->Weights;
-        delete HULBPPixelData[i][i1];
+        if (HUOFDataState != ps_Uninitialized)
+        {
+          ReleaseHUOFData();
+        }
+
+        if (HUOFDataState == ps_Uninitialized)
+        {
+          HUOFPointsNumber = imagewidth*imageheight / 1000;
+          HUOFPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1);
+          HUOFPrevPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1);
+          HUOFPoints[0] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[0][0]));
+          HUOFPoints[1] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[1][0]));
+        }
       }
 
-    for (int i = 0; i < HUImageWidth / 2; i++)
-    {
-      delete[] HULBPPixelData[i];
-    }
-    delete[] HULBPPixelData;
+      void MotionDetection::ReleaseHUData()
+      {
+        if (MDDataState != ps_Uninitialized)
+        {
+          for (int i = 0; i < HUImageWidth / 2; i++)
+            for (int i1 = 0; i1 < HUImageHeight; i1++)
+            {
+              delete[] HULBPPixelData[i][i1]->PreviousHistogram;
+              for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+                delete[] HULBPPixelData[i][i1]->Histograms[i2];
+              delete[] HULBPPixelData[i][i1]->Histograms;
+              delete[] HULBPPixelData[i][i1]->BackgroundHistogram;
+              delete[] HULBPPixelData[i][i1]->Weights;
+              delete HULBPPixelData[i][i1];
+            }
 
-    if (MDMode == md_DLBPHistograms)
-      ReleaseHUOFData();
+          for (int i = 0; i < HUImageWidth / 2; i++)
+          {
+            delete[] HULBPPixelData[i];
+          }
+          delete[] HULBPPixelData;
 
-    HUImageWidth = -1;
-    HUImageHeight = -1;
-    HULBPPixelData = NULL;
-    MDDataState = ps_Uninitialized;
+          if (MDMode == md_DLBPHistograms)
+            ReleaseHUOFData();
 
-    // Release auxiliary variables
-    for (int i = 0; i < HUHistogramArea; ++i)
-      delete[] HUMaskColumnAddDel[i];
-    delete[] HUMaskColumnAddDel;
+          HUImageWidth = -1;
+          HUImageHeight = -1;
+          HULBPPixelData = NULL;
+          MDDataState = ps_Uninitialized;
 
-    for (int i = 0; i < HUHistogramArea; ++i)
-      delete[] HUMaskRowAddDel[i];
-    delete[] HUMaskRowAddDel;
+          // Release auxiliary variables
+          for (int i = 0; i < HUHistogramArea; ++i)
+            delete[] HUMaskColumnAddDel[i];
+          delete[] HUMaskColumnAddDel;
 
-    HUMaskColumnAddDel = NULL;
-    HUMaskRowAddDel = NULL;
-  }
-}
+          for (int i = 0; i < HUHistogramArea; ++i)
+            delete[] HUMaskRowAddDel[i];
+          delete[] HUMaskRowAddDel;
 
-void MotionDetection::ReleaseHUOFData()
-{
-  if (MDDataState != ps_Uninitialized)
-  {
-    if (HUOFPyramid)
-    {
-      cvReleaseImage(&HUOFPyramid);
-      HUOFPyramid = NULL;
-    }
-    if (HUOFPrevPyramid)
-    {
-      cvReleaseImage(&HUOFPrevPyramid);
-      HUOFPrevPyramid = NULL;
-    }
-    if (HUOFPoints[0])
-    {
-      cvFree(&HUOFPoints[0]);
-      HUOFPoints[0] = NULL;
-    }
-    if (HUOFPoints[1])
-    {
-      cvFree(&HUOFPoints[1]);
-      HUOFPoints[1] = NULL;
-    }
-    HUOFDataState = ps_Uninitialized;
-  }
-}
+          HUMaskColumnAddDel = NULL;
+          HUMaskRowAddDel = NULL;
+        }
+      }
 
-void MotionDetection::ClearHUData()
-{
-  if (MDDataState != ps_Uninitialized)
-  {
-    for (int i = (HUImageWidth / 2) - 1; i >= 0; --i)
-      for (int i1 = HUImageHeight - 1; i1 >= 0; --i1)
+      void MotionDetection::ReleaseHUOFData()
       {
-        for (int i2 = HUHistogramsPerPixel - 1; i2 >= 0; --i2)
+        if (MDDataState != ps_Uninitialized)
         {
-          memset(HULBPPixelData[i][i1]->Histograms[i2], 0,
-            HUHistogramBins * sizeof(float));
-          HULBPPixelData[i][i1]->Weights[i2] = 1.0 / HUHistogramsPerPixel;
-          HULBPPixelData[i][i1]->BackgroundHistogram[i2] = true;
+          if (HUOFPyramid)
+          {
+            cvReleaseImage(&HUOFPyramid);
+            HUOFPyramid = NULL;
+          }
+          if (HUOFPrevPyramid)
+          {
+            cvReleaseImage(&HUOFPrevPyramid);
+            HUOFPrevPyramid = NULL;
+          }
+          if (HUOFPoints[0])
+          {
+            cvFree(&HUOFPoints[0]);
+            HUOFPoints[0] = NULL;
+          }
+          if (HUOFPoints[1])
+          {
+            cvFree(&HUOFPoints[1]);
+            HUOFPoints[1] = NULL;
+          }
+          HUOFDataState = ps_Uninitialized;
         }
-        HULBPPixelData[i][i1]->BackgroundRate = 1.0;
-        HULBPPixelData[i][i1]->LifeCycle = 0;
       }
-    MDDataState = ps_Initialized;
-  }
-}
 
-void MotionDetection::DetectMotionsHU(MEImage& image)
-{
-  unsigned char *ImgData = NULL;
-  MEImage newimage = image;
-  float DiffAreas = 0;
-
-  // Init the histogram update data structures if needs be
-  if ((MDDataState == ps_Uninitialized) ||
-    (HUImageWidth != newimage.GetWidth() - HUHistogramArea + 1) ||
-    (HUImageHeight != newimage.GetHeight() - HUHistogramArea + 1))
-  {
-    InitHUData(newimage.GetWidth(), newimage.GetHeight());
-  }
+      void MotionDetection::ClearHUData()
+      {
+        if (MDDataState != ps_Uninitialized)
+        {
+          for (int i = (HUImageWidth / 2) - 1; i >= 0; --i)
+            for (int i1 = HUImageHeight - 1; i1 >= 0; --i1)
+            {
+              for (int i2 = HUHistogramsPerPixel - 1; i2 >= 0; --i2)
+              {
+                memset(HULBPPixelData[i][i1]->Histograms[i2], 0,
+                  HUHistogramBins * sizeof(float));
+                HULBPPixelData[i][i1]->Weights[i2] = 1.0 / HUHistogramsPerPixel;
+                HULBPPixelData[i][i1]->BackgroundHistogram[i2] = true;
+              }
+              HULBPPixelData[i][i1]->BackgroundRate = 1.0;
+              HULBPPixelData[i][i1]->LifeCycle = 0;
+            }
+          MDDataState = ps_Initialized;
+        }
+      }
 
-  if (newimage.GetLayers() == 1)
-  {
-    newimage.ConvertGrayscaleToRGB();
-  }
+      void MotionDetection::DetectMotionsHU(MEImage& image)
+      {
+        unsigned char *ImgData = NULL;
+        MEImage newimage = image;
+        float DiffAreas = 0;
+
+        // Init the histogram update data structures if needs be
+        if ((MDDataState == ps_Uninitialized) ||
+          (HUImageWidth != newimage.GetWidth() - HUHistogramArea + 1) ||
+          (HUImageHeight != newimage.GetHeight() - HUHistogramArea + 1))
+        {
+          InitHUData(newimage.GetWidth(), newimage.GetHeight());
+        }
 
-  MEImage blueimage = newimage;
-  blueimage.ColorSpace(MEImage::csc_RGBtoCIELuv);
+        if (newimage.GetLayers() == 1)
+        {
+          newimage.ConvertGrayscaleToRGB();
+        }
 
-  if (HUColorSpace != -1)
-  {
-    newimage.ColorSpace((MEImage::ColorSpaceConvertType)HUColorSpace);
-  }
+        MEImage blueimage = newimage;
+        blueimage.ColorSpace(MEImage::csc_RGBtoCIELuv);
 
-  if (Frames == 0)
-  {
-    MEImage BlueLayer;
-    blueimage.GetLayer(BlueLayer, 1);
-    BlueLayer.Resize(32, 24);
-    PreviousBlueLayer = BlueLayer;
-  }
+        if (HUColorSpace != -1)
+        {
+          newimage.ColorSpace((MEImage::ColorSpaceConvertType)HUColorSpace);
+        }
 
-  Frames++;
+        if (Frames == 0)
+        {
+          MEImage BlueLayer;
+          blueimage.GetLayer(BlueLayer, 1);
+          BlueLayer.Resize(32, 24);
+          PreviousBlueLayer = BlueLayer;
+        }
 
-  // Detect the fast, big changes in the scene
-  MEImage BlueLayer;
-  blueimage.GetLayer(BlueLayer, 1);
-  BlueLayer.Resize(32, 24);
-  DiffAreas = BlueLayer.DifferenceAreas(PreviousBlueLayer, 12);
+        Frames++;
 
-  if (DiffAreas > 80)
-  {
-    MDDataState = ps_Initialized;
-    if (MDMode == md_DLBPHistograms)
-      HUOFDataState = ps_Initialized;
-    printf("Frame: %d - big changes in the scene (%f)", Frames, DiffAreas);
-    Frames = 1;
-    HUOFFrames = -1;
-  }
-  PreviousBlueLayer = BlueLayer;
+        // Detect the fast, big changes in the scene
+        MEImage BlueLayer;
+        blueimage.GetLayer(BlueLayer, 1);
+        BlueLayer.Resize(32, 24);
+        DiffAreas = BlueLayer.DifferenceAreas(PreviousBlueLayer, 12);
 
-  if (Frames == 1)
-  {
-    CurrentImage = image;
-    PreviousImage = CurrentImage;
-  }
-  else
-    if (Frames > 1)
-    {
-      PreviousImage = CurrentImage;
-      CurrentImage = image;
-      // Optical flow correction of the camera movements
-      if (MDMode == md_DLBPHistograms)
-      {
-        OpticalFlowCorrection();
-      }
-    }
+        if (DiffAreas > 80)
+        {
+          MDDataState = ps_Initialized;
+          if (MDMode == md_DLBPHistograms)
+            HUOFDataState = ps_Initialized;
+          printf("Frame: %d - big changes in the scene (%f)", Frames, DiffAreas);
+          Frames = 1;
+          HUOFFrames = -1;
+        }
+        PreviousBlueLayer = BlueLayer;
 
-  newimage.ConvertToGrayscale(MEImage::g_OpenCV);
+        if (Frames == 1)
+        {
+          CurrentImage = image;
+          PreviousImage = CurrentImage;
+        }
+        else
+          if (Frames > 1)
+          {
+            PreviousImage = CurrentImage;
+            CurrentImage = image;
+            // Optical flow correction of the camera movements
+            if (MDMode == md_DLBPHistograms)
+            {
+              OpticalFlowCorrection();
+            }
+          }
 
-  if (HULBPMode != -1)
-  {
-    newimage.LBP((MEImage::LBPType)HULBPMode);
-  }
+        newimage.ConvertToGrayscale(MEImage::g_OpenCV);
 
-  // Set some auxiliary variables
-  ImgData = newimage.GetImageData();
-  int DivisionOperator = (int)(log((double)256 / HUHistogramBins) / log((double) 2.)) + 1;
+        if (HULBPMode != -1)
+        {
+          newimage.LBP((MEImage::LBPType)HULBPMode);
+        }
 
-  // Downscale the image
-  for (int i = newimage.GetRowWidth()*newimage.GetHeight() - 1; i >= 0; --i)
-  {
-    ImgData[i] >>= DivisionOperator;
-  }
+        // Set some auxiliary variables
+        ImgData = newimage.GetImageData();
+        int DivisionOperator = (int)(log((double)256 / HUHistogramBins) / log((double) 2.)) + 1;
 
-  UpdateModelHU(newimage, HULBPPixelData);
+        // Downscale the image
+        for (int i = newimage.GetRowWidth()*newimage.GetHeight() - 1; i >= 0; --i)
+        {
+          ImgData[i] >>= DivisionOperator;
+        }
 
-  // Change the state of the HU data structures
-  if (MDDataState == ps_Initialized)
-  {
-    MDDataState = ps_Successful;
-  }
-  HUOFCamMovement = false;
-  ReadyMask = false;
-}
+        UpdateModelHU(newimage, HULBPPixelData);
 
-void MotionDetection::UpdateModelHU(MEImage& image, MEPixelDataType*** model)
-{
-  float *CurrentHistogram = new float[HUHistogramBins];
-  float *CurrentHistogram2 = new float[HUHistogramBins];
-  unsigned char *ImgData = image.GetImageData();
-  int RowWidth = image.GetRowWidth();
-  int RowStart = (HUImageHeight - 1)*RowWidth;
-
-  memset(CurrentHistogram, 0, HUHistogramBins * sizeof(float));
-  // Calculate the first histogram
-  for (int y = HUHistogramArea - 1; y >= 0; --y)
-  {
-    for (int x = HUHistogramArea - 1; x >= 0; --x)
-    {
-      if ((HUMaskRowAddDel[y][1] > x) && (HUMaskRowAddDel[y][0] <= x) &&
-        (HUMaskColumnAddDel[x][1] > y) && (HUMaskColumnAddDel[x][0] <= y))
-      {
-        CurrentHistogram[ImgData[RowStart + HUImageWidth - 1 + x]]++;
-      }
-    }
-    RowStart += RowWidth;
-  }
-
-  // This cycle generates the last row of histograms
-  for (int y = HUImageHeight - 1; y >= 0; --y)
-  {
-    if (HUImageHeight - 1 > y)
-    {
-      // Delete and add a pixel column from the histogram data
-      for (int i = HUHistogramArea - 1; i >= 0; --i)
-      {
-        if (HUMaskColumnAddDel[i][0] != -1)
-          CurrentHistogram[ImgData[RowWidth*(y + HUMaskColumnAddDel[i][0]) + HUImageWidth - 1 + i]]++;
-        if (HUMaskColumnAddDel[i][1] != -1)
-          CurrentHistogram[ImgData[RowWidth*(y + HUMaskColumnAddDel[i][1]) + HUImageWidth - 1 + i]]--;
-      }
-    }
-
-    if (y % 2 == HUImageWidth % 2)
-    {
-      MEPixelDataType* PixelData = model[(HUImageWidth - 1) / 2][y];
-
-      // Allocate and initialize the pixel data if needs be
-      if (!PixelData)
-      {
-        // Memory allocation
-        PixelData = new MEPixelDataType;
-        PixelData->Weights = new float[HUHistogramsPerPixel];
-        PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel];
-        PixelData->Histograms = new float*[HUHistogramsPerPixel];
-        for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
-          PixelData->Histograms[i2] = new float[HUHistogramBins];
-        PixelData->PreviousHistogram = new float[HUHistogramBins];
-
-        for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+        // Change the state of the HU data structures
+        if (MDDataState == ps_Initialized)
         {
-          memcpy(PixelData->Histograms[i], CurrentHistogram, HUHistogramBins * sizeof(float));
-          PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
-          PixelData->BackgroundHistogram[i] = true;
+          MDDataState = ps_Successful;
         }
-        PixelData->BackgroundRate = 1.0;
-        PixelData->LifeCycle = 0;
-        memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float));
-
-        model[(HUImageWidth - 1) / 2][y] = PixelData;
+        HUOFCamMovement = false;
+        ReadyMask = false;
       }
-      else {
-        bool InitHistograms = (MDDataState == ps_Initialized);
 
-        if (MDDataState != ps_Initialized && HUOFCamMovement)
+      void MotionDetection::UpdateModelHU(MEImage& image, MEPixelDataType*** model)
+      {
+        float *CurrentHistogram = new float[HUHistogramBins];
+        float *CurrentHistogram2 = new float[HUHistogramBins];
+        unsigned char *ImgData = image.GetImageData();
+        int RowWidth = image.GetRowWidth();
+        int RowStart = (HUImageHeight - 1)*RowWidth;
+
+        memset(CurrentHistogram, 0, HUHistogramBins * sizeof(float));
+        // Calculate the first histogram
+        for (int y = HUHistogramArea - 1; y >= 0; --y)
         {
-          // Histogram intersection between the previous and the current histogram
-          float Difference = 0.0;
-          for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1)
+          for (int x = HUHistogramArea - 1; x >= 0; --x)
           {
-            Difference += (float)(CurrentHistogram[i1] < PixelData->PreviousHistogram[i1] ?
-              CurrentHistogram[i1] : PixelData->PreviousHistogram[i1]);
+            if ((HUMaskRowAddDel[y][1] > x) && (HUMaskRowAddDel[y][0] <= x) &&
+              (HUMaskColumnAddDel[x][1] > y) && (HUMaskColumnAddDel[x][0] <= y))
+            {
+              CurrentHistogram[ImgData[RowStart + HUImageWidth - 1 + x]]++;
+            }
           }
-          Difference /= HUSamplePixels;
-
-          if (Difference < HUBackgrThres)
-            InitHistograms = true;
+          RowStart += RowWidth;
         }
-        if (InitHistograms)
+
+        // This cycle generates the last row of histograms
+        for (int y = HUImageHeight - 1; y >= 0; --y)
         {
-          // Copy the histogram data to the HU data structures
-          for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+          if (HUImageHeight - 1 > y)
           {
-            memcpy(PixelData->Histograms[i], CurrentHistogram, HUHistogramBins * sizeof(float));
-            PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
-            PixelData->BackgroundHistogram[i] = true;
+            // Delete and add a pixel column from the histogram data
+            for (int i = HUHistogramArea - 1; i >= 0; --i)
+            {
+              if (HUMaskColumnAddDel[i][0] != -1)
+                CurrentHistogram[ImgData[RowWidth*(y + HUMaskColumnAddDel[i][0]) + HUImageWidth - 1 + i]]++;
+              if (HUMaskColumnAddDel[i][1] != -1)
+                CurrentHistogram[ImgData[RowWidth*(y + HUMaskColumnAddDel[i][1]) + HUImageWidth - 1 + i]]--;
+            }
           }
-          memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float));
-          PixelData->BackgroundRate = 1.0;
-          PixelData->LifeCycle = 0;
-        }
-        else {
-          // Update the HU data structures
-          UpdateHUPixelData(PixelData, CurrentHistogram);
 
-          if (MDMode == md_DLBPHistograms)
+          if (y % 2 == HUImageWidth % 2)
           {
-            memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float));
-          }
-        }
-      }
-    }
-
-    // Copy the histogram
-    memcpy(CurrentHistogram2, CurrentHistogram, HUHistogramBins * sizeof(float));
+            MEPixelDataType* PixelData = model[(HUImageWidth - 1) / 2][y];
 
-    // This cycle generates a column of histograms
-    for (int x = HUImageWidth - 2; x >= 0; --x)
-    {
-      RowStart = RowWidth*y;
+            // Allocate and initialize the pixel data if needs be
+            if (!PixelData)
+            {
+              // Memory allocation
+              PixelData = new MEPixelDataType;
+              PixelData->Weights = new float[HUHistogramsPerPixel];
+              PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel];
+              PixelData->Histograms = new float*[HUHistogramsPerPixel];
+              for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+                PixelData->Histograms[i2] = new float[HUHistogramBins];
+              PixelData->PreviousHistogram = new float[HUHistogramBins];
 
-      // Delete and add a pixel column from the histogram data
-      for (int i = HUHistogramArea - 1; i >= 0; --i)
-      {
-        if (HUMaskRowAddDel[i][0] != -1)
-          CurrentHistogram2[ImgData[RowStart + x + HUMaskRowAddDel[i][0]]]++;
-        if (HUMaskRowAddDel[i][1] != -1)
-          CurrentHistogram2[ImgData[RowStart + x + HUMaskRowAddDel[i][1]]]--;
+              for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+              {
+                memcpy(PixelData->Histograms[i], CurrentHistogram, HUHistogramBins * sizeof(float));
+                PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
+                PixelData->BackgroundHistogram[i] = true;
+              }
+              PixelData->BackgroundRate = 1.0;
+              PixelData->LifeCycle = 0;
+              memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float));
 
-        RowStart += RowWidth;
-      }
-      if (x % 2 == 0)
-      {
-        MEPixelDataType* PixelData = model[x / 2][y];
+              model[(HUImageWidth - 1) / 2][y] = PixelData;
+            }
+            else {
+              bool InitHistograms = (MDDataState == ps_Initialized);
 
-        // Allocate and initialize the pixel data if needs be
-        if (!PixelData)
-        {
-          // Memory allocation
-          PixelData = new MEPixelDataType;
-          PixelData->Weights = new float[HUHistogramsPerPixel];
-          PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel];
-          PixelData->Histograms = new float*[HUHistogramsPerPixel];
-          for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
-            PixelData->Histograms[i2] = new float[HUHistogramBins];
-          PixelData->PreviousHistogram = new float[HUHistogramBins];
-
-          for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
-          {
-            memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2));
-            PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
-            PixelData->BackgroundHistogram[i] = true;
+              if (MDDataState != ps_Initialized && HUOFCamMovement)
+              {
+                // Histogram intersection between the previous and the current histogram
+                float Difference = 0.0;
+                for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1)
+                {
+                  Difference += (float)(CurrentHistogram[i1] < PixelData->PreviousHistogram[i1] ?
+                    CurrentHistogram[i1] : PixelData->PreviousHistogram[i1]);
+                }
+                Difference /= HUSamplePixels;
+
+                if (Difference < HUBackgrThres)
+                  InitHistograms = true;
+              }
+              if (InitHistograms)
+              {
+                // Copy the histogram data to the HU data structures
+                for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+                {
+                  memcpy(PixelData->Histograms[i], CurrentHistogram, HUHistogramBins * sizeof(float));
+                  PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
+                  PixelData->BackgroundHistogram[i] = true;
+                }
+                memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float));
+                PixelData->BackgroundRate = 1.0;
+                PixelData->LifeCycle = 0;
+              }
+              else {
+                // Update the HU data structures
+                UpdateHUPixelData(PixelData, CurrentHistogram);
+
+                if (MDMode == md_DLBPHistograms)
+                {
+                  memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float));
+                }
+              }
+            }
           }
-          PixelData->BackgroundRate = 1.0;
-          PixelData->LifeCycle = 0;
-          model[x / 2][y] = PixelData;
-          memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2));
-        }
-        else {
-          bool InitHistograms = (MDDataState == ps_Initialized);
 
-          if (MDDataState != ps_Initialized && HUOFCamMovement)
-          {
-            // Histogram intersection between the previous and the current histogram
-            float Difference = 0.0;
-            for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1)
-            {
-              Difference += (float)(CurrentHistogram2[i1] < PixelData->PreviousHistogram[i1] ?
-                CurrentHistogram2[i1] : PixelData->PreviousHistogram[i1]);
-            }
-            Difference /= HUSamplePixels;
+          // Copy the histogram
+          memcpy(CurrentHistogram2, CurrentHistogram, HUHistogramBins * sizeof(float));
 
-            if (Difference < HUBackgrThres)
-              InitHistograms = true;
-          }
-          if (InitHistograms)
+          // This cycle generates a column of histograms
+          for (int x = HUImageWidth - 2; x >= 0; --x)
           {
-            // Copy the histogram data to the HU data structures
-            for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+            RowStart = RowWidth*y;
+
+            // Delete and add a pixel column from the histogram data
+            for (int i = HUHistogramArea - 1; i >= 0; --i)
             {
-              memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2));
-              PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
-              PixelData->BackgroundHistogram[i] = true;
-            }
-            memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2));
-            PixelData->BackgroundRate = 1.0;
-            PixelData->LifeCycle = 0;
-          }
-          else {
-            // Update the HU data structures
-            UpdateHUPixelData(PixelData, CurrentHistogram2);
+              if (HUMaskRowAddDel[i][0] != -1)
+                CurrentHistogram2[ImgData[RowStart + x + HUMaskRowAddDel[i][0]]]++;
+              if (HUMaskRowAddDel[i][1] != -1)
+                CurrentHistogram2[ImgData[RowStart + x + HUMaskRowAddDel[i][1]]]--;
 
-            if (MDMode == md_DLBPHistograms)
+              RowStart += RowWidth;
+            }
+            if (x % 2 == 0)
             {
-              memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2));
+              MEPixelDataType* PixelData = model[x / 2][y];
+
+              // Allocate and initialize the pixel data if needs be
+              if (!PixelData)
+              {
+                // Memory allocation
+                PixelData = new MEPixelDataType;
+                PixelData->Weights = new float[HUHistogramsPerPixel];
+                PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel];
+                PixelData->Histograms = new float*[HUHistogramsPerPixel];
+                for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+                  PixelData->Histograms[i2] = new float[HUHistogramBins];
+                PixelData->PreviousHistogram = new float[HUHistogramBins];
+
+                for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+                {
+                  memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2));
+                  PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
+                  PixelData->BackgroundHistogram[i] = true;
+                }
+                PixelData->BackgroundRate = 1.0;
+                PixelData->LifeCycle = 0;
+                model[x / 2][y] = PixelData;
+                memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2));
+              }
+              else {
+                bool InitHistograms = (MDDataState == ps_Initialized);
+
+                if (MDDataState != ps_Initialized && HUOFCamMovement)
+                {
+                  // Histogram intersection between the previous and the current histogram
+                  float Difference = 0.0;
+                  for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1)
+                  {
+                    Difference += (float)(CurrentHistogram2[i1] < PixelData->PreviousHistogram[i1] ?
+                      CurrentHistogram2[i1] : PixelData->PreviousHistogram[i1]);
+                  }
+                  Difference /= HUSamplePixels;
+
+                  if (Difference < HUBackgrThres)
+                    InitHistograms = true;
+                }
+                if (InitHistograms)
+                {
+                  // Copy the histogram data to the HU data structures
+                  for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+                  {
+                    memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2));
+                    PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
+                    PixelData->BackgroundHistogram[i] = true;
+                  }
+                  memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2));
+                  PixelData->BackgroundRate = 1.0;
+                  PixelData->LifeCycle = 0;
+                }
+                else {
+                  // Update the HU data structures
+                  UpdateHUPixelData(PixelData, CurrentHistogram2);
+
+                  if (MDMode == md_DLBPHistograms)
+                  {
+                    memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2));
+                  }
+                }
+              }
             }
+
           }
         }
+        delete[] CurrentHistogram;
+        delete[] CurrentHistogram2;
       }
 
-    }
-  }
-  delete[] CurrentHistogram;
-  delete[] CurrentHistogram2;
-}
-
-void MotionDetection::UpdateHUPixelData(MEPixelDataType* PixelData, const float *histogram)
-{
-  int MaxIndex = 0;
-  float MaxValue = -1;
-  bool Replace = true;
-  float *IntersectionResults = new float[HUHistogramsPerPixel];
+      void MotionDetection::UpdateHUPixelData(MEPixelDataType* PixelData, const float *histogram)
+      {
+        int MaxIndex = 0;
+        float MaxValue = -1;
+        bool Replace = true;
+        float *IntersectionResults = new float[HUHistogramsPerPixel];
 
-  PixelData->LifeCycle++;
-  PixelData->BackgroundRate = 0.0;
+        PixelData->LifeCycle++;
+        PixelData->BackgroundRate = 0.0;
 
-  // Compute intersection between the currect and older histograms
-  for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
-  {
-    // Histogram intersection
-    float Difference = 0.0;
-    for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1)
-    {
-      Difference += (float)histogram[i1] < PixelData->Histograms[i][i1] ?
-        (float)histogram[i1] : PixelData->Histograms[i][i1];
-    }
+        // Compute intersection between the currect and older histograms
+        for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+        {
+          // Histogram intersection
+          float Difference = 0.0;
+          for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1)
+          {
+            Difference += (float)histogram[i1] < PixelData->Histograms[i][i1] ?
+              (float)histogram[i1] : PixelData->Histograms[i][i1];
+          }
 
-    IntersectionResults[i] = (float)Difference / (float)(HUSamplePixels);
+          IntersectionResults[i] = (float)Difference / (float)(HUSamplePixels);
 
-    if (PixelData->BackgroundHistogram[i] &&
-      IntersectionResults[i] > PixelData->BackgroundRate)
-    {
-      PixelData->BackgroundRate = IntersectionResults[i];
-    }
+          if (PixelData->BackgroundHistogram[i] &&
+            IntersectionResults[i] > PixelData->BackgroundRate)
+          {
+            PixelData->BackgroundRate = IntersectionResults[i];
+          }
 
-    if (MaxValue < IntersectionResults[i])
-    {
-      MaxValue = IntersectionResults[i];
-      MaxIndex = i;
-    }
+          if (MaxValue < IntersectionResults[i])
+          {
+            MaxValue = IntersectionResults[i];
+            MaxIndex = i;
+          }
 
-    Replace = Replace && (IntersectionResults[i] < HUPrThres);
-  }
+          Replace = Replace && (IntersectionResults[i] < HUPrThres);
+        }
 
-  // Replace the histogram with the lowest weight
-  if (Replace)
-  {
-    // Find the histogram with minimal weight
-    int MinIndex = 0;
-    float MinValue = PixelData->Weights[0];
-    for (int i1 = HUHistogramsPerPixel - 1; i1 > 0; --i1)
-    {
-      if (MinValue > PixelData->Weights[i1])
-      {
-        MinValue = PixelData->Weights[i1];
-        MinIndex = i1;
-      }
-    }
+        // Replace the histogram with the lowest weight
+        if (Replace)
+        {
+          // Find the histogram with minimal weight
+          int MinIndex = 0;
+          float MinValue = PixelData->Weights[0];
+          for (int i1 = HUHistogramsPerPixel - 1; i1 > 0; --i1)
+          {
+            if (MinValue > PixelData->Weights[i1])
+            {
+              MinValue = PixelData->Weights[i1];
+              MinIndex = i1;
+            }
+          }
 
-    PixelData->Weights[MinIndex] = 0.01;
-    for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1)
-      PixelData->Histograms[MinIndex][i1] = (float)histogram[i1];
-    PixelData->BackgroundHistogram[MinIndex] = 0;
+          PixelData->Weights[MinIndex] = 0.01;
+          for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1)
+            PixelData->Histograms[MinIndex][i1] = (float)histogram[i1];
+          PixelData->BackgroundHistogram[MinIndex] = 0;
 
-    // Normalize the weights
-    float sum = 0;
-    for (int i1 = HUHistogramsPerPixel - 1; i1 >= 0; --i1)
-      sum += PixelData->Weights[i1];
+          // Normalize the weights
+          float sum = 0;
+          for (int i1 = HUHistogramsPerPixel - 1; i1 >= 0; --i1)
+            sum += PixelData->Weights[i1];
 
-    for (int i1 = HUHistogramsPerPixel - 1; i1 >= 0; --i1)
-      PixelData->Weights[i1] = PixelData->Weights[i1] / sum;
+          for (int i1 = HUHistogramsPerPixel - 1; i1 >= 0; --i1)
+            PixelData->Weights[i1] = PixelData->Weights[i1] / sum;
 
-    return;
-  }
+          return;
+        }
 
-  float LearningRate = HUHistLRate;
+        float LearningRate = HUHistLRate;
 
-  if (PixelData->LifeCycle < 100)
-    LearningRate += (float)(100 - PixelData->LifeCycle) / 100;
-  else
-    if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40)
-      LearningRate += (HUOFFrames < 80 ? 0.05 : 0);
+        if (PixelData->LifeCycle < 100)
+          LearningRate += (float)(100 - PixelData->LifeCycle) / 100;
+        else
+          if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40)
+            LearningRate += (HUOFFrames < 80 ? 0.05 : 0);
 
-  // Match was found -> Update the histogram of the best match
-  for (int i = HUHistogramBins - 1; i >= 0; --i)
-  {
-    PixelData->Histograms[MaxIndex][i] *= (1.0 - LearningRate);
-    PixelData->Histograms[MaxIndex][i] += LearningRate*(float)histogram[i];
-  }
+        // Match was found -> Update the histogram of the best match
+        for (int i = HUHistogramBins - 1; i >= 0; --i)
+        {
+          PixelData->Histograms[MaxIndex][i] *= (1.0 - LearningRate);
+          PixelData->Histograms[MaxIndex][i] += LearningRate*(float)histogram[i];
+        }
 
-  LearningRate = HUWeightsLRate;
-  if (PixelData->LifeCycle < 100)
-    LearningRate += (float)(100 - PixelData->LifeCycle) / 100;
-  else
-    if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40)
-      LearningRate += (HUOFFrames < 80 ? 0.05 : 0);
+        LearningRate = HUWeightsLRate;
+        if (PixelData->LifeCycle < 100)
+          LearningRate += (float)(100 - PixelData->LifeCycle) / 100;
+        else
+          if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40)
+            LearningRate += (HUOFFrames < 80 ? 0.05 : 0);
 
-  // Update the weights of the histograms
-  for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
-  {
-    PixelData->Weights[i] =
-      (LearningRate*(i == MaxIndex) + (1.0 - LearningRate)*PixelData->Weights[i]);
-  }
+        // Update the weights of the histograms
+        for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+        {
+          PixelData->Weights[i] =
+            (LearningRate*(i == MaxIndex) + (1.0 - LearningRate)*PixelData->Weights[i]);
+        }
 
-  // Order and select the background histograms
-  float **Weights = new float*[HUHistogramsPerPixel];
-  for (int i = 0; i < HUHistogramsPerPixel; ++i)
-    Weights[i] = new float[2];
+        // Order and select the background histograms
+        float **Weights = new float*[HUHistogramsPerPixel];
+        for (int i = 0; i < HUHistogramsPerPixel; ++i)
+          Weights[i] = new float[2];
 
-  for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
-  {
-    Weights[i][0] = (float)i;
-    Weights[i][1] = PixelData->Weights[i];
-  }
+        for (int i = HUHistogramsPerPixel - 1; i >= 0; --i)
+        {
+          Weights[i][0] = (float)i;
+          Weights[i][1] = PixelData->Weights[i];
+        }
 
-  for (int i1 = HUHistogramsPerPixel - 1; i1 >= 2; --i1)
-    for (int i = i1; i >= 1; --i)
-    {
-      if (Weights[i][1] <= Weights[i - 1][1])
-      {
-        float tmp = Weights[i][0];
-        float tmp2 = Weights[i][1];
+        for (int i1 = HUHistogramsPerPixel - 1; i1 >= 2; --i1)
+          for (int i = i1; i >= 1; --i)
+          {
+            if (Weights[i][1] <= Weights[i - 1][1])
+            {
+              float tmp = Weights[i][0];
+              float tmp2 = Weights[i][1];
 
-        Weights[i][0] = Weights[i - 1][0];
-        Weights[i][1] = Weights[i - 1][1];
+              Weights[i][0] = Weights[i - 1][0];
+              Weights[i][1] = Weights[i - 1][1];
 
-        Weights[i - 1][0] = tmp;
-        Weights[i - 1][1] = tmp2;
-      }
-    }
+              Weights[i - 1][0] = tmp;
+              Weights[i - 1][1] = tmp2;
+            }
+          }
 
-  float Sum = 0;
-  int i = 0;
+        float Sum = 0;
+        int i = 0;
 
-  for (i = HUHistogramsPerPixel - 1; i >= 0; --i)
-  {
-    Sum += Weights[i][1];
-    PixelData->BackgroundHistogram[(int)Weights[i][0]] = true;
+        for (i = HUHistogramsPerPixel - 1; i >= 0; --i)
+        {
+          Sum += Weights[i][1];
+          PixelData->BackgroundHistogram[(int)Weights[i][0]] = true;
 
-    if (Sum > HUBackgrThres)
-      break;
-  }
-  for (int i1 = i - 1; i1 >= 0; --i1)
-  {
-    PixelData->BackgroundHistogram[(int)Weights[i1][0]] = false;
-  }
-  delete[] IntersectionResults;
-  for (int i = 0; i < HUHistogramsPerPixel; ++i)
-    delete[] Weights[i];
-  delete[] Weights;
-}
+          if (Sum > HUBackgrThres)
+            break;
+        }
+        for (int i1 = i - 1; i1 >= 0; --i1)
+        {
+          PixelData->BackgroundHistogram[(int)Weights[i1][0]] = false;
+        }
+        delete[] IntersectionResults;
+        for (int i = 0; i < HUHistogramsPerPixel; ++i)
+          delete[] Weights[i];
+        delete[] Weights;
+      }
 
-void MotionDetection::OpticalFlowCorrection()
-{
-  IplImage *PreviousGray = NULL, *CurrentGray = NULL;
-  char* PointsStatus = (char*)cvAlloc(HUOFPointsNumber);
-  int i = 0, i1 = 0;
+      void MotionDetection::OpticalFlowCorrection()
+      {
+        IplImage *PreviousGray = NULL, *CurrentGray = NULL;
+        char* PointsStatus = (char*)cvAlloc(HUOFPointsNumber);
+        int i = 0, i1 = 0;
 
-  if (HUOFFrames != -1)
-    HUOFFrames++;
+        if (HUOFFrames != -1)
+          HUOFFrames++;
 
-  // Convert the images into grayscale
-  if (CurrentImage.GetLayers() > 1)
-  {
-    CurrentGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1);
-    cvCvtColor(CurrentImage.GetIplImage(), CurrentGray, CV_BGR2GRAY);
-  }
-  else
-    CurrentGray = (IplImage*)CurrentImage.GetIplImage();
-  if (PreviousImage.GetLayers() > 1)
-  {
-    PreviousGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1);
-    cvCvtColor(PreviousImage.GetIplImage(), PreviousGray, CV_BGR2GRAY);
-  }
-  else
-    PreviousGray = (IplImage*)PreviousImage.GetIplImage();
+        // Convert the images into grayscale
+        if (CurrentImage.GetLayers() > 1)
+        {
+          CurrentGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1);
+          cvCvtColor(CurrentImage.GetIplImage(), CurrentGray, CV_BGR2GRAY);
+        }
+        else
+          CurrentGray = (IplImage*)CurrentImage.GetIplImage();
+        if (PreviousImage.GetLayers() > 1)
+        {
+          PreviousGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1);
+          cvCvtColor(PreviousImage.GetIplImage(), PreviousGray, CV_BGR2GRAY);
+        }
+        else
+          PreviousGray = (IplImage*)PreviousImage.GetIplImage();
 
-  if (HUOFDataState != ps_Successful)
-  {
-    printf("Search new corners\n");
-    IplImage* TempEig = cvCreateImage(cvGetSize(CurrentGray), 32, 1);
-    IplImage* Temp = cvCreateImage(cvGetSize(CurrentGray), 32, 1);
-    double MinDistance = (CurrentImage.GetWidth() + CurrentImage.GetHeight()) / 20;
-    HUOFPointsNumber = MaxTrackedPoints = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000;
-
-    // Search good trackable points
-    cvGoodFeaturesToTrack(PreviousGray, TempEig, Temp,
-      HUOFPoints[0], &HUOFPointsNumber,
-      0.01, MinDistance, NULL, 3);
-    MaxTrackedPoints = HUOFPointsNumber;
-    // Release temporary images
-    cvReleaseImage(&TempEig);
-    cvReleaseImage(&Temp);
-    // Realloc the point status array
-    if (PointsStatus)
-    {
-      cvFree(&PointsStatus);
-      PointsStatus = NULL;
-    }
+        if (HUOFDataState != ps_Successful)
+        {
+          printf("Search new corners\n");
+          IplImage* TempEig = cvCreateImage(cvGetSize(CurrentGray), 32, 1);
+          IplImage* Temp = cvCreateImage(cvGetSize(CurrentGray), 32, 1);
+          double MinDistance = (CurrentImage.GetWidth() + CurrentImage.GetHeight()) / 20;
+          HUOFPointsNumber = MaxTrackedPoints = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000;
+
+          // Search good trackable points
+          cvGoodFeaturesToTrack(PreviousGray, TempEig, Temp,
+            (CvPoint2D32f*)HUOFPoints[0], &HUOFPointsNumber,
+            0.01, MinDistance, NULL, 3);
+          MaxTrackedPoints = HUOFPointsNumber;
+          // Release temporary images
+          cvReleaseImage(&TempEig);
+          cvReleaseImage(&Temp);
+          // Realloc the point status array
+          if (PointsStatus)
+          {
+            cvFree(&PointsStatus);
+            PointsStatus = NULL;
+          }
 
-    if (MaxTrackedPoints < 2)
-    {
-      HUOFDataState = ps_Initialized;
-      HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000;
-      return;
-    }
-    else
-      HUOFDataState = ps_Successful;
-    PointsStatus = (char*)cvAlloc(HUOFPointsNumber);
-  }
+          if (MaxTrackedPoints < 2)
+          {
+            HUOFDataState = ps_Initialized;
+            HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000;
+            return;
+          }
+          else
+            HUOFDataState = ps_Successful;
+          PointsStatus = (char*)cvAlloc(HUOFPointsNumber);
+        }
 
-  cvCalcOpticalFlowPyrLK(PreviousGray, CurrentGray, HUOFPrevPyramid, HUOFPyramid,
-    HUOFPoints[0], HUOFPoints[1], HUOFPointsNumber,
-    cvSize(10, 10), 3, PointsStatus, NULL,
-    cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 5, 1), 0);
+        cvCalcOpticalFlowPyrLK(PreviousGray, CurrentGray, HUOFPrevPyramid, HUOFPyramid,
+          HUOFPoints[0], HUOFPoints[1], HUOFPointsNumber,
+          cvSize(10, 10), 3, PointsStatus, NULL,
+          cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 5, 1), 0);
 
-  // Count the distances of the tracked points
-  int **Distances = new int*[HUOFPointsNumber];
-  for (int i = 0; i < HUOFPointsNumber; ++i)
-    Distances[i] = new int[3];
+        // Count the distances of the tracked points
+        int **Distances = new int*[HUOFPointsNumber];
+        for (int i = 0; i < HUOFPointsNumber; ++i)
+          Distances[i] = new int[3];
 
-  int DistanceMax = 0;
-  for (i = 0; i < HUOFPointsNumber; ++i)
-  {
-    int DiffX = (int)MERound(HUOFPoints[1][i].x - HUOFPoints[0][i].x);
-    int DiffY = (int)MERound(HUOFPoints[1][i].y - HUOFPoints[0][i].y);
-    if ((PointsStatus[i] == 1) && !((DiffX == 0) && (DiffY == 0)))
-    {
-      bool found = false;
-      // Create a list from the differences to count them
-      for (i1 = 0; i1 < DistanceMax; ++i1)
-      {
-        if ((Distances[i1][0] == DiffX) &&
-          (Distances[i1][1] == DiffY))
+        int DistanceMax = 0;
+        for (i = 0; i < HUOFPointsNumber; ++i)
         {
-          Distances[i1][2]++;
-          found = true;
-          break;
+          int DiffX = (int)MERound(HUOFPoints[1][i].x - HUOFPoints[0][i].x);
+          int DiffY = (int)MERound(HUOFPoints[1][i].y - HUOFPoints[0][i].y);
+          if ((PointsStatus[i] == 1) && !((DiffX == 0) && (DiffY == 0)))
+          {
+            bool found = false;
+            // Create a list from the differences to count them
+            for (i1 = 0; i1 < DistanceMax; ++i1)
+            {
+              if ((Distances[i1][0] == DiffX) &&
+                (Distances[i1][1] == DiffY))
+              {
+                Distances[i1][2]++;
+                found = true;
+                break;
+              }
+            }
+            if ((!found) && !((DiffX == 0) && (DiffY == 0)))
+            {
+              Distances[DistanceMax][0] = (int)MERound(HUOFPoints[1][i].x - HUOFPoints[0][i].x);
+              Distances[DistanceMax][1] = (int)MERound(HUOFPoints[1][i].y - HUOFPoints[0][i].y);
+              Distances[DistanceMax][2] = 1;
+              DistanceMax++;
+            }
+          }
         }
-      }
-      if ((!found) && !((DiffX == 0) && (DiffY == 0)))
-      {
-        Distances[DistanceMax][0] = (int)MERound(HUOFPoints[1][i].x - HUOFPoints[0][i].x);
-        Distances[DistanceMax][1] = (int)MERound(HUOFPoints[1][i].y - HUOFPoints[0][i].y);
-        Distances[DistanceMax][2] = 1;
-        DistanceMax++;
-      }
-    }
-  }
 
-  // Sort the results
-  for (int i1 = DistanceMax - 1; i1 >= 2; --i1)
-  {
-    for (int i = i1; i >= 1; --i)
-    {
-      if ((Distances[i][2] > Distances[i - 1][2]) ||
-        ((Distances[i][2] == Distances[i - 1][2]) &&
-        (abs(Distances[i][0]) + abs(Distances[i][1]) <
-          abs(Distances[i - 1][0]) + abs(Distances[i - 1][1]))))
-      {
-        int tmp = Distances[i][0];
-        int tmp2 = Distances[i][1];
-        int tmp3 = Distances[i][2];
-
-        Distances[i][0] = Distances[i - 1][0];
-        Distances[i][1] = Distances[i - 1][1];
-        Distances[i][2] = Distances[i - 1][2];
-
-        Distances[i - 1][0] = tmp;
-        Distances[i - 1][1] = tmp2;
-        Distances[i - 1][2] = tmp3;
-      }
-    }
-  }
-
-  float MoveX = 0.0;
-  float MoveY = 0.0;
-  int SampleNums = 0;
-  float DistanceMeasure = 0.0;
+        // Sort the results
+        for (int i1 = DistanceMax - 1; i1 >= 2; --i1)
+        {
+          for (int i = i1; i >= 1; --i)
+          {
+            if ((Distances[i][2] > Distances[i - 1][2]) ||
+              ((Distances[i][2] == Distances[i - 1][2]) &&
+              (abs(Distances[i][0]) + abs(Distances[i][1]) <
+                abs(Distances[i - 1][0]) + abs(Distances[i - 1][1]))))
+            {
+              int tmp = Distances[i][0];
+              int tmp2 = Distances[i][1];
+              int tmp3 = Distances[i][2];
 
-  // Calculate the final camera movement
-  for (i = 0; i < DistanceMax; ++i)
-  {
-    if ((Distances[i][2] <= MaxTrackedPoints / 10))
-      break;
+              Distances[i][0] = Distances[i - 1][0];
+              Distances[i][1] = Distances[i - 1][1];
+              Distances[i][2] = Distances[i - 1][2];
 
-    if (i > 0)
-    {
-      DistanceMeasure += (Distances[i][0] - Distances[i - 1][0])*(Distances[i][0] - Distances[i - 1][0]);
-      DistanceMeasure += (Distances[i][1] - Distances[i - 1][1])*(Distances[i][1] - Distances[i - 1][1]);
-    }
+              Distances[i - 1][0] = tmp;
+              Distances[i - 1][1] = tmp2;
+              Distances[i - 1][2] = tmp3;
+            }
+          }
+        }
 
-    MoveX += Distances[i][0] * Distances[i][2];
-    MoveY += Distances[i][1] * Distances[i][2];
-    SampleNums += Distances[i][2];
-  }
+        float MoveX = 0.0;
+        float MoveY = 0.0;
+        int SampleNums = 0;
+        float DistanceMeasure = 0.0;
 
-  if (SampleNums > 0)
-  {
-    MoveX = MERound(MoveX / SampleNums);
-    MoveY = MERound(MoveY / SampleNums);
-  }
+        // Calculate the final camera movement
+        for (i = 0; i < DistanceMax; ++i)
+        {
+          if ((Distances[i][2] <= MaxTrackedPoints / 10))
+            break;
 
-  if (!((MoveX == 0) && (MoveY == 0)) &&
-    (SampleNums > MaxTrackedPoints / 2))
-  {
-    HUOFCamMovementX += (int)MoveX;
-    int HUOFCamMovementY = (int)MoveY;
-    int MaxX = (HUImageWidth / 2) - 1;
-    int MaxY = HUImageHeight - 1;
-    /*
-    printf("-----------\n");
-
-    for (i = 0; i < DistanceMax; ++i)
-    printf("%d: %d,%d\n", Distances[i][2], Distances[i][0], Distances[i][1]);
-
-    printf("FINAL: %d,%d,%1.2f\n", (int)MoveX, (int)MoveY, DistanceMeasure);
-    printf("-----------\n");
-    printf("Camera movement: %d,%d,%d (max: %d, current: %d)\n",
-    SampleNums, HUOFCamMovementX, HUOFCamMovementY, MaxTrackedPoints, HUOFPointsNumber);
-    */
-    HUOFFrames = 0;
-    HUOFCamMovement = true;
-
-    if (!(HUOFCamMovementY == 0 && HUOFCamMovementX >= -1 && HUOFCamMovementX <= 1))
-    {
-      MEPixelDataType ***PreviousData = new MEPixelDataType**[MaxX + 1];
+          if (i > 0)
+          {
+            DistanceMeasure += (Distances[i][0] - Distances[i - 1][0])*(Distances[i][0] - Distances[i - 1][0]);
+            DistanceMeasure += (Distances[i][1] - Distances[i - 1][1])*(Distances[i][1] - Distances[i - 1][1]);
+          }
 
-      for (int i = 0; i < MaxX + 1; ++i)
-        PreviousData[i] = new MEPixelDataType*[MaxY + 1];
+          MoveX += Distances[i][0] * Distances[i][2];
+          MoveY += Distances[i][1] * Distances[i][2];
+          SampleNums += Distances[i][2];
+        }
 
-      // Camera movement being happened
-      for (int y = MaxY; y >= 0; --y)
-      {
-        for (int x = MaxX; x >= 0; --x)
+        if (SampleNums > 0)
         {
-          PreviousData[x][y] = NULL;
+          MoveX = MERound(MoveX / SampleNums);
+          MoveY = MERound(MoveY / SampleNums);
         }
-      }
 
-      // Move the LBP data to new locations
-      for (int y = MaxY; y >= 0; --y)
-      {
-        for (int x = MaxX; x >= 0; --x)
+        if (!((MoveX == 0) && (MoveY == 0)) &&
+          (SampleNums > MaxTrackedPoints / 2))
         {
-          int NewX = x + (HUOFCamMovementX / 2);
-          int NewY = y + HUOFCamMovementY;
-
-          if (NewX >= 0 && NewX <= MaxX &&
-            NewY >= 0 && NewY <= MaxY)
+          HUOFCamMovementX += (int)MoveX;
+          int HUOFCamMovementY = (int)MoveY;
+          int MaxX = (HUImageWidth / 2) - 1;
+          int MaxY = HUImageHeight - 1;
+          /*
+          printf("-----------\n");
+
+          for (i = 0; i < DistanceMax; ++i)
+          printf("%d: %d,%d\n", Distances[i][2], Distances[i][0], Distances[i][1]);
+
+          printf("FINAL: %d,%d,%1.2f\n", (int)MoveX, (int)MoveY, DistanceMeasure);
+          printf("-----------\n");
+          printf("Camera movement: %d,%d,%d (max: %d, current: %d)\n",
+          SampleNums, HUOFCamMovementX, HUOFCamMovementY, MaxTrackedPoints, HUOFPointsNumber);
+          */
+          HUOFFrames = 0;
+          HUOFCamMovement = true;
+
+          if (!(HUOFCamMovementY == 0 && HUOFCamMovementX >= -1 && HUOFCamMovementX <= 1))
           {
-            if (HULBPPixelData[NewX][NewY])
+            MEPixelDataType ***PreviousData = new MEPixelDataType**[MaxX + 1];
+
+            for (int i = 0; i < MaxX + 1; ++i)
+              PreviousData[i] = new MEPixelDataType*[MaxY + 1];
+
+            // Camera movement being happened
+            for (int y = MaxY; y >= 0; --y)
             {
-              PreviousData[NewX][NewY] = HULBPPixelData[NewX][NewY];
-              HULBPPixelData[NewX][NewY] = NULL;
-              if (PreviousData[x][y])
+              for (int x = MaxX; x >= 0; --x)
               {
-                HULBPPixelData[NewX][NewY] = PreviousData[x][y];
                 PreviousData[x][y] = NULL;
               }
-              else
-              {
-                HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y];
-                HULBPPixelData[x][y] = NULL;
-              }
             }
-            else
+
+            // Move the LBP data to new locations
+            for (int y = MaxY; y >= 0; --y)
             {
-              if (PreviousData[x][y])
+              for (int x = MaxX; x >= 0; --x)
               {
-                HULBPPixelData[NewX][NewY] = PreviousData[x][y];
-                PreviousData[x][y] = NULL;
+                int NewX = x + (HUOFCamMovementX / 2);
+                int NewY = y + HUOFCamMovementY;
+
+                if (NewX >= 0 && NewX <= MaxX &&
+                  NewY >= 0 && NewY <= MaxY)
+                {
+                  if (HULBPPixelData[NewX][NewY])
+                  {
+                    PreviousData[NewX][NewY] = HULBPPixelData[NewX][NewY];
+                    HULBPPixelData[NewX][NewY] = NULL;
+                    if (PreviousData[x][y])
+                    {
+                      HULBPPixelData[NewX][NewY] = PreviousData[x][y];
+                      PreviousData[x][y] = NULL;
+                    }
+                    else
+                    {
+                      HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y];
+                      HULBPPixelData[x][y] = NULL;
+                    }
+                  }
+                  else
+                  {
+                    if (PreviousData[x][y])
+                    {
+                      HULBPPixelData[NewX][NewY] = PreviousData[x][y];
+                      PreviousData[x][y] = NULL;
+                    }
+                    else
+                    {
+                      HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y];
+                      HULBPPixelData[x][y] = NULL;
+                    }
+                  }
+                }
+                else
+                {
+                  if (HULBPPixelData[x][y])
+                  {
+                    delete[] HULBPPixelData[x][y]->PreviousHistogram;
+                    for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+                      delete[] HULBPPixelData[x][y]->Histograms[i2];
+                    delete[] HULBPPixelData[x][y]->Histograms;
+                    delete[] HULBPPixelData[x][y]->BackgroundHistogram;
+                    delete[] HULBPPixelData[x][y]->Weights;
+                    delete HULBPPixelData[x][y];
+                    HULBPPixelData[x][y] = NULL;
+                  }
+                }
               }
-              else
+            }
+
+            // Release unused data
+            for (int y = MaxY; y >= 0; --y)
+            {
+              for (int x = MaxX; x >= 0; --x)
               {
-                HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y];
-                HULBPPixelData[x][y] = NULL;
+                if (PreviousData[x][y])
+                {
+                  delete[] PreviousData[x][y]->PreviousHistogram;
+                  for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+                    delete[] PreviousData[x][y]->Histograms[i2];
+                  delete[] PreviousData[x][y]->Histograms;
+                  delete[] PreviousData[x][y]->BackgroundHistogram;
+                  delete[] PreviousData[x][y]->Weights;
+                  delete PreviousData[x][y];
+                  PreviousData[x][y] = NULL;
+                }
               }
             }
+
+            HUOFCamMovementX = HUOFCamMovementX % 1;
+
+            for (int i = 0; i < MaxX + 1; ++i)
+              delete[] PreviousData[i];
+            delete[] PreviousData;
           }
-          else
+        }
+
+        i1 = 0;
+        // Throw the missed points away
+        for (i = 0; i < HUOFPointsNumber; ++i)
+        {
+          if (PointsStatus[i] == 1)
           {
-            if (HULBPPixelData[x][y])
-            {
-              delete[] HULBPPixelData[x][y]->PreviousHistogram;
-              for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
-                delete[] HULBPPixelData[x][y]->Histograms[i2];
-              delete[] HULBPPixelData[x][y]->Histograms;
-              delete[] HULBPPixelData[x][y]->BackgroundHistogram;
-              delete[] HULBPPixelData[x][y]->Weights;
-              delete HULBPPixelData[x][y];
-              HULBPPixelData[x][y] = NULL;
-            }
+            HUOFPoints[0][i1] = HUOFPoints[1][i];
+            i1++;
           }
         }
+        HUOFPointsNumber -= i + 1 - i1;
+
+        if (HUOFPointsNumber < MaxTrackedPoints / 2)
+        {
+          printf("Re-init the optical flow\n");
+          HUOFDataState = ps_Initialized;
+          HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000;
+        }
+        // Free memory
+        if (PreviousGray != PreviousImage.GetIplImage())
+          cvReleaseImage(&PreviousGray);
+        if (CurrentGray != CurrentImage.GetIplImage())
+          cvReleaseImage(&CurrentGray);
+        cvFree(&PointsStatus);
+
+        for (int i = 0; i < HUOFPointsNumber; ++i)
+          delete[] Distances[i];
+        delete[] Distances;
       }
 
-      // Release unused data
-      for (int y = MaxY; y >= 0; --y)
+      void MotionDetection::GetMotionsMaskHU(MEImage& mask_image)
       {
-        for (int x = MaxX; x >= 0; --x)
+        if (MDDataState != ps_Successful)
+        {
+          mask_image.Clear();
+          return;
+        }
+
+        // Reallocate the mask image if needs be
+        if ((HUImageWidth + HUHistogramArea - 1 != mask_image.GetWidth()) ||
+          (HUImageHeight + HUHistogramArea - 1 != mask_image.GetHeight()) ||
+          (mask_image.GetLayers() != 1))
         {
-          if (PreviousData[x][y])
+          mask_image.Realloc(HUImageWidth + HUHistogramArea - 1,
+            HUImageHeight + HUHistogramArea - 1, 1);
+        }
+        mask_image.Clear();
+        // Generate the mask image
+        unsigned char* MaskImgData = mask_image.GetImageData();
+        int RowStart = (mask_image.GetHeight() - HUHistogramArea / 2)*mask_image.GetRowWidth();
+        int RowWidth = mask_image.GetRowWidth();
+
+        // Generate a graph about the histogram data
+        Graph::node_id **Nodes = new Graph::node_id*[HUImageWidth / 2];
+        for (int i = 0; i < HUImageWidth / 2; ++i)
+          Nodes[i] = new Graph::node_id[HUImageHeight];
+        Graph *LBPGraph = new Graph();
+
+        for (int x = (HUImageWidth / 2) - 1; x >= 0; --x)
+        {
+          for (int y = HUImageHeight - 1; y >= 0; --y)
           {
-            delete[] PreviousData[x][y]->PreviousHistogram;
-            for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
-              delete[] PreviousData[x][y]->Histograms[i2];
-            delete[] PreviousData[x][y]->Histograms;
-            delete[] PreviousData[x][y]->BackgroundHistogram;
-            delete[] PreviousData[x][y]->Weights;
-            delete PreviousData[x][y];
-            PreviousData[x][y] = NULL;
+            Nodes[x][y] = LBPGraph->add_node();
           }
         }
-      }
 
-      HUOFCamMovementX = HUOFCamMovementX % 1;
-
-      for (int i = 0; i < MaxX + 1; ++i)
-        delete[] PreviousData[i];
-      delete[] PreviousData;
-    }
-  }
+        for (int x = (HUImageWidth / 2) - 1; x >= 0; --x)
+        {
+          for (int y = HUImageHeight - 1; y >= 0; --y)
+          {
+            LBPGraph->set_tweights(Nodes[x][y], 1,
+              (short int)(HUMinCutWeight*(1 - HULBPPixelData[x][y]->BackgroundRate)));
 
-  i1 = 0;
-  // Throw the missed points away
-  for (i = 0; i < HUOFPointsNumber; ++i)
-  {
-    if (PointsStatus[i] == 1)
-    {
-      HUOFPoints[0][i1] = HUOFPoints[1][i];
-      i1++;
-    }
-  }
-  HUOFPointsNumber -= i + 1 - i1;
+            if (x > 0 && y > 0)
+            {
+              LBPGraph->add_edge(Nodes[x][y], Nodes[x - 1][y], 1, 1);
+              LBPGraph->add_edge(Nodes[x][y], Nodes[x][y - 1], 1, 1);
+            }
+          }
+        }
 
-  if (HUOFPointsNumber < MaxTrackedPoints / 2)
-  {
-    printf("Re-init the optical flow\n");
-    HUOFDataState = ps_Initialized;
-    HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000;
-  }
-  // Free memory
-  if (PreviousGray != PreviousImage.GetIplImage())
-    cvReleaseImage(&PreviousGray);
-  if (CurrentGray != CurrentImage.GetIplImage())
-    cvReleaseImage(&CurrentGray);
-  cvFree(&PointsStatus);
-
-  for (int i = 0; i < HUOFPointsNumber; ++i)
-    delete[] Distances[i];
-  delete[] Distances;
-}
+        LBPGraph->maxflow();
 
-void MotionDetection::GetMotionsMaskHU(MEImage& mask_image)
-{
-  if (MDDataState != ps_Successful)
-  {
-    mask_image.Clear();
-    return;
-  }
+        for (int x = (HUImageWidth / 2) - 1; x >= 0; --x)
+        {
+          for (int y = HUImageHeight - 1; y >= 0; --y)
+          {
+            if (LBPGraph->what_segment(Nodes[x][y]) == Graph::SINK)
+              HULBPPixelData[x][y]->BackgroundRate = 0.0;
+            else
+              HULBPPixelData[x][y]->BackgroundRate = 1.0;
+          }
+        }
 
-  // Reallocate the mask image if needs be
-  if ((HUImageWidth + HUHistogramArea - 1 != mask_image.GetWidth()) ||
-    (HUImageHeight + HUHistogramArea - 1 != mask_image.GetHeight()) ||
-    (mask_image.GetLayers() != 1))
-  {
-    mask_image.Realloc(HUImageWidth + HUHistogramArea - 1,
-      HUImageHeight + HUHistogramArea - 1, 1);
-  }
-  mask_image.Clear();
-  // Generate the mask image
-  unsigned char* MaskImgData = mask_image.GetImageData();
-  int RowStart = (mask_image.GetHeight() - HUHistogramArea / 2)*mask_image.GetRowWidth();
-  int RowWidth = mask_image.GetRowWidth();
-
-  // Generate a graph about the histogram data
-  Graph::node_id **Nodes = new Graph::node_id*[HUImageWidth / 2];
-  for (int i = 0; i < HUImageWidth / 2; ++i)
-    Nodes[i] = new Graph::node_id[HUImageHeight];
-  Graph *LBPGraph = new Graph();
-
-  for (int x = (HUImageWidth / 2) - 1; x >= 0; --x)
-  {
-    for (int y = HUImageHeight - 1; y >= 0; --y)
-    {
-      Nodes[x][y] = LBPGraph->add_node();
-    }
-  }
+        delete LBPGraph;
+        LBPGraph = NULL;
+        for (int y = HUImageHeight - 1; y >= 0; --y)
+        {
+          for (int x = HUImageWidth - 1; x >= 0; --x)
+          {
+            if (y % 2 == (x + 1) % 2)
+              MaskImgData[RowStart + x + (HUHistogramArea / 2)] =
+              (HULBPPixelData[x / 2][y]->BackgroundRate == 0.0) ? 255 : 0;
+            else
+            {
+              MaskImgData[RowStart + x + (HUHistogramArea / 2)] =
+                ((int)(x > 1 && HULBPPixelData[(x / 2) - 1][y]->BackgroundRate == 0.0) +
+                (int)(x < mask_image.GetWidth() - HUHistogramArea - 1 &&
+                  HULBPPixelData[(x / 2) + 1][y]->BackgroundRate == 0.0) +
+                  (int)(y > 0 && HULBPPixelData[x / 2][y - 1]->BackgroundRate == 0.0) +
+                  (int)(y < mask_image.GetHeight() - HUHistogramArea &&
+                    HULBPPixelData[x / 2][y + 1]->BackgroundRate == 0.0) > 1)
+                ? 255 : 0;
+            }
+          }
+          RowStart -= RowWidth;
+        }
 
-  for (int x = (HUImageWidth / 2) - 1; x >= 0; --x)
-  {
-    for (int y = HUImageHeight - 1; y >= 0; --y)
-    {
-      LBPGraph->set_tweights(Nodes[x][y], 1,
-        (short int)(HUMinCutWeight*(1 - HULBPPixelData[x][y]->BackgroundRate)));
+        cvFloodFill(mask_image.GetIplImage(), cvPoint(0, 0), cvScalar(128, 128, 128, 128),
+          cvScalar(0, 0, 0, 0), cvScalar(0, 0, 0, 0));
+        for (int i = ((IplImage*)mask_image.GetIplImage())->widthStep*((IplImage*)mask_image.GetIplImage())->height - 1; i >= 0; --i)
+        {
+          if (MaskImgData[i] == 128)
+          {
+            MaskImgData[i] = 0;
+          }
+          else
+          {
+            if (MaskImgData[i] == 0)
+            {
+              MaskImgData[i] = 255;
+            }
+          }
+        }
+        // Apply an erode operator
+        mask_image.Erode(1);
 
-      if (x > 0 && y > 0)
-      {
-        LBPGraph->add_edge(Nodes[x][y], Nodes[x - 1][y], 1, 1);
-        LBPGraph->add_edge(Nodes[x][y], Nodes[x][y - 1], 1, 1);
+        for (int i = 0; i < HUImageWidth / 2; ++i)
+          delete[] Nodes[i];
+        delete[] Nodes;
       }
-    }
-  }
 
-  LBPGraph->maxflow();
+      void MotionDetection::SetSampleMaskHU(SampleMaskType mask_type, int desiredarea)
+      {
+        if (HUMaskColumnAddDel == NULL || HUMaskRowAddDel == NULL)
+        {
+          printf("Auxiliary variables are NULL\n");
+          return;
+        }
 
-  for (int x = (HUImageWidth / 2) - 1; x >= 0; --x)
-  {
-    for (int y = HUImageHeight - 1; y >= 0; --y)
-    {
-      if (LBPGraph->what_segment(Nodes[x][y]) == Graph::SINK)
-        HULBPPixelData[x][y]->BackgroundRate = 0.0;
-      else
-        HULBPPixelData[x][y]->BackgroundRate = 1.0;
-    }
-  }
+        // Generate a mask for computing the histograms
+        IplImage *MaskImage = cvCreateImage(cvSize(HUHistogramArea, HUHistogramArea), 8, 1);
+        int DesiredArea = desiredarea <= 0 ? HUHistogramBins * 2 : desiredarea;
 
-  delete LBPGraph;
-  LBPGraph = NULL;
-  for (int y = HUImageHeight - 1; y >= 0; --y)
-  {
-    for (int x = HUImageWidth - 1; x >= 0; --x)
-    {
-      if (y % 2 == (x + 1) % 2)
-        MaskImgData[RowStart + x + (HUHistogramArea / 2)] =
-        (HULBPPixelData[x / 2][y]->BackgroundRate == 0.0) ? 255 : 0;
-      else
-      {
-        MaskImgData[RowStart + x + (HUHistogramArea / 2)] =
-          ((int)(x > 1 && HULBPPixelData[(x / 2) - 1][y]->BackgroundRate == 0.0) +
-          (int)(x < mask_image.GetWidth() - HUHistogramArea - 1 &&
-            HULBPPixelData[(x / 2) + 1][y]->BackgroundRate == 0.0) +
-            (int)(y > 0 && HULBPPixelData[x / 2][y - 1]->BackgroundRate == 0.0) +
-            (int)(y < mask_image.GetHeight() - HUHistogramArea &&
-              HULBPPixelData[x / 2][y + 1]->BackgroundRate == 0.0) > 1)
-          ? 255 : 0;
-      }
-    }
-    RowStart -= RowWidth;
-  }
+        int **CalculationMask = new int*[HUHistogramArea];
+        for (int i = 0; i < HUHistogramArea; ++i)
+          CalculationMask[i] = new int[HUHistogramArea];
 
-  cvFloodFill(mask_image.GetIplImage(), cvPoint(0, 0), cvScalar(128, 128, 128, 128),
-    cvScalar(0, 0, 0, 0), cvScalar(0, 0, 0, 0));
-  for (int i = ((IplImage*)mask_image.GetIplImage())->widthStep*((IplImage*)mask_image.GetIplImage())->height - 1; i >= 0; --i)
-  {
-    if (MaskImgData[i] == 128)
-    {
-      MaskImgData[i] = 0;
-    }
-    else
-    {
-      if (MaskImgData[i] == 0)
-      {
-        MaskImgData[i] = 255;
-      }
-    }
-  }
-  // Apply an erode operator
-  mask_image.Erode(1);
+        int SquareSide = (int)MERound(sqrt((float)DesiredArea));
+        int CircleRadius = (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE));
+        int EllipseA = (int)MERound(HUHistogramArea / 2 + 1);
+        int EllipseB = (int)MERound(DesiredArea / (EllipseA*1.2*ME_PI_VALUE));
 
-  for (int i = 0; i < HUImageWidth / 2; ++i)
-    delete[] Nodes[i];
-  delete[] Nodes;
-}
+        cvSetZero(MaskImage);
 
-void MotionDetection::SetSampleMaskHU(SampleMaskType mask_type, int desiredarea)
-{
-  if (HUMaskColumnAddDel == NULL || HUMaskRowAddDel == NULL)
-  {
-    printf("Auxiliary variables are NULL\n");
-    return;
-  }
+        switch (mask_type)
+        {
+        case sm_Circle:
+          cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2),
+            CircleRadius, CV_RGB(1, 1, 1), -1);
+          break;
 
-  // Generate a mask for computing the histograms
-  IplImage *MaskImage = cvCreateImage(cvSize(HUHistogramArea, HUHistogramArea), 8, 1);
-  int DesiredArea = desiredarea <= 0 ? HUHistogramBins * 2 : desiredarea;
+        case sm_Square:
+          cvRectangle(MaskImage,
+            cvPoint(HUHistogramArea / 2 - SquareSide / 2, HUHistogramArea / 2 - SquareSide / 2),
+            cvPoint(HUHistogramArea / 2 + SquareSide / 2, HUHistogramArea / 2 + SquareSide / 2),
+            CV_RGB(1, 1, 1), -1);
+          break;
 
-  int **CalculationMask = new int*[HUHistogramArea];
-  for (int i = 0; i < HUHistogramArea; ++i)
-    CalculationMask[i] = new int[HUHistogramArea];
+        case sm_Ellipse:
+          cvEllipse(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2),
+            cvSize(EllipseA, EllipseB), 45, 0, 360,
+            CV_RGB(1, 1, 1), -1);
+          break;
 
-  int SquareSide = (int)MERound(sqrt((float)DesiredArea));
-  int CircleRadius = (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE));
-  int EllipseA = (int)MERound(HUHistogramArea / 2 + 1);
-  int EllipseB = (int)MERound(DesiredArea / (EllipseA*1.2*ME_PI_VALUE));
+        case sm_RandomPixels:
+          HUSamplePixels = 0;
+          while (HUSamplePixels != DesiredArea)
+          {
+            int i = rand() % HUHistogramArea;
+            int j = rand() % HUHistogramArea;
 
-  cvSetZero(MaskImage);
+            if (MaskImage->imageData[i*MaskImage->widthStep + j] == 0)
+            {
+              MaskImage->imageData[i*MaskImage->widthStep + j] = 1;
+              HUSamplePixels++;
+            }
+          }
+          break;
 
-  switch (mask_type)
-  {
-  case sm_Circle:
-    cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2),
-      CircleRadius, CV_RGB(1, 1, 1), -1);
-    break;
-
-  case sm_Square:
-    cvRectangle(MaskImage,
-      cvPoint(HUHistogramArea / 2 - SquareSide / 2, HUHistogramArea / 2 - SquareSide / 2),
-      cvPoint(HUHistogramArea / 2 + SquareSide / 2, HUHistogramArea / 2 + SquareSide / 2),
-      CV_RGB(1, 1, 1), -1);
-    break;
-
-  case sm_Ellipse:
-    cvEllipse(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2),
-      cvSize(EllipseA, EllipseB), 45, 0, 360,
-      CV_RGB(1, 1, 1), -1);
-    break;
-
-  case sm_RandomPixels:
-    HUSamplePixels = 0;
-    while (HUSamplePixels != DesiredArea)
-    {
-      int i = rand() % HUHistogramArea;
-      int j = rand() % HUHistogramArea;
+        default:
+          cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2),
+            (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE)), CV_RGB(1, 1, 1), -1);
+          break;
+        }
 
-      if (MaskImage->imageData[i*MaskImage->widthStep + j] == 0)
-      {
-        MaskImage->imageData[i*MaskImage->widthStep + j] = 1;
-        HUSamplePixels++;
-      }
-    }
-    break;
+        HUSamplePixels = 0;
+        //memset(CalculationMask, 0, sizeof(CalculationMask));
 
-  default:
-    cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2),
-      (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE)), CV_RGB(1, 1, 1), -1);
-    break;
-  }
+        for (int i = 0; i < HUHistogramArea; ++i)
+        {
+          for (int i1 = 0; i1 < HUHistogramArea; ++i1)
+          {
+            if (MaskImage->imageData[i*MaskImage->widthStep + i1] != 0)
+            {
+              HUSamplePixels++;
+              CalculationMask[i][i1] = 1;
+            }
+            else {
+              CalculationMask[i][i1] = 0;
+            }
+          }
+        }
 
-  HUSamplePixels = 0;
-  //memset(CalculationMask, 0, sizeof(CalculationMask));
+        // Fill an auxiliary variable for fast computing with data
+        for (int i = 0; i < HUHistogramArea; ++i)
+        {
+          HUMaskColumnAddDel[i][0] = -1;
+          for (int i1 = 0; i1 < HUHistogramArea; ++i1)
+          {
+            if (CalculationMask[i][i1] != 0)
+            {
+              HUMaskColumnAddDel[i][0] = i1;
+              break;
+            }
+          }
+          HUMaskColumnAddDel[i][1] = -1;
+          for (int i1 = HUHistogramArea - 1; i1 >= 0; --i1)
+          {
+            if (CalculationMask[i][i1] != 0)
+            {
+              HUMaskColumnAddDel[i][1] = i1 + 1;
+              break;
+            }
+          }
+        }
 
-  for (int i = 0; i < HUHistogramArea; ++i)
-  {
-    for (int i1 = 0; i1 < HUHistogramArea; ++i1)
-    {
-      if (MaskImage->imageData[i*MaskImage->widthStep + i1] != 0)
-      {
-        HUSamplePixels++;
-        CalculationMask[i][i1] = 1;
-      }
-      else {
-        CalculationMask[i][i1] = 0;
-      }
-    }
-  }
+        // Fill an auxiliary variable for fast computing with data
+        for (int i = 0; i < HUHistogramArea; ++i)
+        {
+          HUMaskRowAddDel[i][0] = -1;
+          for (int i1 = 0; i1 < HUHistogramArea; ++i1)
+          {
+            if (CalculationMask[i1][i] != 0)
+            {
+              HUMaskRowAddDel[i][0] = i1;
+              break;
+            }
+          }
+          HUMaskRowAddDel[i][1] = -1;
+          for (int i1 = HUHistogramArea - 1; i1 >= 0; --i1)
+          {
+            if (CalculationMask[i1][i] != 0)
+            {
+              HUMaskRowAddDel[i][1] = i1 + 1;
+              break;
+            }
+          }
+        }
 
-  // Fill an auxiliary variable for fast computing with data
-  for (int i = 0; i < HUHistogramArea; ++i)
-  {
-    HUMaskColumnAddDel[i][0] = -1;
-    for (int i1 = 0; i1 < HUHistogramArea; ++i1)
-    {
-      if (CalculationMask[i][i1] != 0)
-      {
-        HUMaskColumnAddDel[i][0] = i1;
-        break;
-      }
-    }
-    HUMaskColumnAddDel[i][1] = -1;
-    for (int i1 = HUHistogramArea - 1; i1 >= 0; --i1)
-    {
-      if (CalculationMask[i][i1] != 0)
-      {
-        HUMaskColumnAddDel[i][1] = i1 + 1;
-        break;
-      }
-    }
-  }
+        // Freeing memory
+        cvReleaseImage(&MaskImage);
 
-  // Fill an auxiliary variable for fast computing with data
-  for (int i = 0; i < HUHistogramArea; ++i)
-  {
-    HUMaskRowAddDel[i][0] = -1;
-    for (int i1 = 0; i1 < HUHistogramArea; ++i1)
-    {
-      if (CalculationMask[i1][i] != 0)
-      {
-        HUMaskRowAddDel[i][0] = i1;
-        break;
-      }
-    }
-    HUMaskRowAddDel[i][1] = -1;
-    for (int i1 = HUHistogramArea - 1; i1 >= 0; --i1)
-    {
-      if (CalculationMask[i1][i] != 0)
-      {
-        HUMaskRowAddDel[i][1] = i1 + 1;
-        break;
+        for (int i = 0; i < HUHistogramArea; ++i)
+          delete[] CalculationMask[i];
+        delete[] CalculationMask;
       }
     }
   }
-
-  // Freeing memory
-  cvReleaseImage(&MaskImage);
-
-  for (int i = 0; i < HUHistogramArea; ++i)
-    delete[] CalculationMask[i];
-  delete[] CalculationMask;
 }
 
 #endif
diff --git a/src/algorithms/LBP_MRF/MotionDetection.hpp b/src/algorithms/LBP_MRF/MotionDetection.hpp
index ff47011c211449f39529200999be93dd7fc9219c..f7720e5d2198275130c20c7762760fa91b129d81 100644
--- a/src/algorithms/LBP_MRF/MotionDetection.hpp
+++ b/src/algorithms/LBP_MRF/MotionDetection.hpp
@@ -3,373 +3,384 @@
 #include "opencv2/core/version.hpp"
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
+#include <opencv2/imgproc/types_c.h>
+
 #include "MEDefs.hpp"
 #include "MEImage.hpp"
 
-class CvBGStatModel;
-struct CvPoint2D32f;
-
-// Struct for histogram update data of a pixel
-struct MEPixelDataType;
-
-/**
- * MotionDetection
- * @brief Extract moving objects from image sequence
- */
-class MotionDetection
+namespace bgslibrary
 {
-public:
-
-  /// Types of motion detection
-  typedef enum
-  {
-    md_Min = 0,               /*!< Minimum value */
-    md_NotDefined = md_Min,   /*!< Not defined */
-    md_DLBPHistograms,        /*!< Dynamic LBP */
-    md_LBPHistograms,         /*!< Normal LBP */
-    md_Max = md_LBPHistograms /*!< Maximum value */
-  } DetectorType;
-
-  /// Types of sample mask
-  typedef enum
-  {
-    sm_Min = 0,              /*!< Minimum value */
-    sm_Circle = sm_Min,      /*!< Circle */
-    sm_Square,               /*!< Square */
-    sm_Ellipse,              /*!< Ellipse */
-    sm_RandomPixels,         /*!< Random pixels */
-    sm_Max = sm_RandomPixels /*!< Maximum value */
-  } SampleMaskType;
-
-  /// Types of motion detection parameters
-  typedef enum
+  namespace algorithms
   {
-    mdp_Min = 0,                         /*!< Minimum value */
-    mdp_HUProximityThreshold = mdp_Min,  /*!< Proximity threshold */
-    mdp_HUBackgroundThreshold,           /*!< Background threshold */
-    mdp_HUHistogramLearningRate,         /*!< Histogram learning rate */
-    mdp_HUWeightsLearningRate,           /*!< Weights learning rate */
-    mdp_HUMinCutWeight,                  /*!< Minimum cut weight */
-    mdp_HUDesiredSamplePixels,           /*!< Desired sample pixels */
-    mdp_HUHistogramsPerPixel,            /*!< Histogram per pixel */
-    mdp_HUHistogramArea,                 /*!< Histogram area */
-    mdp_HUHistogramBins,                 /*!< Histogram bins */
-    mdp_HUColorSpace,                    /*!< Color space */
-    mdp_HULBPMode,                       /*!< LBP mode */
-    mdp_Max = mdp_HULBPMode              /*!< Maximum value */
-  } ParametersType;
-
-  /*!
-   * @brief Class constructor
-   *
-   * @param mode Detection mode
-   *
-   * Class constructor with the possibility to specify the detection mode.
-   * The default is dynamic LBP.
-   *
-   */
-
-  MotionDetection(DetectorType mode = md_DLBPHistograms);
-  /// Destructor of class
-  ~MotionDetection();
-
-  /*
-  -------------------------------------------------------------------
-                           Motion methods
-  -------------------------------------------------------------------
-  */
-
-  /*!
-   * @brief Set the mode of the motion detection
-   *
-   * @param newmode New mode of detection
-   *
-   * Set the mode of the motion detection.
-   *
-   */
-
-  void SetMode(DetectorType newmode);
-
-  /*!
-   * @brief Get a parameter value of the motion detection
-   *
-   * @param param Parameter of the detection
-   *
-   * @return Queried value
-   *
-   * Get the value of a parameter of the motion detection.
-   *
-   */
-
-  float GetParameter(ParametersType param) const;
-
-  /*!
-   * @brief Set a parameter of the motion detection
-   *
-   * @param param Parameter of the detection
-   * @param value New value
-   *
-   * Set a new value to a parameter of the motion detection.
-   *
-   */
-
-  void SetParameter(ParametersType param, float value);
-
-  /*!
-   * @brief Detect the motions on an image
-   *
-   * @param image Image to process
-   *
-   * The function designed to search motions in image streams
-   * thus it needs to process the image sequence frame by frame.
-   * It processes an image from this sequence and searches moving blobs
-   * on that.
-   *
-   */
-
-  void DetectMotions(MEImage& image);
-
-  /*!
-   * @brief Get mask image with detected motions
-   *
-   * @param mask_image Result mask image
-   *
-   * The function creates a mask image on which the objects are
-   * indicated by white blobs.
-   *
-   */
-
-  void GetMotionsMask(MEImage& mask_image);
-
-  /*!
-   * @brief Calculate results of the motion detection
-   *
-   * @param referenceimage Reference mask image
-   * @param tnegatives True negative pixels
-   * @param tpositives True positive pixels
-   * @param ttnegatives Total true negative pixels
-   * @param ttpositives Total true positive pixels
-   *
-   * The function calculates the results of the motion detection
-   * between the current motion mask and a given reference mask
-   * image.
-   *
-   */
-
-  void CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives,
-    int& ttnegatives, int& ttpositives);
-
-private:
-
-  /*!
-   * @brief Release data structures
-   *
-   * Function releases the data structures.
-   *
-   */
-
-  void ReleaseData();
-
-  /*
-  -------------------------------------------------------------------
-                    Histogram update methods
-  -------------------------------------------------------------------
-  */
-
-  /*!
-   * @brief Init HU data structures
-   *
-   * @param imagewidth Image width for HU to process
-   * @param imageheight Image height for HU to process
-   *
-   * Function allocates/re-allocates the HU data structures and they
-   * are cleared if needs be.
-   *
-   */
-
-  void InitHUData(int imagewidth, int imageheight);
-
-  /*!
-   * @brief Init HU optical flow data structures
-   *
-   * @param imagewidth Image width for HU to process
-   * @param imageheight Image height for HU to process
-   *
-   * Function allocates/re-allocates the HU optical flow
-   * data structures.
-   *
-   */
-
-  void InitHUOFData(int imagewidth, int imageheight);
-
-  /*!
-   * @brief Release HU data structures
-   *
-   * Function releases the HU data structures.
-   *
-   */
-
-  void ReleaseHUData();
-
-  /*!
-   * @brief Release HU optical flow data structures
-   *
-   * Function releases the HU optical flow data structures.
-   *
-   */
-
-  void ReleaseHUOFData();
-
-  /*!
-   * @brief Clear HU data structures
-   *
-   * Function clears the HU data structures.
-   *
-   */
-
-  void ClearHUData();
-
-  /*!
-   * @brief Get mask image with detected motions by histogram update
-   *
-   * @param mask_image Result mask image
-   *
-   * The function creates a mask image on which the objects are
-   * indicated by white blobs.
-   *
-   */
-
-  void GetMotionsMaskHU(MEImage& mask_image);
-
-  /*!
-   * @brief Set the sample mask
-   *
-   * @param mask_type Type of the mask
-   * @param desiredarea The desired area size of the mask
-   *
-   * The function creates a sample mask with a desired form
-   * (square, circle, ellipse, random pixels) and size.
-   *
-   */
-
-  void SetSampleMaskHU(SampleMaskType mask_type, int desiredarea);
-
-  /*!
-   * @brief Detect the motions on an image with histogram update
-   *
-   * @param image Image to process
-   *
-   * The function designed to search motions in image streams
-   * thus it needs to process the image sequence frame by frame.
-   * It processes an image from this sequence and searches moving blobs
-   * on that. It uses histogram update method.
-   *
-   */
-
-  void DetectMotionsHU(MEImage& image);
-
-  /*!
-   * @brief Update a model
-   *
-   * @param image Image to process
-   * @param model Model to update
-   *
-   * The function updates a histogram model of the image.
-   *
-   */
-
-  void UpdateModelHU(MEImage& image, MEPixelDataType*** model);
-
-  /*!
-   * @brief Update the HU data structure for one pixel
-   *
-   * @param pixeldata Pixel data
-   * @param histogram Current histogram
-   *
-   * This method updates the HU data for one pixel.
-   *
-   */
-
-  void UpdateHUPixelData(MEPixelDataType* pixeldata, const float *histogram);
-
-  /*!
-   * @brief Optical flow correction of the camera movements
-   *
-   * The function trackes some points on the scene if a camera movement is
-   * detected, then the LBP pixel data is corrected.
-   *
-   */
-
-  void OpticalFlowCorrection();
-
-private:
-  // GENERAL VARIABLES
-  /// Motion detection type
-  DetectorType MDMode;
-  /// State of the data structures
-  MEProcessStateType MDDataState;
-  /// Processed number in the image sequence
-  int Frames;
-  /// Store the current image
-  MEImage CurrentImage;
-  /// Store the previous image
-  MEImage PreviousImage;
-  /// Store the current mask image
-  MEImage MaskImage;
-  /// Store the current mask image
-  bool ReadyMask;
-  // HISTOGRAM UPDATE VARIABLES
-  /// Color space (-1 = no conversion)
-  int HUColorSpace;
-  /// LBP calculation mode (-1 = no conversion)
-  int HULBPMode;
-  /// Histograms per pixel
-  int HUHistogramsPerPixel;
-  /// Histogram area
-  int HUHistogramArea;
-  /// Histogram bins
-  int HUHistogramBins;
-  /// Image width for histogram update
-  int HUImageWidth;
-  /// Image height for histogram update
-  int HUImageHeight;
-  /// Data of the LBP histograms
-  MEPixelDataType ***HULBPPixelData;
-  /// Store the previous blue layer
-  MEImage PreviousBlueLayer;
-  /// Histogram proximity threshold
-  float HUPrThres;
-  /// Background selection threshold
-  float HUBackgrThres;
-  /// Histogram learning rate
-  float HUHistLRate;
-  /// Weights learning rate
-  float HUWeightsLRate;
-  /// Pixel number used to calculate the histograms
-  int HUSamplePixels;
-  /// The desired pixel number used to calculate the histograms (-1 = Auto)
-  int HUDesiredSamplePixels;
-  /// Min cut weight
-  float HUMinCutWeight;
-  /// Auxiliary variable for computing the histograms in a column
-  int **HUMaskColumnAddDel;
-  /// Auxiliary variable for computing the histograms in a row
-  int **HUMaskRowAddDel;
-  // OPTICAL FLOW VARIABLES
-  /// State of the optical flow
-  MEProcessStateType HUOFDataState;
-  /// Number of the tracked points with optical flow
-  int HUOFPointsNumber;
-  /// Tracked points
-  CvPoint2D32f* HUOFPoints[2];
-  /// The rest x component of previous camera movement
-  int HUOFCamMovementX;
-  /// Maximum tracked points detected in one cycle
-  int MaxTrackedPoints;
-  /// Processed frame number with optical flow in the image sequence
-  int HUOFFrames;
-  /// Indicator of a new camera movement
-  bool HUOFCamMovement;
-};
+    namespace lbp_mrf
+    {
+      class CvBGStatModel;
+      //struct CvPoint2D32f;
+
+      // Struct for histogram update data of a pixel
+      struct MEPixelDataType;
+
+      /**
+       * MotionDetection
+       * @brief Extract moving objects from image sequence
+       */
+      class MotionDetection
+      {
+      public:
+
+        /// Types of motion detection
+        typedef enum
+        {
+          md_Min = 0,               /*!< Minimum value */
+          md_NotDefined = md_Min,   /*!< Not defined */
+          md_DLBPHistograms,        /*!< Dynamic LBP */
+          md_LBPHistograms,         /*!< Normal LBP */
+          md_Max = md_LBPHistograms /*!< Maximum value */
+        } DetectorType;
+
+        /// Types of sample mask
+        typedef enum
+        {
+          sm_Min = 0,              /*!< Minimum value */
+          sm_Circle = sm_Min,      /*!< Circle */
+          sm_Square,               /*!< Square */
+          sm_Ellipse,              /*!< Ellipse */
+          sm_RandomPixels,         /*!< Random pixels */
+          sm_Max = sm_RandomPixels /*!< Maximum value */
+        } SampleMaskType;
+
+        /// Types of motion detection parameters
+        typedef enum
+        {
+          mdp_Min = 0,                         /*!< Minimum value */
+          mdp_HUProximityThreshold = mdp_Min,  /*!< Proximity threshold */
+          mdp_HUBackgroundThreshold,           /*!< Background threshold */
+          mdp_HUHistogramLearningRate,         /*!< Histogram learning rate */
+          mdp_HUWeightsLearningRate,           /*!< Weights learning rate */
+          mdp_HUMinCutWeight,                  /*!< Minimum cut weight */
+          mdp_HUDesiredSamplePixels,           /*!< Desired sample pixels */
+          mdp_HUHistogramsPerPixel,            /*!< Histogram per pixel */
+          mdp_HUHistogramArea,                 /*!< Histogram area */
+          mdp_HUHistogramBins,                 /*!< Histogram bins */
+          mdp_HUColorSpace,                    /*!< Color space */
+          mdp_HULBPMode,                       /*!< LBP mode */
+          mdp_Max = mdp_HULBPMode              /*!< Maximum value */
+        } ParametersType;
+
+        /*!
+        * @brief Class constructor
+        *
+        * @param mode Detection mode
+        *
+        * Class constructor with the possibility to specify the detection mode.
+        * The default is dynamic LBP.
+        *
+        */
+
+        MotionDetection(DetectorType mode = md_DLBPHistograms);
+        /// Destructor of class
+        ~MotionDetection();
+
+        /*
+        -------------------------------------------------------------------
+                                Motion methods
+        -------------------------------------------------------------------
+        */
+
+        /*!
+        * @brief Set the mode of the motion detection
+        *
+        * @param newmode New mode of detection
+        *
+        * Set the mode of the motion detection.
+        *
+        */
+
+        void SetMode(DetectorType newmode);
+
+        /*!
+        * @brief Get a parameter value of the motion detection
+        *
+        * @param param Parameter of the detection
+        *
+        * @return Queried value
+        *
+        * Get the value of a parameter of the motion detection.
+        *
+        */
+
+        float GetParameter(ParametersType param) const;
+
+        /*!
+        * @brief Set a parameter of the motion detection
+        *
+        * @param param Parameter of the detection
+        * @param value New value
+        *
+        * Set a new value to a parameter of the motion detection.
+        *
+        */
+
+        void SetParameter(ParametersType param, float value);
+
+        /*!
+        * @brief Detect the motions on an image
+        *
+        * @param image Image to process
+        *
+        * The function designed to search motions in image streams
+        * thus it needs to process the image sequence frame by frame.
+        * It processes an image from this sequence and searches moving blobs
+        * on that.
+        *
+        */
+
+        void DetectMotions(MEImage& image);
+
+        /*!
+        * @brief Get mask image with detected motions
+        *
+        * @param mask_image Result mask image
+        *
+        * The function creates a mask image on which the objects are
+        * indicated by white blobs.
+        *
+        */
+
+        void GetMotionsMask(MEImage& mask_image);
+
+        /*!
+        * @brief Calculate results of the motion detection
+        *
+        * @param referenceimage Reference mask image
+        * @param tnegatives True negative pixels
+        * @param tpositives True positive pixels
+        * @param ttnegatives Total true negative pixels
+        * @param ttpositives Total true positive pixels
+        *
+        * The function calculates the results of the motion detection
+        * between the current motion mask and a given reference mask
+        * image.
+        *
+        */
+
+        void CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives,
+          int& ttnegatives, int& ttpositives);
+
+      private:
+
+        /*!
+        * @brief Release data structures
+        *
+        * Function releases the data structures.
+        *
+        */
+
+        void ReleaseData();
+
+        /*
+        -------------------------------------------------------------------
+                          Histogram update methods
+        -------------------------------------------------------------------
+        */
+
+        /*!
+        * @brief Init HU data structures
+        *
+        * @param imagewidth Image width for HU to process
+        * @param imageheight Image height for HU to process
+        *
+        * Function allocates/re-allocates the HU data structures and they
+        * are cleared if needs be.
+        *
+        */
+
+        void InitHUData(int imagewidth, int imageheight);
+
+        /*!
+        * @brief Init HU optical flow data structures
+        *
+        * @param imagewidth Image width for HU to process
+        * @param imageheight Image height for HU to process
+        *
+        * Function allocates/re-allocates the HU optical flow
+        * data structures.
+        *
+        */
+
+        void InitHUOFData(int imagewidth, int imageheight);
+
+        /*!
+        * @brief Release HU data structures
+        *
+        * Function releases the HU data structures.
+        *
+        */
+
+        void ReleaseHUData();
+
+        /*!
+        * @brief Release HU optical flow data structures
+        *
+        * Function releases the HU optical flow data structures.
+        *
+        */
+
+        void ReleaseHUOFData();
+
+        /*!
+        * @brief Clear HU data structures
+        *
+        * Function clears the HU data structures.
+        *
+        */
+
+        void ClearHUData();
+
+        /*!
+        * @brief Get mask image with detected motions by histogram update
+        *
+        * @param mask_image Result mask image
+        *
+        * The function creates a mask image on which the objects are
+        * indicated by white blobs.
+        *
+        */
+
+        void GetMotionsMaskHU(MEImage& mask_image);
+
+        /*!
+        * @brief Set the sample mask
+        *
+        * @param mask_type Type of the mask
+        * @param desiredarea The desired area size of the mask
+        *
+        * The function creates a sample mask with a desired form
+        * (square, circle, ellipse, random pixels) and size.
+        *
+        */
+
+        void SetSampleMaskHU(SampleMaskType mask_type, int desiredarea);
+
+        /*!
+        * @brief Detect the motions on an image with histogram update
+        *
+        * @param image Image to process
+        *
+        * The function designed to search motions in image streams
+        * thus it needs to process the image sequence frame by frame.
+        * It processes an image from this sequence and searches moving blobs
+        * on that. It uses histogram update method.
+        *
+        */
+
+        void DetectMotionsHU(MEImage& image);
+
+        /*!
+        * @brief Update a model
+        *
+        * @param image Image to process
+        * @param model Model to update
+        *
+        * The function updates a histogram model of the image.
+        *
+        */
+
+        void UpdateModelHU(MEImage& image, MEPixelDataType*** model);
+
+        /*!
+        * @brief Update the HU data structure for one pixel
+        *
+        * @param pixeldata Pixel data
+        * @param histogram Current histogram
+        *
+        * This method updates the HU data for one pixel.
+        *
+        */
+
+        void UpdateHUPixelData(MEPixelDataType* pixeldata, const float *histogram);
+
+        /*!
+        * @brief Optical flow correction of the camera movements
+        *
+        * The function trackes some points on the scene if a camera movement is
+        * detected, then the LBP pixel data is corrected.
+        *
+        */
+
+        void OpticalFlowCorrection();
+
+      private:
+        // GENERAL VARIABLES
+        /// Motion detection type
+        DetectorType MDMode;
+        /// State of the data structures
+        MEProcessStateType MDDataState;
+        /// Processed number in the image sequence
+        int Frames;
+        /// Store the current image
+        MEImage CurrentImage;
+        /// Store the previous image
+        MEImage PreviousImage;
+        /// Store the current mask image
+        MEImage MaskImage;
+        /// Store the current mask image
+        bool ReadyMask;
+        // HISTOGRAM UPDATE VARIABLES
+        /// Color space (-1 = no conversion)
+        int HUColorSpace;
+        /// LBP calculation mode (-1 = no conversion)
+        int HULBPMode;
+        /// Histograms per pixel
+        int HUHistogramsPerPixel;
+        /// Histogram area
+        int HUHistogramArea;
+        /// Histogram bins
+        int HUHistogramBins;
+        /// Image width for histogram update
+        int HUImageWidth;
+        /// Image height for histogram update
+        int HUImageHeight;
+        /// Data of the LBP histograms
+        MEPixelDataType ***HULBPPixelData;
+        /// Store the previous blue layer
+        MEImage PreviousBlueLayer;
+        /// Histogram proximity threshold
+        float HUPrThres;
+        /// Background selection threshold
+        float HUBackgrThres;
+        /// Histogram learning rate
+        float HUHistLRate;
+        /// Weights learning rate
+        float HUWeightsLRate;
+        /// Pixel number used to calculate the histograms
+        int HUSamplePixels;
+        /// The desired pixel number used to calculate the histograms (-1 = Auto)
+        int HUDesiredSamplePixels;
+        /// Min cut weight
+        float HUMinCutWeight;
+        /// Auxiliary variable for computing the histograms in a column
+        int **HUMaskColumnAddDel;
+        /// Auxiliary variable for computing the histograms in a row
+        int **HUMaskRowAddDel;
+        // OPTICAL FLOW VARIABLES
+        /// State of the optical flow
+        MEProcessStateType HUOFDataState;
+        /// Number of the tracked points with optical flow
+        int HUOFPointsNumber;
+        /// Tracked points
+        CvPoint2D32f* HUOFPoints[2];
+        /// The rest x component of previous camera movement
+        int HUOFCamMovementX;
+        /// Maximum tracked points detected in one cycle
+        int MaxTrackedPoints;
+        /// Processed frame number with optical flow in the image sequence
+        int HUOFFrames;
+        /// Indicator of a new camera movement
+        bool HUOFCamMovement;
+      };
+    }
+  }
+}
 
 #endif
diff --git a/src/algorithms/LBP_MRF/block.h b/src/algorithms/LBP_MRF/block.h
index 16c86b7248dfe0c357f5af16eaa1aad62e259582..7f5c3d25889725f326d07b297e45acad5bed7a65 100644
--- a/src/algorithms/LBP_MRF/block.h
+++ b/src/algorithms/LBP_MRF/block.h
@@ -3,170 +3,176 @@
 #include <stdlib.h>
 #include <stdio.h>
 
-namespace ck
+namespace bgslibrary
 {
-  template <class Type> class Block
+  namespace algorithms
   {
-  public:
-    /* Constructor. Arguments are the block size and
-         (optionally) the pointer to the function which
-         will be called if allocation failed; the message
-         passed to this function is "Not enough memory!" */
-    Block(int size, void(*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; }
-
-    /* Destructor. Deallocates all items added so far */
-    ~Block() { while (first) { block *next = first->next; delete first; first = next; } }
-
-    /* Allocates 'num' consecutive items; returns pointer
-         to the first item. 'num' cannot be greater than the
-         block size since items must fit in one block */
-    Type *New(int num = 1)
+    namespace lbp_mrf
     {
-      Type *t;
-
-      if (!last || last->current + num > last->last)
+      template <class Type> class Block
       {
-        if (last && last->next) last = last->next;
-        else
+      public:
+        /* Constructor. Arguments are the block size and
+            (optionally) the pointer to the function which
+            will be called if allocation failed; the message
+            passed to this function is "Not enough memory!" */
+        Block(int size, void(*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; }
+
+        /* Destructor. Deallocates all items added so far */
+        ~Block() { while (first) { block *next = first->next; delete first; first = next; } }
+
+        /* Allocates 'num' consecutive items; returns pointer
+            to the first item. 'num' cannot be greater than the
+            block size since items must fit in one block */
+        Type *New(int num = 1)
         {
-          block *next = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(Type)];
-          if (!next) { fprintf(stderr, "Not enough memory!"); exit(1); }
-          if (last) last->next = next;
-          else first = next;
-          last = next;
-          last->current = &(last->data[0]);
-          last->last = last->current + block_size;
-          last->next = NULL;
+          Type *t;
+
+          if (!last || last->current + num > last->last)
+          {
+            if (last && last->next) last = last->next;
+            else
+            {
+              block *next = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(Type)];
+              if (!next) { fprintf(stderr, "Not enough memory!"); exit(1); }
+              if (last) last->next = next;
+              else first = next;
+              last = next;
+              last->current = &(last->data[0]);
+              last->last = last->current + block_size;
+              last->next = NULL;
+            }
+          }
+
+          t = last->current;
+          last->current += num;
+          return t;
         }
-      }
-
-      t = last->current;
-      last->current += num;
-      return t;
-    }
 
-    /* Returns the first item (or NULL, if no items were added) */
-    Type *ScanFirst()
-    {
-      scan_current_block = first;
-      if (!scan_current_block) return NULL;
-      scan_current_data = &(scan_current_block->data[0]);
-      return scan_current_data++;
-    }
-
-    /* Returns the next item (or NULL, if all items have been read)
-         Can be called only if previous ScanFirst() or ScanNext()
-         call returned not NULL. */
-    Type *ScanNext()
-    {
-      if (scan_current_data >= scan_current_block->current)
-      {
-        scan_current_block = scan_current_block->next;
-        if (!scan_current_block) return NULL;
-        scan_current_data = &(scan_current_block->data[0]);
-      }
-      return scan_current_data++;
-    }
+        /* Returns the first item (or NULL, if no items were added) */
+        Type *ScanFirst()
+        {
+          scan_current_block = first;
+          if (!scan_current_block) return NULL;
+          scan_current_data = &(scan_current_block->data[0]);
+          return scan_current_data++;
+        }
 
-    /* Marks all elements as empty */
-    void Reset()
-    {
-      block *b;
-      if (!first) return;
-      for (b = first;; b = b->next)
-      {
-        b->current = &(b->data[0]);
-        if (b == last) break;
-      }
-      last = first;
-    }
+        /* Returns the next item (or NULL, if all items have been read)
+            Can be called only if previous ScanFirst() or ScanNext()
+            call returned not NULL. */
+        Type *ScanNext()
+        {
+          if (scan_current_data >= scan_current_block->current)
+          {
+            scan_current_block = scan_current_block->next;
+            if (!scan_current_block) return NULL;
+            scan_current_data = &(scan_current_block->data[0]);
+          }
+          return scan_current_data++;
+        }
 
-    /***********************************************************************/
+        /* Marks all elements as empty */
+        void Reset()
+        {
+          block *b;
+          if (!first) return;
+          for (b = first;; b = b->next)
+          {
+            b->current = &(b->data[0]);
+            if (b == last) break;
+          }
+          last = first;
+        }
 
-  private:
+        /***********************************************************************/
 
-    typedef struct block_st
-    {
-      Type					*current, *last;
-      struct block_st			*next;
-      Type					data[1];
-    } block;
+      private:
 
-    int		block_size;
-    block	*first;
-    block	*last;
+        typedef struct block_st
+        {
+          Type					*current, *last;
+          struct block_st			*next;
+          Type					data[1];
+        } block;
 
-    block	*scan_current_block;
-    Type	*scan_current_data;
+        int		block_size;
+        block	*first;
+        block	*last;
 
-    void(*error_function)(char *);
-  };
+        block	*scan_current_block;
+        Type	*scan_current_data;
 
-  /***********************************************************************/
-  /***********************************************************************/
-  /***********************************************************************/
+        void(*error_function)(char *);
+      };
 
-  template <class Type> class DBlock
-  {
-  public:
-    /* Constructor. Arguments are the block size and
-         (optionally) the pointer to the function which
-         will be called if allocation failed; the message
-         passed to this function is "Not enough memory!" */
-    DBlock(int size, void(*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; }
-
-    /* Destructor. Deallocates all items added so far */
-    ~DBlock() { while (first) { block *next = first->next; delete first; first = next; } }
-
-    /* Allocates one item */
-    Type *New()
-    {
-      block_item *item;
+      /***********************************************************************/
+      /***********************************************************************/
+      /***********************************************************************/
 
-      if (!first_free)
+      template <class Type> class DBlock
       {
-        block *next = first;
-        first = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(block_item)];
-        if (!first) { fprintf(stderr, "Not enough memory!"); exit(1); }
-        first_free = &(first->data[0]);
-        for (item = first_free; item < first_free + block_size - 1; item++)
-          item->next_free = item + 1;
-        item->next_free = NULL;
-        first->next = next;
-      }
-
-      item = first_free;
-      first_free = item->next_free;
-      return (Type *)item;
-    }
+      public:
+        /* Constructor. Arguments are the block size and
+            (optionally) the pointer to the function which
+            will be called if allocation failed; the message
+            passed to this function is "Not enough memory!" */
+        DBlock(int size, void(*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; }
+
+        /* Destructor. Deallocates all items added so far */
+        ~DBlock() { while (first) { block *next = first->next; delete first; first = next; } }
+
+        /* Allocates one item */
+        Type *New()
+        {
+          block_item *item;
+
+          if (!first_free)
+          {
+            block *next = first;
+            first = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(block_item)];
+            if (!first) { fprintf(stderr, "Not enough memory!"); exit(1); }
+            first_free = &(first->data[0]);
+            for (item = first_free; item < first_free + block_size - 1; item++)
+              item->next_free = item + 1;
+            item->next_free = NULL;
+            first->next = next;
+          }
+
+          item = first_free;
+          first_free = item->next_free;
+          return (Type *)item;
+        }
 
-    /* Deletes an item allocated previously */
-    void Delete(Type *t)
-    {
-      ((block_item *)t)->next_free = first_free;
-      first_free = (block_item *)t;
-    }
+        /* Deletes an item allocated previously */
+        void Delete(Type *t)
+        {
+          ((block_item *)t)->next_free = first_free;
+          first_free = (block_item *)t;
+        }
 
-    /***********************************************************************/
+        /***********************************************************************/
 
-  private:
+      private:
 
-    typedef union block_item_st
-    {
-      Type			t;
-      block_item_st	*next_free;
-    } block_item;
+        typedef union block_item_st
+        {
+          Type			t;
+          block_item_st	*next_free;
+        } block_item;
 
-    typedef struct block_st
-    {
-      struct block_st			*next;
-      block_item				data[1];
-    } block;
+        typedef struct block_st
+        {
+          struct block_st			*next;
+          block_item				data[1];
+        } block;
 
-    int			block_size;
-    block		*first;
-    block_item	*first_free;
+        int			block_size;
+        block		*first;
+        block_item	*first_free;
 
-    void(*error_function)(char *);
-  };
+        void(*error_function)(char *);
+      };
+    }
+  }
 }
diff --git a/src/algorithms/LBP_MRF/graph.cpp b/src/algorithms/LBP_MRF/graph.cpp
index cdc137932f8ab2b45bf453b3ba5183d7bdc07a5e..541efb3669ebd8b732fdd26bda47d560c471fcd2 100644
--- a/src/algorithms/LBP_MRF/graph.cpp
+++ b/src/algorithms/LBP_MRF/graph.cpp
@@ -2,64 +2,70 @@
 
 #include "graph.h"
 
-namespace ck
+namespace bgslibrary
 {
-  Graph::Graph(void(*err_function)(char *))
+  namespace algorithms
   {
-    error_function = err_function;
-    node_block = new Block<node>(NODE_BLOCK_SIZE, error_function);
-    arc_block = new Block<arc>(NODE_BLOCK_SIZE, error_function);
-    flow = 0;
-  }
+    namespace lbp_mrf
+    {
+      Graph::Graph(void(*err_function)(char *))
+      {
+        error_function = err_function;
+        node_block = new Block<node>(NODE_BLOCK_SIZE, error_function);
+        arc_block = new Block<arc>(NODE_BLOCK_SIZE, error_function);
+        flow = 0;
+      }
 
-  Graph::~Graph()
-  {
-    delete node_block;
-    delete arc_block;
-  }
+      Graph::~Graph()
+      {
+        delete node_block;
+        delete arc_block;
+      }
 
-  Graph::node_id Graph::add_node()
-  {
-    node *i = node_block->New();
+      Graph::node_id Graph::add_node()
+      {
+        node *i = node_block->New();
 
-    i->first = NULL;
-    i->tr_cap = 0;
+        i->first = NULL;
+        i->tr_cap = 0;
 
-    return (node_id)i;
-  }
+        return (node_id)i;
+      }
 
-  void Graph::add_edge(node_id from, node_id to, captype cap, captype rev_cap)
-  {
-    arc *a, *a_rev;
+      void Graph::add_edge(node_id from, node_id to, captype cap, captype rev_cap)
+      {
+        arc *a, *a_rev;
 
-    a = arc_block->New(2);
-    a_rev = a + 1;
+        a = arc_block->New(2);
+        a_rev = a + 1;
 
-    a->sister = a_rev;
-    a_rev->sister = a;
-    a->next = ((node*)from)->first;
-    ((node*)from)->first = a;
-    a_rev->next = ((node*)to)->first;
-    ((node*)to)->first = a_rev;
-    a->head = (node*)to;
-    a_rev->head = (node*)from;
-    a->r_cap = cap;
-    a_rev->r_cap = rev_cap;
-  }
+        a->sister = a_rev;
+        a_rev->sister = a;
+        a->next = ((node*)from)->first;
+        ((node*)from)->first = a;
+        a_rev->next = ((node*)to)->first;
+        ((node*)to)->first = a_rev;
+        a->head = (node*)to;
+        a_rev->head = (node*)from;
+        a->r_cap = cap;
+        a_rev->r_cap = rev_cap;
+      }
 
-  void Graph::set_tweights(node_id i, captype cap_source, captype cap_sink)
-  {
-    flow += (cap_source < cap_sink) ? cap_source : cap_sink;
-    ((node*)i)->tr_cap = cap_source - cap_sink;
-  }
+      void Graph::set_tweights(node_id i, captype cap_source, captype cap_sink)
+      {
+        flow += (cap_source < cap_sink) ? cap_source : cap_sink;
+        ((node*)i)->tr_cap = cap_source - cap_sink;
+      }
 
-  void Graph::add_tweights(node_id i, captype cap_source, captype cap_sink)
-  {
-    //register
-    captype delta = ((node*)i)->tr_cap; // 'register' storage class specifier is deprecated and incompatible with C++17
-    if (delta > 0) cap_source += delta;
-    else           cap_sink -= delta;
-    flow += (cap_source < cap_sink) ? cap_source : cap_sink;
-    ((node*)i)->tr_cap = cap_source - cap_sink;
+      void Graph::add_tweights(node_id i, captype cap_source, captype cap_sink)
+      {
+        //register
+        captype delta = ((node*)i)->tr_cap; // 'register' storage class specifier is deprecated and incompatible with C++17
+        if (delta > 0) cap_source += delta;
+        else           cap_sink -= delta;
+        flow += (cap_source < cap_sink) ? cap_source : cap_sink;
+        ((node*)i)->tr_cap = cap_source - cap_sink;
+      }
+    }
   }
 }
diff --git a/src/algorithms/LBP_MRF/graph.h b/src/algorithms/LBP_MRF/graph.h
index a30e938e73702f685ee44711b50fb10a95ec1fd8..257b0a77d35e71952154eaec1be8df0ed3bf883c 100644
--- a/src/algorithms/LBP_MRF/graph.h
+++ b/src/algorithms/LBP_MRF/graph.h
@@ -2,136 +2,142 @@
 
 #include "block.h"
 
-/*
-  Nodes, arcs and pointers to nodes are
-  added in blocks for memory and time efficiency.
-  Below are numbers of items in blocks
-  */
-#define NODE_BLOCK_SIZE 512
-#define ARC_BLOCK_SIZE 1024
-#define NODEPTR_BLOCK_SIZE 128
-
-namespace ck
+namespace bgslibrary
 {
-  class Graph
+  namespace algorithms
   {
-  public:
-    typedef enum
+    namespace lbp_mrf
     {
-      SOURCE = 0,
-      SINK = 1
-    } termtype; /* terminals */
-
-    /* Type of edge weights.
-         Can be changed to char, int, float, double, ... */
-    typedef short captype;
-    /* Type of total flow */
-    typedef int flowtype;
-
-    typedef void * node_id;
-
-    /* interface functions */
-
-    /* Constructor. Optional argument is the pointer to the
-         function which will be called if an error occurs;
-         an error message is passed to this function. If this
-         argument is omitted, exit(1) will be called. */
-    Graph(void(*err_function)(char *) = NULL);
-
-    /* Destructor */
-    ~Graph();
-
-    /* Adds a node to the graph */
-    node_id add_node();
-
-    /* Adds a bidirectional edge between 'from' and 'to'
-         with the weights 'cap' and 'rev_cap' */
-    void add_edge(node_id from, node_id to, captype cap, captype rev_cap);
-
-    /* Sets the weights of the edges 'SOURCE->i' and 'i->SINK'
-         Can be called at most once for each node before any call to 'add_tweights'.
-         Weights can be negative */
-    void set_tweights(node_id i, captype cap_source, captype cap_sink);
-
-    /* Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights
-         Can be called multiple times for each node.
-         Weights can be negative */
-    void add_tweights(node_id i, captype cap_source, captype cap_sink);
-
-    /* After the maxflow is computed, this function returns to which
-         segment the node 'i' belongs (Graph::SOURCE or Graph::SINK) */
-    termtype what_segment(node_id i);
-
-    /* Computes the maxflow. Can be called only once. */
-    flowtype maxflow();
-
-    /***********************************************************************/
-    /***********************************************************************/
-    /***********************************************************************/
-
-  private:
-    /* internal variables and functions */
-
-    struct arc_st;
-
-    /* node structure */
-    typedef struct node_st
-    {
-      arc_st			*first;		/* first outcoming arc */
-
-      arc_st			*parent;	/* node's parent */
-      node_st			*next;		/* pointer to the next active node
-                         (or to itself if it is the last node in the list) */
-      int				TS;			/* timestamp showing when DIST was computed */
-      int				DIST;		/* distance to the terminal */
-      short			is_sink;	/* flag showing whether the node is in the source or in the sink tree */
-
-      captype			tr_cap;		/* if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node
-                         otherwise         -tr_cap is residual capacity of the arc node->SINK */
-    } node;
-
-    /* arc structure */
-    typedef struct arc_st
-    {
-      node_st			*head;		/* node the arc points to */
-      arc_st			*next;		/* next arc with the same originating node */
-      arc_st			*sister;	/* reverse arc */
-
-      captype			r_cap;		/* residual capacity */
-    } arc;
-
-    /* 'pointer to node' structure */
-    typedef struct nodeptr_st
-    {
-      node_st			*ptr;
-      nodeptr_st		*next;
-    } nodeptr;
-
-    Block<node>			*node_block;
-    Block<arc>			*arc_block;
-    DBlock<nodeptr>		*nodeptr_block;
-
-    void(*error_function)(char *);	/* this function is called if a error occurs,
-                           with a corresponding error message
-                           (or exit(1) is called if it's NULL) */
-
-    flowtype			flow;		/* total flow */
-
-    /***********************************************************************/
-
-    node				*queue_first[2], *queue_last[2];	/* list of active nodes */
-    nodeptr				*orphan_first, *orphan_last;		/* list of pointers to orphans */
-    int					TIME;								/* monotonically increasing global counter */
-
-    /***********************************************************************/
-
-    /* functions for processing active list */
-    void set_active(node *i);
-    node *next_active();
-
-    void maxflow_init();
-    void augment(arc *middle_arc);
-    void process_source_orphan(node *i);
-    void process_sink_orphan(node *i);
-  };
+      /*
+        Nodes, arcs and pointers to nodes are
+        added in blocks for memory and time efficiency.
+        Below are numbers of items in blocks
+        */
+      const int NODE_BLOCK_SIZE = 512;
+      const int ARC_BLOCK_SIZE = 1024;
+      const int NODEPTR_BLOCK_SIZE = 128;
+      
+      class Graph
+      {
+      public:
+        typedef enum
+        {
+          SOURCE = 0,
+          SINK = 1
+        } termtype; /* terminals */
+
+        /* Type of edge weights.
+            Can be changed to char, int, float, double, ... */
+        typedef short captype;
+        /* Type of total flow */
+        typedef int flowtype;
+
+        typedef void * node_id;
+
+        /* interface functions */
+
+        /* Constructor. Optional argument is the pointer to the
+            function which will be called if an error occurs;
+            an error message is passed to this function. If this
+            argument is omitted, exit(1) will be called. */
+        Graph(void(*err_function)(char *) = NULL);
+
+        /* Destructor */
+        ~Graph();
+
+        /* Adds a node to the graph */
+        node_id add_node();
+
+        /* Adds a bidirectional edge between 'from' and 'to'
+            with the weights 'cap' and 'rev_cap' */
+        void add_edge(node_id from, node_id to, captype cap, captype rev_cap);
+
+        /* Sets the weights of the edges 'SOURCE->i' and 'i->SINK'
+            Can be called at most once for each node before any call to 'add_tweights'.
+            Weights can be negative */
+        void set_tweights(node_id i, captype cap_source, captype cap_sink);
+
+        /* Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights
+            Can be called multiple times for each node.
+            Weights can be negative */
+        void add_tweights(node_id i, captype cap_source, captype cap_sink);
+
+        /* After the maxflow is computed, this function returns to which
+            segment the node 'i' belongs (Graph::SOURCE or Graph::SINK) */
+        termtype what_segment(node_id i);
+
+        /* Computes the maxflow. Can be called only once. */
+        flowtype maxflow();
+
+        /***********************************************************************/
+        /***********************************************************************/
+        /***********************************************************************/
+
+      private:
+        /* internal variables and functions */
+
+        struct arc_st;
+
+        /* node structure */
+        typedef struct node_st
+        {
+          arc_st			*first;		/* first outcoming arc */
+
+          arc_st			*parent;	/* node's parent */
+          node_st			*next;		/* pointer to the next active node
+                            (or to itself if it is the last node in the list) */
+          int				TS;			/* timestamp showing when DIST was computed */
+          int				DIST;		/* distance to the terminal */
+          short			is_sink;	/* flag showing whether the node is in the source or in the sink tree */
+
+          captype			tr_cap;		/* if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node
+                            otherwise         -tr_cap is residual capacity of the arc node->SINK */
+        } node;
+
+        /* arc structure */
+        typedef struct arc_st
+        {
+          node_st			*head;		/* node the arc points to */
+          arc_st			*next;		/* next arc with the same originating node */
+          arc_st			*sister;	/* reverse arc */
+
+          captype			r_cap;		/* residual capacity */
+        } arc;
+
+        /* 'pointer to node' structure */
+        typedef struct nodeptr_st
+        {
+          node_st			*ptr;
+          nodeptr_st		*next;
+        } nodeptr;
+
+        Block<node>			*node_block;
+        Block<arc>			*arc_block;
+        DBlock<nodeptr>		*nodeptr_block;
+
+        void(*error_function)(char *);	/* this function is called if a error occurs,
+                              with a corresponding error message
+                              (or exit(1) is called if it's NULL) */
+
+        flowtype			flow;		/* total flow */
+
+        /***********************************************************************/
+
+        node				*queue_first[2], *queue_last[2];	/* list of active nodes */
+        nodeptr				*orphan_first, *orphan_last;		/* list of pointers to orphans */
+        int					TIME;								/* monotonically increasing global counter */
+
+        /***********************************************************************/
+
+        /* functions for processing active list */
+        void set_active(node *i);
+        node *next_active();
+
+        void maxflow_init();
+        void augment(arc *middle_arc);
+        void process_source_orphan(node *i);
+        void process_sink_orphan(node *i);
+      };
+    }
+  }
 }
diff --git a/src/algorithms/LBP_MRF/maxflow.cpp b/src/algorithms/LBP_MRF/maxflow.cpp
index 05b3ceffc7c1a2f934fecfdc5c054fa4df35c297..660de7ba78293768815fd2df9d8d3c04d7998533 100644
--- a/src/algorithms/LBP_MRF/maxflow.cpp
+++ b/src/algorithms/LBP_MRF/maxflow.cpp
@@ -24,474 +24,479 @@ the front of the first queue. If the first queue
 is empty, it is replaced by the second queue
 (and the second queue becomes empty).
 */
-namespace ck
+namespace bgslibrary
 {
-  inline void Graph::set_active(node *i)
+  namespace algorithms
   {
-    if (!i->next)
+    namespace lbp_mrf
     {
-      /* it's not in the list yet */
-      if (queue_last[1]) queue_last[1]->next = i;
-      else               queue_first[1] = i;
-      queue_last[1] = i;
-      i->next = i;
-    }
-  }
-
-  /*
-      Returns the next active node.
-      If it is connected to the sink, it stays in the list,
-      otherwise it is removed from the list
-      */
-  inline Graph::node * Graph::next_active()
-  {
-    node *i;
-
-    while (1)
-    {
-      if (!(i = queue_first[0]))
+      inline void Graph::set_active(node *i)
       {
-        queue_first[0] = i = queue_first[1];
-        queue_last[0] = queue_last[1];
-        queue_first[1] = NULL;
-        queue_last[1] = NULL;
-        if (!i) return NULL;
+        if (!i->next)
+        {
+          /* it's not in the list yet */
+          if (queue_last[1]) queue_last[1]->next = i;
+          else               queue_first[1] = i;
+          queue_last[1] = i;
+          i->next = i;
+        }
       }
 
-      /* remove it from the active list */
-      if (i->next == i) queue_first[0] = queue_last[0] = NULL;
-      else              queue_first[0] = i->next;
-      i->next = NULL;
-
-      /* a node in the list is active iff it has a parent */
-      if (i->parent) return i;
-    }
-  }
-
-  /***********************************************************************/
-
-  void Graph::maxflow_init()
-  {
-    node *i;
-
-    queue_first[0] = queue_last[0] = NULL;
-    queue_first[1] = queue_last[1] = NULL;
-    orphan_first = NULL;
-
-    for (i = node_block->ScanFirst(); i; i = node_block->ScanNext())
-    {
-      i->next = NULL;
-      i->TS = 0;
-      if (i->tr_cap > 0)
-      {
-        /* i is connected to the source */
-        i->is_sink = 0;
-        i->parent = TERMINAL;
-        set_active(i);
-        i->TS = 0;
-        i->DIST = 1;
-      }
-      else if (i->tr_cap < 0)
+      /*
+          Returns the next active node.
+          If it is connected to the sink, it stays in the list,
+          otherwise it is removed from the list
+          */
+      inline Graph::node * Graph::next_active()
       {
-        /* i is connected to the sink */
-        i->is_sink = 1;
-        i->parent = TERMINAL;
-        set_active(i);
-        i->TS = 0;
-        i->DIST = 1;
-      }
-      else
-      {
-        i->parent = NULL;
-      }
-    }
-    TIME = 0;
-  }
+        node *i;
 
-  /***********************************************************************/
-
-  void Graph::augment(arc *middle_arc)
-  {
-    node *i;
-    arc *a;
-    captype bottleneck;
-    nodeptr *np;
-
-
-    /* 1. Finding bottleneck capacity */
-    /* 1a - the source tree */
-    bottleneck = middle_arc->r_cap;
-    for (i = middle_arc->sister->head;; i = a->head)
-    {
-      a = i->parent;
-      if (a == TERMINAL) break;
-      if (bottleneck > a->sister->r_cap) bottleneck = a->sister->r_cap;
-    }
-    if (bottleneck > i->tr_cap) bottleneck = i->tr_cap;
-    /* 1b - the sink tree */
-    for (i = middle_arc->head;; i = a->head)
-    {
-      a = i->parent;
-      if (a == TERMINAL) break;
-      if (bottleneck > a->r_cap) bottleneck = a->r_cap;
-    }
-    if (bottleneck > -i->tr_cap) bottleneck = -i->tr_cap;
+        while (1)
+        {
+          if (!(i = queue_first[0]))
+          {
+            queue_first[0] = i = queue_first[1];
+            queue_last[0] = queue_last[1];
+            queue_first[1] = NULL;
+            queue_last[1] = NULL;
+            if (!i) return NULL;
+          }
 
+          /* remove it from the active list */
+          if (i->next == i) queue_first[0] = queue_last[0] = NULL;
+          else              queue_first[0] = i->next;
+          i->next = NULL;
 
-    /* 2. Augmenting */
-    /* 2a - the source tree */
-    middle_arc->sister->r_cap += bottleneck;
-    middle_arc->r_cap -= bottleneck;
-    for (i = middle_arc->sister->head;; i = a->head)
-    {
-      a = i->parent;
-      if (a == TERMINAL) break;
-      a->r_cap += bottleneck;
-      a->sister->r_cap -= bottleneck;
-      if (!a->sister->r_cap)
-      {
-        /* add i to the adoption list */
-        i->parent = ORPHAN;
-        np = nodeptr_block->New();
-        np->ptr = i;
-        np->next = orphan_first;
-        orphan_first = np;
-      }
-    }
-    i->tr_cap -= bottleneck;
-    if (!i->tr_cap)
-    {
-      /* add i to the adoption list */
-      i->parent = ORPHAN;
-      np = nodeptr_block->New();
-      np->ptr = i;
-      np->next = orphan_first;
-      orphan_first = np;
-    }
-    /* 2b - the sink tree */
-    for (i = middle_arc->head;; i = a->head)
-    {
-      a = i->parent;
-      if (a == TERMINAL) break;
-      a->sister->r_cap += bottleneck;
-      a->r_cap -= bottleneck;
-      if (!a->r_cap)
-      {
-        /* add i to the adoption list */
-        i->parent = ORPHAN;
-        np = nodeptr_block->New();
-        np->ptr = i;
-        np->next = orphan_first;
-        orphan_first = np;
+          /* a node in the list is active iff it has a parent */
+          if (i->parent) return i;
+        }
       }
-    }
-    i->tr_cap += bottleneck;
-    if (!i->tr_cap)
-    {
-      /* add i to the adoption list */
-      i->parent = ORPHAN;
-      np = nodeptr_block->New();
-      np->ptr = i;
-      np->next = orphan_first;
-      orphan_first = np;
-    }
 
+      /***********************************************************************/
 
-    flow += bottleneck;
-  }
+      void Graph::maxflow_init()
+      {
+        node *i;
 
-  /***********************************************************************/
+        queue_first[0] = queue_last[0] = NULL;
+        queue_first[1] = queue_last[1] = NULL;
+        orphan_first = NULL;
 
-  void Graph::process_source_orphan(node *i)
-  {
-    node *j;
-    arc *a0, *a0_min = NULL, *a;
-    nodeptr *np;
-    int d, d_min = INFINITE_D;
-
-    /* trying to find a new parent */
-    for (a0 = i->first; a0; a0 = a0->next)
-      if (a0->sister->r_cap)
-      {
-        j = a0->head;
-        if (!j->is_sink && (a = j->parent))
+        for (i = node_block->ScanFirst(); i; i = node_block->ScanNext())
         {
-          /* checking the origin of j */
-          d = 0;
-          while (1)
+          i->next = NULL;
+          i->TS = 0;
+          if (i->tr_cap > 0)
           {
-            if (j->TS == TIME)
-            {
-              d += j->DIST;
-              break;
-            }
-            a = j->parent;
-            d++;
-            if (a == TERMINAL)
-            {
-              j->TS = TIME;
-              j->DIST = 1;
-              break;
-            }
-            if (a == ORPHAN) { d = INFINITE_D; break; }
-            j = a->head;
+            /* i is connected to the source */
+            i->is_sink = 0;
+            i->parent = TERMINAL;
+            set_active(i);
+            i->TS = 0;
+            i->DIST = 1;
           }
-          if (d < INFINITE_D) /* j originates from the source - done */
+          else if (i->tr_cap < 0)
           {
-            if (d < d_min)
-            {
-              a0_min = a0;
-              d_min = d;
-            }
-            /* set marks along the path */
-            for (j = a0->head; j->TS != TIME; j = j->parent->head)
-            {
-              j->TS = TIME;
-              j->DIST = d--;
-            }
+            /* i is connected to the sink */
+            i->is_sink = 1;
+            i->parent = TERMINAL;
+            set_active(i);
+            i->TS = 0;
+            i->DIST = 1;
+          }
+          else
+          {
+            i->parent = NULL;
           }
         }
+        TIME = 0;
       }
 
-    if ((i->parent = a0_min))
-    {
-      i->TS = TIME;
-      i->DIST = d_min + 1;
-    }
-    else
-    {
-      /* no parent is found */
-      i->TS = 0;
+      /***********************************************************************/
 
-      /* process neighbors */
-      for (a0 = i->first; a0; a0 = a0->next)
+      void Graph::augment(arc *middle_arc)
       {
-        j = a0->head;
-        if (!j->is_sink && (a = j->parent))
+        node *i;
+        arc *a;
+        captype bottleneck;
+        nodeptr *np;
+
+
+        /* 1. Finding bottleneck capacity */
+        /* 1a - the source tree */
+        bottleneck = middle_arc->r_cap;
+        for (i = middle_arc->sister->head;; i = a->head)
         {
-          if (a0->sister->r_cap) set_active(j);
-          if (a != TERMINAL && a != ORPHAN && a->head == i)
-          {
-            /* add j to the adoption list */
-            j->parent = ORPHAN;
-            np = nodeptr_block->New();
-            np->ptr = j;
-            if (orphan_last) orphan_last->next = np;
-            else             orphan_first = np;
-            orphan_last = np;
-            np->next = NULL;
-          }
+          a = i->parent;
+          if (a == TERMINAL) break;
+          if (bottleneck > a->sister->r_cap) bottleneck = a->sister->r_cap;
         }
-      }
-    }
-  }
+        if (bottleneck > i->tr_cap) bottleneck = i->tr_cap;
+        /* 1b - the sink tree */
+        for (i = middle_arc->head;; i = a->head)
+        {
+          a = i->parent;
+          if (a == TERMINAL) break;
+          if (bottleneck > a->r_cap) bottleneck = a->r_cap;
+        }
+        if (bottleneck > -i->tr_cap) bottleneck = -i->tr_cap;
 
-  void Graph::process_sink_orphan(node *i)
-  {
-    node *j;
-    arc *a0, *a0_min = NULL, *a;
-    nodeptr *np;
-    int d, d_min = INFINITE_D;
-
-    /* trying to find a new parent */
-    for (a0 = i->first; a0; a0 = a0->next)
-      if (a0->r_cap)
-      {
-        j = a0->head;
-        if (j->is_sink && (a = j->parent))
+
+        /* 2. Augmenting */
+        /* 2a - the source tree */
+        middle_arc->sister->r_cap += bottleneck;
+        middle_arc->r_cap -= bottleneck;
+        for (i = middle_arc->sister->head;; i = a->head)
         {
-          /* checking the origin of j */
-          d = 0;
-          while (1)
-          {
-            if (j->TS == TIME)
-            {
-              d += j->DIST;
-              break;
-            }
-            a = j->parent;
-            d++;
-            if (a == TERMINAL)
-            {
-              j->TS = TIME;
-              j->DIST = 1;
-              break;
-            }
-            if (a == ORPHAN) { d = INFINITE_D; break; }
-            j = a->head;
-          }
-          if (d < INFINITE_D) /* j originates from the sink - done */
+          a = i->parent;
+          if (a == TERMINAL) break;
+          a->r_cap += bottleneck;
+          a->sister->r_cap -= bottleneck;
+          if (!a->sister->r_cap)
           {
-            if (d < d_min)
-            {
-              a0_min = a0;
-              d_min = d;
-            }
-            /* set marks along the path */
-            for (j = a0->head; j->TS != TIME; j = j->parent->head)
-            {
-              j->TS = TIME;
-              j->DIST = d--;
-            }
+            /* add i to the adoption list */
+            i->parent = ORPHAN;
+            np = nodeptr_block->New();
+            np->ptr = i;
+            np->next = orphan_first;
+            orphan_first = np;
           }
         }
-      }
-
-    if ((i->parent = a0_min))
-    {
-      i->TS = TIME;
-      i->DIST = d_min + 1;
-    }
-    else
-    {
-      /* no parent is found */
-      i->TS = 0;
-
-      /* process neighbors */
-      for (a0 = i->first; a0; a0 = a0->next)
-      {
-        j = a0->head;
-        if (j->is_sink && (a = j->parent))
+        i->tr_cap -= bottleneck;
+        if (!i->tr_cap)
+        {
+          /* add i to the adoption list */
+          i->parent = ORPHAN;
+          np = nodeptr_block->New();
+          np->ptr = i;
+          np->next = orphan_first;
+          orphan_first = np;
+        }
+        /* 2b - the sink tree */
+        for (i = middle_arc->head;; i = a->head)
         {
-          if (a0->r_cap) set_active(j);
-          if (a != TERMINAL && a != ORPHAN && a->head == i)
+          a = i->parent;
+          if (a == TERMINAL) break;
+          a->sister->r_cap += bottleneck;
+          a->r_cap -= bottleneck;
+          if (!a->r_cap)
           {
-            /* add j to the adoption list */
-            j->parent = ORPHAN;
+            /* add i to the adoption list */
+            i->parent = ORPHAN;
             np = nodeptr_block->New();
-            np->ptr = j;
-            if (orphan_last) orphan_last->next = np;
-            else             orphan_first = np;
-            orphan_last = np;
-            np->next = NULL;
+            np->ptr = i;
+            np->next = orphan_first;
+            orphan_first = np;
           }
         }
-      }
-    }
-  }
-
-  /***********************************************************************/
-
-  Graph::flowtype Graph::maxflow()
-  {
-    node *i, *j, *current_node = NULL;
-    arc *a;
-    nodeptr *np, *np_next;
+        i->tr_cap += bottleneck;
+        if (!i->tr_cap)
+        {
+          /* add i to the adoption list */
+          i->parent = ORPHAN;
+          np = nodeptr_block->New();
+          np->ptr = i;
+          np->next = orphan_first;
+          orphan_first = np;
+        }
 
-    maxflow_init();
-    nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function);
 
-    while (1)
-    {
-      if ((i = current_node))
-      {
-        i->next = NULL; /* remove active flag */
-        if (!i->parent) i = NULL;
-      }
-      if (!i)
-      {
-        if (!(i = next_active())) break;
+        flow += bottleneck;
       }
 
-      /* growth */
-      if (!i->is_sink)
+      /***********************************************************************/
+
+      void Graph::process_source_orphan(node *i)
       {
-        /* grow source tree */
-        for (a = i->first; a; a = a->next)
-          if (a->r_cap)
+        node *j;
+        arc *a0, *a0_min = NULL, *a;
+        nodeptr *np;
+        int d, d_min = INFINITE_D;
+
+        /* trying to find a new parent */
+        for (a0 = i->first; a0; a0 = a0->next)
+          if (a0->sister->r_cap)
           {
-            j = a->head;
-            if (!j->parent)
+            j = a0->head;
+            if (!j->is_sink && (a = j->parent))
             {
-              j->is_sink = 0;
-              j->parent = a->sister;
-              j->TS = i->TS;
-              j->DIST = i->DIST + 1;
-              set_active(j);
+              /* checking the origin of j */
+              d = 0;
+              while (1)
+              {
+                if (j->TS == TIME)
+                {
+                  d += j->DIST;
+                  break;
+                }
+                a = j->parent;
+                d++;
+                if (a == TERMINAL)
+                {
+                  j->TS = TIME;
+                  j->DIST = 1;
+                  break;
+                }
+                if (a == ORPHAN) { d = INFINITE_D; break; }
+                j = a->head;
+              }
+              if (d < INFINITE_D) /* j originates from the source - done */
+              {
+                if (d < d_min)
+                {
+                  a0_min = a0;
+                  d_min = d;
+                }
+                /* set marks along the path */
+                for (j = a0->head; j->TS != TIME; j = j->parent->head)
+                {
+                  j->TS = TIME;
+                  j->DIST = d--;
+                }
+              }
             }
-            else if (j->is_sink) break;
-            else if (j->TS <= i->TS &&
-              j->DIST > i->DIST)
+          }
+
+        if ((i->parent = a0_min))
+        {
+          i->TS = TIME;
+          i->DIST = d_min + 1;
+        }
+        else
+        {
+          /* no parent is found */
+          i->TS = 0;
+
+          /* process neighbors */
+          for (a0 = i->first; a0; a0 = a0->next)
+          {
+            j = a0->head;
+            if (!j->is_sink && (a = j->parent))
             {
-              /* heuristic - trying to make the distance from j to the source shorter */
-              j->parent = a->sister;
-              j->TS = i->TS;
-              j->DIST = i->DIST + 1;
+              if (a0->sister->r_cap) set_active(j);
+              if (a != TERMINAL && a != ORPHAN && a->head == i)
+              {
+                /* add j to the adoption list */
+                j->parent = ORPHAN;
+                np = nodeptr_block->New();
+                np->ptr = j;
+                if (orphan_last) orphan_last->next = np;
+                else             orphan_first = np;
+                orphan_last = np;
+                np->next = NULL;
+              }
             }
           }
+        }
       }
-      else
+
+      void Graph::process_sink_orphan(node *i)
       {
-        /* grow sink tree */
-        for (a = i->first; a; a = a->next)
-          if (a->sister->r_cap)
+        node *j;
+        arc *a0, *a0_min = NULL, *a;
+        nodeptr *np;
+        int d, d_min = INFINITE_D;
+
+        /* trying to find a new parent */
+        for (a0 = i->first; a0; a0 = a0->next)
+          if (a0->r_cap)
           {
-            j = a->head;
-            if (!j->parent)
+            j = a0->head;
+            if (j->is_sink && (a = j->parent))
             {
-              j->is_sink = 1;
-              j->parent = a->sister;
-              j->TS = i->TS;
-              j->DIST = i->DIST + 1;
-              set_active(j);
+              /* checking the origin of j */
+              d = 0;
+              while (1)
+              {
+                if (j->TS == TIME)
+                {
+                  d += j->DIST;
+                  break;
+                }
+                a = j->parent;
+                d++;
+                if (a == TERMINAL)
+                {
+                  j->TS = TIME;
+                  j->DIST = 1;
+                  break;
+                }
+                if (a == ORPHAN) { d = INFINITE_D; break; }
+                j = a->head;
+              }
+              if (d < INFINITE_D) /* j originates from the sink - done */
+              {
+                if (d < d_min)
+                {
+                  a0_min = a0;
+                  d_min = d;
+                }
+                /* set marks along the path */
+                for (j = a0->head; j->TS != TIME; j = j->parent->head)
+                {
+                  j->TS = TIME;
+                  j->DIST = d--;
+                }
+              }
             }
-            else if (!j->is_sink) { a = a->sister; break; }
-            else if (j->TS <= i->TS &&
-              j->DIST > i->DIST)
+          }
+
+        if ((i->parent = a0_min))
+        {
+          i->TS = TIME;
+          i->DIST = d_min + 1;
+        }
+        else
+        {
+          /* no parent is found */
+          i->TS = 0;
+
+          /* process neighbors */
+          for (a0 = i->first; a0; a0 = a0->next)
+          {
+            j = a0->head;
+            if (j->is_sink && (a = j->parent))
             {
-              /* heuristic - trying to make the distance from j to the sink shorter */
-              j->parent = a->sister;
-              j->TS = i->TS;
-              j->DIST = i->DIST + 1;
+              if (a0->r_cap) set_active(j);
+              if (a != TERMINAL && a != ORPHAN && a->head == i)
+              {
+                /* add j to the adoption list */
+                j->parent = ORPHAN;
+                np = nodeptr_block->New();
+                np->ptr = j;
+                if (orphan_last) orphan_last->next = np;
+                else             orphan_first = np;
+                orphan_last = np;
+                np->next = NULL;
+              }
             }
           }
+        }
       }
 
-      TIME++;
+      /***********************************************************************/
 
-      if (a)
+      Graph::flowtype Graph::maxflow()
       {
-        i->next = i; /* set active flag */
-        current_node = i;
+        node *i, *j, *current_node = NULL;
+        arc *a;
+        nodeptr *np, *np_next;
 
-        /* augmentation */
-        augment(a);
-        /* augmentation end */
+        maxflow_init();
+        nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function);
 
-        /* adoption */
-        while ((np = orphan_first))
+        while (1)
         {
-          np_next = np->next;
-          np->next = NULL;
+          if ((i = current_node))
+          {
+            i->next = NULL; /* remove active flag */
+            if (!i->parent) i = NULL;
+          }
+          if (!i)
+          {
+            if (!(i = next_active())) break;
+          }
 
-          while ((np = orphan_first))
+          /* growth */
+          if (!i->is_sink)
           {
-            orphan_first = np->next;
-            i = np->ptr;
-            nodeptr_block->Delete(np);
-            if (!orphan_first) orphan_last = NULL;
-            if (i->is_sink) process_sink_orphan(i);
-            else            process_source_orphan(i);
+            /* grow source tree */
+            for (a = i->first; a; a = a->next)
+              if (a->r_cap)
+              {
+                j = a->head;
+                if (!j->parent)
+                {
+                  j->is_sink = 0;
+                  j->parent = a->sister;
+                  j->TS = i->TS;
+                  j->DIST = i->DIST + 1;
+                  set_active(j);
+                }
+                else if (j->is_sink) break;
+                else if (j->TS <= i->TS &&
+                  j->DIST > i->DIST)
+                {
+                  /* heuristic - trying to make the distance from j to the source shorter */
+                  j->parent = a->sister;
+                  j->TS = i->TS;
+                  j->DIST = i->DIST + 1;
+                }
+              }
           }
+          else
+          {
+            /* grow sink tree */
+            for (a = i->first; a; a = a->next)
+              if (a->sister->r_cap)
+              {
+                j = a->head;
+                if (!j->parent)
+                {
+                  j->is_sink = 1;
+                  j->parent = a->sister;
+                  j->TS = i->TS;
+                  j->DIST = i->DIST + 1;
+                  set_active(j);
+                }
+                else if (!j->is_sink) { a = a->sister; break; }
+                else if (j->TS <= i->TS &&
+                  j->DIST > i->DIST)
+                {
+                  /* heuristic - trying to make the distance from j to the sink shorter */
+                  j->parent = a->sister;
+                  j->TS = i->TS;
+                  j->DIST = i->DIST + 1;
+                }
+              }
+          }
+
+          TIME++;
+
+          if (a)
+          {
+            i->next = i; /* set active flag */
+            current_node = i;
 
-          orphan_first = np_next;
+            /* augmentation */
+            augment(a);
+            /* augmentation end */
+
+            /* adoption */
+            while ((np = orphan_first))
+            {
+              np_next = np->next;
+              np->next = NULL;
+
+              while ((np = orphan_first))
+              {
+                orphan_first = np->next;
+                i = np->ptr;
+                nodeptr_block->Delete(np);
+                if (!orphan_first) orphan_last = NULL;
+                if (i->is_sink) process_sink_orphan(i);
+                else            process_source_orphan(i);
+              }
+
+              orphan_first = np_next;
+            }
+            /* adoption end */
+          }
+          else current_node = NULL;
         }
-        /* adoption end */
-      }
-      else current_node = NULL;
-    }
 
-    delete nodeptr_block;
+        delete nodeptr_block;
 
-    return flow;
-  }
+        return flow;
+      }
 
-  /***********************************************************************/
+      /***********************************************************************/
 
-  Graph::termtype Graph::what_segment(node_id i)
-  {
-    if (((node*)i)->parent && !((node*)i)->is_sink) return SOURCE;
-    return SINK;
+      Graph::termtype Graph::what_segment(node_id i)
+      {
+        if (((node*)i)->parent && !((node*)i)->is_sink) return SOURCE;
+        return SINK;
+      }
+    }
   }
-
 }
diff --git a/src/algorithms/LBSP/BackgroundSubtractorLBSP.cpp b/src/algorithms/LBSP/BackgroundSubtractorLBSP.cpp
index 6344b6dc8d4c8a280380288c61a3284fe6a8b280..53dc0bedfd3bd3f446a0ed37334d087f51c34976 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorLBSP.cpp
+++ b/src/algorithms/LBSP/BackgroundSubtractorLBSP.cpp
@@ -9,6 +9,8 @@
 #include "DistanceUtils.h"
 #include "RandUtils.h"
 
+//using namespace bgslibrary::algorithms::lbsp;
+
 #ifndef SIZE_MAX
 # if __WORDSIZE == 64
 #  define SIZE_MAX		(18446744073709551615UL)
@@ -17,55 +19,64 @@
 # endif
 #endif
 
-// local define used to determine the default median blur kernel size
-#define DEFAULT_MEDIAN_BLUR_KERNEL_SIZE (9)
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      // local define used to determine the default median blur kernel size
+      const int DEFAULT_MEDIAN_BLUR_KERNEL_SIZE = 9;
 
-BackgroundSubtractorLBSP::BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset)
-  : m_nImgChannels(0)
-  , m_nImgType(0)
-  , m_nLBSPThresholdOffset(nLBSPThresholdOffset)
-  , m_fRelLBSPThreshold(fRelLBSPThreshold)
-  , m_nTotPxCount(0)
-  , m_nTotRelevantPxCount(0)
-  , m_nFrameIndex(SIZE_MAX)
-  , m_nFramesSinceLastReset(0)
-  , m_nModelResetCooldown(0)
-  , m_aPxIdxLUT(nullptr)
-  , m_aPxInfoLUT(nullptr)
-  , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE)
-  , m_bInitialized(false)
-  , m_bAutoModelResetEnabled(true)
-  , m_bUsingMovingCamera(false)
-  , nDebugCoordX(0), nDebugCoordY(0) {
-  CV_Assert(m_fRelLBSPThreshold >= 0);
-}
+      BackgroundSubtractorLBSP::BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset)
+        : m_nImgChannels(0)
+        , m_nImgType(0)
+        , m_nLBSPThresholdOffset(nLBSPThresholdOffset)
+        , m_fRelLBSPThreshold(fRelLBSPThreshold)
+        , m_nTotPxCount(0)
+        , m_nTotRelevantPxCount(0)
+        , m_nFrameIndex(SIZE_MAX)
+        , m_nFramesSinceLastReset(0)
+        , m_nModelResetCooldown(0)
+        , m_aPxIdxLUT(nullptr)
+        , m_aPxInfoLUT(nullptr)
+        , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE)
+        , m_bInitialized(false)
+        , m_bAutoModelResetEnabled(true)
+        , m_bUsingMovingCamera(false)
+        , nDebugCoordX(0), nDebugCoordY(0) {
+        CV_Assert(m_fRelLBSPThreshold >= 0);
+      }
 
-BackgroundSubtractorLBSP::~BackgroundSubtractorLBSP() {}
+      BackgroundSubtractorLBSP::~BackgroundSubtractorLBSP() {}
 
-void BackgroundSubtractorLBSP::initialize(const cv::Mat& oInitImg) {
-  this->initialize(oInitImg, cv::Mat());
-}
+      void BackgroundSubtractorLBSP::initialize(const cv::Mat& oInitImg) {
+        this->initialize(oInitImg, cv::Mat());
+      }
 
-/*cv::AlgorithmInfo* BackgroundSubtractorLBSP::info() const {
-  return nullptr;
-}*/
+      /*cv::AlgorithmInfo* BackgroundSubtractorLBSP::info() const {
+        return nullptr;
+      }*/
 
-cv::Mat BackgroundSubtractorLBSP::getROICopy() const {
-  return m_oROI.clone();
-}
+      cv::Mat BackgroundSubtractorLBSP::getROICopy() const {
+        return m_oROI.clone();
+      }
 
-void BackgroundSubtractorLBSP::setROI(cv::Mat& oROI) {
-  LBSP::validateROI(oROI);
-  CV_Assert(cv::countNonZero(oROI) > 0);
-  if (m_bInitialized) {
-    cv::Mat oLatestBackgroundImage;
-    getBackgroundImage(oLatestBackgroundImage);
-    initialize(oLatestBackgroundImage, oROI);
-  }
-  else
-    m_oROI = oROI.clone();
-}
+      void BackgroundSubtractorLBSP::setROI(cv::Mat& oROI) {
+        LBSP::validateROI(oROI);
+        CV_Assert(cv::countNonZero(oROI) > 0);
+        if (m_bInitialized) {
+          cv::Mat oLatestBackgroundImage;
+          getBackgroundImage(oLatestBackgroundImage);
+          initialize(oLatestBackgroundImage, oROI);
+        }
+        else
+          m_oROI = oROI.clone();
+      }
 
-void BackgroundSubtractorLBSP::setAutomaticModelReset(bool bVal) {
-  m_bAutoModelResetEnabled = bVal;
+      void BackgroundSubtractorLBSP::setAutomaticModelReset(bool bVal) {
+        m_bAutoModelResetEnabled = bVal;
+      }
+    }
+  }
 }
diff --git a/src/algorithms/LBSP/BackgroundSubtractorLBSP.h b/src/algorithms/LBSP/BackgroundSubtractorLBSP.h
index e22a10aaf49b68312e27dc38b70580f0c1a0adcc..3744b8c3358a58c2265644e4bed5a5ec3b0d014b 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorLBSP.h
+++ b/src/algorithms/LBSP/BackgroundSubtractorLBSP.h
@@ -5,82 +5,90 @@
 
 #include "LBSP.h"
 
-/*!
-  Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class).
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      /*!
+        Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class).
 
-  For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background
-  Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection
-  in Feature Space Using Local Binary Similarity Patterns", in CRV 2013.
+        For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background
+        Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection
+        in Feature Space Using Local Binary Similarity Patterns", in CRV 2013.
 
-  This algorithm is currently NOT thread-safe.
- */
-class BackgroundSubtractorLBSP : public cv::BackgroundSubtractor {
-public:
-  //! full constructor
-  BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0);
-  //! default destructor
-  virtual ~BackgroundSubtractorLBSP();
-  //! (re)initiaization method; needs to be called before starting background subtraction
-  virtual void initialize(const cv::Mat& oInitImg);
-  //! (re)initiaization method; needs to be called before starting background subtraction
-  virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0;
-  //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0)
-  virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0;
-  //! unused, always returns nullptr
-  //virtual cv::AlgorithmInfo* info() const;
-  //! returns a copy of the ROI used for descriptor extraction
-  virtual cv::Mat getROICopy() const;
-  //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI)
-  virtual void setROI(cv::Mat& oROI);
-  //! turns automatic model reset on or off
-  void setAutomaticModelReset(bool);
+        This algorithm is currently NOT thread-safe.
+      */
+      class BackgroundSubtractorLBSP : public cv::BackgroundSubtractor {
+      public:
+        //! full constructor
+        BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0);
+        //! default destructor
+        virtual ~BackgroundSubtractorLBSP();
+        //! (re)initiaization method; needs to be called before starting background subtraction
+        virtual void initialize(const cv::Mat& oInitImg);
+        //! (re)initiaization method; needs to be called before starting background subtraction
+        virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0;
+        //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0)
+        virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0;
+        //! unused, always returns nullptr
+        //virtual cv::AlgorithmInfo* info() const;
+        //! returns a copy of the ROI used for descriptor extraction
+        virtual cv::Mat getROICopy() const;
+        //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI)
+        virtual void setROI(cv::Mat& oROI);
+        //! turns automatic model reset on or off
+        void setAutomaticModelReset(bool);
 
-protected:
-  struct PxInfoBase {
-    int nImgCoord_Y;
-    int nImgCoord_X;
-    size_t nModelIdx;
-  };
-  //! background model ROI used for LBSP descriptor extraction (specific to the input image size)
-  cv::Mat m_oROI;
-  //! input image size
-  cv::Size m_oImgSize;
-  //! input image channel size
-  size_t m_nImgChannels;
-  //! input image type
-  int m_nImgType;
-  //! LBSP internal threshold offset value, used to reduce texture noise in dark regions
-  const size_t m_nLBSPThresholdOffset;
-  //! LBSP relative internal threshold (kept here since we don't keep an LBSP object)
-  const float m_fRelLBSPThreshold;
-  //! total number of pixels (depends on the input frame size) & total number of relevant pixels
-  size_t m_nTotPxCount, m_nTotRelevantPxCount;
-  //! current frame index, frame count since last model reset & model reset cooldown counters
-  size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown;
-  //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities
-  size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1];
-  //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI)
-  size_t* m_aPxIdxLUT;
-  //! internal pixel info LUT for all possible pixel indexes
-  PxInfoBase* m_aPxInfoLUT;
-  //! default kernel size for median blur post-proc filtering
-  const int m_nDefaultMedianBlurKernelSize;
-  //! specifies whether the algorithm is fully initialized or not
-  bool m_bInitialized;
-  //! specifies whether automatic model resets are enabled or not
-  bool m_bAutoModelResetEnabled;
-  //! specifies whether the camera is considered moving or not
-  bool m_bUsingMovingCamera;
-  //! copy of latest pixel intensities (used when refreshing model)
-  cv::Mat m_oLastColorFrame;
-  //! copy of latest descriptors (used when refreshing model)
-  cv::Mat m_oLastDescFrame;
-  //! the foreground mask generated by the method at [t-1]
-  cv::Mat m_oLastFGMask;
-
-public:
-  // ######## DEBUG PURPOSES ONLY ##########
-  int nDebugCoordX, nDebugCoordY;
-  std::string sDebugName;
-};
+      protected:
+        struct PxInfoBase {
+          int nImgCoord_Y;
+          int nImgCoord_X;
+          size_t nModelIdx;
+        };
+        //! background model ROI used for LBSP descriptor extraction (specific to the input image size)
+        cv::Mat m_oROI;
+        //! input image size
+        cv::Size m_oImgSize;
+        //! input image channel size
+        size_t m_nImgChannels;
+        //! input image type
+        int m_nImgType;
+        //! LBSP internal threshold offset value, used to reduce texture noise in dark regions
+        const size_t m_nLBSPThresholdOffset;
+        //! LBSP relative internal threshold (kept here since we don't keep an LBSP object)
+        const float m_fRelLBSPThreshold;
+        //! total number of pixels (depends on the input frame size) & total number of relevant pixels
+        size_t m_nTotPxCount, m_nTotRelevantPxCount;
+        //! current frame index, frame count since last model reset & model reset cooldown counters
+        size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown;
+        //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities
+        size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1];
+        //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI)
+        size_t* m_aPxIdxLUT;
+        //! internal pixel info LUT for all possible pixel indexes
+        PxInfoBase* m_aPxInfoLUT;
+        //! default kernel size for median blur post-proc filtering
+        const int m_nDefaultMedianBlurKernelSize;
+        //! specifies whether the algorithm is fully initialized or not
+        bool m_bInitialized;
+        //! specifies whether automatic model resets are enabled or not
+        bool m_bAutoModelResetEnabled;
+        //! specifies whether the camera is considered moving or not
+        bool m_bUsingMovingCamera;
+        //! copy of latest pixel intensities (used when refreshing model)
+        cv::Mat m_oLastColorFrame;
+        //! copy of latest descriptors (used when refreshing model)
+        cv::Mat m_oLastDescFrame;
+        //! the foreground mask generated by the method at [t-1]
+        cv::Mat m_oLastFGMask;
 
+      public:
+        // ######## DEBUG PURPOSES ONLY ##########
+        int nDebugCoordX, nDebugCoordY;
+        std::string sDebugName;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBSP/BackgroundSubtractorLBSP_.cpp b/src/algorithms/LBSP/BackgroundSubtractorLBSP_.cpp
index d5324bdebf4682617eba6139647624ee7255965f..4bcdfb1a85f78b334b8e66bfa4316ec089449f20 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorLBSP_.cpp
+++ b/src/algorithms/LBSP/BackgroundSubtractorLBSP_.cpp
@@ -9,57 +9,68 @@
 #include "DistanceUtils.h"
 #include "RandUtils.h"
 
-// local define used to determine the default median blur kernel size
-#define DEFAULT_MEDIAN_BLUR_KERNEL_SIZE (9)
+//using namespace bgslibrary::algorithms::lbsp;
 
-BackgroundSubtractorLBSP_::BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset)
-  : m_nImgChannels(0)
-  , m_nImgType(0)
-  , m_nLBSPThresholdOffset(nLBSPThresholdOffset)
-  , m_fRelLBSPThreshold(fRelLBSPThreshold)
-  , m_nTotPxCount(0)
-  , m_nTotRelevantPxCount(0)
-  , m_nFrameIndex(SIZE_MAX)
-  , m_nFramesSinceLastReset(0)
-  , m_nModelResetCooldown(0)
-  , m_aPxIdxLUT(nullptr)
-  , m_aPxInfoLUT(nullptr)
-  , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE)
-  , m_bInitialized(false)
-  , m_bAutoModelResetEnabled(true)
-  , m_bUsingMovingCamera(false)
-  , m_nDebugCoordX(0)
-  , m_nDebugCoordY(0)
-  , m_pDebugFS(nullptr) {
-  CV_Assert(m_fRelLBSPThreshold >= 0);
-}
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      // local define used to determine the default median blur kernel size
+      const int DEFAULT_MEDIAN_BLUR_KERNEL_SIZE = 9;
 
-BackgroundSubtractorLBSP_::~BackgroundSubtractorLBSP_() {}
+      BackgroundSubtractorLBSP_::BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset)
+        : m_nImgChannels(0)
+        , m_nImgType(0)
+        , m_nLBSPThresholdOffset(nLBSPThresholdOffset)
+        , m_fRelLBSPThreshold(fRelLBSPThreshold)
+        , m_nTotPxCount(0)
+        , m_nTotRelevantPxCount(0)
+        , m_nFrameIndex(SIZE_MAX)
+        , m_nFramesSinceLastReset(0)
+        , m_nModelResetCooldown(0)
+        , m_aPxIdxLUT(nullptr)
+        , m_aPxInfoLUT(nullptr)
+        , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE)
+        , m_bInitialized(false)
+        , m_bAutoModelResetEnabled(true)
+        , m_bUsingMovingCamera(false)
+        , m_nDebugCoordX(0)
+        , m_nDebugCoordY(0)
+        , m_pDebugFS(nullptr) {
+        CV_Assert(m_fRelLBSPThreshold >= 0);
+      }
 
-void BackgroundSubtractorLBSP_::initialize(const cv::Mat& oInitImg) {
-  this->initialize(oInitImg, cv::Mat());
-}
-/*
-cv::AlgorithmInfo* BackgroundSubtractorLBSP_::info() const {
-    return nullptr;
-}
-*/
-cv::Mat BackgroundSubtractorLBSP_::getROICopy() const {
-  return m_oROI.clone();
-}
+      BackgroundSubtractorLBSP_::~BackgroundSubtractorLBSP_() {}
 
-void BackgroundSubtractorLBSP_::setROI(cv::Mat& oROI) {
-  LBSP_::validateROI(oROI);
-  CV_Assert(cv::countNonZero(oROI) > 0);
-  if (m_bInitialized) {
-    cv::Mat oLatestBackgroundImage;
-    getBackgroundImage(oLatestBackgroundImage);
-    initialize(oLatestBackgroundImage, oROI);
-  }
-  else
-    m_oROI = oROI.clone();
-}
+      void BackgroundSubtractorLBSP_::initialize(const cv::Mat& oInitImg) {
+        this->initialize(oInitImg, cv::Mat());
+      }
+      /*
+      cv::AlgorithmInfo* BackgroundSubtractorLBSP_::info() const {
+          return nullptr;
+      }
+      */
+      cv::Mat BackgroundSubtractorLBSP_::getROICopy() const {
+        return m_oROI.clone();
+      }
 
-void BackgroundSubtractorLBSP_::setAutomaticModelReset(bool bVal) {
-  m_bAutoModelResetEnabled = bVal;
+      void BackgroundSubtractorLBSP_::setROI(cv::Mat& oROI) {
+        LBSP_::validateROI(oROI);
+        CV_Assert(cv::countNonZero(oROI) > 0);
+        if (m_bInitialized) {
+          cv::Mat oLatestBackgroundImage;
+          getBackgroundImage(oLatestBackgroundImage);
+          initialize(oLatestBackgroundImage, oROI);
+        }
+        else
+          m_oROI = oROI.clone();
+      }
+
+      void BackgroundSubtractorLBSP_::setAutomaticModelReset(bool bVal) {
+        m_bAutoModelResetEnabled = bVal;
+      }
+    }
+  }
 }
diff --git a/src/algorithms/LBSP/BackgroundSubtractorLBSP_.h b/src/algorithms/LBSP/BackgroundSubtractorLBSP_.h
index d828e107cf3db6bb948a182340e20852f45a3a6f..79d6df927c4071bdd1e48ed63d62ca2dcf25793e 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorLBSP_.h
+++ b/src/algorithms/LBSP/BackgroundSubtractorLBSP_.h
@@ -5,88 +5,97 @@
 
 #include "LBSP_.h"
 
-/*!
-    Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class).
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      /*!
+          Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class).
 
-    For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background
-    Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection
-    in Feature Space Using Local Binary Similarity Patterns", in CRV 2013.
+          For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background
+          Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection
+          in Feature Space Using Local Binary Similarity Patterns", in CRV 2013.
 
-    This algorithm is currently NOT thread-safe.
- */
-class BackgroundSubtractorLBSP_ : public cv::BackgroundSubtractor {
-public:
-  //! full constructor
-  BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0);
-  //! default destructor
-  virtual ~BackgroundSubtractorLBSP_();
-  //! (re)initiaization method; needs to be called before starting background subtraction
-  virtual void initialize(const cv::Mat& oInitImg);
-  //! (re)initiaization method; needs to be called before starting background subtraction
-  virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0;
-  //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0)
-  virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0;
-  //! unused, always returns nullptr
-  //virtual cv::AlgorithmInfo* info() const;
-  //! returns a copy of the ROI used for descriptor extraction
-  virtual cv::Mat getROICopy() const;
-  //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI)
-  virtual void setROI(cv::Mat& oROI);
-  //! turns automatic model reset on or off
-  void setAutomaticModelReset(bool);
+          This algorithm is currently NOT thread-safe.
+      */
+      class BackgroundSubtractorLBSP_ : public cv::BackgroundSubtractor {
+      public:
+        //! full constructor
+        BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0);
+        //! default destructor
+        virtual ~BackgroundSubtractorLBSP_();
+        //! (re)initiaization method; needs to be called before starting background subtraction
+        virtual void initialize(const cv::Mat& oInitImg);
+        //! (re)initiaization method; needs to be called before starting background subtraction
+        virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0;
+        //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0)
+        virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0;
+        //! unused, always returns nullptr
+        //virtual cv::AlgorithmInfo* info() const;
+        //! returns a copy of the ROI used for descriptor extraction
+        virtual cv::Mat getROICopy() const;
+        //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI)
+        virtual void setROI(cv::Mat& oROI);
+        //! turns automatic model reset on or off
+        void setAutomaticModelReset(bool);
 
-protected:
-  struct PxInfoBase {
-    int nImgCoord_Y;
-    int nImgCoord_X;
-    size_t nModelIdx;
-  };
-  //! background model ROI used for LBSP descriptor extraction (specific to the input image size)
-  cv::Mat m_oROI;
-  //! input image size
-  cv::Size m_oImgSize;
-  //! input image channel size
-  size_t m_nImgChannels;
-  //! input image type
-  int m_nImgType;
-  //! LBSP internal threshold offset value, used to reduce texture noise in dark regions
-  const size_t m_nLBSPThresholdOffset;
-  //! LBSP relative internal threshold (kept here since we don't keep an LBSP object)
-  const float m_fRelLBSPThreshold;
-  //! total number of pixels (depends on the input frame size) & total number of relevant pixels
-  size_t m_nTotPxCount, m_nTotRelevantPxCount;
-  //! current frame index, frame count since last model reset & model reset cooldown counters
-  size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown;
-  //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities
-  size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1];
-  //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI)
-  size_t* m_aPxIdxLUT;
-  //! internal pixel info LUT for all possible pixel indexes
-  PxInfoBase* m_aPxInfoLUT;
-  //! default kernel size for median blur post-proc filtering
-  const int m_nDefaultMedianBlurKernelSize;
-  //! specifies whether the algorithm is fully initialized or not
-  bool m_bInitialized;
-  //! specifies whether automatic model resets are enabled or not
-  bool m_bAutoModelResetEnabled;
-  //! specifies whether the camera is considered moving or not
-  bool m_bUsingMovingCamera;
-  //! copy of latest pixel intensities (used when refreshing model)
-  cv::Mat m_oLastColorFrame;
-  //! copy of latest descriptors (used when refreshing model)
-  cv::Mat m_oLastDescFrame;
-  //! the foreground mask generated by the method at [t-1]
-  cv::Mat m_oLastFGMask;
+      protected:
+        struct PxInfoBase {
+          int nImgCoord_Y;
+          int nImgCoord_X;
+          size_t nModelIdx;
+        };
+        //! background model ROI used for LBSP descriptor extraction (specific to the input image size)
+        cv::Mat m_oROI;
+        //! input image size
+        cv::Size m_oImgSize;
+        //! input image channel size
+        size_t m_nImgChannels;
+        //! input image type
+        int m_nImgType;
+        //! LBSP internal threshold offset value, used to reduce texture noise in dark regions
+        const size_t m_nLBSPThresholdOffset;
+        //! LBSP relative internal threshold (kept here since we don't keep an LBSP object)
+        const float m_fRelLBSPThreshold;
+        //! total number of pixels (depends on the input frame size) & total number of relevant pixels
+        size_t m_nTotPxCount, m_nTotRelevantPxCount;
+        //! current frame index, frame count since last model reset & model reset cooldown counters
+        size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown;
+        //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities
+        size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1];
+        //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI)
+        size_t* m_aPxIdxLUT;
+        //! internal pixel info LUT for all possible pixel indexes
+        PxInfoBase* m_aPxInfoLUT;
+        //! default kernel size for median blur post-proc filtering
+        const int m_nDefaultMedianBlurKernelSize;
+        //! specifies whether the algorithm is fully initialized or not
+        bool m_bInitialized;
+        //! specifies whether automatic model resets are enabled or not
+        bool m_bAutoModelResetEnabled;
+        //! specifies whether the camera is considered moving or not
+        bool m_bUsingMovingCamera;
+        //! copy of latest pixel intensities (used when refreshing model)
+        cv::Mat m_oLastColorFrame;
+        //! copy of latest descriptors (used when refreshing model)
+        cv::Mat m_oLastDescFrame;
+        //! the foreground mask generated by the method at [t-1]
+        cv::Mat m_oLastFGMask;
 
-private:
-  //! copy constructor -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers
-  BackgroundSubtractorLBSP_(const BackgroundSubtractorLBSP_&);
-  //! assignment operator -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers
-  BackgroundSubtractorLBSP_& operator=(const BackgroundSubtractorLBSP_&);
+      private:
+        //! copy constructor -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers
+        BackgroundSubtractorLBSP_(const BackgroundSubtractorLBSP_&);
+        //! assignment operator -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers
+        BackgroundSubtractorLBSP_& operator=(const BackgroundSubtractorLBSP_&);
 
-public:
-  // ######## DEBUG PURPOSES ONLY ##########
-  int m_nDebugCoordX, m_nDebugCoordY;
-  std::string m_sDebugName;
-  cv::FileStorage* m_pDebugFS;
-};
+      public:
+        // ######## DEBUG PURPOSES ONLY ##########
+        int m_nDebugCoordX, m_nDebugCoordY;
+        std::string m_sDebugName;
+        cv::FileStorage* m_pDebugFS;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.cpp b/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.cpp
index 1b67ae6ca3859b3ffce2ba2487dcd94225141cb4..330a1ac50889d908942ce98d35085b37b45e6ac6 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.cpp
+++ b/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.cpp
@@ -7,6 +7,8 @@
 #include "BackgroundSubtractorLOBSTER.h"
 #include "RandUtils.h"
 
+using namespace bgslibrary::algorithms::lbsp;
+
 BackgroundSubtractorLOBSTER::BackgroundSubtractorLOBSTER(float fRelLBSPThreshold
   , size_t nLBSPThresholdOffset
   , size_t nDescDistThreshold
diff --git a/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.h b/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.h
index d229e52ae2b87e9499829364a70bc0faf1960fad..b7860a188628fdb3ec7c35a0bd703910ddeed9a5 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.h
+++ b/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.h
@@ -2,66 +2,74 @@
 
 #include "BackgroundSubtractorLBSP.h"
 
-//! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold
-#define BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.365f)
-//! defines the default value for BackgroundSubtractorLBSP::m_nLBSPThresholdOffset
-#define BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD (0)
-//! defines the default value for BackgroundSubtractorLOBSTER::m_nDescDistThreshold
-#define BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD (4)
-//! defines the default value for BackgroundSubtractorLOBSTER::m_nColorDistThreshold
-#define BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD (30)
-//! defines the default value for BackgroundSubtractorLOBSTER::m_nBGSamples
-#define BGSLOBSTER_DEFAULT_NB_BG_SAMPLES (35)
-//! defines the default value for BackgroundSubtractorLOBSTER::m_nRequiredBGSamples
-#define BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES (2)
-//! defines the default value for the learning rate passed to BackgroundSubtractorLOBSTER::operator()
-#define BGSLOBSTER_DEFAULT_LEARNING_RATE (16)
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      //! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold
+      const float BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD = 0.365f;
+      //! defines the default value for BackgroundSubtractorLBSP::m_nLBSPThresholdOffset
+      const int BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD = 0;
+      //! defines the default value for BackgroundSubtractorLOBSTER::m_nDescDistThreshold
+      const int BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD = 4;
+      //! defines the default value for BackgroundSubtractorLOBSTER::m_nColorDistThreshold
+      const int BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD = 30;
+      //! defines the default value for BackgroundSubtractorLOBSTER::m_nBGSamples
+      const int BGSLOBSTER_DEFAULT_NB_BG_SAMPLES = 35;
+      //! defines the default value for BackgroundSubtractorLOBSTER::m_nRequiredBGSamples
+      const int BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES = 2;
+      //! defines the default value for the learning rate passed to BackgroundSubtractorLOBSTER::operator()
+      const int BGSLOBSTER_DEFAULT_LEARNING_RATE = 16;
 
-/*!
-  LOcal Binary Similarity segmenTER (LOBSTER) change detection algorithm.
+      /*!
+        LOcal Binary Similarity segmenTER (LOBSTER) change detection algorithm.
 
-  Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically).
-  For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3.
+        Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically).
+        For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3.
 
-  For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles and
-  G.-A. Bilodeau, "Improving Background Subtraction using Local Binary Similarity Patterns", in WACV 2014.
+        For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles and
+        G.-A. Bilodeau, "Improving Background Subtraction using Local Binary Similarity Patterns", in WACV 2014.
 
-  This algorithm is currently NOT thread-safe.
- */
-class BackgroundSubtractorLOBSTER : public BackgroundSubtractorLBSP {
-public:
-  //! full constructor
-  BackgroundSubtractorLOBSTER(float fRelLBSPThreshold = BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD,
-    size_t nLBSPThresholdOffset = BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD,
-    size_t nDescDistThreshold = BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD,
-    size_t nColorDistThreshold = BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD,
-    size_t nBGSamples = BGSLOBSTER_DEFAULT_NB_BG_SAMPLES,
-    size_t nRequiredBGSamples = BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES);
-  //! default destructor
-  virtual ~BackgroundSubtractorLOBSTER();
-  //! (re)initiaization method; needs to be called before starting background subtraction
-  virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI);
-  //! refreshes all samples based on the last analyzed frame
-  virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false);
-  //! primary model update function; the learning param is reinterpreted as an integer and should be > 0 (smaller values == faster adaptation)
-  virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = BGSLOBSTER_DEFAULT_LEARNING_RATE);
-  //! returns a copy of the latest reconstructed background image
-  void getBackgroundImage(cv::OutputArray backgroundImage) const;
-  //! returns a copy of the latest reconstructed background descriptors image
-  virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const;
-
-protected:
-  //! absolute color distance threshold
-  const size_t m_nColorDistThreshold;
-  //! absolute descriptor distance threshold
-  const size_t m_nDescDistThreshold;
-  //! number of different samples per pixel/block to be taken from input frames to build the background model
-  const size_t m_nBGSamples;
-  //! number of similar samples needed to consider the current pixel/block as 'background'
-  const size_t m_nRequiredBGSamples;
-  //! background model pixel intensity samples
-  std::vector<cv::Mat> m_voBGColorSamples;
-  //! background model descriptors samples
-  std::vector<cv::Mat> m_voBGDescSamples;
-};
+        This algorithm is currently NOT thread-safe.
+      */
+      class BackgroundSubtractorLOBSTER : public BackgroundSubtractorLBSP {
+      public:
+        //! full constructor
+        BackgroundSubtractorLOBSTER(float fRelLBSPThreshold = BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD,
+          size_t nLBSPThresholdOffset = BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD,
+          size_t nDescDistThreshold = BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD,
+          size_t nColorDistThreshold = BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD,
+          size_t nBGSamples = BGSLOBSTER_DEFAULT_NB_BG_SAMPLES,
+          size_t nRequiredBGSamples = BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES);
+        //! default destructor
+        virtual ~BackgroundSubtractorLOBSTER();
+        //! (re)initiaization method; needs to be called before starting background subtraction
+        virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI);
+        //! refreshes all samples based on the last analyzed frame
+        virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false);
+        //! primary model update function; the learning param is reinterpreted as an integer and should be > 0 (smaller values == faster adaptation)
+        virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = BGSLOBSTER_DEFAULT_LEARNING_RATE);
+        //! returns a copy of the latest reconstructed background image
+        void getBackgroundImage(cv::OutputArray backgroundImage) const;
+        //! returns a copy of the latest reconstructed background descriptors image
+        virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const;
 
+      protected:
+        //! absolute color distance threshold
+        const size_t m_nColorDistThreshold;
+        //! absolute descriptor distance threshold
+        const size_t m_nDescDistThreshold;
+        //! number of different samples per pixel/block to be taken from input frames to build the background model
+        const size_t m_nBGSamples;
+        //! number of similar samples needed to consider the current pixel/block as 'background'
+        const size_t m_nRequiredBGSamples;
+        //! background model pixel intensity samples
+        std::vector<cv::Mat> m_voBGColorSamples;
+        //! background model descriptors samples
+        std::vector<cv::Mat> m_voBGDescSamples;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBSP/BackgroundSubtractorPAWCS.cpp b/src/algorithms/LBSP/BackgroundSubtractorPAWCS.cpp
index 8a1415d2d5fecfcc526afe452f0b871e42cbfba0..acb1a8f4b522fda388fcfe4d51873dc9c989d705 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorPAWCS.cpp
+++ b/src/algorithms/LBSP/BackgroundSubtractorPAWCS.cpp
@@ -7,1328 +7,1339 @@
 #include "BackgroundSubtractorPAWCS.h"
 #include "RandUtils.h"
 
-/*
- *
- * Intrinsic configuration parameters are defined here; tuning these for better
- * performance should not be required in most cases -- although improvements in
- * very specific scenarios are always possible.
- *
- */
- //! parameter used for dynamic distance threshold adjustments ('R(x)')
-#define FEEDBACK_R_VAR (0.01f)
-//! parameters used to adjust the variation step size of 'v(x)'
-#define FEEDBACK_V_INCR  (1.000f)
-#define FEEDBACK_V_DECR  (0.100f)
-//! parameters used to scale dynamic learning rate adjustments  ('T(x)')
-#define FEEDBACK_T_DECR  (0.2500f)
-#define FEEDBACK_T_INCR  (0.5000f)
-#define FEEDBACK_T_LOWER (1.0000f)
-#define FEEDBACK_T_UPPER (256.00f)
-//! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values
-#define UNSTABLE_REG_RATIO_MIN (0.100f)
-#define UNSTABLE_REG_RDIST_MIN (3.000f)
-//! parameters used to scale the relative LBSP intensity threshold used for internal comparisons
-#define LBSPDESC_RATIO_MIN (0.100f)
-#define LBSPDESC_RATIO_MAX (0.500f)
-//! parameters used to trigger auto model resets in our frame-level component
-#define FRAMELEVEL_MIN_L1DIST_THRES (45)
-#define FRAMELEVEL_MIN_CDIST_THRES (FRAMELEVEL_MIN_L1DIST_THRES/10)
-#define FRAMELEVEL_DOWNSAMPLE_RATIO (8)
-//! parameters used to downscale gword maps & scale thresholds to make comparisons easier
-#define GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO (2)
-#define GWORD_DEFAULT_NB_INIT_SAMPL_PASSES (2)
-#define GWORD_DESC_THRES_BITS_MATCH_FACTOR (4)
+//using namespace bgslibrary::algorithms::lbsp;
 
-// local define used to specify the default frame size (320x240 = QVGA)
-#define DEFAULT_FRAME_SIZE cv::Size(320,240)
-// local define used to specify the default lword/gword update rate (16 = like vibe)
-#define DEFAULT_RESAMPLING_RATE (16)
-// local define used to specify the bootstrap window size for faster model stabilization
-#define DEFAULT_BOOTSTRAP_WIN_SIZE (500)
-// local define for the amount of weight offset to apply to words, making sure new words aren't always better than old ones
-#define DEFAULT_LWORD_WEIGHT_OFFSET (DEFAULT_BOOTSTRAP_WIN_SIZE*2)
-// local define used to set the default local word occurrence increment
-#define DEFAULT_LWORD_OCC_INCR 1
-// local define for the maximum weight a word can achieve before cutting off occ incr (used to make sure model stays good for long-term uses)
-#define DEFAULT_LWORD_MAX_WEIGHT (1.0f)
-// local define for the initial weight of a new word (used to make sure old words aren't worse off than new seeds)
-#define DEFAULT_LWORD_INIT_WEIGHT (1.0f/m_nLocalWordWeightOffset)
-// local define used to specify the desc dist threshold offset used for unstable regions
-#define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset)
-// local define used to specify the min descriptor bit count for flat regions
-#define FLAT_REGION_BIT_COUNT (s_nDescMaxDataRange_1ch/8)
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      /*
+       *
+       * Intrinsic configuration parameters are defined here; tuning these for better
+       * performance should not be required in most cases -- although improvements in
+       * very specific scenarios are always possible.
+       *
+       */
+       //! parameter used for dynamic distance threshold adjustments ('R(x)')
+      const float FEEDBACK_R_VAR = 0.01f;
+      //! parameters used to adjust the variation step size of 'v(x)'
+      const float FEEDBACK_V_INCR = 1.000f;
+      const float FEEDBACK_V_DECR = 0.100f;
+      //! parameters used to scale dynamic learning rate adjustments  ('T(x)')
+      const float FEEDBACK_T_DECR = 0.2500f;
+      const float FEEDBACK_T_INCR = 0.5000f;
+      const float FEEDBACK_T_LOWER = 1.0000f;
+      const float FEEDBACK_T_UPPER = 256.00f;
+      //! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values
+      const float UNSTABLE_REG_RATIO_MIN = 0.100f;
+      const float UNSTABLE_REG_RDIST_MIN = 3.000f;
+      //! parameters used to scale the relative LBSP intensity threshold used for internal comparisons
+      const float LBSPDESC_RATIO_MIN = 0.100f;
+      const float LBSPDESC_RATIO_MAX = 0.500f;
+      //! parameters used to trigger auto model resets in our frame-level component
+      const int FRAMELEVEL_MIN_L1DIST_THRES = 45;
+      const float FRAMELEVEL_MIN_CDIST_THRES = (FRAMELEVEL_MIN_L1DIST_THRES / 10);
+      const int FRAMELEVEL_DOWNSAMPLE_RATIO = 8;
+      //! parameters used to downscale gword maps & scale thresholds to make comparisons easier
+      const int GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO = 2;
+      const int GWORD_DEFAULT_NB_INIT_SAMPL_PASSES = 2;
+      const int GWORD_DESC_THRES_BITS_MATCH_FACTOR = 4;
 
-static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX;
-static const size_t s_nDescMaxDataRange_1ch = LBSP_::DESC_SIZE * 8;
-static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3;
-static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3;
+      // local define used to specify the default frame size (320x240 = QVGA)
+      #define DEFAULT_FRAME_SIZE cv::Size(320,240)
+      // local define used to specify the default lword/gword update rate (16 = like vibe)
+      const int DEFAULT_RESAMPLING_RATE = 16;
+      // local define used to specify the bootstrap window size for faster model stabilization
+      const int DEFAULT_BOOTSTRAP_WIN_SIZE = 500;
+      // local define for the amount of weight offset to apply to words, making sure new words aren't always better than old ones
+      const float DEFAULT_LWORD_WEIGHT_OFFSET = (DEFAULT_BOOTSTRAP_WIN_SIZE * 2);
+      // local define used to set the default local word occurrence increment
+      const int DEFAULT_LWORD_OCC_INCR = 1;
+      // local define for the maximum weight a word can achieve before cutting off occ incr (used to make sure model stays good for long-term uses)
+      const float DEFAULT_LWORD_MAX_WEIGHT = 1.0f;
+      // local define for the initial weight of a new word (used to make sure old words aren't worse off than new seeds)
+      const double DEFAULT_LWORD_INIT_WEIGHT = (1.0f / DEFAULT_LWORD_WEIGHT_OFFSET);
+      // local define used to specify the desc dist threshold offset used for unstable regions
+      #define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset)
+      // local define used to specify the min descriptor bit count for flat regions
+      #define FLAT_REGION_BIT_COUNT (s_nDescMaxDataRange_1ch/8)
 
-BackgroundSubtractorPAWCS::BackgroundSubtractorPAWCS(float fRelLBSPThreshold
-  , size_t nDescDistThresholdOffset
-  , size_t nMinColorDistThreshold
-  , size_t nMaxNbWords
-  , size_t nSamplesForMovingAvgs)
-  : BackgroundSubtractorLBSP_(fRelLBSPThreshold)
-  , m_nMinColorDistThreshold(nMinColorDistThreshold)
-  , m_nDescDistThresholdOffset(nDescDistThresholdOffset)
-  , m_nMaxLocalWords(nMaxNbWords)
-  , m_nCurrLocalWords(0)
-  , m_nMaxGlobalWords(nMaxNbWords / 2)
-  , m_nCurrGlobalWords(0)
-  , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs)
-  , m_fLastNonFlatRegionRatio(0.0f)
-  , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize)
-  , m_nDownSampledROIPxCount(0)
-  , m_nLocalWordWeightOffset(DEFAULT_LWORD_WEIGHT_OFFSET)
-  , m_apLocalWordDict(nullptr)
-  , m_aLocalWordList_1ch(nullptr)
-  , m_pLocalWordListIter_1ch(nullptr)
-  , m_aLocalWordList_3ch(nullptr)
-  , m_pLocalWordListIter_3ch(nullptr)
-  , m_apGlobalWordDict(nullptr)
-  , m_aGlobalWordList_1ch(nullptr)
-  , m_pGlobalWordListIter_1ch(nullptr)
-  , m_aGlobalWordList_3ch(nullptr)
-  , m_pGlobalWordListIter_3ch(nullptr)
-  , m_aPxInfoLUT_PAWCS(nullptr) {
-  CV_Assert(m_nMaxLocalWords > 0 && m_nMaxGlobalWords > 0);
-}
-
-BackgroundSubtractorPAWCS::~BackgroundSubtractorPAWCS() {
-  CleanupDictionaries();
-}
+      static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX;
+      static const size_t s_nDescMaxDataRange_1ch = LBSP_::DESC_SIZE * 8;
+      static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3;
+      static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3;
 
-void BackgroundSubtractorPAWCS::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) {
-  // == init
-  CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0);
-  CV_Assert(oInitImg.isContinuous());
-  CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1);
-  if (oInitImg.type() == CV_8UC3) {
-    std::vector<cv::Mat> voInitImgChannels;
-    cv::split(oInitImg, voInitImgChannels);
-    if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1])))
-      std::cout << std::endl << "\tBackgroundSubtractorPAWCS : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl;
-  }
-  cv::Mat oNewBGROI;
-  if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) {
-    oNewBGROI.create(oInitImg.size(), CV_8UC1);
-    oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX);
-  }
-  else if (oROI.empty())
-    oNewBGROI = m_oROI;
-  else {
-    CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1);
-    CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0);
-    oNewBGROI = oROI.clone();
-    cv::Mat oTempROI;
-    cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP_::PATCH_SIZE / 2);
-    cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI);
-  }
-  const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI);
-  CV_Assert(nOrigROIPxCount > 0);
-  LBSP_::validateROI(oNewBGROI);
-  const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI);
-  CV_Assert(nFinalROIPxCount > 0);
-  CleanupDictionaries();
-  m_oROI = oNewBGROI;
-  m_oImgSize = oInitImg.size();
-  m_nImgType = oInitImg.type();
-  m_nImgChannels = oInitImg.channels();
-  m_nTotPxCount = m_oImgSize.area();
-  m_nTotRelevantPxCount = nFinalROIPxCount;
-  m_nFrameIndex = 0;
-  m_nFramesSinceLastReset = 0;
-  m_nModelResetCooldown = 0;
-  m_bUsingMovingCamera = false;
-  m_oDownSampledFrameSize_MotionAnalysis = cv::Size(m_oImgSize.width / FRAMELEVEL_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_DOWNSAMPLE_RATIO);
-  m_oDownSampledFrameSize_GlobalWordLookup = cv::Size(m_oImgSize.width / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO, m_oImgSize.height / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO);
-  cv::resize(m_oROI, m_oDownSampledROI_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA);
-  m_fLastNonFlatRegionRatio = 0.0f;
-  m_nCurrLocalWords = m_nMaxLocalWords;
-  if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) {
-    const float fRegionSizeScaleFactor = (float)m_nTotPxCount / DEFAULT_FRAME_SIZE.area();
-    const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + fRegionSizeScaleFactor) + m_nDefaultMedianBlurKernelSize, m_nDefaultMedianBlurKernelSize + 4);
-    m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1;
-    m_nCurrGlobalWords = m_nMaxGlobalWords;
-    m_oDownSampledROI_MotionAnalysis |= UCHAR_MAX / 2;
-  }
-  else {
-    const float fRegionSizeScaleFactor = (float)nOrigROIPxCount / DEFAULT_FRAME_SIZE.area();
-    const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + m_nDefaultMedianBlurKernelSize*fRegionSizeScaleFactor * 2) + (m_nDefaultMedianBlurKernelSize - 4), m_nDefaultMedianBlurKernelSize);
-    m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1;
-    m_nCurrGlobalWords = std::min((size_t)std::pow(m_nMaxGlobalWords*fRegionSizeScaleFactor, 2) + 1, m_nMaxGlobalWords);
-  }
-  if (m_nImgChannels == 1) {
-    m_nCurrLocalWords = std::max(m_nCurrLocalWords / 2, (size_t)1);
-    m_nCurrGlobalWords = std::max(m_nCurrGlobalWords / 2, (size_t)1);
-  }
-  m_nDownSampledROIPxCount = (size_t)cv::countNonZero(m_oDownSampledROI_MotionAnalysis);
-  m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET;
-  m_oIllumUpdtRegionMask.create(m_oImgSize, CV_8UC1);
-  m_oIllumUpdtRegionMask = cv::Scalar_<uchar>(0);
-  m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1);
-  m_oUpdateRateFrame = cv::Scalar(FEEDBACK_T_LOWER);
-  m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1);
-  m_oDistThresholdFrame = cv::Scalar(2.0f);
-  m_oDistThresholdVariationFrame.create(m_oImgSize, CV_32FC1);
-  m_oDistThresholdVariationFrame = cv::Scalar(FEEDBACK_V_INCR * 10);
-  m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1);
-  m_oMeanMinDistFrame_LT = cv::Scalar(0.0f);
-  m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1);
-  m_oMeanMinDistFrame_ST = cv::Scalar(0.0f);
-  m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels));
-  m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f);
-  m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels));
-  m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f);
-  m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1);
-  m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f);
-  m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1);
-  m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f);
-  m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1);
-  m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f);
-  m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1);
-  m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f);
-  m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1);
-  m_oUnstableRegionMask = cv::Scalar_<uchar>(0);
-  m_oBlinksFrame.create(m_oImgSize, CV_8UC1);
-  m_oBlinksFrame = cv::Scalar_<uchar>(0);
-  m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize_MotionAnalysis, CV_8UC((int)m_nImgChannels));
-  m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0);
-  m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels));
-  m_oLastColorFrame = cv::Scalar_<uchar>::all(0);
-  m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels));
-  m_oLastDescFrame = cv::Scalar_<ushort>::all(0);
-  m_oLastRawFGMask.create(m_oImgSize, CV_8UC1);
-  m_oLastRawFGMask = cv::Scalar_<uchar>(0);
-  m_oLastFGMask.create(m_oImgSize, CV_8UC1);
-  m_oLastFGMask = cv::Scalar_<uchar>(0);
-  m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1);
-  m_oLastFGMask_dilated = cv::Scalar_<uchar>(0);
-  m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1);
-  m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0);
-  m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1);
-  m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0);
-  m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1);
-  m_oFGMask_PreFlood = cv::Scalar_<uchar>(0);
-  m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1);
-  m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0);
-  m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1);
-  m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0);
-  m_oTempGlobalWordWeightDiffFactor.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1);
-  m_oTempGlobalWordWeightDiffFactor = cv::Scalar(-0.1f);
-  m_oMorphExStructElement = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
-  m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount];
-  memset(m_aPxIdxLUT, 0, sizeof(size_t)*m_nTotRelevantPxCount);
-  m_aPxInfoLUT_PAWCS = new PxInfo_PAWCS[m_nTotPxCount];
-  memset(m_aPxInfoLUT_PAWCS, 0, sizeof(PxInfo_PAWCS)*m_nTotPxCount);
-  m_aPxInfoLUT = m_aPxInfoLUT_PAWCS;
-  m_apLocalWordDict = new LocalWordBase*[m_nTotRelevantPxCount*m_nCurrLocalWords];
-  memset(m_apLocalWordDict, 0, sizeof(LocalWordBase*)*m_nTotRelevantPxCount*m_nCurrLocalWords);
-  m_apGlobalWordDict = new GlobalWordBase*[m_nCurrGlobalWords];
-  memset(m_apGlobalWordDict, 0, sizeof(GlobalWordBase*)*m_nCurrGlobalWords);
-  if (m_nImgChannels == 1) {
-    CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1);
-    CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2);
-    m_aLocalWordList_1ch = new LocalWord_1ch[m_nTotRelevantPxCount*m_nCurrLocalWords];
-    memset(m_aLocalWordList_1ch, 0, sizeof(LocalWord_1ch)*m_nTotRelevantPxCount*m_nCurrLocalWords);
-    m_pLocalWordListIter_1ch = m_aLocalWordList_1ch;
-    m_aGlobalWordList_1ch = new GlobalWord_1ch[m_nCurrGlobalWords];
-    m_pGlobalWordListIter_1ch = m_aGlobalWordList_1ch;
-    for (size_t t = 0; t <= UCHAR_MAX; ++t)
-      m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3);
-    for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) {
-      if (m_oROI.data[nPxIter]) {
-        m_aPxIdxLUT[nModelIter] = nPxIter;
-        m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width;
-        m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width;
-        m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter;
-        m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4;
-        m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords];
-        for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter)
-          m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_1ch[nGlobalWordIdxIter]);
-        m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter];
-        const size_t nDescIter = nPxIter * 2;
-        LBSP_::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter)));
-        ++nModelIter;
+      BackgroundSubtractorPAWCS::BackgroundSubtractorPAWCS(float fRelLBSPThreshold
+        , size_t nDescDistThresholdOffset
+        , size_t nMinColorDistThreshold
+        , size_t nMaxNbWords
+        , size_t nSamplesForMovingAvgs)
+        : BackgroundSubtractorLBSP_(fRelLBSPThreshold)
+        , m_nMinColorDistThreshold(nMinColorDistThreshold)
+        , m_nDescDistThresholdOffset(nDescDistThresholdOffset)
+        , m_nMaxLocalWords(nMaxNbWords)
+        , m_nCurrLocalWords(0)
+        , m_nMaxGlobalWords(nMaxNbWords / 2)
+        , m_nCurrGlobalWords(0)
+        , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs)
+        , m_fLastNonFlatRegionRatio(0.0f)
+        , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize)
+        , m_nDownSampledROIPxCount(0)
+        , m_nLocalWordWeightOffset(DEFAULT_LWORD_WEIGHT_OFFSET)
+        , m_apLocalWordDict(nullptr)
+        , m_aLocalWordList_1ch(nullptr)
+        , m_pLocalWordListIter_1ch(nullptr)
+        , m_aLocalWordList_3ch(nullptr)
+        , m_pLocalWordListIter_3ch(nullptr)
+        , m_apGlobalWordDict(nullptr)
+        , m_aGlobalWordList_1ch(nullptr)
+        , m_pGlobalWordListIter_1ch(nullptr)
+        , m_aGlobalWordList_3ch(nullptr)
+        , m_pGlobalWordListIter_3ch(nullptr)
+        , m_aPxInfoLUT_PAWCS(nullptr) {
+        CV_Assert(m_nMaxLocalWords > 0 && m_nMaxGlobalWords > 0);
       }
-    }
-  }
-  else { //m_nImgChannels==3
-    CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3);
-    CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2);
-    m_aLocalWordList_3ch = new LocalWord_3ch[m_nTotRelevantPxCount*m_nCurrLocalWords];
-    memset(m_aLocalWordList_3ch, 0, sizeof(LocalWord_3ch)*m_nTotRelevantPxCount*m_nCurrLocalWords);
-    m_pLocalWordListIter_3ch = m_aLocalWordList_3ch;
-    m_aGlobalWordList_3ch = new GlobalWord_3ch[m_nCurrGlobalWords];
-    m_pGlobalWordListIter_3ch = m_aGlobalWordList_3ch;
-    for (size_t t = 0; t <= UCHAR_MAX; ++t)
-      m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold);
-    for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) {
-      if (m_oROI.data[nPxIter]) {
-        m_aPxIdxLUT[nModelIter] = nPxIter;
-        m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width;
-        m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width;
-        m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter;
-        m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4;
-        m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords];
-        for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter)
-          m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_3ch[nGlobalWordIdxIter]);
-        const size_t nPxRGBIter = nPxIter * 3;
-        const size_t nDescRGBIter = nPxRGBIter * 2;
-        for (size_t c = 0; c < 3; ++c) {
-          m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c];
-          LBSP_::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]);
-        }
-        ++nModelIter;
+
+      BackgroundSubtractorPAWCS::~BackgroundSubtractorPAWCS() {
+        CleanupDictionaries();
       }
-    }
-  }
-  m_bInitialized = true;
-  refreshModel(1, 0);
-}
 
-void BackgroundSubtractorPAWCS::refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate) {
-  // == refresh
-  CV_Assert(m_bInitialized);
-  CV_Assert(fOccDecrFrac >= 0.0f && fOccDecrFrac <= 1.0f);
-  if (m_nImgChannels == 1) {
-    for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-      const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-      if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) {
-        const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
-        const size_t nFloatIter = nPxIter * 4;
-        uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
-        const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
-        const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2;
-        const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET);
-        // == refresh: local decr
-        if (fOccDecrFrac > 0.0f) {
-          for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
-            LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-            if (pCurrLocalWord)
-              pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences);
-          }
+      void BackgroundSubtractorPAWCS::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) {
+        // == init
+        CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0);
+        CV_Assert(oInitImg.isContinuous());
+        CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1);
+        if (oInitImg.type() == CV_8UC3) {
+          std::vector<cv::Mat> voInitImgChannels;
+          cv::split(oInitImg, voInitImgChannels);
+          if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1])))
+            std::cout << std::endl << "\tBackgroundSubtractorPAWCS : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl;
         }
-        const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR;
-        const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2;
-        for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) {
-          // == refresh: local resampling
-          int nSampleImgCoord_Y, nSampleImgCoord_X;
-          getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
-          const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
-          if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) {
-            const uchar nSampleColor = m_oLastColorFrame.data[nSamplePxIdx];
-            const size_t nSampleDescIdx = nSamplePxIdx * 2;
-            const ushort nSampleIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx));
-            bool bFoundUninitd = false;
-            size_t nLocalWordIdx;
-            for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
-              LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-              if (pCurrLocalWord
-                && L1dist(nSampleColor, pCurrLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold
-                && hdist(nSampleIntraDesc, pCurrLocalWord->oFeature.anDesc[0]) <= nCurrDescDistThreshold) {
-                pCurrLocalWord->nOccurrences += nCurrWordOccIncr;
-                pCurrLocalWord->nLastOcc = m_nFrameIndex;
-                break;
-              }
-              else if (!pCurrLocalWord)
-                bFoundUninitd = true;
-            }
-            if (nLocalWordIdx == m_nCurrLocalWords) {
-              nLocalWordIdx = m_nCurrLocalWords - 1;
-              LocalWord_1ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_1ch++ : (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-              pCurrLocalWord->oFeature.anColor[0] = nSampleColor;
-              pCurrLocalWord->oFeature.anDesc[0] = nSampleIntraDesc;
-              pCurrLocalWord->nOccurrences = nBaseOccCount;
-              pCurrLocalWord->nFirstOcc = m_nFrameIndex;
-              pCurrLocalWord->nLastOcc = m_nFrameIndex;
-              m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord;
-            }
-            while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) {
-              std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
-              --nLocalWordIdx;
+        cv::Mat oNewBGROI;
+        if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) {
+          oNewBGROI.create(oInitImg.size(), CV_8UC1);
+          oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX);
+        }
+        else if (oROI.empty())
+          oNewBGROI = m_oROI;
+        else {
+          CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1);
+          CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0);
+          oNewBGROI = oROI.clone();
+          cv::Mat oTempROI;
+          cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP_::PATCH_SIZE / 2);
+          cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI);
+        }
+        const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI);
+        CV_Assert(nOrigROIPxCount > 0);
+        LBSP_::validateROI(oNewBGROI);
+        const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI);
+        CV_Assert(nFinalROIPxCount > 0);
+        CleanupDictionaries();
+        m_oROI = oNewBGROI;
+        m_oImgSize = oInitImg.size();
+        m_nImgType = oInitImg.type();
+        m_nImgChannels = oInitImg.channels();
+        m_nTotPxCount = m_oImgSize.area();
+        m_nTotRelevantPxCount = nFinalROIPxCount;
+        m_nFrameIndex = 0;
+        m_nFramesSinceLastReset = 0;
+        m_nModelResetCooldown = 0;
+        m_bUsingMovingCamera = false;
+        m_oDownSampledFrameSize_MotionAnalysis = cv::Size(m_oImgSize.width / FRAMELEVEL_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_DOWNSAMPLE_RATIO);
+        m_oDownSampledFrameSize_GlobalWordLookup = cv::Size(m_oImgSize.width / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO, m_oImgSize.height / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO);
+        cv::resize(m_oROI, m_oDownSampledROI_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA);
+        m_fLastNonFlatRegionRatio = 0.0f;
+        m_nCurrLocalWords = m_nMaxLocalWords;
+        if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) {
+          const float fRegionSizeScaleFactor = (float)m_nTotPxCount / DEFAULT_FRAME_SIZE.area();
+          const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + fRegionSizeScaleFactor) + m_nDefaultMedianBlurKernelSize, m_nDefaultMedianBlurKernelSize + 4);
+          m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1;
+          m_nCurrGlobalWords = m_nMaxGlobalWords;
+          m_oDownSampledROI_MotionAnalysis |= UCHAR_MAX / 2;
+        }
+        else {
+          const float fRegionSizeScaleFactor = (float)nOrigROIPxCount / DEFAULT_FRAME_SIZE.area();
+          const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + m_nDefaultMedianBlurKernelSize*fRegionSizeScaleFactor * 2) + (m_nDefaultMedianBlurKernelSize - 4), m_nDefaultMedianBlurKernelSize);
+          m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1;
+          m_nCurrGlobalWords = std::min((size_t)std::pow(m_nMaxGlobalWords*fRegionSizeScaleFactor, 2) + 1, m_nMaxGlobalWords);
+        }
+        if (m_nImgChannels == 1) {
+          m_nCurrLocalWords = std::max(m_nCurrLocalWords / 2, (size_t)1);
+          m_nCurrGlobalWords = std::max(m_nCurrGlobalWords / 2, (size_t)1);
+        }
+        m_nDownSampledROIPxCount = (size_t)cv::countNonZero(m_oDownSampledROI_MotionAnalysis);
+        m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET;
+        m_oIllumUpdtRegionMask.create(m_oImgSize, CV_8UC1);
+        m_oIllumUpdtRegionMask = cv::Scalar_<uchar>(0);
+        m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1);
+        m_oUpdateRateFrame = cv::Scalar(FEEDBACK_T_LOWER);
+        m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1);
+        m_oDistThresholdFrame = cv::Scalar(2.0f);
+        m_oDistThresholdVariationFrame.create(m_oImgSize, CV_32FC1);
+        m_oDistThresholdVariationFrame = cv::Scalar(FEEDBACK_V_INCR * 10);
+        m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1);
+        m_oMeanMinDistFrame_LT = cv::Scalar(0.0f);
+        m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1);
+        m_oMeanMinDistFrame_ST = cv::Scalar(0.0f);
+        m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels));
+        m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f);
+        m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels));
+        m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f);
+        m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1);
+        m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f);
+        m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1);
+        m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f);
+        m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1);
+        m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f);
+        m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1);
+        m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f);
+        m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1);
+        m_oUnstableRegionMask = cv::Scalar_<uchar>(0);
+        m_oBlinksFrame.create(m_oImgSize, CV_8UC1);
+        m_oBlinksFrame = cv::Scalar_<uchar>(0);
+        m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize_MotionAnalysis, CV_8UC((int)m_nImgChannels));
+        m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0);
+        m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels));
+        m_oLastColorFrame = cv::Scalar_<uchar>::all(0);
+        m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels));
+        m_oLastDescFrame = cv::Scalar_<ushort>::all(0);
+        m_oLastRawFGMask.create(m_oImgSize, CV_8UC1);
+        m_oLastRawFGMask = cv::Scalar_<uchar>(0);
+        m_oLastFGMask.create(m_oImgSize, CV_8UC1);
+        m_oLastFGMask = cv::Scalar_<uchar>(0);
+        m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1);
+        m_oLastFGMask_dilated = cv::Scalar_<uchar>(0);
+        m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1);
+        m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0);
+        m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1);
+        m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0);
+        m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1);
+        m_oFGMask_PreFlood = cv::Scalar_<uchar>(0);
+        m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1);
+        m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0);
+        m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1);
+        m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0);
+        m_oTempGlobalWordWeightDiffFactor.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1);
+        m_oTempGlobalWordWeightDiffFactor = cv::Scalar(-0.1f);
+        m_oMorphExStructElement = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
+        m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount];
+        memset(m_aPxIdxLUT, 0, sizeof(size_t)*m_nTotRelevantPxCount);
+        m_aPxInfoLUT_PAWCS = new PxInfo_PAWCS[m_nTotPxCount];
+        memset(m_aPxInfoLUT_PAWCS, 0, sizeof(PxInfo_PAWCS)*m_nTotPxCount);
+        m_aPxInfoLUT = m_aPxInfoLUT_PAWCS;
+        m_apLocalWordDict = new LocalWordBase*[m_nTotRelevantPxCount*m_nCurrLocalWords];
+        memset(m_apLocalWordDict, 0, sizeof(LocalWordBase*)*m_nTotRelevantPxCount*m_nCurrLocalWords);
+        m_apGlobalWordDict = new GlobalWordBase*[m_nCurrGlobalWords];
+        memset(m_apGlobalWordDict, 0, sizeof(GlobalWordBase*)*m_nCurrGlobalWords);
+        if (m_nImgChannels == 1) {
+          CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1);
+          CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2);
+          m_aLocalWordList_1ch = new LocalWord_1ch[m_nTotRelevantPxCount*m_nCurrLocalWords];
+          memset(m_aLocalWordList_1ch, 0, sizeof(LocalWord_1ch)*m_nTotRelevantPxCount*m_nCurrLocalWords);
+          m_pLocalWordListIter_1ch = m_aLocalWordList_1ch;
+          m_aGlobalWordList_1ch = new GlobalWord_1ch[m_nCurrGlobalWords];
+          m_pGlobalWordListIter_1ch = m_aGlobalWordList_1ch;
+          for (size_t t = 0; t <= UCHAR_MAX; ++t)
+            m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3);
+          for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) {
+            if (m_oROI.data[nPxIter]) {
+              m_aPxIdxLUT[nModelIter] = nPxIter;
+              m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width;
+              m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width;
+              m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter;
+              m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4;
+              m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords];
+              for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter)
+                m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_1ch[nGlobalWordIdxIter]);
+              m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter];
+              const size_t nDescIter = nPxIter * 2;
+              LBSP_::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter)));
+              ++nModelIter;
             }
           }
         }
-        CV_Assert(m_apLocalWordDict[nLocalDictIdx]);
-        for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
-          // == refresh: local random resampling
-          LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-          if (!pCurrLocalWord) {
-            const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx);
-            const LocalWord_1ch* pRefLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx];
-            const int nRandColorOffset = (rand() % (nCurrColorDistThreshold + 1)) - (int)nCurrColorDistThreshold / 2;
-            pCurrLocalWord = m_pLocalWordListIter_1ch++;
-            pCurrLocalWord->oFeature.anColor[0] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[0] + nRandColorOffset);
-            pCurrLocalWord->oFeature.anDesc[0] = pRefLocalWord->oFeature.anDesc[0];
-            pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1);
-            pCurrLocalWord->nFirstOcc = m_nFrameIndex;
-            pCurrLocalWord->nLastOcc = m_nFrameIndex;
-            m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord;
+        else { //m_nImgChannels==3
+          CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3);
+          CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2);
+          m_aLocalWordList_3ch = new LocalWord_3ch[m_nTotRelevantPxCount*m_nCurrLocalWords];
+          memset(m_aLocalWordList_3ch, 0, sizeof(LocalWord_3ch)*m_nTotRelevantPxCount*m_nCurrLocalWords);
+          m_pLocalWordListIter_3ch = m_aLocalWordList_3ch;
+          m_aGlobalWordList_3ch = new GlobalWord_3ch[m_nCurrGlobalWords];
+          m_pGlobalWordListIter_3ch = m_aGlobalWordList_3ch;
+          for (size_t t = 0; t <= UCHAR_MAX; ++t)
+            m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold);
+          for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) {
+            if (m_oROI.data[nPxIter]) {
+              m_aPxIdxLUT[nModelIter] = nPxIter;
+              m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width;
+              m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width;
+              m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter;
+              m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4;
+              m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords];
+              for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter)
+                m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_3ch[nGlobalWordIdxIter]);
+              const size_t nPxRGBIter = nPxIter * 3;
+              const size_t nDescRGBIter = nPxRGBIter * 2;
+              for (size_t c = 0; c < 3; ++c) {
+                m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c];
+                LBSP_::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]);
+              }
+              ++nModelIter;
+            }
           }
         }
+        m_bInitialized = true;
+        refreshModel(1, 0);
       }
-    }
-    CV_Assert(m_aLocalWordList_1ch == (m_pLocalWordListIter_1ch - m_nTotRelevantPxCount*m_nCurrLocalWords));
-    cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0));
-    size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1);
-    for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) {
-      for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-        // == refresh: global resampling
-        const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-        if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels
-          if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) {
-            const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
-            const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
-            const size_t nFloatIter = nPxIter * 4;
-            uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
-            const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
-            const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2;
-            const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET);
-            CV_Assert(m_apLocalWordDict[nLocalDictIdx]);
-            const LocalWord_1ch* pRefBestLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx];
-            const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-            const uchar nRefBestLocalWordDescBITS = (uchar)popcount(pRefBestLocalWord->oFeature.anDesc[0]);
-            bool bFoundUninitd = false;
-            size_t nGlobalWordIdx;
-            for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
-              GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx];
-              if (pCurrGlobalWord
-                && L1dist(pCurrGlobalWord->oFeature.anColor[0], pRefBestLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold
-                && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR)
-                break;
-              else if (!pCurrGlobalWord)
-                bFoundUninitd = true;
+
+      void BackgroundSubtractorPAWCS::refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate) {
+        // == refresh
+        CV_Assert(m_bInitialized);
+        CV_Assert(fOccDecrFrac >= 0.0f && fOccDecrFrac <= 1.0f);
+        if (m_nImgChannels == 1) {
+          for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+            const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+            if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) {
+              const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
+              const size_t nFloatIter = nPxIter * 4;
+              uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
+              const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
+              const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2;
+              const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET);
+              // == refresh: local decr
+              if (fOccDecrFrac > 0.0f) {
+                for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
+                  LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+                  if (pCurrLocalWord)
+                    pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences);
+                }
+              }
+              const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR;
+              const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2;
+              for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) {
+                // == refresh: local resampling
+                int nSampleImgCoord_Y, nSampleImgCoord_X;
+                getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
+                const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
+                if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) {
+                  const uchar nSampleColor = m_oLastColorFrame.data[nSamplePxIdx];
+                  const size_t nSampleDescIdx = nSamplePxIdx * 2;
+                  const ushort nSampleIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx));
+                  bool bFoundUninitd = false;
+                  size_t nLocalWordIdx;
+                  for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
+                    LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+                    if (pCurrLocalWord
+                      && L1dist(nSampleColor, pCurrLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold
+                      && hdist(nSampleIntraDesc, pCurrLocalWord->oFeature.anDesc[0]) <= nCurrDescDistThreshold) {
+                      pCurrLocalWord->nOccurrences += nCurrWordOccIncr;
+                      pCurrLocalWord->nLastOcc = m_nFrameIndex;
+                      break;
+                    }
+                    else if (!pCurrLocalWord)
+                      bFoundUninitd = true;
+                  }
+                  if (nLocalWordIdx == m_nCurrLocalWords) {
+                    nLocalWordIdx = m_nCurrLocalWords - 1;
+                    LocalWord_1ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_1ch++ : (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+                    pCurrLocalWord->oFeature.anColor[0] = nSampleColor;
+                    pCurrLocalWord->oFeature.anDesc[0] = nSampleIntraDesc;
+                    pCurrLocalWord->nOccurrences = nBaseOccCount;
+                    pCurrLocalWord->nFirstOcc = m_nFrameIndex;
+                    pCurrLocalWord->nLastOcc = m_nFrameIndex;
+                    m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord;
+                  }
+                  while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) {
+                    std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
+                    --nLocalWordIdx;
+                  }
+                }
+              }
+              CV_Assert(m_apLocalWordDict[nLocalDictIdx]);
+              for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
+                // == refresh: local random resampling
+                LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+                if (!pCurrLocalWord) {
+                  const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx);
+                  const LocalWord_1ch* pRefLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx];
+                  const int nRandColorOffset = (rand() % (nCurrColorDistThreshold + 1)) - (int)nCurrColorDistThreshold / 2;
+                  pCurrLocalWord = m_pLocalWordListIter_1ch++;
+                  pCurrLocalWord->oFeature.anColor[0] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[0] + nRandColorOffset);
+                  pCurrLocalWord->oFeature.anDesc[0] = pRefLocalWord->oFeature.anDesc[0];
+                  pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1);
+                  pCurrLocalWord->nFirstOcc = m_nFrameIndex;
+                  pCurrLocalWord->nLastOcc = m_nFrameIndex;
+                  m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord;
+                }
+              }
             }
-            if (nGlobalWordIdx == m_nCurrGlobalWords) {
-              nGlobalWordIdx = m_nCurrGlobalWords - 1;
-              GlobalWord_1ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_1ch++ : (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx];
-              pCurrGlobalWord->oFeature.anColor[0] = pRefBestLocalWord->oFeature.anColor[0];
-              pCurrGlobalWord->oFeature.anDesc[0] = pRefBestLocalWord->oFeature.anDesc[0];
-              pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS;
+          }
+          CV_Assert(m_aLocalWordList_1ch == (m_pLocalWordListIter_1ch - m_nTotRelevantPxCount*m_nCurrLocalWords));
+          cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0));
+          size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1);
+          for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) {
+            for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+              // == refresh: global resampling
+              const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+              if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels
+                if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) {
+                  const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
+                  const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
+                  const size_t nFloatIter = nPxIter * 4;
+                  uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
+                  const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
+                  const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2;
+                  const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET);
+                  CV_Assert(m_apLocalWordDict[nLocalDictIdx]);
+                  const LocalWord_1ch* pRefBestLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx];
+                  const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+                  const uchar nRefBestLocalWordDescBITS = (uchar)popcount(pRefBestLocalWord->oFeature.anDesc[0]);
+                  bool bFoundUninitd = false;
+                  size_t nGlobalWordIdx;
+                  for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
+                    GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx];
+                    if (pCurrGlobalWord
+                      && L1dist(pCurrGlobalWord->oFeature.anColor[0], pRefBestLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold
+                      && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR)
+                      break;
+                    else if (!pCurrGlobalWord)
+                      bFoundUninitd = true;
+                  }
+                  if (nGlobalWordIdx == m_nCurrGlobalWords) {
+                    nGlobalWordIdx = m_nCurrGlobalWords - 1;
+                    GlobalWord_1ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_1ch++ : (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx];
+                    pCurrGlobalWord->oFeature.anColor[0] = pRefBestLocalWord->oFeature.anColor[0];
+                    pCurrGlobalWord->oFeature.anDesc[0] = pRefBestLocalWord->oFeature.anDesc[0];
+                    pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS;
+                    pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1);
+                    pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
+                    pCurrGlobalWord->fLatestWeight = 0.0f;
+                    m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord;
+                  }
+                  float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+                  if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) {
+                    m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight;
+                    fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight;
+                  }
+                  oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX;
+                  while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) {
+                    std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]);
+                    --nGlobalWordIdx;
+                  }
+                }
+              }
+            }
+            nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1);
+          }
+          for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
+            GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx];
+            if (!pCurrGlobalWord) {
+              pCurrGlobalWord = m_pGlobalWordListIter_1ch++;
+              pCurrGlobalWord->oFeature.anColor[0] = 0;
+              pCurrGlobalWord->oFeature.anDesc[0] = 0;
+              pCurrGlobalWord->nDescBITS = 0;
               pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1);
               pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
               pCurrGlobalWord->fLatestWeight = 0.0f;
               m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord;
             }
-            float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-            if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) {
-              m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight;
-              fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight;
-            }
-            oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX;
-            while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) {
-              std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]);
-              --nGlobalWordIdx;
-            }
           }
+          CV_Assert((size_t)(m_pGlobalWordListIter_1ch - m_aGlobalWordList_1ch) == m_nCurrGlobalWords && m_aGlobalWordList_1ch == (m_pGlobalWordListIter_1ch - m_nCurrGlobalWords));
         }
-      }
-      nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1);
-    }
-    for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
-      GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx];
-      if (!pCurrGlobalWord) {
-        pCurrGlobalWord = m_pGlobalWordListIter_1ch++;
-        pCurrGlobalWord->oFeature.anColor[0] = 0;
-        pCurrGlobalWord->oFeature.anDesc[0] = 0;
-        pCurrGlobalWord->nDescBITS = 0;
-        pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1);
-        pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
-        pCurrGlobalWord->fLatestWeight = 0.0f;
-        m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord;
-      }
-    }
-    CV_Assert((size_t)(m_pGlobalWordListIter_1ch - m_aGlobalWordList_1ch) == m_nCurrGlobalWords && m_aGlobalWordList_1ch == (m_pGlobalWordListIter_1ch - m_nCurrGlobalWords));
-  }
-  else { //m_nImgChannels==3
-    for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-      const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-      if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) {
-        const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
-        const size_t nFloatIter = nPxIter * 4;
-        uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
-        const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
-        const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3;
-        const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3;
-        // == refresh: local decr
-        if (fOccDecrFrac > 0.0f) {
-          for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
-            LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-            if (pCurrLocalWord)
-              pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences);
+        else { //m_nImgChannels==3
+          for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+            const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+            if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) {
+              const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
+              const size_t nFloatIter = nPxIter * 4;
+              uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
+              const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
+              const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3;
+              const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3;
+              // == refresh: local decr
+              if (fOccDecrFrac > 0.0f) {
+                for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
+                  LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+                  if (pCurrLocalWord)
+                    pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences);
+                }
+              }
+              const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR;
+              const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2;
+              for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) {
+                // == refresh: local resampling
+                int nSampleImgCoord_Y, nSampleImgCoord_X;
+                getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
+                const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
+                if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) {
+                  const size_t nSamplePxRGBIdx = nSamplePxIdx * 3;
+                  const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2;
+                  const uchar* const anSampleColor = m_oLastColorFrame.data + nSamplePxRGBIdx;
+                  const ushort* const anSampleIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx));
+                  bool bFoundUninitd = false;
+                  size_t nLocalWordIdx;
+                  for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
+                    LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+                    if (pCurrLocalWord
+                      && cmixdist<3>(anSampleColor, pCurrLocalWord->oFeature.anColor) <= nCurrTotColorDistThreshold
+                      && hdist<3>(anSampleIntraDesc, pCurrLocalWord->oFeature.anDesc) <= nCurrTotDescDistThreshold) {
+                      pCurrLocalWord->nOccurrences += nCurrWordOccIncr;
+                      pCurrLocalWord->nLastOcc = m_nFrameIndex;
+                      break;
+                    }
+                    else if (!pCurrLocalWord)
+                      bFoundUninitd = true;
+                  }
+                  if (nLocalWordIdx == m_nCurrLocalWords) {
+                    nLocalWordIdx = m_nCurrLocalWords - 1;
+                    LocalWord_3ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_3ch++ : (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+                    for (size_t c = 0; c < 3; ++c) {
+                      pCurrLocalWord->oFeature.anColor[c] = anSampleColor[c];
+                      pCurrLocalWord->oFeature.anDesc[c] = anSampleIntraDesc[c];
+                    }
+                    pCurrLocalWord->nOccurrences = nBaseOccCount;
+                    pCurrLocalWord->nFirstOcc = m_nFrameIndex;
+                    pCurrLocalWord->nLastOcc = m_nFrameIndex;
+                    m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord;
+                  }
+                  while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) {
+                    std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
+                    --nLocalWordIdx;
+                  }
+                }
+              }
+              CV_Assert(m_apLocalWordDict[nLocalDictIdx]);
+              for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
+                // == refresh: local random resampling
+                LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+                if (!pCurrLocalWord) {
+                  const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx);
+                  const LocalWord_3ch* pRefLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx];
+                  const int nRandColorOffset = (rand() % (nCurrTotColorDistThreshold / 3 + 1)) - (int)(nCurrTotColorDistThreshold / 6);
+                  pCurrLocalWord = m_pLocalWordListIter_3ch++;
+                  for (size_t c = 0; c < 3; ++c) {
+                    pCurrLocalWord->oFeature.anColor[c] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[c] + nRandColorOffset);
+                    pCurrLocalWord->oFeature.anDesc[c] = pRefLocalWord->oFeature.anDesc[c];
+                  }
+                  pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1);
+                  pCurrLocalWord->nFirstOcc = m_nFrameIndex;
+                  pCurrLocalWord->nLastOcc = m_nFrameIndex;
+                  m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord;
+                }
+              }
+            }
           }
-        }
-        const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR;
-        const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2;
-        for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) {
-          // == refresh: local resampling
-          int nSampleImgCoord_Y, nSampleImgCoord_X;
-          getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
-          const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
-          if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) {
-            const size_t nSamplePxRGBIdx = nSamplePxIdx * 3;
-            const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2;
-            const uchar* const anSampleColor = m_oLastColorFrame.data + nSamplePxRGBIdx;
-            const ushort* const anSampleIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx));
-            bool bFoundUninitd = false;
-            size_t nLocalWordIdx;
-            for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
-              LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-              if (pCurrLocalWord
-                && cmixdist<3>(anSampleColor, pCurrLocalWord->oFeature.anColor) <= nCurrTotColorDistThreshold
-                && hdist<3>(anSampleIntraDesc, pCurrLocalWord->oFeature.anDesc) <= nCurrTotDescDistThreshold) {
-                pCurrLocalWord->nOccurrences += nCurrWordOccIncr;
-                pCurrLocalWord->nLastOcc = m_nFrameIndex;
-                break;
+          CV_Assert(m_aLocalWordList_3ch == (m_pLocalWordListIter_3ch - m_nTotRelevantPxCount*m_nCurrLocalWords));
+          cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0));
+          size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1);
+          for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) {
+            for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+              // == refresh: global resampling
+              const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+              if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels
+                if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) {
+                  const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
+                  const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
+                  const size_t nFloatIter = nPxIter * 4;
+                  uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
+                  const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
+                  const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3;
+                  const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3;
+                  CV_Assert(m_apLocalWordDict[nLocalDictIdx]);
+                  const LocalWord_3ch* pRefBestLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx];
+                  const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+                  const uchar nRefBestLocalWordDescBITS = (uchar)popcount<3>(pRefBestLocalWord->oFeature.anDesc);
+                  bool bFoundUninitd = false;
+                  size_t nGlobalWordIdx;
+                  for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
+                    GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx];
+                    if (pCurrGlobalWord
+                      && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR
+                      && cmixdist<3>(pRefBestLocalWord->oFeature.anColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold)
+                      break;
+                    else if (!pCurrGlobalWord)
+                      bFoundUninitd = true;
+                  }
+                  if (nGlobalWordIdx == m_nCurrGlobalWords) {
+                    nGlobalWordIdx = m_nCurrGlobalWords - 1;
+                    GlobalWord_3ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_3ch++ : (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx];
+                    for (size_t c = 0; c < 3; ++c) {
+                      pCurrGlobalWord->oFeature.anColor[c] = pRefBestLocalWord->oFeature.anColor[c];
+                      pCurrGlobalWord->oFeature.anDesc[c] = pRefBestLocalWord->oFeature.anDesc[c];
+                    }
+                    pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS;
+                    pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1);
+                    pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
+                    pCurrGlobalWord->fLatestWeight = 0.0f;
+                    m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord;
+                  }
+                  float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+                  if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) {
+                    m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight;
+                    fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight;
+                  }
+                  oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX;
+                  while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) {
+                    std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]);
+                    --nGlobalWordIdx;
+                  }
+                }
               }
-              else if (!pCurrLocalWord)
-                bFoundUninitd = true;
             }
-            if (nLocalWordIdx == m_nCurrLocalWords) {
-              nLocalWordIdx = m_nCurrLocalWords - 1;
-              LocalWord_3ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_3ch++ : (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+            nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1);
+          }
+          for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
+            GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx];
+            if (!pCurrGlobalWord) {
+              pCurrGlobalWord = m_pGlobalWordListIter_3ch++;
               for (size_t c = 0; c < 3; ++c) {
-                pCurrLocalWord->oFeature.anColor[c] = anSampleColor[c];
-                pCurrLocalWord->oFeature.anDesc[c] = anSampleIntraDesc[c];
+                pCurrGlobalWord->oFeature.anColor[c] = 0;
+                pCurrGlobalWord->oFeature.anDesc[c] = 0;
               }
-              pCurrLocalWord->nOccurrences = nBaseOccCount;
-              pCurrLocalWord->nFirstOcc = m_nFrameIndex;
-              pCurrLocalWord->nLastOcc = m_nFrameIndex;
-              m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord;
-            }
-            while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) {
-              std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
-              --nLocalWordIdx;
+              pCurrGlobalWord->nDescBITS = 0;
+              pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1);
+              pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
+              pCurrGlobalWord->fLatestWeight = 0.0f;
+              m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord;
             }
           }
+          CV_Assert((size_t)(m_pGlobalWordListIter_3ch - m_aGlobalWordList_3ch) == m_nCurrGlobalWords && m_aGlobalWordList_3ch == (m_pGlobalWordListIter_3ch - m_nCurrGlobalWords));
         }
-        CV_Assert(m_apLocalWordDict[nLocalDictIdx]);
-        for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
-          // == refresh: local random resampling
-          LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-          if (!pCurrLocalWord) {
-            const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx);
-            const LocalWord_3ch* pRefLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx];
-            const int nRandColorOffset = (rand() % (nCurrTotColorDistThreshold / 3 + 1)) - (int)(nCurrTotColorDistThreshold / 6);
-            pCurrLocalWord = m_pLocalWordListIter_3ch++;
-            for (size_t c = 0; c < 3; ++c) {
-              pCurrLocalWord->oFeature.anColor[c] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[c] + nRandColorOffset);
-              pCurrLocalWord->oFeature.anDesc[c] = pRefLocalWord->oFeature.anDesc[c];
-            }
-            pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1);
-            pCurrLocalWord->nFirstOcc = m_nFrameIndex;
-            pCurrLocalWord->nLastOcc = m_nFrameIndex;
-            m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord;
+        for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+          // == refresh: per-px global word sort
+          const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+          const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
+          float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+          for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
+            const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+            if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight)
+              std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]);
+            else
+              fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight;
           }
         }
       }
-    }
-    CV_Assert(m_aLocalWordList_3ch == (m_pLocalWordListIter_3ch - m_nTotRelevantPxCount*m_nCurrLocalWords));
-    cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0));
-    size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1);
-    for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) {
-      for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-        // == refresh: global resampling
-        const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-        if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels
-          if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) {
+
+      void BackgroundSubtractorPAWCS::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) {
+        // == process
+        CV_Assert(m_bInitialized);
+        cv::Mat oInputImg = _image.getMat();
+        CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize);
+        CV_Assert(oInputImg.isContinuous());
+        _fgmask.create(m_oImgSize, CV_8UC1);
+        cv::Mat oCurrFGMask = _fgmask.getMat();
+        memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows);
+        const bool bBootstrapping = ++m_nFrameIndex <= DEFAULT_BOOTSTRAP_WIN_SIZE;
+        const size_t nCurrSamplesForMovingAvg_LT = bBootstrapping ? m_nSamplesForMovingAvgs / 2 : m_nSamplesForMovingAvgs;
+        const size_t nCurrSamplesForMovingAvg_ST = nCurrSamplesForMovingAvg_LT / 4;
+        const float fRollAvgFactor_LT = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_LT);
+        const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_ST);
+        const size_t nCurrGlobalWordUpdateRate = bBootstrapping ? DEFAULT_RESAMPLING_RATE / 2 : DEFAULT_RESAMPLING_RATE;
+        size_t nFlatRegionCount = 0;
+        if (m_nImgChannels == 1) {
+          for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+            const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+            const size_t nDescIter = nPxIter * 2;
+            const size_t nFloatIter = nPxIter * 4;
             const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
             const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
+            const uchar nCurrColor = oInputImg.data[nPxIter];
+            uchar& nLastColor = m_oLastColorFrame.data[nPxIter];
+            ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter));
+            size_t nMinColorDist = s_nColorMaxDataRange_1ch;
+            size_t nMinDescDist = s_nDescMaxDataRange_1ch;
+            float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter);
+            float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter);
+            float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter);
+            float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter);
+            float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
+            float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter);
+            float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter);
+            float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter);
+            float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter);
+            const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset);
+            const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2);
+            uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
+            uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter];
+            uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter];
+            const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX;
+            const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X;
+            const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y;
+            ushort nCurrInterDesc, nCurrIntraDesc;
+            LBSP_::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc);
+            const uchar nCurrIntraDescBITS = (uchar)popcount(nCurrIntraDesc);
+            const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT;
+            if (bCurrRegionIsFlat)
+              ++nFlatRegionCount;
+            const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping);
+            const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate);
+            const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2;
+            const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET);
+            size_t nLocalWordIdx = 0;
+            float fPotentialLocalWordsWeightSum = 0.0f;
+            float fLastLocalWordWeight = FLT_MAX;
+            while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) {
+              LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+              const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+              {
+                const size_t nColorDist = L1dist(nCurrColor, pCurrLocalWord->oFeature.anColor[0]);
+                const size_t nIntraDescDist = hdist(nCurrIntraDesc, pCurrLocalWord->oFeature.anDesc[0]);
+                LBSP_::computeGrayscaleDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor[0], nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]], nCurrInterDesc);
+                const size_t nInterDescDist = hdist(nCurrInterDesc, pCurrLocalWord->oFeature.anDesc[0]);
+                const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2;
+                if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder)
+                  && nColorDist <= nCurrColorDistThreshold
+                  && nColorDist >= nCurrColorDistThreshold / 2
+                  && nIntraDescDist <= nCurrDescDistThreshold / 2
+                  && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) {
+                  // == illum updt
+                  pCurrLocalWord->oFeature.anColor[0] = nCurrColor;
+                  pCurrLocalWord->oFeature.anDesc[0] = nCurrIntraDesc;
+                  m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1];
+                  m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1];
+                  m_oIllumUpdtRegionMask.data[nPxIter] = 2;
+                }
+                if (nDescDist <= nCurrDescDistThreshold && nColorDist <= nCurrColorDistThreshold) {
+                  fPotentialLocalWordsWeightSum += fCurrLocalWordWeight;
+                  pCurrLocalWord->nLastOcc = m_nFrameIndex;
+                  if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
+                    pCurrLocalWord->nOccurrences += nCurrWordOccIncr;
+                  nMinColorDist = std::min(nMinColorDist, nColorDist);
+                  nMinDescDist = std::min(nMinDescDist, nDescDist);
+                }
+              }
+              if (fCurrLocalWordWeight > fLastLocalWordWeight) {
+                std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
+              }
+              else
+                fLastLocalWordWeight = fCurrLocalWordWeight;
+              ++nLocalWordIdx;
+            }
+            while (nLocalWordIdx < m_nCurrLocalWords) {
+              const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset);
+              if (fCurrLocalWordWeight > fLastLocalWordWeight) {
+                std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
+              }
+              else
+                fLastLocalWordWeight = fCurrLocalWordWeight;
+              ++nLocalWordIdx;
+            }
+            if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) {
+              // == background
+              const float fNormalizedMinDist = std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch);
+              fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
+              fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
+              fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT);
+              fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST);
+              if ((rand() % nCurrLocalWordUpdateRate) == 0) {
+                size_t nGlobalWordLUTIdx;
+                GlobalWord_1ch* pCurrGlobalWord = nullptr;
+                for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
+                  pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx];
+                  if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold
+                    && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR)
+                    break;
+                }
+                if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) {
+                  if (nGlobalWordLUTIdx == m_nCurrGlobalWords) {
+                    pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1];
+                    pCurrGlobalWord->oFeature.anColor[0] = nCurrColor;
+                    pCurrGlobalWord->oFeature.anDesc[0] = nCurrIntraDesc;
+                    pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS;
+                    pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
+                    pCurrGlobalWord->fLatestWeight = 0.0f;
+                  }
+                  float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+                  if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) {
+                    pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum;
+                    fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum;
+                  }
+                }
+              }
+            }
+            else {
+              // == foreground
+              const float fNormalizedMinDist = std::max(std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold);
+              fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
+              fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
+              fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT;
+              fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST;
+              if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) {
+                size_t nGlobalWordLUTIdx;
+                GlobalWord_1ch* pCurrGlobalWord;
+                for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
+                  pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx];
+                  if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold
+                    && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR)
+                    break;
+                }
+                if (nGlobalWordLUTIdx == m_nCurrGlobalWords)
+                  nCurrRegionSegmVal = UCHAR_MAX;
+                else {
+                  const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+                  if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold)
+                    nCurrRegionSegmVal = UCHAR_MAX;
+                }
+              }
+              else
+                nCurrRegionSegmVal = UCHAR_MAX;
+              if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) {
+                const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1;
+                LocalWord_1ch* pNewLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx];
+                pNewLocalWord->oFeature.anColor[0] = nCurrColor;
+                pNewLocalWord->oFeature.anDesc[0] = nCurrIntraDesc;
+                pNewLocalWord->nOccurrences = nCurrWordOccIncr;
+                pNewLocalWord->nFirstOcc = m_nFrameIndex;
+                pNewLocalWord->nLastOcc = m_nFrameIndex;
+              }
+            }
+            // == neighb updt
+            if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) {
+              //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) {
+              int nSampleImgCoord_Y, nSampleImgCoord_X;
+              if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera)
+                getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
+              else
+                getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
+              const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
+              if (m_oROI.data[nSamplePxIdx]) {
+                const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords;
+                size_t nNeighborLocalWordIdx = 0;
+                float fNeighborPotentialLocalWordsWeightSum = 0.0f;
+                while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) {
+                  LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx];
+                  const size_t nNeighborColorDist = L1dist(nCurrColor, pNeighborLocalWord->oFeature.anColor[0]);
+                  const size_t nNeighborIntraDescDist = hdist(nCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc[0]);
+                  const bool bNeighborRegionIsFlat = popcount(pNeighborLocalWord->oFeature.anDesc[0]) < FLAT_REGION_BIT_COUNT;
+                  const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr;
+                  if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborIntraDescDist <= nCurrDescDistThreshold) {
+                    const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+                    fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
+                    pNeighborLocalWord->nLastOcc = m_nFrameIndex;
+                    if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
+                      pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
+                  }
+                  else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) {
+                    const size_t nSampleDescIdx = nSamplePxIdx * 2;
+                    ushort& nNeighborLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx));
+                    const size_t nNeighborLastIntraDescDist = hdist(nCurrIntraDesc, nNeighborLastIntraDesc);
+                    if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborLastIntraDescDist <= nCurrDescDistThreshold / 2) {
+                      const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+                      fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
+                      pNeighborLocalWord->nLastOcc = m_nFrameIndex;
+                      if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
+                        pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
+                      pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc;
+                    }
+                  }
+                  ++nNeighborLocalWordIdx;
+                }
+                if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) {
+                  nNeighborLocalWordIdx = m_nCurrLocalWords - 1;
+                  LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx];
+                  pNeighborLocalWord->oFeature.anColor[0] = nCurrColor;
+                  pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc;
+                  pNeighborLocalWord->nOccurrences = nCurrWordOccIncr;
+                  pNeighborLocalWord->nFirstOcc = m_nFrameIndex;
+                  pNeighborLocalWord->nLastOcc = m_nFrameIndex;
+                }
+              }
+            }
+            if (nCurrRegionIllumUpdtVal)
+              nCurrRegionIllumUpdtVal -= 1;
+            // == feedback adj
+            bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN;
+            if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal))
+              fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER);
+            else
+              fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER);
+            if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter])
+              (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR;
+            else
+              fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR);
+            if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2))
+              fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR);
+            else
+              fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f);
+            nLastIntraDesc = nCurrIntraDesc;
+            nLastColor = nCurrColor;
+          }
+        }
+        else { //m_nImgChannels==3
+          for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+            const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+            const size_t nPxRGBIter = nPxIter * 3;
+            const size_t nDescRGBIter = nPxRGBIter * 2;
             const size_t nFloatIter = nPxIter * 4;
+            const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
+            const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
+            const uchar* const anCurrColor = oInputImg.data + nPxRGBIter;
+            uchar* anLastColor = m_oLastColorFrame.data + nPxRGBIter;
+            ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescRGBIter));
+            size_t nMinTotColorDist = s_nColorMaxDataRange_3ch;
+            size_t nMinTotDescDist = s_nDescMaxDataRange_3ch;
+            float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter);
+            float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter);
+            float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter);
+            float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter);
+            float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
+            float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter);
+            float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter);
+            float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter);
+            float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter);
+            const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset);
+            const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2);
             uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
-            const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
+            uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter];
+            uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter];
+            const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX;
+            const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X;
+            const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y;
+            ushort anCurrInterDesc[3], anCurrIntraDesc[3];
+            const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] };
+            LBSP_::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc);
+            const uchar nCurrIntraDescBITS = (uchar)popcount<3>(anCurrIntraDesc);
+            const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT * 2;
+            if (bCurrRegionIsFlat)
+              ++nFlatRegionCount;
+            const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping);
+            const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate);
             const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3;
             const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3;
-            CV_Assert(m_apLocalWordDict[nLocalDictIdx]);
-            const LocalWord_3ch* pRefBestLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx];
-            const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-            const uchar nRefBestLocalWordDescBITS = (uchar)popcount<3>(pRefBestLocalWord->oFeature.anDesc);
-            bool bFoundUninitd = false;
-            size_t nGlobalWordIdx;
-            for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
-              GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx];
-              if (pCurrGlobalWord
-                && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR
-                && cmixdist<3>(pRefBestLocalWord->oFeature.anColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold)
-                break;
-              else if (!pCurrGlobalWord)
-                bFoundUninitd = true;
+            size_t nLocalWordIdx = 0;
+            float fPotentialLocalWordsWeightSum = 0.0f;
+            float fLastLocalWordWeight = FLT_MAX;
+            while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) {
+              LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+              const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+              {
+                const size_t nTotColorL1Dist = L1dist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor);
+                const size_t nColorDistortion = cdist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor);
+                const size_t nTotColorMixDist = cmixdist(nTotColorL1Dist, nColorDistortion);
+                const size_t nTotIntraDescDist = hdist<3>(anCurrIntraDesc, pCurrLocalWord->oFeature.anDesc);
+                const size_t anCurrInterLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[1]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[2]] };
+                LBSP_::computeRGBDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrInterLBSPThresholds, anCurrInterDesc);
+                const size_t nTotInterDescDist = hdist<3>(anCurrInterDesc, pCurrLocalWord->oFeature.anDesc);
+                const size_t nTotDescDist = (nTotIntraDescDist + nTotInterDescDist) / 2;
+                if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder)
+                  && nTotColorMixDist <= nCurrTotColorDistThreshold
+                  && nTotColorL1Dist >= nCurrTotColorDistThreshold / 2
+                  && nTotIntraDescDist <= nCurrTotDescDistThreshold / 2
+                  && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) {
+                  // == illum updt
+                  for (size_t c = 0; c < 3; ++c) {
+                    pCurrLocalWord->oFeature.anColor[c] = anCurrColor[c];
+                    pCurrLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
+                  }
+                  m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1];
+                  m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1];
+                  m_oIllumUpdtRegionMask.data[nPxIter] = 2;
+                }
+                if (nTotDescDist <= nCurrTotDescDistThreshold && nTotColorMixDist <= nCurrTotColorDistThreshold) {
+                  fPotentialLocalWordsWeightSum += fCurrLocalWordWeight;
+                  pCurrLocalWord->nLastOcc = m_nFrameIndex;
+                  if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
+                    pCurrLocalWord->nOccurrences += nCurrWordOccIncr;
+                  nMinTotColorDist = std::min(nMinTotColorDist, nTotColorMixDist);
+                  nMinTotDescDist = std::min(nMinTotDescDist, nTotDescDist);
+                }
+              }
+              if (fCurrLocalWordWeight > fLastLocalWordWeight) {
+                std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
+              }
+              else
+                fLastLocalWordWeight = fCurrLocalWordWeight;
+              ++nLocalWordIdx;
             }
-            if (nGlobalWordIdx == m_nCurrGlobalWords) {
-              nGlobalWordIdx = m_nCurrGlobalWords - 1;
-              GlobalWord_3ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_3ch++ : (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx];
-              for (size_t c = 0; c < 3; ++c) {
-                pCurrGlobalWord->oFeature.anColor[c] = pRefBestLocalWord->oFeature.anColor[c];
-                pCurrGlobalWord->oFeature.anDesc[c] = pRefBestLocalWord->oFeature.anDesc[c];
+            while (nLocalWordIdx < m_nCurrLocalWords) {
+              const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset);
+              if (fCurrLocalWordWeight > fLastLocalWordWeight) {
+                std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
+              }
+              else
+                fLastLocalWordWeight = fCurrLocalWordWeight;
+              ++nLocalWordIdx;
+            }
+            if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) {
+              // == background
+              const float fNormalizedMinDist = std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch);
+              fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
+              fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
+              fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT);
+              fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST);
+              if ((rand() % nCurrLocalWordUpdateRate) == 0) {
+                size_t nGlobalWordLUTIdx;
+                GlobalWord_3ch* pCurrGlobalWord = nullptr;
+                for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
+                  pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx];
+                  if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR
+                    && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold)
+                    break;
+                }
+                if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) {
+                  if (nGlobalWordLUTIdx == m_nCurrGlobalWords) {
+                    pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1];
+                    for (size_t c = 0; c < 3; ++c) {
+                      pCurrGlobalWord->oFeature.anColor[c] = anCurrColor[c];
+                      pCurrGlobalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
+                    }
+                    pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS;
+                    pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
+                    pCurrGlobalWord->fLatestWeight = 0.0f;
+                  }
+                  float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+                  if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) {
+                    pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum;
+                    fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum;
+                  }
+                }
               }
-              pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS;
-              pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1);
-              pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
-              pCurrGlobalWord->fLatestWeight = 0.0f;
-              m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord;
             }
-            float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-            if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) {
-              m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight;
-              fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight;
+            else {
+              // == foreground
+              const float fNormalizedMinDist = std::max(std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold);
+              fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
+              fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
+              fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT;
+              fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST;
+              if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) {
+                size_t nGlobalWordLUTIdx;
+                GlobalWord_3ch* pCurrGlobalWord;
+                for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
+                  pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx];
+                  if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR
+                    && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold)
+                    break;
+                }
+                if (nGlobalWordLUTIdx == m_nCurrGlobalWords)
+                  nCurrRegionSegmVal = UCHAR_MAX;
+                else {
+                  const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+                  if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold)
+                    nCurrRegionSegmVal = UCHAR_MAX;
+                }
+              }
+              else
+                nCurrRegionSegmVal = UCHAR_MAX;
+              if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) {
+                const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1;
+                LocalWord_3ch* pNewLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx];
+                for (size_t c = 0; c < 3; ++c) {
+                  pNewLocalWord->oFeature.anColor[c] = anCurrColor[c];
+                  pNewLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
+                }
+                pNewLocalWord->nOccurrences = nCurrWordOccIncr;
+                pNewLocalWord->nFirstOcc = m_nFrameIndex;
+                pNewLocalWord->nLastOcc = m_nFrameIndex;
+              }
             }
-            oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX;
-            while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) {
-              std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]);
-              --nGlobalWordIdx;
+            // == neighb updt
+            if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) {
+              //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) {
+              int nSampleImgCoord_Y, nSampleImgCoord_X;
+              if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera)
+                getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
+              else
+                getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
+              const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
+              if (m_oROI.data[nSamplePxIdx]) {
+                const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords;
+                size_t nNeighborLocalWordIdx = 0;
+                float fNeighborPotentialLocalWordsWeightSum = 0.0f;
+                while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) {
+                  LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx];
+                  const size_t nNeighborTotColorL1Dist = L1dist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor);
+                  const size_t nNeighborColorDistortion = cdist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor);
+                  const size_t nNeighborTotColorMixDist = cmixdist(nNeighborTotColorL1Dist, nNeighborColorDistortion);
+                  const size_t nNeighborTotIntraDescDist = hdist<3>(anCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc);
+                  const bool bNeighborRegionIsFlat = popcount<3>(pNeighborLocalWord->oFeature.anDesc) < FLAT_REGION_BIT_COUNT * 2;
+                  const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr;
+                  if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold) {
+                    const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+                    fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
+                    pNeighborLocalWord->nLastOcc = m_nFrameIndex;
+                    if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
+                      pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
+                  }
+                  else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) {
+                    const size_t nSamplePxRGBIdx = nSamplePxIdx * 3;
+                    const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2;
+                    ushort* anNeighborLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx));
+                    const size_t nNeighborTotLastIntraDescDist = hdist<3>(anCurrIntraDesc, anNeighborLastIntraDesc);
+                    if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotLastIntraDescDist <= nCurrTotDescDistThreshold / 2) {
+                      const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+                      fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
+                      pNeighborLocalWord->nLastOcc = m_nFrameIndex;
+                      if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
+                        pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
+                      for (size_t c = 0; c < 3; ++c)
+                        pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
+                    }
+                    else {
+                      const bool bNeighborLastRegionIsFlat = popcount<3>(anNeighborLastIntraDesc) < FLAT_REGION_BIT_COUNT * 2;
+                      if (bNeighborLastRegionIsFlat && bCurrRegionIsFlat &&
+                        nNeighborTotLastIntraDescDist + nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold &&
+                        nNeighborColorDistortion <= nCurrTotColorDistThreshold / 4) {
+                        const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+                        fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
+                        pNeighborLocalWord->nLastOcc = m_nFrameIndex;
+                        if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
+                          pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
+                        for (size_t c = 0; c < 3; ++c)
+                          pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c];
+                      }
+                    }
+                  }
+                  ++nNeighborLocalWordIdx;
+                }
+                if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) {
+                  nNeighborLocalWordIdx = m_nCurrLocalWords - 1;
+                  LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx];
+                  for (size_t c = 0; c < 3; ++c) {
+                    pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c];
+                    pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
+                  }
+                  pNeighborLocalWord->nOccurrences = nCurrWordOccIncr;
+                  pNeighborLocalWord->nFirstOcc = m_nFrameIndex;
+                  pNeighborLocalWord->nLastOcc = m_nFrameIndex;
+                }
+              }
+            }
+            if (nCurrRegionIllumUpdtVal)
+              nCurrRegionIllumUpdtVal -= 1;
+            // == feedback adj
+            bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN;
+            if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal))
+              fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER);
+            else
+              fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER);
+            if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter])
+              (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR;
+            else
+              fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR);
+            if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2))
+              fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR);
+            else
+              fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f);
+            for (size_t c = 0; c < 3; ++c) {
+              anLastIntraDesc[c] = anCurrIntraDesc[c];
+              anLastColor[c] = anCurrColor[c];
             }
           }
         }
-      }
-      nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1);
-    }
-    for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
-      GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx];
-      if (!pCurrGlobalWord) {
-        pCurrGlobalWord = m_pGlobalWordListIter_3ch++;
-        for (size_t c = 0; c < 3; ++c) {
-          pCurrGlobalWord->oFeature.anColor[c] = 0;
-          pCurrGlobalWord->oFeature.anDesc[c] = 0;
-        }
-        pCurrGlobalWord->nDescBITS = 0;
-        pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1);
-        pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
-        pCurrGlobalWord->fLatestWeight = 0.0f;
-        m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord;
-      }
-    }
-    CV_Assert((size_t)(m_pGlobalWordListIter_3ch - m_aGlobalWordList_3ch) == m_nCurrGlobalWords && m_aGlobalWordList_3ch == (m_pGlobalWordListIter_3ch - m_nCurrGlobalWords));
-  }
-  for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-    // == refresh: per-px global word sort
-    const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-    const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
-    float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-    for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
-      const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-      if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight)
-        std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]);
-      else
-        fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight;
-    }
-  }
-}
-
-void BackgroundSubtractorPAWCS::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) {
-  // == process
-  CV_Assert(m_bInitialized);
-  cv::Mat oInputImg = _image.getMat();
-  CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize);
-  CV_Assert(oInputImg.isContinuous());
-  _fgmask.create(m_oImgSize, CV_8UC1);
-  cv::Mat oCurrFGMask = _fgmask.getMat();
-  memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows);
-  const bool bBootstrapping = ++m_nFrameIndex <= DEFAULT_BOOTSTRAP_WIN_SIZE;
-  const size_t nCurrSamplesForMovingAvg_LT = bBootstrapping ? m_nSamplesForMovingAvgs / 2 : m_nSamplesForMovingAvgs;
-  const size_t nCurrSamplesForMovingAvg_ST = nCurrSamplesForMovingAvg_LT / 4;
-  const float fRollAvgFactor_LT = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_LT);
-  const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_ST);
-  const size_t nCurrGlobalWordUpdateRate = bBootstrapping ? DEFAULT_RESAMPLING_RATE / 2 : DEFAULT_RESAMPLING_RATE;
-  size_t nFlatRegionCount = 0;
-  if (m_nImgChannels == 1) {
-    for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-      const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-      const size_t nDescIter = nPxIter * 2;
-      const size_t nFloatIter = nPxIter * 4;
-      const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
-      const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
-      const uchar nCurrColor = oInputImg.data[nPxIter];
-      uchar& nLastColor = m_oLastColorFrame.data[nPxIter];
-      ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter));
-      size_t nMinColorDist = s_nColorMaxDataRange_1ch;
-      size_t nMinDescDist = s_nDescMaxDataRange_1ch;
-      float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter);
-      float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter);
-      float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter);
-      float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter);
-      float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
-      float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter);
-      float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter);
-      float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter);
-      float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter);
-      const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset);
-      const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2);
-      uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
-      uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter];
-      uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter];
-      const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX;
-      const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X;
-      const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y;
-      ushort nCurrInterDesc, nCurrIntraDesc;
-      LBSP_::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc);
-      const uchar nCurrIntraDescBITS = (uchar)popcount(nCurrIntraDesc);
-      const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT;
-      if (bCurrRegionIsFlat)
-        ++nFlatRegionCount;
-      const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping);
-      const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate);
-      const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2;
-      const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET);
-      size_t nLocalWordIdx = 0;
-      float fPotentialLocalWordsWeightSum = 0.0f;
-      float fLastLocalWordWeight = FLT_MAX;
-      while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) {
-        LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-        const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-        {
-          const size_t nColorDist = L1dist(nCurrColor, pCurrLocalWord->oFeature.anColor[0]);
-          const size_t nIntraDescDist = hdist(nCurrIntraDesc, pCurrLocalWord->oFeature.anDesc[0]);
-          LBSP_::computeGrayscaleDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor[0], nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]], nCurrInterDesc);
-          const size_t nInterDescDist = hdist(nCurrInterDesc, pCurrLocalWord->oFeature.anDesc[0]);
-          const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2;
-          if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder)
-            && nColorDist <= nCurrColorDistThreshold
-            && nColorDist >= nCurrColorDistThreshold / 2
-            && nIntraDescDist <= nCurrDescDistThreshold / 2
-            && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) {
-            // == illum updt
-            pCurrLocalWord->oFeature.anColor[0] = nCurrColor;
-            pCurrLocalWord->oFeature.anDesc[0] = nCurrIntraDesc;
-            m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1];
-            m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1];
-            m_oIllumUpdtRegionMask.data[nPxIter] = 2;
+        const bool bRecalcGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate << 5));
+        const bool bUpdateGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate));
+        cv::Mat oLastFGMask_dilated_inverted_downscaled;
+        if (bUpdateGlobalWords)
+          cv::resize(m_oLastFGMask_dilated_inverted, oLastFGMask_dilated_inverted_downscaled, m_oDownSampledFrameSize_GlobalWordLookup, 0, 0, cv::INTER_NEAREST);
+        for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
+          if (bRecalcGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) {
+            m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = GetGlobalWordWeight(m_apGlobalWordDict[nGlobalWordIdx]);
+            if (m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight < 1.0f) {
+              m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = 0.0f;
+              m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap = cv::Scalar(0.0f);
+            }
           }
-          if (nDescDist <= nCurrDescDistThreshold && nColorDist <= nCurrColorDistThreshold) {
-            fPotentialLocalWordsWeightSum += fCurrLocalWordWeight;
-            pCurrLocalWord->nLastOcc = m_nFrameIndex;
-            if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
-              pCurrLocalWord->nOccurrences += nCurrWordOccIncr;
-            nMinColorDist = std::min(nMinColorDist, nColorDist);
-            nMinDescDist = std::min(nMinDescDist, nDescDist);
+          if (bUpdateGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) {
+            cv::accumulateProduct(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_oTempGlobalWordWeightDiffFactor, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, oLastFGMask_dilated_inverted_downscaled);
+            m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight *= 0.9f;
+            cv::blur(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, cv::Size(3, 3), cv::Point(-1, -1), cv::BORDER_REPLICATE);
           }
+          if (nGlobalWordIdx > 0 && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)
+            std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]);
         }
-        if (fCurrLocalWordWeight > fLastLocalWordWeight) {
-          std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
-        }
-        else
-          fLastLocalWordWeight = fCurrLocalWordWeight;
-        ++nLocalWordIdx;
-      }
-      while (nLocalWordIdx < m_nCurrLocalWords) {
-        const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset);
-        if (fCurrLocalWordWeight > fLastLocalWordWeight) {
-          std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
-        }
-        else
-          fLastLocalWordWeight = fCurrLocalWordWeight;
-        ++nLocalWordIdx;
-      }
-      if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) {
-        // == background
-        const float fNormalizedMinDist = std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch);
-        fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
-        fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
-        fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT);
-        fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST);
-        if ((rand() % nCurrLocalWordUpdateRate) == 0) {
-          size_t nGlobalWordLUTIdx;
-          GlobalWord_1ch* pCurrGlobalWord = nullptr;
-          for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
-            pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx];
-            if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold
-              && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR)
-              break;
-          }
-          if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) {
-            if (nGlobalWordLUTIdx == m_nCurrGlobalWords) {
-              pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1];
-              pCurrGlobalWord->oFeature.anColor[0] = nCurrColor;
-              pCurrGlobalWord->oFeature.anDesc[0] = nCurrIntraDesc;
-              pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS;
-              pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
-              pCurrGlobalWord->fLatestWeight = 0.0f;
-            }
-            float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-            if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) {
-              pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum;
-              fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum;
+        if (bUpdateGlobalWords) {
+          for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+            const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+            const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
+            float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+            for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
+              const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
+              if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight)
+                std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]);
+              else
+                fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight;
             }
           }
         }
-      }
-      else {
-        // == foreground
-        const float fNormalizedMinDist = std::max(std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold);
-        fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
-        fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
-        fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT;
-        fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST;
-        if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) {
-          size_t nGlobalWordLUTIdx;
-          GlobalWord_1ch* pCurrGlobalWord;
-          for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
-            pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx];
-            if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold
-              && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR)
-              break;
-          }
-          if (nGlobalWordLUTIdx == m_nCurrGlobalWords)
-            nCurrRegionSegmVal = UCHAR_MAX;
-          else {
-            const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-            if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold)
-              nCurrRegionSegmVal = UCHAR_MAX;
-          }
+        cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask);
+        cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame);
+        m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask);
+        oCurrFGMask.copyTo(m_oLastRawFGMask);
+        cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, m_oMorphExStructElement);
+        m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles);
+        cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX);
+        cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles);
+        cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3);
+        cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask);
+        cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask);
+        cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize);
+        cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3);
+        cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame);
+        cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted);
+        cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame);
+        m_oLastFGMask.copyTo(oCurrFGMask);
+        cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F);
+        cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F);
+        const float fCurrNonFlatRegionRatio = (float)(m_nTotRelevantPxCount - nFlatRegionCount) / m_nTotRelevantPxCount;
+        if (fCurrNonFlatRegionRatio < LBSPDESC_RATIO_MIN && m_fLastNonFlatRegionRatio < LBSPDESC_RATIO_MIN) {
+          for (size_t t = 0; t <= UCHAR_MAX; ++t)
+            if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 4))
+              --m_anLBSPThreshold_8bitLUT[t];
         }
-        else
-          nCurrRegionSegmVal = UCHAR_MAX;
-        if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) {
-          const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1;
-          LocalWord_1ch* pNewLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx];
-          pNewLocalWord->oFeature.anColor[0] = nCurrColor;
-          pNewLocalWord->oFeature.anDesc[0] = nCurrIntraDesc;
-          pNewLocalWord->nOccurrences = nCurrWordOccIncr;
-          pNewLocalWord->nFirstOcc = m_nFrameIndex;
-          pNewLocalWord->nLastOcc = m_nFrameIndex;
+        else if (fCurrNonFlatRegionRatio > LBSPDESC_RATIO_MAX && m_fLastNonFlatRegionRatio > LBSPDESC_RATIO_MAX) {
+          for (size_t t = 0; t <= UCHAR_MAX; ++t)
+            if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold))
+              ++m_anLBSPThreshold_8bitLUT[t];
         }
-      }
-      // == neighb updt
-      if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) {
-        //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) {
-        int nSampleImgCoord_Y, nSampleImgCoord_X;
-        if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera)
-          getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
-        else
-          getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
-        const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
-        if (m_oROI.data[nSamplePxIdx]) {
-          const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords;
-          size_t nNeighborLocalWordIdx = 0;
-          float fNeighborPotentialLocalWordsWeightSum = 0.0f;
-          while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) {
-            LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx];
-            const size_t nNeighborColorDist = L1dist(nCurrColor, pNeighborLocalWord->oFeature.anColor[0]);
-            const size_t nNeighborIntraDescDist = hdist(nCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc[0]);
-            const bool bNeighborRegionIsFlat = popcount(pNeighborLocalWord->oFeature.anDesc[0]) < FLAT_REGION_BIT_COUNT;
-            const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr;
-            if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborIntraDescDist <= nCurrDescDistThreshold) {
-              const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-              fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
-              pNeighborLocalWord->nLastOcc = m_nFrameIndex;
-              if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
-                pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
+        m_fLastNonFlatRegionRatio = fCurrNonFlatRegionRatio;
+        cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA);
+        cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT);
+        cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST);
+        const float fCurrMeanL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)m_oMeanDownSampledLastDistFrame_ST.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, m_oDownSampledROI_MotionAnalysis.data) / m_nDownSampledROIPxCount;
+        if (!m_bAutoModelResetEnabled && fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES * 2)
+          m_bAutoModelResetEnabled = true;
+        if (m_bAutoModelResetEnabled || m_bUsingMovingCamera) {
+          if ((m_nFrameIndex%DEFAULT_BOOTSTRAP_WIN_SIZE) == 0) {
+            cv::Mat oCurrBackgroundImg, oDownSampledBackgroundImg;
+            getBackgroundImage(oCurrBackgroundImg);
+            cv::resize(oCurrBackgroundImg, oDownSampledBackgroundImg, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA);
+            cv::Mat oDownSampledBackgroundImg_32F; oDownSampledBackgroundImg.convertTo(oDownSampledBackgroundImg_32F, CV_32F);
+            const float fCurrModelL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount;
+            const float fCurrModelCDistRatio = cdist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount;
+            if (m_bUsingMovingCamera && fCurrModelL1DistRatio < FRAMELEVEL_MIN_L1DIST_THRES / 4 && fCurrModelCDistRatio < FRAMELEVEL_MIN_CDIST_THRES / 4) {
+              m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET;
+              m_bUsingMovingCamera = false;
+              refreshModel(1, 1, true);
             }
-            else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) {
-              const size_t nSampleDescIdx = nSamplePxIdx * 2;
-              ushort& nNeighborLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx));
-              const size_t nNeighborLastIntraDescDist = hdist(nCurrIntraDesc, nNeighborLastIntraDesc);
-              if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborLastIntraDescDist <= nCurrDescDistThreshold / 2) {
-                const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-                fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
-                pNeighborLocalWord->nLastOcc = m_nFrameIndex;
-                if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
-                  pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
-                pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc;
-              }
+            else if (bBootstrapping && !m_bUsingMovingCamera && (fCurrModelL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES || fCurrModelCDistRatio >= FRAMELEVEL_MIN_CDIST_THRES)) {
+              m_nLocalWordWeightOffset = 5;
+              m_bUsingMovingCamera = true;
+              refreshModel(1, 1, true);
             }
-            ++nNeighborLocalWordIdx;
           }
-          if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) {
-            nNeighborLocalWordIdx = m_nCurrLocalWords - 1;
-            LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx];
-            pNeighborLocalWord->oFeature.anColor[0] = nCurrColor;
-            pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc;
-            pNeighborLocalWord->nOccurrences = nCurrWordOccIncr;
-            pNeighborLocalWord->nFirstOcc = m_nFrameIndex;
-            pNeighborLocalWord->nLastOcc = m_nFrameIndex;
+          if (m_nFramesSinceLastReset > DEFAULT_BOOTSTRAP_WIN_SIZE * 2)
+            m_bAutoModelResetEnabled = false;
+          else if (fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES && m_nModelResetCooldown == 0) {
+            m_nFramesSinceLastReset = 0;
+            refreshModel(m_nLocalWordWeightOffset / 8, 0, true);
+            m_nModelResetCooldown = nCurrSamplesForMovingAvg_ST;
+            m_oUpdateRateFrame = cv::Scalar(1.0f);
           }
+          else if (!bBootstrapping)
+            ++m_nFramesSinceLastReset;
         }
+        if (m_nModelResetCooldown > 0)
+          --m_nModelResetCooldown;
       }
-      if (nCurrRegionIllumUpdtVal)
-        nCurrRegionIllumUpdtVal -= 1;
-      // == feedback adj
-      bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN;
-      if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal))
-        fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER);
-      else
-        fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER);
-      if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter])
-        (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR;
-      else
-        fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR);
-      if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2))
-        fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR);
-      else
-        fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f);
-      nLastIntraDesc = nCurrIntraDesc;
-      nLastColor = nCurrColor;
-    }
-  }
-  else { //m_nImgChannels==3
-    for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-      const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-      const size_t nPxRGBIter = nPxIter * 3;
-      const size_t nDescRGBIter = nPxRGBIter * 2;
-      const size_t nFloatIter = nPxIter * 4;
-      const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
-      const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
-      const uchar* const anCurrColor = oInputImg.data + nPxRGBIter;
-      uchar* anLastColor = m_oLastColorFrame.data + nPxRGBIter;
-      ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescRGBIter));
-      size_t nMinTotColorDist = s_nColorMaxDataRange_3ch;
-      size_t nMinTotDescDist = s_nDescMaxDataRange_3ch;
-      float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter);
-      float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter);
-      float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter);
-      float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter);
-      float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter);
-      float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter);
-      float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter);
-      float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter);
-      float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter);
-      const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset);
-      const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2);
-      uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter];
-      uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter];
-      uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter];
-      const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX;
-      const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X;
-      const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y;
-      ushort anCurrInterDesc[3], anCurrIntraDesc[3];
-      const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] };
-      LBSP_::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc);
-      const uchar nCurrIntraDescBITS = (uchar)popcount<3>(anCurrIntraDesc);
-      const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT * 2;
-      if (bCurrRegionIsFlat)
-        ++nFlatRegionCount;
-      const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping);
-      const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate);
-      const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3;
-      const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3;
-      size_t nLocalWordIdx = 0;
-      float fPotentialLocalWordsWeightSum = 0.0f;
-      float fLastLocalWordWeight = FLT_MAX;
-      while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) {
-        LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-        const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-        {
-          const size_t nTotColorL1Dist = L1dist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor);
-          const size_t nColorDistortion = cdist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor);
-          const size_t nTotColorMixDist = cmixdist(nTotColorL1Dist, nColorDistortion);
-          const size_t nTotIntraDescDist = hdist<3>(anCurrIntraDesc, pCurrLocalWord->oFeature.anDesc);
-          const size_t anCurrInterLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[1]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[2]] };
-          LBSP_::computeRGBDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrInterLBSPThresholds, anCurrInterDesc);
-          const size_t nTotInterDescDist = hdist<3>(anCurrInterDesc, pCurrLocalWord->oFeature.anDesc);
-          const size_t nTotDescDist = (nTotIntraDescDist + nTotInterDescDist) / 2;
-          if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder)
-            && nTotColorMixDist <= nCurrTotColorDistThreshold
-            && nTotColorL1Dist >= nCurrTotColorDistThreshold / 2
-            && nTotIntraDescDist <= nCurrTotDescDistThreshold / 2
-            && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) {
-            // == illum updt
-            for (size_t c = 0; c < 3; ++c) {
-              pCurrLocalWord->oFeature.anColor[c] = anCurrColor[c];
-              pCurrLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
+
+      void BackgroundSubtractorPAWCS::getBackgroundImage(cv::OutputArray backgroundImage) const { // @@@ add option to reconstruct from gwords?
+        CV_Assert(m_bInitialized);
+        cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels));
+        for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+          const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+          const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
+          const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X;
+          const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y;
+          if (m_nImgChannels == 1) {
+            float fTotWeight = 0.0f;
+            float fTotColor = 0.0f;
+            for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
+              LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+              float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+              fTotColor += (float)pCurrLocalWord->oFeature.anColor[0] * fCurrWeight;
+              fTotWeight += fCurrWeight;
             }
-            m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1];
-            m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1];
-            m_oIllumUpdtRegionMask.data[nPxIter] = 2;
+            oAvgBGImg.at<float>(nCurrImgCoord_Y, nCurrImgCoord_X) = fTotColor / fTotWeight;
           }
-          if (nTotDescDist <= nCurrTotDescDistThreshold && nTotColorMixDist <= nCurrTotColorDistThreshold) {
-            fPotentialLocalWordsWeightSum += fCurrLocalWordWeight;
-            pCurrLocalWord->nLastOcc = m_nFrameIndex;
-            if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
-              pCurrLocalWord->nOccurrences += nCurrWordOccIncr;
-            nMinTotColorDist = std::min(nMinTotColorDist, nTotColorMixDist);
-            nMinTotDescDist = std::min(nMinTotDescDist, nTotDescDist);
+          else { //m_nImgChannels==3
+            float fTotWeight = 0.0f;
+            float fTotColor[3] = { 0.0f,0.0f,0.0f };
+            for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
+              LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
+              float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
+              for (size_t c = 0; c < 3; ++c)
+                fTotColor[c] += (float)pCurrLocalWord->oFeature.anColor[c] * fCurrWeight;
+              fTotWeight += fCurrWeight;
+            }
+            oAvgBGImg.at<cv::Vec3f>(nCurrImgCoord_Y, nCurrImgCoord_X) = cv::Vec3f(fTotColor[0] / fTotWeight, fTotColor[1] / fTotWeight, fTotColor[2] / fTotWeight);
           }
         }
-        if (fCurrLocalWordWeight > fLastLocalWordWeight) {
-          std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
-        }
-        else
-          fLastLocalWordWeight = fCurrLocalWordWeight;
-        ++nLocalWordIdx;
-      }
-      while (nLocalWordIdx < m_nCurrLocalWords) {
-        const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset);
-        if (fCurrLocalWordWeight > fLastLocalWordWeight) {
-          std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]);
-        }
-        else
-          fLastLocalWordWeight = fCurrLocalWordWeight;
-        ++nLocalWordIdx;
+        oAvgBGImg.convertTo(backgroundImage, CV_8U);
       }
-      if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) {
-        // == background
-        const float fNormalizedMinDist = std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch);
-        fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
-        fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
-        fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT);
-        fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST);
-        if ((rand() % nCurrLocalWordUpdateRate) == 0) {
-          size_t nGlobalWordLUTIdx;
-          GlobalWord_3ch* pCurrGlobalWord = nullptr;
-          for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
-            pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx];
-            if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR
-              && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold)
-              break;
-          }
-          if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) {
-            if (nGlobalWordLUTIdx == m_nCurrGlobalWords) {
-              pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1];
-              for (size_t c = 0; c < 3; ++c) {
-                pCurrGlobalWord->oFeature.anColor[c] = anCurrColor[c];
-                pCurrGlobalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
+
+      void BackgroundSubtractorPAWCS::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const {
+        CV_Assert(LBSP_::DESC_SIZE == 2);
+        CV_Assert(m_bInitialized);
+        cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels));
+        // @@@@@@ TO BE REWRITTEN FOR WORD-BASED RECONSTRUCTION
+        /*for(size_t n=0; n<m_voBGDescSamples.size(); ++n) {
+              for(int y=0; y<m_oImgSize.height; ++y) {
+                  for(int x=0; x<m_oImgSize.width; ++x) {
+                      const size_t nDescIter = m_voBGDescSamples[n].step.p[0]*y + m_voBGDescSamples[n].step.p[1]*x;
+                      const size_t nFloatIter = nDescIter*2;
+                      float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data+nFloatIter);
+                      const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data+nDescIter);
+                      for(size_t c=0; c<m_nImgChannels; ++c)
+                          oAvgBgDescPtr[c] += ((float)oBGDescPtr[c])/m_voBGDescSamples.size();
+                  }
               }
-              pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS;
-              pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f);
-              pCurrGlobalWord->fLatestWeight = 0.0f;
-            }
-            float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-            if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) {
-              pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum;
-              fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum;
-            }
-          }
-        }
+          }*/
+        oAvgBGDesc.convertTo(backgroundDescImage, CV_16U);
       }
-      else {
-        // == foreground
-        const float fNormalizedMinDist = std::max(std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold);
-        fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
-        fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
-        fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT;
-        fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST;
-        if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) {
-          size_t nGlobalWordLUTIdx;
-          GlobalWord_3ch* pCurrGlobalWord;
-          for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
-            pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx];
-            if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR
-              && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold)
-              break;
-          }
-          if (nGlobalWordLUTIdx == m_nCurrGlobalWords)
-            nCurrRegionSegmVal = UCHAR_MAX;
-          else {
-            const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-            if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold)
-              nCurrRegionSegmVal = UCHAR_MAX;
-          }
+
+      void BackgroundSubtractorPAWCS::CleanupDictionaries() {
+        if (m_aLocalWordList_1ch) {
+          delete[] m_aLocalWordList_1ch;
+          m_aLocalWordList_1ch = nullptr;
+          m_pLocalWordListIter_1ch = nullptr;
         }
-        else
-          nCurrRegionSegmVal = UCHAR_MAX;
-        if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) {
-          const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1;
-          LocalWord_3ch* pNewLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx];
-          for (size_t c = 0; c < 3; ++c) {
-            pNewLocalWord->oFeature.anColor[c] = anCurrColor[c];
-            pNewLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
-          }
-          pNewLocalWord->nOccurrences = nCurrWordOccIncr;
-          pNewLocalWord->nFirstOcc = m_nFrameIndex;
-          pNewLocalWord->nLastOcc = m_nFrameIndex;
+        else if (m_aLocalWordList_3ch) {
+          delete[] m_aLocalWordList_3ch;
+          m_aLocalWordList_3ch = nullptr;
+          m_pLocalWordListIter_3ch = nullptr;
         }
-      }
-      // == neighb updt
-      if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) {
-        //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) {
-        int nSampleImgCoord_Y, nSampleImgCoord_X;
-        if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera)
-          getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
-        else
-          getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize);
-        const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
-        if (m_oROI.data[nSamplePxIdx]) {
-          const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords;
-          size_t nNeighborLocalWordIdx = 0;
-          float fNeighborPotentialLocalWordsWeightSum = 0.0f;
-          while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) {
-            LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx];
-            const size_t nNeighborTotColorL1Dist = L1dist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor);
-            const size_t nNeighborColorDistortion = cdist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor);
-            const size_t nNeighborTotColorMixDist = cmixdist(nNeighborTotColorL1Dist, nNeighborColorDistortion);
-            const size_t nNeighborTotIntraDescDist = hdist<3>(anCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc);
-            const bool bNeighborRegionIsFlat = popcount<3>(pNeighborLocalWord->oFeature.anDesc) < FLAT_REGION_BIT_COUNT * 2;
-            const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr;
-            if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold) {
-              const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-              fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
-              pNeighborLocalWord->nLastOcc = m_nFrameIndex;
-              if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
-                pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
-            }
-            else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) {
-              const size_t nSamplePxRGBIdx = nSamplePxIdx * 3;
-              const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2;
-              ushort* anNeighborLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx));
-              const size_t nNeighborTotLastIntraDescDist = hdist<3>(anCurrIntraDesc, anNeighborLastIntraDesc);
-              if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotLastIntraDescDist <= nCurrTotDescDistThreshold / 2) {
-                const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-                fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
-                pNeighborLocalWord->nLastOcc = m_nFrameIndex;
-                if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
-                  pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
-                for (size_t c = 0; c < 3; ++c)
-                  pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
-              }
-              else {
-                const bool bNeighborLastRegionIsFlat = popcount<3>(anNeighborLastIntraDesc) < FLAT_REGION_BIT_COUNT * 2;
-                if (bNeighborLastRegionIsFlat && bCurrRegionIsFlat &&
-                  nNeighborTotLastIntraDescDist + nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold &&
-                  nNeighborColorDistortion <= nCurrTotColorDistThreshold / 4) {
-                  const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-                  fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight;
-                  pNeighborLocalWord->nLastOcc = m_nFrameIndex;
-                  if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT)
-                    pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr;
-                  for (size_t c = 0; c < 3; ++c)
-                    pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c];
-                }
-              }
-            }
-            ++nNeighborLocalWordIdx;
-          }
-          if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) {
-            nNeighborLocalWordIdx = m_nCurrLocalWords - 1;
-            LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx];
-            for (size_t c = 0; c < 3; ++c) {
-              pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c];
-              pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c];
-            }
-            pNeighborLocalWord->nOccurrences = nCurrWordOccIncr;
-            pNeighborLocalWord->nFirstOcc = m_nFrameIndex;
-            pNeighborLocalWord->nLastOcc = m_nFrameIndex;
-          }
+        if (m_apLocalWordDict) {
+          delete[] m_apLocalWordDict;
+          m_apLocalWordDict = nullptr;
+        }
+        if (m_aGlobalWordList_1ch) {
+          delete[] m_aGlobalWordList_1ch;
+          m_aGlobalWordList_1ch = nullptr;
+          m_pGlobalWordListIter_1ch = nullptr;
+        }
+        else if (m_aGlobalWordList_3ch) {
+          delete[] m_aGlobalWordList_3ch;
+          m_aGlobalWordList_3ch = nullptr;
+          m_pGlobalWordListIter_3ch = nullptr;
+        }
+        if (m_apGlobalWordDict) {
+          delete[] m_apGlobalWordDict;
+          m_apGlobalWordDict = nullptr;
+        }
+        if (m_aPxInfoLUT_PAWCS) {
+          for (size_t nPxIter = 0; nPxIter < m_nTotPxCount; ++nPxIter)
+            delete[] m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT;
+          delete[] m_aPxInfoLUT_PAWCS;
+          m_aPxInfoLUT = nullptr;
+          m_aPxInfoLUT_PAWCS = nullptr;
+        }
+        if (m_aPxIdxLUT) {
+          delete[] m_aPxIdxLUT;
+          m_aPxIdxLUT = nullptr;
         }
       }
-      if (nCurrRegionIllumUpdtVal)
-        nCurrRegionIllumUpdtVal -= 1;
-      // == feedback adj
-      bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN;
-      if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal))
-        fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER);
-      else
-        fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER);
-      if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter])
-        (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR;
-      else
-        fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR);
-      if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2))
-        fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR);
-      else
-        fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f);
-      for (size_t c = 0; c < 3; ++c) {
-        anLastIntraDesc[c] = anCurrIntraDesc[c];
-        anLastColor[c] = anCurrColor[c];
-      }
-    }
-  }
-  const bool bRecalcGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate << 5));
-  const bool bUpdateGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate));
-  cv::Mat oLastFGMask_dilated_inverted_downscaled;
-  if (bUpdateGlobalWords)
-    cv::resize(m_oLastFGMask_dilated_inverted, oLastFGMask_dilated_inverted_downscaled, m_oDownSampledFrameSize_GlobalWordLookup, 0, 0, cv::INTER_NEAREST);
-  for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) {
-    if (bRecalcGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) {
-      m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = GetGlobalWordWeight(m_apGlobalWordDict[nGlobalWordIdx]);
-      if (m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight < 1.0f) {
-        m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = 0.0f;
-        m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap = cv::Scalar(0.0f);
-      }
-    }
-    if (bUpdateGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) {
-      cv::accumulateProduct(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_oTempGlobalWordWeightDiffFactor, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, oLastFGMask_dilated_inverted_downscaled);
-      m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight *= 0.9f;
-      cv::blur(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, cv::Size(3, 3), cv::Point(-1, -1), cv::BORDER_REPLICATE);
-    }
-    if (nGlobalWordIdx > 0 && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)
-      std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]);
-  }
-  if (bUpdateGlobalWords) {
-    for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-      const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-      const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx;
-      float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-      for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) {
-        const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx);
-        if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight)
-          std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]);
-        else
-          fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight;
-      }
-    }
-  }
-  cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask);
-  cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame);
-  m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask);
-  oCurrFGMask.copyTo(m_oLastRawFGMask);
-  cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, m_oMorphExStructElement);
-  m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles);
-  cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX);
-  cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles);
-  cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3);
-  cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask);
-  cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask);
-  cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize);
-  cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3);
-  cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame);
-  cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted);
-  cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame);
-  m_oLastFGMask.copyTo(oCurrFGMask);
-  cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F);
-  cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F);
-  const float fCurrNonFlatRegionRatio = (float)(m_nTotRelevantPxCount - nFlatRegionCount) / m_nTotRelevantPxCount;
-  if (fCurrNonFlatRegionRatio < LBSPDESC_RATIO_MIN && m_fLastNonFlatRegionRatio < LBSPDESC_RATIO_MIN) {
-    for (size_t t = 0; t <= UCHAR_MAX; ++t)
-      if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 4))
-        --m_anLBSPThreshold_8bitLUT[t];
-  }
-  else if (fCurrNonFlatRegionRatio > LBSPDESC_RATIO_MAX && m_fLastNonFlatRegionRatio > LBSPDESC_RATIO_MAX) {
-    for (size_t t = 0; t <= UCHAR_MAX; ++t)
-      if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold))
-        ++m_anLBSPThreshold_8bitLUT[t];
-  }
-  m_fLastNonFlatRegionRatio = fCurrNonFlatRegionRatio;
-  cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA);
-  cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT);
-  cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST);
-  const float fCurrMeanL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)m_oMeanDownSampledLastDistFrame_ST.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, m_oDownSampledROI_MotionAnalysis.data) / m_nDownSampledROIPxCount;
-  if (!m_bAutoModelResetEnabled && fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES * 2)
-    m_bAutoModelResetEnabled = true;
-  if (m_bAutoModelResetEnabled || m_bUsingMovingCamera) {
-    if ((m_nFrameIndex%DEFAULT_BOOTSTRAP_WIN_SIZE) == 0) {
-      cv::Mat oCurrBackgroundImg, oDownSampledBackgroundImg;
-      getBackgroundImage(oCurrBackgroundImg);
-      cv::resize(oCurrBackgroundImg, oDownSampledBackgroundImg, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA);
-      cv::Mat oDownSampledBackgroundImg_32F; oDownSampledBackgroundImg.convertTo(oDownSampledBackgroundImg_32F, CV_32F);
-      const float fCurrModelL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount;
-      const float fCurrModelCDistRatio = cdist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount;
-      if (m_bUsingMovingCamera && fCurrModelL1DistRatio < FRAMELEVEL_MIN_L1DIST_THRES / 4 && fCurrModelCDistRatio < FRAMELEVEL_MIN_CDIST_THRES / 4) {
-        m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET;
-        m_bUsingMovingCamera = false;
-        refreshModel(1, 1, true);
-      }
-      else if (bBootstrapping && !m_bUsingMovingCamera && (fCurrModelL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES || fCurrModelCDistRatio >= FRAMELEVEL_MIN_CDIST_THRES)) {
-        m_nLocalWordWeightOffset = 5;
-        m_bUsingMovingCamera = true;
-        refreshModel(1, 1, true);
-      }
-    }
-    if (m_nFramesSinceLastReset > DEFAULT_BOOTSTRAP_WIN_SIZE * 2)
-      m_bAutoModelResetEnabled = false;
-    else if (fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES && m_nModelResetCooldown == 0) {
-      m_nFramesSinceLastReset = 0;
-      refreshModel(m_nLocalWordWeightOffset / 8, 0, true);
-      m_nModelResetCooldown = nCurrSamplesForMovingAvg_ST;
-      m_oUpdateRateFrame = cv::Scalar(1.0f);
-    }
-    else if (!bBootstrapping)
-      ++m_nFramesSinceLastReset;
-  }
-  if (m_nModelResetCooldown > 0)
-    --m_nModelResetCooldown;
-}
 
-void BackgroundSubtractorPAWCS::getBackgroundImage(cv::OutputArray backgroundImage) const { // @@@ add option to reconstruct from gwords?
-  CV_Assert(m_bInitialized);
-  cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels));
-  for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-    const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-    const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords;
-    const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X;
-    const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y;
-    if (m_nImgChannels == 1) {
-      float fTotWeight = 0.0f;
-      float fTotColor = 0.0f;
-      for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
-        LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-        float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-        fTotColor += (float)pCurrLocalWord->oFeature.anColor[0] * fCurrWeight;
-        fTotWeight += fCurrWeight;
+      float BackgroundSubtractorPAWCS::GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset) {
+        return (float)(w->nOccurrences) / ((w->nLastOcc - w->nFirstOcc) + (nCurrFrame - w->nLastOcc) * 2 + nOffset);
       }
-      oAvgBGImg.at<float>(nCurrImgCoord_Y, nCurrImgCoord_X) = fTotColor / fTotWeight;
-    }
-    else { //m_nImgChannels==3
-      float fTotWeight = 0.0f;
-      float fTotColor[3] = { 0.0f,0.0f,0.0f };
-      for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) {
-        LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx];
-        float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset);
-        for (size_t c = 0; c < 3; ++c)
-          fTotColor[c] += (float)pCurrLocalWord->oFeature.anColor[c] * fCurrWeight;
-        fTotWeight += fCurrWeight;
+
+      float BackgroundSubtractorPAWCS::GetGlobalWordWeight(const GlobalWordBase* w) {
+        return (float)cv::sum(w->oSpatioOccMap).val[0];
       }
-      oAvgBGImg.at<cv::Vec3f>(nCurrImgCoord_Y, nCurrImgCoord_X) = cv::Vec3f(fTotColor[0] / fTotWeight, fTotColor[1] / fTotWeight, fTotColor[2] / fTotWeight);
     }
   }
-  oAvgBGImg.convertTo(backgroundImage, CV_8U);
-}
-
-void BackgroundSubtractorPAWCS::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const {
-  CV_Assert(LBSP_::DESC_SIZE == 2);
-  CV_Assert(m_bInitialized);
-  cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels));
-  // @@@@@@ TO BE REWRITTEN FOR WORD-BASED RECONSTRUCTION
-  /*for(size_t n=0; n<m_voBGDescSamples.size(); ++n) {
-        for(int y=0; y<m_oImgSize.height; ++y) {
-            for(int x=0; x<m_oImgSize.width; ++x) {
-                const size_t nDescIter = m_voBGDescSamples[n].step.p[0]*y + m_voBGDescSamples[n].step.p[1]*x;
-                const size_t nFloatIter = nDescIter*2;
-                float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data+nFloatIter);
-                const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data+nDescIter);
-                for(size_t c=0; c<m_nImgChannels; ++c)
-                    oAvgBgDescPtr[c] += ((float)oBGDescPtr[c])/m_voBGDescSamples.size();
-            }
-        }
-    }*/
-  oAvgBGDesc.convertTo(backgroundDescImage, CV_16U);
-}
-
-void BackgroundSubtractorPAWCS::CleanupDictionaries() {
-  if (m_aLocalWordList_1ch) {
-    delete[] m_aLocalWordList_1ch;
-    m_aLocalWordList_1ch = nullptr;
-    m_pLocalWordListIter_1ch = nullptr;
-  }
-  else if (m_aLocalWordList_3ch) {
-    delete[] m_aLocalWordList_3ch;
-    m_aLocalWordList_3ch = nullptr;
-    m_pLocalWordListIter_3ch = nullptr;
-  }
-  if (m_apLocalWordDict) {
-    delete[] m_apLocalWordDict;
-    m_apLocalWordDict = nullptr;
-  }
-  if (m_aGlobalWordList_1ch) {
-    delete[] m_aGlobalWordList_1ch;
-    m_aGlobalWordList_1ch = nullptr;
-    m_pGlobalWordListIter_1ch = nullptr;
-  }
-  else if (m_aGlobalWordList_3ch) {
-    delete[] m_aGlobalWordList_3ch;
-    m_aGlobalWordList_3ch = nullptr;
-    m_pGlobalWordListIter_3ch = nullptr;
-  }
-  if (m_apGlobalWordDict) {
-    delete[] m_apGlobalWordDict;
-    m_apGlobalWordDict = nullptr;
-  }
-  if (m_aPxInfoLUT_PAWCS) {
-    for (size_t nPxIter = 0; nPxIter < m_nTotPxCount; ++nPxIter)
-      delete[] m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT;
-    delete[] m_aPxInfoLUT_PAWCS;
-    m_aPxInfoLUT = nullptr;
-    m_aPxInfoLUT_PAWCS = nullptr;
-  }
-  if (m_aPxIdxLUT) {
-    delete[] m_aPxIdxLUT;
-    m_aPxIdxLUT = nullptr;
-  }
-}
-
-float BackgroundSubtractorPAWCS::GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset) {
-  return (float)(w->nOccurrences) / ((w->nLastOcc - w->nFirstOcc) + (nCurrFrame - w->nLastOcc) * 2 + nOffset);
-}
-
-float BackgroundSubtractorPAWCS::GetGlobalWordWeight(const GlobalWordBase* w) {
-  return (float)cv::sum(w->oSpatioOccMap).val[0];
 }
diff --git a/src/algorithms/LBSP/BackgroundSubtractorPAWCS.h b/src/algorithms/LBSP/BackgroundSubtractorPAWCS.h
index b32d5b786a64028a028f6a2cd9a7048446c50100..e81736d37618108540ae33033b971932c2907fb4 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorPAWCS.h
+++ b/src/algorithms/LBSP/BackgroundSubtractorPAWCS.h
@@ -2,152 +2,161 @@
 
 #include "BackgroundSubtractorLBSP_.h"
 
-//! defines the default value for BackgroundSubtractorLBSP_::m_fRelLBSPThreshold
-#define BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.333f)
-//! defines the default value for BackgroundSubtractorPAWCS::m_nDescDistThresholdOffset
-#define BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET (2)
-//! defines the default value for BackgroundSubtractorPAWCS::m_nMinColorDistThreshold
-#define BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD (20)
-//! defines the default value for BackgroundSubtractorPAWCS::m_nMaxLocalWords and m_nMaxGlobalWords
-#define BGSPAWCS_DEFAULT_MAX_NB_WORDS (50)
-//! defines the default value for BackgroundSubtractorPAWCS::m_nSamplesForMovingAvgs
-#define BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS (100)
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      //! defines the default value for BackgroundSubtractorLBSP_::m_fRelLBSPThreshold
+      const float BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD = 0.333f;
+      //! defines the default value for BackgroundSubtractorPAWCS::m_nDescDistThresholdOffset
+      const int BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET = 2;
+      //! defines the default value for BackgroundSubtractorPAWCS::m_nMinColorDistThreshold
+      const int BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD = 20;
+      //! defines the default value for BackgroundSubtractorPAWCS::m_nMaxLocalWords and m_nMaxGlobalWords
+      const int BGSPAWCS_DEFAULT_MAX_NB_WORDS = 50;
+      //! defines the default value for BackgroundSubtractorPAWCS::m_nSamplesForMovingAvgs
+      const int BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS = 100;
 
-/*!
-    Pixel-based Adaptive Word Consensus Segmenter (PAWCS) change detection algorithm.
+      /*!
+          Pixel-based Adaptive Word Consensus Segmenter (PAWCS) change detection algorithm.
 
-    Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically).
-    For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3.
+          Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically).
+          For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3.
 
-    For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al.,
-    "A Self-Adjusting Approach to Change Detection Based on Background Word Consensus", in WACV 2015.
+          For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al.,
+          "A Self-Adjusting Approach to Change Detection Based on Background Word Consensus", in WACV 2015.
 
-    This algorithm is currently NOT thread-safe.
- */
-class BackgroundSubtractorPAWCS : public BackgroundSubtractorLBSP_ {
-public:
-  //! full constructor
-  BackgroundSubtractorPAWCS(float fRelLBSPThreshold = BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD,
-    size_t nDescDistThresholdOffset = BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET,
-    size_t nMinColorDistThreshold = BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD,
-    size_t nMaxNbWords = BGSPAWCS_DEFAULT_MAX_NB_WORDS,
-    size_t nSamplesForMovingAvgs = BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS);
-  //! default destructor
-  virtual ~BackgroundSubtractorPAWCS();
-  //! (re)initiaization method; needs to be called before starting background subtraction
-  virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI);
-  //! refreshes all local (+ global) dictionaries based on the last analyzed frame
-  virtual void refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate = false);
-  //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0)
-  virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0);
-  //! returns a copy of the latest reconstructed background image
-  virtual void getBackgroundImage(cv::OutputArray backgroundImage) const;
-  //! returns a copy of the latest reconstructed background descriptors image
-  virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const;
+          This algorithm is currently NOT thread-safe.
+      */
+      class BackgroundSubtractorPAWCS : public BackgroundSubtractorLBSP_ {
+      public:
+        //! full constructor
+        BackgroundSubtractorPAWCS(float fRelLBSPThreshold = BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD,
+          size_t nDescDistThresholdOffset = BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET,
+          size_t nMinColorDistThreshold = BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD,
+          size_t nMaxNbWords = BGSPAWCS_DEFAULT_MAX_NB_WORDS,
+          size_t nSamplesForMovingAvgs = BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS);
+        //! default destructor
+        virtual ~BackgroundSubtractorPAWCS();
+        //! (re)initiaization method; needs to be called before starting background subtraction
+        virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI);
+        //! refreshes all local (+ global) dictionaries based on the last analyzed frame
+        virtual void refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate = false);
+        //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0)
+        virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0);
+        //! returns a copy of the latest reconstructed background image
+        virtual void getBackgroundImage(cv::OutputArray backgroundImage) const;
+        //! returns a copy of the latest reconstructed background descriptors image
+        virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const;
 
-protected:
-  template<size_t nChannels>
-  struct ColorLBSPFeature {
-    uchar anColor[nChannels];
-    ushort anDesc[nChannels];
-  };
-  struct LocalWordBase {
-    size_t nFirstOcc;
-    size_t nLastOcc;
-    size_t nOccurrences;
-  };
-  template<typename T>
-  struct LocalWord : LocalWordBase {
-    T oFeature;
-  };
-  struct GlobalWordBase {
-    float fLatestWeight;
-    cv::Mat oSpatioOccMap;
-    uchar nDescBITS;
-  };
-  template<typename T>
-  struct GlobalWord : GlobalWordBase {
-    T oFeature;
-  };
-  typedef LocalWord<ColorLBSPFeature<1>> LocalWord_1ch;
-  typedef LocalWord<ColorLBSPFeature<3>> LocalWord_3ch;
-  typedef GlobalWord<ColorLBSPFeature<1>> GlobalWord_1ch;
-  typedef GlobalWord<ColorLBSPFeature<3>> GlobalWord_3ch;
-  struct PxInfo_PAWCS : PxInfoBase {
-    size_t nGlobalWordMapLookupIdx;
-    GlobalWordBase** apGlobalDictSortLUT;
-  };
-  //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here)
-  const size_t m_nMinColorDistThreshold;
-  //! absolute descriptor distance threshold offset
-  const size_t m_nDescDistThresholdOffset;
-  //! max/curr number of local words used to build background submodels (for a single pixel, similar to 'N' in ViBe/PBAS, may vary based on img/channel size)
-  size_t m_nMaxLocalWords, m_nCurrLocalWords;
-  //! max/curr number of global words used to build the global background model (may vary based on img/channel size)
-  size_t m_nMaxGlobalWords, m_nCurrGlobalWords;
-  //! number of samples to use to compute the learning rate of moving averages
-  const size_t m_nSamplesForMovingAvgs;
-  //! last calculated non-flat region ratio
-  float m_fLastNonFlatRegionRatio;
-  //! current kernel size for median blur post-proc filtering
-  int m_nMedianBlurKernelSize;
-  //! specifies the downsampled frame size used for cam motion analysis & gword lookup maps
-  cv::Size m_oDownSampledFrameSize_MotionAnalysis, m_oDownSampledFrameSize_GlobalWordLookup;
-  //! downsampled version of the ROI used for cam motion analysis
-  cv::Mat m_oDownSampledROI_MotionAnalysis;
-  //! total pixel count for the downsampled ROIs
-  size_t m_nDownSampledROIPxCount;
-  //! current local word weight offset
-  size_t m_nLocalWordWeightOffset;
+      protected:
+        template<size_t nChannels>
+        struct ColorLBSPFeature {
+          uchar anColor[nChannels];
+          ushort anDesc[nChannels];
+        };
+        struct LocalWordBase {
+          size_t nFirstOcc;
+          size_t nLastOcc;
+          size_t nOccurrences;
+        };
+        template<typename T>
+        struct LocalWord : LocalWordBase {
+          T oFeature;
+        };
+        struct GlobalWordBase {
+          float fLatestWeight;
+          cv::Mat oSpatioOccMap;
+          uchar nDescBITS;
+        };
+        template<typename T>
+        struct GlobalWord : GlobalWordBase {
+          T oFeature;
+        };
+        typedef LocalWord<ColorLBSPFeature<1>> LocalWord_1ch;
+        typedef LocalWord<ColorLBSPFeature<3>> LocalWord_3ch;
+        typedef GlobalWord<ColorLBSPFeature<1>> GlobalWord_1ch;
+        typedef GlobalWord<ColorLBSPFeature<3>> GlobalWord_3ch;
+        struct PxInfo_PAWCS : PxInfoBase {
+          size_t nGlobalWordMapLookupIdx;
+          GlobalWordBase** apGlobalDictSortLUT;
+        };
+        //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here)
+        const size_t m_nMinColorDistThreshold;
+        //! absolute descriptor distance threshold offset
+        const size_t m_nDescDistThresholdOffset;
+        //! max/curr number of local words used to build background submodels (for a single pixel, similar to 'N' in ViBe/PBAS, may vary based on img/channel size)
+        size_t m_nMaxLocalWords, m_nCurrLocalWords;
+        //! max/curr number of global words used to build the global background model (may vary based on img/channel size)
+        size_t m_nMaxGlobalWords, m_nCurrGlobalWords;
+        //! number of samples to use to compute the learning rate of moving averages
+        const size_t m_nSamplesForMovingAvgs;
+        //! last calculated non-flat region ratio
+        float m_fLastNonFlatRegionRatio;
+        //! current kernel size for median blur post-proc filtering
+        int m_nMedianBlurKernelSize;
+        //! specifies the downsampled frame size used for cam motion analysis & gword lookup maps
+        cv::Size m_oDownSampledFrameSize_MotionAnalysis, m_oDownSampledFrameSize_GlobalWordLookup;
+        //! downsampled version of the ROI used for cam motion analysis
+        cv::Mat m_oDownSampledROI_MotionAnalysis;
+        //! total pixel count for the downsampled ROIs
+        size_t m_nDownSampledROIPxCount;
+        //! current local word weight offset
+        size_t m_nLocalWordWeightOffset;
 
-  //! word lists & dictionaries
-  LocalWordBase** m_apLocalWordDict;
-  LocalWord_1ch* m_aLocalWordList_1ch, *m_pLocalWordListIter_1ch;
-  LocalWord_3ch* m_aLocalWordList_3ch, *m_pLocalWordListIter_3ch;
-  GlobalWordBase** m_apGlobalWordDict;
-  GlobalWord_1ch* m_aGlobalWordList_1ch, *m_pGlobalWordListIter_1ch;
-  GlobalWord_3ch* m_aGlobalWordList_3ch, *m_pGlobalWordListIter_3ch;
-  PxInfo_PAWCS* m_aPxInfoLUT_PAWCS;
+        //! word lists & dictionaries
+        LocalWordBase** m_apLocalWordDict;
+        LocalWord_1ch* m_aLocalWordList_1ch, *m_pLocalWordListIter_1ch;
+        LocalWord_3ch* m_aLocalWordList_3ch, *m_pLocalWordListIter_3ch;
+        GlobalWordBase** m_apGlobalWordDict;
+        GlobalWord_1ch* m_aGlobalWordList_1ch, *m_pGlobalWordListIter_1ch;
+        GlobalWord_3ch* m_aGlobalWordList_3ch, *m_pGlobalWordListIter_3ch;
+        PxInfo_PAWCS* m_aPxInfoLUT_PAWCS;
 
-  //! a lookup map used to keep track of regions where illumination recently changed
-  cv::Mat m_oIllumUpdtRegionMask;
-  //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe)
-  cv::Mat m_oUpdateRateFrame;
-  //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds)
-  cv::Mat m_oDistThresholdFrame;
-  //! per-pixel distance threshold variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations)
-  cv::Mat m_oDistThresholdVariationFrame;
-  //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)')
-  cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST;
-  //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and force global model resets automatically)
-  cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST;
-  //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions)
-  cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST;
-  //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions)
-  cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST;
-  //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds)
-  cv::Mat m_oUnstableRegionMask;
-  //! per-pixel blink detection map ('Z(x)')
-  cv::Mat m_oBlinksFrame;
-  //! pre-allocated matrix used to downsample the input frame when needed
-  cv::Mat m_oDownSampledFrame_MotionAnalysis;
-  //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection)
-  cv::Mat m_oLastRawFGMask;
+        //! a lookup map used to keep track of regions where illumination recently changed
+        cv::Mat m_oIllumUpdtRegionMask;
+        //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe)
+        cv::Mat m_oUpdateRateFrame;
+        //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds)
+        cv::Mat m_oDistThresholdFrame;
+        //! per-pixel distance threshold variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations)
+        cv::Mat m_oDistThresholdVariationFrame;
+        //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)')
+        cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST;
+        //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and force global model resets automatically)
+        cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST;
+        //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions)
+        cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST;
+        //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions)
+        cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST;
+        //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds)
+        cv::Mat m_oUnstableRegionMask;
+        //! per-pixel blink detection map ('Z(x)')
+        cv::Mat m_oBlinksFrame;
+        //! pre-allocated matrix used to downsample the input frame when needed
+        cv::Mat m_oDownSampledFrame_MotionAnalysis;
+        //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection)
+        cv::Mat m_oLastRawFGMask;
 
-  //! pre-allocated CV_8UC1 matrices used to speed up morph ops
-  cv::Mat m_oFGMask_PreFlood;
-  cv::Mat m_oFGMask_FloodedHoles;
-  cv::Mat m_oLastFGMask_dilated;
-  cv::Mat m_oLastFGMask_dilated_inverted;
-  cv::Mat m_oCurrRawFGBlinkMask;
-  cv::Mat m_oLastRawFGBlinkMask;
-  cv::Mat m_oTempGlobalWordWeightDiffFactor;
-  cv::Mat m_oMorphExStructElement;
+        //! pre-allocated CV_8UC1 matrices used to speed up morph ops
+        cv::Mat m_oFGMask_PreFlood;
+        cv::Mat m_oFGMask_FloodedHoles;
+        cv::Mat m_oLastFGMask_dilated;
+        cv::Mat m_oLastFGMask_dilated_inverted;
+        cv::Mat m_oCurrRawFGBlinkMask;
+        cv::Mat m_oLastRawFGBlinkMask;
+        cv::Mat m_oTempGlobalWordWeightDiffFactor;
+        cv::Mat m_oMorphExStructElement;
 
-  //! internal cleanup function for the dictionary structures
-  void CleanupDictionaries();
-  //! internal weight lookup function for local words
-  static float GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset);
-  //! internal weight lookup function for global words
-  static float GetGlobalWordWeight(const GlobalWordBase* w);
-};
+        //! internal cleanup function for the dictionary structures
+        void CleanupDictionaries();
+        //! internal weight lookup function for local words
+        static float GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset);
+        //! internal weight lookup function for global words
+        static float GetGlobalWordWeight(const GlobalWordBase* w);
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.cpp b/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.cpp
index f965b048bb19f950ee51349ed0e463b23932ec95..04a084acc18d7930f19ab209bc989cf010c1f89c 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.cpp
+++ b/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.cpp
@@ -7,732 +7,743 @@
 #include "BackgroundSubtractorSuBSENSE.h"
 #include "RandUtils.h"
 
-/*
- *
- * Intrinsic parameters for our method are defined here; tuning these for better
- * performance should not be required in most cases -- although improvements in
- * very specific scenarios are always possible.
- *
- */
- //! defines the threshold value(s) used to detect long-term ghosting and trigger the fast edge-based absorption heuristic
-#define GHOSTDET_D_MAX (0.010f) // defines 'negligible' change here
-#define GHOSTDET_S_MIN (0.995f) // defines the required minimum local foreground saturation value
-//! parameter used to scale dynamic distance threshold adjustments ('R(x)')
-#define FEEDBACK_R_VAR (0.01f)
-//! parameters used to adjust the variation step size of 'v(x)'
-#define FEEDBACK_V_INCR  (1.000f)
-#define FEEDBACK_V_DECR  (0.100f)
-//! parameters used to scale dynamic learning rate adjustments  ('T(x)')
-#define FEEDBACK_T_DECR  (0.2500f)
-#define FEEDBACK_T_INCR  (0.5000f)
-#define FEEDBACK_T_LOWER (2.0000f)
-#define FEEDBACK_T_UPPER (256.00f)
-//! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values
-#define UNSTABLE_REG_RATIO_MIN (0.100f)
-#define UNSTABLE_REG_RDIST_MIN (3.000f)
-//! parameters used to scale the relative LBSP intensity threshold used for internal comparisons
-#define LBSPDESC_NONZERO_RATIO_MIN (0.100f)
-#define LBSPDESC_NONZERO_RATIO_MAX (0.500f)
-//! parameters used to define model reset/learning rate boosts in our frame-level component
+//using namespace bgslibrary::algorithms::lbsp;
+
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      /*
+       *
+       * Intrinsic parameters for our method are defined here; tuning these for better
+       * performance should not be required in most cases -- although improvements in
+       * very specific scenarios are always possible.
+       *
+       */
+       //! defines the threshold value(s) used to detect long-term ghosting and trigger the fast edge-based absorption heuristic
+      const float GHOSTDET_D_MAX = 0.010f; // defines 'negligible' change here
+      const float GHOSTDET_S_MIN = 0.995f; // defines the required minimum local foreground saturation value
+      //! parameter used to scale dynamic distance threshold adjustments ('R(x)')
+      const float FEEDBACK_R_VAR = 0.01f;
+      //! parameters used to adjust the variation step size of 'v(x)'
+      const float FEEDBACK_V_INCR = 1.000f;
+      const float FEEDBACK_V_DECR = 0.100f;
+      //! parameters used to scale dynamic learning rate adjustments  ('T(x)')
+      const float FEEDBACK_T_DECR = 0.2500f;
+      const float FEEDBACK_T_INCR = 0.5000f;
+      const float FEEDBACK_T_LOWER = 2.0000f;
+      const float FEEDBACK_T_UPPER = 256.00f;
+      //! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values
+      const float UNSTABLE_REG_RATIO_MIN = 0.100f;
+      const float UNSTABLE_REG_RDIST_MIN = 3.000f;
+      //! parameters used to scale the relative LBSP intensity threshold used for internal comparisons
+      const float LBSPDESC_NONZERO_RATIO_MIN = 0.100f;
+      const float LBSPDESC_NONZERO_RATIO_MAX = 0.500f;
+      //! parameters used to define model reset/learning rate boosts in our frame-level component
 #define FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD  (m_nMinColorDistThreshold/2)
-#define FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO (8)
+      const int FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO = 8;
 
-// local define used to display debug information
-#define DISPLAY_SUBSENSE_DEBUG_INFO 0
-// local define used to specify the default frame size (320x240 = QVGA)
+      // local define used to display debug information
+      const int DISPLAY_SUBSENSE_DEBUG_INFO = 0;
+      // local define used to specify the default frame size (320x240 = QVGA)
 #define DEFAULT_FRAME_SIZE cv::Size(320,240)
 // local define used to specify the color dist threshold offset used for unstable regions
 #define STAB_COLOR_DIST_OFFSET (m_nMinColorDistThreshold/5)
 // local define used to specify the desc dist threshold offset used for unstable regions
 #define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset)
 
-static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX;
-static const size_t s_nDescMaxDataRange_1ch = LBSP::DESC_SIZE * 8;
-static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3;
-static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3;
-
-BackgroundSubtractorSuBSENSE::BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold
-  , size_t nDescDistThresholdOffset
-  , size_t nMinColorDistThreshold
-  , size_t nBGSamples
-  , size_t nRequiredBGSamples
-  , size_t nSamplesForMovingAvgs)
-  : BackgroundSubtractorLBSP(fRelLBSPThreshold)
-  , m_nMinColorDistThreshold(nMinColorDistThreshold)
-  , m_nDescDistThresholdOffset(nDescDistThresholdOffset)
-  , m_nBGSamples(nBGSamples)
-  , m_nRequiredBGSamples(nRequiredBGSamples)
-  , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs)
-  , m_fLastNonZeroDescRatio(0.0f)
-  , m_bLearningRateScalingEnabled(true)
-  , m_fCurrLearningRateLowerCap(FEEDBACK_T_LOWER)
-  , m_fCurrLearningRateUpperCap(FEEDBACK_T_UPPER)
-  , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize)
-  , m_bUse3x3Spread(true) {
-  CV_Assert(m_nBGSamples > 0 && m_nRequiredBGSamples <= m_nBGSamples);
-  CV_Assert(m_nMinColorDistThreshold >= STAB_COLOR_DIST_OFFSET);
-}
+      static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX;
+      static const size_t s_nDescMaxDataRange_1ch = LBSP::DESC_SIZE * 8;
+      static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3;
+      static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3;
 
-BackgroundSubtractorSuBSENSE::~BackgroundSubtractorSuBSENSE() {
-  if (m_aPxIdxLUT)
-    delete[] m_aPxIdxLUT;
-  if (m_aPxInfoLUT)
-    delete[] m_aPxInfoLUT;
-}
-
-void BackgroundSubtractorSuBSENSE::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) {
-  // == init
-  CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0);
-  CV_Assert(oInitImg.isContinuous());
-  CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1);
-  if (oInitImg.type() == CV_8UC3) {
-    std::vector<cv::Mat> voInitImgChannels;
-    cv::split(oInitImg, voInitImgChannels);
-    if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1])))
-      std::cout << std::endl << "\tBackgroundSubtractorSuBSENSE : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl;
-  }
-  cv::Mat oNewBGROI;
-  if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) {
-    oNewBGROI.create(oInitImg.size(), CV_8UC1);
-    oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX);
-  }
-  else if (oROI.empty())
-    oNewBGROI = m_oROI;
-  else {
-    CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1);
-    CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0);
-    oNewBGROI = oROI.clone();
-    cv::Mat oTempROI;
-    cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP::PATCH_SIZE / 2);
-    cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI);
-  }
-  const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI);
-  CV_Assert(nOrigROIPxCount > 0);
-  LBSP::validateROI(oNewBGROI);
-  const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI);
-  CV_Assert(nFinalROIPxCount > 0);
-  m_oROI = oNewBGROI;
-  m_oImgSize = oInitImg.size();
-  m_nImgType = oInitImg.type();
-  m_nImgChannels = oInitImg.channels();
-  m_nTotPxCount = m_oImgSize.area();
-  m_nTotRelevantPxCount = nFinalROIPxCount;
-  m_nFrameIndex = 0;
-  m_nFramesSinceLastReset = 0;
-  m_nModelResetCooldown = 0;
-  m_fLastNonZeroDescRatio = 0.0f;
-  const int nTotImgPixels = m_oImgSize.height*m_oImgSize.width;
-  if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) {
-    m_bLearningRateScalingEnabled = true;
-    m_bAutoModelResetEnabled = true;
-    m_bUse3x3Spread = !(nTotImgPixels > DEFAULT_FRAME_SIZE.area() * 2);
-    const int nRawMedianBlurKernelSize = std::min((int)floor((float)nTotImgPixels / DEFAULT_FRAME_SIZE.area() + 0.5f) + m_nDefaultMedianBlurKernelSize, 14);
-    m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1;
-    m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER;
-    m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER;
-  }
-  else {
-    m_bLearningRateScalingEnabled = false;
-    m_bAutoModelResetEnabled = false;
-    m_bUse3x3Spread = true;
-    m_nMedianBlurKernelSize = m_nDefaultMedianBlurKernelSize;
-    m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER * 2;
-    m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER * 2;
-  }
-  m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1);
-  m_oUpdateRateFrame = cv::Scalar(m_fCurrLearningRateLowerCap);
-  m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1);
-  m_oDistThresholdFrame = cv::Scalar(1.0f);
-  m_oVariationModulatorFrame.create(m_oImgSize, CV_32FC1);
-  m_oVariationModulatorFrame = cv::Scalar(10.0f); // should always be >= FEEDBACK_V_DECR
-  m_oMeanLastDistFrame.create(m_oImgSize, CV_32FC1);
-  m_oMeanLastDistFrame = cv::Scalar(0.0f);
-  m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1);
-  m_oMeanMinDistFrame_LT = cv::Scalar(0.0f);
-  m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1);
-  m_oMeanMinDistFrame_ST = cv::Scalar(0.0f);
-  m_oDownSampledFrameSize = cv::Size(m_oImgSize.width / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO);
-  m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels));
-  m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f);
-  m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels));
-  m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f);
-  m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1);
-  m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f);
-  m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1);
-  m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f);
-  m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1);
-  m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f);
-  m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1);
-  m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f);
-  m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1);
-  m_oUnstableRegionMask = cv::Scalar_<uchar>(0);
-  m_oBlinksFrame.create(m_oImgSize, CV_8UC1);
-  m_oBlinksFrame = cv::Scalar_<uchar>(0);
-  m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize, CV_8UC((int)m_nImgChannels));
-  m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0);
-  m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels));
-  m_oLastColorFrame = cv::Scalar_<uchar>::all(0);
-  m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels));
-  m_oLastDescFrame = cv::Scalar_<ushort>::all(0);
-  m_oLastRawFGMask.create(m_oImgSize, CV_8UC1);
-  m_oLastRawFGMask = cv::Scalar_<uchar>(0);
-  m_oLastFGMask.create(m_oImgSize, CV_8UC1);
-  m_oLastFGMask = cv::Scalar_<uchar>(0);
-  m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1);
-  m_oLastFGMask_dilated = cv::Scalar_<uchar>(0);
-  m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1);
-  m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0);
-  m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1);
-  m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0);
-  m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1);
-  m_oFGMask_PreFlood = cv::Scalar_<uchar>(0);
-  m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1);
-  m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0);
-  m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1);
-  m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0);
-  m_voBGColorSamples.resize(m_nBGSamples);
-  m_voBGDescSamples.resize(m_nBGSamples);
-  for (size_t s = 0; s < m_nBGSamples; ++s) {
-    m_voBGColorSamples[s].create(m_oImgSize, CV_8UC((int)m_nImgChannels));
-    m_voBGColorSamples[s] = cv::Scalar_<uchar>::all(0);
-    m_voBGDescSamples[s].create(m_oImgSize, CV_16UC((int)m_nImgChannels));
-    m_voBGDescSamples[s] = cv::Scalar_<ushort>::all(0);
-  }
-  if (m_aPxIdxLUT)
-    delete[] m_aPxIdxLUT;
-  if (m_aPxInfoLUT)
-    delete[] m_aPxInfoLUT;
-  m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount];
-  m_aPxInfoLUT = new PxInfoBase[m_nTotPxCount];
-  if (m_nImgChannels == 1) {
-    CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1);
-    CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2);
-    for (size_t t = 0; t <= UCHAR_MAX; ++t)
-      m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3);
-    for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) {
-      if (m_oROI.data[nPxIter]) {
-        m_aPxIdxLUT[nModelIter] = nPxIter;
-        m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width;
-        m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width;
-        m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter;
-        m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter];
-        const size_t nDescIter = nPxIter * 2;
-        LBSP::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter)));
-        ++nModelIter;
+      BackgroundSubtractorSuBSENSE::BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold
+        , size_t nDescDistThresholdOffset
+        , size_t nMinColorDistThreshold
+        , size_t nBGSamples
+        , size_t nRequiredBGSamples
+        , size_t nSamplesForMovingAvgs)
+        : BackgroundSubtractorLBSP(fRelLBSPThreshold)
+        , m_nMinColorDistThreshold(nMinColorDistThreshold)
+        , m_nDescDistThresholdOffset(nDescDistThresholdOffset)
+        , m_nBGSamples(nBGSamples)
+        , m_nRequiredBGSamples(nRequiredBGSamples)
+        , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs)
+        , m_fLastNonZeroDescRatio(0.0f)
+        , m_bLearningRateScalingEnabled(true)
+        , m_fCurrLearningRateLowerCap(FEEDBACK_T_LOWER)
+        , m_fCurrLearningRateUpperCap(FEEDBACK_T_UPPER)
+        , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize)
+        , m_bUse3x3Spread(true) {
+        CV_Assert(m_nBGSamples > 0 && m_nRequiredBGSamples <= m_nBGSamples);
+        CV_Assert(m_nMinColorDistThreshold >= STAB_COLOR_DIST_OFFSET);
       }
-    }
-  }
-  else { //m_nImgChannels==3
-    CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3);
-    CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2);
-    for (size_t t = 0; t <= UCHAR_MAX; ++t)
-      m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold);
-    for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) {
-      if (m_oROI.data[nPxIter]) {
-        m_aPxIdxLUT[nModelIter] = nPxIter;
-        m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width;
-        m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width;
-        m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter;
-        const size_t nPxRGBIter = nPxIter * 3;
-        const size_t nDescRGBIter = nPxRGBIter * 2;
-        for (size_t c = 0; c < 3; ++c) {
-          m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c];
-          LBSP::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]);
-        }
-        ++nModelIter;
+
+      BackgroundSubtractorSuBSENSE::~BackgroundSubtractorSuBSENSE() {
+        if (m_aPxIdxLUT)
+          delete[] m_aPxIdxLUT;
+        if (m_aPxInfoLUT)
+          delete[] m_aPxInfoLUT;
       }
-    }
-  }
-  m_bInitialized = true;
-  refreshModel(1.0f);
-}
 
-void BackgroundSubtractorSuBSENSE::refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate) {
-  // == refresh
-  CV_Assert(m_bInitialized);
-  CV_Assert(fSamplesRefreshFrac > 0.0f && fSamplesRefreshFrac <= 1.0f);
-  const size_t nModelsToRefresh = fSamplesRefreshFrac < 1.0f ? (size_t)(fSamplesRefreshFrac*m_nBGSamples) : m_nBGSamples;
-  const size_t nRefreshStartPos = fSamplesRefreshFrac < 1.0f ? rand() % m_nBGSamples : 0;
-  if (m_nImgChannels == 1) {
-    for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-      const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-      if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) {
-        for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) {
-          int nSampleImgCoord_Y, nSampleImgCoord_X;
-          getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
-          const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
-          if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) {
-            const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples;
-            m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter] = m_oLastColorFrame.data[nSamplePxIdx];
-            *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + nPxIter * 2)) = *((ushort*)(m_oLastDescFrame.data + nSamplePxIdx * 2));
-          }
+      void BackgroundSubtractorSuBSENSE::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) {
+        // == init
+        CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0);
+        CV_Assert(oInitImg.isContinuous());
+        CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1);
+        if (oInitImg.type() == CV_8UC3) {
+          std::vector<cv::Mat> voInitImgChannels;
+          cv::split(oInitImg, voInitImgChannels);
+          if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1])))
+            std::cout << std::endl << "\tBackgroundSubtractorSuBSENSE : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl;
         }
-      }
-    }
-  }
-  else { //m_nImgChannels==3
-    for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-      const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-      if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) {
-        for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) {
-          int nSampleImgCoord_Y, nSampleImgCoord_X;
-          getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
-          const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
-          if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) {
-            const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples;
-            for (size_t c = 0; c < 3; ++c) {
-              m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter * 3 + c] = m_oLastColorFrame.data[nSamplePxIdx * 3 + c];
-              *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + (nPxIter * 3 + c) * 2)) = *((ushort*)(m_oLastDescFrame.data + (nSamplePxIdx * 3 + c) * 2));
-            }
-          }
+        cv::Mat oNewBGROI;
+        if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) {
+          oNewBGROI.create(oInitImg.size(), CV_8UC1);
+          oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX);
         }
-      }
-    }
-  }
-}
-
-void BackgroundSubtractorSuBSENSE::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) {
-  // == process
-  CV_Assert(m_bInitialized);
-  cv::Mat oInputImg = _image.getMat();
-  CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize);
-  CV_Assert(oInputImg.isContinuous());
-  _fgmask.create(m_oImgSize, CV_8UC1);
-  cv::Mat oCurrFGMask = _fgmask.getMat();
-  memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows);
-  size_t nNonZeroDescCount = 0;
-  const float fRollAvgFactor_LT = 1.0f / std::min(++m_nFrameIndex, m_nSamplesForMovingAvgs);
-  const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, m_nSamplesForMovingAvgs / 4);
-  if (m_nImgChannels == 1) {
-    for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-      const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-      const size_t nDescIter = nPxIter * 2;
-      const size_t nFloatIter = nPxIter * 4;
-      const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X;
-      const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y;
-      const uchar nCurrColor = oInputImg.data[nPxIter];
-      size_t nMinDescDist = s_nDescMaxDataRange_1ch;
-      size_t nMinSumDist = s_nColorMaxDataRange_1ch;
-      float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter);
-      float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter);
-      float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter));
-      float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter));
-      float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter));
-      float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter));
-      float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter));
-      float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter));
-      float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter));
-      float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter));
-      ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter));
-      uchar& nLastColor = m_oLastColorFrame.data[nPxIter];
-      const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET)) / 2;
-      const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET);
-      ushort nCurrInterDesc, nCurrIntraDesc;
-      LBSP::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc);
-      m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0;
-      size_t nGoodSamplesCount = 0, nSampleIdx = 0;
-      while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) {
-        const uchar& nBGColor = m_voBGColorSamples[nSampleIdx].data[nPxIter];
-        {
-          const size_t nColorDist = L1dist(nCurrColor, nBGColor);
-          if (nColorDist > nCurrColorDistThreshold)
-            goto failedcheck1ch;
-          const ushort& nBGIntraDesc = *((ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIter));
-          const size_t nIntraDescDist = hdist(nCurrIntraDesc, nBGIntraDesc);
-          LBSP::computeGrayscaleDescriptor(oInputImg, nBGColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nBGColor], nCurrInterDesc);
-          const size_t nInterDescDist = hdist(nCurrInterDesc, nBGIntraDesc);
-          const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2;
-          if (nDescDist > nCurrDescDistThreshold)
-            goto failedcheck1ch;
-          const size_t nSumDist = std::min((nDescDist / 4)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch);
-          if (nSumDist > nCurrColorDistThreshold)
-            goto failedcheck1ch;
-          if (nMinDescDist > nDescDist)
-            nMinDescDist = nDescDist;
-          if (nMinSumDist > nSumDist)
-            nMinSumDist = nSumDist;
-          nGoodSamplesCount++;
+        else if (oROI.empty())
+          oNewBGROI = m_oROI;
+        else {
+          CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1);
+          CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0);
+          oNewBGROI = oROI.clone();
+          cv::Mat oTempROI;
+          cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP::PATCH_SIZE / 2);
+          cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI);
         }
-      failedcheck1ch:
-        nSampleIdx++;
-      }
-      const float fNormalizedLastDist = ((float)L1dist(nLastColor, nCurrColor) / s_nColorMaxDataRange_1ch + (float)hdist(nLastIntraDesc, nCurrIntraDesc) / s_nDescMaxDataRange_1ch) / 2;
-      *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST;
-      if (nGoodSamplesCount < m_nRequiredBGSamples) {
-        // == foreground
-        const float fNormalizedMinDist = std::min(1.0f, ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples);
-        *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
-        *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
-        *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT;
-        *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST;
-        oCurrFGMask.data[nPxIter] = UCHAR_MAX;
-        if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) {
-          const size_t s_rand = rand() % m_nBGSamples;
-          *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc;
-          m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor;
+        const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI);
+        CV_Assert(nOrigROIPxCount > 0);
+        LBSP::validateROI(oNewBGROI);
+        const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI);
+        CV_Assert(nFinalROIPxCount > 0);
+        m_oROI = oNewBGROI;
+        m_oImgSize = oInitImg.size();
+        m_nImgType = oInitImg.type();
+        m_nImgChannels = oInitImg.channels();
+        m_nTotPxCount = m_oImgSize.area();
+        m_nTotRelevantPxCount = nFinalROIPxCount;
+        m_nFrameIndex = 0;
+        m_nFramesSinceLastReset = 0;
+        m_nModelResetCooldown = 0;
+        m_fLastNonZeroDescRatio = 0.0f;
+        const int nTotImgPixels = m_oImgSize.height*m_oImgSize.width;
+        if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) {
+          m_bLearningRateScalingEnabled = true;
+          m_bAutoModelResetEnabled = true;
+          m_bUse3x3Spread = !(nTotImgPixels > DEFAULT_FRAME_SIZE.area() * 2);
+          const int nRawMedianBlurKernelSize = std::min((int)floor((float)nTotImgPixels / DEFAULT_FRAME_SIZE.area() + 0.5f) + m_nDefaultMedianBlurKernelSize, 14);
+          m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1;
+          m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER;
+          m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER;
         }
-      }
-      else {
-        // == background
-        const float fNormalizedMinDist = ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2;
-        *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
-        *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
-        *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT);
-        *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST);
-        const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate);
-        if ((rand() % nLearningRate) == 0) {
-          const size_t s_rand = rand() % m_nBGSamples;
-          *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc;
-          m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor;
+        else {
+          m_bLearningRateScalingEnabled = false;
+          m_bAutoModelResetEnabled = false;
+          m_bUse3x3Spread = true;
+          m_nMedianBlurKernelSize = m_nDefaultMedianBlurKernelSize;
+          m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER * 2;
+          m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER * 2;
         }
-        int nSampleImgCoord_Y, nSampleImgCoord_X;
-        const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter];
-        if (bCurrUsing3x3Spread)
-          getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
-        else
-          getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
-        const size_t n_rand = rand();
-        const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
-        const size_t idx_rand_flt32 = idx_rand_uchar * 4;
-        const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32));
-        const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32));
-        if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0
-          || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) {
-          const size_t idx_rand_ushrt = idx_rand_uchar * 2;
-          const size_t s_rand = rand() % m_nBGSamples;
-          *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt)) = nCurrIntraDesc;
-          m_voBGColorSamples[s_rand].data[idx_rand_uchar] = nCurrColor;
+        m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1);
+        m_oUpdateRateFrame = cv::Scalar(m_fCurrLearningRateLowerCap);
+        m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1);
+        m_oDistThresholdFrame = cv::Scalar(1.0f);
+        m_oVariationModulatorFrame.create(m_oImgSize, CV_32FC1);
+        m_oVariationModulatorFrame = cv::Scalar(10.0f); // should always be >= FEEDBACK_V_DECR
+        m_oMeanLastDistFrame.create(m_oImgSize, CV_32FC1);
+        m_oMeanLastDistFrame = cv::Scalar(0.0f);
+        m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1);
+        m_oMeanMinDistFrame_LT = cv::Scalar(0.0f);
+        m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1);
+        m_oMeanMinDistFrame_ST = cv::Scalar(0.0f);
+        m_oDownSampledFrameSize = cv::Size(m_oImgSize.width / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO);
+        m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels));
+        m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f);
+        m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels));
+        m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f);
+        m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1);
+        m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f);
+        m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1);
+        m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f);
+        m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1);
+        m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f);
+        m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1);
+        m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f);
+        m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1);
+        m_oUnstableRegionMask = cv::Scalar_<uchar>(0);
+        m_oBlinksFrame.create(m_oImgSize, CV_8UC1);
+        m_oBlinksFrame = cv::Scalar_<uchar>(0);
+        m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize, CV_8UC((int)m_nImgChannels));
+        m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0);
+        m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels));
+        m_oLastColorFrame = cv::Scalar_<uchar>::all(0);
+        m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels));
+        m_oLastDescFrame = cv::Scalar_<ushort>::all(0);
+        m_oLastRawFGMask.create(m_oImgSize, CV_8UC1);
+        m_oLastRawFGMask = cv::Scalar_<uchar>(0);
+        m_oLastFGMask.create(m_oImgSize, CV_8UC1);
+        m_oLastFGMask = cv::Scalar_<uchar>(0);
+        m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1);
+        m_oLastFGMask_dilated = cv::Scalar_<uchar>(0);
+        m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1);
+        m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0);
+        m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1);
+        m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0);
+        m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1);
+        m_oFGMask_PreFlood = cv::Scalar_<uchar>(0);
+        m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1);
+        m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0);
+        m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1);
+        m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0);
+        m_voBGColorSamples.resize(m_nBGSamples);
+        m_voBGDescSamples.resize(m_nBGSamples);
+        for (size_t s = 0; s < m_nBGSamples; ++s) {
+          m_voBGColorSamples[s].create(m_oImgSize, CV_8UC((int)m_nImgChannels));
+          m_voBGColorSamples[s] = cv::Scalar_<uchar>::all(0);
+          m_voBGDescSamples[s].create(m_oImgSize, CV_16UC((int)m_nImgChannels));
+          m_voBGDescSamples[s] = cv::Scalar_<ushort>::all(0);
         }
-      }
-      if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) {
-        if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap)
-          *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor));
-      }
-      else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap)
-        *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST);
-      if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap)
-        *pfCurrLearningRate = m_fCurrLearningRateLowerCap;
-      else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap)
-        *pfCurrLearningRate = m_fCurrLearningRateUpperCap;
-      if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter])
-        (*pfCurrVariationFactor) += FEEDBACK_V_INCR;
-      else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) {
-        (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR;
-        if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR)
-          (*pfCurrVariationFactor) = FEEDBACK_V_DECR;
-      }
-      if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2))
-        (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR);
-      else {
-        (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor);
-        if ((*pfCurrDistThresholdFactor) < 1.0f)
-          (*pfCurrDistThresholdFactor) = 1.0f;
-      }
-      if (popcount(nCurrIntraDesc) >= 2)
-        ++nNonZeroDescCount;
-      nLastIntraDesc = nCurrIntraDesc;
-      nLastColor = nCurrColor;
-    }
-  }
-  else { //m_nImgChannels==3
-    for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
-      const size_t nPxIter = m_aPxIdxLUT[nModelIter];
-      const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X;
-      const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y;
-      const size_t nPxIterRGB = nPxIter * 3;
-      const size_t nDescIterRGB = nPxIterRGB * 2;
-      const size_t nFloatIter = nPxIter * 4;
-      const uchar* const anCurrColor = oInputImg.data + nPxIterRGB;
-      size_t nMinTotDescDist = s_nDescMaxDataRange_3ch;
-      size_t nMinTotSumDist = s_nColorMaxDataRange_3ch;
-      float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter);
-      float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter);
-      float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter));
-      float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter));
-      float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter));
-      float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter));
-      float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter));
-      float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter));
-      float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter));
-      float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter));
-      ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescIterRGB));
-      uchar* anLastColor = m_oLastColorFrame.data + nPxIterRGB;
-      const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET));
-      const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET);
-      const size_t nCurrTotColorDistThreshold = nCurrColorDistThreshold * 3;
-      const size_t nCurrTotDescDistThreshold = nCurrDescDistThreshold * 3;
-      const size_t nCurrSCColorDistThreshold = nCurrTotColorDistThreshold / 2;
-      ushort anCurrInterDesc[3], anCurrIntraDesc[3];
-      const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] };
-      LBSP::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc);
-      m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0;
-      size_t nGoodSamplesCount = 0, nSampleIdx = 0;
-      while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) {
-        const ushort* const anBGIntraDesc = (ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIterRGB);
-        const uchar* const anBGColor = m_voBGColorSamples[nSampleIdx].data + nPxIterRGB;
-        size_t nTotDescDist = 0;
-        size_t nTotSumDist = 0;
-        for (size_t c = 0; c < 3; ++c) {
-          const size_t nColorDist = L1dist(anCurrColor[c], anBGColor[c]);
-          if (nColorDist > nCurrSCColorDistThreshold)
-            goto failedcheck3ch;
-          const size_t nIntraDescDist = hdist(anCurrIntraDesc[c], anBGIntraDesc[c]);
-          LBSP::computeSingleRGBDescriptor(oInputImg, anBGColor[c], nCurrImgCoord_X, nCurrImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[anBGColor[c]], anCurrInterDesc[c]);
-          const size_t nInterDescDist = hdist(anCurrInterDesc[c], anBGIntraDesc[c]);
-          const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2;
-          const size_t nSumDist = std::min((nDescDist / 2)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch);
-          if (nSumDist > nCurrSCColorDistThreshold)
-            goto failedcheck3ch;
-          nTotDescDist += nDescDist;
-          nTotSumDist += nSumDist;
+        if (m_aPxIdxLUT)
+          delete[] m_aPxIdxLUT;
+        if (m_aPxInfoLUT)
+          delete[] m_aPxInfoLUT;
+        m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount];
+        m_aPxInfoLUT = new PxInfoBase[m_nTotPxCount];
+        if (m_nImgChannels == 1) {
+          CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1);
+          CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2);
+          for (size_t t = 0; t <= UCHAR_MAX; ++t)
+            m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3);
+          for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) {
+            if (m_oROI.data[nPxIter]) {
+              m_aPxIdxLUT[nModelIter] = nPxIter;
+              m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width;
+              m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width;
+              m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter;
+              m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter];
+              const size_t nDescIter = nPxIter * 2;
+              LBSP::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter)));
+              ++nModelIter;
+            }
+          }
         }
-        if (nTotDescDist > nCurrTotDescDistThreshold || nTotSumDist > nCurrTotColorDistThreshold)
-          goto failedcheck3ch;
-        if (nMinTotDescDist > nTotDescDist)
-          nMinTotDescDist = nTotDescDist;
-        if (nMinTotSumDist > nTotSumDist)
-          nMinTotSumDist = nTotSumDist;
-        nGoodSamplesCount++;
-      failedcheck3ch:
-        nSampleIdx++;
-      }
-      const float fNormalizedLastDist = ((float)L1dist<3>(anLastColor, anCurrColor) / s_nColorMaxDataRange_3ch + (float)hdist<3>(anLastIntraDesc, anCurrIntraDesc) / s_nDescMaxDataRange_3ch) / 2;
-      *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST;
-      if (nGoodSamplesCount < m_nRequiredBGSamples) {
-        // == foreground
-        const float fNormalizedMinDist = std::min(1.0f, ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples);
-        *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
-        *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
-        *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT;
-        *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST;
-        oCurrFGMask.data[nPxIter] = UCHAR_MAX;
-        if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) {
-          const size_t s_rand = rand() % m_nBGSamples;
-          for (size_t c = 0; c < 3; ++c) {
-            *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c];
-            *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c];
+        else { //m_nImgChannels==3
+          CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3);
+          CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2);
+          for (size_t t = 0; t <= UCHAR_MAX; ++t)
+            m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold);
+          for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) {
+            if (m_oROI.data[nPxIter]) {
+              m_aPxIdxLUT[nModelIter] = nPxIter;
+              m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width;
+              m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width;
+              m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter;
+              const size_t nPxRGBIter = nPxIter * 3;
+              const size_t nDescRGBIter = nPxRGBIter * 2;
+              for (size_t c = 0; c < 3; ++c) {
+                m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c];
+                LBSP::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]);
+              }
+              ++nModelIter;
+            }
           }
         }
+        m_bInitialized = true;
+        refreshModel(1.0f);
       }
-      else {
-        // == background
-        const float fNormalizedMinDist = ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2;
-        *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
-        *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
-        *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT);
-        *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST);
-        const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate);
-        if ((rand() % nLearningRate) == 0) {
-          const size_t s_rand = rand() % m_nBGSamples;
-          for (size_t c = 0; c < 3; ++c) {
-            *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c];
-            *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c];
+
+      void BackgroundSubtractorSuBSENSE::refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate) {
+        // == refresh
+        CV_Assert(m_bInitialized);
+        CV_Assert(fSamplesRefreshFrac > 0.0f && fSamplesRefreshFrac <= 1.0f);
+        const size_t nModelsToRefresh = fSamplesRefreshFrac < 1.0f ? (size_t)(fSamplesRefreshFrac*m_nBGSamples) : m_nBGSamples;
+        const size_t nRefreshStartPos = fSamplesRefreshFrac < 1.0f ? rand() % m_nBGSamples : 0;
+        if (m_nImgChannels == 1) {
+          for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+            const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+            if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) {
+              for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) {
+                int nSampleImgCoord_Y, nSampleImgCoord_X;
+                getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
+                const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
+                if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) {
+                  const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples;
+                  m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter] = m_oLastColorFrame.data[nSamplePxIdx];
+                  *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + nPxIter * 2)) = *((ushort*)(m_oLastDescFrame.data + nSamplePxIdx * 2));
+                }
+              }
+            }
           }
         }
-        int nSampleImgCoord_Y, nSampleImgCoord_X;
-        const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter];
-        if (bCurrUsing3x3Spread)
-          getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
-        else
-          getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
-        const size_t n_rand = rand();
-        const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
-        const size_t idx_rand_flt32 = idx_rand_uchar * 4;
-        const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32));
-        const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32));
-        if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0
-          || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) {
-          const size_t idx_rand_uchar_rgb = idx_rand_uchar * 3;
-          const size_t idx_rand_ushrt_rgb = idx_rand_uchar_rgb * 2;
-          const size_t s_rand = rand() % m_nBGSamples;
-          for (size_t c = 0; c < 3; ++c) {
-            *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt_rgb + 2 * c)) = anCurrIntraDesc[c];
-            *(m_voBGColorSamples[s_rand].data + idx_rand_uchar_rgb + c) = anCurrColor[c];
+        else { //m_nImgChannels==3
+          for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+            const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+            if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) {
+              for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) {
+                int nSampleImgCoord_Y, nSampleImgCoord_X;
+                getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
+                const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
+                if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) {
+                  const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples;
+                  for (size_t c = 0; c < 3; ++c) {
+                    m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter * 3 + c] = m_oLastColorFrame.data[nSamplePxIdx * 3 + c];
+                    *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + (nPxIter * 3 + c) * 2)) = *((ushort*)(m_oLastDescFrame.data + (nSamplePxIdx * 3 + c) * 2));
+                  }
+                }
+              }
+            }
           }
         }
       }
-      if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) {
-        if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap)
-          *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor));
-      }
-      else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap)
-        *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST);
-      if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap)
-        *pfCurrLearningRate = m_fCurrLearningRateLowerCap;
-      else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap)
-        *pfCurrLearningRate = m_fCurrLearningRateUpperCap;
-      if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter])
-        (*pfCurrVariationFactor) += FEEDBACK_V_INCR;
-      else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) {
-        (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR;
-        if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR)
-          (*pfCurrVariationFactor) = FEEDBACK_V_DECR;
-      }
-      if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2))
-        (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR);
-      else {
-        (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor);
-        if ((*pfCurrDistThresholdFactor) < 1.0f)
-          (*pfCurrDistThresholdFactor) = 1.0f;
-      }
-      if (popcount<3>(anCurrIntraDesc) >= 4)
-        ++nNonZeroDescCount;
-      for (size_t c = 0; c < 3; ++c) {
-        anLastIntraDesc[c] = anCurrIntraDesc[c];
-        anLastColor[c] = anCurrColor[c];
-      }
-    }
-  }
+
+      void BackgroundSubtractorSuBSENSE::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) {
+        // == process
+        CV_Assert(m_bInitialized);
+        cv::Mat oInputImg = _image.getMat();
+        CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize);
+        CV_Assert(oInputImg.isContinuous());
+        _fgmask.create(m_oImgSize, CV_8UC1);
+        cv::Mat oCurrFGMask = _fgmask.getMat();
+        memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows);
+        size_t nNonZeroDescCount = 0;
+        const float fRollAvgFactor_LT = 1.0f / std::min(++m_nFrameIndex, m_nSamplesForMovingAvgs);
+        const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, m_nSamplesForMovingAvgs / 4);
+        if (m_nImgChannels == 1) {
+          for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+            const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+            const size_t nDescIter = nPxIter * 2;
+            const size_t nFloatIter = nPxIter * 4;
+            const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X;
+            const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y;
+            const uchar nCurrColor = oInputImg.data[nPxIter];
+            size_t nMinDescDist = s_nDescMaxDataRange_1ch;
+            size_t nMinSumDist = s_nColorMaxDataRange_1ch;
+            float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter);
+            float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter);
+            float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter));
+            float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter));
+            float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter));
+            float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter));
+            float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter));
+            float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter));
+            float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter));
+            float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter));
+            ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter));
+            uchar& nLastColor = m_oLastColorFrame.data[nPxIter];
+            const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET)) / 2;
+            const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET);
+            ushort nCurrInterDesc, nCurrIntraDesc;
+            LBSP::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc);
+            m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0;
+            size_t nGoodSamplesCount = 0, nSampleIdx = 0;
+            while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) {
+              const uchar& nBGColor = m_voBGColorSamples[nSampleIdx].data[nPxIter];
+              {
+                const size_t nColorDist = L1dist(nCurrColor, nBGColor);
+                if (nColorDist > nCurrColorDistThreshold)
+                  goto failedcheck1ch;
+                const ushort& nBGIntraDesc = *((ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIter));
+                const size_t nIntraDescDist = hdist(nCurrIntraDesc, nBGIntraDesc);
+                LBSP::computeGrayscaleDescriptor(oInputImg, nBGColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nBGColor], nCurrInterDesc);
+                const size_t nInterDescDist = hdist(nCurrInterDesc, nBGIntraDesc);
+                const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2;
+                if (nDescDist > nCurrDescDistThreshold)
+                  goto failedcheck1ch;
+                const size_t nSumDist = std::min((nDescDist / 4)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch);
+                if (nSumDist > nCurrColorDistThreshold)
+                  goto failedcheck1ch;
+                if (nMinDescDist > nDescDist)
+                  nMinDescDist = nDescDist;
+                if (nMinSumDist > nSumDist)
+                  nMinSumDist = nSumDist;
+                nGoodSamplesCount++;
+              }
+            failedcheck1ch:
+              nSampleIdx++;
+            }
+            const float fNormalizedLastDist = ((float)L1dist(nLastColor, nCurrColor) / s_nColorMaxDataRange_1ch + (float)hdist(nLastIntraDesc, nCurrIntraDesc) / s_nDescMaxDataRange_1ch) / 2;
+            *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST;
+            if (nGoodSamplesCount < m_nRequiredBGSamples) {
+              // == foreground
+              const float fNormalizedMinDist = std::min(1.0f, ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples);
+              *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
+              *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
+              *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT;
+              *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST;
+              oCurrFGMask.data[nPxIter] = UCHAR_MAX;
+              if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) {
+                const size_t s_rand = rand() % m_nBGSamples;
+                *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc;
+                m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor;
+              }
+            }
+            else {
+              // == background
+              const float fNormalizedMinDist = ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2;
+              *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
+              *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
+              *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT);
+              *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST);
+              const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate);
+              if ((rand() % nLearningRate) == 0) {
+                const size_t s_rand = rand() % m_nBGSamples;
+                *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc;
+                m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor;
+              }
+              int nSampleImgCoord_Y, nSampleImgCoord_X;
+              const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter];
+              if (bCurrUsing3x3Spread)
+                getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
+              else
+                getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
+              const size_t n_rand = rand();
+              const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
+              const size_t idx_rand_flt32 = idx_rand_uchar * 4;
+              const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32));
+              const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32));
+              if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0
+                || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) {
+                const size_t idx_rand_ushrt = idx_rand_uchar * 2;
+                const size_t s_rand = rand() % m_nBGSamples;
+                *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt)) = nCurrIntraDesc;
+                m_voBGColorSamples[s_rand].data[idx_rand_uchar] = nCurrColor;
+              }
+            }
+            if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) {
+              if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap)
+                *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor));
+            }
+            else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap)
+              *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST);
+            if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap)
+              *pfCurrLearningRate = m_fCurrLearningRateLowerCap;
+            else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap)
+              *pfCurrLearningRate = m_fCurrLearningRateUpperCap;
+            if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter])
+              (*pfCurrVariationFactor) += FEEDBACK_V_INCR;
+            else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) {
+              (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR;
+              if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR)
+                (*pfCurrVariationFactor) = FEEDBACK_V_DECR;
+            }
+            if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2))
+              (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR);
+            else {
+              (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor);
+              if ((*pfCurrDistThresholdFactor) < 1.0f)
+                (*pfCurrDistThresholdFactor) = 1.0f;
+            }
+            if (popcount(nCurrIntraDesc) >= 2)
+              ++nNonZeroDescCount;
+            nLastIntraDesc = nCurrIntraDesc;
+            nLastColor = nCurrColor;
+          }
+        }
+        else { //m_nImgChannels==3
+          for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) {
+            const size_t nPxIter = m_aPxIdxLUT[nModelIter];
+            const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X;
+            const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y;
+            const size_t nPxIterRGB = nPxIter * 3;
+            const size_t nDescIterRGB = nPxIterRGB * 2;
+            const size_t nFloatIter = nPxIter * 4;
+            const uchar* const anCurrColor = oInputImg.data + nPxIterRGB;
+            size_t nMinTotDescDist = s_nDescMaxDataRange_3ch;
+            size_t nMinTotSumDist = s_nColorMaxDataRange_3ch;
+            float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter);
+            float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter);
+            float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter));
+            float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter));
+            float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter));
+            float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter));
+            float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter));
+            float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter));
+            float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter));
+            float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter));
+            ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescIterRGB));
+            uchar* anLastColor = m_oLastColorFrame.data + nPxIterRGB;
+            const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET));
+            const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET);
+            const size_t nCurrTotColorDistThreshold = nCurrColorDistThreshold * 3;
+            const size_t nCurrTotDescDistThreshold = nCurrDescDistThreshold * 3;
+            const size_t nCurrSCColorDistThreshold = nCurrTotColorDistThreshold / 2;
+            ushort anCurrInterDesc[3], anCurrIntraDesc[3];
+            const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] };
+            LBSP::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc);
+            m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0;
+            size_t nGoodSamplesCount = 0, nSampleIdx = 0;
+            while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) {
+              const ushort* const anBGIntraDesc = (ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIterRGB);
+              const uchar* const anBGColor = m_voBGColorSamples[nSampleIdx].data + nPxIterRGB;
+              size_t nTotDescDist = 0;
+              size_t nTotSumDist = 0;
+              for (size_t c = 0; c < 3; ++c) {
+                const size_t nColorDist = L1dist(anCurrColor[c], anBGColor[c]);
+                if (nColorDist > nCurrSCColorDistThreshold)
+                  goto failedcheck3ch;
+                const size_t nIntraDescDist = hdist(anCurrIntraDesc[c], anBGIntraDesc[c]);
+                LBSP::computeSingleRGBDescriptor(oInputImg, anBGColor[c], nCurrImgCoord_X, nCurrImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[anBGColor[c]], anCurrInterDesc[c]);
+                const size_t nInterDescDist = hdist(anCurrInterDesc[c], anBGIntraDesc[c]);
+                const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2;
+                const size_t nSumDist = std::min((nDescDist / 2)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch);
+                if (nSumDist > nCurrSCColorDistThreshold)
+                  goto failedcheck3ch;
+                nTotDescDist += nDescDist;
+                nTotSumDist += nSumDist;
+              }
+              if (nTotDescDist > nCurrTotDescDistThreshold || nTotSumDist > nCurrTotColorDistThreshold)
+                goto failedcheck3ch;
+              if (nMinTotDescDist > nTotDescDist)
+                nMinTotDescDist = nTotDescDist;
+              if (nMinTotSumDist > nTotSumDist)
+                nMinTotSumDist = nTotSumDist;
+              nGoodSamplesCount++;
+            failedcheck3ch:
+              nSampleIdx++;
+            }
+            const float fNormalizedLastDist = ((float)L1dist<3>(anLastColor, anCurrColor) / s_nColorMaxDataRange_3ch + (float)hdist<3>(anLastIntraDesc, anCurrIntraDesc) / s_nDescMaxDataRange_3ch) / 2;
+            *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST;
+            if (nGoodSamplesCount < m_nRequiredBGSamples) {
+              // == foreground
+              const float fNormalizedMinDist = std::min(1.0f, ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples);
+              *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
+              *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
+              *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT;
+              *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST;
+              oCurrFGMask.data[nPxIter] = UCHAR_MAX;
+              if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) {
+                const size_t s_rand = rand() % m_nBGSamples;
+                for (size_t c = 0; c < 3; ++c) {
+                  *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c];
+                  *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c];
+                }
+              }
+            }
+            else {
+              // == background
+              const float fNormalizedMinDist = ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2;
+              *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT;
+              *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST;
+              *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT);
+              *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST);
+              const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate);
+              if ((rand() % nLearningRate) == 0) {
+                const size_t s_rand = rand() % m_nBGSamples;
+                for (size_t c = 0; c < 3; ++c) {
+                  *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c];
+                  *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c];
+                }
+              }
+              int nSampleImgCoord_Y, nSampleImgCoord_X;
+              const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter];
+              if (bCurrUsing3x3Spread)
+                getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
+              else
+                getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize);
+              const size_t n_rand = rand();
+              const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X;
+              const size_t idx_rand_flt32 = idx_rand_uchar * 4;
+              const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32));
+              const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32));
+              if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0
+                || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) {
+                const size_t idx_rand_uchar_rgb = idx_rand_uchar * 3;
+                const size_t idx_rand_ushrt_rgb = idx_rand_uchar_rgb * 2;
+                const size_t s_rand = rand() % m_nBGSamples;
+                for (size_t c = 0; c < 3; ++c) {
+                  *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt_rgb + 2 * c)) = anCurrIntraDesc[c];
+                  *(m_voBGColorSamples[s_rand].data + idx_rand_uchar_rgb + c) = anCurrColor[c];
+                }
+              }
+            }
+            if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) {
+              if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap)
+                *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor));
+            }
+            else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap)
+              *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST);
+            if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap)
+              *pfCurrLearningRate = m_fCurrLearningRateLowerCap;
+            else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap)
+              *pfCurrLearningRate = m_fCurrLearningRateUpperCap;
+            if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter])
+              (*pfCurrVariationFactor) += FEEDBACK_V_INCR;
+            else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) {
+              (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR;
+              if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR)
+                (*pfCurrVariationFactor) = FEEDBACK_V_DECR;
+            }
+            if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2))
+              (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR);
+            else {
+              (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor);
+              if ((*pfCurrDistThresholdFactor) < 1.0f)
+                (*pfCurrDistThresholdFactor) = 1.0f;
+            }
+            if (popcount<3>(anCurrIntraDesc) >= 4)
+              ++nNonZeroDescCount;
+            for (size_t c = 0; c < 3; ++c) {
+              anLastIntraDesc[c] = anCurrIntraDesc[c];
+              anLastColor[c] = anCurrColor[c];
+            }
+          }
+        }
 #if DISPLAY_SUBSENSE_DEBUG_INFO
-  std::cout << std::endl;
-  cv::Point dbgpt(nDebugCoordX, nDebugCoordY);
-  cv::Mat oMeanMinDistFrameNormalized; m_oMeanMinDistFrame_ST.copyTo(oMeanMinDistFrameNormalized);
-  cv::circle(oMeanMinDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
-  cv::resize(oMeanMinDistFrameNormalized, oMeanMinDistFrameNormalized, DEFAULT_FRAME_SIZE);
-  cv::imshow("d_min(x)", oMeanMinDistFrameNormalized);
-  std::cout << std::fixed << std::setprecision(5) << "  d_min(" << dbgpt << ") = " << m_oMeanMinDistFrame_ST.at<float>(dbgpt) << std::endl;
-  cv::Mat oMeanLastDistFrameNormalized; m_oMeanLastDistFrame.copyTo(oMeanLastDistFrameNormalized);
-  cv::circle(oMeanLastDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
-  cv::resize(oMeanLastDistFrameNormalized, oMeanLastDistFrameNormalized, DEFAULT_FRAME_SIZE);
-  cv::imshow("d_last(x)", oMeanLastDistFrameNormalized);
-  std::cout << std::fixed << std::setprecision(5) << " d_last(" << dbgpt << ") = " << m_oMeanLastDistFrame.at<float>(dbgpt) << std::endl;
-  cv::Mat oMeanRawSegmResFrameNormalized; m_oMeanRawSegmResFrame_ST.copyTo(oMeanRawSegmResFrameNormalized);
-  cv::circle(oMeanRawSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
-  cv::resize(oMeanRawSegmResFrameNormalized, oMeanRawSegmResFrameNormalized, DEFAULT_FRAME_SIZE);
-  cv::imshow("s_avg(x)", oMeanRawSegmResFrameNormalized);
-  std::cout << std::fixed << std::setprecision(5) << "  s_avg(" << dbgpt << ") = " << m_oMeanRawSegmResFrame_ST.at<float>(dbgpt) << std::endl;
-  cv::Mat oMeanFinalSegmResFrameNormalized; m_oMeanFinalSegmResFrame_ST.copyTo(oMeanFinalSegmResFrameNormalized);
-  cv::circle(oMeanFinalSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
-  cv::resize(oMeanFinalSegmResFrameNormalized, oMeanFinalSegmResFrameNormalized, DEFAULT_FRAME_SIZE);
-  cv::imshow("z_avg(x)", oMeanFinalSegmResFrameNormalized);
-  std::cout << std::fixed << std::setprecision(5) << "  z_avg(" << dbgpt << ") = " << m_oMeanFinalSegmResFrame_ST.at<float>(dbgpt) << std::endl;
-  cv::Mat oDistThresholdFrameNormalized; m_oDistThresholdFrame.convertTo(oDistThresholdFrameNormalized, CV_32FC1, 0.25f, -0.25f);
-  cv::circle(oDistThresholdFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
-  cv::resize(oDistThresholdFrameNormalized, oDistThresholdFrameNormalized, DEFAULT_FRAME_SIZE);
-  cv::imshow("r(x)", oDistThresholdFrameNormalized);
-  std::cout << std::fixed << std::setprecision(5) << "      r(" << dbgpt << ") = " << m_oDistThresholdFrame.at<float>(dbgpt) << std::endl;
-  cv::Mat oVariationModulatorFrameNormalized; cv::normalize(m_oVariationModulatorFrame, oVariationModulatorFrameNormalized, 0, 255, cv::NORM_MINMAX, CV_8UC1);
-  cv::circle(oVariationModulatorFrameNormalized, dbgpt, 5, cv::Scalar(255));
-  cv::resize(oVariationModulatorFrameNormalized, oVariationModulatorFrameNormalized, DEFAULT_FRAME_SIZE);
-  cv::imshow("v(x)", oVariationModulatorFrameNormalized);
-  std::cout << std::fixed << std::setprecision(5) << "      v(" << dbgpt << ") = " << m_oVariationModulatorFrame.at<float>(dbgpt) << std::endl;
-  cv::Mat oUpdateRateFrameNormalized; m_oUpdateRateFrame.convertTo(oUpdateRateFrameNormalized, CV_32FC1, 1.0f / FEEDBACK_T_UPPER, -FEEDBACK_T_LOWER / FEEDBACK_T_UPPER);
-  cv::circle(oUpdateRateFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
-  cv::resize(oUpdateRateFrameNormalized, oUpdateRateFrameNormalized, DEFAULT_FRAME_SIZE);
-  cv::imshow("t(x)", oUpdateRateFrameNormalized);
-  std::cout << std::fixed << std::setprecision(5) << "      t(" << dbgpt << ") = " << m_oUpdateRateFrame.at<float>(dbgpt) << std::endl;
+        std::cout << std::endl;
+        cv::Point dbgpt(nDebugCoordX, nDebugCoordY);
+        cv::Mat oMeanMinDistFrameNormalized; m_oMeanMinDistFrame_ST.copyTo(oMeanMinDistFrameNormalized);
+        cv::circle(oMeanMinDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
+        cv::resize(oMeanMinDistFrameNormalized, oMeanMinDistFrameNormalized, DEFAULT_FRAME_SIZE);
+        cv::imshow("d_min(x)", oMeanMinDistFrameNormalized);
+        std::cout << std::fixed << std::setprecision(5) << "  d_min(" << dbgpt << ") = " << m_oMeanMinDistFrame_ST.at<float>(dbgpt) << std::endl;
+        cv::Mat oMeanLastDistFrameNormalized; m_oMeanLastDistFrame.copyTo(oMeanLastDistFrameNormalized);
+        cv::circle(oMeanLastDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
+        cv::resize(oMeanLastDistFrameNormalized, oMeanLastDistFrameNormalized, DEFAULT_FRAME_SIZE);
+        cv::imshow("d_last(x)", oMeanLastDistFrameNormalized);
+        std::cout << std::fixed << std::setprecision(5) << " d_last(" << dbgpt << ") = " << m_oMeanLastDistFrame.at<float>(dbgpt) << std::endl;
+        cv::Mat oMeanRawSegmResFrameNormalized; m_oMeanRawSegmResFrame_ST.copyTo(oMeanRawSegmResFrameNormalized);
+        cv::circle(oMeanRawSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
+        cv::resize(oMeanRawSegmResFrameNormalized, oMeanRawSegmResFrameNormalized, DEFAULT_FRAME_SIZE);
+        cv::imshow("s_avg(x)", oMeanRawSegmResFrameNormalized);
+        std::cout << std::fixed << std::setprecision(5) << "  s_avg(" << dbgpt << ") = " << m_oMeanRawSegmResFrame_ST.at<float>(dbgpt) << std::endl;
+        cv::Mat oMeanFinalSegmResFrameNormalized; m_oMeanFinalSegmResFrame_ST.copyTo(oMeanFinalSegmResFrameNormalized);
+        cv::circle(oMeanFinalSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
+        cv::resize(oMeanFinalSegmResFrameNormalized, oMeanFinalSegmResFrameNormalized, DEFAULT_FRAME_SIZE);
+        cv::imshow("z_avg(x)", oMeanFinalSegmResFrameNormalized);
+        std::cout << std::fixed << std::setprecision(5) << "  z_avg(" << dbgpt << ") = " << m_oMeanFinalSegmResFrame_ST.at<float>(dbgpt) << std::endl;
+        cv::Mat oDistThresholdFrameNormalized; m_oDistThresholdFrame.convertTo(oDistThresholdFrameNormalized, CV_32FC1, 0.25f, -0.25f);
+        cv::circle(oDistThresholdFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
+        cv::resize(oDistThresholdFrameNormalized, oDistThresholdFrameNormalized, DEFAULT_FRAME_SIZE);
+        cv::imshow("r(x)", oDistThresholdFrameNormalized);
+        std::cout << std::fixed << std::setprecision(5) << "      r(" << dbgpt << ") = " << m_oDistThresholdFrame.at<float>(dbgpt) << std::endl;
+        cv::Mat oVariationModulatorFrameNormalized; cv::normalize(m_oVariationModulatorFrame, oVariationModulatorFrameNormalized, 0, 255, cv::NORM_MINMAX, CV_8UC1);
+        cv::circle(oVariationModulatorFrameNormalized, dbgpt, 5, cv::Scalar(255));
+        cv::resize(oVariationModulatorFrameNormalized, oVariationModulatorFrameNormalized, DEFAULT_FRAME_SIZE);
+        cv::imshow("v(x)", oVariationModulatorFrameNormalized);
+        std::cout << std::fixed << std::setprecision(5) << "      v(" << dbgpt << ") = " << m_oVariationModulatorFrame.at<float>(dbgpt) << std::endl;
+        cv::Mat oUpdateRateFrameNormalized; m_oUpdateRateFrame.convertTo(oUpdateRateFrameNormalized, CV_32FC1, 1.0f / FEEDBACK_T_UPPER, -FEEDBACK_T_LOWER / FEEDBACK_T_UPPER);
+        cv::circle(oUpdateRateFrameNormalized, dbgpt, 5, cv::Scalar(1.0f));
+        cv::resize(oUpdateRateFrameNormalized, oUpdateRateFrameNormalized, DEFAULT_FRAME_SIZE);
+        cv::imshow("t(x)", oUpdateRateFrameNormalized);
+        std::cout << std::fixed << std::setprecision(5) << "      t(" << dbgpt << ") = " << m_oUpdateRateFrame.at<float>(dbgpt) << std::endl;
 #endif //DISPLAY_SUBSENSE_DEBUG_INFO
-  cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask);
-  cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame);
-  m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask);
-  oCurrFGMask.copyTo(m_oLastRawFGMask);
-  cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, cv::Mat());
-  m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles);
-  cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX);
-  cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles);
-  cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3);
-  cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask);
-  cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask);
-  cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize);
-  cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3);
-  cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame);
-  cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted);
-  cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame);
-  m_oLastFGMask.copyTo(oCurrFGMask);
-  cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F);
-  cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F);
-  const float fCurrNonZeroDescRatio = (float)nNonZeroDescCount / m_nTotRelevantPxCount;
-  if (fCurrNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN && m_fLastNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN) {
-    for (size_t t = 0; t <= UCHAR_MAX; ++t)
-      if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + ceil(t*m_fRelLBSPThreshold / 4)))
-        --m_anLBSPThreshold_8bitLUT[t];
-  }
-  else if (fCurrNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX && m_fLastNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX) {
-    for (size_t t = 0; t <= UCHAR_MAX; ++t)
-      if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold))
-        ++m_anLBSPThreshold_8bitLUT[t];
-  }
-  m_fLastNonZeroDescRatio = fCurrNonZeroDescRatio;
-  if (m_bLearningRateScalingEnabled) {
-    cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize, 0, 0, cv::INTER_AREA);
-    cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT);
-    cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST);
-    size_t nTotColorDiff = 0;
-    for (int i = 0; i < m_oMeanDownSampledLastDistFrame_ST.rows; ++i) {
-      const size_t idx1 = m_oMeanDownSampledLastDistFrame_ST.step.p[0] * i;
-      for (int j = 0; j < m_oMeanDownSampledLastDistFrame_ST.cols; ++j) {
-        const size_t idx2 = idx1 + m_oMeanDownSampledLastDistFrame_ST.step.p[1] * j;
-        nTotColorDiff += (m_nImgChannels == 1) ?
-          (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))) / 2
-          :  //(m_nImgChannels==3)
-          std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))),
-            std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 4)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 4))),
-            (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 8)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 8)))));
-      }
-    }
-    const float fCurrColorDiffRatio = (float)nTotColorDiff / (m_oMeanDownSampledLastDistFrame_ST.rows*m_oMeanDownSampledLastDistFrame_ST.cols);
-    if (m_bAutoModelResetEnabled) {
-      if (m_nFramesSinceLastReset > 1000)
-        m_bAutoModelResetEnabled = false;
-      else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD && m_nModelResetCooldown == 0) {
-        m_nFramesSinceLastReset = 0;
-        refreshModel(0.1f); // reset 10% of the bg model
-        m_nModelResetCooldown = m_nSamplesForMovingAvgs / 4;
-        m_oUpdateRateFrame = cv::Scalar(1.0f);
+        cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask);
+        cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame);
+        m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask);
+        oCurrFGMask.copyTo(m_oLastRawFGMask);
+        cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, cv::Mat());
+        m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles);
+        cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX);
+        cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles);
+        cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3);
+        cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask);
+        cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask);
+        cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize);
+        cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3);
+        cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame);
+        cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted);
+        cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame);
+        m_oLastFGMask.copyTo(oCurrFGMask);
+        cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F);
+        cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F);
+        const float fCurrNonZeroDescRatio = (float)nNonZeroDescCount / m_nTotRelevantPxCount;
+        if (fCurrNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN && m_fLastNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN) {
+          for (size_t t = 0; t <= UCHAR_MAX; ++t)
+            if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + ceil(t*m_fRelLBSPThreshold / 4)))
+              --m_anLBSPThreshold_8bitLUT[t];
+        }
+        else if (fCurrNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX && m_fLastNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX) {
+          for (size_t t = 0; t <= UCHAR_MAX; ++t)
+            if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold))
+              ++m_anLBSPThreshold_8bitLUT[t];
+        }
+        m_fLastNonZeroDescRatio = fCurrNonZeroDescRatio;
+        if (m_bLearningRateScalingEnabled) {
+          cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize, 0, 0, cv::INTER_AREA);
+          cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT);
+          cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST);
+          size_t nTotColorDiff = 0;
+          for (int i = 0; i < m_oMeanDownSampledLastDistFrame_ST.rows; ++i) {
+            const size_t idx1 = m_oMeanDownSampledLastDistFrame_ST.step.p[0] * i;
+            for (int j = 0; j < m_oMeanDownSampledLastDistFrame_ST.cols; ++j) {
+              const size_t idx2 = idx1 + m_oMeanDownSampledLastDistFrame_ST.step.p[1] * j;
+              nTotColorDiff += (m_nImgChannels == 1) ?
+                (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))) / 2
+                :  //(m_nImgChannels==3)
+                std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))),
+                  std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 4)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 4))),
+                  (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 8)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 8)))));
+            }
+          }
+          const float fCurrColorDiffRatio = (float)nTotColorDiff / (m_oMeanDownSampledLastDistFrame_ST.rows*m_oMeanDownSampledLastDistFrame_ST.cols);
+          if (m_bAutoModelResetEnabled) {
+            if (m_nFramesSinceLastReset > 1000)
+              m_bAutoModelResetEnabled = false;
+            else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD && m_nModelResetCooldown == 0) {
+              m_nFramesSinceLastReset = 0;
+              refreshModel(0.1f); // reset 10% of the bg model
+              m_nModelResetCooldown = m_nSamplesForMovingAvgs / 4;
+              m_oUpdateRateFrame = cv::Scalar(1.0f);
+            }
+            else
+              ++m_nFramesSinceLastReset;
+          }
+          else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD * 2) {
+            m_nFramesSinceLastReset = 0;
+            m_bAutoModelResetEnabled = true;
+          }
+          if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD / 2) {
+            m_fCurrLearningRateLowerCap = (float)std::max((int)FEEDBACK_T_LOWER >> (int)(fCurrColorDiffRatio / 2), 1);
+            m_fCurrLearningRateUpperCap = (float)std::max((int)FEEDBACK_T_UPPER >> (int)(fCurrColorDiffRatio / 2), 1);
+          }
+          else {
+            m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER;
+            m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER;
+          }
+          if (m_nModelResetCooldown > 0)
+            --m_nModelResetCooldown;
+        }
       }
-      else
-        ++m_nFramesSinceLastReset;
-    }
-    else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD * 2) {
-      m_nFramesSinceLastReset = 0;
-      m_bAutoModelResetEnabled = true;
-    }
-    if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD / 2) {
-      m_fCurrLearningRateLowerCap = (float)std::max((int)FEEDBACK_T_LOWER >> (int)(fCurrColorDiffRatio / 2), 1);
-      m_fCurrLearningRateUpperCap = (float)std::max((int)FEEDBACK_T_UPPER >> (int)(fCurrColorDiffRatio / 2), 1);
-    }
-    else {
-      m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER;
-      m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER;
-    }
-    if (m_nModelResetCooldown > 0)
-      --m_nModelResetCooldown;
-  }
-}
 
-void BackgroundSubtractorSuBSENSE::getBackgroundImage(cv::OutputArray backgroundImage) const {
-  CV_Assert(m_bInitialized);
-  cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels));
-  for (size_t s = 0; s < m_nBGSamples; ++s) {
-    for (int y = 0; y < m_oImgSize.height; ++y) {
-      for (int x = 0; x < m_oImgSize.width; ++x) {
-        const size_t idx_nimg = m_voBGColorSamples[s].step.p[0] * y + m_voBGColorSamples[s].step.p[1] * x;
-        const size_t nFloatIter = idx_nimg * 4;
-        float* oAvgBgImgPtr = (float*)(oAvgBGImg.data + nFloatIter);
-        const uchar* const oBGImgPtr = m_voBGColorSamples[s].data + idx_nimg;
-        for (size_t c = 0; c < m_nImgChannels; ++c)
-          oAvgBgImgPtr[c] += ((float)oBGImgPtr[c]) / m_nBGSamples;
+      void BackgroundSubtractorSuBSENSE::getBackgroundImage(cv::OutputArray backgroundImage) const {
+        CV_Assert(m_bInitialized);
+        cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels));
+        for (size_t s = 0; s < m_nBGSamples; ++s) {
+          for (int y = 0; y < m_oImgSize.height; ++y) {
+            for (int x = 0; x < m_oImgSize.width; ++x) {
+              const size_t idx_nimg = m_voBGColorSamples[s].step.p[0] * y + m_voBGColorSamples[s].step.p[1] * x;
+              const size_t nFloatIter = idx_nimg * 4;
+              float* oAvgBgImgPtr = (float*)(oAvgBGImg.data + nFloatIter);
+              const uchar* const oBGImgPtr = m_voBGColorSamples[s].data + idx_nimg;
+              for (size_t c = 0; c < m_nImgChannels; ++c)
+                oAvgBgImgPtr[c] += ((float)oBGImgPtr[c]) / m_nBGSamples;
+            }
+          }
+        }
+        oAvgBGImg.convertTo(backgroundImage, CV_8U);
       }
-    }
-  }
-  oAvgBGImg.convertTo(backgroundImage, CV_8U);
-}
 
-void BackgroundSubtractorSuBSENSE::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const {
-  CV_Assert(LBSP::DESC_SIZE == 2);
-  CV_Assert(m_bInitialized);
-  cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels));
-  for (size_t n = 0; n < m_voBGDescSamples.size(); ++n) {
-    for (int y = 0; y < m_oImgSize.height; ++y) {
-      for (int x = 0; x < m_oImgSize.width; ++x) {
-        const size_t idx_ndesc = m_voBGDescSamples[n].step.p[0] * y + m_voBGDescSamples[n].step.p[1] * x;
-        const size_t nFloatIter = idx_ndesc * 2;
-        float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data + nFloatIter);
-        const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data + idx_ndesc);
-        for (size_t c = 0; c < m_nImgChannels; ++c)
-          oAvgBgDescPtr[c] += ((float)oBGDescPtr[c]) / m_voBGDescSamples.size();
+      void BackgroundSubtractorSuBSENSE::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const {
+        CV_Assert(LBSP::DESC_SIZE == 2);
+        CV_Assert(m_bInitialized);
+        cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels));
+        for (size_t n = 0; n < m_voBGDescSamples.size(); ++n) {
+          for (int y = 0; y < m_oImgSize.height; ++y) {
+            for (int x = 0; x < m_oImgSize.width; ++x) {
+              const size_t idx_ndesc = m_voBGDescSamples[n].step.p[0] * y + m_voBGDescSamples[n].step.p[1] * x;
+              const size_t nFloatIter = idx_ndesc * 2;
+              float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data + nFloatIter);
+              const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data + idx_ndesc);
+              for (size_t c = 0; c < m_nImgChannels; ++c)
+                oAvgBgDescPtr[c] += ((float)oBGDescPtr[c]) / m_voBGDescSamples.size();
+            }
+          }
+        }
+        oAvgBGDesc.convertTo(backgroundDescImage, CV_16U);
       }
     }
   }
-  oAvgBGDesc.convertTo(backgroundDescImage, CV_16U);
 }
diff --git a/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.h b/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.h
index 48c0a0d89312820db330b17c08c4a11997a7e42f..9ec95e1e0825a24102ebbf34e2dff12470604b2b 100644
--- a/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.h
+++ b/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.h
@@ -2,112 +2,120 @@
 
 #include "BackgroundSubtractorLBSP.h"
 
-//! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold
-#define BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.333f)
-//! defines the default value for BackgroundSubtractorSuBSENSE::m_nDescDistThresholdOffset
-#define BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET (3)
-//! defines the default value for BackgroundSubtractorSuBSENSE::m_nMinColorDistThreshold
-#define BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD (30)
-//! defines the default value for BackgroundSubtractorSuBSENSE::m_nBGSamples
-#define BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES (50)
-//! defines the default value for BackgroundSubtractorSuBSENSE::m_nRequiredBGSamples
-#define BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES (2)
-//! defines the default value for BackgroundSubtractorSuBSENSE::m_nSamplesForMovingAvgs
-#define BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS (100)
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      //! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold
+      const float BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD = 0.333f;
+      //! defines the default value for BackgroundSubtractorSuBSENSE::m_nDescDistThresholdOffset
+      const int BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET = 3;
+      //! defines the default value for BackgroundSubtractorSuBSENSE::m_nMinColorDistThreshold
+      const int BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD = 30;
+      //! defines the default value for BackgroundSubtractorSuBSENSE::m_nBGSamples
+      const int BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES = 50;
+      //! defines the default value for BackgroundSubtractorSuBSENSE::m_nRequiredBGSamples
+      const int BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES = 2;
+      //! defines the default value for BackgroundSubtractorSuBSENSE::m_nSamplesForMovingAvgs
+      const int BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS = 100;
 
-/*!
-  Self-Balanced Sensitivity segmenTER (SuBSENSE) change detection algorithm.
+      /*!
+        Self-Balanced Sensitivity segmenTER (SuBSENSE) change detection algorithm.
 
-  Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically).
-  For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3.
+        Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically).
+        For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3.
 
-  For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al.,
-  "Flexible Background Subtraction With Self-Balanced Local Sensitivity", in CVPRW 2014.
+        For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al.,
+        "Flexible Background Subtraction With Self-Balanced Local Sensitivity", in CVPRW 2014.
 
-  This algorithm is currently NOT thread-safe.
- */
-class BackgroundSubtractorSuBSENSE : public BackgroundSubtractorLBSP {
-public:
-  //! full constructor
-  BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold = BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD,
-    size_t nDescDistThresholdOffset = BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET,
-    size_t nMinColorDistThreshold = BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD,
-    size_t nBGSamples = BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES,
-    size_t nRequiredBGSamples = BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES,
-    size_t nSamplesForMovingAvgs = BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS);
-  //! default destructor
-  virtual ~BackgroundSubtractorSuBSENSE();
-  //! (re)initiaization method; needs to be called before starting background subtraction
-  virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI);
-  //! refreshes all samples based on the last analyzed frame
-  virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false);
-  //! primary model update function; the learning param is used to override the internal learning thresholds (ignored when <= 0)
-  virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0);
-  //! returns a copy of the latest reconstructed background image
-  void getBackgroundImage(cv::OutputArray backgroundImage) const;
-  //! returns a copy of the latest reconstructed background descriptors image
-  void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const;
+        This algorithm is currently NOT thread-safe.
+      */
+      class BackgroundSubtractorSuBSENSE : public BackgroundSubtractorLBSP {
+      public:
+        //! full constructor
+        BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold = BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD,
+          size_t nDescDistThresholdOffset = BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET,
+          size_t nMinColorDistThreshold = BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD,
+          size_t nBGSamples = BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES,
+          size_t nRequiredBGSamples = BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES,
+          size_t nSamplesForMovingAvgs = BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS);
+        //! default destructor
+        virtual ~BackgroundSubtractorSuBSENSE();
+        //! (re)initiaization method; needs to be called before starting background subtraction
+        virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI);
+        //! refreshes all samples based on the last analyzed frame
+        virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false);
+        //! primary model update function; the learning param is used to override the internal learning thresholds (ignored when <= 0)
+        virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0);
+        //! returns a copy of the latest reconstructed background image
+        void getBackgroundImage(cv::OutputArray backgroundImage) const;
+        //! returns a copy of the latest reconstructed background descriptors image
+        void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const;
 
-protected:
-  //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here)
-  const size_t m_nMinColorDistThreshold;
-  //! absolute descriptor distance threshold offset
-  const size_t m_nDescDistThresholdOffset;
-  //! number of different samples per pixel/block to be taken from input frames to build the background model (same as 'N' in ViBe/PBAS)
-  const size_t m_nBGSamples;
-  //! number of similar samples needed to consider the current pixel/block as 'background' (same as '#_min' in ViBe/PBAS)
-  const size_t m_nRequiredBGSamples;
-  //! number of samples to use to compute the learning rate of moving averages
-  const size_t m_nSamplesForMovingAvgs;
-  //! last calculated non-zero desc ratio
-  float m_fLastNonZeroDescRatio;
-  //! specifies whether Tmin/Tmax scaling is enabled or not
-  bool m_bLearningRateScalingEnabled;
-  //! current learning rate caps
-  float m_fCurrLearningRateLowerCap, m_fCurrLearningRateUpperCap;
-  //! current kernel size for median blur post-proc filtering
-  int m_nMedianBlurKernelSize;
-  //! specifies the px update spread range
-  bool m_bUse3x3Spread;
-  //! specifies the downsampled frame size used for cam motion analysis
-  cv::Size m_oDownSampledFrameSize;
+      protected:
+        //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here)
+        const size_t m_nMinColorDistThreshold;
+        //! absolute descriptor distance threshold offset
+        const size_t m_nDescDistThresholdOffset;
+        //! number of different samples per pixel/block to be taken from input frames to build the background model (same as 'N' in ViBe/PBAS)
+        const size_t m_nBGSamples;
+        //! number of similar samples needed to consider the current pixel/block as 'background' (same as '#_min' in ViBe/PBAS)
+        const size_t m_nRequiredBGSamples;
+        //! number of samples to use to compute the learning rate of moving averages
+        const size_t m_nSamplesForMovingAvgs;
+        //! last calculated non-zero desc ratio
+        float m_fLastNonZeroDescRatio;
+        //! specifies whether Tmin/Tmax scaling is enabled or not
+        bool m_bLearningRateScalingEnabled;
+        //! current learning rate caps
+        float m_fCurrLearningRateLowerCap, m_fCurrLearningRateUpperCap;
+        //! current kernel size for median blur post-proc filtering
+        int m_nMedianBlurKernelSize;
+        //! specifies the px update spread range
+        bool m_bUse3x3Spread;
+        //! specifies the downsampled frame size used for cam motion analysis
+        cv::Size m_oDownSampledFrameSize;
 
-  //! background model pixel color intensity samples (equivalent to 'B(x)' in PBAS)
-  std::vector<cv::Mat> m_voBGColorSamples;
-  //! background model descriptors samples
-  std::vector<cv::Mat> m_voBGDescSamples;
+        //! background model pixel color intensity samples (equivalent to 'B(x)' in PBAS)
+        std::vector<cv::Mat> m_voBGColorSamples;
+        //! background model descriptors samples
+        std::vector<cv::Mat> m_voBGDescSamples;
 
-  //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe)
-  cv::Mat m_oUpdateRateFrame;
-  //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds)
-  cv::Mat m_oDistThresholdFrame;
-  //! per-pixel distance variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations)
-  cv::Mat m_oVariationModulatorFrame;
-  //! per-pixel mean distances between consecutive frames ('D_last(x)', used to detect ghosts and high variation regions in the sequence)
-  cv::Mat m_oMeanLastDistFrame;
-  //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)')
-  cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST;
-  //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and control max learning rates globally)
-  cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST;
-  //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions)
-  cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST;
-  //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions)
-  cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST;
-  //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds)
-  cv::Mat m_oUnstableRegionMask;
-  //! per-pixel blink detection map ('Z(x)')
-  cv::Mat m_oBlinksFrame;
-  //! pre-allocated matrix used to downsample the input frame when needed
-  cv::Mat m_oDownSampledFrame_MotionAnalysis;
-  //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection)
-  cv::Mat m_oLastRawFGMask;
-
-  //! pre-allocated CV_8UC1 matrices used to speed up morph ops
-  cv::Mat m_oFGMask_PreFlood;
-  cv::Mat m_oFGMask_FloodedHoles;
-  cv::Mat m_oLastFGMask_dilated;
-  cv::Mat m_oLastFGMask_dilated_inverted;
-  cv::Mat m_oCurrRawFGBlinkMask;
-  cv::Mat m_oLastRawFGBlinkMask;
-};
+        //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe)
+        cv::Mat m_oUpdateRateFrame;
+        //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds)
+        cv::Mat m_oDistThresholdFrame;
+        //! per-pixel distance variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations)
+        cv::Mat m_oVariationModulatorFrame;
+        //! per-pixel mean distances between consecutive frames ('D_last(x)', used to detect ghosts and high variation regions in the sequence)
+        cv::Mat m_oMeanLastDistFrame;
+        //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)')
+        cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST;
+        //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and control max learning rates globally)
+        cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST;
+        //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions)
+        cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST;
+        //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions)
+        cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST;
+        //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds)
+        cv::Mat m_oUnstableRegionMask;
+        //! per-pixel blink detection map ('Z(x)')
+        cv::Mat m_oBlinksFrame;
+        //! pre-allocated matrix used to downsample the input frame when needed
+        cv::Mat m_oDownSampledFrame_MotionAnalysis;
+        //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection)
+        cv::Mat m_oLastRawFGMask;
 
+        //! pre-allocated CV_8UC1 matrices used to speed up morph ops
+        cv::Mat m_oFGMask_PreFlood;
+        cv::Mat m_oFGMask_FloodedHoles;
+        cv::Mat m_oLastFGMask_dilated;
+        cv::Mat m_oLastFGMask_dilated_inverted;
+        cv::Mat m_oCurrRawFGBlinkMask;
+        cv::Mat m_oLastRawFGBlinkMask;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBSP/DistanceUtils.h b/src/algorithms/LBSP/DistanceUtils.h
index 124d4bcc73009bce8a31a1ed16e0bed826792b81..59a0fe1b96cd248b7811ab7a2857227fed6a2e9a 100644
--- a/src/algorithms/LBSP/DistanceUtils.h
+++ b/src/algorithms/LBSP/DistanceUtils.h
@@ -1,316 +1,326 @@
 #pragma once
 
+// opencv legacy includes
 #include <opencv2/core/types_c.h>
 
-//! computes the L1 distance between two integer values
-template<typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type L1dist(T a, T b) {
-  return (size_t)abs((int)a-b);
-}
-
-//! computes the L1 distance between two float values
-template<typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type L1dist(T a, T b) {
-  return fabs((float)a-(float)b);
-}
-
-//! computes the L1 distance between two generic arrays
-template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b) -> decltype(L1dist(*a,*b)) {
-  decltype(L1dist(*a,*b)) oResult = 0;
-  for(size_t c=0; c<nChannels; ++c)
-    oResult += L1dist(a[c],b[c]);
-  return oResult;
-}
-
-//! computes the L1 distance between two generic arrays
-template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L1dist<nChannels>(a,b)) {
-  decltype(L1dist<nChannels>(a,b)) oResult = 0;
-  size_t nTotElements = nElements*nChannels;
-  if(m) {
-    for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
-      if(m[i])
-        oResult += L1dist<nChannels>(a+n,b+n);
-  }
-  else {
-    for(size_t n=0; n<nTotElements; n+=nChannels)
-      oResult += L1dist<nChannels>(a+n,b+n);
-  }
-  return oResult;
-}
-
-//! computes the L1 distance between two generic arrays
-template<typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L1dist<3>(a,b,nElements,m)) {
-  CV_Assert(nChannels>0 && nChannels<=4);
-  switch(nChannels) {
-  case 1: return L1dist<1>(a,b,nElements,m);
-  case 2: return L1dist<2>(a,b,nElements,m);
-  case 3: return L1dist<3>(a,b,nElements,m);
-  case 4: return L1dist<4>(a,b,nElements,m);
-  default: return 0;
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      //! computes the L1 distance between two integer values
+      template<typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type L1dist(T a, T b) {
+        return (size_t)abs((int)a-b);
+      }
+
+      //! computes the L1 distance between two float values
+      template<typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type L1dist(T a, T b) {
+        return fabs((float)a-(float)b);
+      }
+
+      //! computes the L1 distance between two generic arrays
+      template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b) -> decltype(L1dist(*a,*b)) {
+        decltype(L1dist(*a,*b)) oResult = 0;
+        for(size_t c=0; c<nChannels; ++c)
+          oResult += L1dist(a[c],b[c]);
+        return oResult;
+      }
+
+      //! computes the L1 distance between two generic arrays
+      template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L1dist<nChannels>(a,b)) {
+        decltype(L1dist<nChannels>(a,b)) oResult = 0;
+        size_t nTotElements = nElements*nChannels;
+        if(m) {
+          for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
+            if(m[i])
+              oResult += L1dist<nChannels>(a+n,b+n);
+        }
+        else {
+          for(size_t n=0; n<nTotElements; n+=nChannels)
+            oResult += L1dist<nChannels>(a+n,b+n);
+        }
+        return oResult;
+      }
+
+      //! computes the L1 distance between two generic arrays
+      template<typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L1dist<3>(a,b,nElements,m)) {
+        CV_Assert(nChannels>0 && nChannels<=4);
+        switch(nChannels) {
+        case 1: return L1dist<1>(a,b,nElements,m);
+        case 2: return L1dist<2>(a,b,nElements,m);
+        case 3: return L1dist<3>(a,b,nElements,m);
+        case 4: return L1dist<4>(a,b,nElements,m);
+        default: return 0;
+        }
+      }
+
+      //! computes the L1 distance between two opencv vectors
+      template<size_t nChannels, typename T> static inline auto L1dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L1dist<nChannels,T>((T*)(0),(T*)(0))) {
+        T a_array[nChannels], b_array[nChannels];
+        for(size_t c=0; c<nChannels; ++c) {
+          a_array[c] = a[(int)c];
+          b_array[c] = b[(int)c];
+        }
+        return L1dist<nChannels>(a_array,b_array);
+      }
+
+      ///////////////////////////////////////////////////////////////////////////////////////////////////
+
+      //! computes the squared L2 distance between two generic variables
+      template<typename T> static inline auto L2sqrdist(T a, T b) -> decltype(L1dist(a,b)) {
+        auto oResult = L1dist(a,b);
+        return oResult*oResult;
+      }
+
+      //! computes the squared L2 distance between two generic arrays
+      template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b) -> decltype(L2sqrdist(*a,*b)) {
+        decltype(L2sqrdist(*a,*b)) oResult = 0;
+        for(size_t c=0; c<nChannels; ++c)
+          oResult += L2sqrdist(a[c],b[c]);
+        return oResult;
+      }
+
+      //! computes the squared L2 distance between two generic arrays
+      template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L2sqrdist<nChannels>(a,b)) {
+        decltype(L2sqrdist<nChannels>(a,b)) oResult = 0;
+        size_t nTotElements = nElements*nChannels;
+        if(m) {
+          for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
+            if(m[i])
+              oResult += L2sqrdist<nChannels>(a+n,b+n);
+        }
+        else {
+          for(size_t n=0; n<nTotElements; n+=nChannels)
+            oResult += L2sqrdist<nChannels>(a+n,b+n);
+        }
+        return oResult;
+      }
+
+      //! computes the squared L2 distance between two generic arrays
+      template<typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L2sqrdist<3>(a,b,nElements,m)) {
+        CV_Assert(nChannels>0 && nChannels<=4);
+        switch(nChannels) {
+        case 1: return L2sqrdist<1>(a,b,nElements,m);
+        case 2: return L2sqrdist<2>(a,b,nElements,m);
+        case 3: return L2sqrdist<3>(a,b,nElements,m);
+        case 4: return L2sqrdist<4>(a,b,nElements,m);
+        default: return 0;
+        }
+      }
+
+      //! computes the squared L2 distance between two opencv vectors
+      template<size_t nChannels, typename T> static inline auto L2sqrdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L2sqrdist<nChannels,T>((T*)(0),(T*)(0))) {
+        T a_array[nChannels], b_array[nChannels];
+        for(size_t c=0; c<nChannels; ++c) {
+          a_array[c] = a[(int)c];
+          b_array[c] = b[(int)c];
+        }
+        return L2sqrdist<nChannels>(a_array,b_array);
+      }
+
+      //! computes the L2 distance between two generic arrays
+      template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b) {
+        decltype(L2sqrdist(*a,*b)) oResult = 0;
+        for(size_t c=0; c<nChannels; ++c)
+          oResult += L2sqrdist(a[c],b[c]);
+        return sqrt((float)oResult);
+      }
+
+      //! computes the L2 distance between two generic arrays
+      template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) {
+        decltype(L2sqrdist<nChannels>(a,b)) oResult = 0;
+        size_t nTotElements = nElements*nChannels;
+        if(m) {
+          for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
+            if(m[i])
+              oResult += L2sqrdist<nChannels>(a+n,b+n);
+        }
+        else {
+          for(size_t n=0; n<nTotElements; n+=nChannels)
+            oResult += L2sqrdist<nChannels>(a+n,b+n);
+        }
+        return sqrt((float)oResult);
+      }
+
+      //! computes the squared L2 distance between two generic arrays
+      template<typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) {
+        CV_Assert(nChannels>0 && nChannels<=4);
+        switch(nChannels) {
+        case 1: return L2dist<1>(a,b,nElements,m);
+        case 2: return L2dist<2>(a,b,nElements,m);
+        case 3: return L2dist<3>(a,b,nElements,m);
+        case 4: return L2dist<4>(a,b,nElements,m);
+        default: return 0;
+        }
+      }
+
+      //! computes the L2 distance between two opencv vectors
+      template<size_t nChannels, typename T> static inline float L2dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) {
+        T a_array[nChannels], b_array[nChannels];
+        for(size_t c=0; c<nChannels; ++c) {
+          a_array[c] = a[(int)c];
+          b_array[c] = b[(int)c];
+        }
+        return L2dist<nChannels>(a_array,b_array);
+      }
+
+      ///////////////////////////////////////////////////////////////////////////////////////////////////
+
+      //! computes the color distortion between two integer arrays
+      template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cdist(const T* curr, const T* bg) {
+        static_assert(nChannels>1,"cdist: requires more than one channel");
+        size_t curr_sqr = 0;
+        bool bSkip = true;
+        for(size_t c=0; c<nChannels; ++c) {
+          curr_sqr += curr[c]*curr[c];
+          bSkip = bSkip&(bg[c]<=0);
+        }
+        if(bSkip)
+          return (size_t)sqrt((float)curr_sqr);
+        size_t bg_sqr = 0;
+        size_t mix = 0;
+        for(size_t c=0; c<nChannels; ++c) {
+          bg_sqr += bg[c]*bg[c];
+          mix += curr[c]*bg[c];
+        }
+        return (size_t)sqrt(curr_sqr-((float)(mix*mix)/bg_sqr));
+      }
+
+      //! computes the color distortion between two float arrays
+      template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cdist(const T* curr, const T* bg) {
+        static_assert(nChannels>1,"cdist: requires more than one channel");
+        float curr_sqr = 0;
+        bool bSkip = true;
+        for(size_t c=0; c<nChannels; ++c) {
+          curr_sqr += (float)curr[c]*curr[c];
+          bSkip = bSkip&(bg[c]<=0);
+        }
+        if(bSkip)
+          return sqrt(curr_sqr);
+        float bg_sqr = 0;
+        float mix = 0;
+        for(size_t c=0; c<nChannels; ++c) {
+          bg_sqr += (float)bg[c]*bg[c];
+          mix += (float)curr[c]*bg[c];
+        }
+        return sqrt(curr_sqr-((mix*mix)/bg_sqr));
+      }
+
+      //! computes the color distortion between two generic arrays
+      template<size_t nChannels, typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(cdist<nChannels>(a,b)) {
+        decltype(cdist<nChannels>(a,b)) oResult = 0;
+        size_t nTotElements = nElements*nChannels;
+        if(m) {
+          for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
+            if(m[i])
+              oResult += cdist<nChannels>(a+n,b+n);
+        }
+        else {
+          for(size_t n=0; n<nTotElements; n+=nChannels)
+            oResult += cdist<nChannels>(a+n,b+n);
+        }
+        return oResult;
+      }
+
+      //! computes the color distortion between two generic arrays
+      template<typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(cdist<3>(a,b,nElements,m)) {
+        CV_Assert(nChannels>1 && nChannels<=4);
+        switch(nChannels) {
+        case 2: return cdist<2>(a,b,nElements,m);
+        case 3: return cdist<3>(a,b,nElements,m);
+        case 4: return cdist<4>(a,b,nElements,m);
+        default: return 0;
+        }
+      }
+
+      //! computes the color distortion between two opencv vectors
+      template<size_t nChannels, typename T> static inline auto cdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(cdist<nChannels,T>((T*)(0),(T*)(0))) {
+        T a_array[nChannels], b_array[nChannels];
+        for(size_t c=0; c<nChannels; ++c) {
+          a_array[c] = a[(int)c];
+          b_array[c] = b[(int)c];
+        }
+        return cdist<nChannels>(a_array,b_array);
+      }
+
+      //! computes a color distortion-distance mix using two generic distances
+      template<typename T> static inline T cmixdist(T oL1Distance, T oCDistortion) {
+        return (oL1Distance/2+oCDistortion*4);
+      }
+
+      //! computes a color distoirtion-distance mix using two generic arrays
+      template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cmixdist(const T* curr, const T* bg) {
+        return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg));
+      }
+
+      template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cmixdist(const T* curr, const T* bg) {
+        return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg));
+      }
+
+      ///////////////////////////////////////////////////////////////////////////////////////////////////
+
+      //! popcount LUT for 8-bit vectors
+      static const uchar popcount_LUT8[256] = {
+        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+      };
+
+      //! computes the population count of an N-byte vector using an 8-bit popcount LUT
+      template<typename T> static inline size_t popcount(T x) {
+        size_t nBytes = sizeof(T);
+        size_t nResult = 0;
+        for(size_t l=0; l<nBytes; ++l)
+          nResult += popcount_LUT8[(uchar)(x>>l*8)];
+        return nResult;
+      }
+
+      //! computes the hamming distance between two N-byte vectors using an 8-bit popcount LUT
+      template<typename T> static inline size_t hdist(T a, T b) {
+        return popcount(a^b);
+      }
+
+      //! computes the gradient magnitude distance between two N-byte vectors using an 8-bit popcount LUT
+      template<typename T> static inline size_t gdist(T a, T b) {
+        return L1dist(popcount(a),popcount(b));
+      }
+
+      //! computes the population count of a (nChannels*N)-byte vector using an 8-bit popcount LUT
+      template<size_t nChannels, typename T> static inline size_t popcount(const T* x) {
+        size_t nBytes = sizeof(T);
+        size_t nResult = 0;
+        for(size_t c=0; c<nChannels; ++c)
+          for(size_t l=0; l<nBytes; ++l)
+            nResult += popcount_LUT8[(uchar)(*(x+c)>>l*8)];
+        return nResult;
+      }
+
+      //! computes the hamming distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT
+      template<size_t nChannels, typename T> static inline size_t hdist(const T* a, const T* b) {
+        T xor_array[nChannels];
+        for(size_t c=0; c<nChannels; ++c)
+          xor_array[c] = a[c]^b[c];
+        return popcount<nChannels>(xor_array);
+      }
+
+      //! computes the gradient magnitude distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT
+      template<size_t nChannels, typename T> static inline size_t gdist(const T* a, const T* b) {
+        return L1dist(popcount<nChannels>(a),popcount<nChannels>(b));
+      }
+    }
   }
 }
-
-//! computes the L1 distance between two opencv vectors
-template<size_t nChannels, typename T> static inline auto L1dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L1dist<nChannels,T>((T*)(0),(T*)(0))) {
-  T a_array[nChannels], b_array[nChannels];
-  for(size_t c=0; c<nChannels; ++c) {
-    a_array[c] = a[(int)c];
-    b_array[c] = b[(int)c];
-  }
-  return L1dist<nChannels>(a_array,b_array);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-//! computes the squared L2 distance between two generic variables
-template<typename T> static inline auto L2sqrdist(T a, T b) -> decltype(L1dist(a,b)) {
-  auto oResult = L1dist(a,b);
-  return oResult*oResult;
-}
-
-//! computes the squared L2 distance between two generic arrays
-template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b) -> decltype(L2sqrdist(*a,*b)) {
-  decltype(L2sqrdist(*a,*b)) oResult = 0;
-  for(size_t c=0; c<nChannels; ++c)
-    oResult += L2sqrdist(a[c],b[c]);
-  return oResult;
-}
-
-//! computes the squared L2 distance between two generic arrays
-template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L2sqrdist<nChannels>(a,b)) {
-  decltype(L2sqrdist<nChannels>(a,b)) oResult = 0;
-  size_t nTotElements = nElements*nChannels;
-  if(m) {
-    for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
-      if(m[i])
-        oResult += L2sqrdist<nChannels>(a+n,b+n);
-  }
-  else {
-    for(size_t n=0; n<nTotElements; n+=nChannels)
-      oResult += L2sqrdist<nChannels>(a+n,b+n);
-  }
-  return oResult;
-}
-
-//! computes the squared L2 distance between two generic arrays
-template<typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L2sqrdist<3>(a,b,nElements,m)) {
-  CV_Assert(nChannels>0 && nChannels<=4);
-  switch(nChannels) {
-  case 1: return L2sqrdist<1>(a,b,nElements,m);
-  case 2: return L2sqrdist<2>(a,b,nElements,m);
-  case 3: return L2sqrdist<3>(a,b,nElements,m);
-  case 4: return L2sqrdist<4>(a,b,nElements,m);
-  default: return 0;
-  }
-}
-
-//! computes the squared L2 distance between two opencv vectors
-template<size_t nChannels, typename T> static inline auto L2sqrdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L2sqrdist<nChannels,T>((T*)(0),(T*)(0))) {
-  T a_array[nChannels], b_array[nChannels];
-  for(size_t c=0; c<nChannels; ++c) {
-    a_array[c] = a[(int)c];
-    b_array[c] = b[(int)c];
-  }
-  return L2sqrdist<nChannels>(a_array,b_array);
-}
-
-//! computes the L2 distance between two generic arrays
-template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b) {
-  decltype(L2sqrdist(*a,*b)) oResult = 0;
-  for(size_t c=0; c<nChannels; ++c)
-    oResult += L2sqrdist(a[c],b[c]);
-  return sqrt((float)oResult);
-}
-
-//! computes the L2 distance between two generic arrays
-template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) {
-  decltype(L2sqrdist<nChannels>(a,b)) oResult = 0;
-  size_t nTotElements = nElements*nChannels;
-  if(m) {
-    for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
-      if(m[i])
-        oResult += L2sqrdist<nChannels>(a+n,b+n);
-  }
-  else {
-    for(size_t n=0; n<nTotElements; n+=nChannels)
-      oResult += L2sqrdist<nChannels>(a+n,b+n);
-  }
-  return sqrt((float)oResult);
-}
-
-//! computes the squared L2 distance between two generic arrays
-template<typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) {
-  CV_Assert(nChannels>0 && nChannels<=4);
-  switch(nChannels) {
-  case 1: return L2dist<1>(a,b,nElements,m);
-  case 2: return L2dist<2>(a,b,nElements,m);
-  case 3: return L2dist<3>(a,b,nElements,m);
-  case 4: return L2dist<4>(a,b,nElements,m);
-  default: return 0;
-  }
-}
-
-//! computes the L2 distance between two opencv vectors
-template<size_t nChannels, typename T> static inline float L2dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) {
-  T a_array[nChannels], b_array[nChannels];
-  for(size_t c=0; c<nChannels; ++c) {
-    a_array[c] = a[(int)c];
-    b_array[c] = b[(int)c];
-  }
-  return L2dist<nChannels>(a_array,b_array);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-//! computes the color distortion between two integer arrays
-template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cdist(const T* curr, const T* bg) {
-  static_assert(nChannels>1,"cdist: requires more than one channel");
-  size_t curr_sqr = 0;
-  bool bSkip = true;
-  for(size_t c=0; c<nChannels; ++c) {
-    curr_sqr += curr[c]*curr[c];
-    bSkip = bSkip&(bg[c]<=0);
-  }
-  if(bSkip)
-    return (size_t)sqrt((float)curr_sqr);
-  size_t bg_sqr = 0;
-  size_t mix = 0;
-  for(size_t c=0; c<nChannels; ++c) {
-    bg_sqr += bg[c]*bg[c];
-    mix += curr[c]*bg[c];
-  }
-  return (size_t)sqrt(curr_sqr-((float)(mix*mix)/bg_sqr));
-}
-
-//! computes the color distortion between two float arrays
-template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cdist(const T* curr, const T* bg) {
-  static_assert(nChannels>1,"cdist: requires more than one channel");
-  float curr_sqr = 0;
-  bool bSkip = true;
-  for(size_t c=0; c<nChannels; ++c) {
-    curr_sqr += (float)curr[c]*curr[c];
-    bSkip = bSkip&(bg[c]<=0);
-  }
-  if(bSkip)
-    return sqrt(curr_sqr);
-  float bg_sqr = 0;
-  float mix = 0;
-  for(size_t c=0; c<nChannels; ++c) {
-    bg_sqr += (float)bg[c]*bg[c];
-    mix += (float)curr[c]*bg[c];
-  }
-  return sqrt(curr_sqr-((mix*mix)/bg_sqr));
-}
-
-//! computes the color distortion between two generic arrays
-template<size_t nChannels, typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(cdist<nChannels>(a,b)) {
-  decltype(cdist<nChannels>(a,b)) oResult = 0;
-  size_t nTotElements = nElements*nChannels;
-  if(m) {
-    for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
-      if(m[i])
-        oResult += cdist<nChannels>(a+n,b+n);
-  }
-  else {
-    for(size_t n=0; n<nTotElements; n+=nChannels)
-      oResult += cdist<nChannels>(a+n,b+n);
-  }
-  return oResult;
-}
-
-//! computes the color distortion between two generic arrays
-template<typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(cdist<3>(a,b,nElements,m)) {
-  CV_Assert(nChannels>1 && nChannels<=4);
-  switch(nChannels) {
-  case 2: return cdist<2>(a,b,nElements,m);
-  case 3: return cdist<3>(a,b,nElements,m);
-  case 4: return cdist<4>(a,b,nElements,m);
-  default: return 0;
-  }
-}
-
-//! computes the color distortion between two opencv vectors
-template<size_t nChannels, typename T> static inline auto cdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(cdist<nChannels,T>((T*)(0),(T*)(0))) {
-  T a_array[nChannels], b_array[nChannels];
-  for(size_t c=0; c<nChannels; ++c) {
-    a_array[c] = a[(int)c];
-    b_array[c] = b[(int)c];
-  }
-  return cdist<nChannels>(a_array,b_array);
-}
-
-//! computes a color distortion-distance mix using two generic distances
-template<typename T> static inline T cmixdist(T oL1Distance, T oCDistortion) {
-  return (oL1Distance/2+oCDistortion*4);
-}
-
-//! computes a color distoirtion-distance mix using two generic arrays
-template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cmixdist(const T* curr, const T* bg) {
-  return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg));
-}
-
-template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cmixdist(const T* curr, const T* bg) {
-  return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg));
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-//! popcount LUT for 8-bit vectors
-static const uchar popcount_LUT8[256] = {
-  0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
-  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-  4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
-};
-
-//! computes the population count of an N-byte vector using an 8-bit popcount LUT
-template<typename T> static inline size_t popcount(T x) {
-  size_t nBytes = sizeof(T);
-  size_t nResult = 0;
-  for(size_t l=0; l<nBytes; ++l)
-    nResult += popcount_LUT8[(uchar)(x>>l*8)];
-  return nResult;
-}
-
-//! computes the hamming distance between two N-byte vectors using an 8-bit popcount LUT
-template<typename T> static inline size_t hdist(T a, T b) {
-  return popcount(a^b);
-}
-
-//! computes the gradient magnitude distance between two N-byte vectors using an 8-bit popcount LUT
-template<typename T> static inline size_t gdist(T a, T b) {
-  return L1dist(popcount(a),popcount(b));
-}
-
-//! computes the population count of a (nChannels*N)-byte vector using an 8-bit popcount LUT
-template<size_t nChannels, typename T> static inline size_t popcount(const T* x) {
-  size_t nBytes = sizeof(T);
-  size_t nResult = 0;
-  for(size_t c=0; c<nChannels; ++c)
-    for(size_t l=0; l<nBytes; ++l)
-      nResult += popcount_LUT8[(uchar)(*(x+c)>>l*8)];
-  return nResult;
-}
-
-//! computes the hamming distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT
-template<size_t nChannels, typename T> static inline size_t hdist(const T* a, const T* b) {
-  T xor_array[nChannels];
-  for(size_t c=0; c<nChannels; ++c)
-    xor_array[c] = a[c]^b[c];
-  return popcount<nChannels>(xor_array);
-}
-
-//! computes the gradient magnitude distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT
-template<size_t nChannels, typename T> static inline size_t gdist(const T* a, const T* b) {
-  return L1dist(popcount<nChannels>(a),popcount<nChannels>(b));
-}
diff --git a/src/algorithms/LBSP/LBSP.cpp b/src/algorithms/LBSP/LBSP.cpp
index 5f5a57a68f76e9ed0b03222d5989c4bd938acf37..b965112cde62d8e1990e8f8adad914eedbfc3fff 100644
--- a/src/algorithms/LBSP/LBSP.cpp
+++ b/src/algorithms/LBSP/LBSP.cpp
@@ -1,318 +1,329 @@
 #include "LBSP.h"
 
-LBSP::LBSP(size_t nThreshold)
-  : m_bOnlyUsingAbsThreshold(true)
-  , m_fRelThreshold(0) // unused
-  , m_nThreshold(nThreshold)
-  , m_oRefImage() {}
+//using namespace bgslibrary::algorithms::lbsp;
 
-LBSP::LBSP(float fRelThreshold, size_t nThresholdOffset)
-  : m_bOnlyUsingAbsThreshold(false)
-  , m_fRelThreshold(fRelThreshold)
-  , m_nThreshold(nThresholdOffset)
-  , m_oRefImage() {
-  CV_Assert(m_fRelThreshold >= 0);
-}
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      LBSP::LBSP(size_t nThreshold)
+        : m_bOnlyUsingAbsThreshold(true)
+        , m_fRelThreshold(0) // unused
+        , m_nThreshold(nThreshold)
+        , m_oRefImage() {}
 
-LBSP::~LBSP() {}
+      LBSP::LBSP(float fRelThreshold, size_t nThresholdOffset)
+        : m_bOnlyUsingAbsThreshold(false)
+        , m_fRelThreshold(fRelThreshold)
+        , m_nThreshold(nThresholdOffset)
+        , m_oRefImage() {
+        CV_Assert(m_fRelThreshold >= 0);
+      }
 
-void LBSP::read(const cv::FileNode& /*fn*/) {
-  // ... = fn["..."];
-}
+      LBSP::~LBSP() {}
 
-void LBSP::write(cv::FileStorage& /*fs*/) const {
-  //fs << "..." << ...;
-}
+      void LBSP::read(const cv::FileNode& /*fn*/) {
+        // ... = fn["..."];
+      }
 
-void LBSP::setReference(const cv::Mat& img) {
-  CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3);
-  m_oRefImage = img;
-}
+      void LBSP::write(cv::FileStorage& /*fs*/) const {
+        //fs << "..." << ...;
+      }
 
-int LBSP::descriptorSize() const {
-  return DESC_SIZE;
-}
+      void LBSP::setReference(const cv::Mat& img) {
+        CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3);
+        m_oRefImage = img;
+      }
 
-int LBSP::descriptorType() const {
-  return CV_16U;
-}
+      int LBSP::descriptorSize() const {
+        return DESC_SIZE;
+      }
 
-bool LBSP::isUsingRelThreshold() const {
-  return !m_bOnlyUsingAbsThreshold;
-}
+      int LBSP::descriptorType() const {
+        return CV_16U;
+      }
 
-float LBSP::getRelThreshold() const {
-  return m_fRelThreshold;
-}
+      bool LBSP::isUsingRelThreshold() const {
+        return !m_bOnlyUsingAbsThreshold;
+      }
 
-size_t LBSP::getAbsThreshold() const {
-  return m_nThreshold;
-}
+      float LBSP::getRelThreshold() const {
+        return m_fRelThreshold;
+      }
 
-static inline void lbsp_computeImpl(const cv::Mat& oInputImg,
-  const cv::Mat& oRefImg,
-  const std::vector<cv::KeyPoint>& voKeyPoints,
-  cv::Mat& oDesc,
-  size_t _t) {
-  CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
-  CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
-  CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  const size_t nChannels = (size_t)oInputImg.channels();
-  const size_t _step_row = oInputImg.step.p[0];
-  const uchar* _data = oInputImg.data;
-  const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
-  const size_t nKeyPoints = voKeyPoints.size();
-  if (nChannels == 1) {
-    oDesc.create((int)nKeyPoints, 1, CV_16UC1);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar _ref = _refdata[_step_row*(_y)+_x];
-      ushort& _res = oDesc.at<ushort>((int)k);
+      size_t LBSP::getAbsThreshold() const {
+        return m_nThreshold;
+      }
+
+      static inline void lbsp_computeImpl(const cv::Mat& oInputImg,
+        const cv::Mat& oRefImg,
+        const std::vector<cv::KeyPoint>& voKeyPoints,
+        cv::Mat& oDesc,
+        size_t _t) {
+        CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
+        CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
+        CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        const size_t nChannels = (size_t)oInputImg.channels();
+        const size_t _step_row = oInputImg.step.p[0];
+        const uchar* _data = oInputImg.data;
+        const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
+        const size_t nKeyPoints = voKeyPoints.size();
+        if (nChannels == 1) {
+          oDesc.create((int)nKeyPoints, 1, CV_16UC1);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar _ref = _refdata[_step_row*(_y)+_x];
+            ushort& _res = oDesc.at<ushort>((int)k);
 #include "LBSP_16bits_dbcross_1ch.i"
-    }
-  }
-  else { //nChannels==3
-    oDesc.create((int)nKeyPoints, 1, CV_16UC3);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
-      ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k));
+          }
+        }
+        else { //nChannels==3
+          oDesc.create((int)nKeyPoints, 1, CV_16UC3);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
+            ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k));
 #include "LBSP_16bits_dbcross_3ch1t.i"
-    }
-  }
-}
+          }
+        }
+      }
 
-static inline void lbsp_computeImpl(const cv::Mat& oInputImg,
-  const cv::Mat& oRefImg,
-  const std::vector<cv::KeyPoint>& voKeyPoints,
-  cv::Mat& oDesc,
-  float fThreshold,
-  size_t nThresholdOffset) {
-  CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
-  CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
-  CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  CV_DbgAssert(fThreshold >= 0);
-  const size_t nChannels = (size_t)oInputImg.channels();
-  const size_t _step_row = oInputImg.step.p[0];
-  const uchar* _data = oInputImg.data;
-  const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
-  const size_t nKeyPoints = voKeyPoints.size();
-  if (nChannels == 1) {
-    oDesc.create((int)nKeyPoints, 1, CV_16UC1);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar _ref = _refdata[_step_row*(_y)+_x];
-      ushort& _res = oDesc.at<ushort>((int)k);
-      const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset;
+      static inline void lbsp_computeImpl(const cv::Mat& oInputImg,
+        const cv::Mat& oRefImg,
+        const std::vector<cv::KeyPoint>& voKeyPoints,
+        cv::Mat& oDesc,
+        float fThreshold,
+        size_t nThresholdOffset) {
+        CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
+        CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
+        CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        CV_DbgAssert(fThreshold >= 0);
+        const size_t nChannels = (size_t)oInputImg.channels();
+        const size_t _step_row = oInputImg.step.p[0];
+        const uchar* _data = oInputImg.data;
+        const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
+        const size_t nKeyPoints = voKeyPoints.size();
+        if (nChannels == 1) {
+          oDesc.create((int)nKeyPoints, 1, CV_16UC1);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar _ref = _refdata[_step_row*(_y)+_x];
+            ushort& _res = oDesc.at<ushort>((int)k);
+            const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset;
 #include "LBSP_16bits_dbcross_1ch.i"
-    }
-  }
-  else { //nChannels==3
-    oDesc.create((int)nKeyPoints, 1, CV_16UC3);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
-      ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k));
-      const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset };
+          }
+        }
+        else { //nChannels==3
+          oDesc.create((int)nKeyPoints, 1, CV_16UC3);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
+            ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k));
+            const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset };
 #include "LBSP_16bits_dbcross_3ch3t.i"
-    }
-  }
-}
+          }
+        }
+      }
 
-static inline void lbsp_computeImpl2(const cv::Mat& oInputImg,
-  const cv::Mat& oRefImg,
-  const std::vector<cv::KeyPoint>& voKeyPoints,
-  cv::Mat& oDesc,
-  size_t _t) {
-  CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
-  CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
-  CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  const size_t nChannels = (size_t)oInputImg.channels();
-  const size_t _step_row = oInputImg.step.p[0];
-  const uchar* _data = oInputImg.data;
-  const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
-  const size_t nKeyPoints = voKeyPoints.size();
-  if (nChannels == 1) {
-    oDesc.create(oInputImg.size(), CV_16UC1);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar _ref = _refdata[_step_row*(_y)+_x];
-      ushort& _res = oDesc.at<ushort>(_y, _x);
+      static inline void lbsp_computeImpl2(const cv::Mat& oInputImg,
+        const cv::Mat& oRefImg,
+        const std::vector<cv::KeyPoint>& voKeyPoints,
+        cv::Mat& oDesc,
+        size_t _t) {
+        CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
+        CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
+        CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        const size_t nChannels = (size_t)oInputImg.channels();
+        const size_t _step_row = oInputImg.step.p[0];
+        const uchar* _data = oInputImg.data;
+        const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
+        const size_t nKeyPoints = voKeyPoints.size();
+        if (nChannels == 1) {
+          oDesc.create(oInputImg.size(), CV_16UC1);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar _ref = _refdata[_step_row*(_y)+_x];
+            ushort& _res = oDesc.at<ushort>(_y, _x);
 #include "LBSP_16bits_dbcross_1ch.i"
-    }
-  }
-  else { //nChannels==3
-    oDesc.create(oInputImg.size(), CV_16UC3);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
-      ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x));
+          }
+        }
+        else { //nChannels==3
+          oDesc.create(oInputImg.size(), CV_16UC3);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
+            ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x));
 #include "LBSP_16bits_dbcross_3ch1t.i"
-    }
-  }
-}
+          }
+        }
+      }
 
-static inline void lbsp_computeImpl2(const cv::Mat& oInputImg,
-  const cv::Mat& oRefImg,
-  const std::vector<cv::KeyPoint>& voKeyPoints,
-  cv::Mat& oDesc,
-  float fThreshold,
-  size_t nThresholdOffset) {
-  CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
-  CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
-  CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  CV_DbgAssert(fThreshold >= 0);
-  const size_t nChannels = (size_t)oInputImg.channels();
-  const size_t _step_row = oInputImg.step.p[0];
-  const uchar* _data = oInputImg.data;
-  const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
-  const size_t nKeyPoints = voKeyPoints.size();
-  if (nChannels == 1) {
-    oDesc.create(oInputImg.size(), CV_16UC1);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar _ref = _refdata[_step_row*(_y)+_x];
-      ushort& _res = oDesc.at<ushort>(_y, _x);
-      const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset;
+      static inline void lbsp_computeImpl2(const cv::Mat& oInputImg,
+        const cv::Mat& oRefImg,
+        const std::vector<cv::KeyPoint>& voKeyPoints,
+        cv::Mat& oDesc,
+        float fThreshold,
+        size_t nThresholdOffset) {
+        CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
+        CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
+        CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        CV_DbgAssert(fThreshold >= 0);
+        const size_t nChannels = (size_t)oInputImg.channels();
+        const size_t _step_row = oInputImg.step.p[0];
+        const uchar* _data = oInputImg.data;
+        const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
+        const size_t nKeyPoints = voKeyPoints.size();
+        if (nChannels == 1) {
+          oDesc.create(oInputImg.size(), CV_16UC1);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar _ref = _refdata[_step_row*(_y)+_x];
+            ushort& _res = oDesc.at<ushort>(_y, _x);
+            const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset;
 #include "LBSP_16bits_dbcross_1ch.i"
-    }
-  }
-  else { //nChannels==3
-    oDesc.create(oInputImg.size(), CV_16UC3);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
-      ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x));
-      const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset };
+          }
+        }
+        else { //nChannels==3
+          oDesc.create(oInputImg.size(), CV_16UC3);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
+            ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x));
+            const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset };
 #include "LBSP_16bits_dbcross_3ch3t.i"
-    }
-  }
-}
+          }
+        }
+      }
 
-void LBSP::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const {
-  CV_Assert(!oImage.empty());
-  cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2);
-  cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon());
-  if (voKeypoints.empty()) {
-    oDescriptors.release();
-    return;
-  }
-  if (m_bOnlyUsingAbsThreshold)
-    lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold);
-  else
-    lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold);
-}
+      void LBSP::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const {
+        CV_Assert(!oImage.empty());
+        cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2);
+        cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon());
+        if (voKeypoints.empty()) {
+          oDescriptors.release();
+          return;
+        }
+        if (m_bOnlyUsingAbsThreshold)
+          lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold);
+        else
+          lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold);
+      }
 
-void LBSP::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const {
-  CV_Assert(voImageCollection.size() == vvoPointCollection.size());
-  voDescCollection.resize(voImageCollection.size());
-  for (size_t i = 0; i < voImageCollection.size(); i++)
-    compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]);
-}
+      void LBSP::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const {
+        CV_Assert(voImageCollection.size() == vvoPointCollection.size());
+        voDescCollection.resize(voImageCollection.size());
+        for (size_t i = 0; i < voImageCollection.size(); i++)
+          compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]);
+      }
 
-void LBSP::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const {
-  CV_Assert(!oImage.empty());
-  cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2);
-  cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon());
-  if (voKeypoints.empty()) {
-    oDescriptors.release();
-    return;
-  }
-  if (m_bOnlyUsingAbsThreshold)
-    lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold);
-  else
-    lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold);
-}
+      void LBSP::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const {
+        CV_Assert(!oImage.empty());
+        cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2);
+        cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon());
+        if (voKeypoints.empty()) {
+          oDescriptors.release();
+          return;
+        }
+        if (m_bOnlyUsingAbsThreshold)
+          lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold);
+        else
+          lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold);
+      }
 
-void LBSP::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) {
-  CV_DbgAssert(!voKeypoints.empty());
-  CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1);
-  CV_DbgAssert(oSize.width > 0 && oSize.height > 0);
-  CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3);
-  const size_t nChannels = (size_t)oDescriptors.channels();
-  const size_t nKeyPoints = voKeypoints.size();
-  if (nChannels == 1) {
-    oOutput.create(oSize, CV_16UC1);
-    oOutput = cv::Scalar_<ushort>(0);
-    for (size_t k = 0; k < nKeyPoints; ++k)
-      oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k);
-  }
-  else { //nChannels==3
-    oOutput.create(oSize, CV_16UC3);
-    oOutput = cv::Scalar_<ushort>(0, 0, 0);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y);
-      const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k);
-      const size_t idx = 3 * (int)voKeypoints[k].pt.x;
-      for (size_t n = 0; n < 3; ++n)
-        output_ptr[idx + n] = desc_ptr[n];
-    }
-  }
-}
+      void LBSP::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) {
+        CV_DbgAssert(!voKeypoints.empty());
+        CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1);
+        CV_DbgAssert(oSize.width > 0 && oSize.height > 0);
+        CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3);
+        const size_t nChannels = (size_t)oDescriptors.channels();
+        const size_t nKeyPoints = voKeypoints.size();
+        if (nChannels == 1) {
+          oOutput.create(oSize, CV_16UC1);
+          oOutput = cv::Scalar_<ushort>(0);
+          for (size_t k = 0; k < nKeyPoints; ++k)
+            oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k);
+        }
+        else { //nChannels==3
+          oOutput.create(oSize, CV_16UC3);
+          oOutput = cv::Scalar_<ushort>(0, 0, 0);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y);
+            const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k);
+            const size_t idx = 3 * (int)voKeypoints[k].pt.x;
+            for (size_t n = 0; n < 3; ++n)
+              output_ptr[idx + n] = desc_ptr[n];
+          }
+        }
+      }
 
-void LBSP::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) {
-  CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type());
-  CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3);
-  CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U);
-  CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX);
-  CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]);
-  const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8);
-  const size_t nChannels = CV_MAT_CN(oDesc1.type());
-  const size_t _step_row = oDesc1.step.p[0];
-  if (nChannels == 1) {
-    oOutput.create(oDesc1.size(), CV_8UC1);
-    oOutput = cv::Scalar(0);
-    for (int i = 0; i < oDesc1.rows; ++i) {
-      const size_t idx = _step_row*i;
-      const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx);
-      const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx);
-      for (int j = 0; j < oDesc1.cols; ++j)
-        oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j]));
-    }
-  }
-  else { //nChannels==3
-    if (bForceMergeChannels)
-      oOutput.create(oDesc1.size(), CV_8UC1);
-    else
-      oOutput.create(oDesc1.size(), CV_8UC3);
-    oOutput = cv::Scalar::all(0);
-    for (int i = 0; i < oDesc1.rows; ++i) {
-      const size_t idx = _step_row*i;
-      const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx);
-      const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx);
-      uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i;
-      for (int j = 0; j < oDesc1.cols; ++j) {
-        for (size_t n = 0; n < 3; ++n) {
-          const size_t idx2 = 3 * j + n;
+      void LBSP::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) {
+        CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type());
+        CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3);
+        CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U);
+        CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX);
+        CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]);
+        const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8);
+        const size_t nChannels = CV_MAT_CN(oDesc1.type());
+        const size_t _step_row = oDesc1.step.p[0];
+        if (nChannels == 1) {
+          oOutput.create(oDesc1.size(), CV_8UC1);
+          oOutput = cv::Scalar(0);
+          for (int i = 0; i < oDesc1.rows; ++i) {
+            const size_t idx = _step_row*i;
+            const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx);
+            const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx);
+            for (int j = 0; j < oDesc1.cols; ++j)
+              oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j]));
+          }
+        }
+        else { //nChannels==3
           if (bForceMergeChannels)
-            output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3);
+            oOutput.create(oDesc1.size(), CV_8UC1);
           else
-            output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2]));
+            oOutput.create(oDesc1.size(), CV_8UC3);
+          oOutput = cv::Scalar::all(0);
+          for (int i = 0; i < oDesc1.rows; ++i) {
+            const size_t idx = _step_row*i;
+            const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx);
+            const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx);
+            uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i;
+            for (int j = 0; j < oDesc1.cols; ++j) {
+              for (size_t n = 0; n < 3; ++n) {
+                const size_t idx2 = 3 * j + n;
+                if (bForceMergeChannels)
+                  output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3);
+                else
+                  output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2]));
+              }
+            }
+          }
         }
       }
-    }
-  }
-}
 
-void LBSP::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) {
-  cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2);
-}
+      void LBSP::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) {
+        cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2);
+      }
 
-void LBSP::validateROI(cv::Mat& oROI) {
-  CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1);
-  cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0));
-  const size_t nBorderSize = PATCH_SIZE / 2;
-  const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2);
-  cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner));
-  oROI = oROI_new;
+      void LBSP::validateROI(cv::Mat& oROI) {
+        CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1);
+        cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0));
+        const size_t nBorderSize = PATCH_SIZE / 2;
+        const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2);
+        cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner));
+        oROI = oROI_new;
+      }
+    }
+  }
 }
diff --git a/src/algorithms/LBSP/LBSP.h b/src/algorithms/LBSP/LBSP.h
index cab6a60206cfb897a88eadab2c64ae2911250233..6c8eb80256a0383f729ed8adfb5f909d7c809399 100644
--- a/src/algorithms/LBSP/LBSP.h
+++ b/src/algorithms/LBSP/LBSP.h
@@ -6,114 +6,123 @@
 
 #include "DistanceUtils.h"
 
-/*!
-  Local Binary Similarity Pattern (LBSP) feature extractor
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      /*!
+        Local Binary Similarity Pattern (LBSP) feature extractor
 
-  Note 1: both grayscale and RGB/BGR images may be used with this extractor.
-  Note 2: using LBSP::compute2(...) is logically equivalent to using LBSP::compute(...) followed by LBSP::reshapeDesc(...).
+        Note 1: both grayscale and RGB/BGR images may be used with this extractor.
+        Note 2: using LBSP::compute2(...) is logically equivalent to using LBSP::compute(...) followed by LBSP::reshapeDesc(...).
 
-  For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local
-  Binary Similarity Patterns", in CRV 2013.
+        For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local
+        Binary Similarity Patterns", in CRV 2013.
 
-  This algorithm is currently NOT thread-safe.
- */
-class LBSP : public cv::DescriptorExtractor {
-public:
-  //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons
-  LBSP(size_t nThreshold);
-  //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons
-  LBSP(float fRelThreshold, size_t nThresholdOffset = 0);
-  //! default destructor
-  virtual ~LBSP();
-  //! loads extractor params from the specified file node @@@@ not impl
-  virtual void read(const cv::FileNode&);
-  //! writes extractor params to the specified file storage @@@@ not impl
-  virtual void write(cv::FileStorage&) const;
-  //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons)
-  virtual void setReference(const cv::Mat&);
-  //! returns the current descriptor size, in bytes
-  virtual int descriptorSize() const;
-  //! returns the current descriptor data type
-  virtual int descriptorType() const;
-  //! returns whether this extractor is using a relative threshold or not
-  virtual bool isUsingRelThreshold() const;
-  //! returns the current relative threshold used for comparisons (-1 = invalid/not used)
-  virtual float getRelThreshold() const;
-  //! returns the current absolute threshold used for comparisons (-1 = invalid/not used)
-  virtual size_t getAbsThreshold() const;
+        This algorithm is currently NOT thread-safe.
+      */
+      class LBSP : public cv::DescriptorExtractor {
+      public:
+        //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons
+        LBSP(size_t nThreshold);
+        //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons
+        LBSP(float fRelThreshold, size_t nThresholdOffset = 0);
+        //! default destructor
+        virtual ~LBSP();
+        //! loads extractor params from the specified file node @@@@ not impl
+        virtual void read(const cv::FileNode&);
+        //! writes extractor params to the specified file storage @@@@ not impl
+        virtual void write(cv::FileStorage&) const;
+        //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons)
+        virtual void setReference(const cv::Mat&);
+        //! returns the current descriptor size, in bytes
+        virtual int descriptorSize() const;
+        //! returns the current descriptor data type
+        virtual int descriptorType() const;
+        //! returns whether this extractor is using a relative threshold or not
+        virtual bool isUsingRelThreshold() const;
+        //! returns the current relative threshold used for comparisons (-1 = invalid/not used)
+        virtual float getRelThreshold() const;
+        //! returns the current absolute threshold used for comparisons (-1 = invalid/not used)
+        virtual size_t getAbsThreshold() const;
 
-  //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed)
-  void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const;
-  //! batch version of LBSP::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...)
-  void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const;
+        //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed)
+        void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const;
+        //! batch version of LBSP::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...)
+        void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const;
 
-  //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version)
-  inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) {
-    CV_DbgAssert(!oInputImg.empty());
-    CV_DbgAssert(oInputImg.type() == CV_8UC1);
-    CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-    CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2);
-    CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2);
-    const size_t _step_row = oInputImg.step.p[0];
-    const uchar* const _data = oInputImg.data;
-#include "LBSP_16bits_dbcross_1ch.i"
-  }
+        //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version)
+        inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) {
+          CV_DbgAssert(!oInputImg.empty());
+          CV_DbgAssert(oInputImg.type() == CV_8UC1);
+          CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+          CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2);
+          CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2);
+          const size_t _step_row = oInputImg.step.p[0];
+          const uchar* const _data = oInputImg.data;
+      #include "LBSP_16bits_dbcross_1ch.i"
+        }
 
-  //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version)
-  inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) {
-    CV_DbgAssert(!oInputImg.empty());
-    CV_DbgAssert(oInputImg.type() == CV_8UC3);
-    CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-    CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2);
-    CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2);
-    const size_t _step_row = oInputImg.step.p[0];
-    const uchar* const _data = oInputImg.data;
-#include "LBSP_16bits_dbcross_3ch3t.i"
-  }
+        //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version)
+        inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) {
+          CV_DbgAssert(!oInputImg.empty());
+          CV_DbgAssert(oInputImg.type() == CV_8UC3);
+          CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+          CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2);
+          CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2);
+          const size_t _step_row = oInputImg.step.p[0];
+          const uchar* const _data = oInputImg.data;
+      #include "LBSP_16bits_dbcross_3ch3t.i"
+        }
 
-  //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version)
-  inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) {
-    CV_DbgAssert(!oInputImg.empty());
-    CV_DbgAssert(oInputImg.type() == CV_8UC3);
-    CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-    CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2);
-    CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2);
-    const size_t _step_row = oInputImg.step.p[0];
-    const uchar* const _data = oInputImg.data;
-#include "LBSP_16bits_dbcross_3ch1t.i"
-  }
+        //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version)
+        inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) {
+          CV_DbgAssert(!oInputImg.empty());
+          CV_DbgAssert(oInputImg.type() == CV_8UC3);
+          CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+          CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2);
+          CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2);
+          const size_t _step_row = oInputImg.step.p[0];
+          const uchar* const _data = oInputImg.data;
+      #include "LBSP_16bits_dbcross_3ch1t.i"
+        }
 
-  //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version)
-  inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) {
-    CV_DbgAssert(!oInputImg.empty());
-    CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3);
-    CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-    CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2);
-    CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2);
-    const size_t _step_row = oInputImg.step.p[0];
-    const uchar* const _data = oInputImg.data;
-#include "LBSP_16bits_dbcross_s3ch.i"
-  }
+        //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version)
+        inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) {
+          CV_DbgAssert(!oInputImg.empty());
+          CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3);
+          CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+          CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2);
+          CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2);
+          const size_t _step_row = oInputImg.step.p[0];
+          const uchar* const _data = oInputImg.data;
+      #include "LBSP_16bits_dbcross_s3ch.i"
+        }
 
-  //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations
-  static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput);
-  //! utility function, used to illustrate the difference between two descriptor images
-  static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false);
-  //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border
-  static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize);
-  //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border
-  static void validateROI(cv::Mat& oROI);
-  //! utility, specifies the pixel size of the pattern used (width and height)
-  static const size_t PATCH_SIZE = 5;
-  //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()')
-  static const size_t DESC_SIZE = 2;
+        //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations
+        static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput);
+        //! utility function, used to illustrate the difference between two descriptor images
+        static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false);
+        //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border
+        static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize);
+        //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border
+        static void validateROI(cv::Mat& oROI);
+        //! utility, specifies the pixel size of the pattern used (width and height)
+        static const size_t PATCH_SIZE = 5;
+        //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()')
+        static const size_t DESC_SIZE = 2;
 
-protected:
-  //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output
-  virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const;
+      protected:
+        //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output
+        virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const;
 
-  const bool m_bOnlyUsingAbsThreshold;
-  const float m_fRelThreshold;
-  const size_t m_nThreshold;
-  cv::Mat m_oRefImage;
-};
+        const bool m_bOnlyUsingAbsThreshold;
+        const float m_fRelThreshold;
+        const size_t m_nThreshold;
+        cv::Mat m_oRefImage;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBSP/LBSP_.cpp b/src/algorithms/LBSP/LBSP_.cpp
index 2cf2eb65bd6b1d060e79b76398fb61bfc93a881a..0116dbbeec54cafafc3200ce65072216b72951f9 100644
--- a/src/algorithms/LBSP/LBSP_.cpp
+++ b/src/algorithms/LBSP/LBSP_.cpp
@@ -1,318 +1,329 @@
 #include "LBSP_.h"
 
-LBSP_::LBSP_(size_t nThreshold)
-  : m_bOnlyUsingAbsThreshold(true)
-  , m_fRelThreshold(0) // unused
-  , m_nThreshold(nThreshold)
-  , m_oRefImage() {}
+//using namespace bgslibrary::algorithms::lbsp;
 
-LBSP_::LBSP_(float fRelThreshold, size_t nThresholdOffset)
-  : m_bOnlyUsingAbsThreshold(false)
-  , m_fRelThreshold(fRelThreshold)
-  , m_nThreshold(nThresholdOffset)
-  , m_oRefImage() {
-  CV_Assert(m_fRelThreshold >= 0);
-}
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      LBSP_::LBSP_(size_t nThreshold)
+        : m_bOnlyUsingAbsThreshold(true)
+        , m_fRelThreshold(0) // unused
+        , m_nThreshold(nThreshold)
+        , m_oRefImage() {}
 
-LBSP_::~LBSP_() {}
+      LBSP_::LBSP_(float fRelThreshold, size_t nThresholdOffset)
+        : m_bOnlyUsingAbsThreshold(false)
+        , m_fRelThreshold(fRelThreshold)
+        , m_nThreshold(nThresholdOffset)
+        , m_oRefImage() {
+        CV_Assert(m_fRelThreshold >= 0);
+      }
 
-void LBSP_::read(const cv::FileNode& /*fn*/) {
-  // ... = fn["..."];
-}
+      LBSP_::~LBSP_() {}
 
-void LBSP_::write(cv::FileStorage& /*fs*/) const {
-  //fs << "..." << ...;
-}
+      void LBSP_::read(const cv::FileNode& /*fn*/) {
+        // ... = fn["..."];
+      }
 
-void LBSP_::setReference(const cv::Mat& img) {
-  CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3);
-  m_oRefImage = img;
-}
+      void LBSP_::write(cv::FileStorage& /*fs*/) const {
+        //fs << "..." << ...;
+      }
 
-int LBSP_::descriptorSize() const {
-  return DESC_SIZE;
-}
+      void LBSP_::setReference(const cv::Mat& img) {
+        CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3);
+        m_oRefImage = img;
+      }
 
-int LBSP_::descriptorType() const {
-  return CV_16U;
-}
+      int LBSP_::descriptorSize() const {
+        return DESC_SIZE;
+      }
 
-bool LBSP_::isUsingRelThreshold() const {
-  return !m_bOnlyUsingAbsThreshold;
-}
+      int LBSP_::descriptorType() const {
+        return CV_16U;
+      }
 
-float LBSP_::getRelThreshold() const {
-  return m_fRelThreshold;
-}
+      bool LBSP_::isUsingRelThreshold() const {
+        return !m_bOnlyUsingAbsThreshold;
+      }
 
-size_t LBSP_::getAbsThreshold() const {
-  return m_nThreshold;
-}
+      float LBSP_::getRelThreshold() const {
+        return m_fRelThreshold;
+      }
 
-static inline void LBSP__computeImpl(const cv::Mat& oInputImg,
-  const cv::Mat& oRefImg,
-  const std::vector<cv::KeyPoint>& voKeyPoints,
-  cv::Mat& oDesc,
-  size_t _t) {
-  CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
-  CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
-  CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  const size_t nChannels = (size_t)oInputImg.channels();
-  const size_t _step_row = oInputImg.step.p[0];
-  const uchar* _data = oInputImg.data;
-  const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
-  const size_t nKeyPoints = voKeyPoints.size();
-  if (nChannels == 1) {
-    oDesc.create((int)nKeyPoints, 1, CV_16UC1);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar _ref = _refdata[_step_row*(_y)+_x];
-      ushort& _res = oDesc.at<ushort>((int)k);
+      size_t LBSP_::getAbsThreshold() const {
+        return m_nThreshold;
+      }
+
+      static inline void LBSP__computeImpl(const cv::Mat& oInputImg,
+        const cv::Mat& oRefImg,
+        const std::vector<cv::KeyPoint>& voKeyPoints,
+        cv::Mat& oDesc,
+        size_t _t) {
+        CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
+        CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
+        CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        const size_t nChannels = (size_t)oInputImg.channels();
+        const size_t _step_row = oInputImg.step.p[0];
+        const uchar* _data = oInputImg.data;
+        const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
+        const size_t nKeyPoints = voKeyPoints.size();
+        if (nChannels == 1) {
+          oDesc.create((int)nKeyPoints, 1, CV_16UC1);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar _ref = _refdata[_step_row*(_y)+_x];
+            ushort& _res = oDesc.at<ushort>((int)k);
 #include "LBSP_16bits_dbcross_1ch.i"
-    }
-  }
-  else { //nChannels==3
-    oDesc.create((int)nKeyPoints, 1, CV_16UC3);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
-      ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k));
+          }
+        }
+        else { //nChannels==3
+          oDesc.create((int)nKeyPoints, 1, CV_16UC3);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
+            ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k));
 #include "LBSP_16bits_dbcross_3ch1t.i"
-    }
-  }
-}
+          }
+        }
+      }
 
-static inline void LBSP__computeImpl(const cv::Mat& oInputImg,
-  const cv::Mat& oRefImg,
-  const std::vector<cv::KeyPoint>& voKeyPoints,
-  cv::Mat& oDesc,
-  float fThreshold,
-  size_t nThresholdOffset) {
-  CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
-  CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
-  CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  CV_DbgAssert(fThreshold >= 0);
-  const size_t nChannels = (size_t)oInputImg.channels();
-  const size_t _step_row = oInputImg.step.p[0];
-  const uchar* _data = oInputImg.data;
-  const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
-  const size_t nKeyPoints = voKeyPoints.size();
-  if (nChannels == 1) {
-    oDesc.create((int)nKeyPoints, 1, CV_16UC1);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar _ref = _refdata[_step_row*(_y)+_x];
-      ushort& _res = oDesc.at<ushort>((int)k);
-      const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset;
+      static inline void LBSP__computeImpl(const cv::Mat& oInputImg,
+        const cv::Mat& oRefImg,
+        const std::vector<cv::KeyPoint>& voKeyPoints,
+        cv::Mat& oDesc,
+        float fThreshold,
+        size_t nThresholdOffset) {
+        CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
+        CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
+        CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        CV_DbgAssert(fThreshold >= 0);
+        const size_t nChannels = (size_t)oInputImg.channels();
+        const size_t _step_row = oInputImg.step.p[0];
+        const uchar* _data = oInputImg.data;
+        const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
+        const size_t nKeyPoints = voKeyPoints.size();
+        if (nChannels == 1) {
+          oDesc.create((int)nKeyPoints, 1, CV_16UC1);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar _ref = _refdata[_step_row*(_y)+_x];
+            ushort& _res = oDesc.at<ushort>((int)k);
+            const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset;
 #include "LBSP_16bits_dbcross_1ch.i"
-    }
-  }
-  else { //nChannels==3
-    oDesc.create((int)nKeyPoints, 1, CV_16UC3);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
-      ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k));
-      const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset };
+          }
+        }
+        else { //nChannels==3
+          oDesc.create((int)nKeyPoints, 1, CV_16UC3);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
+            ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k));
+            const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset };
 #include "LBSP_16bits_dbcross_3ch3t.i"
-    }
-  }
-}
+          }
+        }
+      }
 
-static inline void LBSP__computeImpl2(const cv::Mat& oInputImg,
-  const cv::Mat& oRefImg,
-  const std::vector<cv::KeyPoint>& voKeyPoints,
-  cv::Mat& oDesc,
-  size_t _t) {
-  CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
-  CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
-  CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  const size_t nChannels = (size_t)oInputImg.channels();
-  const size_t _step_row = oInputImg.step.p[0];
-  const uchar* _data = oInputImg.data;
-  const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
-  const size_t nKeyPoints = voKeyPoints.size();
-  if (nChannels == 1) {
-    oDesc.create(oInputImg.size(), CV_16UC1);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar _ref = _refdata[_step_row*(_y)+_x];
-      ushort& _res = oDesc.at<ushort>(_y, _x);
+      static inline void LBSP__computeImpl2(const cv::Mat& oInputImg,
+        const cv::Mat& oRefImg,
+        const std::vector<cv::KeyPoint>& voKeyPoints,
+        cv::Mat& oDesc,
+        size_t _t) {
+        CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
+        CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
+        CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        const size_t nChannels = (size_t)oInputImg.channels();
+        const size_t _step_row = oInputImg.step.p[0];
+        const uchar* _data = oInputImg.data;
+        const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
+        const size_t nKeyPoints = voKeyPoints.size();
+        if (nChannels == 1) {
+          oDesc.create(oInputImg.size(), CV_16UC1);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar _ref = _refdata[_step_row*(_y)+_x];
+            ushort& _res = oDesc.at<ushort>(_y, _x);
 #include "LBSP_16bits_dbcross_1ch.i"
-    }
-  }
-  else { //nChannels==3
-    oDesc.create(oInputImg.size(), CV_16UC3);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
-      ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x));
+          }
+        }
+        else { //nChannels==3
+          oDesc.create(oInputImg.size(), CV_16UC3);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
+            ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x));
 #include "LBSP_16bits_dbcross_3ch1t.i"
-    }
-  }
-}
+          }
+        }
+      }
 
-static inline void LBSP__computeImpl2(const cv::Mat& oInputImg,
-  const cv::Mat& oRefImg,
-  const std::vector<cv::KeyPoint>& voKeyPoints,
-  cv::Mat& oDesc,
-  float fThreshold,
-  size_t nThresholdOffset) {
-  CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
-  CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
-  CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  CV_DbgAssert(fThreshold >= 0);
-  const size_t nChannels = (size_t)oInputImg.channels();
-  const size_t _step_row = oInputImg.step.p[0];
-  const uchar* _data = oInputImg.data;
-  const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
-  const size_t nKeyPoints = voKeyPoints.size();
-  if (nChannels == 1) {
-    oDesc.create(oInputImg.size(), CV_16UC1);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar _ref = _refdata[_step_row*(_y)+_x];
-      ushort& _res = oDesc.at<ushort>(_y, _x);
-      const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset;
+      static inline void LBSP__computeImpl2(const cv::Mat& oInputImg,
+        const cv::Mat& oRefImg,
+        const std::vector<cv::KeyPoint>& voKeyPoints,
+        cv::Mat& oDesc,
+        float fThreshold,
+        size_t nThresholdOffset) {
+        CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type()));
+        CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3);
+        CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        CV_DbgAssert(fThreshold >= 0);
+        const size_t nChannels = (size_t)oInputImg.channels();
+        const size_t _step_row = oInputImg.step.p[0];
+        const uchar* _data = oInputImg.data;
+        const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data;
+        const size_t nKeyPoints = voKeyPoints.size();
+        if (nChannels == 1) {
+          oDesc.create(oInputImg.size(), CV_16UC1);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar _ref = _refdata[_step_row*(_y)+_x];
+            ushort& _res = oDesc.at<ushort>(_y, _x);
+            const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset;
 #include "LBSP_16bits_dbcross_1ch.i"
-    }
-  }
-  else { //nChannels==3
-    oDesc.create(oInputImg.size(), CV_16UC3);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      const int _x = (int)voKeyPoints[k].pt.x;
-      const int _y = (int)voKeyPoints[k].pt.y;
-      const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
-      ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x));
-      const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset };
+          }
+        }
+        else { //nChannels==3
+          oDesc.create(oInputImg.size(), CV_16UC3);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            const int _x = (int)voKeyPoints[k].pt.x;
+            const int _y = (int)voKeyPoints[k].pt.y;
+            const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x);
+            ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x));
+            const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset };
 #include "LBSP_16bits_dbcross_3ch3t.i"
-    }
-  }
-}
+          }
+        }
+      }
 
-void LBSP_::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const {
-  CV_Assert(!oImage.empty());
-  cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2);
-  cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon());
-  if (voKeypoints.empty()) {
-    oDescriptors.release();
-    return;
-  }
-  if (m_bOnlyUsingAbsThreshold)
-    LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold);
-  else
-    LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold);
-}
+      void LBSP_::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const {
+        CV_Assert(!oImage.empty());
+        cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2);
+        cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon());
+        if (voKeypoints.empty()) {
+          oDescriptors.release();
+          return;
+        }
+        if (m_bOnlyUsingAbsThreshold)
+          LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold);
+        else
+          LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold);
+      }
 
-void LBSP_::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const {
-  CV_Assert(voImageCollection.size() == vvoPointCollection.size());
-  voDescCollection.resize(voImageCollection.size());
-  for (size_t i = 0; i < voImageCollection.size(); i++)
-    compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]);
-}
+      void LBSP_::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const {
+        CV_Assert(voImageCollection.size() == vvoPointCollection.size());
+        voDescCollection.resize(voImageCollection.size());
+        for (size_t i = 0; i < voImageCollection.size(); i++)
+          compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]);
+      }
 
-void LBSP_::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const {
-  CV_Assert(!oImage.empty());
-  cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2);
-  cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon());
-  if (voKeypoints.empty()) {
-    oDescriptors.release();
-    return;
-  }
-  if (m_bOnlyUsingAbsThreshold)
-    LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold);
-  else
-    LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold);
-}
+      void LBSP_::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const {
+        CV_Assert(!oImage.empty());
+        cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2);
+        cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon());
+        if (voKeypoints.empty()) {
+          oDescriptors.release();
+          return;
+        }
+        if (m_bOnlyUsingAbsThreshold)
+          LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold);
+        else
+          LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold);
+      }
 
-void LBSP_::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) {
-  CV_DbgAssert(!voKeypoints.empty());
-  CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1);
-  CV_DbgAssert(oSize.width > 0 && oSize.height > 0);
-  CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3);
-  const size_t nChannels = (size_t)oDescriptors.channels();
-  const size_t nKeyPoints = voKeypoints.size();
-  if (nChannels == 1) {
-    oOutput.create(oSize, CV_16UC1);
-    oOutput = cv::Scalar_<ushort>(0);
-    for (size_t k = 0; k < nKeyPoints; ++k)
-      oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k);
-  }
-  else { //nChannels==3
-    oOutput.create(oSize, CV_16UC3);
-    oOutput = cv::Scalar_<ushort>(0, 0, 0);
-    for (size_t k = 0; k < nKeyPoints; ++k) {
-      ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y);
-      const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k);
-      const size_t idx = 3 * (int)voKeypoints[k].pt.x;
-      for (size_t n = 0; n < 3; ++n)
-        output_ptr[idx + n] = desc_ptr[n];
-    }
-  }
-}
+      void LBSP_::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) {
+        CV_DbgAssert(!voKeypoints.empty());
+        CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1);
+        CV_DbgAssert(oSize.width > 0 && oSize.height > 0);
+        CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3);
+        const size_t nChannels = (size_t)oDescriptors.channels();
+        const size_t nKeyPoints = voKeypoints.size();
+        if (nChannels == 1) {
+          oOutput.create(oSize, CV_16UC1);
+          oOutput = cv::Scalar_<ushort>(0);
+          for (size_t k = 0; k < nKeyPoints; ++k)
+            oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k);
+        }
+        else { //nChannels==3
+          oOutput.create(oSize, CV_16UC3);
+          oOutput = cv::Scalar_<ushort>(0, 0, 0);
+          for (size_t k = 0; k < nKeyPoints; ++k) {
+            ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y);
+            const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k);
+            const size_t idx = 3 * (int)voKeypoints[k].pt.x;
+            for (size_t n = 0; n < 3; ++n)
+              output_ptr[idx + n] = desc_ptr[n];
+          }
+        }
+      }
 
-void LBSP_::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) {
-  CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type());
-  CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size
-  CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3);
-  CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U);
-  CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX);
-  CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]);
-  const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8);
-  const size_t nChannels = CV_MAT_CN(oDesc1.type());
-  const size_t _step_row = oDesc1.step.p[0];
-  if (nChannels == 1) {
-    oOutput.create(oDesc1.size(), CV_8UC1);
-    oOutput = cv::Scalar(0);
-    for (int i = 0; i < oDesc1.rows; ++i) {
-      const size_t idx = _step_row*i;
-      const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx);
-      const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx);
-      for (int j = 0; j < oDesc1.cols; ++j)
-        oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j]));
-    }
-  }
-  else { //nChannels==3
-    if (bForceMergeChannels)
-      oOutput.create(oDesc1.size(), CV_8UC1);
-    else
-      oOutput.create(oDesc1.size(), CV_8UC3);
-    oOutput = cv::Scalar::all(0);
-    for (int i = 0; i < oDesc1.rows; ++i) {
-      const size_t idx = _step_row*i;
-      const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx);
-      const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx);
-      uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i;
-      for (int j = 0; j < oDesc1.cols; ++j) {
-        for (size_t n = 0; n < 3; ++n) {
-          const size_t idx2 = 3 * j + n;
+      void LBSP_::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) {
+        CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type());
+        CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size
+        CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3);
+        CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U);
+        CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX);
+        CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]);
+        const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8);
+        const size_t nChannels = CV_MAT_CN(oDesc1.type());
+        const size_t _step_row = oDesc1.step.p[0];
+        if (nChannels == 1) {
+          oOutput.create(oDesc1.size(), CV_8UC1);
+          oOutput = cv::Scalar(0);
+          for (int i = 0; i < oDesc1.rows; ++i) {
+            const size_t idx = _step_row*i;
+            const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx);
+            const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx);
+            for (int j = 0; j < oDesc1.cols; ++j)
+              oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j]));
+          }
+        }
+        else { //nChannels==3
           if (bForceMergeChannels)
-            output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3);
+            oOutput.create(oDesc1.size(), CV_8UC1);
           else
-            output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2]));
+            oOutput.create(oDesc1.size(), CV_8UC3);
+          oOutput = cv::Scalar::all(0);
+          for (int i = 0; i < oDesc1.rows; ++i) {
+            const size_t idx = _step_row*i;
+            const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx);
+            const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx);
+            uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i;
+            for (int j = 0; j < oDesc1.cols; ++j) {
+              for (size_t n = 0; n < 3; ++n) {
+                const size_t idx2 = 3 * j + n;
+                if (bForceMergeChannels)
+                  output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3);
+                else
+                  output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2]));
+              }
+            }
+          }
         }
       }
-    }
-  }
-}
 
-void LBSP_::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) {
-  cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2);
-}
+      void LBSP_::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) {
+        cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2);
+      }
 
-void LBSP_::validateROI(cv::Mat& oROI) {
-  CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1);
-  cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0));
-  const size_t nBorderSize = PATCH_SIZE / 2;
-  const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2);
-  cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner));
-  oROI = oROI_new;
+      void LBSP_::validateROI(cv::Mat& oROI) {
+        CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1);
+        cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0));
+        const size_t nBorderSize = PATCH_SIZE / 2;
+        const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2);
+        cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner));
+        oROI = oROI_new;
+      }
+    }
+  }
 }
diff --git a/src/algorithms/LBSP/LBSP_.h b/src/algorithms/LBSP/LBSP_.h
index 25fd831eee97a8c6b791832c793613e24914ba6d..3b89a3736407413e726b228ba067c498edf37d5a 100644
--- a/src/algorithms/LBSP/LBSP_.h
+++ b/src/algorithms/LBSP/LBSP_.h
@@ -6,114 +6,123 @@
 
 #include "DistanceUtils.h"
 
-/*!
-    Local Binary Similarity Pattern (LBSP) feature extractor
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      /*!
+          Local Binary Similarity Pattern (LBSP) feature extractor
 
-    Note 1: both grayscale and RGB/BGR images may be used with this extractor.
-    Note 2: using LBSP_::compute2(...) is logically equivalent to using LBSP_::compute(...) followed by LBSP_::reshapeDesc(...).
+          Note 1: both grayscale and RGB/BGR images may be used with this extractor.
+          Note 2: using LBSP_::compute2(...) is logically equivalent to using LBSP_::compute(...) followed by LBSP_::reshapeDesc(...).
 
-    For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local
-    Binary Similarity Patterns", in CRV 2013.
+          For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local
+          Binary Similarity Patterns", in CRV 2013.
 
-    This algorithm is currently NOT thread-safe.
- */
-class LBSP_ : public cv::Feature2D {
-public:
-  //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons
-  LBSP_(size_t nThreshold);
-  //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons
-  LBSP_(float fRelThreshold, size_t nThresholdOffset = 0);
-  //! default destructor
-  virtual ~LBSP_();
-  //! loads extractor params from the specified file node @@@@ not impl
-  virtual void read(const cv::FileNode&);
-  //! writes extractor params to the specified file storage @@@@ not impl
-  virtual void write(cv::FileStorage&) const;
-  //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons)
-  virtual void setReference(const cv::Mat&);
-  //! returns the current descriptor size, in bytes
-  virtual int descriptorSize() const;
-  //! returns the current descriptor data type
-  virtual int descriptorType() const;
-  //! returns whether this extractor is using a relative threshold or not
-  virtual bool isUsingRelThreshold() const;
-  //! returns the current relative threshold used for comparisons (-1 = invalid/not used)
-  virtual float getRelThreshold() const;
-  //! returns the current absolute threshold used for comparisons (-1 = invalid/not used)
-  virtual size_t getAbsThreshold() const;
+          This algorithm is currently NOT thread-safe.
+      */
+      class LBSP_ : public cv::Feature2D {
+      public:
+        //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons
+        LBSP_(size_t nThreshold);
+        //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons
+        LBSP_(float fRelThreshold, size_t nThresholdOffset = 0);
+        //! default destructor
+        virtual ~LBSP_();
+        //! loads extractor params from the specified file node @@@@ not impl
+        virtual void read(const cv::FileNode&);
+        //! writes extractor params to the specified file storage @@@@ not impl
+        virtual void write(cv::FileStorage&) const;
+        //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons)
+        virtual void setReference(const cv::Mat&);
+        //! returns the current descriptor size, in bytes
+        virtual int descriptorSize() const;
+        //! returns the current descriptor data type
+        virtual int descriptorType() const;
+        //! returns whether this extractor is using a relative threshold or not
+        virtual bool isUsingRelThreshold() const;
+        //! returns the current relative threshold used for comparisons (-1 = invalid/not used)
+        virtual float getRelThreshold() const;
+        //! returns the current absolute threshold used for comparisons (-1 = invalid/not used)
+        virtual size_t getAbsThreshold() const;
 
-  //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed)
-  void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const;
-  //! batch version of LBSP_::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...)
-  void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const;
+        //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed)
+        void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const;
+        //! batch version of LBSP_::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...)
+        void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const;
 
-  //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version)
-  inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) {
-    CV_DbgAssert(!oInputImg.empty());
-    CV_DbgAssert(oInputImg.type() == CV_8UC1);
-    CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-    CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2);
-    CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2);
-    const size_t _step_row = oInputImg.step.p[0];
-    const uchar* const _data = oInputImg.data;
-#include "LBSP_16bits_dbcross_1ch.i"
-  }
+        //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version)
+        inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) {
+          CV_DbgAssert(!oInputImg.empty());
+          CV_DbgAssert(oInputImg.type() == CV_8UC1);
+          CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+          CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2);
+          CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2);
+          const size_t _step_row = oInputImg.step.p[0];
+          const uchar* const _data = oInputImg.data;
+      #include "LBSP_16bits_dbcross_1ch.i"
+        }
 
-  //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version)
-  inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) {
-    CV_DbgAssert(!oInputImg.empty());
-    CV_DbgAssert(oInputImg.type() == CV_8UC3);
-    CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-    CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2);
-    CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2);
-    const size_t _step_row = oInputImg.step.p[0];
-    const uchar* const _data = oInputImg.data;
-#include "LBSP_16bits_dbcross_3ch3t.i"
-  }
+        //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version)
+        inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) {
+          CV_DbgAssert(!oInputImg.empty());
+          CV_DbgAssert(oInputImg.type() == CV_8UC3);
+          CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+          CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2);
+          CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2);
+          const size_t _step_row = oInputImg.step.p[0];
+          const uchar* const _data = oInputImg.data;
+      #include "LBSP_16bits_dbcross_3ch3t.i"
+        }
 
-  //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version)
-  inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) {
-    CV_DbgAssert(!oInputImg.empty());
-    CV_DbgAssert(oInputImg.type() == CV_8UC3);
-    CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-    CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2);
-    CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2);
-    const size_t _step_row = oInputImg.step.p[0];
-    const uchar* const _data = oInputImg.data;
-#include "LBSP_16bits_dbcross_3ch1t.i"
-  }
+        //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version)
+        inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) {
+          CV_DbgAssert(!oInputImg.empty());
+          CV_DbgAssert(oInputImg.type() == CV_8UC3);
+          CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+          CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2);
+          CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2);
+          const size_t _step_row = oInputImg.step.p[0];
+          const uchar* const _data = oInputImg.data;
+      #include "LBSP_16bits_dbcross_3ch1t.i"
+        }
 
-  //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version)
-  inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) {
-    CV_DbgAssert(!oInputImg.empty());
-    CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3);
-    CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
-    CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2);
-    CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2);
-    const size_t _step_row = oInputImg.step.p[0];
-    const uchar* const _data = oInputImg.data;
-#include "LBSP_16bits_dbcross_s3ch.i"
-  }
+        //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version)
+        inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) {
+          CV_DbgAssert(!oInputImg.empty());
+          CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3);
+          CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size
+          CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2);
+          CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2);
+          const size_t _step_row = oInputImg.step.p[0];
+          const uchar* const _data = oInputImg.data;
+      #include "LBSP_16bits_dbcross_s3ch.i"
+        }
 
-  //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations
-  static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput);
-  //! utility function, used to illustrate the difference between two descriptor images
-  static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false);
-  //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border
-  static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize);
-  //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border
-  static void validateROI(cv::Mat& oROI);
-  //! utility, specifies the pixel size of the pattern used (width and height)
-  static const size_t PATCH_SIZE = 5;
-  //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()')
-  static const size_t DESC_SIZE = 2;
+        //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations
+        static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput);
+        //! utility function, used to illustrate the difference between two descriptor images
+        static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false);
+        //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border
+        static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize);
+        //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border
+        static void validateROI(cv::Mat& oROI);
+        //! utility, specifies the pixel size of the pattern used (width and height)
+        static const size_t PATCH_SIZE = 5;
+        //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()')
+        static const size_t DESC_SIZE = 2;
 
-protected:
-  //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output
-  virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const;
+      protected:
+        //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output
+        virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const;
 
-  const bool m_bOnlyUsingAbsThreshold;
-  const float m_fRelThreshold;
-  const size_t m_nThreshold;
-  cv::Mat m_oRefImage;
-};
+        const bool m_bOnlyUsingAbsThreshold;
+        const float m_fRelThreshold;
+        const size_t m_nThreshold;
+        cv::Mat m_oRefImage;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/LBSP/RandUtils.h b/src/algorithms/LBSP/RandUtils.h
index 69f4432a42ac46f8c964a83a93525d4fbfd6eba4..570d333f30c10bef209d0cb665af143e32752d1f 100644
--- a/src/algorithms/LBSP/RandUtils.h
+++ b/src/algorithms/LBSP/RandUtils.h
@@ -1,96 +1,105 @@
 #pragma once
 
-/*// gaussian 3x3 pattern, based on 'floor(fspecial('gaussian', 3, 1)*256)'
-static const int s_nSamplesInitPatternWidth = 3;
-static const int s_nSamplesInitPatternHeight = 3;
-static const int s_nSamplesInitPatternTot = 256;
-static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = {
-    {19,    32,    19,},
-    {32,    52,    32,},
-    {19,    32,    19,},
-};*/
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace lbsp
+    {
+      /*// gaussian 3x3 pattern, based on 'floor(fspecial('gaussian', 3, 1)*256)'
+      static const int s_nSamplesInitPatternWidth = 3;
+      static const int s_nSamplesInitPatternHeight = 3;
+      static const int s_nSamplesInitPatternTot = 256;
+      static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = {
+          {19,    32,    19,},
+          {32,    52,    32,},
+          {19,    32,    19,},
+      };*/
 
-// gaussian 7x7 pattern, based on 'floor(fspecial('gaussian',7,2)*512)'
-static const int s_nSamplesInitPatternWidth = 7;
-static const int s_nSamplesInitPatternHeight = 7;
-static const int s_nSamplesInitPatternTot = 512;
-static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = {
-  {2,     4,     6,     7,     6,     4,     2,},
-  {4,     8,    12,    14,    12,     8,     4,},
-  {6,    12,    21,    25,    21,    12,     6,},
-  {7,    14,    25,    28,    25,    14,     7,},
-  {6,    12,    21,    25,    21,    12,     6,},
-  {4,     8,    12,    14,    12,     8,     4,},
-  {2,     4,     6,     7,     6,     4,     2,},
-};
+      // gaussian 7x7 pattern, based on 'floor(fspecial('gaussian',7,2)*512)'
+      static const int s_nSamplesInitPatternWidth = 7;
+      static const int s_nSamplesInitPatternHeight = 7;
+      static const int s_nSamplesInitPatternTot = 512;
+      static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = {
+        {2,     4,     6,     7,     6,     4,     2,},
+        {4,     8,    12,    14,    12,     8,     4,},
+        {6,    12,    21,    25,    21,    12,     6,},
+        {7,    14,    25,    28,    25,    14,     7,},
+        {6,    12,    21,    25,    21,    12,     6,},
+        {4,     8,    12,    14,    12,     8,     4,},
+        {2,     4,     6,     7,     6,     4,     2,},
+      };
 
-//! returns a random init/sampling position for the specified pixel position; also guards against out-of-bounds values via image/border size check.
-static inline void getRandSamplePosition(int& x_sample, int& y_sample, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) {
-  int r = 1+rand()%s_nSamplesInitPatternTot;
-  for(x_sample=0; x_sample<s_nSamplesInitPatternWidth; ++x_sample) {
-    for(y_sample=0; y_sample<s_nSamplesInitPatternHeight; ++y_sample) {
-      r -= s_anSamplesInitPattern[y_sample][x_sample];
-      if(r<=0)
-        goto stop;
-    }
-  }
-stop:
-  x_sample += x_orig-s_nSamplesInitPatternWidth/2;
-  y_sample += y_orig-s_nSamplesInitPatternHeight/2;
-  if(x_sample<border)
-    x_sample = border;
-  else if(x_sample>=imgsize.width-border)
-    x_sample = imgsize.width-border-1;
-  if(y_sample<border)
-    y_sample = border;
-  else if(y_sample>=imgsize.height-border)
-    y_sample = imgsize.height-border-1;
-}
+      //! returns a random init/sampling position for the specified pixel position; also guards against out-of-bounds values via image/border size check.
+      static inline void getRandSamplePosition(int& x_sample, int& y_sample, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) {
+        int r = 1+rand()%s_nSamplesInitPatternTot;
+        for(x_sample=0; x_sample<s_nSamplesInitPatternWidth; ++x_sample) {
+          for(y_sample=0; y_sample<s_nSamplesInitPatternHeight; ++y_sample) {
+            r -= s_anSamplesInitPattern[y_sample][x_sample];
+            if(r<=0)
+              goto stop;
+          }
+        }
+      stop:
+        x_sample += x_orig-s_nSamplesInitPatternWidth/2;
+        y_sample += y_orig-s_nSamplesInitPatternHeight/2;
+        if(x_sample<border)
+          x_sample = border;
+        else if(x_sample>=imgsize.width-border)
+          x_sample = imgsize.width-border-1;
+        if(y_sample<border)
+          y_sample = border;
+        else if(y_sample>=imgsize.height-border)
+          y_sample = imgsize.height-border-1;
+      }
 
-// simple 8-connected (3x3) neighbors pattern
-static const int s_anNeighborPatternSize_3x3 = 8;
-static const int s_anNeighborPattern_3x3[8][2] = {
-  {-1, 1},  { 0, 1},  { 1, 1},
-  {-1, 0},            { 1, 0},
-  {-1,-1},  { 0,-1},  { 1,-1},
-};
+      // simple 8-connected (3x3) neighbors pattern
+      static const int s_anNeighborPatternSize_3x3 = 8;
+      static const int s_anNeighborPattern_3x3[8][2] = {
+        {-1, 1},  { 0, 1},  { 1, 1},
+        {-1, 0},            { 1, 0},
+        {-1,-1},  { 0,-1},  { 1,-1},
+      };
 
-//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check.
-static inline void getRandNeighborPosition_3x3(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) {
-  int r = rand()%s_anNeighborPatternSize_3x3;
-  x_neighbor = x_orig+s_anNeighborPattern_3x3[r][0];
-  y_neighbor = y_orig+s_anNeighborPattern_3x3[r][1];
-  if(x_neighbor<border)
-    x_neighbor = border;
-  else if(x_neighbor>=imgsize.width-border)
-    x_neighbor = imgsize.width-border-1;
-  if(y_neighbor<border)
-    y_neighbor = border;
-  else if(y_neighbor>=imgsize.height-border)
-    y_neighbor = imgsize.height-border-1;
-}
+      //! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check.
+      static inline void getRandNeighborPosition_3x3(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) {
+        int r = rand()%s_anNeighborPatternSize_3x3;
+        x_neighbor = x_orig+s_anNeighborPattern_3x3[r][0];
+        y_neighbor = y_orig+s_anNeighborPattern_3x3[r][1];
+        if(x_neighbor<border)
+          x_neighbor = border;
+        else if(x_neighbor>=imgsize.width-border)
+          x_neighbor = imgsize.width-border-1;
+        if(y_neighbor<border)
+          y_neighbor = border;
+        else if(y_neighbor>=imgsize.height-border)
+          y_neighbor = imgsize.height-border-1;
+      }
 
-// 5x5 neighbors pattern
-static const int s_anNeighborPatternSize_5x5 = 24;
-static const int s_anNeighborPattern_5x5[24][2] = {
-  {-2, 2},  {-1, 2},  { 0, 2},  { 1, 2},  { 2, 2},
-  {-2, 1},  {-1, 1},  { 0, 1},  { 1, 1},  { 2, 1},
-  {-2, 0},  {-1, 0},            { 1, 0},  { 2, 0},
-  {-2,-1},  {-1,-1},  { 0,-1},  { 1,-1},  { 2,-1},
-  {-2,-2},  {-1,-2},  { 0,-2},  { 1,-2},  { 2,-2},
-};
+      // 5x5 neighbors pattern
+      static const int s_anNeighborPatternSize_5x5 = 24;
+      static const int s_anNeighborPattern_5x5[24][2] = {
+        {-2, 2},  {-1, 2},  { 0, 2},  { 1, 2},  { 2, 2},
+        {-2, 1},  {-1, 1},  { 0, 1},  { 1, 1},  { 2, 1},
+        {-2, 0},  {-1, 0},            { 1, 0},  { 2, 0},
+        {-2,-1},  {-1,-1},  { 0,-1},  { 1,-1},  { 2,-1},
+        {-2,-2},  {-1,-2},  { 0,-2},  { 1,-2},  { 2,-2},
+      };
 
-//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check.
-static inline void getRandNeighborPosition_5x5(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) {
-  int r = rand()%s_anNeighborPatternSize_5x5;
-  x_neighbor = x_orig+s_anNeighborPattern_5x5[r][0];
-  y_neighbor = y_orig+s_anNeighborPattern_5x5[r][1];
-  if(x_neighbor<border)
-    x_neighbor = border;
-  else if(x_neighbor>=imgsize.width-border)
-    x_neighbor = imgsize.width-border-1;
-  if(y_neighbor<border)
-    y_neighbor = border;
-  else if(y_neighbor>=imgsize.height-border)
-    y_neighbor = imgsize.height-border-1;
+      //! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check.
+      static inline void getRandNeighborPosition_5x5(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) {
+        int r = rand()%s_anNeighborPatternSize_5x5;
+        x_neighbor = x_orig+s_anNeighborPattern_5x5[r][0];
+        y_neighbor = y_orig+s_anNeighborPattern_5x5[r][1];
+        if(x_neighbor<border)
+          x_neighbor = border;
+        else if(x_neighbor>=imgsize.width-border)
+          x_neighbor = imgsize.width-border-1;
+        if(y_neighbor<border)
+          y_neighbor = border;
+        else if(y_neighbor>=imgsize.height-border)
+          y_neighbor = imgsize.height-border-1;
+      }
+    }
+  }
 }
diff --git a/src/algorithms/LBSimpleGaussian.cpp b/src/algorithms/LBSimpleGaussian.cpp
index 368af80c8102faec5659f008cdf49b4e8891f236..6586833be501a0bb2e6fb557c48dae89dd876eec 100644
--- a/src/algorithms/LBSimpleGaussian.cpp
+++ b/src/algorithms/LBSimpleGaussian.cpp
@@ -27,7 +27,7 @@ void LBSimpleGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv
     int w = cvGetSize(frame).width;
     int h = cvGetSize(frame).height;
 
-    m_pBGModel = new BGModelGauss(w, h);
+    m_pBGModel = new lb::BGModelGauss(w, h);
     m_pBGModel->InitModel(frame);
   }
 
diff --git a/src/algorithms/LBSimpleGaussian.h b/src/algorithms/LBSimpleGaussian.h
index 990751cf5214771b3f2daa0694687f7f776d7dd3..b41d54d7be4287d30464105ccee56bfc7b95ad45 100644
--- a/src/algorithms/LBSimpleGaussian.h
+++ b/src/algorithms/LBSimpleGaussian.h
@@ -7,9 +7,6 @@
 
 #include "lb/BGModelGauss.h"
 
-using namespace lb_library;
-using namespace lb_library::SimpleGaussian;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -17,7 +14,7 @@ namespace bgslibrary
     class LBSimpleGaussian : public IBGS
     {
     private:
-      BGModel* m_pBGModel;
+      lb::BGModel* m_pBGModel;
       int sensitivity;
       int noiseVariance;
       int learningRate;
diff --git a/src/algorithms/LOBSTER.cpp b/src/algorithms/LOBSTER.cpp
index 937c31e75a10b214921a21861607714f519199d0..2a03c1086caf687a391ccd609a500324502e7c7a 100644
--- a/src/algorithms/LOBSTER.cpp
+++ b/src/algorithms/LOBSTER.cpp
@@ -5,12 +5,12 @@ using namespace bgslibrary::algorithms;
 LOBSTER::LOBSTER() :
   IBGS(quote(LOBSTER)),
   pLOBSTER(nullptr),
-  fRelLBSPThreshold(BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD),
-  nLBSPThresholdOffset(BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD),
-  nDescDistThreshold(BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD),
-  nColorDistThreshold(BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD),
-  nBGSamples(BGSLOBSTER_DEFAULT_NB_BG_SAMPLES),
-  nRequiredBGSamples(BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES)
+  fRelLBSPThreshold(lbsp::BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD),
+  nLBSPThresholdOffset(lbsp::BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD),
+  nDescDistThreshold(lbsp::BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD),
+  nColorDistThreshold(lbsp::BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD),
+  nBGSamples(lbsp::BGSLOBSTER_DEFAULT_NB_BG_SAMPLES),
+  nRequiredBGSamples(lbsp::BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES)
 {
   debug_construction(LOBSTER);
   initLoadSaveConfig(algorithmName);
@@ -27,7 +27,7 @@ void LOBSTER::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &im
   init(img_input, img_output, img_bgmodel);
 
   if (firstTime) {
-    pLOBSTER = new BackgroundSubtractorLOBSTER(
+    pLOBSTER = new lbsp::BackgroundSubtractorLOBSTER(
       fRelLBSPThreshold, nLBSPThresholdOffset, nDescDistThreshold,
       nColorDistThreshold, nBGSamples, nRequiredBGSamples);
 
diff --git a/src/algorithms/LOBSTER.h b/src/algorithms/LOBSTER.h
index 324cd5230010e7796fa6015010a90ba56f7ff7a0..505fd779de190b12ea6554c4386ac0ead960ff40 100644
--- a/src/algorithms/LOBSTER.h
+++ b/src/algorithms/LOBSTER.h
@@ -11,7 +11,7 @@ namespace bgslibrary
     class LOBSTER : public IBGS
     {
     private:
-      BackgroundSubtractorLOBSTER* pLOBSTER;
+      lbsp::BackgroundSubtractorLOBSTER* pLOBSTER;
 
       float fRelLBSPThreshold;
       int nLBSPThresholdOffset;
diff --git a/src/algorithms/MultiCue.cpp b/src/algorithms/MultiCue.cpp
index a961678e32f645455668348fef05586fbdb6df33..72fbab1a8904b5c5f8b1ed9cefab613c1a7fea16 100644
--- a/src/algorithms/MultiCue.cpp
+++ b/src/algorithms/MultiCue.cpp
@@ -2,9 +2,24 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace bgslibrary::algorithms::libMultiCue;
+using namespace bgslibrary::algorithms::multiCue;
 using namespace bgslibrary::algorithms;
 
+#define MIN3(x,y,z)  ((y) <= (z) ? ((x) <= (y) ? (x) : (y)) : ((x) <= (z) ? (x) : (z)))
+#define MAX3(x,y,z)  ((y) >= (z) ? ((x) >= (y) ? (x) : (y)) : ((x) >= (z) ? (x) : (z)))
+
+#ifndef PI
+#define PI 3.141592653589793f
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
 MultiCue::MultiCue() :
   IBGS(quote(MultiCue))
 {
diff --git a/src/algorithms/MultiCue.h b/src/algorithms/MultiCue.h
index 31e31b16b82df8af9cfa6bb3925627e831038557..ca75a50eff404f33b9d4ae924114e47149b84f24 100644
--- a/src/algorithms/MultiCue.h
+++ b/src/algorithms/MultiCue.h
@@ -3,23 +3,6 @@
 #include "opencv2/core/version.hpp"
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-#define MIN3(x,y,z)  ((y) <= (z) ? ((x) <= (y) ? (x) : (y)) : ((x) <= (z) ? (x) : (z)))
-#define MAX3(x,y,z)  ((y) >= (z) ? ((x) >= (y) ? (x) : (y)) : ((x) >= (z) ? (x) : (z)))
-
-#ifndef PI
-#define PI 3.14159
-#endif
-
-typedef int BOOL;
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
 #if !defined(__APPLE__)
 #include <malloc.h>
 #endif
@@ -36,8 +19,10 @@ namespace bgslibrary
 {
   namespace algorithms
   {
-    namespace libMultiCue
+    namespace multiCue
     {
+      typedef int BOOL;
+
       struct point {
         short m_nX;
         short m_nY;
@@ -106,7 +91,7 @@ namespace bgslibrary
 {
   namespace algorithms
   {
-    using namespace bgslibrary::algorithms::libMultiCue;
+    //using namespace bgslibrary::algorithms::multiCue;
 
     class MultiCue : public IBGS
     {
@@ -115,10 +100,14 @@ namespace bgslibrary
       void load_config(cv::FileStorage &fs);
 
     public:
+      typedef bgslibrary::algorithms::multiCue::point point;
+      typedef bgslibrary::algorithms::multiCue::TextureModel TextureModel;
+      typedef bgslibrary::algorithms::multiCue::BoundingBoxInfo BoundingBoxInfo;
+      typedef bgslibrary::algorithms::multiCue::ColorModel ColorModel;
+      typedef bgslibrary::algorithms::multiCue::BOOL BOOL;
+
       MultiCue();
       ~MultiCue();
-
-    public:
       //----------------------------------------------------
       //		APIs and User-Adjustable Parameters
       //----------------------------------------------------
@@ -136,7 +125,6 @@ namespace bgslibrary
       short g_nTextureTrainVolRange;								//the codebook size factor for texture models.		(The parameter k in the paper)
       short g_nColorTrainVolRange;								//the codebook size factor for color models.		(The parameter eta_1 in the paper)
 
-    public:
       //----------------------------------------------------
       //	Implemented Function Lists
       //----------------------------------------------------
@@ -185,7 +173,7 @@ namespace bgslibrary
       void C_ClearNonEssentialEntries(short nClearNum, ColorModel* pModel);
       void C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short nReferredIdx, short nClearNum, ColorModel* pCachebook);
       void C_Absorption(int iAbsorbCnt, point pos, short** aContinuCnt, short** aRefferedIndex, ColorModel* pModel, ColorModel* pCache);
-    public:
+
       //----------------------------------------------------
       //	Implemented Variable Lists
       //----------------------------------------------------
diff --git a/src/algorithms/MultiLayer.cpp b/src/algorithms/MultiLayer.cpp
index 89aa30a2fc2e60d1afbe5652225f38b2993b7f4a..1914785815ed7780af4925ab6fcd40f045a8b4c4 100644
--- a/src/algorithms/MultiLayer.cpp
+++ b/src/algorithms/MultiLayer.cpp
@@ -26,7 +26,6 @@ void MultiLayer::setStatus(Status _status) {
 void MultiLayer::finish() {
   if (bg_model_preload.empty()) {
     bg_model_preload = "./" + algorithmName + ".yml";
-    saveConfig();
   }
 
   if (status == MLBGS_LEARN && saveModel == true) {
@@ -68,7 +67,7 @@ void MultiLayer::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat
     fg_prob_img3 = cvCreateImage(img_size, org_img->depth, org_img->nChannels);
     merged_img = cvCreateImage(cvSize(img_size.width * 2, img_size.height * 2), org_img->depth, org_img->nChannels);
 
-    BGS = new CMultiLayerBGS();
+    BGS = new multilayer::CMultiLayerBGS();
     BGS->Init(img_size.width, img_size.height);
     BGS->SetForegroundMaskImage(fg_mask_img);
     BGS->SetForegroundProbImage(fg_prob_img);
diff --git a/src/algorithms/MultiLayer.h b/src/algorithms/MultiLayer.h
index 26e33286d592c7e921f57f4f497f06f194a90bac..b33d72fd076c929afe569ce33ea8721d914a137d 100644
--- a/src/algorithms/MultiLayer.h
+++ b/src/algorithms/MultiLayer.h
@@ -21,13 +21,13 @@ namespace bgslibrary
       };
 
     private:
-      long long frameNumber;
+      long frameNumber;
       cv::Mat img_merged;
       bool saveModel;
       bool disableDetectMode;
       bool disableLearning;
       int detectAfter;
-      CMultiLayerBGS* BGS;
+      multilayer::CMultiLayerBGS* BGS;
       Status status;
       //IplImage* img;
       IplImage* org_img;
diff --git a/src/algorithms/MultiLayer/BGS.h b/src/algorithms/MultiLayer/BGS.h
index 2ae1280a827f33b097c8e30ba1688398fd6e988e..97eeaf4cc71e2195d835fd9dec1ae2be8fa3b0a7 100644
--- a/src/algorithms/MultiLayer/BGS.h
+++ b/src/algorithms/MultiLayer/BGS.h
@@ -3,19 +3,6 @@
 // opencv legacy includes
 #include "OpenCvLegacyIncludes.h"
 
-#define MAX_LBP_MODE_NUM	5
-#define ROBUST_COLOR_OFFSET	6.0f
-#define LOW_INITIAL_MODE_WEIGHT	0.01f
-#define MODE_UPDATING_LEARN_RATE	0.01f
-#define WEIGHT_UPDATING_LEARN_RATE	0.01f
-#define COLOR_MAX_MIN_OFFSET		5
-#define BACKGROUND_MODEL_PERCENT	0.6f
-#define PATTERN_COLOR_DIST_BACKGROUND_THRESHOLD	0.2f
-#define PATTERN_DIST_SMOOTH_NEIG_HALF_SIZE	6
-#define PATTERN_DIST_CONV_GAUSSIAN_SIGMA	2.5f
-#define ROBUST_SHADOW_RATE	0.6f
-#define ROBUST_HIGHLIGHT_RATE	1.20f
-
 #define BINARY_PATTERM_ELEM(c1, c2, offset)	\
   ((float)(c2)-(float)(c1)+offset > 0)
 
@@ -28,134 +15,156 @@
 #define PI 3.141592653589793f
 #endif
 
-/************************************************************************/
-/* some data structures for multi-level LBP (local binary pattern)      */
-/* texture feature for background subtraction                           */
-/************************************************************************/
-typedef struct _LBP
-{
-  float* bg_pattern;			/* the average local binary pattern of background mode */
-  float* bg_intensity;			/* the average color intensity of background mode */
-  float* max_intensity;			/* the maximal color intensity of background mode */
-  float* min_intensity;			/* the minimal color intensity of background mode */
-  float weight;				/* the weight of background mode, i.e. probability that the background mode belongs to background */
-  float max_weight;			/* the maximal weight of background mode */
-  int bg_layer_num;			/* the background layer number of background mode */
-  unsigned long first_time;				/* the first time of background mode appearing */
-  unsigned long last_time;				/* the last time of background model appearing */
-  int freq;				/* the appearing frequency */
-  //long mnrl;				/* maximum negative run-length */
-  unsigned long layer_time;				/* the first time of background mode becoming a background layer */
-}
-LBPStruct;
-
-typedef struct _PixelLBP
-{
-  LBPStruct* LBPs;			/* the background modes */
-  unsigned short* lbp_idxes;		/* the indices of background modes */
-  unsigned int cur_bg_layer_no;
-  unsigned int num;			/* the total number of background modes */
-  unsigned int bg_num;			/* the number of the first background modes for foreground detection */
-  unsigned char* cur_intensity;		/* the color intensity of current pixel */
-  float* cur_pattern;			/* the local binary pattern of current pixel */
-  float matched_mode_first_time;		/* the index of currently matched pixel mode */
-}
-PixelLBPStruct;
-
-/*********************************************************************************/
-/* should replace the above structure using class in the future (not finished)   */
-/*********************************************************************************/
-
-class BG_PIXEL_MODE
+namespace bgslibrary
 {
-public:
-  float* bg_lbp_pattern;			/* the average local binary pattern of background mode */
-  float* bg_intensity;			/* the average color intensity of background mode */
-  float* max_intensity;			/* the maximal color intensity of background mode */
-  float* min_intensity;			/* the minimal color intensity of background mode */
-  float weight;				/* the weight of background mode, i.e. probability that the background mode belongs to background */
-  float max_weight;			/* the maximal weight of background mode */
-  int bg_layer_num;			/* the background layer number of background mode */
-
-  int lbp_pattern_length;
-  int color_channel;
-
-  BG_PIXEL_MODE(int _lbp_pattern_length, int _color_channel = 3) {
-    lbp_pattern_length = _lbp_pattern_length;
-    color_channel = _color_channel;
-
-    bg_lbp_pattern = new float[lbp_pattern_length];
-    bg_intensity = new float[color_channel];
-    max_intensity = new float[color_channel];
-    min_intensity = new float[color_channel];
-  };
-
-  virtual ~BG_PIXEL_MODE() {
-    delete[] bg_lbp_pattern;
-    delete[] bg_intensity;
-    delete[] max_intensity;
-    delete[] min_intensity;
-  };
-};
-
-class BG_PIXEL_PATTERN
-{
-public:
-  BG_PIXEL_MODE** pixel_MODEs;		/* the background modes */
-  unsigned short* lbp_pattern_idxes;	/* the indices of background modes */
-  unsigned int cur_bg_layer_no;
-  unsigned int num;			/* the total number of background modes */
-  unsigned int bg_num;			/* the number of the first background modes for foreground detection */
-  unsigned char* cur_intensity;		/* the color intensity of current pixel */
-  float* cur_lbp_pattern;			/* the local binary pattern of current pixel */
-
-  int lbp_pattern_length;
-  int color_channel;
-  int pixel_mode_num;
-
-  BG_PIXEL_PATTERN(int _pixel_mode_num, int _lbp_pattern_length, int _color_channel = 3) {
-    pixel_mode_num = _pixel_mode_num;
-    lbp_pattern_length = _lbp_pattern_length;
-    color_channel = _color_channel;
-
-    pixel_MODEs = new BG_PIXEL_MODE*[pixel_mode_num];
-
-    for (int i = 0; i < pixel_mode_num; i++) {
-      pixel_MODEs[i] = new BG_PIXEL_MODE(_lbp_pattern_length, _color_channel);
+  namespace algorithms
+  {
+    namespace multilayer
+    {
+      const int MAX_LBP_MODE_NUM = 5;
+      const float ROBUST_COLOR_OFFSET = 6.0f;
+      const float LOW_INITIAL_MODE_WEIGHT = 0.01f;
+      const float MODE_UPDATING_LEARN_RATE = 0.01f;
+      const float WEIGHT_UPDATING_LEARN_RATE = 0.01f;
+      const int COLOR_MAX_MIN_OFFSET = 5;
+      const float BACKGROUND_MODEL_PERCENT = 0.6f;
+      const float PATTERN_COLOR_DIST_BACKGROUND_THRESHOLD = 0.2f;
+      const float PATTERN_DIST_SMOOTH_NEIG_HALF_SIZE = 6;
+      const float PATTERN_DIST_CONV_GAUSSIAN_SIGMA = 2.5f;
+      const float ROBUST_SHADOW_RATE = 0.6f;
+      const float ROBUST_HIGHLIGHT_RATE = 1.20f;
+
+      /************************************************************************/
+      /* some data structures for multi-level LBP (local binary pattern)      */
+      /* texture feature for background subtraction                           */
+      /************************************************************************/
+      typedef struct _LBP
+      {
+        float* bg_pattern;			/* the average local binary pattern of background mode */
+        float* bg_intensity;			/* the average color intensity of background mode */
+        float* max_intensity;			/* the maximal color intensity of background mode */
+        float* min_intensity;			/* the minimal color intensity of background mode */
+        float weight;				/* the weight of background mode, i.e. probability that the background mode belongs to background */
+        float max_weight;			/* the maximal weight of background mode */
+        int bg_layer_num;			/* the background layer number of background mode */
+        unsigned long first_time;				/* the first time of background mode appearing */
+        unsigned long last_time;				/* the last time of background model appearing */
+        int freq;				/* the appearing frequency */
+        //long mnrl;				/* maximum negative run-length */
+        unsigned long layer_time;				/* the first time of background mode becoming a background layer */
+      }
+      LBPStruct;
+
+      typedef struct _PixelLBP
+      {
+        LBPStruct* LBPs;			/* the background modes */
+        unsigned short* lbp_idxes;		/* the indices of background modes */
+        unsigned int cur_bg_layer_no;
+        unsigned int num;			/* the total number of background modes */
+        unsigned int bg_num;			/* the number of the first background modes for foreground detection */
+        unsigned char* cur_intensity;		/* the color intensity of current pixel */
+        float* cur_pattern;			/* the local binary pattern of current pixel */
+        float matched_mode_first_time;		/* the index of currently matched pixel mode */
+      }
+      PixelLBPStruct;
+
+      /*********************************************************************************/
+      /* should replace the above structure using class in the future (not finished)   */
+      /*********************************************************************************/
+
+      class BG_PIXEL_MODE
+      {
+      public:
+        float* bg_lbp_pattern;			/* the average local binary pattern of background mode */
+        float* bg_intensity;			/* the average color intensity of background mode */
+        float* max_intensity;			/* the maximal color intensity of background mode */
+        float* min_intensity;			/* the minimal color intensity of background mode */
+        float weight;				/* the weight of background mode, i.e. probability that the background mode belongs to background */
+        float max_weight;			/* the maximal weight of background mode */
+        int bg_layer_num;			/* the background layer number of background mode */
+
+        int lbp_pattern_length;
+        int color_channel;
+
+        BG_PIXEL_MODE(int _lbp_pattern_length, int _color_channel = 3) {
+          lbp_pattern_length = _lbp_pattern_length;
+          color_channel = _color_channel;
+
+          bg_lbp_pattern = new float[lbp_pattern_length];
+          bg_intensity = new float[color_channel];
+          max_intensity = new float[color_channel];
+          min_intensity = new float[color_channel];
+        };
+
+        virtual ~BG_PIXEL_MODE() {
+          delete[] bg_lbp_pattern;
+          delete[] bg_intensity;
+          delete[] max_intensity;
+          delete[] min_intensity;
+        };
+      };
+
+      class BG_PIXEL_PATTERN
+      {
+      public:
+        BG_PIXEL_MODE** pixel_MODEs;		/* the background modes */
+        unsigned short* lbp_pattern_idxes;	/* the indices of background modes */
+        unsigned int cur_bg_layer_no;
+        unsigned int num;			/* the total number of background modes */
+        unsigned int bg_num;			/* the number of the first background modes for foreground detection */
+        unsigned char* cur_intensity;		/* the color intensity of current pixel */
+        float* cur_lbp_pattern;			/* the local binary pattern of current pixel */
+
+        int lbp_pattern_length;
+        int color_channel;
+        int pixel_mode_num;
+
+        BG_PIXEL_PATTERN(int _pixel_mode_num, int _lbp_pattern_length, int _color_channel = 3) {
+          pixel_mode_num = _pixel_mode_num;
+          lbp_pattern_length = _lbp_pattern_length;
+          color_channel = _color_channel;
+
+          pixel_MODEs = new BG_PIXEL_MODE*[pixel_mode_num];
+
+          for (int i = 0; i < pixel_mode_num; i++) {
+            pixel_MODEs[i] = new BG_PIXEL_MODE(_lbp_pattern_length, _color_channel);
+          }
+
+          lbp_pattern_idxes = new unsigned short[pixel_mode_num];
+          cur_intensity = new unsigned char[color_channel];
+          cur_lbp_pattern = new float[lbp_pattern_length];
+        };
+
+        virtual ~BG_PIXEL_PATTERN() {
+          delete[] lbp_pattern_idxes;
+          delete[] cur_intensity;
+          delete[] cur_lbp_pattern;
+
+          for (int i = 0; i < pixel_mode_num; i++)
+            delete pixel_MODEs[i];
+          delete[] pixel_MODEs;
+        };
+      };
+
+      class IMAGE_BG_MODEL
+      {
+        int pixel_length;
+
+        BG_PIXEL_PATTERN** pixel_PATTERNs;
+
+        IMAGE_BG_MODEL(int _pixel_length, int _pixel_mode_num, int _lbp_pattern_length, int _color_channel = 3) {
+          pixel_length = _pixel_length;
+
+          pixel_PATTERNs = new BG_PIXEL_PATTERN*[pixel_length];
+          for (int i = 0; i < pixel_length; i++)
+            pixel_PATTERNs[i] = new BG_PIXEL_PATTERN(_pixel_mode_num, _lbp_pattern_length, _color_channel);
+        }
+        virtual ~IMAGE_BG_MODEL() {
+          for (int i = 0; i < pixel_length; i++)
+            delete pixel_PATTERNs[i];
+          delete[] pixel_PATTERNs;
+        }
+      };
     }
-
-    lbp_pattern_idxes = new unsigned short[pixel_mode_num];
-    cur_intensity = new unsigned char[color_channel];
-    cur_lbp_pattern = new float[lbp_pattern_length];
-  };
-
-  virtual ~BG_PIXEL_PATTERN() {
-    delete[] lbp_pattern_idxes;
-    delete[] cur_intensity;
-    delete[] cur_lbp_pattern;
-
-    for (int i = 0; i < pixel_mode_num; i++)
-      delete pixel_MODEs[i];
-    delete[] pixel_MODEs;
-  };
-};
-
-class IMAGE_BG_MODEL
-{
-  int pixel_length;
-
-  BG_PIXEL_PATTERN** pixel_PATTERNs;
-
-  IMAGE_BG_MODEL(int _pixel_length, int _pixel_mode_num, int _lbp_pattern_length, int _color_channel = 3) {
-    pixel_length = _pixel_length;
-
-    pixel_PATTERNs = new BG_PIXEL_PATTERN*[pixel_length];
-    for (int i = 0; i < pixel_length; i++)
-      pixel_PATTERNs[i] = new BG_PIXEL_PATTERN(_pixel_mode_num, _lbp_pattern_length, _color_channel);
   }
-  virtual ~IMAGE_BG_MODEL() {
-    for (int i = 0; i < pixel_length; i++)
-      delete pixel_PATTERNs[i];
-    delete[] pixel_PATTERNs;
-  }
-};
+}
diff --git a/src/algorithms/MultiLayer/BackgroundSubtractionAPI.h b/src/algorithms/MultiLayer/BackgroundSubtractionAPI.h
index 39223986b73c3710cf1bd3c966ee6415771cdb82..b44cdd7ec583b6f6b9a7dee99929bcede1df049d 100644
--- a/src/algorithms/MultiLayer/BackgroundSubtractionAPI.h
+++ b/src/algorithms/MultiLayer/BackgroundSubtractionAPI.h
@@ -3,90 +3,99 @@
 // opencv legacy includes
 #include "OpenCvLegacyIncludes.h"
 
-class CBackgroundSubtractionAPI
+namespace bgslibrary
 {
-public:
-  //CBackgroundSubtractionAPI(){};
-  //virtual ~CBackgroundSubtractionAPI(){};
+  namespace algorithms
+  {
+    namespace multilayer
+    {
+      class CBackgroundSubtractionAPI
+      {
+      public:
+        //CBackgroundSubtractionAPI(){};
+        //virtual ~CBackgroundSubtractionAPI(){};
 
-  //-------------------------------------------------------------
-  // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES
-  // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED
-  void   Init(int width, int height);
+        //-------------------------------------------------------------
+        // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES
+        // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED
+        void   Init(int width, int height);
 
-  //-------------------------------------------------------------
-  // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND
-  // SUBTRACTION DOES NOT NEED TO BE PERFORMED
-  //
-  //  mode is useful to specify if the points to remove from
-  //  processing are in addition to the ones potentially
-  //  removed according to the configuration file,
-  //  or if they are the only ones to be removed
-  //
-  // mode=0 : provided points need to be removed
-  //          in addition to those already removed
-  // mode=1 : the provided points are the only one to remove
-  //          from processing
-  // Note:  maskImage(li,co)=0 indicate the points to remove
-  //       from background processing
-  void   SetValidPointMask(IplImage* maskImage, int mode);
+        //-------------------------------------------------------------
+        // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND
+        // SUBTRACTION DOES NOT NEED TO BE PERFORMED
+        //
+        //  mode is useful to specify if the points to remove from
+        //  processing are in addition to the ones potentially
+        //  removed according to the configuration file,
+        //  or if they are the only ones to be removed
+        //
+        // mode=0 : provided points need to be removed
+        //          in addition to those already removed
+        // mode=1 : the provided points are the only one to remove
+        //          from processing
+        // Note:  maskImage(li,co)=0 indicate the points to remove
+        //       from background processing
+        void   SetValidPointMask(IplImage* maskImage, int mode);
 
-  //-------------------------------------------------------------
-  //
-  //   set the frame rate, to adjust the update parameters
-  //   to the actual frame rate.
-  //   Can be called only once at initialisation,
-  //   but in online cases, can be used to indicate
-  //   the time interval during the last processed frame
-  //
-  //   frameDuration is in millisecond
-  void   SetFrameRate(float    frameDuration);
+        //-------------------------------------------------------------
+        //
+        //   set the frame rate, to adjust the update parameters
+        //   to the actual frame rate.
+        //   Can be called only once at initialisation,
+        //   but in online cases, can be used to indicate
+        //   the time interval during the last processed frame
+        //
+        //   frameDuration is in millisecond
+        void   SetFrameRate(float    frameDuration);
 
-  //-------------------------------------------------------------
-  //   PROVIDE A POINTER TO THE INPUT IMAGE
-  //   -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED
-  //
-  //   Here assumes that the input image will contain RGB images.
-  //   The memory of this image is handled by the caller.
-  //
-  //    The return value indicate whether the actual Background
-  //    Subtraction algorithm handles RGB images (1) or not (0).
-  //
-  int  SetRGBInputImage(IplImage  *  inputImage);
+        //-------------------------------------------------------------
+        //   PROVIDE A POINTER TO THE INPUT IMAGE
+        //   -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED
+        //
+        //   Here assumes that the input image will contain RGB images.
+        //   The memory of this image is handled by the caller.
+        //
+        //    The return value indicate whether the actual Background
+        //    Subtraction algorithm handles RGB images (1) or not (0).
+        //
+        int  SetRGBInputImage(IplImage  *  inputImage);
 
-  //-------------------------------------------------------------
-  //   PROVIDE A POINTER TO THE RESULT IMAGE
-  //   INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED
-  //
-  //   The return value is 1 if correct image format is provided,
-  //   otherwise the return value is 0.
-  //   e.g. fg_mask_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1);
-  int  SetForegroundMaskImage(IplImage *fg_mask_img);
+        //-------------------------------------------------------------
+        //   PROVIDE A POINTER TO THE RESULT IMAGE
+        //   INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED
+        //
+        //   The return value is 1 if correct image format is provided,
+        //   otherwise the return value is 0.
+        //   e.g. fg_mask_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1);
+        int  SetForegroundMaskImage(IplImage *fg_mask_img);
 
-  //   The return value is 1 if the function is implemented
-  //   with correct format, otherwise the return value is 0
-  //   e.g. fg_prob_img = cvCreateImage(imgSize, IPL_DEPTH_32F, 1);
-  int  SetForegroundProbImage(IplImage *fg_prob_img);
+        //   The return value is 1 if the function is implemented
+        //   with correct format, otherwise the return value is 0
+        //   e.g. fg_prob_img = cvCreateImage(imgSize, IPL_DEPTH_32F, 1);
+        int  SetForegroundProbImage(IplImage *fg_prob_img);
 
-  //-------------------------------------------------------------
-  // This function should be called each time a new image is
-  // available in the input image.
-  //
-  // The return value is 1 if everything goes well,
-  // otherwise the return value is 0.
-  //
-  int   Process();
+        //-------------------------------------------------------------
+        // This function should be called each time a new image is
+        // available in the input image.
+        //
+        // The return value is 1 if everything goes well,
+        // otherwise the return value is 0.
+        //
+        int   Process();
 
-  //-------------------------------------------------------------
-  // this function should save parameters and information of the model
-  // (e.g. after a training of the model, or in such a way
-  // that the model can be reload to process the next frame
-  // type of save:
-  void   Save(char   *bg_model_fn);
+        //-------------------------------------------------------------
+        // this function should save parameters and information of the model
+        // (e.g. after a training of the model, or in such a way
+        // that the model can be reload to process the next frame
+        // type of save:
+        void   Save(char   *bg_model_fn);
 
-  //-------------------------------------------------------------
-  // this function should load the parameters necessary
-  // for the processing of the background subtraction or
-  // load background model information
-  void   Load(char  *bg_model_fn);
-};
+        //-------------------------------------------------------------
+        // this function should load the parameters necessary
+        // for the processing of the background subtraction or
+        // load background model information
+        void   Load(char  *bg_model_fn);
+      };
+    }
+  }
+}
diff --git a/src/algorithms/MultiLayer/BlobExtraction.cpp b/src/algorithms/MultiLayer/BlobExtraction.cpp
index 97d1e9a5294e6ffc64160ca4ff0e06e6e12ce980..8ef878a93c0113e9c6cb5e02d5afbf4010b18e7a 100644
--- a/src/algorithms/MultiLayer/BlobExtraction.cpp
+++ b/src/algorithms/MultiLayer/BlobExtraction.cpp
@@ -1,1440 +1,1449 @@
-//! Indica si la connectivitat es a 8 (si es desactiva es a 4)
-#define B_CONNECTIVITAT_8
-
-//! si la imatge és cíclica verticalment (els blobs que toquen
-//! les vores superior i inferior no es consideren externs)
-#define IMATGE_CICLICA_VERTICAL		1
-//! si la imatge és cíclica horitzontalment (els blobs que toquen
-//! les vores dreta i esquerra no es consideren externs)
-#define IMATGE_CICLICA_HORITZONTAL	0
-
-#define PERIMETRE_DIAGONAL (1.41421356237310 - 2)
-#define SQRT2	1.41421356237310
-// color dels píxels de la màscara per ser exteriors
-#define PIXEL_EXTERIOR 0
-
 #include "BlobResult.h"
 #include "BlobExtraction.h"
 #include "OpenCvLegacyIncludes.h"
 
-namespace Blob
+//! Indica si la connectivitat es a 8 (si es desactiva es a 4)
+#define B_CONNECTIVITAT_8
+
+namespace bgslibrary
 {
-  /**
-    - FUNCIÓ: BlobAnalysis
-    - FUNCIONALITAT: Extreu els blobs d'una imatge d'un sol canal
-    - PARÀMETRES:
-    - inputImage: Imatge d'entrada. Ha de ser d'un sol canal
-    - threshold: Nivell de gris per considerar un pixel blanc o negre
-    - maskImage: Imatge de màscara fora de la cual no es calculen els blobs. A més,
-    els blobs que toquen els pixels de la màscara a 0, són considerats
-    externs
-    - borderColor: Color del marc de la imatge (0=black or 1=white)
-    - findmoments: calcula els moments dels blobs o no
-    - RegionData: on es desarà el resultat
-    - RESULTAT:
-    - retorna true si tot ha anat bé, false si no. Deixa el resultat a blobs.
-    - RESTRICCIONS:
-    - La imatge d'entrada ha de ser d'un sol canal
-    - AUTOR: dgrossman@cdr.stanford.edu
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    - fpinyol@cvc.uab.es, rborras@cvc.uab.es: adaptació a les OpenCV
-    */
-  bool BlobAnalysis(IplImage* inputImage,
-    uchar threshold,
-    IplImage* maskImage,
-    bool borderColor,
-    bool findmoments,
-    blob_vector &RegionData)
+  namespace algorithms
   {
-    // dimensions of input image taking in account the ROI
-    int Cols, Rows, startCol, startRow;
-
-    if (inputImage->roi)
-    {
-      CvRect imageRoi = cvGetImageROI(inputImage);
-      startCol = imageRoi.x;
-      startRow = imageRoi.y;
-      Cols = imageRoi.width;
-      Rows = imageRoi.height;
-    }
-    else
+    namespace multilayer
     {
-      startCol = 0;
-      startRow = 0;
-      Cols = inputImage->width;
-      Rows = inputImage->height;
-    }
+      namespace blob
+      {
+        //! si la imatge és cíclica verticalment (els blobs que toquen
+        //! les vores superior i inferior no es consideren externs)
+        const int IMATGE_CICLICA_VERTICAL = 1;
+        //! si la imatge és cíclica horitzontalment (els blobs que toquen
+        //! les vores dreta i esquerra no es consideren externs)
+        const int IMATGE_CICLICA_HORITZONTAL = 0;
+
+        const double SQRT2 = 1.41421356237310;
+        const double PERIMETRE_DIAGONAL = (SQRT2 - 2);
+
+        // color dels píxels de la màscara per ser exteriors
+        const int PIXEL_EXTERIOR = 0;
+
+        /**
+          - FUNCIÓ: BlobAnalysis
+          - FUNCIONALITAT: Extreu els blobs d'una imatge d'un sol canal
+          - PARÀMETRES:
+          - inputImage: Imatge d'entrada. Ha de ser d'un sol canal
+          - threshold: Nivell de gris per considerar un pixel blanc o negre
+          - maskImage: Imatge de màscara fora de la cual no es calculen els blobs. A més,
+          els blobs que toquen els pixels de la màscara a 0, són considerats
+          externs
+          - borderColor: Color del marc de la imatge (0=black or 1=white)
+          - findmoments: calcula els moments dels blobs o no
+          - RegionData: on es desarà el resultat
+          - RESULTAT:
+          - retorna true si tot ha anat bé, false si no. Deixa el resultat a blobs.
+          - RESTRICCIONS:
+          - La imatge d'entrada ha de ser d'un sol canal
+          - AUTOR: dgrossman@cdr.stanford.edu
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          - fpinyol@cvc.uab.es, rborras@cvc.uab.es: adaptació a les OpenCV
+          */
+        bool BlobAnalysis(IplImage* inputImage,
+          uchar threshold,
+          IplImage* maskImage,
+          bool borderColor,
+          bool findmoments,
+          blob_vector &RegionData)
+        {
+          // dimensions of input image taking in account the ROI
+          int Cols, Rows, startCol, startRow;
 
-    int Trans = Cols;				// MAX trans in any row
-    char* pMask = NULL;
-    char* pImage;
+          if (inputImage->roi)
+          {
+            CvRect imageRoi = cvGetImageROI(inputImage);
+            startCol = imageRoi.x;
+            startRow = imageRoi.y;
+            Cols = imageRoi.width;
+            Rows = imageRoi.height;
+          }
+          else
+          {
+            startCol = 0;
+            startRow = 0;
+            Cols = inputImage->width;
+            Rows = inputImage->height;
+          }
 
-    // Convert image array into transition array. In each row
-    // the transition array tells which columns have a color change
-    int iCol, iRow, iTran, Tran;				// Data for a given run
-    bool ThisCell, LastCell;		// Contents (colors (0 or 1)) within this row
-    int TransitionOffset = 0;		// Performance booster to avoid multiplication
+          int Trans = Cols;				// MAX trans in any row
+          char* pMask = NULL;
+          char* pImage;
 
-    // row 0 and row Rows+1 represent the border
-    int i;
-    int *Transition;				// Transition Matrix
+          // Convert image array into transition array. In each row
+          // the transition array tells which columns have a color change
+          int iCol, iRow, iTran, Tran;				// Data for a given run
+          bool ThisCell, LastCell;		// Contents (colors (0 or 1)) within this row
+          int TransitionOffset = 0;		// Performance booster to avoid multiplication
 
-    int nombre_pixels_mascara = 0;
-    //! Imatge amb el perimetre extern de cada pixel
-    IplImage *imatgePerimetreExtern;
+          // row 0 and row Rows+1 represent the border
+          int i;
+          int *Transition;				// Transition Matrix
 
-    // input images must have only 1-channel and be an image
-    if (!CV_IS_IMAGE(inputImage) || (inputImage->nChannels != 1))
-    {
-      return false;
-    }
-    if (maskImage != NULL)
-    {
-      // input image and mask are a valid image?
-      if (!CV_IS_IMAGE(inputImage) || !CV_IS_IMAGE(maskImage))
-        return false;
+          int nombre_pixels_mascara = 0;
+          //! Imatge amb el perimetre extern de cada pixel
+          IplImage *imatgePerimetreExtern;
 
-      // comprova que la màscara tingui les mateixes dimensions que la imatge
-      if (inputImage->width != maskImage->width || inputImage->height != maskImage->height)
-      {
-        return false;
-      }
+          // input images must have only 1-channel and be an image
+          if (!CV_IS_IMAGE(inputImage) || (inputImage->nChannels != 1))
+          {
+            return false;
+          }
+          if (maskImage != NULL)
+          {
+            // input image and mask are a valid image?
+            if (!CV_IS_IMAGE(inputImage) || !CV_IS_IMAGE(maskImage))
+              return false;
 
-      // comprova que la màscara sigui una imatge d'un sol canal (grayscale)
-      if (maskImage->nChannels != 1)
-      {
-        return false;
-      }
+            // comprova que la màscara tingui les mateixes dimensions que la imatge
+            if (inputImage->width != maskImage->width || inputImage->height != maskImage->height)
+            {
+              return false;
+            }
 
-    }
+            // comprova que la màscara sigui una imatge d'un sol canal (grayscale)
+            if (maskImage->nChannels != 1)
+            {
+              return false;
+            }
 
-    // Initialize Transition array
-    Transition = new int[(Rows + 2)*(Cols + 2)];
-    memset(Transition, 0, (Rows + 2) * (Cols + 2) * sizeof(int));
-    Transition[0] = Transition[(Rows + 1) * (Cols + 2)] = Cols + 2;
+          }
 
-    // Start at the beginning of the image (startCol, startRow)
-    pImage = inputImage->imageData + startCol - 1 + startRow * inputImage->widthStep;
+          // Initialize Transition array
+          Transition = new int[(Rows + 2)*(Cols + 2)];
+          memset(Transition, 0, (Rows + 2) * (Cols + 2) * sizeof(int));
+          Transition[0] = Transition[(Rows + 1) * (Cols + 2)] = Cols + 2;
 
-    /*
-      Paral·lelització del càlcul de la matriu de transicions
-      Fem que cada iteració del for el faci un thread o l'altre ( tenim 2 possibles threads )
-      */
-    if (maskImage == NULL)
-    {
-      imatgePerimetreExtern = NULL;
+          // Start at the beginning of the image (startCol, startRow)
+          pImage = inputImage->imageData + startCol - 1 + startRow * inputImage->widthStep;
 
-      //Fill Transition array
-      for (iRow = 1; iRow < Rows + 1; iRow++)		// Choose a row of Bordered image
-      {
-        TransitionOffset = iRow*(Cols + 2); //per a que sigui paral·litzable
-        iTran = 0;					// Index into Transition array
-        Tran = 0;					// No transitions at row start
-        LastCell = borderColor;
+          /*
+            Paral·lelització del càlcul de la matriu de transicions
+            Fem que cada iteració del for el faci un thread o l'altre ( tenim 2 possibles threads )
+            */
+          if (maskImage == NULL)
+          {
+            imatgePerimetreExtern = NULL;
 
-        for (iCol = 0; iCol < Cols + 2; iCol++)	// Scan that row of Bordered image
-        {
-          if (iCol == 0 || iCol == Cols + 1)
-            ThisCell = borderColor;
-          else
-            ThisCell = ((unsigned char)*(pImage)) > threshold;
+            //Fill Transition array
+            for (iRow = 1; iRow < Rows + 1; iRow++)		// Choose a row of Bordered image
+            {
+              TransitionOffset = iRow*(Cols + 2); //per a que sigui paral·litzable
+              iTran = 0;					// Index into Transition array
+              Tran = 0;					// No transitions at row start
+              LastCell = borderColor;
 
-          if (ThisCell != LastCell)
-          {
-            Transition[TransitionOffset + iTran] = Tran;	// Save completed Tran
-            iTran++;						// Prepare new index
-            LastCell = ThisCell;			// With this color
+              for (iCol = 0; iCol < Cols + 2; iCol++)	// Scan that row of Bordered image
+              {
+                if (iCol == 0 || iCol == Cols + 1)
+                  ThisCell = borderColor;
+                else
+                  ThisCell = ((unsigned char)*(pImage)) > threshold;
+
+                if (ThisCell != LastCell)
+                {
+                  Transition[TransitionOffset + iTran] = Tran;	// Save completed Tran
+                  iTran++;						// Prepare new index
+                  LastCell = ThisCell;			// With this color
+                }
+
+                Tran++;	// Tran continues
+                pImage++;
+              }
+
+              Transition[TransitionOffset + iTran] = Tran;	// Save completed run
+              if ((TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2))
+              {
+                Transition[TransitionOffset + iTran + 1] = -1;
+              }
+              //jump to next row (beginning from (startCol, startRow))
+              pImage = inputImage->imageData - 1 + startCol + (iRow + startRow)*inputImage->widthStep;
+            }
           }
+          else
+          {
+            //maskImage not NULL: Cal recòrrer la màscara també per calcular la matriu de transicions
 
-          Tran++;	// Tran continues
-          pImage++;
-        }
+            char perimeter;
+            char *pPerimetre;
 
-        Transition[TransitionOffset + iTran] = Tran;	// Save completed run
-        if ((TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2))
-        {
-          Transition[TransitionOffset + iTran + 1] = -1;
-        }
-        //jump to next row (beginning from (startCol, startRow))
-        pImage = inputImage->imageData - 1 + startCol + (iRow + startRow)*inputImage->widthStep;
-      }
-    }
-    else
-    {
-      //maskImage not NULL: Cal recòrrer la màscara també per calcular la matriu de transicions
+            // creem la imatge que contindrà el perimetre extern de cada pixel
+            imatgePerimetreExtern = cvCreateImage(cvSize(maskImage->width, maskImage->height), IPL_DEPTH_8U, 1);
+            cvSetZero(imatgePerimetreExtern);
 
-      char perimeter;
-      char *pPerimetre;
+            pMask = maskImage->imageData - 1;
 
-      // creem la imatge que contindrà el perimetre extern de cada pixel
-      imatgePerimetreExtern = cvCreateImage(cvSize(maskImage->width, maskImage->height), IPL_DEPTH_8U, 1);
-      cvSetZero(imatgePerimetreExtern);
+            //Fill Transition array
+            for (iRow = 1; iRow < Rows + 1; iRow++)		// Choose a row of Bordered image
+            {
+              TransitionOffset = iRow*(Cols + 2);
+              iTran = 0;					// Index into Transition array
+              Tran = 0;					// No transitions at row start
+              LastCell = borderColor;
 
-      pMask = maskImage->imageData - 1;
+              pPerimetre = imatgePerimetreExtern->imageData + (iRow - 1) * imatgePerimetreExtern->widthStep;
+              //pMask = maskImage->imageData + (iRow-1) * maskImage->widthStep;
 
-      //Fill Transition array
-      for (iRow = 1; iRow < Rows + 1; iRow++)		// Choose a row of Bordered image
-      {
-        TransitionOffset = iRow*(Cols + 2);
-        iTran = 0;					// Index into Transition array
-        Tran = 0;					// No transitions at row start
-        LastCell = borderColor;
+              for (iCol = 0; iCol < Cols + 2; iCol++)	// Scan that row of Bordered image
+              {
+                if (iCol == 0 || iCol == Cols + 1 || ((unsigned char)*pMask) == PIXEL_EXTERIOR)
+                  ThisCell = borderColor;
+                else
+                  ThisCell = ((unsigned char)*(pImage)) > threshold;
 
-        pPerimetre = imatgePerimetreExtern->imageData + (iRow - 1) * imatgePerimetreExtern->widthStep;
-        //pMask = maskImage->imageData + (iRow-1) * maskImage->widthStep;
+                if (ThisCell != LastCell)
+                {
+                  Transition[TransitionOffset + iTran] = Tran;	// Save completed Tran
+                  iTran++;						// Prepare new index
+                  LastCell = ThisCell;			// With this color
+                }
 
-        for (iCol = 0; iCol < Cols + 2; iCol++)	// Scan that row of Bordered image
-        {
-          if (iCol == 0 || iCol == Cols + 1 || ((unsigned char)*pMask) == PIXEL_EXTERIOR)
-            ThisCell = borderColor;
-          else
-            ThisCell = ((unsigned char)*(pImage)) > threshold;
+                /*////////////////////////////////////////////////////////////////////////
+                  Calcul de la imatge amb els pixels externs
+                  ////////////////////////////////////////////////////////////////////////*/
+                  // pels pixels externs no cal calcular res pq no hi accedir-hem
+                if ((iCol > 0) && (iCol < Cols))
+                {
+                  if (*pMask == PIXEL_EXTERIOR)
+                  {
+                    *pPerimetre = 0;
+                  }
+                  else
+                  {
+                    perimeter = 0;
 
-          if (ThisCell != LastCell)
-          {
-            Transition[TransitionOffset + iTran] = Tran;	// Save completed Tran
-            iTran++;						// Prepare new index
-            LastCell = ThisCell;			// With this color
-          }
+                    // pixels al nord de l'actual
+                    if (iRow > 1)
+                    {
+                      if (*(pMask - maskImage->widthStep) == PIXEL_EXTERIOR) perimeter++;
+                    }
 
-          /*////////////////////////////////////////////////////////////////////////
-            Calcul de la imatge amb els pixels externs
-            ////////////////////////////////////////////////////////////////////////*/
-            // pels pixels externs no cal calcular res pq no hi accedir-hem
-          if ((iCol > 0) && (iCol < Cols))
-          {
-            if (*pMask == PIXEL_EXTERIOR)
-            {
-              *pPerimetre = 0;
-            }
-            else
-            {
-              perimeter = 0;
+                    // pixels a l'est i oest de l'actual
+                    if (iRow < imatgePerimetreExtern->height)
+                    {
+                      if ((iCol > 0) && (*(pMask - 1) == PIXEL_EXTERIOR)) perimeter++;
 
-              // pixels al nord de l'actual
-              if (iRow > 1)
-              {
-                if (*(pMask - maskImage->widthStep) == PIXEL_EXTERIOR) perimeter++;
-              }
+                      if ((iCol < imatgePerimetreExtern->width - 1) && (*(pMask + 1) == PIXEL_EXTERIOR)) perimeter++;
+                    }
 
-              // pixels a l'est i oest de l'actual
-              if (iRow < imatgePerimetreExtern->height)
-              {
-                if ((iCol > 0) && (*(pMask - 1) == PIXEL_EXTERIOR)) perimeter++;
+                    // pixels al sud de l'actual
+                    if (iRow < imatgePerimetreExtern->height - 1)
+                    {
+                      if (*(pMask + maskImage->widthStep) == PIXEL_EXTERIOR) perimeter++;
+                    }
+
+                    *pPerimetre = perimeter;
+                  }
+                }
 
-                if ((iCol < imatgePerimetreExtern->width - 1) && (*(pMask + 1) == PIXEL_EXTERIOR)) perimeter++;
+                Tran++;	// Tran continues
+                pImage++;
+                pMask++;
+                pPerimetre++;
               }
+              Transition[TransitionOffset + iTran] = Tran;	// Save completed run
 
-              // pixels al sud de l'actual
-              if (iRow < imatgePerimetreExtern->height - 1)
+              if ((TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2))
               {
-                if (*(pMask + maskImage->widthStep) == PIXEL_EXTERIOR) perimeter++;
+                Transition[TransitionOffset + iTran + 1] = -1;
               }
 
-              *pPerimetre = perimeter;
+
+              //jump to next row (beginning from (startCol, startRow))
+              pImage = inputImage->imageData - 1 + startCol + (iRow + startRow)*inputImage->widthStep;
+              //the mask should be the same size as image Roi, so don't take into account the offset
+              pMask = maskImage->imageData - 1 + iRow*maskImage->widthStep;
             }
           }
 
-          Tran++;	// Tran continues
-          pImage++;
-          pMask++;
-          pPerimetre++;
-        }
-        Transition[TransitionOffset + iTran] = Tran;	// Save completed run
+          // Process transition code depending on Last row and This row
+          //
+          // Last ---++++++--+++++++++++++++-----+++++++++++++++++++-----++++++-------+++---
+          // This -----+++-----++++----+++++++++----+++++++---++------------------++++++++--
+          //
+          // There are various possibilities:
+          //
+          // Case     1       2       3       4       5       6       7       8
+          // Last |xxx    |xxxxoo |xxxxxxx|xxxxxxx|ooxxxxx|ooxxx  |ooxxxxx|    xxx|
+          // This |    yyy|    yyy|  yyyy |  yyyyy|yyyyyyy|yyyyyyy|yyyy   |yyyy   |
+          // Here o is optional
+          //
+          // Here are the primitive tests to distinguish these 6 cases:
+          //   A) Last end < This start - 1 OR NOT		Note: -1
+          //   B) This end < Last start OR NOT
+          //   C) Last start < This start OR NOT
+          //   D) This end < Last end OR NOT
+          //   E) This end = Last end OR NOT
+          //
+          // Here is how to use these tests to determine the case:
+          //   Case 1 = A [=> NOT B AND C AND NOT D AND NOT E]
+          //   Case 2 = C AND NOT D AND NOT E [AND NOT A AND NOT B]
+          //   Case 3 = C AND D [=> NOT E] [AND NOT A AND NOT B]
+          //   Case 4 = C AND NOT D AND E [AND NOT A AND NOT B]
+          //   Case 5 = NOT C AND E [=> NOT D] [AND NOT A AND NOT B]
+          //   Case 6 = NOT C AND NOT D AND NOT E [AND NOT A AND NOT B]
+          //   Case 7 = NOT C AND D [=> NOT E] [AND NOT A AND NOT B]
+          //   Case 8 = B [=> NOT A AND NOT C AND D AND NOT E]
+          //
+          // In cases 2,3,4,5,6,7 the following additional test is needed:
+          //   Match) This color = Last color OR NOT
+          //
+          // In cases 5,6,7 the following additional test is needed:
+          //   Known) This region was already matched OR NOT
+          //
+          // Here are the main tests and actions:
+          //   Case 1: LastIndex++;
+          //   Case 2: if(Match) {y = x;}
+          //           LastIndex++;
+          //   Case 3: if(Match) {y = x;}
+          //           else {y = new}
+          //           ThisIndex++;
+          //   Case 4: if(Match) {y = x;}
+          //           else {y = new}
+          //           LastIndex++;
+          //           ThisIndex++;
+          //   Case 5: if(Match AND NOT Known) {y = x}
+          //           else if(Match AND Known) {Subsume(x,y)}
+          //           LastIndex++;ThisIndex++
+          //   Case 6: if(Match AND NOT Known) {y = x}
+          //           else if(Match AND Known) {Subsume(x,y)}
+          //           LastIndex++;
+          //   Case 7: if(Match AND NOT Known) {y = x}
+          //           else if(Match AND Known) {Subsume(x,y)}
+          //           ThisIndex++;
+          //   Case 8: ThisIndex++;
+
+          int *SubsumedRegion = NULL;
+
+          double ThisParent;	// These data can change when the line is current
+          double ThisArea;
+          double ThisPerimeter;
+          double ThisSumX = 0;
+          double ThisSumY = 0;
+          double ThisSumXX = 0;
+          double ThisSumYY = 0;
+          double ThisSumXY = 0;
+          double ThisMinX;
+          double ThisMaxX;
+          double ThisMinY;
+          double ThisMaxY;
+          double LastPerimeter;	// This is the only data for retroactive change
+          double ThisExternPerimeter;
+
+          int HighRegionNum = 0;
+          //int RegionNum = 0;
+          int ErrorFlag = 0;
+
+          int LastRow, ThisRow;			// Row number
+          int LastStart, ThisStart;		// Starting column of run
+          int LastEnd, ThisEnd;			// Ending column of run
+          int LastColor, ThisColor;		// Color of run
+
+          int LastIndex, ThisIndex;		// Which run are we up to
+          int LastIndexCount, ThisIndexCount;	// Out of these runs
+          int LastRegionNum, ThisRegionNum;	// Which assignment
+          int *LastRegion;				// Row assignment of region number
+          int *ThisRegion;		// Row assignment of region number
+
+          int LastOffset = -(Trans + 2);	// For performance to avoid multiplication
+          int ThisOffset = 0;				// For performance to avoid multiplication
+          int ComputeData;
+
+          CvPoint actualedge;
+          uchar imagevalue;
+          bool CandidatExterior = false;
+
+          // apuntadors als blobs de la regió actual i last
+          CBlob *regionDataThisRegion, *regionDataLastRegion;
+
+          LastRegion = new int[Cols + 2];
+          ThisRegion = new int[Cols + 2];
+
+          for (i = 0; i < Cols + 2; i++)	// Initialize result arrays
+          {
+            LastRegion[i] = -1;
+            ThisRegion[i] = -1;
+          }
 
-        if ((TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2))
-        {
-          Transition[TransitionOffset + iTran + 1] = -1;
-        }
+          //create the external blob
+          RegionData.push_back(new CBlob());
+          SubsumedRegion = NewSubsume(SubsumedRegion, 0);
+          RegionData[0]->parent = -1;
+          RegionData[0]->area = (double)Transition[0];
+          RegionData[0]->perimeter = (double)(2 + 2 * Transition[0]);
 
+          ThisIndexCount = 1;
+          ThisRegion[0] = 0;	// Border region
 
-        //jump to next row (beginning from (startCol, startRow))
-        pImage = inputImage->imageData - 1 + startCol + (iRow + startRow)*inputImage->widthStep;
-        //the mask should be the same size as image Roi, so don't take into account the offset
-        pMask = maskImage->imageData - 1 + iRow*maskImage->widthStep;
-      }
-    }
+          // beginning of the image
+          // en cada linia, pimage apunta al primer pixel de la fila
+          pImage = inputImage->imageData - 1 + startCol + startRow * inputImage->widthStep;
+          //the mask should be the same size as image Roi, so don't take into account the offset
+          if (maskImage != NULL) pMask = maskImage->imageData - 1;
 
-    // Process transition code depending on Last row and This row
-    //
-    // Last ---++++++--+++++++++++++++-----+++++++++++++++++++-----++++++-------+++---
-    // This -----+++-----++++----+++++++++----+++++++---++------------------++++++++--
-    //
-    // There are various possibilities:
-    //
-    // Case     1       2       3       4       5       6       7       8
-    // Last |xxx    |xxxxoo |xxxxxxx|xxxxxxx|ooxxxxx|ooxxx  |ooxxxxx|    xxx|
-    // This |    yyy|    yyy|  yyyy |  yyyyy|yyyyyyy|yyyyyyy|yyyy   |yyyy   |
-    // Here o is optional
-    //
-    // Here are the primitive tests to distinguish these 6 cases:
-    //   A) Last end < This start - 1 OR NOT		Note: -1
-    //   B) This end < Last start OR NOT
-    //   C) Last start < This start OR NOT
-    //   D) This end < Last end OR NOT
-    //   E) This end = Last end OR NOT
-    //
-    // Here is how to use these tests to determine the case:
-    //   Case 1 = A [=> NOT B AND C AND NOT D AND NOT E]
-    //   Case 2 = C AND NOT D AND NOT E [AND NOT A AND NOT B]
-    //   Case 3 = C AND D [=> NOT E] [AND NOT A AND NOT B]
-    //   Case 4 = C AND NOT D AND E [AND NOT A AND NOT B]
-    //   Case 5 = NOT C AND E [=> NOT D] [AND NOT A AND NOT B]
-    //   Case 6 = NOT C AND NOT D AND NOT E [AND NOT A AND NOT B]
-    //   Case 7 = NOT C AND D [=> NOT E] [AND NOT A AND NOT B]
-    //   Case 8 = B [=> NOT A AND NOT C AND D AND NOT E]
-    //
-    // In cases 2,3,4,5,6,7 the following additional test is needed:
-    //   Match) This color = Last color OR NOT
-    //
-    // In cases 5,6,7 the following additional test is needed:
-    //   Known) This region was already matched OR NOT
-    //
-    // Here are the main tests and actions:
-    //   Case 1: LastIndex++;
-    //   Case 2: if(Match) {y = x;}
-    //           LastIndex++;
-    //   Case 3: if(Match) {y = x;}
-    //           else {y = new}
-    //           ThisIndex++;
-    //   Case 4: if(Match) {y = x;}
-    //           else {y = new}
-    //           LastIndex++;
-    //           ThisIndex++;
-    //   Case 5: if(Match AND NOT Known) {y = x}
-    //           else if(Match AND Known) {Subsume(x,y)}
-    //           LastIndex++;ThisIndex++
-    //   Case 6: if(Match AND NOT Known) {y = x}
-    //           else if(Match AND Known) {Subsume(x,y)}
-    //           LastIndex++;
-    //   Case 7: if(Match AND NOT Known) {y = x}
-    //           else if(Match AND Known) {Subsume(x,y)}
-    //           ThisIndex++;
-    //   Case 8: ThisIndex++;
-
-    int *SubsumedRegion = NULL;
-
-    double ThisParent;	// These data can change when the line is current
-    double ThisArea;
-    double ThisPerimeter;
-    double ThisSumX = 0;
-    double ThisSumY = 0;
-    double ThisSumXX = 0;
-    double ThisSumYY = 0;
-    double ThisSumXY = 0;
-    double ThisMinX;
-    double ThisMaxX;
-    double ThisMinY;
-    double ThisMaxY;
-    double LastPerimeter;	// This is the only data for retroactive change
-    double ThisExternPerimeter;
-
-    int HighRegionNum = 0;
-    //int RegionNum = 0;
-    int ErrorFlag = 0;
-
-    int LastRow, ThisRow;			// Row number
-    int LastStart, ThisStart;		// Starting column of run
-    int LastEnd, ThisEnd;			// Ending column of run
-    int LastColor, ThisColor;		// Color of run
-
-    int LastIndex, ThisIndex;		// Which run are we up to
-    int LastIndexCount, ThisIndexCount;	// Out of these runs
-    int LastRegionNum, ThisRegionNum;	// Which assignment
-    int *LastRegion;				// Row assignment of region number
-    int *ThisRegion;		// Row assignment of region number
-
-    int LastOffset = -(Trans + 2);	// For performance to avoid multiplication
-    int ThisOffset = 0;				// For performance to avoid multiplication
-    int ComputeData;
-
-    CvPoint actualedge;
-    uchar imagevalue;
-    bool CandidatExterior = false;
-
-    // apuntadors als blobs de la regió actual i last
-    CBlob *regionDataThisRegion, *regionDataLastRegion;
-
-    LastRegion = new int[Cols + 2];
-    ThisRegion = new int[Cols + 2];
-
-    for (i = 0; i < Cols + 2; i++)	// Initialize result arrays
-    {
-      LastRegion[i] = -1;
-      ThisRegion[i] = -1;
-    }
+          char *pImageAux, *pMaskAux = NULL;
 
-    //create the external blob
-    RegionData.push_back(new CBlob());
-    SubsumedRegion = NewSubsume(SubsumedRegion, 0);
-    RegionData[0]->parent = -1;
-    RegionData[0]->area = (double)Transition[0];
-    RegionData[0]->perimeter = (double)(2 + 2 * Transition[0]);
+          // Loop over all rows
+          for (ThisRow = 1; ThisRow < Rows + 2; ThisRow++)
+          {
+            //cout << "========= THIS ROW = " << ThisRow << endl;	// for debugging
+            ThisOffset += Trans + 2;
+            ThisIndex = 0;
+            LastOffset += Trans + 2;;
+            LastRow = ThisRow - 1;
+            LastIndexCount = ThisIndexCount;
+            LastIndex = 0;
+
+            int EndLast = 0;
+            int EndThis = 0;
+
+            for (int j = 0; j < Trans + 2; j++)
+            {
+              int Index = ThisOffset + j;
+              int TranVal = Transition[Index];
+              if (TranVal > 0) ThisIndexCount = j + 1;	// stop at highest
 
-    ThisIndexCount = 1;
-    ThisRegion[0] = 0;	// Border region
+              if (ThisRegion[j] == -1) { EndLast = 1; }
+              if (TranVal < 0) { EndThis = 1; }
 
-    // beginning of the image
-    // en cada linia, pimage apunta al primer pixel de la fila
-    pImage = inputImage->imageData - 1 + startCol + startRow * inputImage->widthStep;
-    //the mask should be the same size as image Roi, so don't take into account the offset
-    if (maskImage != NULL) pMask = maskImage->imageData - 1;
+              if (EndLast > 0 && EndThis > 0) { break; }
 
-    char *pImageAux, *pMaskAux = NULL;
+              LastRegion[j] = ThisRegion[j];
+              ThisRegion[j] = -1;		// Flag indicates region is not initialized
+            }
 
-    // Loop over all rows
-    for (ThisRow = 1; ThisRow < Rows + 2; ThisRow++)
-    {
-      //cout << "========= THIS ROW = " << ThisRow << endl;	// for debugging
-      ThisOffset += Trans + 2;
-      ThisIndex = 0;
-      LastOffset += Trans + 2;;
-      LastRow = ThisRow - 1;
-      LastIndexCount = ThisIndexCount;
-      LastIndex = 0;
-
-      int EndLast = 0;
-      int EndThis = 0;
-
-      for (int j = 0; j < Trans + 2; j++)
-      {
-        int Index = ThisOffset + j;
-        int TranVal = Transition[Index];
-        if (TranVal > 0) ThisIndexCount = j + 1;	// stop at highest
+            int MaxIndexCount = LastIndexCount;
+            if (ThisIndexCount > MaxIndexCount) MaxIndexCount = ThisIndexCount;
 
-        if (ThisRegion[j] == -1) { EndLast = 1; }
-        if (TranVal < 0) { EndThis = 1; }
+            // Main loop over runs within Last and This rows
+            while (LastIndex < LastIndexCount && ThisIndex < ThisIndexCount)
+            {
+              ComputeData = 0;
+
+              if (LastIndex == 0) LastStart = 0;
+              else LastStart = Transition[LastOffset + LastIndex - 1];
+              LastEnd = Transition[LastOffset + LastIndex] - 1;
+              LastColor = LastIndex - 2 * (LastIndex / 2);
+              LastRegionNum = LastRegion[LastIndex];
+
+              regionDataLastRegion = RegionData[LastRegionNum];
+
+
+              if (ThisIndex == 0) ThisStart = 0;
+              else ThisStart = Transition[ThisOffset + ThisIndex - 1];
+              ThisEnd = Transition[ThisOffset + ThisIndex] - 1;
+              ThisColor = ThisIndex - 2 * (ThisIndex / 2);
+              ThisRegionNum = ThisRegion[ThisIndex];
+
+              if (ThisRegionNum >= 0)
+                regionDataThisRegion = RegionData[ThisRegionNum];
+              else
+                regionDataThisRegion = NULL;
+
+
+              // blobs externs
+              CandidatExterior = false;
+              if (
+      #if !IMATGE_CICLICA_VERTICAL
+                ThisRow == 1 || ThisRow == Rows ||
+      #endif
+      #if !IMATGE_CICLICA_HORITZONTAL
+                ThisStart <= 1 || ThisEnd >= Cols ||
+      #endif
+                GetExternPerimeter(ThisStart, ThisEnd, ThisRow, inputImage->width, inputImage->height, imatgePerimetreExtern)
+                )
+              {
+                CandidatExterior = true;
+              }
 
-        if (EndLast > 0 && EndThis > 0) { break; }
+              int TestA = (LastEnd < ThisStart - 1);	// initially false
+              int TestB = (ThisEnd < LastStart);		// initially false
+              int TestC = (LastStart < ThisStart);	// initially false
+              int TestD = (ThisEnd < LastEnd);
+              int TestE = (ThisEnd == LastEnd);
 
-        LastRegion[j] = ThisRegion[j];
-        ThisRegion[j] = -1;		// Flag indicates region is not initialized
-      }
+              int TestMatch = (ThisColor == LastColor);		// initially true
+              int TestKnown = (ThisRegion[ThisIndex] >= 0);	// initially false
 
-      int MaxIndexCount = LastIndexCount;
-      if (ThisIndexCount > MaxIndexCount) MaxIndexCount = ThisIndexCount;
+              int Case = 0;
+              if (TestA) Case = 1;
+              else if (TestB) Case = 8;
+              else if (TestC)
+              {
+                if (TestD) Case = 3;
+                else if (!TestE) Case = 2;
+                else Case = 4;
+              }
+              else
+              {
+                if (TestE) Case = 5;
+                else if (TestD) Case = 7;
+                else Case = 6;
+              }
 
-      // Main loop over runs within Last and This rows
-      while (LastIndex < LastIndexCount && ThisIndex < ThisIndexCount)
-      {
-        ComputeData = 0;
-
-        if (LastIndex == 0) LastStart = 0;
-        else LastStart = Transition[LastOffset + LastIndex - 1];
-        LastEnd = Transition[LastOffset + LastIndex] - 1;
-        LastColor = LastIndex - 2 * (LastIndex / 2);
-        LastRegionNum = LastRegion[LastIndex];
-
-        regionDataLastRegion = RegionData[LastRegionNum];
-
-
-        if (ThisIndex == 0) ThisStart = 0;
-        else ThisStart = Transition[ThisOffset + ThisIndex - 1];
-        ThisEnd = Transition[ThisOffset + ThisIndex] - 1;
-        ThisColor = ThisIndex - 2 * (ThisIndex / 2);
-        ThisRegionNum = ThisRegion[ThisIndex];
-
-        if (ThisRegionNum >= 0)
-          regionDataThisRegion = RegionData[ThisRegionNum];
-        else
-          regionDataThisRegion = NULL;
-
-
-        // blobs externs
-        CandidatExterior = false;
-        if (
-#if !IMATGE_CICLICA_VERTICAL
-          ThisRow == 1 || ThisRow == Rows ||
-#endif
-#if !IMATGE_CICLICA_HORITZONTAL
-          ThisStart <= 1 || ThisEnd >= Cols ||
-#endif
-          GetExternPerimeter(ThisStart, ThisEnd, ThisRow, inputImage->width, inputImage->height, imatgePerimetreExtern)
-          )
-        {
-          CandidatExterior = true;
-        }
+              // Initialize common variables
+              ThisArea = (float) 0.0;
 
-        int TestA = (LastEnd < ThisStart - 1);	// initially false
-        int TestB = (ThisEnd < LastStart);		// initially false
-        int TestC = (LastStart < ThisStart);	// initially false
-        int TestD = (ThisEnd < LastEnd);
-        int TestE = (ThisEnd == LastEnd);
+              if (findmoments)
+              {
+                ThisSumX = ThisSumY = (float) 0.0;
+                ThisSumXX = ThisSumYY = ThisSumXY = (float) 0.0;
+              }
+              ThisMinX = ThisMinY = (float) 1000000.0;
+              ThisMaxX = ThisMaxY = (float)-1.0;
 
-        int TestMatch = (ThisColor == LastColor);		// initially true
-        int TestKnown = (ThisRegion[ThisIndex] >= 0);	// initially false
+              LastPerimeter = ThisPerimeter = (float) 0.0;
+              ThisParent = (float)-1;
+              ThisExternPerimeter = 0.0;
 
-        int Case = 0;
-        if (TestA) Case = 1;
-        else if (TestB) Case = 8;
-        else if (TestC)
-        {
-          if (TestD) Case = 3;
-          else if (!TestE) Case = 2;
-          else Case = 4;
-        }
-        else
-        {
-          if (TestE) Case = 5;
-          else if (TestD) Case = 7;
-          else Case = 6;
-        }
+              // Determine necessary action and take it
+              switch (Case)
+              {
+              case 1: //|xxx    |
+                //|    yyy|
 
-        // Initialize common variables
-        ThisArea = (float) 0.0;
+                ThisRegion[ThisIndex] = ThisRegionNum;
+                LastRegion[LastIndex] = LastRegionNum;
+                LastIndex++;
 
-        if (findmoments)
-        {
-          ThisSumX = ThisSumY = (float) 0.0;
-          ThisSumXX = ThisSumYY = ThisSumXY = (float) 0.0;
-        }
-        ThisMinX = ThisMinY = (float) 1000000.0;
-        ThisMaxX = ThisMaxY = (float)-1.0;
+                //afegim la cantonada a LastRegion
+                actualedge.x = ThisEnd;
+                actualedge.y = ThisRow - 1;
+                cvSeqPush(regionDataLastRegion->edges, &actualedge);
 
-        LastPerimeter = ThisPerimeter = (float) 0.0;
-        ThisParent = (float)-1;
-        ThisExternPerimeter = 0.0;
+                //afegim la cantonada a ThisRegion
+                actualedge.x = ThisStart - 1;
+                actualedge.y = ThisRow - 1;
+                cvSeqPush(regionDataThisRegion->edges, &actualedge);
 
-        // Determine necessary action and take it
-        switch (Case)
-        {
-        case 1: //|xxx    |
-          //|    yyy|
+                break;
 
-          ThisRegion[ThisIndex] = ThisRegionNum;
-          LastRegion[LastIndex] = LastRegionNum;
-          LastIndex++;
 
-          //afegim la cantonada a LastRegion
-          actualedge.x = ThisEnd;
-          actualedge.y = ThisRow - 1;
-          cvSeqPush(regionDataLastRegion->edges, &actualedge);
+              case 2: //|xxxxoo |
+                //|    yyy|
 
-          //afegim la cantonada a ThisRegion
-          actualedge.x = ThisStart - 1;
-          actualedge.y = ThisRow - 1;
-          cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                if (TestMatch)	// Same color
+                {
+                  ThisRegionNum = LastRegionNum;
+                  regionDataThisRegion = regionDataLastRegion;
 
-          break;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  LastPerimeter = LastEnd - ThisStart + 1;	// to subtract
+                  ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter +
+                    PERIMETRE_DIAGONAL * 2;
 
+                  if (CandidatExterior)
+                  {
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
+                    ThisExternPerimeter += PERIMETRE_DIAGONAL * 2;
+                  }
+                  ComputeData = 1;
+                }
 
-        case 2: //|xxxxoo |
-          //|    yyy|
+                //afegim la cantonada a ThisRegion
+                if (ThisRegionNum != -1)
+                {
+                  // afegim dos vertexs si són diferents, només
+                  if (ThisStart - 1 != ThisEnd)
+                  {
+                    actualedge.x = ThisStart - 1;
+                    actualedge.y = ThisRow - 1;
+                    cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  }
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                }
+                //afegim la cantonada a ThisRegion
+                if (LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
+                {
+                  // afegim dos vertexs si són diferents, només
+                  if (ThisStart - 1 != ThisEnd)
+                  {
+                    actualedge.x = ThisStart - 1;
+                    actualedge.y = ThisRow - 1;
+                    cvSeqPush(regionDataLastRegion->edges, &actualedge);
+                  }
+                }
 
-          if (TestMatch)	// Same color
-          {
-            ThisRegionNum = LastRegionNum;
-            regionDataThisRegion = regionDataLastRegion;
+                ThisRegion[ThisIndex] = ThisRegionNum;
+                LastRegion[LastIndex] = LastRegionNum;
+                LastIndex++;
+                break;
 
-            ThisArea = ThisEnd - ThisStart + 1;
-            LastPerimeter = LastEnd - ThisStart + 1;	// to subtract
-            ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter +
-              PERIMETRE_DIAGONAL * 2;
 
-            if (CandidatExterior)
-            {
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
-              ThisExternPerimeter += PERIMETRE_DIAGONAL * 2;
-            }
-            ComputeData = 1;
-          }
+              case 3: //|xxxxxxx|
+                //|  yyyy |
 
-          //afegim la cantonada a ThisRegion
-          if (ThisRegionNum != -1)
-          {
-            // afegim dos vertexs si són diferents, només
-            if (ThisStart - 1 != ThisEnd)
-            {
-              actualedge.x = ThisStart - 1;
-              actualedge.y = ThisRow - 1;
-              cvSeqPush(regionDataThisRegion->edges, &actualedge);
-            }
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataThisRegion->edges, &actualedge);
-          }
-          //afegim la cantonada a ThisRegion
-          if (LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
-          {
-            // afegim dos vertexs si són diferents, només
-            if (ThisStart - 1 != ThisEnd)
-            {
-              actualedge.x = ThisStart - 1;
-              actualedge.y = ThisRow - 1;
-              cvSeqPush(regionDataLastRegion->edges, &actualedge);
-            }
-          }
+                if (TestMatch)	// Same color
+                {
+                  ThisRegionNum = LastRegionNum;
+                  regionDataThisRegion = regionDataLastRegion;
 
-          ThisRegion[ThisIndex] = ThisRegionNum;
-          LastRegion[LastIndex] = LastRegionNum;
-          LastIndex++;
-          break;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  LastPerimeter = ThisArea;	// to subtract
+                  ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL * 2;
+                  if (CandidatExterior)
+                  {
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
 
+                    ThisExternPerimeter += PERIMETRE_DIAGONAL * 2;
+                  }
+                }
+                else		// Different color => New region
+                {
+                  ThisParent = LastRegionNum;
+                  ThisRegionNum = ++HighRegionNum;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  ThisPerimeter = 2 + 2 * ThisArea;
+                  RegionData.push_back(new CBlob());
+                  regionDataThisRegion = RegionData.back();
+
+                  SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum);
+                  if (CandidatExterior)
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
 
-        case 3: //|xxxxxxx|
-          //|  yyyy |
+                }
 
-          if (TestMatch)	// Same color
-          {
-            ThisRegionNum = LastRegionNum;
-            regionDataThisRegion = regionDataLastRegion;
+                if (ThisRegionNum != -1)
+                {
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisStart - 1;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                }
+                // si hem creat un nou blob, afegim tb a l'anterior
+                if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
+                {
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisStart - 1;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataLastRegion->edges, &actualedge);
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataLastRegion->edges, &actualedge);
+                }
 
-            ThisArea = ThisEnd - ThisStart + 1;
-            LastPerimeter = ThisArea;	// to subtract
-            ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL * 2;
-            if (CandidatExterior)
-            {
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
+                ThisRegion[ThisIndex] = ThisRegionNum;
+                LastRegion[LastIndex] = LastRegionNum;
+                ComputeData = 1;
+                ThisIndex++;
+                break;
 
-              ThisExternPerimeter += PERIMETRE_DIAGONAL * 2;
-            }
-          }
-          else		// Different color => New region
-          {
-            ThisParent = LastRegionNum;
-            ThisRegionNum = ++HighRegionNum;
-            ThisArea = ThisEnd - ThisStart + 1;
-            ThisPerimeter = 2 + 2 * ThisArea;
-            RegionData.push_back(new CBlob());
-            regionDataThisRegion = RegionData.back();
-
-            SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum);
-            if (CandidatExterior)
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
 
-          }
+              case 4:	//|xxxxxxx|
+                //|  yyyyy|
 
-          if (ThisRegionNum != -1)
-          {
-            //afegim la cantonada a la regio
-            actualedge.x = ThisStart - 1;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataThisRegion->edges, &actualedge);
-            //afegim la cantonada a la regio
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataThisRegion->edges, &actualedge);
-          }
-          // si hem creat un nou blob, afegim tb a l'anterior
-          if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
-          {
-            //afegim la cantonada a la regio
-            actualedge.x = ThisStart - 1;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataLastRegion->edges, &actualedge);
-            //afegim la cantonada a la regio
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataLastRegion->edges, &actualedge);
-          }
+                if (TestMatch)	// Same color
+                {
+                  ThisRegionNum = LastRegionNum;
+                  regionDataThisRegion = regionDataLastRegion;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  LastPerimeter = ThisArea;	// to subtract
+                  ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL;
+                  if (CandidatExterior)
+                  {
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
 
-          ThisRegion[ThisIndex] = ThisRegionNum;
-          LastRegion[LastIndex] = LastRegionNum;
-          ComputeData = 1;
-          ThisIndex++;
-          break;
+                    ThisExternPerimeter += PERIMETRE_DIAGONAL;
+                  }
+                }
+                else		// Different color => New region
+                {
+                  ThisParent = LastRegionNum;
+                  ThisRegionNum = ++HighRegionNum;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  ThisPerimeter = 2 + 2 * ThisArea;
+                  RegionData.push_back(new CBlob());
+                  regionDataThisRegion = RegionData.back();
+                  SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum);
+                  if (CandidatExterior)
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
 
+                }
 
-        case 4:	//|xxxxxxx|
-          //|  yyyyy|
+                if (ThisRegionNum != -1)
+                {
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisStart - 1;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                }
+                // si hem creat un nou blob, afegim tb a l'anterior
+                if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
+                {
+                  actualedge.x = ThisStart - 1;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataLastRegion->edges, &actualedge);
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataLastRegion->edges, &actualedge);
+                }
 
-          if (TestMatch)	// Same color
-          {
-            ThisRegionNum = LastRegionNum;
-            regionDataThisRegion = regionDataLastRegion;
-            ThisArea = ThisEnd - ThisStart + 1;
-            LastPerimeter = ThisArea;	// to subtract
-            ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL;
-            if (CandidatExterior)
-            {
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
+                ThisRegion[ThisIndex] = ThisRegionNum;
+                LastRegion[LastIndex] = LastRegionNum;
+                ComputeData = 1;
 
-              ThisExternPerimeter += PERIMETRE_DIAGONAL;
-            }
-          }
-          else		// Different color => New region
-          {
-            ThisParent = LastRegionNum;
-            ThisRegionNum = ++HighRegionNum;
-            ThisArea = ThisEnd - ThisStart + 1;
-            ThisPerimeter = 2 + 2 * ThisArea;
-            RegionData.push_back(new CBlob());
-            regionDataThisRegion = RegionData.back();
-            SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum);
-            if (CandidatExterior)
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
+      #ifdef B_CONNECTIVITAT_8
+                if (TestMatch)
+                {
+                  LastIndex++;
+                  ThisIndex++;
+                }
+                else
+                {
+                  LastIndex++;
+                }
+      #else
+                LastIndex++;
+                ThisIndex++;
+      #endif					
+                break;
 
-          }
 
-          if (ThisRegionNum != -1)
-          {
-            //afegim la cantonada a la regio
-            actualedge.x = ThisStart - 1;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataThisRegion->edges, &actualedge);
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataThisRegion->edges, &actualedge);
-          }
-          // si hem creat un nou blob, afegim tb a l'anterior
-          if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
-          {
-            actualedge.x = ThisStart - 1;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataLastRegion->edges, &actualedge);
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataLastRegion->edges, &actualedge);
-          }
+              case 5:	//|ooxxxxx|
+                //|yyyyyyy|
 
-          ThisRegion[ThisIndex] = ThisRegionNum;
-          LastRegion[LastIndex] = LastRegionNum;
-          ComputeData = 1;
+                if (!TestMatch && !TestKnown)	// Different color and unknown => new region
+                {
+                  ThisParent = LastRegionNum;
+                  ThisRegionNum = ++HighRegionNum;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  ThisPerimeter = 2 + 2 * ThisArea;
+                  RegionData.push_back(new CBlob());
+                  regionDataThisRegion = RegionData.back();
+                  SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum);
+                  if (CandidatExterior)
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
 
-#ifdef B_CONNECTIVITAT_8
-          if (TestMatch)
-          {
-            LastIndex++;
-            ThisIndex++;
-          }
-          else
-          {
-            LastIndex++;
-          }
-#else
-          LastIndex++;
-          ThisIndex++;
-#endif					
-          break;
+                }
+                else if (TestMatch && !TestKnown)	// Same color and unknown
+                {
+                  ThisRegionNum = LastRegionNum;
+                  regionDataThisRegion = regionDataLastRegion;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  LastPerimeter = LastEnd - LastStart + 1;	// to subtract
+                  ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
+                    + PERIMETRE_DIAGONAL * (LastStart != ThisStart);
+                  if (CandidatExterior)
+                  {
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
 
 
-        case 5:	//|ooxxxxx|
-          //|yyyyyyy|
+                    ThisExternPerimeter += PERIMETRE_DIAGONAL * (LastStart != ThisStart);
+                  }
+                  ComputeData = 1;
+                }
+                else if (TestMatch && TestKnown)	// Same color and known
+                {
+                  LastPerimeter = LastEnd - LastStart + 1;	// to subtract
+                  //ThisPerimeter = - LastPerimeter;
+                  ThisPerimeter = -2 * LastPerimeter
+                    + PERIMETRE_DIAGONAL * (LastStart != ThisStart);
 
-          if (!TestMatch && !TestKnown)	// Different color and unknown => new region
-          {
-            ThisParent = LastRegionNum;
-            ThisRegionNum = ++HighRegionNum;
-            ThisArea = ThisEnd - ThisStart + 1;
-            ThisPerimeter = 2 + 2 * ThisArea;
-            RegionData.push_back(new CBlob());
-            regionDataThisRegion = RegionData.back();
-            SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum);
-            if (CandidatExterior)
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
+                  if (ThisRegionNum > LastRegionNum)
+                  {
+                    Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion,
+                      findmoments, ThisRegionNum, LastRegionNum);
+                    for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+                    {
+                      if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
+                      if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+                    }
+                    ThisRegionNum = LastRegionNum;
+                  }
+                  else if (ThisRegionNum < LastRegionNum)
+                  {
+                    Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion,
+                      findmoments, LastRegionNum, ThisRegionNum);
+
+                    for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+                    {
+                      if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
+                      if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
+                    }
+                    LastRegionNum = ThisRegionNum;
+                  }
+                }
 
-          }
-          else if (TestMatch && !TestKnown)	// Same color and unknown
-          {
-            ThisRegionNum = LastRegionNum;
-            regionDataThisRegion = regionDataLastRegion;
-            ThisArea = ThisEnd - ThisStart + 1;
-            LastPerimeter = LastEnd - LastStart + 1;	// to subtract
-            ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
-              + PERIMETRE_DIAGONAL * (LastStart != ThisStart);
-            if (CandidatExterior)
-            {
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
 
+                if (ThisRegionNum != -1)
+                {
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataThisRegion->edges, &actualedge);
 
-              ThisExternPerimeter += PERIMETRE_DIAGONAL * (LastStart != ThisStart);
-            }
-            ComputeData = 1;
-          }
-          else if (TestMatch && TestKnown)	// Same color and known
-          {
-            LastPerimeter = LastEnd - LastStart + 1;	// to subtract
-            //ThisPerimeter = - LastPerimeter;
-            ThisPerimeter = -2 * LastPerimeter
-              + PERIMETRE_DIAGONAL * (LastStart != ThisStart);
+                  if (ThisStart - 1 != LastEnd)
+                  {
+                    //afegim la cantonada a la regio
+                    actualedge.x = ThisStart - 1;
+                    actualedge.y = ThisRow - 1;
+                    cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  }
+                }
+                // si hem creat un nou blob, afegim tb a l'anterior
+                if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
+                {
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataLastRegion->edges, &actualedge);
+                }
 
-            if (ThisRegionNum > LastRegionNum)
-            {
-              Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion,
-                findmoments, ThisRegionNum, LastRegionNum);
-              for (int iOld = 0; iOld < MaxIndexCount; iOld++)
-              {
-                if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
-                if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
-              }
-              ThisRegionNum = LastRegionNum;
-            }
-            else if (ThisRegionNum < LastRegionNum)
-            {
-              Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion,
-                findmoments, LastRegionNum, ThisRegionNum);
+                ThisRegion[ThisIndex] = ThisRegionNum;
+                LastRegion[LastIndex] = LastRegionNum;
 
-              for (int iOld = 0; iOld < MaxIndexCount; iOld++)
-              {
-                if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
-                if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
-              }
-              LastRegionNum = ThisRegionNum;
-            }
-          }
+      #ifdef B_CONNECTIVITAT_8
+                if (TestMatch)
+                {
+                  LastIndex++;
+                  ThisIndex++;
+                }
+                else
+                {
+                  LastIndex++;
+                }
+      #else
+                LastIndex++;
+                ThisIndex++;
+      #endif	
+                break;
 
 
-          if (ThisRegionNum != -1)
-          {
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataThisRegion->edges, &actualedge);
+              case 6:	//|ooxxx  |
+                //|yyyyyyy|
 
-            if (ThisStart - 1 != LastEnd)
-            {
-              //afegim la cantonada a la regio
-              actualedge.x = ThisStart - 1;
-              actualedge.y = ThisRow - 1;
-              cvSeqPush(regionDataThisRegion->edges, &actualedge);
-            }
-          }
-          // si hem creat un nou blob, afegim tb a l'anterior
-          if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
-          {
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataLastRegion->edges, &actualedge);
-          }
+                if (TestMatch && !TestKnown)
+                {
+                  ThisRegionNum = LastRegionNum;
+                  regionDataThisRegion = regionDataLastRegion;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  LastPerimeter = LastEnd - LastStart + 1;	// to subtract
+                  ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
+                    + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
+                  if (CandidatExterior)
+                  {
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
 
-          ThisRegion[ThisIndex] = ThisRegionNum;
-          LastRegion[LastIndex] = LastRegionNum;
 
-#ifdef B_CONNECTIVITAT_8
-          if (TestMatch)
-          {
-            LastIndex++;
-            ThisIndex++;
-          }
-          else
-          {
-            LastIndex++;
-          }
-#else
-          LastIndex++;
-          ThisIndex++;
-#endif	
-          break;
+                    ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
+                  }
+                  ComputeData = 1;
+                }
+                else if (TestMatch && TestKnown)
+                {
+                  LastPerimeter = LastEnd - LastStart + 1;	// to subtract
+                  //ThisPerimeter = - LastPerimeter;
+                  ThisPerimeter = -2 * LastPerimeter
+                    + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
 
+                  if (ThisRegionNum > LastRegionNum)
+                  {
+                    Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion,
+                      findmoments, ThisRegionNum, LastRegionNum);
+                    for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+                    {
+                      if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
+                      if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+                    }
+                    ThisRegionNum = LastRegionNum;
+                  }
+                  else if (ThisRegionNum < LastRegionNum)
+                  {
+                    Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion,
+                      findmoments, LastRegionNum, ThisRegionNum);
+                    for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+                    {
+                      if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
+                      if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
+                    }
+                    LastRegionNum = ThisRegionNum;
+                  }
+                }
 
-        case 6:	//|ooxxx  |
-          //|yyyyyyy|
 
-          if (TestMatch && !TestKnown)
-          {
-            ThisRegionNum = LastRegionNum;
-            regionDataThisRegion = regionDataLastRegion;
-            ThisArea = ThisEnd - ThisStart + 1;
-            LastPerimeter = LastEnd - LastStart + 1;	// to subtract
-            ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
-              + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
-            if (CandidatExterior)
-            {
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
+                if (ThisRegionNum != -1)
+                {
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  if (ThisStart - 1 != LastEnd)
+                  {
+                    actualedge.x = ThisStart - 1;
+                    actualedge.y = ThisRow - 1;
+                    cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  }
+                }
+                // si hem creat un nou blob, afegim tb a l'anterior
+                if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
+                {
+                  //afegim la cantonada a la regio
+                  if (ThisStart - 1 != LastEnd)
+                  {
+                    actualedge.x = ThisStart - 1;
+                    actualedge.y = ThisRow - 1;
+                    cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  }
+                }
 
+                ThisRegion[ThisIndex] = ThisRegionNum;
+                LastRegion[LastIndex] = LastRegionNum;
+                LastIndex++;
+                break;
 
-              ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
-            }
-            ComputeData = 1;
-          }
-          else if (TestMatch && TestKnown)
-          {
-            LastPerimeter = LastEnd - LastStart + 1;	// to subtract
-            //ThisPerimeter = - LastPerimeter;
-            ThisPerimeter = -2 * LastPerimeter
-              + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
 
-            if (ThisRegionNum > LastRegionNum)
-            {
-              Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion,
-                findmoments, ThisRegionNum, LastRegionNum);
-              for (int iOld = 0; iOld < MaxIndexCount; iOld++)
-              {
-                if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
-                if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
-              }
-              ThisRegionNum = LastRegionNum;
-            }
-            else if (ThisRegionNum < LastRegionNum)
-            {
-              Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion,
-                findmoments, LastRegionNum, ThisRegionNum);
-              for (int iOld = 0; iOld < MaxIndexCount; iOld++)
-              {
-                if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
-                if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
-              }
-              LastRegionNum = ThisRegionNum;
-            }
-          }
+              case 7:	//|ooxxxxx|
+                //|yyyy   |
 
+                if (!TestMatch && !TestKnown)	// Different color and unknown => new region
+                {
+                  ThisParent = LastRegionNum;
+                  ThisRegionNum = ++HighRegionNum;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  ThisPerimeter = 2 + 2 * ThisArea;
+                  RegionData.push_back(new CBlob());
+                  regionDataThisRegion = RegionData.back();
+                  SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum);
+                  if (CandidatExterior)
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
 
-          if (ThisRegionNum != -1)
-          {
-            //afegim la cantonada a la regio
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataThisRegion->edges, &actualedge);
-            if (ThisStart - 1 != LastEnd)
-            {
-              actualedge.x = ThisStart - 1;
-              actualedge.y = ThisRow - 1;
-              cvSeqPush(regionDataThisRegion->edges, &actualedge);
-            }
-          }
-          // si hem creat un nou blob, afegim tb a l'anterior
-          if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
-          {
-            //afegim la cantonada a la regio
-            if (ThisStart - 1 != LastEnd)
-            {
-              actualedge.x = ThisStart - 1;
-              actualedge.y = ThisRow - 1;
-              cvSeqPush(regionDataThisRegion->edges, &actualedge);
-            }
-          }
+                }
+                else if (TestMatch && !TestKnown)
+                {
+                  ThisRegionNum = LastRegionNum;
+                  regionDataThisRegion = regionDataLastRegion;
+                  ThisArea = ThisEnd - ThisStart + 1;
+                  ThisPerimeter = 2 + ThisArea;
+                  LastPerimeter = ThisEnd - LastStart + 1;
+                  ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
+                    + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
+                  if (CandidatExterior)
+                  {
+                    ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
+                      inputImage->width, inputImage->height,
+                      imatgePerimetreExtern);
 
-          ThisRegion[ThisIndex] = ThisRegionNum;
-          LastRegion[LastIndex] = LastRegionNum;
-          LastIndex++;
-          break;
+                    ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
+                  }
+                  ComputeData = 1;
+                }
+                else if (TestMatch && TestKnown)
+                {
+                  LastPerimeter = ThisEnd - LastStart + 1;	// to subtract
+                  //ThisPerimeter = - LastPerimeter;
+                  ThisPerimeter = -2 * LastPerimeter
+                    + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
 
+                  if (ThisRegionNum > LastRegionNum)
+                  {
+                    Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion,
+                      findmoments, ThisRegionNum, LastRegionNum);
+                    for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+                    {
+                      if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
+                      if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+                    }
+                    ThisRegionNum = LastRegionNum;
+                  }
+                  else if (ThisRegionNum < LastRegionNum)
+                  {
+                    Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion,
+                      findmoments, LastRegionNum, ThisRegionNum);
+                    for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+                    {
+                      if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
+                      if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
+                    }
+                    LastRegionNum = ThisRegionNum;
+                  }
+                }
 
-        case 7:	//|ooxxxxx|
-          //|yyyy   |
+                if (ThisRegionNum != -1)
+                {
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  if (ThisStart - 1 != LastEnd)
+                  {
+                    actualedge.x = ThisStart - 1;
+                    actualedge.y = ThisRow - 1;
+                    cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  }
+                }
+                // si hem creat un nou blob, afegim tb a l'anterior
+                if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
+                {
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisEnd;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataLastRegion->edges, &actualedge);
+                  if (ThisStart - 1 != LastEnd)
+                  {
+                    actualedge.x = ThisStart - 1;
+                    actualedge.y = ThisRow - 1;
+                    cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                  }
+                }
 
-          if (!TestMatch && !TestKnown)	// Different color and unknown => new region
-          {
-            ThisParent = LastRegionNum;
-            ThisRegionNum = ++HighRegionNum;
-            ThisArea = ThisEnd - ThisStart + 1;
-            ThisPerimeter = 2 + 2 * ThisArea;
-            RegionData.push_back(new CBlob());
-            regionDataThisRegion = RegionData.back();
-            SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum);
-            if (CandidatExterior)
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
+                ThisRegion[ThisIndex] = ThisRegionNum;
+                LastRegion[LastIndex] = LastRegionNum;
+                ThisIndex++;
+                break;
 
-          }
-          else if (TestMatch && !TestKnown)
-          {
-            ThisRegionNum = LastRegionNum;
-            regionDataThisRegion = regionDataLastRegion;
-            ThisArea = ThisEnd - ThisStart + 1;
-            ThisPerimeter = 2 + ThisArea;
-            LastPerimeter = ThisEnd - LastStart + 1;
-            ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
-              + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
-            if (CandidatExterior)
-            {
-              ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow,
-                inputImage->width, inputImage->height,
-                imatgePerimetreExtern);
+              case 8:	//|    xxx|
+                //|yyyy   |
 
-              ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
-            }
-            ComputeData = 1;
-          }
-          else if (TestMatch && TestKnown)
-          {
-            LastPerimeter = ThisEnd - LastStart + 1;	// to subtract
-            //ThisPerimeter = - LastPerimeter;
-            ThisPerimeter = -2 * LastPerimeter
-              + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart);
+      #ifdef B_CONNECTIVITAT_8					
+              // fusionem blobs
+                if (TestMatch)
+                {
+                  if (ThisRegionNum > LastRegionNum)
+                  {
+                    Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion,
+                      findmoments, ThisRegionNum, LastRegionNum);
+                    for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+                    {
+                      if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
+                      if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+                    }
+                    ThisRegionNum = LastRegionNum;
+                  }
+                  else if (ThisRegionNum < LastRegionNum)
+                  {
+                    Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion,
+                      findmoments, LastRegionNum, ThisRegionNum);
+                    for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+                    {
+                      if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
+                      if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
+                    }
+                    LastRegionNum = ThisRegionNum;
+                  }
 
-            if (ThisRegionNum > LastRegionNum)
-            {
-              Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion,
-                findmoments, ThisRegionNum, LastRegionNum);
-              for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+                  regionDataThisRegion->perimeter = regionDataThisRegion->perimeter + PERIMETRE_DIAGONAL * 2;
+                }
+      #endif
+
+                if (ThisRegionNum != -1)
+                {
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisStart - 1;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataThisRegion->edges, &actualedge);
+                }
+      #ifdef B_CONNECTIVITAT_8					
+                // si hem creat un nou blob, afegim tb a l'anterior
+                if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
+                {
+      #endif					
+                  //afegim la cantonada a la regio
+                  actualedge.x = ThisStart - 1;
+                  actualedge.y = ThisRow - 1;
+                  cvSeqPush(regionDataLastRegion->edges, &actualedge);
+      #ifdef B_CONNECTIVITAT_8
+                }
+      #endif
+
+                ThisRegion[ThisIndex] = ThisRegionNum;
+                LastRegion[LastIndex] = LastRegionNum;
+                ThisIndex++;
+      #ifdef B_CONNECTIVITAT_8					
+                LastIndex--;
+      #endif
+                break;
+
+              default:
+                ErrorFlag = -1;
+              }	// end switch case
+
+              // calculate the blob moments and mean gray level of the current blob (ThisRegionNum)
+              if (ComputeData > 0)
               {
-                if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
-                if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+                // compute blob moments if necessary
+                if (findmoments)
+                {
+                  float ImageRow = (float)(ThisRow - 1);
+
+                  for (int k = ThisStart; k <= ThisEnd; k++)
+                  {
+                    ThisSumX += (float)(k - 1);
+                    ThisSumXX += (float)(k - 1) * (k - 1);
+                  }
+
+                  ThisSumXY = ThisSumX * ImageRow;
+                  ThisSumY = ThisArea * ImageRow;
+                  ThisSumYY = ThisSumY * ImageRow;
+
+                }
+
+                // compute the mean gray level and its std deviation
+                if (ThisRow <= Rows)
+                {
+                  pImageAux = pImage + ThisStart;
+                  if (maskImage != NULL) pMaskAux = pMask + ThisStart;
+                  for (int k = ThisStart; k <= ThisEnd; k++)
+                  {
+                    if ((k > 0) && (k <= Cols))
+                    {
+                      if (maskImage != NULL)
+                      {
+                        // només es té en compte el valor del píxel de la
+                        // imatge que queda dins de la màscara
+                        // (de pas, comptem el nombre de píxels de la màscara)
+                        if (((unsigned char)*pMaskAux) != PIXEL_EXTERIOR)
+                        {
+                          imagevalue = (unsigned char)(*pImageAux);
+                          regionDataThisRegion->mean += imagevalue;
+                          regionDataThisRegion->stddev += imagevalue*imagevalue;
+                        }
+                        else
+                        {
+                          nombre_pixels_mascara++;
+                        }
+                      }
+                      else
+                      {
+                        imagevalue = (unsigned char)(*pImageAux);
+                        regionDataThisRegion->mean += imagevalue;
+                        regionDataThisRegion->stddev += imagevalue*imagevalue;
+
+                      }
+                    }
+                    pImageAux++;
+                    if (maskImage != NULL) pMaskAux++;
+                  }
+                }
+
+                // compute the min and max values of X and Y
+                if (ThisStart - 1 < (int)ThisMinX) ThisMinX = (float)(ThisStart - 1);
+                if (ThisMinX < (float) 0.0) ThisMinX = (float) 0.0;
+                if (ThisEnd > (int) ThisMaxX) ThisMaxX = (float)ThisEnd;
+
+                if (ThisRow - 1 < ThisMinY) ThisMinY = ThisRow - 1;
+                if (ThisMinY < (float) 0.0) ThisMinY = (float) 0.0;
+                if (ThisRow > ThisMaxY) ThisMaxY = ThisRow;
               }
-              ThisRegionNum = LastRegionNum;
-            }
-            else if (ThisRegionNum < LastRegionNum)
-            {
-              Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion,
-                findmoments, LastRegionNum, ThisRegionNum);
-              for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+
+              // put the current results into RegionData
+              if (ThisRegionNum >= 0)
               {
-                if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
-                if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
+                if (ThisParent >= 0) { regionDataThisRegion->parent = (int)ThisParent; }
+                regionDataThisRegion->etiqueta = ThisRegionNum;
+                regionDataThisRegion->area += ThisArea;
+                regionDataThisRegion->perimeter += ThisPerimeter;
+                regionDataThisRegion->externPerimeter += ThisExternPerimeter;
+
+                if (ComputeData > 0)
+                {
+                  if (findmoments)
+                  {
+                    regionDataThisRegion->sumx += ThisSumX;
+                    regionDataThisRegion->sumy += ThisSumY;
+                    regionDataThisRegion->sumxx += ThisSumXX;
+                    regionDataThisRegion->sumyy += ThisSumYY;
+                    regionDataThisRegion->sumxy += ThisSumXY;
+                  }
+                  regionDataThisRegion->perimeter -= LastPerimeter;
+                  regionDataThisRegion->minx = MIN(regionDataThisRegion->minx, ThisMinX);
+                  regionDataThisRegion->maxx = MAX(regionDataThisRegion->maxx, ThisMaxX);
+                  regionDataThisRegion->miny = MIN(regionDataThisRegion->miny, ThisMinY);
+                  regionDataThisRegion->maxy = MAX(regionDataThisRegion->maxy, ThisMaxY);
+                }
+                // blobs externs
+                if (CandidatExterior)
+                {
+                  regionDataThisRegion->exterior = true;
+                }
+
               }
-              LastRegionNum = ThisRegionNum;
-            }
-          }
+            }	// end Main loop
 
-          if (ThisRegionNum != -1)
-          {
-            //afegim la cantonada a la regio
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataThisRegion->edges, &actualedge);
-            if (ThisStart - 1 != LastEnd)
-            {
-              actualedge.x = ThisStart - 1;
-              actualedge.y = ThisRow - 1;
-              cvSeqPush(regionDataThisRegion->edges, &actualedge);
+            if (ErrorFlag != 0) {
+              delete[] Transition;
+              delete[] ThisRegion;
+              delete[] LastRegion;
+              return false;
             }
-          }
-          // si hem creat un nou blob, afegim tb a l'anterior
-          if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
+            // ens situem al primer pixel de la seguent fila
+            pImage = inputImage->imageData - 1 + startCol + (ThisRow + startRow) * inputImage->widthStep;
+
+            if (maskImage != NULL)
+              pMask = maskImage->imageData - 1 + ThisRow * maskImage->widthStep;
+          }	// end Loop over all rows
+
+          // eliminem l'àrea del marc
+          // i també els píxels de la màscara
+          // ATENCIO: PERFER: el fet de restar el nombre_pixels_mascara del
+          // blob 0 només serà cert si la màscara té contacte amb el marc.
+          // Si no, s'haurà de trobar quin és el blob que conté més píxels del
+          // compte.
+          RegionData[0]->area -= (Rows + 1 + Cols + 1) * 2 + nombre_pixels_mascara;
+
+          // eliminem el perímetre de més:
+          // - sense marc: 2m+2n (perímetre extern)
+          // - amb marc:   2(m+2)+2(n+2) = 2m+2n + 8
+          // (segurament no és del tot acurat)
+          // (i amb les màscares encara menys...)
+          RegionData[0]->perimeter -= 8.0;
+
+          // Condense the list
+          blob_vector::iterator itNew, itOld, iti;
+          CBlob *blobActual;
+
+          itNew = RegionData.begin();
+          itOld = RegionData.begin();
+          int iNew = 0;
+          for (int iOld = 0; iOld <= HighRegionNum; iOld++, itOld++)
           {
-            //afegim la cantonada a la regio
-            actualedge.x = ThisEnd;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataLastRegion->edges, &actualedge);
-            if (ThisStart - 1 != LastEnd)
+            if (SubsumedRegion[iOld] < 1)	// This number not subsumed
             {
-              actualedge.x = ThisStart - 1;
-              actualedge.y = ThisRow - 1;
-              cvSeqPush(regionDataThisRegion->edges, &actualedge);
+              // Move data from old region number to new region number
+              //*RegionData[iNew] = *RegionData[iOld];
+              **itNew = **itOld;
+
+              // Update and parent pointer if necessary
+              iti = RegionData.begin();
+              for (int i = 0; i <= HighRegionNum; i++)
+              {
+                //if(RegionData[i]->parent == iOld) { RegionData[i]->parent = iNew; }
+                if ((*iti)->parent == iOld) { (*iti)->parent = iNew; }
+
+                ++iti;
+              }
+              iNew++;
+              ++itNew;
             }
           }
 
-          ThisRegion[ThisIndex] = ThisRegionNum;
-          LastRegion[LastIndex] = LastRegionNum;
-          ThisIndex++;
-          break;
 
-        case 8:	//|    xxx|
-          //|yyyy   |
+          HighRegionNum = iNew - 1;				// Update where the data ends
+          RegionData[HighRegionNum]->parent = -1;	// and set end of array flag
 
-#ifdef B_CONNECTIVITAT_8					
-        // fusionem blobs
-          if (TestMatch)
+
+          if (findmoments)
           {
-            if (ThisRegionNum > LastRegionNum)
+            iti = RegionData.begin();
+            // Normalize summation fields into moments
+            for (ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
             {
-              Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion,
-                findmoments, ThisRegionNum, LastRegionNum);
-              for (int iOld = 0; iOld < MaxIndexCount; iOld++)
+              blobActual = *iti;
+
+              // Get averages
+              blobActual->sumx /= blobActual->area;
+              blobActual->sumy /= blobActual->area;
+              blobActual->sumxx /= blobActual->area;
+              blobActual->sumyy /= blobActual->area;
+              blobActual->sumxy /= blobActual->area;
+
+              // Create moments
+              blobActual->sumxx -= blobActual->sumx * blobActual->sumx;
+              blobActual->sumyy -= blobActual->sumy * blobActual->sumy;
+              blobActual->sumxy -= blobActual->sumx * blobActual->sumy;
+              if (blobActual->sumxy > -1.0E-14 && blobActual->sumxy < 1.0E-14)
               {
-                if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
-                if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+                blobActual->sumxy = (float) 0.0; // Eliminate roundoff error
               }
-              ThisRegionNum = LastRegionNum;
-            }
-            else if (ThisRegionNum < LastRegionNum)
-            {
-              Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion,
-                findmoments, LastRegionNum, ThisRegionNum);
-              for (int iOld = 0; iOld < MaxIndexCount; iOld++)
-              {
-                if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
-                if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
-              }
-              LastRegionNum = ThisRegionNum;
-            }
 
-            regionDataThisRegion->perimeter = regionDataThisRegion->perimeter + PERIMETRE_DIAGONAL * 2;
+            }
           }
-#endif
 
-          if (ThisRegionNum != -1)
-          {
-            //afegim la cantonada a la regio
-            actualedge.x = ThisStart - 1;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataThisRegion->edges, &actualedge);
-          }
-#ifdef B_CONNECTIVITAT_8					
-          // si hem creat un nou blob, afegim tb a l'anterior
-          if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum)
-          {
-#endif					
-            //afegim la cantonada a la regio
-            actualedge.x = ThisStart - 1;
-            actualedge.y = ThisRow - 1;
-            cvSeqPush(regionDataLastRegion->edges, &actualedge);
-#ifdef B_CONNECTIVITAT_8
-          }
-#endif
-
-          ThisRegion[ThisIndex] = ThisRegionNum;
-          LastRegion[LastIndex] = LastRegionNum;
-          ThisIndex++;
-#ifdef B_CONNECTIVITAT_8					
-          LastIndex--;
-#endif
-          break;
-
-        default:
-          ErrorFlag = -1;
-        }	// end switch case
-
-        // calculate the blob moments and mean gray level of the current blob (ThisRegionNum)
-        if (ComputeData > 0)
-        {
-          // compute blob moments if necessary
-          if (findmoments)
+          //Get the real mean and std deviation
+          iti = RegionData.begin();
+          for (ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
           {
-            float ImageRow = (float)(ThisRow - 1);
-
-            for (int k = ThisStart; k <= ThisEnd; k++)
+            blobActual = *iti;
+            if (blobActual->area > 1)
             {
-              ThisSumX += (float)(k - 1);
-              ThisSumXX += (float)(k - 1) * (k - 1);
+              blobActual->stddev =
+                sqrt(
+                (
+                  blobActual->stddev * blobActual->area -
+                  blobActual->mean * blobActual->mean
+                  ) /
+                  (blobActual->area*(blobActual->area - 1))
+                );
             }
+            else
+              blobActual->stddev = 0;
 
-            ThisSumXY = ThisSumX * ImageRow;
-            ThisSumY = ThisArea * ImageRow;
-            ThisSumYY = ThisSumY * ImageRow;
+            if (blobActual->area > 0)
+              blobActual->mean /= blobActual->area;
+            else
+              blobActual->mean = 0;
 
           }
-
-          // compute the mean gray level and its std deviation
-          if (ThisRow <= Rows)
+          // eliminem els blobs subsumats
+          blob_vector::iterator itBlobs = RegionData.begin() + HighRegionNum + 1;
+          while (itBlobs != RegionData.end())
           {
-            pImageAux = pImage + ThisStart;
-            if (maskImage != NULL) pMaskAux = pMask + ThisStart;
-            for (int k = ThisStart; k <= ThisEnd; k++)
-            {
-              if ((k > 0) && (k <= Cols))
-              {
-                if (maskImage != NULL)
-                {
-                  // només es té en compte el valor del píxel de la
-                  // imatge que queda dins de la màscara
-                  // (de pas, comptem el nombre de píxels de la màscara)
-                  if (((unsigned char)*pMaskAux) != PIXEL_EXTERIOR)
-                  {
-                    imagevalue = (unsigned char)(*pImageAux);
-                    regionDataThisRegion->mean += imagevalue;
-                    regionDataThisRegion->stddev += imagevalue*imagevalue;
-                  }
-                  else
-                  {
-                    nombre_pixels_mascara++;
-                  }
-                }
-                else
-                {
-                  imagevalue = (unsigned char)(*pImageAux);
-                  regionDataThisRegion->mean += imagevalue;
-                  regionDataThisRegion->stddev += imagevalue*imagevalue;
-
-                }
-              }
-              pImageAux++;
-              if (maskImage != NULL) pMaskAux++;
-            }
+            delete *itBlobs;
+            //RegionData.erase( itBlobs );
+            ++itBlobs;
           }
+          RegionData.erase(RegionData.begin() + HighRegionNum + 1, RegionData.end());
 
-          // compute the min and max values of X and Y
-          if (ThisStart - 1 < (int)ThisMinX) ThisMinX = (float)(ThisStart - 1);
-          if (ThisMinX < (float) 0.0) ThisMinX = (float) 0.0;
-          if (ThisEnd > (int) ThisMaxX) ThisMaxX = (float)ThisEnd;
+          //free(RegionData);
+          free(SubsumedRegion);
+          delete[] Transition;
+          delete[] ThisRegion;
+          delete[] LastRegion;
 
-          if (ThisRow - 1 < ThisMinY) ThisMinY = ThisRow - 1;
-          if (ThisMinY < (float) 0.0) ThisMinY = (float) 0.0;
-          if (ThisRow > ThisMaxY) ThisMaxY = ThisRow;
+          if (imatgePerimetreExtern) cvReleaseImage(&imatgePerimetreExtern);
+
+          return true;
         }
 
-        // put the current results into RegionData
-        if (ThisRegionNum >= 0)
-        {
-          if (ThisParent >= 0) { regionDataThisRegion->parent = (int)ThisParent; }
-          regionDataThisRegion->etiqueta = ThisRegionNum;
-          regionDataThisRegion->area += ThisArea;
-          regionDataThisRegion->perimeter += ThisPerimeter;
-          regionDataThisRegion->externPerimeter += ThisExternPerimeter;
 
-          if (ComputeData > 0)
+        int *NewSubsume(int *subsumed, int index_subsume)
+        {
+          if (index_subsume == 0)
           {
-            if (findmoments)
-            {
-              regionDataThisRegion->sumx += ThisSumX;
-              regionDataThisRegion->sumy += ThisSumY;
-              regionDataThisRegion->sumxx += ThisSumXX;
-              regionDataThisRegion->sumyy += ThisSumYY;
-              regionDataThisRegion->sumxy += ThisSumXY;
-            }
-            regionDataThisRegion->perimeter -= LastPerimeter;
-            regionDataThisRegion->minx = MIN(regionDataThisRegion->minx, ThisMinX);
-            regionDataThisRegion->maxx = MAX(regionDataThisRegion->maxx, ThisMaxX);
-            regionDataThisRegion->miny = MIN(regionDataThisRegion->miny, ThisMinY);
-            regionDataThisRegion->maxy = MAX(regionDataThisRegion->maxy, ThisMaxY);
+            subsumed = (int*)malloc(sizeof(int));
           }
-          // blobs externs
-          if (CandidatExterior)
+          else
           {
-            regionDataThisRegion->exterior = true;
+            subsumed = (int*)realloc(subsumed, (index_subsume + 1) * sizeof(int));
           }
-
+          subsumed[index_subsume] = 0;
+          return subsumed;
         }
-      }	// end Main loop
 
-      if (ErrorFlag != 0) {
-        delete[] Transition;
-        delete[] ThisRegion;
-        delete[] LastRegion;
-        return false;
-      }
-      // ens situem al primer pixel de la seguent fila
-      pImage = inputImage->imageData - 1 + startCol + (ThisRow + startRow) * inputImage->widthStep;
-
-      if (maskImage != NULL)
-        pMask = maskImage->imageData - 1 + ThisRow * maskImage->widthStep;
-    }	// end Loop over all rows
-
-    // eliminem l'àrea del marc
-    // i també els píxels de la màscara
-    // ATENCIO: PERFER: el fet de restar el nombre_pixels_mascara del
-    // blob 0 només serà cert si la màscara té contacte amb el marc.
-    // Si no, s'haurà de trobar quin és el blob que conté més píxels del
-    // compte.
-    RegionData[0]->area -= (Rows + 1 + Cols + 1) * 2 + nombre_pixels_mascara;
-
-    // eliminem el perímetre de més:
-    // - sense marc: 2m+2n (perímetre extern)
-    // - amb marc:   2(m+2)+2(n+2) = 2m+2n + 8
-    // (segurament no és del tot acurat)
-    // (i amb les màscares encara menys...)
-    RegionData[0]->perimeter -= 8.0;
-
-    // Condense the list
-    blob_vector::iterator itNew, itOld, iti;
-    CBlob *blobActual;
-
-    itNew = RegionData.begin();
-    itOld = RegionData.begin();
-    int iNew = 0;
-    for (int iOld = 0; iOld <= HighRegionNum; iOld++, itOld++)
-    {
-      if (SubsumedRegion[iOld] < 1)	// This number not subsumed
-      {
-        // Move data from old region number to new region number
-        //*RegionData[iNew] = *RegionData[iOld];
-        **itNew = **itOld;
-
-        // Update and parent pointer if necessary
-        iti = RegionData.begin();
-        for (int i = 0; i <= HighRegionNum; i++)
+        /**
+          Fusiona dos blobs i afegeix el blob les característiques del blob RegionData[HiNum]
+          al blob RegionData[LoNum]. Al final allibera el blob de RegionData[HiNum]
+          */
+        void Subsume(blob_vector &RegionData,
+          int HighRegionNum,
+          int* SubsumedRegion,
+          CBlob* blobHi,
+          CBlob* blobLo,
+          bool findmoments,
+          int HiNum,
+          int LoNum)
         {
-          //if(RegionData[i]->parent == iOld) { RegionData[i]->parent = iNew; }
-          if ((*iti)->parent == iOld) { (*iti)->parent = iNew; }
-
-          ++iti;
-        }
-        iNew++;
-        ++itNew;
-      }
-    }
-
+          // cout << "\nSubsuming " << HiNum << " into " << LoNum << endl; // for debugging
 
-    HighRegionNum = iNew - 1;				// Update where the data ends
-    RegionData[HighRegionNum]->parent = -1;	// and set end of array flag
+          int i;
 
+          blobLo->minx = MIN(blobHi->minx, blobLo->minx);
+          blobLo->miny = MIN(blobHi->miny, blobLo->miny);
+          blobLo->maxx = MAX(blobHi->maxx, blobLo->maxx);
+          blobLo->maxy = MAX(blobHi->maxy, blobLo->maxy);
+          blobLo->area += blobHi->area;
+          blobLo->perimeter += blobHi->perimeter;
+          blobLo->externPerimeter += blobHi->externPerimeter;
+          blobLo->exterior = blobLo->exterior || blobHi->exterior;
+          blobLo->mean += blobHi->mean;
+          blobLo->stddev += blobHi->stddev;
 
-    if (findmoments)
-    {
-      iti = RegionData.begin();
-      // Normalize summation fields into moments
-      for (ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
-      {
-        blobActual = *iti;
-
-        // Get averages
-        blobActual->sumx /= blobActual->area;
-        blobActual->sumy /= blobActual->area;
-        blobActual->sumxx /= blobActual->area;
-        blobActual->sumyy /= blobActual->area;
-        blobActual->sumxy /= blobActual->area;
-
-        // Create moments
-        blobActual->sumxx -= blobActual->sumx * blobActual->sumx;
-        blobActual->sumyy -= blobActual->sumy * blobActual->sumy;
-        blobActual->sumxy -= blobActual->sumx * blobActual->sumy;
-        if (blobActual->sumxy > -1.0E-14 && blobActual->sumxy < 1.0E-14)
-        {
-          blobActual->sumxy = (float) 0.0; // Eliminate roundoff error
-        }
-
-      }
-    }
-
-    //Get the real mean and std deviation
-    iti = RegionData.begin();
-    for (ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
-    {
-      blobActual = *iti;
-      if (blobActual->area > 1)
-      {
-        blobActual->stddev =
-          sqrt(
-          (
-            blobActual->stddev * blobActual->area -
-            blobActual->mean * blobActual->mean
-            ) /
-            (blobActual->area*(blobActual->area - 1))
-          );
-      }
-      else
-        blobActual->stddev = 0;
-
-      if (blobActual->area > 0)
-        blobActual->mean /= blobActual->area;
-      else
-        blobActual->mean = 0;
-
-    }
-    // eliminem els blobs subsumats
-    blob_vector::iterator itBlobs = RegionData.begin() + HighRegionNum + 1;
-    while (itBlobs != RegionData.end())
-    {
-      delete *itBlobs;
-      //RegionData.erase( itBlobs );
-      ++itBlobs;
-    }
-    RegionData.erase(RegionData.begin() + HighRegionNum + 1, RegionData.end());
-
-    //free(RegionData);
-    free(SubsumedRegion);
-    delete[] Transition;
-    delete[] ThisRegion;
-    delete[] LastRegion;
-
-    if (imatgePerimetreExtern) cvReleaseImage(&imatgePerimetreExtern);
-
-    return true;
-  }
-
-
-  int *NewSubsume(int *subsumed, int index_subsume)
-  {
-    if (index_subsume == 0)
-    {
-      subsumed = (int*)malloc(sizeof(int));
-    }
-    else
-    {
-      subsumed = (int*)realloc(subsumed, (index_subsume + 1) * sizeof(int));
-    }
-    subsumed[index_subsume] = 0;
-    return subsumed;
-  }
+          if (findmoments)
+          {
+            blobLo->sumx += blobHi->sumx;
+            blobLo->sumy += blobHi->sumy;
+            blobLo->sumxx += blobHi->sumxx;
+            blobLo->sumyy += blobHi->sumyy;
+            blobLo->sumxy += blobHi->sumxy;
+          }
+          // Make sure no region still has subsumed region as parent
+          blob_vector::iterator it = (RegionData.begin() + HiNum + 1);
 
-  /**
-    Fusiona dos blobs i afegeix el blob les característiques del blob RegionData[HiNum]
-    al blob RegionData[LoNum]. Al final allibera el blob de RegionData[HiNum]
-    */
-  void Subsume(blob_vector &RegionData,
-    int HighRegionNum,
-    int* SubsumedRegion,
-    CBlob* blobHi,
-    CBlob* blobLo,
-    bool findmoments,
-    int HiNum,
-    int LoNum)
-  {
-    // cout << "\nSubsuming " << HiNum << " into " << LoNum << endl; // for debugging
-
-    int i;
-
-    blobLo->minx = MIN(blobHi->minx, blobLo->minx);
-    blobLo->miny = MIN(blobHi->miny, blobLo->miny);
-    blobLo->maxx = MAX(blobHi->maxx, blobLo->maxx);
-    blobLo->maxy = MAX(blobHi->maxy, blobLo->maxy);
-    blobLo->area += blobHi->area;
-    blobLo->perimeter += blobHi->perimeter;
-    blobLo->externPerimeter += blobHi->externPerimeter;
-    blobLo->exterior = blobLo->exterior || blobHi->exterior;
-    blobLo->mean += blobHi->mean;
-    blobLo->stddev += blobHi->stddev;
-
-    if (findmoments)
-    {
-      blobLo->sumx += blobHi->sumx;
-      blobLo->sumy += blobHi->sumy;
-      blobLo->sumxx += blobHi->sumxx;
-      blobLo->sumyy += blobHi->sumyy;
-      blobLo->sumxy += blobHi->sumxy;
-    }
-    // Make sure no region still has subsumed region as parent
-    blob_vector::iterator it = (RegionData.begin() + HiNum + 1);
+          for (i = HiNum + 1; i <= HighRegionNum; i++, it++)
+          {
+            if ((*it)->parent == (float)HiNum) { (*it)->parent = LoNum; }
+          }
 
-    for (i = HiNum + 1; i <= HighRegionNum; i++, it++)
-    {
-      if ((*it)->parent == (float)HiNum) { (*it)->parent = LoNum; }
-    }
+          // Mark dead region number for future compression
+          SubsumedRegion[HiNum] = 1;
+          // marquem el blob com a lliure
+          blobHi->etiqueta = -1;
 
-    // Mark dead region number for future compression
-    SubsumedRegion[HiNum] = 1;
-    // marquem el blob com a lliure
-    blobHi->etiqueta = -1;
+          // Atenció!!!! abans d'eliminar els edges
+          // s'han de traspassar del blob HiNum al blob LoNum
+          blobHi->CopyEdges(*blobLo);
+          blobHi->ClearEdges();
+        }
 
-    // Atenció!!!! abans d'eliminar els edges
-    // s'han de traspassar del blob HiNum al blob LoNum
-    blobHi->CopyEdges(*blobLo);
-    blobHi->ClearEdges();
-  }
+        /**
+          - FUNCIÓ: GetExternPerimeter
+          - FUNCIONALITAT: Retorna el perimetre extern d'una run lenght
+          - PARÀMETRES:
+          - start: columna d'inici del run
+          - end: columna final del run
+          - row: fila del run
+          - maskImage: màscara pels pixels externs
+          - RESULTAT:
+          - quantitat de perimetre extern d'un run, suposant que és un blob
+          d'una única fila d'alçada
+          - RESTRICCIONS:
+          - AUTOR:
+          - DATA DE CREACIÓ: 2006/02/27
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+        double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *imatgePerimetreExtern)
+        {
+          double perimeter = 0.0f;
+          char *pPerimetre;
 
-  /**
-    - FUNCIÓ: GetExternPerimeter
-    - FUNCIONALITAT: Retorna el perimetre extern d'una run lenght
-    - PARÀMETRES:
-    - start: columna d'inici del run
-    - end: columna final del run
-    - row: fila del run
-    - maskImage: màscara pels pixels externs
-    - RESULTAT:
-    - quantitat de perimetre extern d'un run, suposant que és un blob
-    d'una única fila d'alçada
-    - RESTRICCIONS:
-    - AUTOR:
-    - DATA DE CREACIÓ: 2006/02/27
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-  double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *imatgePerimetreExtern)
-  {
-    double perimeter = 0.0f;
-    char *pPerimetre;
 
+          // comprovem les dimensions de la imatge
+          perimeter += (start <= 0) + (end >= width - 1);
+          if (row <= 1) perimeter += start - end;
+          if (row >= height - 1) perimeter += start - end;
 
-    // comprovem les dimensions de la imatge
-    perimeter += (start <= 0) + (end >= width - 1);
-    if (row <= 1) perimeter += start - end;
-    if (row >= height - 1) perimeter += start - end;
 
+          // comprovem els pixels que toquen a la màscara (si s'escau)
+          if (imatgePerimetreExtern != NULL)
+          {
+            if (row <= 0 || row >= height) return perimeter;
 
-    // comprovem els pixels que toquen a la màscara (si s'escau)
-    if (imatgePerimetreExtern != NULL)
-    {
-      if (row <= 0 || row >= height) return perimeter;
+            if (start < 0) start = 1;
+            if (end >= width) end = width - 2;
 
-      if (start < 0) start = 1;
-      if (end >= width) end = width - 2;
+            pPerimetre = imatgePerimetreExtern->imageData + (row - 1) * imatgePerimetreExtern->widthStep + start;
+            for (int x = start - 1; x <= end; x++)
+            {
+              perimeter += *pPerimetre;
+              pPerimetre++;
+            }
+          }
 
-      pPerimetre = imatgePerimetreExtern->imageData + (row - 1) * imatgePerimetreExtern->widthStep + start;
-      for (int x = start - 1; x <= end; x++)
-      {
-        perimeter += *pPerimetre;
-        pPerimetre++;
+          return perimeter;
+        }
       }
     }
-
-    return perimeter;
   }
-
 }
diff --git a/src/algorithms/MultiLayer/BlobExtraction.h b/src/algorithms/MultiLayer/BlobExtraction.h
index 6a9dc94cbb5f471c4a4ae234efe79f5ced610ddd..dcd0dfe552d7e7aa4245323f39277149d928f2fa 100644
--- a/src/algorithms/MultiLayer/BlobExtraction.h
+++ b/src/algorithms/MultiLayer/BlobExtraction.h
@@ -1,17 +1,26 @@
 #pragma once
 
-namespace Blob
+namespace bgslibrary
 {
-  //! Extreu els blobs d'una imatge
-  bool BlobAnalysis(IplImage* inputImage, uchar threshold, IplImage* maskImage,
-    bool borderColor, bool findmoments, blob_vector &RegionData);
+  namespace algorithms
+  {
+    namespace multilayer
+    {
+      namespace blob
+      {
+        //! Extreu els blobs d'una imatge
+        bool BlobAnalysis(IplImage* inputImage, uchar threshold, IplImage* maskImage,
+          bool borderColor, bool findmoments, blob_vector &RegionData);
 
-  // FUNCIONS AUXILIARS
+        // FUNCIONS AUXILIARS
 
-  //! Fusiona dos blobs
-  void Subsume(blob_vector &RegionData, int, int*, CBlob*, CBlob*, bool, int, int);
-  //! Reallocata el vector auxiliar de blobs subsumats
-  int *NewSubsume(int *SubSumedRegion, int elems_inbuffer);
-  //! Retorna el perimetre extern d'una run lenght
-  double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *maskImage);
+        //! Fusiona dos blobs
+        void Subsume(blob_vector &RegionData, int, int*, CBlob*, CBlob*, bool, int, int);
+        //! Reallocata el vector auxiliar de blobs subsumats
+        int *NewSubsume(int *SubSumedRegion, int elems_inbuffer);
+        //! Retorna el perimetre extern d'una run lenght
+        double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *maskImage);
+      }
+    }
+  }
 }
diff --git a/src/algorithms/MultiLayer/BlobResult.cpp b/src/algorithms/MultiLayer/BlobResult.cpp
index f5b2f757d5c20a5a2d01d707f4460f12f41fa906..10aafbfcb293c6fd6fb0dfd3071aafa213420a74 100644
--- a/src/algorithms/MultiLayer/BlobResult.cpp
+++ b/src/algorithms/MultiLayer/BlobResult.cpp
@@ -6,791 +6,795 @@
 #include "BlobResult.h"
 #include "BlobExtraction.h"
 
-/**************************************************************************
-Constructors / Destructors
-**************************************************************************/
-
-namespace Blob
+namespace bgslibrary
 {
-  /**
-    - FUNCIÓ: CBlobResult
-    - FUNCIONALITAT: Constructor estandard.
-    - PARÀMETRES:
-    - RESULTAT:
-    - Crea un CBlobResult sense cap blob
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 20-07-2004.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlobResult
-      - FUNCTIONALITY: Standard constructor
-      - PARAMETERS:
-      - RESULT:
-      - creates an empty set of blobs
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlobResult::CBlobResult()
-  {
-    m_blobs = blob_vector();
-  }
-
-  /**
-    - FUNCIÓ: CBlobResult
-    - FUNCIONALITAT: Constructor a partir d'una imatge. Inicialitza la seqüència de blobs
-    amb els blobs resultants de l'anàlisi de blobs de la imatge.
-    - PARÀMETRES:
-    - source: imatge d'on s'extreuran els blobs
-    - mask: màscara a aplicar. Només es calcularan els blobs on la màscara sigui
-    diferent de 0. Els blobs que toquin a un pixel 0 de la màscara seran
-    considerats exteriors.
-    - threshold: llindar que s'aplicarà a la imatge source abans de calcular els blobs
-    - findmoments: indica si s'han de calcular els moments de cada blob
-    - RESULTAT:
-    - objecte CBlobResult amb els blobs de la imatge source
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlob
-      - FUNCTIONALITY: Constructor from an image. Fills an object with all the blobs in
-      the image
-      - PARAMETERS:
-      - source: image to extract the blobs from
-      - mask: optional mask to apply. The blobs will be extracted where the mask is
-      not 0. All the neighbouring blobs where the mask is 0 will be extern blobs
-      - threshold: threshold level to apply to the image before computing blobs
-      - findmoments: true to calculate the blob moments (slower)
-      - RESULT:
-      - object with all the blobs in the image. It throws an EXCEPCIO_CALCUL_BLOBS
-      if some error appears in the BlobAnalysis function
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlobResult::CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments)
-  {
-    bool success;
-
-    try
-    {
-      // cridem la funció amb el marc a true=1=blanc (així no unirà els blobs externs)
-      success = BlobAnalysis(source, (uchar)threshold, mask, true, findmoments, m_blobs);
-    }
-    catch (...)
-    {
-      success = false;
-    }
-
-    if (!success) throw EXCEPCIO_CALCUL_BLOBS;
-  }
-
-  /**
-    - FUNCIÓ: CBlobResult
-    - FUNCIONALITAT: Constructor de còpia. Inicialitza la seqüència de blobs
-    amb els blobs del paràmetre.
-    - PARÀMETRES:
-    - source: objecte que es copiarà
-    - RESULTAT:
-    - objecte CBlobResult amb els blobs de l'objecte source
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlobResult
-      - FUNCTIONALITY: Copy constructor
-      - PARAMETERS:
-      - source: object to copy
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlobResult::CBlobResult(const CBlobResult &source)
-  {
-    m_blobs = blob_vector(source.GetNumBlobs());
-
-    // creem el nou a partir del passat com a paràmetre
-    m_blobs = blob_vector(source.GetNumBlobs());
-    // copiem els blobs de l'origen a l'actual
-    blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin();
-    blob_vector::iterator pBlobsDst = m_blobs.begin();
-
-    while (pBlobsSrc != source.m_blobs.end())
-    {
-      // no podem cridar a l'operador = ja que blob_vector és un
-      // vector de CBlob*. Per tant, creem un blob nou a partir del
-      // blob original
-      *pBlobsDst = new CBlob(**pBlobsSrc);
-      ++pBlobsSrc;
-      ++pBlobsDst;
-    }
-  }
-
-
-
-  /**
-    - FUNCIÓ: ~CBlobResult
-    - FUNCIONALITAT: Destructor estandard.
-    - PARÀMETRES:
-    - RESULTAT:
-    - Allibera la memòria reservada de cadascun dels blobs de la classe
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: ~CBlobResult
-      - FUNCTIONALITY: Destructor
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlobResult::~CBlobResult()
+  namespace algorithms
   {
-    ClearBlobs();
-  }
-
-  /**************************************************************************
-    Operadors / Operators
-    **************************************************************************/
-
-
-    /**
-      - FUNCIÓ: operador =
-      - FUNCIONALITAT: Assigna un objecte source a l'actual
-      - PARÀMETRES:
-      - source: objecte a assignar
-      - RESULTAT:
-      - Substitueix els blobs actuals per els de l'objecte source
-      - RESTRICCIONS:
-      - AUTOR: Ricard Borràs
-      - DATA DE CREACIÓ: 25-05-2005.
-      - MODIFICACIÓ: Data. Autor. Descripció.
-      */
-      /**
-        - FUNCTION: Assigment operator
-        - FUNCTIONALITY:
-        - PARAMETERS:
-        - RESULT:
-        - RESTRICTIONS:
-        - AUTHOR: Ricard Borràs
-        - CREATION DATE: 25-05-2005.
-        - MODIFICATION: Date. Author. Description.
-        */
-  CBlobResult& CBlobResult::operator=(const CBlobResult& source)
-  {
-    // si ja són el mateix, no cal fer res
-    if (this != &source)
+    namespace multilayer
     {
-      // alliberem el conjunt de blobs antic
-      for (int i = 0; i < GetNumBlobs(); i++)
+      namespace blob
       {
-        delete m_blobs[i];
-      }
-      m_blobs.clear();
-      // creem el nou a partir del passat com a paràmetre
-      m_blobs = blob_vector(source.GetNumBlobs());
-      // copiem els blobs de l'origen a l'actual
-      blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin();
-      blob_vector::iterator pBlobsDst = m_blobs.begin();
-
-      while (pBlobsSrc != source.m_blobs.end())
-      {
-        // no podem cridar a l'operador = ja que blob_vector és un
-        // vector de CBlob*. Per tant, creem un blob nou a partir del
-        // blob original
-        *pBlobsDst = new CBlob(**pBlobsSrc);
-        ++pBlobsSrc;
-        ++pBlobsDst;
-      }
-    }
-    return *this;
-  }
-
+        /**
+          - FUNCIÓ: CBlobResult
+          - FUNCIONALITAT: Constructor estandard.
+          - PARÀMETRES:
+          - RESULTAT:
+          - Crea un CBlobResult sense cap blob
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 20-07-2004.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlobResult
+            - FUNCTIONALITY: Standard constructor
+            - PARAMETERS:
+            - RESULT:
+            - creates an empty set of blobs
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlobResult::CBlobResult()
+        {
+          m_blobs = blob_vector();
+        }
 
-  /**
-    - FUNCIÓ: operador +
-    - FUNCIONALITAT: Concatena els blobs de dos CBlobResult
-    - PARÀMETRES:
-    - source: d'on s'agafaran els blobs afegits a l'actual
-    - RESULTAT:
-    - retorna un nou CBlobResult amb els dos CBlobResult concatenats
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - NOTA: per la implementació, els blobs del paràmetre es posen en ordre invers
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: + operator
-      - FUNCTIONALITY: Joins the blobs in source with the current ones
-      - PARAMETERS:
-      - source: object to copy the blobs
-      - RESULT:
-      - object with the actual blobs and the source blobs
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlobResult CBlobResult::operator+(const CBlobResult& source)
-  {
-    //creem el resultat a partir dels blobs actuals
-    CBlobResult resultat(*this);
+        /**
+          - FUNCIÓ: CBlobResult
+          - FUNCIONALITAT: Constructor a partir d'una imatge. Inicialitza la seqüència de blobs
+          amb els blobs resultants de l'anàlisi de blobs de la imatge.
+          - PARÀMETRES:
+          - source: imatge d'on s'extreuran els blobs
+          - mask: màscara a aplicar. Només es calcularan els blobs on la màscara sigui
+          diferent de 0. Els blobs que toquin a un pixel 0 de la màscara seran
+          considerats exteriors.
+          - threshold: llindar que s'aplicarà a la imatge source abans de calcular els blobs
+          - findmoments: indica si s'han de calcular els moments de cada blob
+          - RESULTAT:
+          - objecte CBlobResult amb els blobs de la imatge source
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlob
+            - FUNCTIONALITY: Constructor from an image. Fills an object with all the blobs in
+            the image
+            - PARAMETERS:
+            - source: image to extract the blobs from
+            - mask: optional mask to apply. The blobs will be extracted where the mask is
+            not 0. All the neighbouring blobs where the mask is 0 will be extern blobs
+            - threshold: threshold level to apply to the image before computing blobs
+            - findmoments: true to calculate the blob moments (slower)
+            - RESULT:
+            - object with all the blobs in the image. It throws an EXCEPCIO_CALCUL_BLOBS
+            if some error appears in the BlobAnalysis function
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlobResult::CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments)
+        {
+          bool success;
+
+          try
+          {
+            // cridem la funció amb el marc a true=1=blanc (així no unirà els blobs externs)
+            success = BlobAnalysis(source, (uchar)threshold, mask, true, findmoments, m_blobs);
+          }
+          catch (...)
+          {
+            success = false;
+          }
+
+          if (!success) throw EXCEPCIO_CALCUL_BLOBS;
+        }
 
-    // reservem memòria per als nous blobs
-    resultat.m_blobs.resize(resultat.GetNumBlobs() + source.GetNumBlobs());
+        /**
+          - FUNCIÓ: CBlobResult
+          - FUNCIONALITAT: Constructor de còpia. Inicialitza la seqüència de blobs
+          amb els blobs del paràmetre.
+          - PARÀMETRES:
+          - source: objecte que es copiarà
+          - RESULTAT:
+          - objecte CBlobResult amb els blobs de l'objecte source
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlobResult
+            - FUNCTIONALITY: Copy constructor
+            - PARAMETERS:
+            - source: object to copy
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlobResult::CBlobResult(const CBlobResult &source)
+        {
+          m_blobs = blob_vector(source.GetNumBlobs());
+
+          // creem el nou a partir del passat com a paràmetre
+          m_blobs = blob_vector(source.GetNumBlobs());
+          // copiem els blobs de l'origen a l'actual
+          blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin();
+          blob_vector::iterator pBlobsDst = m_blobs.begin();
+
+          while (pBlobsSrc != source.m_blobs.end())
+          {
+            // no podem cridar a l'operador = ja que blob_vector és un
+            // vector de CBlob*. Per tant, creem un blob nou a partir del
+            // blob original
+            *pBlobsDst = new CBlob(**pBlobsSrc);
+            ++pBlobsSrc;
+            ++pBlobsDst;
+          }
+        }
 
-    // declarem els iterador per recòrrer els blobs d'origen i desti
-    blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin();
-    blob_vector::iterator pBlobsDst = resultat.m_blobs.end();
 
-    // insertem els blobs de l'origen a l'actual
-    while (pBlobsSrc != source.m_blobs.end())
-    {
-      --pBlobsDst;
-      *pBlobsDst = new CBlob(**pBlobsSrc);
-      ++pBlobsSrc;
-    }
 
-    return resultat;
-  }
+        /**
+          - FUNCIÓ: ~CBlobResult
+          - FUNCIONALITAT: Destructor estandard.
+          - PARÀMETRES:
+          - RESULTAT:
+          - Allibera la memòria reservada de cadascun dels blobs de la classe
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: ~CBlobResult
+            - FUNCTIONALITY: Destructor
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlobResult::~CBlobResult()
+        {
+          ClearBlobs();
+        }
 
-  /**************************************************************************
-    Operacions / Operations
-    **************************************************************************/
-
-    /**
-      - FUNCIÓ: AddBlob
-      - FUNCIONALITAT: Afegeix un blob al conjunt
-      - PARÀMETRES:
-      - blob: blob a afegir
-      - RESULTAT:
-      - modifica el conjunt de blobs actual
-      - RESTRICCIONS:
-      - AUTOR: Ricard Borràs
-      - DATA DE CREACIÓ: 2006/03/01
-      - MODIFICACIÓ: Data. Autor. Descripció.
-      */
-  void CBlobResult::AddBlob(CBlob *blob)
-  {
-    if (blob != NULL)
-      m_blobs.push_back(new CBlob(blob));
-  }
+        /**************************************************************************
+          Operadors / Operators
+          **************************************************************************/
+
+
+          /**
+            - FUNCIÓ: operador =
+            - FUNCIONALITAT: Assigna un objecte source a l'actual
+            - PARÀMETRES:
+            - source: objecte a assignar
+            - RESULTAT:
+            - Substitueix els blobs actuals per els de l'objecte source
+            - RESTRICCIONS:
+            - AUTOR: Ricard Borràs
+            - DATA DE CREACIÓ: 25-05-2005.
+            - MODIFICACIÓ: Data. Autor. Descripció.
+            */
+            /**
+              - FUNCTION: Assigment operator
+              - FUNCTIONALITY:
+              - PARAMETERS:
+              - RESULT:
+              - RESTRICTIONS:
+              - AUTHOR: Ricard Borràs
+              - CREATION DATE: 25-05-2005.
+              - MODIFICATION: Date. Author. Description.
+              */
+        CBlobResult& CBlobResult::operator=(const CBlobResult& source)
+        {
+          // si ja són el mateix, no cal fer res
+          if (this != &source)
+          {
+            // alliberem el conjunt de blobs antic
+            for (int i = 0; i < GetNumBlobs(); i++)
+            {
+              delete m_blobs[i];
+            }
+            m_blobs.clear();
+            // creem el nou a partir del passat com a paràmetre
+            m_blobs = blob_vector(source.GetNumBlobs());
+            // copiem els blobs de l'origen a l'actual
+            blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin();
+            blob_vector::iterator pBlobsDst = m_blobs.begin();
+
+            while (pBlobsSrc != source.m_blobs.end())
+            {
+              // no podem cridar a l'operador = ja que blob_vector és un
+              // vector de CBlob*. Per tant, creem un blob nou a partir del
+              // blob original
+              *pBlobsDst = new CBlob(**pBlobsSrc);
+              ++pBlobsSrc;
+              ++pBlobsDst;
+            }
+          }
+          return *this;
+        }
 
 
-  /**
-    - FUNCIÓ: GetSTLResult
-    - FUNCIONALITAT: Calcula el resultat especificat sobre tots els blobs de la classe
-    - PARÀMETRES:
-    - evaluador: Qualsevol objecte derivat de COperadorBlob
-    - RESULTAT:
-    - Retorna un array de double's STL amb el resultat per cada blob
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: GetResult
-      - FUNCTIONALITY: Computes the function evaluador on all the blobs of the class
-      and returns a vector with the result
-      - PARAMETERS:
-      - evaluador: function to apply to each blob (any object derived from the
-      COperadorBlob class )
-      - RESULT:
-      - vector with all the results in the same order as the blobs
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double_stl_vector CBlobResult::GetSTLResult(funcio_calculBlob *evaluador) const
-  {
-    if (GetNumBlobs() <= 0)
-    {
-      return double_stl_vector();
-    }
+        /**
+          - FUNCIÓ: operador +
+          - FUNCIONALITAT: Concatena els blobs de dos CBlobResult
+          - PARÀMETRES:
+          - source: d'on s'agafaran els blobs afegits a l'actual
+          - RESULTAT:
+          - retorna un nou CBlobResult amb els dos CBlobResult concatenats
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - NOTA: per la implementació, els blobs del paràmetre es posen en ordre invers
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: + operator
+            - FUNCTIONALITY: Joins the blobs in source with the current ones
+            - PARAMETERS:
+            - source: object to copy the blobs
+            - RESULT:
+            - object with the actual blobs and the source blobs
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlobResult CBlobResult::operator+(const CBlobResult& source)
+        {
+          //creem el resultat a partir dels blobs actuals
+          CBlobResult resultat(*this);
 
-    // definim el resultat
-    double_stl_vector result = double_stl_vector(GetNumBlobs());
-    // i iteradors sobre els blobs i el resultat
-    double_stl_vector::iterator itResult = result.begin();
-    blob_vector::const_iterator itBlobs = m_blobs.begin();
+          // reservem memòria per als nous blobs
+          resultat.m_blobs.resize(resultat.GetNumBlobs() + source.GetNumBlobs());
 
-    // avaluem la funció en tots els blobs
-    while (itBlobs != m_blobs.end())
-    {
-      *itResult = (*evaluador)(**itBlobs);
-      ++itBlobs;
-      ++itResult;
-    }
-    return result;
-  }
+          // declarem els iterador per recòrrer els blobs d'origen i desti
+          blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin();
+          blob_vector::iterator pBlobsDst = resultat.m_blobs.end();
 
-  /**
-    - FUNCIÓ: GetNumber
-    - FUNCIONALITAT: Calcula el resultat especificat sobre un únic blob de la classe
-    - PARÀMETRES:
-    - evaluador: Qualsevol objecte derivat de COperadorBlob
-    - indexblob: número de blob del que volem calcular el resultat.
-    - RESULTAT:
-    - Retorna un double amb el resultat
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: GetNumber
-      - FUNCTIONALITY: Computes the function evaluador on a blob of the class
-      - PARAMETERS:
-      - indexBlob: index of the blob to compute the function
-      - evaluador: function to apply to each blob (any object derived from the
-      COperadorBlob class )
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobResult::GetNumber(int indexBlob, funcio_calculBlob *evaluador) const
-  {
-    if (indexBlob < 0 || indexBlob >= GetNumBlobs())
-      RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS);
-    return (*evaluador)(*m_blobs[indexBlob]);
-  }
+          // insertem els blobs de l'origen a l'actual
+          while (pBlobsSrc != source.m_blobs.end())
+          {
+            --pBlobsDst;
+            *pBlobsDst = new CBlob(**pBlobsSrc);
+            ++pBlobsSrc;
+          }
 
-  /////////////////////////// FILTRAT DE BLOBS ////////////////////////////////////
-
-  /**
-    - FUNCIÓ: Filter
-    - FUNCIONALITAT: Filtra els blobs de la classe i deixa el resultat amb només
-    els blobs que han passat el filtre.
-    El filtrat es basa en especificar condicions sobre un resultat dels blobs
-    i seleccionar (o excloure) aquells blobs que no compleixen una determinada
-    condicio
-    - PARÀMETRES:
-    - dst: variable per deixar els blobs filtrats
-    - filterAction:	acció de filtrat. Incloure els blobs trobats (B_INCLUDE),
-    o excloure els blobs trobats (B_EXCLUDE)
-    - evaluador: Funció per evaluar els blobs (qualsevol objecte derivat de COperadorBlob
-    - Condition: tipus de condició que ha de superar la mesura (FilterType)
-    sobre cada blob per a ser considerat.
-    B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL,
-    B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE
-    - LowLimit:  valor numèric per a la comparació (Condition) de la mesura (FilterType)
-    - HighLimit: valor numèric per a la comparació (Condition) de la mesura (FilterType)
-    (només té sentit per a aquelles condicions que tenen dos valors
-    (B_INSIDE, per exemple).
-    - RESULTAT:
-    - Deixa els blobs resultants del filtrat a destination
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: Filter
-      - FUNCTIONALITY: Get some blobs from the class based on conditions on measures
-      of the blobs.
-      - PARAMETERS:
-      - dst: where to store the selected blobs
-      - filterAction:	B_INCLUDE: include the blobs which pass the filter in the result
-      B_EXCLUDE: exclude the blobs which pass the filter in the result
-      - evaluador: Object to evaluate the blob
-      - Condition: How to decide if  the result returned by evaluador on each blob
-      is included or not. It can be:
-      B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL,
-      B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE
-      - LowLimit:  numerical value to evaluate the Condition on evaluador(blob)
-      - HighLimit: numerical value to evaluate the Condition on evaluador(blob).
-      Only useful for B_INSIDE and B_OUTSIDE
-      - RESULT:
-      - It returns on dst the blobs that accomplish (B_INCLUDE) or discards (B_EXCLUDE)
-      the Condition on the result returned by evaluador on each blob
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  void CBlobResult::Filter(CBlobResult &dst,
-    int filterAction,
-    funcio_calculBlob *evaluador,
-    int condition,
-    double lowLimit, double highLimit /*=0*/)
+          return resultat;
+        }
 
-  {
-    int i, numBlobs;
-    bool resultavaluacio;
-    double_stl_vector avaluacioBlobs;
-    double_stl_vector::iterator itavaluacioBlobs;
-
-    if (GetNumBlobs() <= 0) return;
-    if (!evaluador) return;
-    //avaluem els blobs amb la funció pertinent
-    avaluacioBlobs = GetSTLResult(evaluador);
-    itavaluacioBlobs = avaluacioBlobs.begin();
-    numBlobs = GetNumBlobs();
-    switch (condition)
-    {
-    case B_EQUAL:
-      for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
-      {
-        resultavaluacio = *itavaluacioBlobs == lowLimit;
-        if ((resultavaluacio && filterAction == B_INCLUDE) ||
-          (!resultavaluacio && filterAction == B_EXCLUDE))
+        /**************************************************************************
+          Operacions / Operations
+          **************************************************************************/
+
+          /**
+            - FUNCIÓ: AddBlob
+            - FUNCIONALITAT: Afegeix un blob al conjunt
+            - PARÀMETRES:
+            - blob: blob a afegir
+            - RESULTAT:
+            - modifica el conjunt de blobs actual
+            - RESTRICCIONS:
+            - AUTOR: Ricard Borràs
+            - DATA DE CREACIÓ: 2006/03/01
+            - MODIFICACIÓ: Data. Autor. Descripció.
+            */
+        void CBlobResult::AddBlob(CBlob *blob)
         {
-          dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+          if (blob != NULL)
+            m_blobs.push_back(new CBlob(blob));
         }
-      }
-      break;
-    case B_NOT_EQUAL:
-      for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
-      {
-        resultavaluacio = *itavaluacioBlobs != lowLimit;
-        if ((resultavaluacio && filterAction == B_INCLUDE) ||
-          (!resultavaluacio && filterAction == B_EXCLUDE))
+
+
+        /**
+          - FUNCIÓ: GetSTLResult
+          - FUNCIONALITAT: Calcula el resultat especificat sobre tots els blobs de la classe
+          - PARÀMETRES:
+          - evaluador: Qualsevol objecte derivat de COperadorBlob
+          - RESULTAT:
+          - Retorna un array de double's STL amb el resultat per cada blob
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: GetResult
+            - FUNCTIONALITY: Computes the function evaluador on all the blobs of the class
+            and returns a vector with the result
+            - PARAMETERS:
+            - evaluador: function to apply to each blob (any object derived from the
+            COperadorBlob class )
+            - RESULT:
+            - vector with all the results in the same order as the blobs
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double_stl_vector CBlobResult::GetSTLResult(funcio_calculBlob *evaluador) const
         {
-          dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+          if (GetNumBlobs() <= 0)
+          {
+            return double_stl_vector();
+          }
+
+          // definim el resultat
+          double_stl_vector result = double_stl_vector(GetNumBlobs());
+          // i iteradors sobre els blobs i el resultat
+          double_stl_vector::iterator itResult = result.begin();
+          blob_vector::const_iterator itBlobs = m_blobs.begin();
+
+          // avaluem la funció en tots els blobs
+          while (itBlobs != m_blobs.end())
+          {
+            *itResult = (*evaluador)(**itBlobs);
+            ++itBlobs;
+            ++itResult;
+          }
+          return result;
         }
-      }
-      break;
-    case B_GREATER:
-      for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
-      {
-        resultavaluacio = *itavaluacioBlobs > lowLimit;
-        if ((resultavaluacio && filterAction == B_INCLUDE) ||
-          (!resultavaluacio && filterAction == B_EXCLUDE))
+
+        /**
+          - FUNCIÓ: GetNumber
+          - FUNCIONALITAT: Calcula el resultat especificat sobre un únic blob de la classe
+          - PARÀMETRES:
+          - evaluador: Qualsevol objecte derivat de COperadorBlob
+          - indexblob: número de blob del que volem calcular el resultat.
+          - RESULTAT:
+          - Retorna un double amb el resultat
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: GetNumber
+            - FUNCTIONALITY: Computes the function evaluador on a blob of the class
+            - PARAMETERS:
+            - indexBlob: index of the blob to compute the function
+            - evaluador: function to apply to each blob (any object derived from the
+            COperadorBlob class )
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobResult::GetNumber(int indexBlob, funcio_calculBlob *evaluador) const
         {
-          dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+          if (indexBlob < 0 || indexBlob >= GetNumBlobs())
+            RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS);
+          return (*evaluador)(*m_blobs[indexBlob]);
         }
-      }
-      break;
-    case B_LESS:
-      for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
-      {
-        resultavaluacio = *itavaluacioBlobs < lowLimit;
-        if ((resultavaluacio && filterAction == B_INCLUDE) ||
-          (!resultavaluacio && filterAction == B_EXCLUDE))
+
+        /////////////////////////// FILTRAT DE BLOBS ////////////////////////////////////
+
+        /**
+          - FUNCIÓ: Filter
+          - FUNCIONALITAT: Filtra els blobs de la classe i deixa el resultat amb només
+          els blobs que han passat el filtre.
+          El filtrat es basa en especificar condicions sobre un resultat dels blobs
+          i seleccionar (o excloure) aquells blobs que no compleixen una determinada
+          condicio
+          - PARÀMETRES:
+          - dst: variable per deixar els blobs filtrats
+          - filterAction:	acció de filtrat. Incloure els blobs trobats (B_INCLUDE),
+          o excloure els blobs trobats (B_EXCLUDE)
+          - evaluador: Funció per evaluar els blobs (qualsevol objecte derivat de COperadorBlob
+          - Condition: tipus de condició que ha de superar la mesura (FilterType)
+          sobre cada blob per a ser considerat.
+          B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL,
+          B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE
+          - LowLimit:  valor numèric per a la comparació (Condition) de la mesura (FilterType)
+          - HighLimit: valor numèric per a la comparació (Condition) de la mesura (FilterType)
+          (només té sentit per a aquelles condicions que tenen dos valors
+          (B_INSIDE, per exemple).
+          - RESULTAT:
+          - Deixa els blobs resultants del filtrat a destination
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: Filter
+            - FUNCTIONALITY: Get some blobs from the class based on conditions on measures
+            of the blobs.
+            - PARAMETERS:
+            - dst: where to store the selected blobs
+            - filterAction:	B_INCLUDE: include the blobs which pass the filter in the result
+            B_EXCLUDE: exclude the blobs which pass the filter in the result
+            - evaluador: Object to evaluate the blob
+            - Condition: How to decide if  the result returned by evaluador on each blob
+            is included or not. It can be:
+            B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL,
+            B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE
+            - LowLimit:  numerical value to evaluate the Condition on evaluador(blob)
+            - HighLimit: numerical value to evaluate the Condition on evaluador(blob).
+            Only useful for B_INSIDE and B_OUTSIDE
+            - RESULT:
+            - It returns on dst the blobs that accomplish (B_INCLUDE) or discards (B_EXCLUDE)
+            the Condition on the result returned by evaluador on each blob
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        void CBlobResult::Filter(CBlobResult &dst,
+          int filterAction,
+          funcio_calculBlob *evaluador,
+          int condition,
+          double lowLimit, double highLimit /*=0*/)
+
         {
-          dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+          int i, numBlobs;
+          bool resultavaluacio;
+          double_stl_vector avaluacioBlobs;
+          double_stl_vector::iterator itavaluacioBlobs;
+
+          if (GetNumBlobs() <= 0) return;
+          if (!evaluador) return;
+          //avaluem els blobs amb la funció pertinent
+          avaluacioBlobs = GetSTLResult(evaluador);
+          itavaluacioBlobs = avaluacioBlobs.begin();
+          numBlobs = GetNumBlobs();
+          switch (condition)
+          {
+          case B_EQUAL:
+            for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
+            {
+              resultavaluacio = *itavaluacioBlobs == lowLimit;
+              if ((resultavaluacio && filterAction == B_INCLUDE) ||
+                (!resultavaluacio && filterAction == B_EXCLUDE))
+              {
+                dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+              }
+            }
+            break;
+          case B_NOT_EQUAL:
+            for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
+            {
+              resultavaluacio = *itavaluacioBlobs != lowLimit;
+              if ((resultavaluacio && filterAction == B_INCLUDE) ||
+                (!resultavaluacio && filterAction == B_EXCLUDE))
+              {
+                dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+              }
+            }
+            break;
+          case B_GREATER:
+            for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
+            {
+              resultavaluacio = *itavaluacioBlobs > lowLimit;
+              if ((resultavaluacio && filterAction == B_INCLUDE) ||
+                (!resultavaluacio && filterAction == B_EXCLUDE))
+              {
+                dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+              }
+            }
+            break;
+          case B_LESS:
+            for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
+            {
+              resultavaluacio = *itavaluacioBlobs < lowLimit;
+              if ((resultavaluacio && filterAction == B_INCLUDE) ||
+                (!resultavaluacio && filterAction == B_EXCLUDE))
+              {
+                dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+              }
+            }
+            break;
+          case B_GREATER_OR_EQUAL:
+            for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
+            {
+              resultavaluacio = *itavaluacioBlobs >= lowLimit;
+              if ((resultavaluacio && filterAction == B_INCLUDE) ||
+                (!resultavaluacio && filterAction == B_EXCLUDE))
+              {
+                dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+              }
+            }
+            break;
+          case B_LESS_OR_EQUAL:
+            for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
+            {
+              resultavaluacio = *itavaluacioBlobs <= lowLimit;
+              if ((resultavaluacio && filterAction == B_INCLUDE) ||
+                (!resultavaluacio && filterAction == B_EXCLUDE))
+              {
+                dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+              }
+            }
+            break;
+          case B_INSIDE:
+            for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
+            {
+              resultavaluacio = (*itavaluacioBlobs >= lowLimit) && (*itavaluacioBlobs <= highLimit);
+              if ((resultavaluacio && filterAction == B_INCLUDE) ||
+                (!resultavaluacio && filterAction == B_EXCLUDE))
+              {
+                dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+              }
+            }
+            break;
+          case B_OUTSIDE:
+            for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
+            {
+              resultavaluacio = (*itavaluacioBlobs < lowLimit) || (*itavaluacioBlobs > highLimit);
+              if ((resultavaluacio && filterAction == B_INCLUDE) ||
+                (!resultavaluacio && filterAction == B_EXCLUDE))
+              {
+                dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+              }
+            }
+            break;
+          }
+
+
+          // en cas de voler filtrar un CBlobResult i deixar-ho en el mateix CBlobResult
+          // ( operacio inline )
+          if (&dst == this)
+          {
+            // esborrem els primers blobs ( que són els originals )
+            // ja que els tindrem replicats al final si passen el filtre
+            blob_vector::iterator itBlobs = m_blobs.begin();
+            for (int i = 0; i < numBlobs; i++)
+            {
+              delete *itBlobs;
+              ++itBlobs;
+            }
+            m_blobs.erase(m_blobs.begin(), itBlobs);
+          }
         }
-      }
-      break;
-    case B_GREATER_OR_EQUAL:
-      for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
-      {
-        resultavaluacio = *itavaluacioBlobs >= lowLimit;
-        if ((resultavaluacio && filterAction == B_INCLUDE) ||
-          (!resultavaluacio && filterAction == B_EXCLUDE))
+
+
+        /**
+          - FUNCIÓ: GetBlob
+          - FUNCIONALITAT: Retorna un blob si aquest existeix (index != -1)
+          - PARÀMETRES:
+          - indexblob: index del blob a retornar
+          - RESULTAT:
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /*
+            - FUNCTION: GetBlob
+            - FUNCTIONALITY: Gets the n-th blob (without ordering the blobs)
+            - PARAMETERS:
+            - indexblob: index in the blob array
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlob CBlobResult::GetBlob(int indexblob) const
         {
-          dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+          if (indexblob < 0 || indexblob >= GetNumBlobs())
+            RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS);
+
+          return *m_blobs[indexblob];
         }
-      }
-      break;
-    case B_LESS_OR_EQUAL:
-      for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
-      {
-        resultavaluacio = *itavaluacioBlobs <= lowLimit;
-        if ((resultavaluacio && filterAction == B_INCLUDE) ||
-          (!resultavaluacio && filterAction == B_EXCLUDE))
+        CBlob *CBlobResult::GetBlob(int indexblob)
         {
-          dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+          if (indexblob < 0 || indexblob >= GetNumBlobs())
+            RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS);
+
+          return m_blobs[indexblob];
         }
-      }
-      break;
-    case B_INSIDE:
-      for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
-      {
-        resultavaluacio = (*itavaluacioBlobs >= lowLimit) && (*itavaluacioBlobs <= highLimit);
-        if ((resultavaluacio && filterAction == B_INCLUDE) ||
-          (!resultavaluacio && filterAction == B_EXCLUDE))
+
+        /**
+          - FUNCIÓ: GetNthBlob
+          - FUNCIONALITAT: Retorna l'enèssim blob segons un determinat criteri
+          - PARÀMETRES:
+          - criteri: criteri per ordenar els blobs (objectes derivats de COperadorBlob)
+          - nBlob: index del blob a retornar
+          - dst: on es retorna el resultat
+          - RESULTAT:
+          - retorna el blob nBlob a dst ordenant els blobs de la classe segons el criteri
+          en ordre DESCENDENT. Per exemple, per obtenir el blob major:
+          GetNthBlob( CBlobGetArea(), 0, blobMajor );
+          GetNthBlob( CBlobGetArea(), 1, blobMajor ); (segon blob més gran)
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /*
+            - FUNCTION: GetNthBlob
+            - FUNCTIONALITY: Gets the n-th blob ordering first the blobs with some criteria
+            - PARAMETERS:
+            - criteri: criteria to order the blob array
+            - nBlob: index of the returned blob in the ordered blob array
+            - dst: where to store the result
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        void CBlobResult::GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const
         {
-          dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+          // verifiquem que no estem accedint fora el vector de blobs
+          if (nBlob < 0 || nBlob >= GetNumBlobs())
+          {
+            //RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS );
+            dst = CBlob();
+            return;
+          }
+
+          double_stl_vector avaluacioBlobs, avaluacioBlobsOrdenat;
+          double valorEnessim;
+
+          //avaluem els blobs amb la funció pertinent
+          avaluacioBlobs = GetSTLResult(criteri);
+
+          avaluacioBlobsOrdenat = double_stl_vector(GetNumBlobs());
+
+          // obtenim els nBlob primers resultats (en ordre descendent)
+          std::partial_sort_copy(avaluacioBlobs.begin(),
+            avaluacioBlobs.end(),
+            avaluacioBlobsOrdenat.begin(),
+            avaluacioBlobsOrdenat.end(),
+            std::greater<double>());
+
+          valorEnessim = avaluacioBlobsOrdenat[nBlob];
+
+          // busquem el primer blob que té el valor n-ssim
+          double_stl_vector::const_iterator itAvaluacio = avaluacioBlobs.begin();
+
+          bool trobatBlob = false;
+          int indexBlob = 0;
+          while (itAvaluacio != avaluacioBlobs.end() && !trobatBlob)
+          {
+            if (*itAvaluacio == valorEnessim)
+            {
+              trobatBlob = true;
+              dst = CBlob(GetBlob(indexBlob));
+            }
+            ++itAvaluacio;
+            indexBlob++;
+          }
         }
-      }
-      break;
-    case B_OUTSIDE:
-      for (i = 0; i < numBlobs; i++, itavaluacioBlobs++)
-      {
-        resultavaluacio = (*itavaluacioBlobs < lowLimit) || (*itavaluacioBlobs > highLimit);
-        if ((resultavaluacio && filterAction == B_INCLUDE) ||
-          (!resultavaluacio && filterAction == B_EXCLUDE))
+
+        /**
+          - FUNCIÓ: ClearBlobs
+          - FUNCIONALITAT: Elimina tots els blobs de l'objecte
+          - PARÀMETRES:
+          - RESULTAT:
+          - Allibera tota la memòria dels blobs
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs Navarra
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /*
+            - FUNCTION: ClearBlobs
+            - FUNCTIONALITY: Clears all the blobs from the object and releases all its memory
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        void CBlobResult::ClearBlobs()
         {
-          dst.m_blobs.push_back(new CBlob(GetBlob(i)));
+          /*for( int i = 0; i < GetNumBlobs(); i++ )
+            {
+            delete m_blobs[i];
+            }*/
+          blob_vector::iterator itBlobs = m_blobs.begin();
+          while (itBlobs != m_blobs.end())
+          {
+            delete *itBlobs;
+            ++itBlobs;
+          }
+
+          m_blobs.clear();
         }
-      }
-      break;
-    }
-
-
-    // en cas de voler filtrar un CBlobResult i deixar-ho en el mateix CBlobResult
-    // ( operacio inline )
-    if (&dst == this)
-    {
-      // esborrem els primers blobs ( que són els originals )
-      // ja que els tindrem replicats al final si passen el filtre
-      blob_vector::iterator itBlobs = m_blobs.begin();
-      for (int i = 0; i < numBlobs; i++)
-      {
-        delete *itBlobs;
-        ++itBlobs;
-      }
-      m_blobs.erase(m_blobs.begin(), itBlobs);
-    }
-  }
-
-
-  /**
-    - FUNCIÓ: GetBlob
-    - FUNCIONALITAT: Retorna un blob si aquest existeix (index != -1)
-    - PARÀMETRES:
-    - indexblob: index del blob a retornar
-    - RESULTAT:
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /*
-      - FUNCTION: GetBlob
-      - FUNCTIONALITY: Gets the n-th blob (without ordering the blobs)
-      - PARAMETERS:
-      - indexblob: index in the blob array
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlob CBlobResult::GetBlob(int indexblob) const
-  {
-    if (indexblob < 0 || indexblob >= GetNumBlobs())
-      RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS);
-
-    return *m_blobs[indexblob];
-  }
-  CBlob *CBlobResult::GetBlob(int indexblob)
-  {
-    if (indexblob < 0 || indexblob >= GetNumBlobs())
-      RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS);
 
-    return m_blobs[indexblob];
-  }
-
-  /**
-    - FUNCIÓ: GetNthBlob
-    - FUNCIONALITAT: Retorna l'enèssim blob segons un determinat criteri
-    - PARÀMETRES:
-    - criteri: criteri per ordenar els blobs (objectes derivats de COperadorBlob)
-    - nBlob: index del blob a retornar
-    - dst: on es retorna el resultat
-    - RESULTAT:
-    - retorna el blob nBlob a dst ordenant els blobs de la classe segons el criteri
-    en ordre DESCENDENT. Per exemple, per obtenir el blob major:
-    GetNthBlob( CBlobGetArea(), 0, blobMajor );
-    GetNthBlob( CBlobGetArea(), 1, blobMajor ); (segon blob més gran)
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /*
-      - FUNCTION: GetNthBlob
-      - FUNCTIONALITY: Gets the n-th blob ordering first the blobs with some criteria
-      - PARAMETERS:
-      - criteri: criteria to order the blob array
-      - nBlob: index of the returned blob in the ordered blob array
-      - dst: where to store the result
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  void CBlobResult::GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const
-  {
-    // verifiquem que no estem accedint fora el vector de blobs
-    if (nBlob < 0 || nBlob >= GetNumBlobs())
-    {
-      //RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS );
-      dst = CBlob();
-      return;
-    }
-
-    double_stl_vector avaluacioBlobs, avaluacioBlobsOrdenat;
-    double valorEnessim;
-
-    //avaluem els blobs amb la funció pertinent
-    avaluacioBlobs = GetSTLResult(criteri);
-
-    avaluacioBlobsOrdenat = double_stl_vector(GetNumBlobs());
+        /**
+          - FUNCIÓ: RaiseError
+          - FUNCIONALITAT: Funció per a notificar errors al l'usuari (en debug) i llença
+          les excepcions
+          - PARÀMETRES:
+          - errorCode: codi d'error
+          - RESULTAT:
+          - Ensenya un missatge a l'usuari (en debug) i llença una excepció
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs Navarra
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /*
+            - FUNCTION: RaiseError
+            - FUNCTIONALITY: Error handling function
+            - PARAMETERS:
+            - errorCode: reason of the error
+            - RESULT:
+            - in _DEBUG version, shows a message box with the error. In release is silent.
+            In both cases throws an exception with the error.
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        void CBlobResult::RaiseError(const int errorCode) const
+        {
+          throw errorCode;
+        }
 
-    // obtenim els nBlob primers resultats (en ordre descendent)
-    std::partial_sort_copy(avaluacioBlobs.begin(),
-      avaluacioBlobs.end(),
-      avaluacioBlobsOrdenat.begin(),
-      avaluacioBlobsOrdenat.end(),
-      std::greater<double>());
 
-    valorEnessim = avaluacioBlobsOrdenat[nBlob];
 
-    // busquem el primer blob que té el valor n-ssim
-    double_stl_vector::const_iterator itAvaluacio = avaluacioBlobs.begin();
+        /**************************************************************************
+          Auxiliars / Auxiliary functions
+          **************************************************************************/
+
+
+          /**
+            - FUNCIÓ: PrintBlobs
+            - FUNCIONALITAT: Escriu els paràmetres (àrea, perímetre, exterior, mitjana)
+            de tots els blobs a un fitxer.
+            - PARÀMETRES:
+            - nom_fitxer: path complet del fitxer amb el resultat
+            - RESULTAT:
+            - RESTRICCIONS:
+            - AUTOR: Ricard Borràs
+            - DATA DE CREACIÓ: 25-05-2005.
+            - MODIFICACIÓ: Data. Autor. Descripció.
+            */
+            /*
+              - FUNCTION: PrintBlobs
+              - FUNCTIONALITY: Prints some blob features in an ASCII file
+              - PARAMETERS:
+              - nom_fitxer: full path + filename to generate
+              - RESULT:
+              - RESTRICTIONS:
+              - AUTHOR: Ricard Borràs
+              - CREATION DATE: 25-05-2005.
+              - MODIFICATION: Date. Author. Description.
+              */
+        void CBlobResult::PrintBlobs(char *nom_fitxer) const
+        {
+          double_stl_vector area, /*perimetre,*/ exterior, mitjana, compacitat, longitud,
+            externPerimeter, perimetreConvex, perimetre;
+          int i;
+          FILE *fitxer_sortida;
+
+          area = GetSTLResult(CBlobGetArea());
+          perimetre = GetSTLResult(CBlobGetPerimeter());
+          exterior = GetSTLResult(CBlobGetExterior());
+          mitjana = GetSTLResult(CBlobGetMean());
+          compacitat = GetSTLResult(CBlobGetCompactness());
+          longitud = GetSTLResult(CBlobGetLength());
+          externPerimeter = GetSTLResult(CBlobGetExternPerimeter());
+          perimetreConvex = GetSTLResult(CBlobGetHullPerimeter());
+
+          fitxer_sortida = fopen(nom_fitxer, "w");
+
+          for (i = 0; i < GetNumBlobs(); i++)
+          {
+            fprintf(fitxer_sortida, "blob %d ->\t a=%7.0f\t p=%8.2f (%8.2f extern)\t pconvex=%8.2f\t ext=%.0f\t m=%7.2f\t c=%3.2f\t l=%8.2f\n",
+              i, area[i], perimetre[i], externPerimeter[i], perimetreConvex[i], exterior[i], mitjana[i], compacitat[i], longitud[i]);
+          }
+          fclose(fitxer_sortida);
 
-    bool trobatBlob = false;
-    int indexBlob = 0;
-    while (itAvaluacio != avaluacioBlobs.end() && !trobatBlob)
-    {
-      if (*itAvaluacio == valorEnessim)
-      {
-        trobatBlob = true;
-        dst = CBlob(GetBlob(indexBlob));
+        }
       }
-      ++itAvaluacio;
-      indexBlob++;
     }
   }
-
-  /**
-    - FUNCIÓ: ClearBlobs
-    - FUNCIONALITAT: Elimina tots els blobs de l'objecte
-    - PARÀMETRES:
-    - RESULTAT:
-    - Allibera tota la memòria dels blobs
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs Navarra
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /*
-      - FUNCTION: ClearBlobs
-      - FUNCTIONALITY: Clears all the blobs from the object and releases all its memory
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  void CBlobResult::ClearBlobs()
-  {
-    /*for( int i = 0; i < GetNumBlobs(); i++ )
-      {
-      delete m_blobs[i];
-      }*/
-    blob_vector::iterator itBlobs = m_blobs.begin();
-    while (itBlobs != m_blobs.end())
-    {
-      delete *itBlobs;
-      ++itBlobs;
-    }
-
-    m_blobs.clear();
-  }
-
-  /**
-    - FUNCIÓ: RaiseError
-    - FUNCIONALITAT: Funció per a notificar errors al l'usuari (en debug) i llença
-    les excepcions
-    - PARÀMETRES:
-    - errorCode: codi d'error
-    - RESULTAT:
-    - Ensenya un missatge a l'usuari (en debug) i llença una excepció
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs Navarra
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /*
-      - FUNCTION: RaiseError
-      - FUNCTIONALITY: Error handling function
-      - PARAMETERS:
-      - errorCode: reason of the error
-      - RESULT:
-      - in _DEBUG version, shows a message box with the error. In release is silent.
-      In both cases throws an exception with the error.
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  void CBlobResult::RaiseError(const int errorCode) const
-  {
-    throw errorCode;
-  }
-
-
-
-  /**************************************************************************
-    Auxiliars / Auxiliary functions
-    **************************************************************************/
-
-
-    /**
-      - FUNCIÓ: PrintBlobs
-      - FUNCIONALITAT: Escriu els paràmetres (àrea, perímetre, exterior, mitjana)
-      de tots els blobs a un fitxer.
-      - PARÀMETRES:
-      - nom_fitxer: path complet del fitxer amb el resultat
-      - RESULTAT:
-      - RESTRICCIONS:
-      - AUTOR: Ricard Borràs
-      - DATA DE CREACIÓ: 25-05-2005.
-      - MODIFICACIÓ: Data. Autor. Descripció.
-      */
-      /*
-        - FUNCTION: PrintBlobs
-        - FUNCTIONALITY: Prints some blob features in an ASCII file
-        - PARAMETERS:
-        - nom_fitxer: full path + filename to generate
-        - RESULT:
-        - RESTRICTIONS:
-        - AUTHOR: Ricard Borràs
-        - CREATION DATE: 25-05-2005.
-        - MODIFICATION: Date. Author. Description.
-        */
-  void CBlobResult::PrintBlobs(char *nom_fitxer) const
-  {
-    double_stl_vector area, /*perimetre,*/ exterior, mitjana, compacitat, longitud,
-      externPerimeter, perimetreConvex, perimetre;
-    int i;
-    FILE *fitxer_sortida;
-
-    area = GetSTLResult(CBlobGetArea());
-    perimetre = GetSTLResult(CBlobGetPerimeter());
-    exterior = GetSTLResult(CBlobGetExterior());
-    mitjana = GetSTLResult(CBlobGetMean());
-    compacitat = GetSTLResult(CBlobGetCompactness());
-    longitud = GetSTLResult(CBlobGetLength());
-    externPerimeter = GetSTLResult(CBlobGetExternPerimeter());
-    perimetreConvex = GetSTLResult(CBlobGetHullPerimeter());
-
-    fitxer_sortida = fopen(nom_fitxer, "w");
-
-    for (i = 0; i < GetNumBlobs(); i++)
-    {
-      fprintf(fitxer_sortida, "blob %d ->\t a=%7.0f\t p=%8.2f (%8.2f extern)\t pconvex=%8.2f\t ext=%.0f\t m=%7.2f\t c=%3.2f\t l=%8.2f\n",
-        i, area[i], perimetre[i], externPerimeter[i], perimetreConvex[i], exterior[i], mitjana[i], compacitat[i], longitud[i]);
-    }
-    fclose(fitxer_sortida);
-
-  }
-
 }
diff --git a/src/algorithms/MultiLayer/BlobResult.h b/src/algorithms/MultiLayer/BlobResult.h
index 62ec48551cac4c82d2ae9e96e3c13a7142fe462d..96d92648ef881d0a44a4c5a6f5af84d7d90c3f6c 100644
--- a/src/algorithms/MultiLayer/BlobResult.h
+++ b/src/algorithms/MultiLayer/BlobResult.h
@@ -9,135 +9,137 @@
 #include "OpenCvLegacyIncludes.h"
 #include "blob.h"
 
-typedef std::vector<double> double_stl_vector;
-
-/**************************************************************************
-  Filtres / Filters
-  **************************************************************************/
-
-  //! accions que es poden fer amb els filtres
-  //! Actions performed by a filter (include or exclude blobs)
-#define B_INCLUDE				1L
-#define B_EXCLUDE				2L
-
-//! condicions sobre els filtres
-//! Conditions to apply the filters
-#define B_EQUAL					3L
-#define B_NOT_EQUAL				4L
-#define B_GREATER				5L
-#define B_LESS					6L
-#define B_GREATER_OR_EQUAL		7L
-#define B_LESS_OR_EQUAL			8L
-#define B_INSIDE			    9L
-#define B_OUTSIDE			    10L
-
-
-/**************************************************************************
-  Excepcions / Exceptions
-  **************************************************************************/
-
-  //! Excepcions llençades per les funcions:
-#define EXCEPTION_BLOB_OUT_OF_BOUNDS	1000
-#define EXCEPCIO_CALCUL_BLOBS			1001
-
-namespace Blob
+namespace bgslibrary
 {
-
-  //! definició de que es un vector de blobs
-  typedef std::vector<CBlob*>	blob_vector;
-
-  /**
-      Classe que conté un conjunt de blobs i permet extreure'n propietats
-      o filtrar-los segons determinats criteris.
-      Class to calculate the blobs of an image and calculate some properties
-      on them. Also, the class provides functions to filter the blobs using
-      some criteria.
-      */
-  class CBlobResult
+  namespace algorithms
   {
-  public:
-
-    //! constructor estandard, crea un conjunt buit de blobs
-    //! Standard constructor, it creates an empty set of blobs
-    CBlobResult();
-    //! constructor a partir d'una imatge
-    //! Image constructor, it creates an object with the blobs of the image
-    CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments);
-    //! constructor de còpia
-    //! Copy constructor
-    CBlobResult(const CBlobResult &source);
-    //! Destructor
-    virtual ~CBlobResult();
-
-    //! operador = per a fer assignacions entre CBlobResult
-    //! Assigment operator
-    CBlobResult& operator=(const CBlobResult& source);
-    //! operador + per concatenar dos CBlobResult
-    //! Addition operator to concatenate two sets of blobs
-    CBlobResult operator+(const CBlobResult& source);
-
-    //! Afegeix un blob al conjunt
-    //! Adds a blob to the set of blobs
-    void AddBlob(CBlob *blob);
-
-#ifdef MATRIXCV_ACTIU
-    //! Calcula un valor sobre tots els blobs de la classe retornant una MatrixCV
-    //! Computes some property on all the blobs of the class
-    double_vector GetResult(funcio_calculBlob *evaluador) const;
-#endif
-    //! Calcula un valor sobre tots els blobs de la classe retornant un std::vector<double>
-    //! Computes some property on all the blobs of the class
-    double_stl_vector GetSTLResult(funcio_calculBlob *evaluador) const;
-
-    //! Calcula un valor sobre un blob de la classe
-    //! Computes some property on one blob of the class
-    double GetNumber(int indexblob, funcio_calculBlob *evaluador) const;
-
-    //! Retorna aquells blobs que compleixen les condicions del filtre en el destination
-    //! Filters the blobs of the class using some property
-    void Filter(CBlobResult &dst,
-      int filterAction, funcio_calculBlob *evaluador,
-      int condition, double lowLimit, double highLimit = 0);
-
-    //! Retorna l'enèssim blob segons un determinat criteri
-    //! Sorts the blobs of the class acording to some criteria and returns the n-th blob
-    void GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const;
-
-    //! Retorna el blob enèssim
-    //! Gets the n-th blob of the class ( without sorting )
-    CBlob GetBlob(int indexblob) const;
-    CBlob *GetBlob(int indexblob);
-
-    //! Elimina tots els blobs de l'objecte
-    //! Clears all the blobs of the class
-    void ClearBlobs();
-
-    //! Escriu els blobs a un fitxer
-    //! Prints some features of all the blobs in a file
-    void PrintBlobs(char *nom_fitxer) const;
-
-
-    //Metodes GET/SET
-
-    //! Retorna el total de blobs
-    //! Gets the total number of blobs
-    int GetNumBlobs() const
+    namespace multilayer
     {
-      return(m_blobs.size());
+      namespace blob
+      {
+        typedef std::vector<double> double_stl_vector;
+
+        /**************************************************************************
+          Filtres / Filters
+          **************************************************************************/
+
+          //! accions que es poden fer amb els filtres
+          //! Actions performed by a filter (include or exclude blobs)
+        const long B_INCLUDE = 1L;
+        const long B_EXCLUDE = 2L;
+
+        //! condicions sobre els filtres
+        //! Conditions to apply the filters
+        const long B_EQUAL = 3L;
+        const long B_NOT_EQUAL = 4L;
+        const long B_GREATER = 5L;
+        const long B_LESS = 6L;
+        const long B_GREATER_OR_EQUAL = 7L;
+        const long B_LESS_OR_EQUAL = 8L;
+        const long B_INSIDE = 9L;
+        const long B_OUTSIDE = 10L;
+
+        /**************************************************************************
+          Excepcions / Exceptions
+          **************************************************************************/
+
+          //! Excepcions llençades per les funcions:
+        const int EXCEPTION_BLOB_OUT_OF_BOUNDS = 1000;
+        const int EXCEPCIO_CALCUL_BLOBS = 1001;
+
+        //! definició de que es un vector de blobs
+        typedef std::vector<CBlob*>	blob_vector;
+
+        /**
+            Classe que conté un conjunt de blobs i permet extreure'n propietats
+            o filtrar-los segons determinats criteris.
+            Class to calculate the blobs of an image and calculate some properties
+            on them. Also, the class provides functions to filter the blobs using
+            some criteria.
+            */
+        class CBlobResult
+        {
+        public:
+          //! constructor estandard, crea un conjunt buit de blobs
+          //! Standard constructor, it creates an empty set of blobs
+          CBlobResult();
+          //! constructor a partir d'una imatge
+          //! Image constructor, it creates an object with the blobs of the image
+          CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments);
+          //! constructor de còpia
+          //! Copy constructor
+          CBlobResult(const CBlobResult &source);
+          //! Destructor
+          virtual ~CBlobResult();
+
+          //! operador = per a fer assignacions entre CBlobResult
+          //! Assigment operator
+          CBlobResult& operator=(const CBlobResult& source);
+          //! operador + per concatenar dos CBlobResult
+          //! Addition operator to concatenate two sets of blobs
+          CBlobResult operator+(const CBlobResult& source);
+
+          //! Afegeix un blob al conjunt
+          //! Adds a blob to the set of blobs
+          void AddBlob(CBlob *blob);
+
+      #ifdef MATRIXCV_ACTIU
+          //! Calcula un valor sobre tots els blobs de la classe retornant una MatrixCV
+          //! Computes some property on all the blobs of the class
+          double_vector GetResult(funcio_calculBlob *evaluador) const;
+      #endif
+          //! Calcula un valor sobre tots els blobs de la classe retornant un std::vector<double>
+          //! Computes some property on all the blobs of the class
+          double_stl_vector GetSTLResult(funcio_calculBlob *evaluador) const;
+
+          //! Calcula un valor sobre un blob de la classe
+          //! Computes some property on one blob of the class
+          double GetNumber(int indexblob, funcio_calculBlob *evaluador) const;
+
+          //! Retorna aquells blobs que compleixen les condicions del filtre en el destination
+          //! Filters the blobs of the class using some property
+          void Filter(CBlobResult &dst,
+            int filterAction, funcio_calculBlob *evaluador,
+            int condition, double lowLimit, double highLimit = 0);
+
+          //! Retorna l'enèssim blob segons un determinat criteri
+          //! Sorts the blobs of the class acording to some criteria and returns the n-th blob
+          void GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const;
+
+          //! Retorna el blob enèssim
+          //! Gets the n-th blob of the class ( without sorting )
+          CBlob GetBlob(int indexblob) const;
+          CBlob *GetBlob(int indexblob);
+
+          //! Elimina tots els blobs de l'objecte
+          //! Clears all the blobs of the class
+          void ClearBlobs();
+
+          //! Escriu els blobs a un fitxer
+          //! Prints some features of all the blobs in a file
+          void PrintBlobs(char *nom_fitxer) const;
+
+
+          //Metodes GET/SET
+
+          //! Retorna el total de blobs
+          //! Gets the total number of blobs
+          int GetNumBlobs() const
+          {
+            return(m_blobs.size());
+          }
+
+        private:
+          //! Funció per gestionar els errors
+          //! Function to manage the errors
+          void RaiseError(const int errorCode) const;
+
+        protected:
+          //! Vector amb els blobs
+          //! Vector with all the blobs
+          blob_vector		m_blobs;
+        };
+      }
     }
-
-
-  private:
-
-    //! Funció per gestionar els errors
-    //! Function to manage the errors
-    void RaiseError(const int errorCode) const;
-
-  protected:
-
-    //! Vector amb els blobs
-    //! Vector with all the blobs
-    blob_vector		m_blobs;
-  };
-
+  }
 }
diff --git a/src/algorithms/MultiLayer/CMultiLayerBGS.cpp b/src/algorithms/MultiLayer/CMultiLayerBGS.cpp
index 0708e57c2910af7e3c270914af1aaeb5636572b9..48e2b42473224ca2a1c8d4ed39bd17a67e6ef7c5 100644
--- a/src/algorithms/MultiLayer/CMultiLayerBGS.cpp
+++ b/src/algorithms/MultiLayer/CMultiLayerBGS.cpp
@@ -9,11 +9,8 @@
 #include "CMultiLayerBGS.h"
 #include "OpenCvLegacyIncludes.h"
 
-using namespace Blob;
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
+using namespace bgslibrary::algorithms::multilayer;
+using namespace bgslibrary::algorithms::multilayer::blob;
 
 CMultiLayerBGS::CMultiLayerBGS() {
   m_nMaxLBPModeNum = MAX_LBP_MODE_NUM;
@@ -1639,7 +1636,7 @@ void CMultiLayerBGS::GetFloatEdgeImage(IplImage *src, IplImage *dst) {
 
 void CMultiLayerBGS::ExportLogMessage(char *msg) {
   const char *log_fn = "log_message.txt";
-  ofstream fout(log_fn, ios::app);
+  std::ofstream fout(log_fn, std::ios::app);
   if (fout.fail()) {
     printf("Error opening log output file %s.\n", log_fn);
     fout.close();
@@ -1826,7 +1823,7 @@ void CMultiLayerBGS::Save(const char *bg_model_fn, int save_type) {
 }
 
 bool CMultiLayerBGS::Load(const char *bg_model_fn) {
-  ifstream fin(bg_model_fn, ios::in);
+  std::ifstream fin(bg_model_fn, std::ios::in);
   if (fin.fail()) {
     printf("Error opening background model file %s.\n", bg_model_fn);
     fin.close();
diff --git a/src/algorithms/MultiLayer/CMultiLayerBGS.h b/src/algorithms/MultiLayer/CMultiLayerBGS.h
index 3043a804104c1cc170af8dd6814317da253f9f58..302a19a56a9b690f7026bbe8b850765feaf1612b 100644
--- a/src/algorithms/MultiLayer/CMultiLayerBGS.h
+++ b/src/algorithms/MultiLayer/CMultiLayerBGS.h
@@ -23,243 +23,249 @@ step. If you compile it under Linux, please uncomment it.
 #include "LocalBinaryPattern.h"
 #include "BlobResult.h"
 #include "OpenCvDataConversion.h"
-
 #include "BackgroundSubtractionAPI.h"
 
 #ifdef LINUX_BILATERAL_FILTER
 #include "CrossBilateralFilter.h"
 #endif
 
-using namespace std;
-
-class CMultiLayerBGS : public CBackgroundSubtractionAPI
+namespace bgslibrary
 {
-public:
-  //-------------------------------------------------------------
-  // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES
-  // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED
-  void   Init(int width, int height);
-
-  //-------------------------------------------------------------
-  // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND
-  // SUBTRACTION DOES NOT NEED TO BE PERFORMED
-  //
-  //  mode is useful to specify if the points to remove from
-  //  processing are in addition to the ones potentially
-  //  removed according to the configuration file,
-  //  or if they are the only ones to be removed
-  //
-  // mode=0 : provided points need to be removed
-  //          in addition to those already removed
-  // mode=1 : the provided points are the only one to remove
-  //          from processing
-  // Note:  maskImage(li,co)=0 indicate the points to remove
-  //       from background processing
-  void   SetValidPointMask(IplImage* maskImage, int mode);
-
-  //-------------------------------------------------------------
-  //
-  //   set the frame rate, to adjust the update parameters
-  //   to the actual frame rate.
-  //   Can be called only once at initialisation,
-  //   but in online cases, can be used to indicate
-  //   the time interval during the last processed frame
-  //
-  //   frameDuration is in millisecond
-  void   SetFrameRate(float    frameDuration);
-
-  //-------------------------------------------------------------
-  //
-  //   set some main parameters for background model learning.
-  //   in general, we can set large updating rates for background
-  //   model learning and set small updating rates in foreground
-  //   detection
-  void SetParameters(int max_lbp_mode_num,		// maximal LBP mode number
-    float mode_updating_learn_rate_per_second,	// background mode updating learning rate per second
-    float weight_updating_learn_rate_per_second,	// mode's weight updating learning rate per second
-    float low_init_mode_weight);			// the low initial mode weight
-
-//-------------------------------------------------------------
-//   PROVIDE A POINTER TO THE INPUT IMAGE
-//   -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED
-//
-//   Here assumes that the input image will contain RGB images.
-//   The memory of this image is handled by the caller.
-//
-//    The return value indicate whether the actual Background
-//    Subtraction algorithm handles RGB images (1) or not (0).
-//
-  int   SetRGBInputImage(IplImage  *  inputImage, CvRect *roi = NULL);
-
-  //-------------------------------------------------------------
-  //   PROVIDE A POINTER TO THE RESULT IMAGE
-  //   INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED
-  //
-  int SetForegroundMaskImage(IplImage* fg_mask_img);
-  int SetForegroundProbImage(IplImage* fg_prob_img);
-
-  //-------------------------------------------------------------
-  // This function should be called each time a new image is
-  // available in the input image.
-  //
-  // The return value is 0 if everything goes well, a non-zero value
-  // otherwise.
-  //
-  int   Process();
-
-  //-------------------------------------------------------------
-  // this function should save parameters and information of the model
-  // (e.g. after a training of the model, or in such a way
-  // that the model can be reload to process the next frame
-  // type of save:
-  //	0 - background model information (pixel by pixel)
-  //	1 - background model parameters
-  //	2 - both background information (pixel by pixel) and parameters
-  void   Save(const char   *bg_model_fn, int save_type);
-  void   Save(const char* bg_model_fn);
-
-  //-------------------------------------------------------------
-  // this function should load the parameters necessary
-  // for the processing of the background subtraction or
-  // load background model information
-  bool   Load(const char  *bg_model_fn);
-
-
-  void SetCurrentFrameNumber(unsigned long cur_frame_no);
-
-  void GetForegroundMaskImage(IplImage *fg_mask_img);
-  void GetForegroundImage(IplImage *fg_img, CvScalar bg_color = CV_RGB(0, 255, 0));
-  void GetBackgroundImage(IplImage *bk_img);
-  void GetForegroundProbabilityImage(IplImage* fg_prob_img);
-
-  void GetBgLayerNoImage(IplImage *bg_layer_no_img, CvScalar* layer_colors = NULL, int layer_num = 0);
-  void GetLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, CvScalar empty_color = CV_RGB(0, 0, 0));
-  void GetCurrentLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, IplImage *layered_fg_img = NULL,
-    CvScalar layered_bg_bk_color = CV_RGB(0, 0, 0), CvScalar layered_fg_color = CV_RGB(255, 0, 0),
-    int smooth_win = 13, float smooth_sigma = 3.0f, float below_layer_noise = 0.5f, float above_layer_noise = 0.3f, int min_blob_size = 50);
-  float DistLBP(LBPStruct *LBP1, LBPStruct *LBP2);
-  void GetColoredBgMultiLayeredImage(IplImage *bg_multi_layer_img, CvScalar *layer_colors);
-  void UpdatePatternColorDistWeights(float *cur_pattern, float *bg_pattern);
-  void ExportLogMessage(char* msg);
-  void Postprocessing();
-  void GetFloatEdgeImage(IplImage *src, IplImage *dst);
-  void RemoveBackgroundLayers(PixelLBPStruct *PLBP, bool *removed_modes = NULL);
-  float CalColorRangeDist(unsigned char *cur_intensity, float *bg_intensity, float *max_intensity,
-    float *min_intensity, float shadow_rate, float highlight_rate);
-  float CalVectorsAngle(float *c1, unsigned char *c2, int length);
-  float CalVectorsNoisedAngle(float *bg_color, unsigned char *noised_color, float offset, int length);
-  void ComputeGradientImage(IplImage *src, IplImage *dst, bool bIsFloat);
-  float CalColorBgDist(uchar *cur_intensity, float *bg_intensity, float *max_intensity, float *min_intensity);
-  float CalPatternBgDist(float *cur_pattern, float *bg_pattern);
-
-  void GetForegroundMaskMap(CvMat *fg_mask_mat);
-  void Initialization(IplImage *first_img, int lbp_level_num, float *radiuses, int *neig_pt_nums);
-  void GetCurrentBackgroundDistMap(CvMat *bk_dist_map);
-  void BackgroundSubtractionProcess();
-  void SetBkMaskImage(IplImage *mask_img);
-  void SetNewImage(IplImage *new_img, CvRect *roi = NULL);
-
-  void ResetAllParameters();
-  void QuickSort(float *pData, unsigned short *pIdxes, long low, long high, bool bAscent);
-  void UpdateBgPixelPattern(float *cur_pattern, float *bg_bg_pattern);
-  void UpdateBgPixelColor(unsigned char* cur_intensity, float* bg_intensity);
-  void Update_MAX_MIN_Intensity(unsigned char *cur_intensity, float *max_intensity, float *min_intensity);
-  void MergeImages(int num, ...);
-
-  int	m_nChannel;				/* most of opencv functions support 1,2,3 or 4 channels, for the input images */
-
-  PixelLBPStruct*	m_pPixelLBPs;			/* the LBP texture patterns for each image */
-  int	m_nMaxLBPModeNum;			/* the maximal number for the used LBP pattern models */
-  float	m_fModeUpdatingLearnRate;		/* the background mode learning rate */
-  float	m_fWeightUpdatingLearnRate;		/* the background mode weight updating rate */
-  float	m_f1_ModeUpdatingLearnRate;		/* 1 - background_mode_learning_rate */
-  float	m_f1_WeightUpdatingLearnRate;		/* 1 - background_mode_weight_updating_rate */
-  float	m_fRobustColorOffset;			/* the intensity offset robust to noise */
-  float	m_fLowInitialModeWeight;		/* the lowest weight of initial background mode */
-  int	m_nLBPLength;				/* the length of texture LBP operator */
-  float	m_fPatternColorDistBgThreshold;		/* the threshold value used to classify background and foreground */
-  float	m_fPatternColorDistBgUpdatedThreshold;	/* the threshold value used to update the background modeling */
-  float	m_fMinBgLayerWeight;			/* the minimal weight to remove background layers */
-
-  int	m_nPatternDistSmoothNeigHalfSize;	/* the neighboring half size of gaussian window to remove the noise
-                                        on the distance map */
-  float	m_fPatternDistConvGaussianSigma;	/* the gaussian sigma used to remove the noise on the distance map */
-
-  float	m_fBackgroundModelPercent;		/* the background mode percent, the first several background modes
-                                      with high mode weights should be regarded as reliable background modes */
-
-  float	m_fRobustShadowRate;			/* the minimal shadow rate, [0.4, 0.7] */
-  float	m_fRobustHighlightRate;			/* the maximal highlight rate, [1.1, 1.4] */
-
-  int	m_nLBPImgNum;				/* the number of images used for texture LBP feature */
-
-  float	m_fMinLBPBinaryProb;			/* the minimal LBP binary probability */
-  float	m_f1_MinLBPBinaryProb;			/* 1 - minimal_LBP_binary_probability */
-
-  CvSize	m_cvImgSize;				/* the image size (width, height) */
-
-  unsigned long	m_nCurImgFrameIdx;			/* the frame index of current image */
-
-  bool	m_bUsedGradImage;			/* the boolean variable signaling whether the gradient image is used
-                              or not for computing LBP operator */
-
-  bool	m_bUsedColorLBP;			/* true - multi-channel color image for LBP operator,
-                              false - gray-scale image for LBP operator  */
-
-  CLocalBinaryPattern	m_cLBP;			/* the class instant for computing LBP (local binary pattern) texture feature */
-
-  IplImage* m_pBkMaskImg;				/* the mask image corresponding to the input image,
-                                i.e. all the masked pixels should be processed  */
-
-  IplImage* m_pOrgImg;				/* the original image */
-  IplImage** m_ppOrgLBPImgs;			/* the multi-layer images used for LBP feature extraction */
-  IplImage* m_pFgImg;				/* the foreground image */
-  IplImage* m_pBgImg;				/* the background image */
-  IplImage* m_pFgMaskImg;				/* the foreground mask image */
-  IplImage* m_pBgDistImg;				/* the background distance image (float) */
-  IplImage* m_pEdgeImg;				/* the edge image used for cross bilateral filter */
-  IplImage* m_pFgProbImg;				/* the foreground probability image (uchar) */
-
-  IplImage* m_pFirstAppearingTimeMap;
-
-#ifdef LINUX_BILATERAL_FILTER
-  CCrossBilateralFilter	m_cCrossBF;		/* the class instant for cross bilateral filter
-                                      which should be used to remove noise on the distance map */
-#endif
-
-  bool	m_disableLearning;
-  float	m_fSigmaS;				/* sigma in the spatial domain for cross bilateral filter */
-  float	m_fSigmaR;				/* sigma in the normalized intensity domain for cross bilateral filter */
-
-  float	m_fTextureWeight;			/* the weight value of texture LBP feature
-                              for background modeling & foreground detection */
-
-  float	m_fColorWeight;				/* the weight value of color invariant feature
-                              for background modeling & foreground detection */
-
-  float	m_fWeightUpdatingConstant;		/* the constant ( >= 1 ) for 'hysteries' weight updating scheme
-                                      (increase when matched, decrease when un-matched */
-
-  float	m_fReliableBackgroundModeWeight;	/* the weight value for background mode
-                                          which should be regarded as a reliable background mode,
-                                          which is useful for multi-layer scheme */
-
-  float	m_fMinNoisedAngle;			/* the minimal angle value between the background color
-                                and the noised observed color */
-
-  float	m_fMinNoisedAngleSine;			/* the minimal angle sine value between the background color
-                                    and the noised observed color */
+  namespace algorithms
+  {
+    namespace multilayer
+    {
+      class CMultiLayerBGS : public CBackgroundSubtractionAPI
+      {
+      public:
+        //-------------------------------------------------------------
+        // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES
+        // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED
+        void   Init(int width, int height);
+
+        //-------------------------------------------------------------
+        // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND
+        // SUBTRACTION DOES NOT NEED TO BE PERFORMED
+        //
+        //  mode is useful to specify if the points to remove from
+        //  processing are in addition to the ones potentially
+        //  removed according to the configuration file,
+        //  or if they are the only ones to be removed
+        //
+        // mode=0 : provided points need to be removed
+        //          in addition to those already removed
+        // mode=1 : the provided points are the only one to remove
+        //          from processing
+        // Note:  maskImage(li,co)=0 indicate the points to remove
+        //       from background processing
+        void   SetValidPointMask(IplImage* maskImage, int mode);
+
+        //-------------------------------------------------------------
+        //
+        //   set the frame rate, to adjust the update parameters
+        //   to the actual frame rate.
+        //   Can be called only once at initialisation,
+        //   but in online cases, can be used to indicate
+        //   the time interval during the last processed frame
+        //
+        //   frameDuration is in millisecond
+        void   SetFrameRate(float    frameDuration);
+
+        //-------------------------------------------------------------
+        //
+        //   set some main parameters for background model learning.
+        //   in general, we can set large updating rates for background
+        //   model learning and set small updating rates in foreground
+        //   detection
+        void SetParameters(int max_lbp_mode_num,		// maximal LBP mode number
+          float mode_updating_learn_rate_per_second,	// background mode updating learning rate per second
+          float weight_updating_learn_rate_per_second,	// mode's weight updating learning rate per second
+          float low_init_mode_weight);			// the low initial mode weight
+
+      //-------------------------------------------------------------
+      //   PROVIDE A POINTER TO THE INPUT IMAGE
+      //   -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED
+      //
+      //   Here assumes that the input image will contain RGB images.
+      //   The memory of this image is handled by the caller.
+      //
+      //    The return value indicate whether the actual Background
+      //    Subtraction algorithm handles RGB images (1) or not (0).
+      //
+        int   SetRGBInputImage(IplImage  *  inputImage, CvRect *roi = NULL);
+
+        //-------------------------------------------------------------
+        //   PROVIDE A POINTER TO THE RESULT IMAGE
+        //   INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED
+        //
+        int SetForegroundMaskImage(IplImage* fg_mask_img);
+        int SetForegroundProbImage(IplImage* fg_prob_img);
+
+        //-------------------------------------------------------------
+        // This function should be called each time a new image is
+        // available in the input image.
+        //
+        // The return value is 0 if everything goes well, a non-zero value
+        // otherwise.
+        //
+        int   Process();
+
+        //-------------------------------------------------------------
+        // this function should save parameters and information of the model
+        // (e.g. after a training of the model, or in such a way
+        // that the model can be reload to process the next frame
+        // type of save:
+        //	0 - background model information (pixel by pixel)
+        //	1 - background model parameters
+        //	2 - both background information (pixel by pixel) and parameters
+        void   Save(const char   *bg_model_fn, int save_type);
+        void   Save(const char* bg_model_fn);
+
+        //-------------------------------------------------------------
+        // this function should load the parameters necessary
+        // for the processing of the background subtraction or
+        // load background model information
+        bool   Load(const char  *bg_model_fn);
+
+
+        void SetCurrentFrameNumber(unsigned long cur_frame_no);
+
+        void GetForegroundMaskImage(IplImage *fg_mask_img);
+        void GetForegroundImage(IplImage *fg_img, CvScalar bg_color = CV_RGB(0, 255, 0));
+        void GetBackgroundImage(IplImage *bk_img);
+        void GetForegroundProbabilityImage(IplImage* fg_prob_img);
+
+        void GetBgLayerNoImage(IplImage *bg_layer_no_img, CvScalar* layer_colors = NULL, int layer_num = 0);
+        void GetLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, CvScalar empty_color = CV_RGB(0, 0, 0));
+        void GetCurrentLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, IplImage *layered_fg_img = NULL,
+          CvScalar layered_bg_bk_color = CV_RGB(0, 0, 0), CvScalar layered_fg_color = CV_RGB(255, 0, 0),
+          int smooth_win = 13, float smooth_sigma = 3.0f, float below_layer_noise = 0.5f, float above_layer_noise = 0.3f, int min_blob_size = 50);
+        float DistLBP(LBPStruct *LBP1, LBPStruct *LBP2);
+        void GetColoredBgMultiLayeredImage(IplImage *bg_multi_layer_img, CvScalar *layer_colors);
+        void UpdatePatternColorDistWeights(float *cur_pattern, float *bg_pattern);
+        void ExportLogMessage(char* msg);
+        void Postprocessing();
+        void GetFloatEdgeImage(IplImage *src, IplImage *dst);
+        void RemoveBackgroundLayers(PixelLBPStruct *PLBP, bool *removed_modes = NULL);
+        float CalColorRangeDist(unsigned char *cur_intensity, float *bg_intensity, float *max_intensity,
+          float *min_intensity, float shadow_rate, float highlight_rate);
+        float CalVectorsAngle(float *c1, unsigned char *c2, int length);
+        float CalVectorsNoisedAngle(float *bg_color, unsigned char *noised_color, float offset, int length);
+        void ComputeGradientImage(IplImage *src, IplImage *dst, bool bIsFloat);
+        float CalColorBgDist(uchar *cur_intensity, float *bg_intensity, float *max_intensity, float *min_intensity);
+        float CalPatternBgDist(float *cur_pattern, float *bg_pattern);
+
+        void GetForegroundMaskMap(CvMat *fg_mask_mat);
+        void Initialization(IplImage *first_img, int lbp_level_num, float *radiuses, int *neig_pt_nums);
+        void GetCurrentBackgroundDistMap(CvMat *bk_dist_map);
+        void BackgroundSubtractionProcess();
+        void SetBkMaskImage(IplImage *mask_img);
+        void SetNewImage(IplImage *new_img, CvRect *roi = NULL);
+
+        void ResetAllParameters();
+        void QuickSort(float *pData, unsigned short *pIdxes, long low, long high, bool bAscent);
+        void UpdateBgPixelPattern(float *cur_pattern, float *bg_bg_pattern);
+        void UpdateBgPixelColor(unsigned char* cur_intensity, float* bg_intensity);
+        void Update_MAX_MIN_Intensity(unsigned char *cur_intensity, float *max_intensity, float *min_intensity);
+        void MergeImages(int num, ...);
+
+        int	m_nChannel;				/* most of opencv functions support 1,2,3 or 4 channels, for the input images */
+
+        PixelLBPStruct*	m_pPixelLBPs;			/* the LBP texture patterns for each image */
+        int	m_nMaxLBPModeNum;			/* the maximal number for the used LBP pattern models */
+        float	m_fModeUpdatingLearnRate;		/* the background mode learning rate */
+        float	m_fWeightUpdatingLearnRate;		/* the background mode weight updating rate */
+        float	m_f1_ModeUpdatingLearnRate;		/* 1 - background_mode_learning_rate */
+        float	m_f1_WeightUpdatingLearnRate;		/* 1 - background_mode_weight_updating_rate */
+        float	m_fRobustColorOffset;			/* the intensity offset robust to noise */
+        float	m_fLowInitialModeWeight;		/* the lowest weight of initial background mode */
+        int	m_nLBPLength;				/* the length of texture LBP operator */
+        float	m_fPatternColorDistBgThreshold;		/* the threshold value used to classify background and foreground */
+        float	m_fPatternColorDistBgUpdatedThreshold;	/* the threshold value used to update the background modeling */
+        float	m_fMinBgLayerWeight;			/* the minimal weight to remove background layers */
+
+        int	m_nPatternDistSmoothNeigHalfSize;	/* the neighboring half size of gaussian window to remove the noise
+                                              on the distance map */
+        float	m_fPatternDistConvGaussianSigma;	/* the gaussian sigma used to remove the noise on the distance map */
+
+        float	m_fBackgroundModelPercent;		/* the background mode percent, the first several background modes
+                                            with high mode weights should be regarded as reliable background modes */
+
+        float	m_fRobustShadowRate;			/* the minimal shadow rate, [0.4, 0.7] */
+        float	m_fRobustHighlightRate;			/* the maximal highlight rate, [1.1, 1.4] */
+
+        int	m_nLBPImgNum;				/* the number of images used for texture LBP feature */
+
+        float	m_fMinLBPBinaryProb;			/* the minimal LBP binary probability */
+        float	m_f1_MinLBPBinaryProb;			/* 1 - minimal_LBP_binary_probability */
+
+        CvSize	m_cvImgSize;				/* the image size (width, height) */
+
+        unsigned long	m_nCurImgFrameIdx;			/* the frame index of current image */
+
+        bool	m_bUsedGradImage;			/* the boolean variable signaling whether the gradient image is used
+                                    or not for computing LBP operator */
+
+        bool	m_bUsedColorLBP;			/* true - multi-channel color image for LBP operator,
+                                    false - gray-scale image for LBP operator  */
+
+        CLocalBinaryPattern	m_cLBP;			/* the class instant for computing LBP (local binary pattern) texture feature */
+
+        IplImage* m_pBkMaskImg;				/* the mask image corresponding to the input image,
+                                      i.e. all the masked pixels should be processed  */
+
+        IplImage* m_pOrgImg;				/* the original image */
+        IplImage** m_ppOrgLBPImgs;			/* the multi-layer images used for LBP feature extraction */
+        IplImage* m_pFgImg;				/* the foreground image */
+        IplImage* m_pBgImg;				/* the background image */
+        IplImage* m_pFgMaskImg;				/* the foreground mask image */
+        IplImage* m_pBgDistImg;				/* the background distance image (float) */
+        IplImage* m_pEdgeImg;				/* the edge image used for cross bilateral filter */
+        IplImage* m_pFgProbImg;				/* the foreground probability image (uchar) */
+
+        IplImage* m_pFirstAppearingTimeMap;
+
+      #ifdef LINUX_BILATERAL_FILTER
+        CCrossBilateralFilter	m_cCrossBF;		/* the class instant for cross bilateral filter
+                                            which should be used to remove noise on the distance map */
+      #endif
+
+        bool	m_disableLearning;
+        float	m_fSigmaS;				/* sigma in the spatial domain for cross bilateral filter */
+        float	m_fSigmaR;				/* sigma in the normalized intensity domain for cross bilateral filter */
+
+        float	m_fTextureWeight;			/* the weight value of texture LBP feature
+                                    for background modeling & foreground detection */
+
+        float	m_fColorWeight;				/* the weight value of color invariant feature
+                                    for background modeling & foreground detection */
+
+        float	m_fWeightUpdatingConstant;		/* the constant ( >= 1 ) for 'hysteries' weight updating scheme
+                                            (increase when matched, decrease when un-matched */
+
+        float	m_fReliableBackgroundModeWeight;	/* the weight value for background mode
+                                                which should be regarded as a reliable background mode,
+                                                which is useful for multi-layer scheme */
+
+        float	m_fMinNoisedAngle;			/* the minimal angle value between the background color
+                                      and the noised observed color */
+
+        float	m_fMinNoisedAngleSine;			/* the minimal angle sine value between the background color
+                                          and the noised observed color */
 
-  float	m_fFrameDuration;			/* frame duration */
+        float	m_fFrameDuration;			/* frame duration */
 
-  float	m_fModeUpdatingLearnRatePerSecond;
-  float	m_fWeightUpdatingLearnRatePerSecond;
+        float	m_fModeUpdatingLearnRatePerSecond;
+        float	m_fWeightUpdatingLearnRatePerSecond;
 
-  int m_nLBPLevelNum;
-  float m_pLBPRadiuses[10];
-  int m_pLBPMeigPointNums[10];
+        int m_nLBPLevelNum;
+        float m_pLBPRadiuses[10];
+        int m_pLBPMeigPointNums[10];
 
-  CvRect* m_pROI;
-  CMultiLayerBGS();
-  virtual ~CMultiLayerBGS();
-};
+        CvRect* m_pROI;
+        CMultiLayerBGS();
+        virtual ~CMultiLayerBGS();
+      };
+    }
+  }
+}
diff --git a/src/algorithms/MultiLayer/LocalBinaryPattern.cpp b/src/algorithms/MultiLayer/LocalBinaryPattern.cpp
index d781d4eecfa224b59b8080220fb77fe2ea9c9502..7ff5f17a520e4b02b28d61e76b420377deff4074 100644
--- a/src/algorithms/MultiLayer/LocalBinaryPattern.cpp
+++ b/src/algorithms/MultiLayer/LocalBinaryPattern.cpp
@@ -1,11 +1,8 @@
 #include "LocalBinaryPattern.h"
 
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
+using namespace bgslibrary::algorithms::multilayer;
 
-CLocalBinaryPattern::CLocalBinaryPattern()
-{
+CLocalBinaryPattern::CLocalBinaryPattern() {
   m_ppOrgImgs = NULL;
   m_pRadiuses = NULL;
   m_fRobustWhiteNoise = 3.0f;
@@ -14,26 +11,20 @@ CLocalBinaryPattern::CLocalBinaryPattern()
   m_pShiftedImg = NULL;
 }
 
-CLocalBinaryPattern::~CLocalBinaryPattern()
-{
+CLocalBinaryPattern::~CLocalBinaryPattern() {
   FreeMemories();
 }
 
 void CLocalBinaryPattern::Initialization(IplImage **first_imgs, int imgs_num, int level_num, float *radius, int *neig_pt_num, float robust_white_noise, int type)
 {
-
   m_nImgsNum = imgs_num;
-
   m_nLBPLevelNum = level_num;
-
   m_pRadiuses = new float[m_nLBPLevelNum];
   m_pNeigPointsNums = new int[m_nLBPLevelNum];
   m_ppOrgImgs = first_imgs;
-
   int a, b;
   for (a = 0; a < m_nImgsNum; a++) {
     m_cvImgSize = cvGetSize(first_imgs[a]);
-
     if (first_imgs[a]->nChannels > 1) {
       printf("Input image channel must be 1!");
       exit(1);
@@ -52,9 +43,7 @@ void CLocalBinaryPattern::Initialization(IplImage **first_imgs, int imgs_num, in
   }
 
   m_pShiftedImg = cvCloneImage(m_ppOrgImgs[0]);
-
   m_pXYShifts = new CvPoint[tot_neig_pts_num];
-
   m_nMaxShift.x = 0;
   m_nMaxShift.y = 0;
   int shift_idx = 0;
diff --git a/src/algorithms/MultiLayer/LocalBinaryPattern.h b/src/algorithms/MultiLayer/LocalBinaryPattern.h
index d02aa6769202ffa82763134fece607befad00a5e..30e17e98d53e22362d28f2fdaddb45224b1fd093 100644
--- a/src/algorithms/MultiLayer/LocalBinaryPattern.h
+++ b/src/algorithms/MultiLayer/LocalBinaryPattern.h
@@ -5,46 +5,55 @@
 #include "BGS.h"
 #include "OpenCvDataConversion.h"
 
-/************************************************************************/
-/* two types of computing the LBP operators but currently GENERAL_LBP   */
-/* has been implemented.                                                */
-/************************************************************************/
-#define	GENERAL_LBP	0
-#define SYMMETRIC_LBP	1
-
-class CLocalBinaryPattern
+namespace bgslibrary
 {
-public:
-  void CalImageDifferenceMap(IplImage *cent_img, IplImage *neig_img, float *pattern, CvRect *roi = NULL);
-  void CalNeigPixelOffset(float radius, int tot_neig_pts_num, int neig_pt_idx, int &offset_x, int &offset_y);
-  void CalShiftedImage(IplImage *src, int offset_x, int offset_y, IplImage *dst, CvRect *roi = NULL);
-  void FreeMemories();
-  void ComputeLBP(PixelLBPStruct *PLBP, CvRect *roi = NULL);
-  void SetNewImages(IplImage **new_imgs);
-
-  IplImage** m_ppOrgImgs;			/* the original images used for computing the LBP operators */
-
-  void Initialization(IplImage **first_imgs, int imgs_num,
-    int level_num, float *radius, int *neig_pt_num,
-    float robust_white_noise = 3.0f, int type = GENERAL_LBP);
-
-  CLocalBinaryPattern();
-  virtual ~CLocalBinaryPattern();
-
-  float	m_fRobustWhiteNoise;		/* the robust noise value for computing the LBP operator in each channel */
-
-private:
-  void SetShiftedMeshGrid(CvSize img_size, float offset_x, float offset_y, CvMat *grid_map_x, CvMat *grid_map_y);
-
-  float*	m_pRadiuses;			/* the circle radiuses for the LBP operator */
-  //int	m_nLBPType;			/* the type of computing LBP operator */
-  int*	m_pNeigPointsNums;		/* the numbers of neighboring pixels on multi-level circles */
-  int	m_nImgsNum;			/* the number of multi-channel image */
-  int	m_nLBPLevelNum;			/* the number of multi-level LBP operator */
-  CvSize	m_cvImgSize;			/* the image size (width, height) */
-
-  CvPoint* m_pXYShifts;
-  CvPoint	m_nMaxShift;
-
-  IplImage* m_pShiftedImg;
-};
+  namespace algorithms
+  {
+    namespace multilayer
+    {
+      /************************************************************************/
+      /* two types of computing the LBP operators but currently GENERAL_LBP   */
+      /* has been implemented.                                                */
+      /************************************************************************/
+      const int	GENERAL_LBP = 0;
+      const int SYMMETRIC_LBP = 1;
+
+      class CLocalBinaryPattern
+      {
+      public:
+        void CalImageDifferenceMap(IplImage *cent_img, IplImage *neig_img, float *pattern, CvRect *roi = NULL);
+        void CalNeigPixelOffset(float radius, int tot_neig_pts_num, int neig_pt_idx, int &offset_x, int &offset_y);
+        void CalShiftedImage(IplImage *src, int offset_x, int offset_y, IplImage *dst, CvRect *roi = NULL);
+        void FreeMemories();
+        void ComputeLBP(PixelLBPStruct *PLBP, CvRect *roi = NULL);
+        void SetNewImages(IplImage **new_imgs);
+
+        IplImage** m_ppOrgImgs;			/* the original images used for computing the LBP operators */
+
+        void Initialization(IplImage **first_imgs, int imgs_num,
+          int level_num, float *radius, int *neig_pt_num,
+          float robust_white_noise = 3.0f, int type = GENERAL_LBP);
+
+        CLocalBinaryPattern();
+        virtual ~CLocalBinaryPattern();
+
+        float	m_fRobustWhiteNoise;		/* the robust noise value for computing the LBP operator in each channel */
+
+      private:
+        void SetShiftedMeshGrid(CvSize img_size, float offset_x, float offset_y, CvMat *grid_map_x, CvMat *grid_map_y);
+
+        float*	m_pRadiuses;			/* the circle radiuses for the LBP operator */
+        //int	m_nLBPType;			/* the type of computing LBP operator */
+        int*	m_pNeigPointsNums;		/* the numbers of neighboring pixels on multi-level circles */
+        int	m_nImgsNum;			/* the number of multi-channel image */
+        int	m_nLBPLevelNum;			/* the number of multi-level LBP operator */
+        CvSize	m_cvImgSize;			/* the image size (width, height) */
+
+        CvPoint* m_pXYShifts;
+        CvPoint	m_nMaxShift;
+
+        IplImage* m_pShiftedImg;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/MultiLayer/OpenCvDataConversion.h b/src/algorithms/MultiLayer/OpenCvDataConversion.h
index 5280b8ad93955f49a3885f1a87be93b6760e194e..4da11a5597f01cb9292ce828640d05871db4d2ef 100644
--- a/src/algorithms/MultiLayer/OpenCvDataConversion.h
+++ b/src/algorithms/MultiLayer/OpenCvDataConversion.h
@@ -4,172 +4,181 @@
 // opencv legacy includes
 #include "OpenCvLegacyIncludes.h"
 
-template <class TI, class TM>		/* class TI - the type of image data, class TM - the type of matrix data */
-class COpencvDataConversion
+namespace bgslibrary
 {
-public:
-
-  /* get the image data */
-  TI * GetImageData(IplImage *img)
-  {
-    if (!img->roi) {	/* no ROI used, i.e. the whole image */
-      int y; //, x;
-      TI* img_data = new TI[img->width*img->height*img->nChannels];
-      TI* temp = img_data;
-      TI* x_data;
-
-      for (y = 0; y < img->height; y++) {
-        x_data = (TI*)(img->imageData + img->widthStep*y);
-        int row_length = img->width*img->nChannels;
-        memcpy(temp, x_data, sizeof(TI)*row_length);
-        temp += row_length;
-        /*
-        for ( x = 0 ; x < img->width*img->nChannels ; x++ )
-        *temp++ = *x_data++;
-        */
-      }
-
-      return img_data;
-    }
-    else {	/* get image data only in ROI */
-      int y;//, x;
-      TI* img_data = new TI[img->roi->width*img->roi->height*img->nChannels];
-      TI* temp = img_data;
-      TI* x_data;
-      for (y = img->roi->yOffset; y < img->roi->yOffset + img->roi->height; y++) {
-        x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels);
-        int row_length = img->roi->width*img->nChannels;
-        memcpy(temp, x_data, sizeof(TI)*row_length);
-        temp += row_length;
-        /*
-        for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ )
-        *temp++ = *x_data++;
-        */
-      }
-      return img_data;
-    }
-  };
-
-  /* set the image data */
-  void SetImageData(IplImage *img, TI *img_data)
-  {
-    if (!img->roi) {	/* no ROI used, i.e. the whole image */
-      int y;//, x;
-      TI* temp = img_data;
-      TI* x_data;
-      for (y = 0; y < img->height; y++) {
-        x_data = (TI*)(img->imageData + img->widthStep*y);
-        int row_length = img->width*img->nChannels;
-        memcpy(x_data, temp, sizeof(TI)*row_length);
-        temp += row_length;
-        /*
-        for ( x = 0 ; x < img->width*img->nChannels ; x++ )
-        *x_data++ = *temp++;
-        */
-      }
-    }
-    else {	/* set image data only in ROI */
-      int y;//, x;
-      TI* temp = img_data;
-      TI* x_data;
-      for (y = img->roi->yOffset; y < img->roi->yOffset + img->roi->height; y++) {
-        x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels);
-        int row_length = img->roi->width*img->nChannels;
-        memcpy(x_data, temp, sizeof(TI)*row_length);
-        temp += row_length;
-        /*
-        for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ )
-        *x_data++ = *temp++;
-        */
-      }
-    }
-  }
-
-  /* get the matrix data */
-  TM * GetMatData(CvMat *mat)
-  {
-    TM* mat_data = new TM[mat->width*mat->height];
-    memcpy(mat_data, mat->data.ptr, sizeof(TM)*mat->width*mat->height);
-    return mat_data;
-
-    /*
-    int y, x;
-    TM* mat_data = new TM[mat->width*mat->height];
-    TM* temp = mat_data;
-    TM* x_data;
-    for ( y = 0 ; y < mat->height ; y++ ) {
-    x_data = (TM*)(mat->data.ptr + mat->step*y);
-    for ( x = 0 ; x < mat->width ; x++ )
-    *temp++ = *x_data++;
-    }
-    return mat_data;
-    */
-  };
-
-  /* set the matrix data */
-  void SetMatData(CvMat *mat, TM *mat_data)
+  namespace algorithms
   {
-    memcpy(mat->data.ptr, mat_data, sizeof(TM)*mat->width*mat->height);
-
-    /*
-    int y, x;
-    TM* temp = mat_data;
-    TM* x_data;
-    for ( y = 0 ; y < mat->height ; y++ ) {
-    x_data = (TM*)(mat->data.ptr + mat->step*y);
-    for ( x = 0 ; x < mat->width ; x++ )
-    *x_data++ = *temp++;
+    namespace multilayer
+    {
+      template <class TI, class TM>		/* class TI - the type of image data, class TM - the type of matrix data */
+      class COpencvDataConversion
+      {
+      public:
+
+        /* get the image data */
+        TI * GetImageData(IplImage *img)
+        {
+          if (!img->roi) {	/* no ROI used, i.e. the whole image */
+            int y; //, x;
+            TI* img_data = new TI[img->width*img->height*img->nChannels];
+            TI* temp = img_data;
+            TI* x_data;
+
+            for (y = 0; y < img->height; y++) {
+              x_data = (TI*)(img->imageData + img->widthStep*y);
+              int row_length = img->width*img->nChannels;
+              memcpy(temp, x_data, sizeof(TI)*row_length);
+              temp += row_length;
+              /*
+              for ( x = 0 ; x < img->width*img->nChannels ; x++ )
+              *temp++ = *x_data++;
+              */
+            }
+
+            return img_data;
+          }
+          else {	/* get image data only in ROI */
+            int y;//, x;
+            TI* img_data = new TI[img->roi->width*img->roi->height*img->nChannels];
+            TI* temp = img_data;
+            TI* x_data;
+            for (y = img->roi->yOffset; y < img->roi->yOffset + img->roi->height; y++) {
+              x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels);
+              int row_length = img->roi->width*img->nChannels;
+              memcpy(temp, x_data, sizeof(TI)*row_length);
+              temp += row_length;
+              /*
+              for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ )
+              *temp++ = *x_data++;
+              */
+            }
+            return img_data;
+          }
+        };
+
+        /* set the image data */
+        void SetImageData(IplImage *img, TI *img_data)
+        {
+          if (!img->roi) {	/* no ROI used, i.e. the whole image */
+            int y;//, x;
+            TI* temp = img_data;
+            TI* x_data;
+            for (y = 0; y < img->height; y++) {
+              x_data = (TI*)(img->imageData + img->widthStep*y);
+              int row_length = img->width*img->nChannels;
+              memcpy(x_data, temp, sizeof(TI)*row_length);
+              temp += row_length;
+              /*
+              for ( x = 0 ; x < img->width*img->nChannels ; x++ )
+              *x_data++ = *temp++;
+              */
+            }
+          }
+          else {	/* set image data only in ROI */
+            int y;//, x;
+            TI* temp = img_data;
+            TI* x_data;
+            for (y = img->roi->yOffset; y < img->roi->yOffset + img->roi->height; y++) {
+              x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels);
+              int row_length = img->roi->width*img->nChannels;
+              memcpy(x_data, temp, sizeof(TI)*row_length);
+              temp += row_length;
+              /*
+              for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ )
+              *x_data++ = *temp++;
+              */
+            }
+          }
+        }
+
+        /* get the matrix data */
+        TM * GetMatData(CvMat *mat)
+        {
+          TM* mat_data = new TM[mat->width*mat->height];
+          memcpy(mat_data, mat->data.ptr, sizeof(TM)*mat->width*mat->height);
+          return mat_data;
+
+          /*
+          int y, x;
+          TM* mat_data = new TM[mat->width*mat->height];
+          TM* temp = mat_data;
+          TM* x_data;
+          for ( y = 0 ; y < mat->height ; y++ ) {
+          x_data = (TM*)(mat->data.ptr + mat->step*y);
+          for ( x = 0 ; x < mat->width ; x++ )
+          *temp++ = *x_data++;
+          }
+          return mat_data;
+          */
+        };
+
+        /* set the matrix data */
+        void SetMatData(CvMat *mat, TM *mat_data)
+        {
+          memcpy(mat->data.ptr, mat_data, sizeof(TM)*mat->width*mat->height);
+
+          /*
+          int y, x;
+          TM* temp = mat_data;
+          TM* x_data;
+          for ( y = 0 ; y < mat->height ; y++ ) {
+          x_data = (TM*)(mat->data.ptr + mat->step*y);
+          for ( x = 0 ; x < mat->width ; x++ )
+          *x_data++ = *temp++;
+          }
+          */
+        }
+
+        /* convert the image data to the matrix data */
+        void ConvertData(IplImage *img_src, CvMat *mat_dst)
+        {
+          if (img_src->nChannels > 1) {
+            printf("Must be one-channel image for ConvertImageData!\n");
+            exit(1);
+          }
+
+          TI* _img_data = GetImageData(img_src);
+          TM* _mat_data = new TM[img_src->width*img_src->height];
+
+          TI* img_data = _img_data;
+          TM* mat_data = _mat_data;
+          int i;
+          for (i = 0; i < img_src->width*img_src->height; i++)
+            *mat_data++ = (TM)(*img_data++);
+
+          SetMatData(mat_dst, _mat_data);
+
+          delete[] _img_data;
+          delete[] _mat_data;
+        }
+
+        /* convert the matrix data to the image data */
+        void ConvertData(CvMat *mat_src, IplImage *img_dst)
+        {
+          if (img_dst->nChannels > 1) {
+            printf("Must be one-channel image for ConvertImageData!\n");
+            exit(1);
+          }
+
+          TM* _mat_data = GetMatData(mat_src);
+          TI* _img_data = new TI[mat_src->width*mat_src->height];
+
+          TM* mat_data = _mat_data;
+          TI* img_data = _img_data;
+
+          int i;
+          for (i = 0; i < mat_src->width*mat_src->height; i++)
+            *img_data++ = (TI)(*mat_data++);
+
+          SetImageData(img_dst, _img_data);
+
+          delete[] _img_data;
+          delete[] _mat_data;
+        }
+
+        COpencvDataConversion() {};
+        virtual ~COpencvDataConversion() {};
+      };
     }
-    */
   }
-
-  /* convert the image data to the matrix data */
-  void ConvertData(IplImage *img_src, CvMat *mat_dst)
-  {
-    if (img_src->nChannels > 1) {
-      printf("Must be one-channel image for ConvertImageData!\n");
-      exit(1);
-    }
-
-    TI* _img_data = GetImageData(img_src);
-    TM* _mat_data = new TM[img_src->width*img_src->height];
-
-    TI* img_data = _img_data;
-    TM* mat_data = _mat_data;
-    int i;
-    for (i = 0; i < img_src->width*img_src->height; i++)
-      *mat_data++ = (TM)(*img_data++);
-
-    SetMatData(mat_dst, _mat_data);
-
-    delete[] _img_data;
-    delete[] _mat_data;
-  }
-
-  /* convert the matrix data to the image data */
-  void ConvertData(CvMat *mat_src, IplImage *img_dst)
-  {
-    if (img_dst->nChannels > 1) {
-      printf("Must be one-channel image for ConvertImageData!\n");
-      exit(1);
-    }
-
-    TM* _mat_data = GetMatData(mat_src);
-    TI* _img_data = new TI[mat_src->width*mat_src->height];
-
-    TM* mat_data = _mat_data;
-    TI* img_data = _img_data;
-
-    int i;
-    for (i = 0; i < mat_src->width*mat_src->height; i++)
-      *img_data++ = (TI)(*mat_data++);
-
-    SetImageData(img_dst, _img_data);
-
-    delete[] _img_data;
-    delete[] _mat_data;
-  }
-
-  COpencvDataConversion() {};
-  virtual ~COpencvDataConversion() {};
-};
+}
diff --git a/src/algorithms/MultiLayer/blob.cpp b/src/algorithms/MultiLayer/blob.cpp
index 62e879ac12060f685c1a700e2562c2695d5e6a9f..e44f98d126905ff06b6a6cb08e7b530f3862970d 100644
--- a/src/algorithms/MultiLayer/blob.cpp
+++ b/src/algorithms/MultiLayer/blob.cpp
@@ -1,1089 +1,1094 @@
 #include <limits.h>
 #include "blob.h"
 
-namespace Blob
+namespace bgslibrary
 {
-  /**
-    - FUNCIÓ: CBlob
-    - FUNCIONALITAT: Constructor estàndard
-    - PARÀMETRES:
-    - RESULTAT:
-    - inicialització de totes les variables internes i de l'storage i la sequencia
-    per a les cantonades del blob
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlob
-      - FUNCTIONALITY: Standard constructor
-      - PARAMETERS:
-      - RESULT:
-      - memory allocation for the blob edges and initialization of member variables
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlob::CBlob()
+  namespace algorithms
   {
-    etiqueta = -1;		// Flag indicates null region
-    exterior = 0;
-    area = 0.0f;
-    perimeter = 0.0f;
-    parent = -1;
-    minx = LONG_MAX;
-    maxx = 0;
-    miny = LONG_MAX;
-    maxy = 0;
-    sumx = 0;
-    sumy = 0;
-    sumxx = 0;
-    sumyy = 0;
-    sumxy = 0;
-    mean = 0;
-    stddev = 0;
-    externPerimeter = 0;
-
-    m_storage = cvCreateMemStorage(0);
-    edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2,
-      sizeof(CvContour),
-      sizeof(CvPoint), m_storage);
-  }
-
-  /**
-    - FUNCIÓ: CBlob
-    - FUNCIONALITAT: Constructor de còpia
-    - PARÀMETRES:
-    - RESULTAT:
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlob
-      - FUNCTIONALITY: Copy constructor
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlob::CBlob(const CBlob &src)
-  {
-    // copiem les propietats del blob origen a l'actual
-    etiqueta = src.etiqueta;
-    exterior = src.exterior;
-    area = src.Area();
-    perimeter = src.Perimeter();
-    parent = src.parent;
-    minx = src.minx;
-    maxx = src.maxx;
-    miny = src.miny;
-    maxy = src.maxy;
-    sumx = src.sumx;
-    sumy = src.sumy;
-    sumxx = src.sumxx;
-    sumyy = src.sumyy;
-    sumxy = src.sumxy;
-    mean = src.mean;
-    stddev = src.stddev;
-    externPerimeter = src.externPerimeter;
-
-    // copiem els edges del blob origen a l'actual
-    CvSeqReader reader;
-    CvSeqWriter writer;
-    CvPoint edgeactual;
-
-    // creem una sequencia buida per als edges
-    m_storage = cvCreateMemStorage(0);
-    edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2,
-      sizeof(CvContour),
-      sizeof(CvPoint), m_storage);
-
-    cvStartReadSeq(src.Edges(), &reader);
-    cvStartAppendToSeq(edges, &writer);
-
-    for (int i = 0; i < src.Edges()->total; i++)
-    {
-      CV_READ_SEQ_ELEM(edgeactual, reader);
-      CV_WRITE_SEQ_ELEM(edgeactual, writer);
-    }
-
-    cvEndWriteSeq(&writer);
-  }
-  CBlob::CBlob(const CBlob *src)
-  {
-    // copiem les propietats del blob origen a l'actual
-    etiqueta = src->etiqueta;
-    exterior = src->exterior;
-    area = src->Area();
-    perimeter = src->Perimeter();
-    parent = src->parent;
-    minx = src->minx;
-    maxx = src->maxx;
-    miny = src->miny;
-    maxy = src->maxy;
-    sumx = src->sumx;
-    sumy = src->sumy;
-    sumxx = src->sumxx;
-    sumyy = src->sumyy;
-    sumxy = src->sumxy;
-    mean = src->mean;
-    stddev = src->stddev;
-    externPerimeter = src->externPerimeter;
-
-    // copiem els edges del blob origen a l'actual
-    CvSeqReader reader;
-    CvSeqWriter writer;
-    CvPoint edgeactual;
-
-    // creem una sequencia buida per als edges
-    m_storage = cvCreateMemStorage(0);
-    edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2,
-      sizeof(CvContour),
-      sizeof(CvPoint), m_storage);
-
-    cvStartReadSeq(src->Edges(), &reader);
-    cvStartAppendToSeq(edges, &writer);
-
-    for (int i = 0; i < src->Edges()->total; i++)
-    {
-      CV_READ_SEQ_ELEM(edgeactual, reader);
-      CV_WRITE_SEQ_ELEM(edgeactual, writer);
-    }
-
-    cvEndWriteSeq(&writer);
-  }
-
-  /**
-    - FUNCIÓ: ~CBlob
-    - FUNCIONALITAT: Destructor estàndard
-    - PARÀMETRES:
-    - RESULTAT:
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlob
-      - FUNCTIONALITY: Standard destructor
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlob::~CBlob()
-  {
-    // Eliminar vèrtexs del blob
-    cvClearSeq(edges);
-    // i la zona de memòria on són
-    cvReleaseMemStorage(&m_storage);
-  }
-
-  /**
-    - FUNCIÓ: operator=
-    - FUNCIONALITAT: Operador d'assignació
-    - PARÀMETRES:
-    - src: blob a assignar a l'actual
-    - RESULTAT:
-    - Substitueix el blob actual per el src
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: Assigment operator
-      - FUNCTIONALITY: Assigns a blob to the current
-      - PARAMETERS:
-      - src: blob to assign
-      - RESULT:
-      - the current blob is replaced by the src blob
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CBlob& CBlob::operator=(const CBlob &src)
-  {
-    // si ja són el mateix, no cal fer res
-    if (this != &src)
-    {
-      // Eliminar vèrtexs del blob
-      cvClearSeq(edges);
-      // i la zona de memòria on són
-      cvReleaseMemStorage(&m_storage);
-
-      // creem una sequencia buida per als edges
-      m_storage = cvCreateMemStorage(0);
-      edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2,
-        sizeof(CvContour),
-        sizeof(CvPoint), m_storage);
-
-      // copiem les propietats del blob origen a l'actual
-      etiqueta = src.etiqueta;
-      exterior = src.exterior;
-      area = src.Area();
-      perimeter = src.Perimeter();
-      parent = src.parent;
-      minx = src.minx;
-      maxx = src.maxx;
-      miny = src.miny;
-      maxy = src.maxy;
-      sumx = src.sumx;
-      sumy = src.sumy;
-      sumxx = src.sumxx;
-      sumyy = src.sumyy;
-      sumxy = src.sumxy;
-      mean = src.mean;
-      stddev = src.stddev;
-      externPerimeter = src.externPerimeter;
-
-      // copiem els edges del blob origen a l'actual
-      CvSeqReader reader;
-      CvSeqWriter writer;
-      CvPoint edgeactual;
-
-      cvStartReadSeq(src.Edges(), &reader);
-      cvStartAppendToSeq(edges, &writer);
-
-      for (int i = 0; i < src.Edges()->total; i++)
-      {
-        CV_READ_SEQ_ELEM(edgeactual, reader);
-        CV_WRITE_SEQ_ELEM(edgeactual, writer);
-      }
-
-      cvEndWriteSeq(&writer);
-    }
-    return *this;
-  }
-
-  /**
-    - FUNCIÓ: FillBlob
-    - FUNCIONALITAT: Pinta l'interior d'un blob amb el color especificat
-    - PARÀMETRES:
-    - imatge: imatge on es vol pintar el el blob
-    - color: color amb que es vol pintar el blob
-    - RESULTAT:
-    - retorna la imatge d'entrada amb el blob pintat
-    - RESTRICCIONS:
-    - AUTOR:
-    - Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: FillBlob
-      - FUNCTIONALITY:
-      - Fills the blob with a specified colour
-      - PARAMETERS:
-      - imatge: where to paint
-      - color: colour to paint the blob
-      - RESULT:
-      - modifies input image and returns the seed point used to fill the blob
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  void CBlob::FillBlob(IplImage *imatge, CvScalar color, int offsetX /*=0*/, int offsetY /*=0*/) const
-  {
-
-    //verifiquem que existeixi el blob i que tingui cantonades
-    if (edges == NULL || edges->total == 0) return;
-
-    CvPoint edgeactual, pt1, pt2;
-    CvSeqReader reader;
-    vectorPunts vectorEdges = vectorPunts(edges->total);
-    vectorPunts::iterator itEdges, itEdgesSeguent;
-    bool dinsBlob;
-    int yActual;
-
-    // passem els punts del blob a un vector de punts de les STL
-    cvStartReadSeq(edges, &reader);
-    itEdges = vectorEdges.begin();
-    while (itEdges != vectorEdges.end())
-    {
-      CV_READ_SEQ_ELEM(edgeactual, reader);
-      *itEdges = edgeactual;
-      ++itEdges;
-    }
-    // ordenem el vector per les Y's i les X's d'esquerra a dreta
-    std::sort(vectorEdges.begin(), vectorEdges.end(), comparaCvPoint());
-
-    // recorrem el vector ordenat i fem linies entre punts consecutius
-    itEdges = vectorEdges.begin();
-    itEdgesSeguent = vectorEdges.begin() + 1;
-    dinsBlob = true;
-    while (itEdges != (vectorEdges.end() - 1))
+    namespace multilayer
     {
-      yActual = (*itEdges).y;
-
-      if (((*itEdges).x != (*itEdgesSeguent).x) &&
-        ((*itEdgesSeguent).y == yActual)
-        )
+      namespace blob
       {
-        if (dinsBlob)
+        /**
+          - FUNCIÓ: CBlob
+          - FUNCIONALITAT: Constructor estàndard
+          - PARÀMETRES:
+          - RESULTAT:
+          - inicialització de totes les variables internes i de l'storage i la sequencia
+          per a les cantonades del blob
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlob
+            - FUNCTIONALITY: Standard constructor
+            - PARAMETERS:
+            - RESULT:
+            - memory allocation for the blob edges and initialization of member variables
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlob::CBlob()
         {
-          pt1 = *itEdges;
-          pt1.x += offsetX;
-          pt1.y += offsetY;
-
-          pt2 = *itEdgesSeguent;
-          pt2.x += offsetX;
-          pt2.y += offsetY;
-
-          cvLine(imatge, pt1, pt2, color);
+          etiqueta = -1;		// Flag indicates null region
+          exterior = 0;
+          area = 0.0f;
+          perimeter = 0.0f;
+          parent = -1;
+          minx = LONG_MAX;
+          maxx = 0;
+          miny = LONG_MAX;
+          maxy = 0;
+          sumx = 0;
+          sumy = 0;
+          sumxx = 0;
+          sumyy = 0;
+          sumxy = 0;
+          mean = 0;
+          stddev = 0;
+          externPerimeter = 0;
+
+          m_storage = cvCreateMemStorage(0);
+          edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2,
+            sizeof(CvContour),
+            sizeof(CvPoint), m_storage);
         }
-        dinsBlob = !dinsBlob;
-      }
-      ++itEdges;
-      ++itEdgesSeguent;
-      if ((*itEdges).y != yActual) dinsBlob = true;
-    }
-    vectorEdges.clear();
-  }
 
-  /**
-    - FUNCIÓ: CopyEdges
-    - FUNCIONALITAT: Afegeix els vèrtexs del blob al blob destination
-    - PARÀMETRES:
-    - destination: blob al que volem afegir els vèrtexs
-    - RESULTAT:
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CopyEdges
-      - FUNCTIONALITY: Adds the blob edges to destination
-      - PARAMETERS:
-      - destination: where to add the edges
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  void CBlob::CopyEdges(CBlob &destination) const
-  {
-    CvSeqReader reader;
-    CvSeqWriter writer;
-    CvPoint edgeactual;
+        /**
+          - FUNCIÓ: CBlob
+          - FUNCIONALITAT: Constructor de còpia
+          - PARÀMETRES:
+          - RESULTAT:
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlob
+            - FUNCTIONALITY: Copy constructor
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlob::CBlob(const CBlob &src)
+        {
+          // copiem les propietats del blob origen a l'actual
+          etiqueta = src.etiqueta;
+          exterior = src.exterior;
+          area = src.Area();
+          perimeter = src.Perimeter();
+          parent = src.parent;
+          minx = src.minx;
+          maxx = src.maxx;
+          miny = src.miny;
+          maxy = src.maxy;
+          sumx = src.sumx;
+          sumy = src.sumy;
+          sumxx = src.sumxx;
+          sumyy = src.sumyy;
+          sumxy = src.sumxy;
+          mean = src.mean;
+          stddev = src.stddev;
+          externPerimeter = src.externPerimeter;
+
+          // copiem els edges del blob origen a l'actual
+          CvSeqReader reader;
+          CvSeqWriter writer;
+          CvPoint edgeactual;
+
+          // creem una sequencia buida per als edges
+          m_storage = cvCreateMemStorage(0);
+          edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2,
+            sizeof(CvContour),
+            sizeof(CvPoint), m_storage);
+
+          cvStartReadSeq(src.Edges(), &reader);
+          cvStartAppendToSeq(edges, &writer);
+
+          for (int i = 0; i < src.Edges()->total; i++)
+          {
+            CV_READ_SEQ_ELEM(edgeactual, reader);
+            CV_WRITE_SEQ_ELEM(edgeactual, writer);
+          }
+
+          cvEndWriteSeq(&writer);
+        }
+        CBlob::CBlob(const CBlob *src)
+        {
+          // copiem les propietats del blob origen a l'actual
+          etiqueta = src->etiqueta;
+          exterior = src->exterior;
+          area = src->Area();
+          perimeter = src->Perimeter();
+          parent = src->parent;
+          minx = src->minx;
+          maxx = src->maxx;
+          miny = src->miny;
+          maxy = src->maxy;
+          sumx = src->sumx;
+          sumy = src->sumy;
+          sumxx = src->sumxx;
+          sumyy = src->sumyy;
+          sumxy = src->sumxy;
+          mean = src->mean;
+          stddev = src->stddev;
+          externPerimeter = src->externPerimeter;
+
+          // copiem els edges del blob origen a l'actual
+          CvSeqReader reader;
+          CvSeqWriter writer;
+          CvPoint edgeactual;
+
+          // creem una sequencia buida per als edges
+          m_storage = cvCreateMemStorage(0);
+          edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2,
+            sizeof(CvContour),
+            sizeof(CvPoint), m_storage);
+
+          cvStartReadSeq(src->Edges(), &reader);
+          cvStartAppendToSeq(edges, &writer);
+
+          for (int i = 0; i < src->Edges()->total; i++)
+          {
+            CV_READ_SEQ_ELEM(edgeactual, reader);
+            CV_WRITE_SEQ_ELEM(edgeactual, writer);
+          }
+
+          cvEndWriteSeq(&writer);
+        }
 
-    cvStartReadSeq(edges, &reader);
-    cvStartAppendToSeq(destination.Edges(), &writer);
+        /**
+          - FUNCIÓ: ~CBlob
+          - FUNCIONALITAT: Destructor estàndard
+          - PARÀMETRES:
+          - RESULTAT:
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlob
+            - FUNCTIONALITY: Standard destructor
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlob::~CBlob()
+        {
+          // Eliminar vèrtexs del blob
+          cvClearSeq(edges);
+          // i la zona de memòria on són
+          cvReleaseMemStorage(&m_storage);
+        }
 
-    for (int i = 0; i < edges->total; i++)
-    {
-      CV_READ_SEQ_ELEM(edgeactual, reader);
-      CV_WRITE_SEQ_ELEM(edgeactual, writer);
-    }
+        /**
+          - FUNCIÓ: operator=
+          - FUNCIONALITAT: Operador d'assignació
+          - PARÀMETRES:
+          - src: blob a assignar a l'actual
+          - RESULTAT:
+          - Substitueix el blob actual per el src
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: Assigment operator
+            - FUNCTIONALITY: Assigns a blob to the current
+            - PARAMETERS:
+            - src: blob to assign
+            - RESULT:
+            - the current blob is replaced by the src blob
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CBlob& CBlob::operator=(const CBlob &src)
+        {
+          // si ja són el mateix, no cal fer res
+          if (this != &src)
+          {
+            // Eliminar vèrtexs del blob
+            cvClearSeq(edges);
+            // i la zona de memòria on són
+            cvReleaseMemStorage(&m_storage);
+
+            // creem una sequencia buida per als edges
+            m_storage = cvCreateMemStorage(0);
+            edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2,
+              sizeof(CvContour),
+              sizeof(CvPoint), m_storage);
+
+            // copiem les propietats del blob origen a l'actual
+            etiqueta = src.etiqueta;
+            exterior = src.exterior;
+            area = src.Area();
+            perimeter = src.Perimeter();
+            parent = src.parent;
+            minx = src.minx;
+            maxx = src.maxx;
+            miny = src.miny;
+            maxy = src.maxy;
+            sumx = src.sumx;
+            sumy = src.sumy;
+            sumxx = src.sumxx;
+            sumyy = src.sumyy;
+            sumxy = src.sumxy;
+            mean = src.mean;
+            stddev = src.stddev;
+            externPerimeter = src.externPerimeter;
+
+            // copiem els edges del blob origen a l'actual
+            CvSeqReader reader;
+            CvSeqWriter writer;
+            CvPoint edgeactual;
+
+            cvStartReadSeq(src.Edges(), &reader);
+            cvStartAppendToSeq(edges, &writer);
+
+            for (int i = 0; i < src.Edges()->total; i++)
+            {
+              CV_READ_SEQ_ELEM(edgeactual, reader);
+              CV_WRITE_SEQ_ELEM(edgeactual, writer);
+            }
+
+            cvEndWriteSeq(&writer);
+          }
+          return *this;
+        }
 
-    cvEndWriteSeq(&writer);
-  }
+        /**
+          - FUNCIÓ: FillBlob
+          - FUNCIONALITAT: Pinta l'interior d'un blob amb el color especificat
+          - PARÀMETRES:
+          - imatge: imatge on es vol pintar el el blob
+          - color: color amb que es vol pintar el blob
+          - RESULTAT:
+          - retorna la imatge d'entrada amb el blob pintat
+          - RESTRICCIONS:
+          - AUTOR:
+          - Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: FillBlob
+            - FUNCTIONALITY:
+            - Fills the blob with a specified colour
+            - PARAMETERS:
+            - imatge: where to paint
+            - color: colour to paint the blob
+            - RESULT:
+            - modifies input image and returns the seed point used to fill the blob
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        void CBlob::FillBlob(IplImage *imatge, CvScalar color, int offsetX /*=0*/, int offsetY /*=0*/) const
+        {
 
-  /**
-    - FUNCIÓ: ClearEdges
-    - FUNCIONALITAT: Elimina els vèrtexs del blob
-    - PARÀMETRES:
-    - RESULTAT:
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: ClearEdges
-      - FUNCTIONALITY: Delete current blob edges
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  void CBlob::ClearEdges()
-  {
-    // Eliminar vèrtexs del blob eliminat
-    cvClearSeq(edges);
-  }
+          //verifiquem que existeixi el blob i que tingui cantonades
+          if (edges == NULL || edges->total == 0) return;
+
+          CvPoint edgeactual, pt1, pt2;
+          CvSeqReader reader;
+          vectorPunts vectorEdges = vectorPunts(edges->total);
+          vectorPunts::iterator itEdges, itEdgesSeguent;
+          bool dinsBlob;
+          int yActual;
+
+          // passem els punts del blob a un vector de punts de les STL
+          cvStartReadSeq(edges, &reader);
+          itEdges = vectorEdges.begin();
+          while (itEdges != vectorEdges.end())
+          {
+            CV_READ_SEQ_ELEM(edgeactual, reader);
+            *itEdges = edgeactual;
+            ++itEdges;
+          }
+          // ordenem el vector per les Y's i les X's d'esquerra a dreta
+          std::sort(vectorEdges.begin(), vectorEdges.end(), comparaCvPoint());
+
+          // recorrem el vector ordenat i fem linies entre punts consecutius
+          itEdges = vectorEdges.begin();
+          itEdgesSeguent = vectorEdges.begin() + 1;
+          dinsBlob = true;
+          while (itEdges != (vectorEdges.end() - 1))
+          {
+            yActual = (*itEdges).y;
+
+            if (((*itEdges).x != (*itEdgesSeguent).x) &&
+              ((*itEdgesSeguent).y == yActual)
+              )
+            {
+              if (dinsBlob)
+              {
+                pt1 = *itEdges;
+                pt1.x += offsetX;
+                pt1.y += offsetY;
+
+                pt2 = *itEdgesSeguent;
+                pt2.x += offsetX;
+                pt2.y += offsetY;
+
+                cvLine(imatge, pt1, pt2, color);
+              }
+              dinsBlob = !dinsBlob;
+            }
+            ++itEdges;
+            ++itEdgesSeguent;
+            if ((*itEdges).y != yActual) dinsBlob = true;
+          }
+          vectorEdges.clear();
+        }
 
-  /**
-    - FUNCIÓ: GetConvexHull
-    - FUNCIONALITAT: Retorna el poligon convex del blob
-    - PARÀMETRES:
-    - dst: sequencia on desarem el resultat (no ha d'estar inicialitzada)
-    - RESULTAT:
-    - true si tot ha anat bé
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: GetConvexHull
-      - FUNCTIONALITY: Calculates the convex hull polygon of the blob
-      - PARAMETERS:
-      - dst: where to store the result
-      - RESULT:
-      - true if no error ocurred
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  bool CBlob::GetConvexHull(CvSeq **dst) const
-  {
-    if (edges != NULL && edges->total > 0)
-    {
-      *dst = cvConvexHull2(edges, 0, CV_CLOCKWISE, 0);
-      return true;
-    }
-    return false;
-  }
+        /**
+          - FUNCIÓ: CopyEdges
+          - FUNCIONALITAT: Afegeix els vèrtexs del blob al blob destination
+          - PARÀMETRES:
+          - destination: blob al que volem afegir els vèrtexs
+          - RESULTAT:
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CopyEdges
+            - FUNCTIONALITY: Adds the blob edges to destination
+            - PARAMETERS:
+            - destination: where to add the edges
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        void CBlob::CopyEdges(CBlob &destination) const
+        {
+          CvSeqReader reader;
+          CvSeqWriter writer;
+          CvPoint edgeactual;
 
-  /**
-    - FUNCIÓ: GetEllipse
-    - FUNCIONALITAT: Retorna l'ellipse que s'ajusta millor a les cantonades del blob
-    - PARÀMETRES:
-    - RESULTAT:
-    - estructura amb l'ellipse
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 25-05-2005.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: GetEllipse
-      - FUNCTIONALITY: Calculates the ellipse that best fits the edges of the blob
-      - PARAMETERS:
-      - RESULT:
-      - CvBox2D struct with the calculated ellipse
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  CvBox2D CBlob::GetEllipse() const
-  {
-    CvBox2D elipse;
-    // necessitem 6 punts per calcular l'elipse
-    if (edges != NULL && edges->total > 6)
-    {
-      elipse = cvFitEllipse2(edges);
-    }
-    else
-    {
-      elipse.center.x = 0.0;
-      elipse.center.y = 0.0;
-      elipse.size.width = 0.0;
-      elipse.size.height = 0.0;
-      elipse.angle = 0.0;
-    }
-    return elipse;
-  }
+          cvStartReadSeq(edges, &reader);
+          cvStartAppendToSeq(destination.Edges(), &writer);
 
+          for (int i = 0; i < edges->total; i++)
+          {
+            CV_READ_SEQ_ELEM(edgeactual, reader);
+            CV_WRITE_SEQ_ELEM(edgeactual, writer);
+          }
 
+          cvEndWriteSeq(&writer);
+        }
 
-  /***************************************************************************
-    Implementació de les classes per al càlcul de característiques sobre el blob
-
-    Implementation of the helper classes to perform operations on blobs
-    **************************************************************************/
-
-    /**
-      - FUNCIÓ: Moment
-      - FUNCIONALITAT: Calcula el moment pq del blob
-      - RESULTAT:
-      - retorna el moment pq especificat o 0 si el moment no està implementat
-      - RESTRICCIONS:
-      - Implementats els moments pq: 00, 01, 10, 20, 02
-      - AUTOR: Ricard Borràs
-      - DATA DE CREACIÓ: 20-07-2004.
-      - MODIFICACIÓ: Data. Autor. Descripció.
-      */
-      /**
-        - FUNCTION: Moment
-        - FUNCTIONALITY: Calculates the pq moment of the blob
-        - PARAMETERS:
-        - RESULT:
-        - returns the pq moment or 0 if the moment it is not implemented
-        - RESTRICTIONS:
-        - Currently, only implemented the 00, 01, 10, 20, 02 pq moments
-        - AUTHOR: Ricard Borràs
-        - CREATION DATE: 20-07-2004.
-        - MODIFICATION: Date. Author. Description.
-        */
-  double CBlobGetMoment::operator()(const CBlob &blob) const
-  {
-    //Moment 00
-    if ((m_p == 0) && (m_q == 0))
-      return blob.Area();
+        /**
+          - FUNCIÓ: ClearEdges
+          - FUNCIONALITAT: Elimina els vèrtexs del blob
+          - PARÀMETRES:
+          - RESULTAT:
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: ClearEdges
+            - FUNCTIONALITY: Delete current blob edges
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        void CBlob::ClearEdges()
+        {
+          // Eliminar vèrtexs del blob eliminat
+          cvClearSeq(edges);
+        }
 
-    //Moment 10
-    if ((m_p == 1) && (m_q == 0))
-      return blob.SumX();
+        /**
+          - FUNCIÓ: GetConvexHull
+          - FUNCIONALITAT: Retorna el poligon convex del blob
+          - PARÀMETRES:
+          - dst: sequencia on desarem el resultat (no ha d'estar inicialitzada)
+          - RESULTAT:
+          - true si tot ha anat bé
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: GetConvexHull
+            - FUNCTIONALITY: Calculates the convex hull polygon of the blob
+            - PARAMETERS:
+            - dst: where to store the result
+            - RESULT:
+            - true if no error ocurred
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        bool CBlob::GetConvexHull(CvSeq **dst) const
+        {
+          if (edges != NULL && edges->total > 0)
+          {
+            *dst = cvConvexHull2(edges, 0, CV_CLOCKWISE, 0);
+            return true;
+          }
+          return false;
+        }
 
-    //Moment 01
-    if ((m_p == 0) && (m_q == 1))
-      return blob.SumY();
+        /**
+          - FUNCIÓ: GetEllipse
+          - FUNCIONALITAT: Retorna l'ellipse que s'ajusta millor a les cantonades del blob
+          - PARÀMETRES:
+          - RESULTAT:
+          - estructura amb l'ellipse
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 25-05-2005.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: GetEllipse
+            - FUNCTIONALITY: Calculates the ellipse that best fits the edges of the blob
+            - PARAMETERS:
+            - RESULT:
+            - CvBox2D struct with the calculated ellipse
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        CvBox2D CBlob::GetEllipse() const
+        {
+          CvBox2D elipse;
+          // necessitem 6 punts per calcular l'elipse
+          if (edges != NULL && edges->total > 6)
+          {
+            elipse = cvFitEllipse2(edges);
+          }
+          else
+          {
+            elipse.center.x = 0.0;
+            elipse.center.y = 0.0;
+            elipse.size.width = 0.0;
+            elipse.size.height = 0.0;
+            elipse.angle = 0.0;
+          }
+          return elipse;
+        }
 
-    //Moment 20
-    if ((m_p == 2) && (m_q == 0))
-      return blob.SumXX();
 
-    //Moment 02
-    if ((m_p == 0) && (m_q == 2))
-      return blob.SumYY();
 
-    return 0;
-  }
+        /***************************************************************************
+          Implementació de les classes per al càlcul de característiques sobre el blob
+
+          Implementation of the helper classes to perform operations on blobs
+          **************************************************************************/
+
+          /**
+            - FUNCIÓ: Moment
+            - FUNCIONALITAT: Calcula el moment pq del blob
+            - RESULTAT:
+            - retorna el moment pq especificat o 0 si el moment no està implementat
+            - RESTRICCIONS:
+            - Implementats els moments pq: 00, 01, 10, 20, 02
+            - AUTOR: Ricard Borràs
+            - DATA DE CREACIÓ: 20-07-2004.
+            - MODIFICACIÓ: Data. Autor. Descripció.
+            */
+            /**
+              - FUNCTION: Moment
+              - FUNCTIONALITY: Calculates the pq moment of the blob
+              - PARAMETERS:
+              - RESULT:
+              - returns the pq moment or 0 if the moment it is not implemented
+              - RESTRICTIONS:
+              - Currently, only implemented the 00, 01, 10, 20, 02 pq moments
+              - AUTHOR: Ricard Borràs
+              - CREATION DATE: 20-07-2004.
+              - MODIFICATION: Date. Author. Description.
+              */
+        double CBlobGetMoment::operator()(const CBlob &blob) const
+        {
+          //Moment 00
+          if ((m_p == 0) && (m_q == 0))
+            return blob.Area();
 
-  /**
-    - FUNCIÓ: HullPerimeter
-    - FUNCIONALITAT: Calcula la longitud del perimetre convex del blob.
-    Fa servir la funció d'OpenCV cvConvexHull2 per a
-    calcular el perimetre convex.
-
-    - PARÀMETRES:
-    - RESULTAT:
-    - retorna la longitud del perímetre convex del blob. Si el blob no té coordenades
-    associades retorna el perímetre normal del blob.
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 20-07-2004.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlobGetHullPerimeter
-      - FUNCTIONALITY: Calculates the convex hull perimeter of the blob
-      - PARAMETERS:
-      - RESULT:
-      - returns the convex hull perimeter of the blob or the perimeter if the
-      blob edges could not be retrieved
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetHullPerimeter::operator()(const CBlob &blob) const
-  {
-    if (blob.Edges() != NULL && blob.Edges()->total > 0)
-    {
-      CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1);
-      return fabs(cvArcLength(hull, CV_WHOLE_SEQ, 1));
-    }
-    return blob.Perimeter();
-  }
+          //Moment 10
+          if ((m_p == 1) && (m_q == 0))
+            return blob.SumX();
 
-  double CBlobGetHullArea::operator()(const CBlob &blob) const
-  {
-    if (blob.Edges() != NULL && blob.Edges()->total > 0)
-    {
-      CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1);
-      return fabs(cvContourArea(hull));
-    }
-    return blob.Perimeter();
-  }
+          //Moment 01
+          if ((m_p == 0) && (m_q == 1))
+            return blob.SumY();
 
-  /**
-    - FUNCIÓ: MinX_at_MinY
-    - FUNCIONALITAT: Calcula el valor MinX a MinY.
-    - PARÀMETRES:
-    - blob: blob del que volem calcular el valor
-    - RESULTAT:
-    - retorna la X minima en la Y minima.
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 20-07-2004.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlobGetMinXatMinY
-      - FUNCTIONALITY: Calculates the minimum X on the minimum Y
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetMinXatMinY::operator()(const CBlob &blob) const
-  {
-    double MinX_at_MinY = LONG_MAX;
+          //Moment 20
+          if ((m_p == 2) && (m_q == 0))
+            return blob.SumXX();
 
-    CvSeqReader reader;
-    CvPoint edgeactual;
+          //Moment 02
+          if ((m_p == 0) && (m_q == 2))
+            return blob.SumYY();
 
-    cvStartReadSeq(blob.Edges(), &reader);
+          return 0;
+        }
 
-    for (int j = 0; j < blob.Edges()->total; j++)
-    {
-      CV_READ_SEQ_ELEM(edgeactual, reader);
-      if ((edgeactual.y == blob.MinY()) && (edgeactual.x < MinX_at_MinY))
-      {
-        MinX_at_MinY = edgeactual.x;
-      }
-    }
+        /**
+          - FUNCIÓ: HullPerimeter
+          - FUNCIONALITAT: Calcula la longitud del perimetre convex del blob.
+          Fa servir la funció d'OpenCV cvConvexHull2 per a
+          calcular el perimetre convex.
+
+          - PARÀMETRES:
+          - RESULTAT:
+          - retorna la longitud del perímetre convex del blob. Si el blob no té coordenades
+          associades retorna el perímetre normal del blob.
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 20-07-2004.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlobGetHullPerimeter
+            - FUNCTIONALITY: Calculates the convex hull perimeter of the blob
+            - PARAMETERS:
+            - RESULT:
+            - returns the convex hull perimeter of the blob or the perimeter if the
+            blob edges could not be retrieved
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetHullPerimeter::operator()(const CBlob &blob) const
+        {
+          if (blob.Edges() != NULL && blob.Edges()->total > 0)
+          {
+            CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1);
+            return fabs(cvArcLength(hull, CV_WHOLE_SEQ, 1));
+          }
+          return blob.Perimeter();
+        }
 
-    return MinX_at_MinY;
-  }
+        double CBlobGetHullArea::operator()(const CBlob &blob) const
+        {
+          if (blob.Edges() != NULL && blob.Edges()->total > 0)
+          {
+            CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1);
+            return fabs(cvContourArea(hull));
+          }
+          return blob.Perimeter();
+        }
 
-  /**
-    - FUNCIÓ: MinY_at_MaxX
-    - FUNCIONALITAT: Calcula el valor MinX a MaxX.
-    - PARÀMETRES:
-    - blob: blob del que volem calcular el valor
-    - RESULTAT:
-    - retorna la Y minima en la X maxima.
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 20-07-2004.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlobGetMinXatMinY
-      - FUNCTIONALITY: Calculates the minimum Y on the maximum X
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetMinYatMaxX::operator()(const CBlob &blob) const
-  {
-    double MinY_at_MaxX = LONG_MAX;
+        /**
+          - FUNCIÓ: MinX_at_MinY
+          - FUNCIONALITAT: Calcula el valor MinX a MinY.
+          - PARÀMETRES:
+          - blob: blob del que volem calcular el valor
+          - RESULTAT:
+          - retorna la X minima en la Y minima.
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 20-07-2004.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlobGetMinXatMinY
+            - FUNCTIONALITY: Calculates the minimum X on the minimum Y
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetMinXatMinY::operator()(const CBlob &blob) const
+        {
+          double MinX_at_MinY = LONG_MAX;
 
-    CvSeqReader reader;
-    CvPoint edgeactual;
+          CvSeqReader reader;
+          CvPoint edgeactual;
 
-    cvStartReadSeq(blob.Edges(), &reader);
+          cvStartReadSeq(blob.Edges(), &reader);
 
-    for (int j = 0; j < blob.Edges()->total; j++)
-    {
-      CV_READ_SEQ_ELEM(edgeactual, reader);
-      if ((edgeactual.x == blob.MaxX()) && (edgeactual.y < MinY_at_MaxX))
-      {
-        MinY_at_MaxX = edgeactual.y;
-      }
-    }
+          for (int j = 0; j < blob.Edges()->total; j++)
+          {
+            CV_READ_SEQ_ELEM(edgeactual, reader);
+            if ((edgeactual.y == blob.MinY()) && (edgeactual.x < MinX_at_MinY))
+            {
+              MinX_at_MinY = edgeactual.x;
+            }
+          }
 
-    return MinY_at_MaxX;
-  }
+          return MinX_at_MinY;
+        }
 
-  /**
-    - FUNCIÓ: MaxX_at_MaxY
-    - FUNCIONALITAT: Calcula el valor MaxX a MaxY.
-    - PARÀMETRES:
-    - blob: blob del que volem calcular el valor
-    - RESULTAT:
-    - retorna la X maxima en la Y maxima.
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 20-07-2004.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlobGetMaxXatMaxY
-      - FUNCTIONALITY: Calculates the maximum X on the maximum Y
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetMaxXatMaxY::operator()(const CBlob &blob) const
-  {
-    double MaxX_at_MaxY = LONG_MIN;
+        /**
+          - FUNCIÓ: MinY_at_MaxX
+          - FUNCIONALITAT: Calcula el valor MinX a MaxX.
+          - PARÀMETRES:
+          - blob: blob del que volem calcular el valor
+          - RESULTAT:
+          - retorna la Y minima en la X maxima.
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 20-07-2004.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlobGetMinXatMinY
+            - FUNCTIONALITY: Calculates the minimum Y on the maximum X
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetMinYatMaxX::operator()(const CBlob &blob) const
+        {
+          double MinY_at_MaxX = LONG_MAX;
 
-    CvSeqReader reader;
-    CvPoint edgeactual;
+          CvSeqReader reader;
+          CvPoint edgeactual;
 
-    cvStartReadSeq(blob.Edges(), &reader);
+          cvStartReadSeq(blob.Edges(), &reader);
 
-    for (int j = 0; j < blob.Edges()->total; j++)
-    {
-      CV_READ_SEQ_ELEM(edgeactual, reader);
-      if ((edgeactual.y == blob.MaxY()) && (edgeactual.x > MaxX_at_MaxY))
-      {
-        MaxX_at_MaxY = edgeactual.x;
-      }
-    }
+          for (int j = 0; j < blob.Edges()->total; j++)
+          {
+            CV_READ_SEQ_ELEM(edgeactual, reader);
+            if ((edgeactual.x == blob.MaxX()) && (edgeactual.y < MinY_at_MaxX))
+            {
+              MinY_at_MaxX = edgeactual.y;
+            }
+          }
 
-    return MaxX_at_MaxY;
-  }
+          return MinY_at_MaxX;
+        }
 
-  /**
-    - FUNCIÓ: MaxY_at_MinX
-    - FUNCIONALITAT: Calcula el valor MaxY a MinX.
-    - PARÀMETRES:
-    - blob: blob del que volem calcular el valor
-    - RESULTAT:
-    - retorna la Y maxima en la X minima.
-    - RESTRICCIONS:
-    - AUTOR: Ricard Borràs
-    - DATA DE CREACIÓ: 20-07-2004.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: CBlobGetMaxYatMinX
-      - FUNCTIONALITY: Calculates the maximum Y on the minimum X
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetMaxYatMinX::operator()(const CBlob &blob) const
-  {
-    double MaxY_at_MinX = LONG_MIN;
+        /**
+          - FUNCIÓ: MaxX_at_MaxY
+          - FUNCIONALITAT: Calcula el valor MaxX a MaxY.
+          - PARÀMETRES:
+          - blob: blob del que volem calcular el valor
+          - RESULTAT:
+          - retorna la X maxima en la Y maxima.
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 20-07-2004.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlobGetMaxXatMaxY
+            - FUNCTIONALITY: Calculates the maximum X on the maximum Y
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetMaxXatMaxY::operator()(const CBlob &blob) const
+        {
+          double MaxX_at_MaxY = LONG_MIN;
 
-    CvSeqReader reader;
-    CvPoint edgeactual;
+          CvSeqReader reader;
+          CvPoint edgeactual;
 
-    cvStartReadSeq(blob.Edges(), &reader);
+          cvStartReadSeq(blob.Edges(), &reader);
 
-    for (int j = 0; j < blob.Edges()->total; j++)
-    {
-      CV_READ_SEQ_ELEM(edgeactual, reader);
-      if ((edgeactual.x == blob.MinY()) && (edgeactual.y > MaxY_at_MinX))
-      {
-        MaxY_at_MinX = edgeactual.y;
-      }
-    }
+          for (int j = 0; j < blob.Edges()->total; j++)
+          {
+            CV_READ_SEQ_ELEM(edgeactual, reader);
+            if ((edgeactual.y == blob.MaxY()) && (edgeactual.x > MaxX_at_MaxY))
+            {
+              MaxX_at_MaxY = edgeactual.x;
+            }
+          }
 
-    return MaxY_at_MinX;
-  }
+          return MaxX_at_MaxY;
+        }
 
-  /**
-    Retorna l'elongació del blob (longitud/amplada)
-    */
-    /**
-      - FUNCTION: CBlobGetElongation
-      - FUNCTIONALITY: Calculates the elongation of the blob ( length/breadth )
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - See below to see how the lenght and the breadth are aproximated
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetElongation::operator()(const CBlob &blob) const
-  {
-    double ampladaC, longitudC, amplada, longitud;
+        /**
+          - FUNCIÓ: MaxY_at_MinX
+          - FUNCIONALITAT: Calcula el valor MaxY a MinX.
+          - PARÀMETRES:
+          - blob: blob del que volem calcular el valor
+          - RESULTAT:
+          - retorna la Y maxima en la X minima.
+          - RESTRICCIONS:
+          - AUTOR: Ricard Borràs
+          - DATA DE CREACIÓ: 20-07-2004.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: CBlobGetMaxYatMinX
+            - FUNCTIONALITY: Calculates the maximum Y on the minimum X
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetMaxYatMinX::operator()(const CBlob &blob) const
+        {
+          double MaxY_at_MinX = LONG_MIN;
 
-    ampladaC = (double)(blob.Perimeter() + sqrt(pow(blob.Perimeter(), 2) - 16 * blob.Area())) / 4;
-    if (ampladaC <= 0.0) return 0;
-    longitudC = (double)blob.Area() / ampladaC;
+          CvSeqReader reader;
+          CvPoint edgeactual;
 
-    longitud = MAX(longitudC, ampladaC);
-    amplada = MIN(longitudC, ampladaC);
+          cvStartReadSeq(blob.Edges(), &reader);
 
-    return (double)longitud / amplada;
-  }
+          for (int j = 0; j < blob.Edges()->total; j++)
+          {
+            CV_READ_SEQ_ELEM(edgeactual, reader);
+            if ((edgeactual.x == blob.MinY()) && (edgeactual.y > MaxY_at_MinX))
+            {
+              MaxY_at_MinX = edgeactual.y;
+            }
+          }
 
-  /**
-    Retorna la compacitat del blob
-    */
-    /**
-      - FUNCTION: CBlobGetCompactness
-      - FUNCTIONALITY: Calculates the compactness of the blob
-      ( maximum for circle shaped blobs, minimum for the rest)
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetCompactness::operator()(const CBlob &blob) const
-  {
-    if (blob.Area() != 0.0)
-      return (double)pow(blob.Perimeter(), 2) / (4 * CV_PI*blob.Area());
-    else
-      return 0.0;
-  }
+          return MaxY_at_MinX;
+        }
 
-  /**
-    Retorna la rugositat del blob
-    */
-    /**
-      - FUNCTION: CBlobGetRoughness
-      - FUNCTIONALITY: Calculates the roughness of the blob
-      ( ratio between perimeter and convex hull perimeter)
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetRoughness::operator()(const CBlob &blob) const
-  {
-    CBlobGetHullPerimeter getHullPerimeter = CBlobGetHullPerimeter();
+        /**
+          Retorna l'elongació del blob (longitud/amplada)
+          */
+          /**
+            - FUNCTION: CBlobGetElongation
+            - FUNCTIONALITY: Calculates the elongation of the blob ( length/breadth )
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - See below to see how the lenght and the breadth are aproximated
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetElongation::operator()(const CBlob &blob) const
+        {
+          double ampladaC, longitudC, amplada, longitud;
 
-    double hullPerimeter = getHullPerimeter(blob);
+          ampladaC = (double)(blob.Perimeter() + sqrt(pow(blob.Perimeter(), 2) - 16 * blob.Area())) / 4;
+          if (ampladaC <= 0.0) return 0;
+          longitudC = (double)blob.Area() / ampladaC;
 
-    if (hullPerimeter != 0.0)
-      return blob.Perimeter() / hullPerimeter;//HullPerimeter();
+          longitud = MAX(longitudC, ampladaC);
+          amplada = MIN(longitudC, ampladaC);
 
-    return 0.0;
-  }
+          return (double)longitud / amplada;
+        }
 
-  /**
-    Retorna la longitud del blob
-    */
-    /**
-      - FUNCTION: CBlobGetLength
-      - FUNCTIONALITY: Calculates the lenght of the blob (the biggest axis of the blob)
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - The lenght is an aproximation to the real lenght
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetLength::operator()(const CBlob &blob) const
-  {
-    double ampladaC, longitudC;
-    double tmp;
+        /**
+          Retorna la compacitat del blob
+          */
+          /**
+            - FUNCTION: CBlobGetCompactness
+            - FUNCTIONALITY: Calculates the compactness of the blob
+            ( maximum for circle shaped blobs, minimum for the rest)
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetCompactness::operator()(const CBlob &blob) const
+        {
+          if (blob.Area() != 0.0)
+            return (double)pow(blob.Perimeter(), 2) / (4 * CV_PI*blob.Area());
+          else
+            return 0.0;
+        }
 
-    tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area();
+        /**
+          Retorna la rugositat del blob
+          */
+          /**
+            - FUNCTION: CBlobGetRoughness
+            - FUNCTIONALITY: Calculates the roughness of the blob
+            ( ratio between perimeter and convex hull perimeter)
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetRoughness::operator()(const CBlob &blob) const
+        {
+          CBlobGetHullPerimeter getHullPerimeter = CBlobGetHullPerimeter();
 
-    if (tmp > 0.0)
-      ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4;
-    // error intrínsec en els càlculs de l'àrea i el perímetre
-    else
-      ampladaC = (double)(blob.Perimeter()) / 4;
+          double hullPerimeter = getHullPerimeter(blob);
 
-    if (ampladaC <= 0.0) return 0;
-    longitudC = (double)blob.Area() / ampladaC;
+          if (hullPerimeter != 0.0)
+            return blob.Perimeter() / hullPerimeter;//HullPerimeter();
 
-    return MAX(longitudC, ampladaC);
-  }
+          return 0.0;
+        }
 
-  /**
-    Retorna l'amplada del blob
-    */
-    /**
-      - FUNCTION: CBlobGetBreadth
-      - FUNCTIONALITY: Calculates the breadth of the blob (the smallest axis of the blob)
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - The breadth is an aproximation to the real breadth
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetBreadth::operator()(const CBlob &blob) const
-  {
-    double ampladaC, longitudC;
-    double tmp;
+        /**
+          Retorna la longitud del blob
+          */
+          /**
+            - FUNCTION: CBlobGetLength
+            - FUNCTIONALITY: Calculates the lenght of the blob (the biggest axis of the blob)
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - The lenght is an aproximation to the real lenght
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetLength::operator()(const CBlob &blob) const
+        {
+          double ampladaC, longitudC;
+          double tmp;
 
-    tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area();
+          tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area();
 
-    if (tmp > 0.0)
-      ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4;
-    // error intrínsec en els càlculs de l'àrea i el perímetre
-    else
-      ampladaC = (double)(blob.Perimeter()) / 4;
+          if (tmp > 0.0)
+            ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4;
+          // error intrínsec en els càlculs de l'àrea i el perímetre
+          else
+            ampladaC = (double)(blob.Perimeter()) / 4;
 
-    if (ampladaC <= 0.0) return 0;
-    longitudC = (double)blob.Area() / ampladaC;
+          if (ampladaC <= 0.0) return 0;
+          longitudC = (double)blob.Area() / ampladaC;
 
-    return MIN(longitudC, ampladaC);
-  }
+          return MAX(longitudC, ampladaC);
+        }
 
-  /**
-    Calcula la distància entre un punt i el centre del blob
-    */
-    /**
-      - FUNCTION: CBlobGetDistanceFromPoint
-      - FUNCTIONALITY: Calculates the euclidean distance between the blob center and
-      the point specified in the constructor
-      - PARAMETERS:
-      - RESULT:
-      - RESTRICTIONS:
-      - AUTHOR: Ricard Borràs
-      - CREATION DATE: 25-05-2005.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetDistanceFromPoint::operator()(const CBlob &blob) const
-  {
-    double xmitjana, ymitjana;
-    CBlobGetXCenter getXCenter;
-    CBlobGetYCenter getYCenter;
+        /**
+          Retorna l'amplada del blob
+          */
+          /**
+            - FUNCTION: CBlobGetBreadth
+            - FUNCTIONALITY: Calculates the breadth of the blob (the smallest axis of the blob)
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - The breadth is an aproximation to the real breadth
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetBreadth::operator()(const CBlob &blob) const
+        {
+          double ampladaC, longitudC;
+          double tmp;
 
-    xmitjana = m_x - getXCenter(blob);
-    ymitjana = m_y - getYCenter(blob);
+          tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area();
 
-    return sqrt((xmitjana*xmitjana) + (ymitjana*ymitjana));
-  }
+          if (tmp > 0.0)
+            ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4;
+          // error intrínsec en els càlculs de l'àrea i el perímetre
+          else
+            ampladaC = (double)(blob.Perimeter()) / 4;
 
-  /**
-    - FUNCIÓ: BlobGetXYInside
-    - FUNCIONALITAT: Calcula si un punt cau dins de la capsa rectangular
-    del blob
-    - RESULTAT:
-    - retorna 1 si hi està; 0 si no
-    - RESTRICCIONS:
-    - AUTOR: Francesc Pinyol Margalef
-    - DATA DE CREACIÓ: 16-01-2006.
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-    /**
-      - FUNCTION: BlobGetXYInside
-      - FUNCTIONALITY: Calculates whether a point is inside the
-      rectangular bounding box of a blob
-      - PARAMETERS:
-      - RESULT:
-      - returns 1 if it is inside; o if not
-      - RESTRICTIONS:
-      - AUTHOR: Francesc Pinyol Margalef
-      - CREATION DATE: 16-01-2006.
-      - MODIFICATION: Date. Author. Description.
-      */
-  double CBlobGetXYInside::operator()(const CBlob &blob) const
-  {
-    if (blob.Edges() == NULL || blob.Edges()->total == 0) return 0.0;
+          if (ampladaC <= 0.0) return 0;
+          longitudC = (double)blob.Area() / ampladaC;
 
-    // passem els punts del blob a un vector de punts de les STL
-    CvSeqReader reader;
-    CBlob::vectorPunts vectorEdges;
-    CBlob::vectorPunts::iterator itEdges, itEdgesSeguent;
-    CvPoint edgeactual;
-    bool dinsBlob;
+          return MIN(longitudC, ampladaC);
+        }
 
-    // agafem tots els punts amb la mateixa y que l'actual
-    cvStartReadSeq(blob.Edges(), &reader);
+        /**
+          Calcula la distància entre un punt i el centre del blob
+          */
+          /**
+            - FUNCTION: CBlobGetDistanceFromPoint
+            - FUNCTIONALITY: Calculates the euclidean distance between the blob center and
+            the point specified in the constructor
+            - PARAMETERS:
+            - RESULT:
+            - RESTRICTIONS:
+            - AUTHOR: Ricard Borràs
+            - CREATION DATE: 25-05-2005.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetDistanceFromPoint::operator()(const CBlob &blob) const
+        {
+          double xmitjana, ymitjana;
+          CBlobGetXCenter getXCenter;
+          CBlobGetYCenter getYCenter;
 
-    for (int i = 0; i < blob.Edges()->total; i++)
-    {
-      CV_READ_SEQ_ELEM(edgeactual, reader);
-      if (edgeactual.y == m_p.y)
-        vectorEdges.push_back(edgeactual);
-    }
+          xmitjana = m_x - getXCenter(blob);
+          ymitjana = m_y - getYCenter(blob);
 
-    if (vectorEdges.empty()) return 0.0;
+          return sqrt((xmitjana*xmitjana) + (ymitjana*ymitjana));
+        }
 
-    // ordenem el vector per les Y's i les X's d'esquerra a dreta
-    std::sort(vectorEdges.begin(), vectorEdges.end(), CBlob::comparaCvPoint());
+        /**
+          - FUNCIÓ: BlobGetXYInside
+          - FUNCIONALITAT: Calcula si un punt cau dins de la capsa rectangular
+          del blob
+          - RESULTAT:
+          - retorna 1 si hi està; 0 si no
+          - RESTRICCIONS:
+          - AUTOR: Francesc Pinyol Margalef
+          - DATA DE CREACIÓ: 16-01-2006.
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+          /**
+            - FUNCTION: BlobGetXYInside
+            - FUNCTIONALITY: Calculates whether a point is inside the
+            rectangular bounding box of a blob
+            - PARAMETERS:
+            - RESULT:
+            - returns 1 if it is inside; o if not
+            - RESTRICTIONS:
+            - AUTHOR: Francesc Pinyol Margalef
+            - CREATION DATE: 16-01-2006.
+            - MODIFICATION: Date. Author. Description.
+            */
+        double CBlobGetXYInside::operator()(const CBlob &blob) const
+        {
+          if (blob.Edges() == NULL || blob.Edges()->total == 0) return 0.0;
+
+          // passem els punts del blob a un vector de punts de les STL
+          CvSeqReader reader;
+          CBlob::vectorPunts vectorEdges;
+          CBlob::vectorPunts::iterator itEdges, itEdgesSeguent;
+          CvPoint edgeactual;
+          bool dinsBlob;
+
+          // agafem tots els punts amb la mateixa y que l'actual
+          cvStartReadSeq(blob.Edges(), &reader);
+
+          for (int i = 0; i < blob.Edges()->total; i++)
+          {
+            CV_READ_SEQ_ELEM(edgeactual, reader);
+            if (edgeactual.y == m_p.y)
+              vectorEdges.push_back(edgeactual);
+          }
+
+          if (vectorEdges.empty()) return 0.0;
+
+          // ordenem el vector per les Y's i les X's d'esquerra a dreta
+          std::sort(vectorEdges.begin(), vectorEdges.end(), CBlob::comparaCvPoint());
+
+          // recorrem el punts del blob de la mateixa fila que el punt d'entrada
+          // i mirem si la X del punt d'entrada està entre dos coordenades "plenes"
+          // del blob
+          itEdges = vectorEdges.begin();
+          itEdgesSeguent = vectorEdges.begin() + 1;
+          dinsBlob = true;
+
+          while (itEdges != (vectorEdges.end() - 1))
+          {
+            if ((*itEdges).x <= m_p.x && (*itEdgesSeguent).x >= m_p.x && dinsBlob)
+            {
+              vectorEdges.clear();
+              return 1.0;
+            }
+
+            ++itEdges;
+            ++itEdgesSeguent;
+            dinsBlob = !dinsBlob;
+          }
+
+          vectorEdges.clear();
+          return 0.0;
+        }
 
-    // recorrem el punts del blob de la mateixa fila que el punt d'entrada
-    // i mirem si la X del punt d'entrada està entre dos coordenades "plenes"
-    // del blob
-    itEdges = vectorEdges.begin();
-    itEdgesSeguent = vectorEdges.begin() + 1;
-    dinsBlob = true;
+      #ifdef BLOB_OBJECT_FACTORY
+        /**
+          - FUNCIÓ: RegistraTotsOperadors
+          - FUNCIONALITAT: Registrar tots els operadors definits a blob.h
+          - PARÀMETRES:
+          - fabricaOperadorsBlob: fàbrica on es registraran els operadors
+          - RESULTAT:
+          - Modifica l'objecte fabricaOperadorsBlob
+          - RESTRICCIONS:
+          - Només es registraran els operadors de blob.h. Si se'n volen afegir, cal afegir-los amb
+          el mètode Register de la fàbrica.
+          - AUTOR: rborras
+          - DATA DE CREACIÓ: 2006/05/18
+          - MODIFICACIÓ: Data. Autor. Descripció.
+          */
+        void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob)
+        {
+          // blob shape
+          fabricaOperadorsBlob.Register(CBlobGetArea().GetNom(), Type2Type<CBlobGetArea>());
+          fabricaOperadorsBlob.Register(CBlobGetBreadth().GetNom(), Type2Type<CBlobGetBreadth>());
+          fabricaOperadorsBlob.Register(CBlobGetCompactness().GetNom(), Type2Type<CBlobGetCompactness>());
+          fabricaOperadorsBlob.Register(CBlobGetElongation().GetNom(), Type2Type<CBlobGetElongation>());
+          fabricaOperadorsBlob.Register(CBlobGetExterior().GetNom(), Type2Type<CBlobGetExterior>());
+          fabricaOperadorsBlob.Register(CBlobGetLength().GetNom(), Type2Type<CBlobGetLength>());
+          fabricaOperadorsBlob.Register(CBlobGetPerimeter().GetNom(), Type2Type<CBlobGetPerimeter>());
+          fabricaOperadorsBlob.Register(CBlobGetRoughness().GetNom(), Type2Type<CBlobGetRoughness>());
+
+          // extern pixels
+          fabricaOperadorsBlob.Register(CBlobGetExternPerimeterRatio().GetNom(), Type2Type<CBlobGetExternPerimeterRatio>());
+          fabricaOperadorsBlob.Register(CBlobGetExternHullPerimeterRatio().GetNom(), Type2Type<CBlobGetExternHullPerimeterRatio>());
+          fabricaOperadorsBlob.Register(CBlobGetExternPerimeter().GetNom(), Type2Type<CBlobGetExternPerimeter>());
+
+
+          // hull
+          fabricaOperadorsBlob.Register(CBlobGetHullPerimeter().GetNom(), Type2Type<CBlobGetHullPerimeter>());
+          fabricaOperadorsBlob.Register(CBlobGetHullArea().GetNom(), Type2Type<CBlobGetHullArea>());
+
+
+          // elipse info
+          fabricaOperadorsBlob.Register(CBlobGetMajorAxisLength().GetNom(), Type2Type<CBlobGetMajorAxisLength>());
+          fabricaOperadorsBlob.Register(CBlobGetMinorAxisLength().GetNom(), Type2Type<CBlobGetMinorAxisLength>());
+          fabricaOperadorsBlob.Register(CBlobGetAxisRatio().GetNom(), Type2Type<CBlobGetAxisRatio>());
+          fabricaOperadorsBlob.Register(CBlobGetOrientation().GetNom(), Type2Type<CBlobGetOrientation>());
+          fabricaOperadorsBlob.Register(CBlobGetOrientationCos().GetNom(), Type2Type<CBlobGetOrientationCos>());
+          fabricaOperadorsBlob.Register(CBlobGetAreaElipseRatio().GetNom(), Type2Type<CBlobGetAreaElipseRatio>());
+
+          // min an max
+          fabricaOperadorsBlob.Register(CBlobGetMaxX().GetNom(), Type2Type<CBlobGetMaxX>());
+          fabricaOperadorsBlob.Register(CBlobGetMaxY().GetNom(), Type2Type<CBlobGetMaxY>());
+          fabricaOperadorsBlob.Register(CBlobGetMinX().GetNom(), Type2Type<CBlobGetMinX>());
+          fabricaOperadorsBlob.Register(CBlobGetMinY().GetNom(), Type2Type<CBlobGetMinY>());
+
+          fabricaOperadorsBlob.Register(CBlobGetMaxXatMaxY().GetNom(), Type2Type<CBlobGetMaxXatMaxY>());
+          fabricaOperadorsBlob.Register(CBlobGetMaxYatMinX().GetNom(), Type2Type<CBlobGetMaxYatMinX>());
+          fabricaOperadorsBlob.Register(CBlobGetMinXatMinY().GetNom(), Type2Type<CBlobGetMinXatMinY>());
+          fabricaOperadorsBlob.Register(CBlobGetMinYatMaxX().GetNom(), Type2Type<CBlobGetMinYatMaxX>());
+
+          // grey level stats
+          fabricaOperadorsBlob.Register(CBlobGetMean().GetNom(), Type2Type<CBlobGetMean>());
+          fabricaOperadorsBlob.Register(CBlobGetStdDev().GetNom(), Type2Type<CBlobGetStdDev>());
+
+          // coordinate info
+          fabricaOperadorsBlob.Register(CBlobGetXYInside().GetNom(), Type2Type<CBlobGetXYInside>());
+          fabricaOperadorsBlob.Register(CBlobGetDiffY().GetNom(), Type2Type<CBlobGetDiffY>());
+          fabricaOperadorsBlob.Register(CBlobGetDiffX().GetNom(), Type2Type<CBlobGetDiffX>());
+          fabricaOperadorsBlob.Register(CBlobGetXCenter().GetNom(), Type2Type<CBlobGetXCenter>());
+          fabricaOperadorsBlob.Register(CBlobGetYCenter().GetNom(), Type2Type<CBlobGetYCenter>());
+          fabricaOperadorsBlob.Register(CBlobGetDistanceFromPoint().GetNom(), Type2Type<CBlobGetDistanceFromPoint>());
+
+          // moments
+          fabricaOperadorsBlob.Register(CBlobGetMoment().GetNom(), Type2Type<CBlobGetMoment>());
 
-    while (itEdges != (vectorEdges.end() - 1))
-    {
-      if ((*itEdges).x <= m_p.x && (*itEdgesSeguent).x >= m_p.x && dinsBlob)
-      {
-        vectorEdges.clear();
-        return 1.0;
+        }
+      #endif
       }
-
-      ++itEdges;
-      ++itEdgesSeguent;
-      dinsBlob = !dinsBlob;
     }
-
-    vectorEdges.clear();
-    return 0.0;
-  }
-
-#ifdef BLOB_OBJECT_FACTORY
-
-  /**
-    - FUNCIÓ: RegistraTotsOperadors
-    - FUNCIONALITAT: Registrar tots els operadors definits a blob.h
-    - PARÀMETRES:
-    - fabricaOperadorsBlob: fàbrica on es registraran els operadors
-    - RESULTAT:
-    - Modifica l'objecte fabricaOperadorsBlob
-    - RESTRICCIONS:
-    - Només es registraran els operadors de blob.h. Si se'n volen afegir, cal afegir-los amb
-    el mètode Register de la fàbrica.
-    - AUTOR: rborras
-    - DATA DE CREACIÓ: 2006/05/18
-    - MODIFICACIÓ: Data. Autor. Descripció.
-    */
-  void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob)
-  {
-    // blob shape
-    fabricaOperadorsBlob.Register(CBlobGetArea().GetNom(), Type2Type<CBlobGetArea>());
-    fabricaOperadorsBlob.Register(CBlobGetBreadth().GetNom(), Type2Type<CBlobGetBreadth>());
-    fabricaOperadorsBlob.Register(CBlobGetCompactness().GetNom(), Type2Type<CBlobGetCompactness>());
-    fabricaOperadorsBlob.Register(CBlobGetElongation().GetNom(), Type2Type<CBlobGetElongation>());
-    fabricaOperadorsBlob.Register(CBlobGetExterior().GetNom(), Type2Type<CBlobGetExterior>());
-    fabricaOperadorsBlob.Register(CBlobGetLength().GetNom(), Type2Type<CBlobGetLength>());
-    fabricaOperadorsBlob.Register(CBlobGetPerimeter().GetNom(), Type2Type<CBlobGetPerimeter>());
-    fabricaOperadorsBlob.Register(CBlobGetRoughness().GetNom(), Type2Type<CBlobGetRoughness>());
-
-    // extern pixels
-    fabricaOperadorsBlob.Register(CBlobGetExternPerimeterRatio().GetNom(), Type2Type<CBlobGetExternPerimeterRatio>());
-    fabricaOperadorsBlob.Register(CBlobGetExternHullPerimeterRatio().GetNom(), Type2Type<CBlobGetExternHullPerimeterRatio>());
-    fabricaOperadorsBlob.Register(CBlobGetExternPerimeter().GetNom(), Type2Type<CBlobGetExternPerimeter>());
-
-
-    // hull
-    fabricaOperadorsBlob.Register(CBlobGetHullPerimeter().GetNom(), Type2Type<CBlobGetHullPerimeter>());
-    fabricaOperadorsBlob.Register(CBlobGetHullArea().GetNom(), Type2Type<CBlobGetHullArea>());
-
-
-    // elipse info
-    fabricaOperadorsBlob.Register(CBlobGetMajorAxisLength().GetNom(), Type2Type<CBlobGetMajorAxisLength>());
-    fabricaOperadorsBlob.Register(CBlobGetMinorAxisLength().GetNom(), Type2Type<CBlobGetMinorAxisLength>());
-    fabricaOperadorsBlob.Register(CBlobGetAxisRatio().GetNom(), Type2Type<CBlobGetAxisRatio>());
-    fabricaOperadorsBlob.Register(CBlobGetOrientation().GetNom(), Type2Type<CBlobGetOrientation>());
-    fabricaOperadorsBlob.Register(CBlobGetOrientationCos().GetNom(), Type2Type<CBlobGetOrientationCos>());
-    fabricaOperadorsBlob.Register(CBlobGetAreaElipseRatio().GetNom(), Type2Type<CBlobGetAreaElipseRatio>());
-
-    // min an max
-    fabricaOperadorsBlob.Register(CBlobGetMaxX().GetNom(), Type2Type<CBlobGetMaxX>());
-    fabricaOperadorsBlob.Register(CBlobGetMaxY().GetNom(), Type2Type<CBlobGetMaxY>());
-    fabricaOperadorsBlob.Register(CBlobGetMinX().GetNom(), Type2Type<CBlobGetMinX>());
-    fabricaOperadorsBlob.Register(CBlobGetMinY().GetNom(), Type2Type<CBlobGetMinY>());
-
-    fabricaOperadorsBlob.Register(CBlobGetMaxXatMaxY().GetNom(), Type2Type<CBlobGetMaxXatMaxY>());
-    fabricaOperadorsBlob.Register(CBlobGetMaxYatMinX().GetNom(), Type2Type<CBlobGetMaxYatMinX>());
-    fabricaOperadorsBlob.Register(CBlobGetMinXatMinY().GetNom(), Type2Type<CBlobGetMinXatMinY>());
-    fabricaOperadorsBlob.Register(CBlobGetMinYatMaxX().GetNom(), Type2Type<CBlobGetMinYatMaxX>());
-
-    // grey level stats
-    fabricaOperadorsBlob.Register(CBlobGetMean().GetNom(), Type2Type<CBlobGetMean>());
-    fabricaOperadorsBlob.Register(CBlobGetStdDev().GetNom(), Type2Type<CBlobGetStdDev>());
-
-    // coordinate info
-    fabricaOperadorsBlob.Register(CBlobGetXYInside().GetNom(), Type2Type<CBlobGetXYInside>());
-    fabricaOperadorsBlob.Register(CBlobGetDiffY().GetNom(), Type2Type<CBlobGetDiffY>());
-    fabricaOperadorsBlob.Register(CBlobGetDiffX().GetNom(), Type2Type<CBlobGetDiffX>());
-    fabricaOperadorsBlob.Register(CBlobGetXCenter().GetNom(), Type2Type<CBlobGetXCenter>());
-    fabricaOperadorsBlob.Register(CBlobGetYCenter().GetNom(), Type2Type<CBlobGetYCenter>());
-    fabricaOperadorsBlob.Register(CBlobGetDistanceFromPoint().GetNom(), Type2Type<CBlobGetDistanceFromPoint>());
-
-    // moments
-    fabricaOperadorsBlob.Register(CBlobGetMoment().GetNom(), Type2Type<CBlobGetMoment>());
-
   }
-
-#endif
-
 }
-
diff --git a/src/algorithms/MultiLayer/blob.h b/src/algorithms/MultiLayer/blob.h
index acad398e188d643eb71c6c6915938a176f5fb71e..6cce6c8ec3b8d9e539b7a27e7fde2e9cf535f333 100644
--- a/src/algorithms/MultiLayer/blob.h
+++ b/src/algorithms/MultiLayer/blob.h
@@ -8,777 +8,785 @@
 // opencv legacy includes
 #include "OpenCvLegacyIncludes.h"
 
-//! Factor de conversió de graus a radians
-#define DEGREE2RAD		(CV_PI / 180.0)
-
-namespace Blob
+namespace bgslibrary
 {
-  /**
-    Classe que representa un blob, entés com un conjunt de pixels del
-    mateix color contigus en una imatge binaritzada.
-
-    Class to represent a blob, a group of connected pixels in a binary image
-    */
-  class CBlob
+  namespace algorithms
   {
-  public:
-    //! Constructor estàndard
-    //! Standard constructor
-    CBlob();
-    //! Constructor de còpia
-    //! Copy constructor
-    CBlob(const CBlob &src);
-    CBlob(const CBlob *src);
-
-    //! Destructor estàndard
-    //! Standard Destructor
-    ~CBlob();
-
-    //! Operador d'assignació
-    //! Assigment operator
-    CBlob& operator=(const CBlob &src);
-
-    //! Indica si el blob està buit ( no té cap info associada )
-    //! Shows if the blob has associated information
-    bool IsEmpty() const
+    namespace multilayer
     {
-      return (area == 0.0 && perimeter == 0.0);
-    };
-
-    //! Neteja les cantonades del blob
-    //! Clears the edges of the blob
-    void ClearEdges();
-    //! Copia les cantonades del blob a un altre (les afegeix al destí)
-    //! Adds the blob edges to another blob
-    void CopyEdges(CBlob &destination) const;
-    //! Retorna el poligon convex del blob
-    //! Calculates the convex hull of the blob
-    bool GetConvexHull(CvSeq **dst) const;
-    //! Calcula l'elipse que s'adapta als vèrtexs del blob
-    //! Fits an ellipse to the blob edges
-    CvBox2D GetEllipse() const;
-
-    //! Pinta l'interior d'un blob d'un color determinat
-    //! Paints the blob in an image
-    void FillBlob(IplImage *imatge, CvScalar color, int offsetX = 0, int offsetY = 0) const;
-
-    //! Funcions GET sobre els valors dels blobs
-    //! Get functions
-
-    inline int Label() const { return etiqueta; }
-    inline int Parent() const { return parent; }
-    inline double Area() const { return area; }
-    inline double Perimeter() const { return perimeter; }
-    inline double ExternPerimeter() const { return externPerimeter; }
-    inline int	  Exterior() const { return exterior; }
-    inline double Mean() const { return mean; }
-    inline double StdDev() const { return stddev; }
-    inline double MinX() const { return minx; }
-    inline double MinY() const { return miny; }
-    inline double MaxX() const { return maxx; }
-    inline double MaxY() const { return maxy; }
-    inline CvSeq *Edges() const { return edges; }
-    inline double SumX() const { return sumx; }
-    inline double SumY() const { return sumy; }
-    inline double SumXX() const { return sumxx; }
-    inline double SumYY() const { return sumyy; }
-    inline double SumXY() const { return sumxy; }
-
-    //! etiqueta del blob
-    //! label of the blob
-    int etiqueta;
-    //! flag per indicar si es exterior o no
-    //! true for extern blobs
-    int exterior;
-    //! area del blob
-    //! Blob area
-    double area;
-    //! perimetre del blob
-    //! Blob perimeter
-    double perimeter;
-    //! quantitat de perimetre del blob extern
-    //! amount of blob perimeter which is exterior
-    double externPerimeter;
-    //! etiqueta del blob pare
-    //! label of the parent blob
-    int parent;
-    //! moments
-    double sumx;
-    double sumy;
-    double sumxx;
-    double sumyy;
-    double sumxy;
-    //! Bounding rect
-    double minx;
-    double maxx;
-    double miny;
-    double maxy;
-
-    //! mitjana
-    //! mean of the grey scale values of the blob pixels
-    double mean;
-    //! desviació standard
-    //! standard deviation of the grey scale values of the blob pixels
-    double stddev;
-
-    //! àrea de memòria on es desaran els punts de contorn del blob
-    //! storage which contains the edges of the blob
-    CvMemStorage *m_storage;
-    //!	Sequència de punts del contorn del blob
-    //! Sequence with the edges of the blob
-    CvSeq *edges;
-
-
-    //! Point datatype for plotting (FillBlob)
-    typedef std::vector<CvPoint> vectorPunts;
-
-    //! Helper class to compare two CvPoints (for sorting in FillBlob)
-    struct comparaCvPoint : public std::binary_function<CvPoint, CvPoint, bool>
-    {
-      //! Definim que un punt és menor com més amunt a la dreta estigui
-      bool operator()(CvPoint a, CvPoint b)
+      namespace blob
       {
-        if (a.y == b.y)
-          return a.x < b.x;
-        else
-          return a.y < b.y;
+        //! Factor de conversió de graus a radians
+        const double DEGREE2RAD = (CV_PI / 180.0);
+
+        /**
+          Classe que representa un blob, entés com un conjunt de pixels del
+          mateix color contigus en una imatge binaritzada.
+
+          Class to represent a blob, a group of connected pixels in a binary image
+          */
+        class CBlob
+        {
+        public:
+          //! Constructor estàndard
+          //! Standard constructor
+          CBlob();
+          //! Constructor de còpia
+          //! Copy constructor
+          CBlob(const CBlob &src);
+          CBlob(const CBlob *src);
+
+          //! Destructor estàndard
+          //! Standard Destructor
+          ~CBlob();
+
+          //! Operador d'assignació
+          //! Assigment operator
+          CBlob& operator=(const CBlob &src);
+
+          //! Indica si el blob està buit ( no té cap info associada )
+          //! Shows if the blob has associated information
+          bool IsEmpty() const
+          {
+            return (area == 0.0 && perimeter == 0.0);
+          };
+
+          //! Neteja les cantonades del blob
+          //! Clears the edges of the blob
+          void ClearEdges();
+          //! Copia les cantonades del blob a un altre (les afegeix al destí)
+          //! Adds the blob edges to another blob
+          void CopyEdges(CBlob &destination) const;
+          //! Retorna el poligon convex del blob
+          //! Calculates the convex hull of the blob
+          bool GetConvexHull(CvSeq **dst) const;
+          //! Calcula l'elipse que s'adapta als vèrtexs del blob
+          //! Fits an ellipse to the blob edges
+          CvBox2D GetEllipse() const;
+
+          //! Pinta l'interior d'un blob d'un color determinat
+          //! Paints the blob in an image
+          void FillBlob(IplImage *imatge, CvScalar color, int offsetX = 0, int offsetY = 0) const;
+
+          //! Funcions GET sobre els valors dels blobs
+          //! Get functions
+
+          inline int Label() const { return etiqueta; }
+          inline int Parent() const { return parent; }
+          inline double Area() const { return area; }
+          inline double Perimeter() const { return perimeter; }
+          inline double ExternPerimeter() const { return externPerimeter; }
+          inline int	  Exterior() const { return exterior; }
+          inline double Mean() const { return mean; }
+          inline double StdDev() const { return stddev; }
+          inline double MinX() const { return minx; }
+          inline double MinY() const { return miny; }
+          inline double MaxX() const { return maxx; }
+          inline double MaxY() const { return maxy; }
+          inline CvSeq *Edges() const { return edges; }
+          inline double SumX() const { return sumx; }
+          inline double SumY() const { return sumy; }
+          inline double SumXX() const { return sumxx; }
+          inline double SumYY() const { return sumyy; }
+          inline double SumXY() const { return sumxy; }
+
+          //! etiqueta del blob
+          //! label of the blob
+          int etiqueta;
+          //! flag per indicar si es exterior o no
+          //! true for extern blobs
+          int exterior;
+          //! area del blob
+          //! Blob area
+          double area;
+          //! perimetre del blob
+          //! Blob perimeter
+          double perimeter;
+          //! quantitat de perimetre del blob extern
+          //! amount of blob perimeter which is exterior
+          double externPerimeter;
+          //! etiqueta del blob pare
+          //! label of the parent blob
+          int parent;
+          //! moments
+          double sumx;
+          double sumy;
+          double sumxx;
+          double sumyy;
+          double sumxy;
+          //! Bounding rect
+          double minx;
+          double maxx;
+          double miny;
+          double maxy;
+
+          //! mitjana
+          //! mean of the grey scale values of the blob pixels
+          double mean;
+          //! desviació standard
+          //! standard deviation of the grey scale values of the blob pixels
+          double stddev;
+
+          //! àrea de memòria on es desaran els punts de contorn del blob
+          //! storage which contains the edges of the blob
+          CvMemStorage *m_storage;
+          //!	Sequència de punts del contorn del blob
+          //! Sequence with the edges of the blob
+          CvSeq *edges;
+
+
+          //! Point datatype for plotting (FillBlob)
+          typedef std::vector<CvPoint> vectorPunts;
+
+          //! Helper class to compare two CvPoints (for sorting in FillBlob)
+          struct comparaCvPoint : public std::binary_function<CvPoint, CvPoint, bool>
+          {
+            //! Definim que un punt és menor com més amunt a la dreta estigui
+            bool operator()(CvPoint a, CvPoint b)
+            {
+              if (a.y == b.y)
+                return a.x < b.x;
+              else
+                return a.y < b.y;
+            }
+          };
+        };
+
+
+
+        /**************************************************************************
+          Definició de les classes per a fer operacions sobre els blobs
+
+          Helper classes to perform operations on blobs
+          **************************************************************************/
+
+
+          //! Classe d'on derivarem totes les operacions sobre els blobs
+          //! Interface to derive all blob operations
+        class COperadorBlob
+        {
+        public:
+          virtual ~COperadorBlob() {};
+
+          //! Aplica l'operació al blob
+          virtual double operator()(const CBlob &blob) const = 0;
+          //! Obté el nom de l'operador
+          virtual const char *GetNom() const = 0;
+
+          operator COperadorBlob*() const
+          {
+            return (COperadorBlob*)this;
+          }
+        };
+
+        typedef COperadorBlob funcio_calculBlob;
+
+      #ifdef BLOB_OBJECT_FACTORY
+        /**
+          Funció per comparar dos identificadors dins de la fàbrica de COperadorBlobs
+          */
+        struct functorComparacioIdOperador
+        {
+          bool operator()(const char* s1, const char* s2) const
+          {
+            return strcmp(s1, s2) < 0;
+          }
+        };
+
+        //! Definition of Object factory type for COperadorBlob objects
+        typedef ObjectFactory<COperadorBlob, const char *, functorComparacioIdOperador > t_OperadorBlobFactory;
+
+        //! Funció global per a registrar tots els operadors definits a blob.h
+        void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob);
+
+      #endif
+
+        //! Classe per calcular l'àrea d'un blob
+        //! Class to get the area of a blob
+        class CBlobGetArea : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.Area();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetArea";
+          }
+        };
+
+        //! Classe per calcular el perimetre d'un blob
+        //! Class to get the perimeter of a blob
+        class CBlobGetPerimeter : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.Perimeter();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetPerimeter";
+          }
+        };
+
+        //! Classe que diu si un blob és extern o no
+        //! Class to get the extern flag of a blob
+        class CBlobGetExterior : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.Exterior();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetExterior";
+          }
+        };
+
+        //! Classe per calcular la mitjana de nivells de gris d'un blob
+        //! Class to get the mean grey level of a blob
+        class CBlobGetMean : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.Mean();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetMean";
+          }
+        };
+
+        //! Classe per calcular la desviació estàndard dels nivells de gris d'un blob
+        //! Class to get the standard deviation of the grey level values of a blob
+        class CBlobGetStdDev : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.StdDev();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetStdDev";
+          }
+        };
+
+        //! Classe per calcular la compacitat d'un blob
+        //! Class to calculate the compactness of a blob
+        class CBlobGetCompactness : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetCompactness";
+          }
+        };
+
+        //! Classe per calcular la longitud d'un blob
+        //! Class to calculate the length of a blob
+        class CBlobGetLength : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetLength";
+          }
+        };
+
+        //! Classe per calcular l'amplada d'un blob
+        //! Class to calculate the breadth of a blob
+        class CBlobGetBreadth : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetBreadth";
+          }
+        };
+
+        //! Classe per calcular la diferència en X del blob
+        class CBlobGetDiffX : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.maxx - blob.minx;
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetDiffX";
+          }
+        };
+
+        //! Classe per calcular la diferència en X del blob
+        class CBlobGetDiffY : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.maxy - blob.miny;
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetDiffY";
+          }
+        };
+
+        //! Classe per calcular el moment PQ del blob
+        //! Class to calculate the P,Q moment of a blob
+        class CBlobGetMoment : public COperadorBlob
+        {
+        public:
+          //! Constructor estàndard
+          //! Standard constructor (gets the 00 moment)
+          CBlobGetMoment()
+          {
+            m_p = m_q = 0;
+          }
+          //! Constructor: indiquem el moment p,q a calcular
+          //! Constructor: gets the PQ moment
+          CBlobGetMoment(int p, int q)
+          {
+            m_p = p;
+            m_q = q;
+          };
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetMoment";
+          }
+
+        private:
+          //! moment que volem calcular
+          int m_p, m_q;
+        };
+
+        //! Classe per calcular el perimetre del poligon convex d'un blob
+        //! Class to calculate the convex hull perimeter of a blob
+        class CBlobGetHullPerimeter : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetHullPerimeter";
+          }
+        };
+
+        //! Classe per calcular l'àrea del poligon convex d'un blob
+        //! Class to calculate the convex hull area of a blob
+        class CBlobGetHullArea : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetHullArea";
+          }
+        };
+
+        //! Classe per calcular la x minima en la y minima
+        //! Class to calculate the minimum x on the minimum y
+        class CBlobGetMinXatMinY : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetMinXatMinY";
+          }
+        };
+
+        //! Classe per calcular la y minima en la x maxima
+        //! Class to calculate the minimum y on the maximum x
+        class CBlobGetMinYatMaxX : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetMinYatMaxX";
+          }
+        };
+
+        //! Classe per calcular la x maxima en la y maxima
+        //! Class to calculate the maximum x on the maximum y
+        class CBlobGetMaxXatMaxY : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetMaxXatMaxY";
+          }
+        };
+
+        //! Classe per calcular la y maxima en la x minima
+        //! Class to calculate the maximum y on the minimum y
+        class CBlobGetMaxYatMinX : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetMaxYatMinX";
+          }
+        };
+
+        //! Classe per a calcular la x mínima
+        //! Class to get the minimum x
+        class CBlobGetMinX : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.MinX();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetMinX";
+          }
+        };
+
+        //! Classe per a calcular la x màxima
+        //! Class to get the maximum x
+        class CBlobGetMaxX : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.MaxX();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetMaxX";
+          }
+        };
+
+        //! Classe per a calcular la y mínima
+        //! Class to get the minimum y
+        class CBlobGetMinY : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.MinY();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetMinY";
+          }
+        };
+
+        //! Classe per a calcular la y màxima
+        //! Class to get the maximum y
+        class CBlobGetMaxY : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.MaxY();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetMax";
+          }
+        };
+
+
+        //! Classe per calcular l'elongacio d'un blob
+        //! Class to calculate the elongation of the blob
+        class CBlobGetElongation : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetElongation";
+          }
+        };
+
+        //! Classe per calcular la rugositat d'un blob
+        //! Class to calculate the roughness of the blob
+        class CBlobGetRoughness : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetRoughness";
+          }
+        };
+
+        //! Classe per calcular la distància entre el centre del blob i un punt donat
+        //! Class to calculate the euclidean distance between the center of a blob and a given point
+        class CBlobGetDistanceFromPoint : public COperadorBlob
+        {
+        public:
+          //! Standard constructor (distance to point 0,0)
+          CBlobGetDistanceFromPoint()
+          {
+            m_x = m_y = 0.0;
+          }
+          //! Constructor (distance to point x,y)
+          CBlobGetDistanceFromPoint(const double x, const double y)
+          {
+            m_x = x;
+            m_y = y;
+          }
+
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetDistanceFromPoint";
+          }
+
+        private:
+          // coordenades del punt on volem calcular la distància
+          double m_x, m_y;
+        };
+
+        //! Classe per calcular el nombre de pixels externs d'un blob
+        //! Class to get the number of extern pixels of a blob
+        class CBlobGetExternPerimeter : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.ExternPerimeter();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetExternPerimeter";
+          }
+        };
+
+        //! Classe per calcular el ratio entre el perimetre i nombre pixels externs
+        //! valors propers a 0 indiquen que la majoria del blob és intern
+        //! valors propers a 1 indiquen que la majoria del blob és extern
+        //! Class to calculate the ratio between the perimeter and the number of extern pixels
+        class CBlobGetExternPerimeterRatio : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            if (blob.Perimeter() != 0)
+              return blob.ExternPerimeter() / blob.Perimeter();
+            else
+              return blob.ExternPerimeter();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetExternPerimeterRatio";
+          }
+        };
+
+        //! Classe per calcular el ratio entre el perimetre convex i nombre pixels externs
+        //! valors propers a 0 indiquen que la majoria del blob és intern
+        //! valors propers a 1 indiquen que la majoria del blob és extern
+        //! Class to calculate the ratio between the perimeter and the number of extern pixels
+        class CBlobGetExternHullPerimeterRatio : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            CBlobGetHullPerimeter getHullPerimeter;
+            double hullPerimeter;
+
+            if ((hullPerimeter = getHullPerimeter(blob)) != 0)
+              return blob.ExternPerimeter() / hullPerimeter;
+            else
+              return blob.ExternPerimeter();
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetExternHullPerimeterRatio";
+          }
+        };
+
+        //! Classe per calcular el centre en el eix X d'un blob
+        //! Class to calculate the center in the X direction
+        class CBlobGetXCenter : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.MinX() + ((blob.MaxX() - blob.MinX()) / 2.0);
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetXCenter";
+          }
+        };
+
+        //! Classe per calcular el centre en el eix Y d'un blob
+        //! Class to calculate the center in the Y direction
+        class CBlobGetYCenter : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            return blob.MinY() + ((blob.MaxY() - blob.MinY()) / 2.0);
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetYCenter";
+          }
+        };
+
+        //! Classe per calcular la longitud de l'eix major d'un blob
+        //! Class to calculate the length of the major axis of the ellipse that fits the blob edges
+        class CBlobGetMajorAxisLength : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            CvBox2D elipse = blob.GetEllipse();
+
+            return elipse.size.width;
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetMajorAxisLength";
+          }
+        };
+
+        //! Classe per calcular el ratio entre l'area de la elipse i la de la taca
+        //! Class
+        class CBlobGetAreaElipseRatio : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            if (blob.Area() == 0.0) return 0.0;
+
+            CvBox2D elipse = blob.GetEllipse();
+            double ratioAreaElipseAreaTaca = ((elipse.size.width / 2.0)
+              *
+              (elipse.size.height / 2.0)
+              *CV_PI
+              )
+              /
+              blob.Area();
+
+            return ratioAreaElipseAreaTaca;
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetAreaElipseRatio";
+          }
+        };
+
+        //! Classe per calcular la longitud de l'eix menor d'un blob
+        //! Class to calculate the length of the minor axis of the ellipse that fits the blob edges
+        class CBlobGetMinorAxisLength : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            CvBox2D elipse = blob.GetEllipse();
+
+            return elipse.size.height;
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetMinorAxisLength";
+          }
+        };
+
+        //! Classe per calcular l'orientació de l'ellipse del blob en radians
+        //! Class to calculate the orientation of the ellipse that fits the blob edges in radians
+        class CBlobGetOrientation : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            CvBox2D elipse = blob.GetEllipse();
+
+            if (elipse.angle > 180.0)
+              return ((elipse.angle - 180.0)* DEGREE2RAD);
+            else
+              return (elipse.angle * DEGREE2RAD);
+
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetOrientation";
+          }
+        };
+
+        //! Classe per calcular el cosinus de l'orientació de l'ellipse del blob
+        //! Class to calculate the cosinus of the orientation of the ellipse that fits the blob edges
+        class CBlobGetOrientationCos : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            CBlobGetOrientation getOrientation;
+            return fabs(cos(getOrientation(blob)));
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetOrientationCos";
+          }
+        };
+
+
+        //! Classe per calcular el ratio entre l'eix major i menor de la el·lipse
+        //! Class to calculate the ratio between both axes of the ellipse
+        class CBlobGetAxisRatio : public COperadorBlob
+        {
+        public:
+          double operator()(const CBlob &blob) const
+          {
+            CvBox2D elipse = blob.GetEllipse();
+
+            return elipse.size.height / elipse.size.width;
+          }
+          const char *GetNom() const
+          {
+            return "CBlobGetAxisRatio";
+          }
+        };
+
+
+        //! Classe per calcular si un punt cau dins del blob
+        //! Class to calculate whether a point is inside a blob
+        class CBlobGetXYInside : public COperadorBlob
+        {
+        public:
+          //! Constructor estàndard
+          //! Standard constructor
+          CBlobGetXYInside()
+          {
+            m_p = cvPoint(0, 0);
+          }
+          //! Constructor: indiquem el punt
+          //! Constructor: sets the point
+          CBlobGetXYInside(CvPoint p)
+          {
+            m_p = p;
+          };
+          double operator()(const CBlob &blob) const;
+          const char *GetNom() const
+          {
+            return "CBlobGetXYInside";
+          }
+
+        private:
+          //! punt que considerem
+          //! point to be considered
+          CvPoint m_p;
+        };
       }
-    };
-  };
-
-
-
-  /**************************************************************************
-    Definició de les classes per a fer operacions sobre els blobs
-
-    Helper classes to perform operations on blobs
-    **************************************************************************/
-
-
-    //! Classe d'on derivarem totes les operacions sobre els blobs
-    //! Interface to derive all blob operations
-  class COperadorBlob
-  {
-  public:
-    virtual ~COperadorBlob() {};
-
-    //! Aplica l'operació al blob
-    virtual double operator()(const CBlob &blob) const = 0;
-    //! Obté el nom de l'operador
-    virtual const char *GetNom() const = 0;
-
-    operator COperadorBlob*() const
-    {
-      return (COperadorBlob*)this;
-    }
-  };
-
-  typedef COperadorBlob funcio_calculBlob;
-
-#ifdef BLOB_OBJECT_FACTORY
-  /**
-    Funció per comparar dos identificadors dins de la fàbrica de COperadorBlobs
-    */
-  struct functorComparacioIdOperador
-  {
-    bool operator()(const char* s1, const char* s2) const
-    {
-      return strcmp(s1, s2) < 0;
-    }
-  };
-
-  //! Definition of Object factory type for COperadorBlob objects
-  typedef ObjectFactory<COperadorBlob, const char *, functorComparacioIdOperador > t_OperadorBlobFactory;
-
-  //! Funció global per a registrar tots els operadors definits a blob.h
-  void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob);
-
-#endif
-
-  //! Classe per calcular l'àrea d'un blob
-  //! Class to get the area of a blob
-  class CBlobGetArea : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.Area();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetArea";
-    }
-  };
-
-  //! Classe per calcular el perimetre d'un blob
-  //! Class to get the perimeter of a blob
-  class CBlobGetPerimeter : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.Perimeter();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetPerimeter";
-    }
-  };
-
-  //! Classe que diu si un blob és extern o no
-  //! Class to get the extern flag of a blob
-  class CBlobGetExterior : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.Exterior();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetExterior";
-    }
-  };
-
-  //! Classe per calcular la mitjana de nivells de gris d'un blob
-  //! Class to get the mean grey level of a blob
-  class CBlobGetMean : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.Mean();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetMean";
-    }
-  };
-
-  //! Classe per calcular la desviació estàndard dels nivells de gris d'un blob
-  //! Class to get the standard deviation of the grey level values of a blob
-  class CBlobGetStdDev : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.StdDev();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetStdDev";
-    }
-  };
-
-  //! Classe per calcular la compacitat d'un blob
-  //! Class to calculate the compactness of a blob
-  class CBlobGetCompactness : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetCompactness";
-    }
-  };
-
-  //! Classe per calcular la longitud d'un blob
-  //! Class to calculate the length of a blob
-  class CBlobGetLength : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetLength";
-    }
-  };
-
-  //! Classe per calcular l'amplada d'un blob
-  //! Class to calculate the breadth of a blob
-  class CBlobGetBreadth : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetBreadth";
-    }
-  };
-
-  //! Classe per calcular la diferència en X del blob
-  class CBlobGetDiffX : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.maxx - blob.minx;
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetDiffX";
-    }
-  };
-
-  //! Classe per calcular la diferència en X del blob
-  class CBlobGetDiffY : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.maxy - blob.miny;
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetDiffY";
-    }
-  };
-
-  //! Classe per calcular el moment PQ del blob
-  //! Class to calculate the P,Q moment of a blob
-  class CBlobGetMoment : public COperadorBlob
-  {
-  public:
-    //! Constructor estàndard
-    //! Standard constructor (gets the 00 moment)
-    CBlobGetMoment()
-    {
-      m_p = m_q = 0;
-    }
-    //! Constructor: indiquem el moment p,q a calcular
-    //! Constructor: gets the PQ moment
-    CBlobGetMoment(int p, int q)
-    {
-      m_p = p;
-      m_q = q;
-    };
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetMoment";
-    }
-
-  private:
-    //! moment que volem calcular
-    int m_p, m_q;
-  };
-
-  //! Classe per calcular el perimetre del poligon convex d'un blob
-  //! Class to calculate the convex hull perimeter of a blob
-  class CBlobGetHullPerimeter : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetHullPerimeter";
-    }
-  };
-
-  //! Classe per calcular l'àrea del poligon convex d'un blob
-  //! Class to calculate the convex hull area of a blob
-  class CBlobGetHullArea : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetHullArea";
-    }
-  };
-
-  //! Classe per calcular la x minima en la y minima
-  //! Class to calculate the minimum x on the minimum y
-  class CBlobGetMinXatMinY : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetMinXatMinY";
-    }
-  };
-
-  //! Classe per calcular la y minima en la x maxima
-  //! Class to calculate the minimum y on the maximum x
-  class CBlobGetMinYatMaxX : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetMinYatMaxX";
-    }
-  };
-
-  //! Classe per calcular la x maxima en la y maxima
-  //! Class to calculate the maximum x on the maximum y
-  class CBlobGetMaxXatMaxY : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetMaxXatMaxY";
-    }
-  };
-
-  //! Classe per calcular la y maxima en la x minima
-  //! Class to calculate the maximum y on the minimum y
-  class CBlobGetMaxYatMinX : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetMaxYatMinX";
-    }
-  };
-
-  //! Classe per a calcular la x mínima
-  //! Class to get the minimum x
-  class CBlobGetMinX : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.MinX();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetMinX";
-    }
-  };
-
-  //! Classe per a calcular la x màxima
-  //! Class to get the maximum x
-  class CBlobGetMaxX : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.MaxX();
     }
-    const char *GetNom() const
-    {
-      return "CBlobGetMaxX";
-    }
-  };
-
-  //! Classe per a calcular la y mínima
-  //! Class to get the minimum y
-  class CBlobGetMinY : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.MinY();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetMinY";
-    }
-  };
-
-  //! Classe per a calcular la y màxima
-  //! Class to get the maximum y
-  class CBlobGetMaxY : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.MaxY();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetMax";
-    }
-  };
-
-
-  //! Classe per calcular l'elongacio d'un blob
-  //! Class to calculate the elongation of the blob
-  class CBlobGetElongation : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetElongation";
-    }
-  };
-
-  //! Classe per calcular la rugositat d'un blob
-  //! Class to calculate the roughness of the blob
-  class CBlobGetRoughness : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetRoughness";
-    }
-  };
-
-  //! Classe per calcular la distància entre el centre del blob i un punt donat
-  //! Class to calculate the euclidean distance between the center of a blob and a given point
-  class CBlobGetDistanceFromPoint : public COperadorBlob
-  {
-  public:
-    //! Standard constructor (distance to point 0,0)
-    CBlobGetDistanceFromPoint()
-    {
-      m_x = m_y = 0.0;
-    }
-    //! Constructor (distance to point x,y)
-    CBlobGetDistanceFromPoint(const double x, const double y)
-    {
-      m_x = x;
-      m_y = y;
-    }
-
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetDistanceFromPoint";
-    }
-
-  private:
-    // coordenades del punt on volem calcular la distància
-    double m_x, m_y;
-  };
-
-  //! Classe per calcular el nombre de pixels externs d'un blob
-  //! Class to get the number of extern pixels of a blob
-  class CBlobGetExternPerimeter : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.ExternPerimeter();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetExternPerimeter";
-    }
-  };
-
-  //! Classe per calcular el ratio entre el perimetre i nombre pixels externs
-  //! valors propers a 0 indiquen que la majoria del blob és intern
-  //! valors propers a 1 indiquen que la majoria del blob és extern
-  //! Class to calculate the ratio between the perimeter and the number of extern pixels
-  class CBlobGetExternPerimeterRatio : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      if (blob.Perimeter() != 0)
-        return blob.ExternPerimeter() / blob.Perimeter();
-      else
-        return blob.ExternPerimeter();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetExternPerimeterRatio";
-    }
-  };
-
-  //! Classe per calcular el ratio entre el perimetre convex i nombre pixels externs
-  //! valors propers a 0 indiquen que la majoria del blob és intern
-  //! valors propers a 1 indiquen que la majoria del blob és extern
-  //! Class to calculate the ratio between the perimeter and the number of extern pixels
-  class CBlobGetExternHullPerimeterRatio : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      CBlobGetHullPerimeter getHullPerimeter;
-      double hullPerimeter;
-
-      if ((hullPerimeter = getHullPerimeter(blob)) != 0)
-        return blob.ExternPerimeter() / hullPerimeter;
-      else
-        return blob.ExternPerimeter();
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetExternHullPerimeterRatio";
-    }
-  };
-
-  //! Classe per calcular el centre en el eix X d'un blob
-  //! Class to calculate the center in the X direction
-  class CBlobGetXCenter : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.MinX() + ((blob.MaxX() - blob.MinX()) / 2.0);
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetXCenter";
-    }
-  };
-
-  //! Classe per calcular el centre en el eix Y d'un blob
-  //! Class to calculate the center in the Y direction
-  class CBlobGetYCenter : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      return blob.MinY() + ((blob.MaxY() - blob.MinY()) / 2.0);
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetYCenter";
-    }
-  };
-
-  //! Classe per calcular la longitud de l'eix major d'un blob
-  //! Class to calculate the length of the major axis of the ellipse that fits the blob edges
-  class CBlobGetMajorAxisLength : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      CvBox2D elipse = blob.GetEllipse();
-
-      return elipse.size.width;
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetMajorAxisLength";
-    }
-  };
-
-  //! Classe per calcular el ratio entre l'area de la elipse i la de la taca
-  //! Class
-  class CBlobGetAreaElipseRatio : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      if (blob.Area() == 0.0) return 0.0;
-
-      CvBox2D elipse = blob.GetEllipse();
-      double ratioAreaElipseAreaTaca = ((elipse.size.width / 2.0)
-        *
-        (elipse.size.height / 2.0)
-        *CV_PI
-        )
-        /
-        blob.Area();
-
-      return ratioAreaElipseAreaTaca;
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetAreaElipseRatio";
-    }
-  };
-
-  //! Classe per calcular la longitud de l'eix menor d'un blob
-  //! Class to calculate the length of the minor axis of the ellipse that fits the blob edges
-  class CBlobGetMinorAxisLength : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      CvBox2D elipse = blob.GetEllipse();
-
-      return elipse.size.height;
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetMinorAxisLength";
-    }
-  };
-
-  //! Classe per calcular l'orientació de l'ellipse del blob en radians
-  //! Class to calculate the orientation of the ellipse that fits the blob edges in radians
-  class CBlobGetOrientation : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      CvBox2D elipse = blob.GetEllipse();
-
-      if (elipse.angle > 180.0)
-        return ((elipse.angle - 180.0)* DEGREE2RAD);
-      else
-        return (elipse.angle * DEGREE2RAD);
-
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetOrientation";
-    }
-  };
-
-  //! Classe per calcular el cosinus de l'orientació de l'ellipse del blob
-  //! Class to calculate the cosinus of the orientation of the ellipse that fits the blob edges
-  class CBlobGetOrientationCos : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      CBlobGetOrientation getOrientation;
-      return fabs(cos(getOrientation(blob)));
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetOrientationCos";
-    }
-  };
-
-
-  //! Classe per calcular el ratio entre l'eix major i menor de la el·lipse
-  //! Class to calculate the ratio between both axes of the ellipse
-  class CBlobGetAxisRatio : public COperadorBlob
-  {
-  public:
-    double operator()(const CBlob &blob) const
-    {
-      CvBox2D elipse = blob.GetEllipse();
-
-      return elipse.size.height / elipse.size.width;
-    }
-    const char *GetNom() const
-    {
-      return "CBlobGetAxisRatio";
-    }
-  };
-
-
-  //! Classe per calcular si un punt cau dins del blob
-  //! Class to calculate whether a point is inside a blob
-  class CBlobGetXYInside : public COperadorBlob
-  {
-  public:
-    //! Constructor estàndard
-    //! Standard constructor
-    CBlobGetXYInside()
-    {
-      m_p = cvPoint(0, 0);
-    }
-    //! Constructor: indiquem el punt
-    //! Constructor: sets the point
-    CBlobGetXYInside(CvPoint p)
-    {
-      m_p = p;
-    };
-    double operator()(const CBlob &blob) const;
-    const char *GetNom() const
-    {
-      return "CBlobGetXYInside";
-    }
-
-  private:
-    //! punt que considerem
-    //! point to be considered
-    CvPoint m_p;
-  };
-
+  }
 }
diff --git a/src/algorithms/PAWCS.cpp b/src/algorithms/PAWCS.cpp
index e9f82d2fa322fea5177228339bf6fde334c16f98..aab37c7f239485bc1aa38923de494e4f3a4e7463 100644
--- a/src/algorithms/PAWCS.cpp
+++ b/src/algorithms/PAWCS.cpp
@@ -5,11 +5,11 @@ using namespace bgslibrary::algorithms;
 PAWCS::PAWCS() : 
   IBGS(quote(PAWCS)),
   pPAWCS(nullptr),
-  fRelLBSPThreshold(BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD),
-  nDescDistThresholdOffset(BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET),
-  nMinColorDistThreshold(BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD),
-  nMaxNbWords(BGSPAWCS_DEFAULT_MAX_NB_WORDS),
-  nSamplesForMovingAvgs(BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS)
+  fRelLBSPThreshold(lbsp::BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD),
+  nDescDistThresholdOffset(lbsp::BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET),
+  nMinColorDistThreshold(lbsp::BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD),
+  nMaxNbWords(lbsp::BGSPAWCS_DEFAULT_MAX_NB_WORDS),
+  nSamplesForMovingAvgs(lbsp::BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS)
 {
   debug_construction(PAWCS);
   initLoadSaveConfig(algorithmName);
@@ -26,7 +26,7 @@ void PAWCS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_
   init(img_input, img_output, img_bgmodel);
 
   if (firstTime) {
-    pPAWCS = new BackgroundSubtractorPAWCS(
+    pPAWCS = new lbsp::BackgroundSubtractorPAWCS(
       fRelLBSPThreshold, nDescDistThresholdOffset, nMinColorDistThreshold,
       nMaxNbWords, nSamplesForMovingAvgs);
 
diff --git a/src/algorithms/PAWCS.h b/src/algorithms/PAWCS.h
index 48d8286a2fb5f9875445d769d70c541e5a557d12..737d5db961d1af9429013ad67faafad5b5ce1e99 100644
--- a/src/algorithms/PAWCS.h
+++ b/src/algorithms/PAWCS.h
@@ -10,7 +10,7 @@ namespace bgslibrary
     class PAWCS : public IBGS
     {
     private:
-      BackgroundSubtractorPAWCS* pPAWCS;
+      lbsp::BackgroundSubtractorPAWCS* pPAWCS;
 
       float fRelLBSPThreshold;
       int nDescDistThresholdOffset;
diff --git a/src/algorithms/PBAS/PBAS.cpp b/src/algorithms/PBAS/PBAS.cpp
index 36ed4596b1130c43c7a60c34d6c136b6c8634620..c024792d7117e58610e772dd741a1303c959019a 100644
--- a/src/algorithms/PBAS/PBAS.cpp
+++ b/src/algorithms/PBAS/PBAS.cpp
@@ -1,9 +1,12 @@
 #include "PBAS.h"
 
-PBAS::PBAS(void) : N(20), R_lower(18), Raute_min(2), T_lower(2), T_upper(200), R_scale(5), R_incdec(0.05), T_dec(0.05), T_inc(1)
-{
-  std::cout << "PBAS()" << std::endl;
+using namespace bgslibrary::algorithms::pbas;
 
+PBAS::PBAS() : 
+  N(20), R_lower(18), Raute_min(2), 
+  T_lower(2), T_upper(200), R_scale(5), 
+  R_incdec(0.05), T_dec(0.05), T_inc(1)
+{
   //feature vector
   alpha = 7.0;
   beta = 1.0;
@@ -61,8 +64,6 @@ void PBAS::newInitialization()
 
 PBAS::~PBAS(void)
 {
-  std::cout << "~PBAS()" << std::endl;
-
   randomN.clear();
   randomX.clear();
   randomY.clear();
diff --git a/src/algorithms/PBAS/PBAS.h b/src/algorithms/PBAS/PBAS.h
index d58dceb7668175a6103ea19f0fee77ebe2c6add1..b1c88310066bb82512fbc34b0a7ecf2ded8f589c 100644
--- a/src/algorithms/PBAS/PBAS.h
+++ b/src/algorithms/PBAS/PBAS.h
@@ -4,148 +4,154 @@
 #include <opencv2/opencv.hpp>
 //#include <highgui.h>
 
-class PBAS
+namespace bgslibrary
 {
-public:
-  PBAS(void);
-  ~PBAS(void);
-  bool process(cv::Mat* input, cv::Mat* output);
-
-  void setN(int);
-  void setRaute_min(int);
-  void setR_lower(double);
-  void setR_incdec(double);
-  void setR_scale(double);
-  void setT_init(double);
-  void setT_lower(double);
-  void setT_upper(double);
-  void setT_dec(double);
-  void setT_inc(double);
-  void setAlpha(double);
-  void setBeta(double);
-
-  bool isMovement();
-
-private:
-  void calculateFeatures(std::vector<cv::Mat>* feature, cv::Mat* inputImage);
-  void checkValid(int *x, int *y);
-  void decisionThresholdRegulator(float* pt, float* meanDistArr);
-  void learningRateRegulator(float* pt, float* meanDist, uchar* isFore);
-  void init(cv::Mat*);
-  void newInitialization();
-
-  cv::Mat meanMinDist;
-  float* meanMinDist_Pt;
-
-
-
-  int width, height;
-  int chans;
-
-  //balance of feature pixel value to conture value
-  double alpha, beta;
-  //##################################################################################
-
-  double formerMeanNorm;
-
-  //define value of foreground/background pixels
-  int foregroundValue, backgroundValue;
-
-  //##################################################################################
-  //random number parameters
-
-  //random number generator
-  cv::RNG randomGenerator;
-
-  //length of random array initialization
-  long countOfRandomNumb;
-
-  //pre - initialize the randomNumbers for better performance
-  std::vector<int> randomN, randomMinDist, randomX, randomY, randomT, randomTN;
-
-  //###################################################################################
-
-  //check if something is moving
-  bool isMove;
-
-  //for init, count number of runs
-  int runs;
-
-
-  cv::Mat* resultMap;
-  std::vector<cv::Mat> currentFeatures;
-
-  std::vector<float*> currentFeaturesM_Pt;
-  std::vector<uchar*> currentFeaturesC_Pt;
-  uchar* resultMap_Pt;
-
-  std::vector<std::vector<float*>>B_Mag_Pts;
-  std::vector<std::vector<uchar*>>B_Col_Pts;
-
-  double sumMagnitude;
-  double formerMeanMag;
-  //float formerDistanceBack;
-
-  //####################################################################################
-  //N - Number: Defining the size of the background-history-model
-  // number of samples per pixel
-  //size of background history B(x_i)
-  int N;
-  // background model
-  std::vector<std::vector<cv::Mat>> backgroundModel;
-  //####################################################################################
-  //####################################################################################
-  //R-Threshhold - Variables
-  //minimal Threshold for foreground and initial value of R(x_i)
-  // radius of the sphere -> lower border boundary
-  double R_lower;
-
-  //factor which defines new threshold of R(x_i) together with meanMinDist(x_i)
-  // scale for the sphere threshhold to define pixel-based Thresholds
-  double R_scale;
-
-  //decreasing / increasing factor of R(x_i)
-  // increasing/decreasing factor for the r-Threshold based on the result of rTreshScale * meanMinDistBackground
-  double R_incdec;
-
-  cv::Mat actualR;
-  float* actualR_Pt; //new pixel-based r-threshhold -> pointer to arrays
-  //#####################################################################################
-  //####################################################################################
-  //counter for minimal distance to background
-  // Defining the number of background-model-images, which have a lowerDIstance to the current Image than defined by the R-Thresholds, that are necessary
-  // to decide that this pixel is background
-  int Raute_min;
-  //#####################################################################################
-  //####################################################################################
-  //initial value of inverse update factor T(x_i)
-  // Initialize the background-model update rate
-  double T_init;
-
-  //increasing Factor of the update rate 1/T(x_i)
-  // scale that defines the increasing of the update rate of the background model, if the current pixel is background
-  //--> more frequently updates if pixel is background because, there shouln't be any change
-  double T_inc;
-
-  //upper boundary of T(x_i)
-  // defining an upper value, that nrSubsampling can achieve, thus it doesn't reach to an infinite value, where actually no update is possible
-  // at all
-  double T_upper;
-
-  //lower boundary of T(x_i)
-  // defining a minimum value for nrSubsampling --> base value 2.0
-  double T_lower;
-
-  //decreasing factor of the update rate 1/T(x_i)
-  // opposite scale to increasingRateScale, for decreasing the update rate of the background model, if the current pixel is foreground
-  //--> Thesis: Our Foreground is a real moving object -> thus the background-model is good, so don't update it
-  double T_dec;
-
-  //holds update rate of current pixel
-  cv::Mat actualT;
-  float* actualT_Pt;
-
-  //#####################################################################################
-
-  cv::Mat sobelX, sobelY;
-};
+  namespace algorithms
+  {
+    namespace pbas
+    {
+      class PBAS
+      {
+      public:
+        PBAS(void);
+        ~PBAS(void);
+        bool process(cv::Mat* input, cv::Mat* output);
+
+        void setN(int);
+        void setRaute_min(int);
+        void setR_lower(double);
+        void setR_incdec(double);
+        void setR_scale(double);
+        void setT_init(double);
+        void setT_lower(double);
+        void setT_upper(double);
+        void setT_dec(double);
+        void setT_inc(double);
+        void setAlpha(double);
+        void setBeta(double);
+
+        bool isMovement();
+
+      private:
+        void calculateFeatures(std::vector<cv::Mat>* feature, cv::Mat* inputImage);
+        void checkValid(int *x, int *y);
+        void decisionThresholdRegulator(float* pt, float* meanDistArr);
+        void learningRateRegulator(float* pt, float* meanDist, uchar* isFore);
+        void init(cv::Mat*);
+        void newInitialization();
+
+        cv::Mat meanMinDist;
+        float* meanMinDist_Pt;
+
+        int width, height;
+        int chans;
+
+        //balance of feature pixel value to conture value
+        double alpha, beta;
+        //##################################################################################
+
+        double formerMeanNorm;
+
+        //define value of foreground/background pixels
+        int foregroundValue, backgroundValue;
+
+        //##################################################################################
+        //random number parameters
+
+        //random number generator
+        cv::RNG randomGenerator;
+
+        //length of random array initialization
+        long countOfRandomNumb;
+
+        //pre - initialize the randomNumbers for better performance
+        std::vector<int> randomN, randomMinDist, randomX, randomY, randomT, randomTN;
+
+        //###################################################################################
+
+        //check if something is moving
+        bool isMove;
+
+        //for init, count number of runs
+        int runs;
+
+        cv::Mat* resultMap;
+        std::vector<cv::Mat> currentFeatures;
+
+        std::vector<float*> currentFeaturesM_Pt;
+        std::vector<uchar*> currentFeaturesC_Pt;
+        uchar* resultMap_Pt;
+
+        std::vector<std::vector<float*>>B_Mag_Pts;
+        std::vector<std::vector<uchar*>>B_Col_Pts;
+
+        double sumMagnitude;
+        double formerMeanMag;
+        //float formerDistanceBack;
+
+        //####################################################################################
+        //N - Number: Defining the size of the background-history-model
+        // number of samples per pixel
+        //size of background history B(x_i)
+        int N;
+        // background model
+        std::vector<std::vector<cv::Mat>> backgroundModel;
+        //####################################################################################
+        //####################################################################################
+        //R-Threshhold - Variables
+        //minimal Threshold for foreground and initial value of R(x_i)
+        // radius of the sphere -> lower border boundary
+        double R_lower;
+
+        //factor which defines new threshold of R(x_i) together with meanMinDist(x_i)
+        // scale for the sphere threshhold to define pixel-based Thresholds
+        double R_scale;
+
+        //decreasing / increasing factor of R(x_i)
+        // increasing/decreasing factor for the r-Threshold based on the result of rTreshScale * meanMinDistBackground
+        double R_incdec;
+
+        cv::Mat actualR;
+        float* actualR_Pt; //new pixel-based r-threshhold -> pointer to arrays
+        //#####################################################################################
+        //####################################################################################
+        //counter for minimal distance to background
+        // Defining the number of background-model-images, which have a lowerDIstance to the current Image than defined by the R-Thresholds, that are necessary
+        // to decide that this pixel is background
+        int Raute_min;
+        //#####################################################################################
+        //####################################################################################
+        //initial value of inverse update factor T(x_i)
+        // Initialize the background-model update rate
+        double T_init;
+
+        //increasing Factor of the update rate 1/T(x_i)
+        // scale that defines the increasing of the update rate of the background model, if the current pixel is background
+        //--> more frequently updates if pixel is background because, there shouln't be any change
+        double T_inc;
+
+        //upper boundary of T(x_i)
+        // defining an upper value, that nrSubsampling can achieve, thus it doesn't reach to an infinite value, where actually no update is possible
+        // at all
+        double T_upper;
+
+        //lower boundary of T(x_i)
+        // defining a minimum value for nrSubsampling --> base value 2.0
+        double T_lower;
+
+        //decreasing factor of the update rate 1/T(x_i)
+        // opposite scale to increasingRateScale, for decreasing the update rate of the background model, if the current pixel is foreground
+        //--> Thesis: Our Foreground is a real moving object -> thus the background-model is good, so don't update it
+        double T_dec;
+
+        //holds update rate of current pixel
+        cv::Mat actualT;
+        float* actualT_Pt;
+
+        //#####################################################################################
+
+        cv::Mat sobelX, sobelY;
+      };
+    }
+  }
+}
diff --git a/src/algorithms/PixelBasedAdaptiveSegmenter.h b/src/algorithms/PixelBasedAdaptiveSegmenter.h
index 65209b010823aebf5665a293963b9ff84c0747e7..02687194013941b9c0dcea056404b9e5bbba45b5 100644
--- a/src/algorithms/PixelBasedAdaptiveSegmenter.h
+++ b/src/algorithms/PixelBasedAdaptiveSegmenter.h
@@ -10,7 +10,7 @@ namespace bgslibrary
     class PixelBasedAdaptiveSegmenter : public IBGS
     {
     private:
-      PBAS pbas;
+      pbas::PBAS pbas;
 
       bool enableInputBlur;
       bool enableOutputBlur;
diff --git a/src/algorithms/SigmaDelta.cpp b/src/algorithms/SigmaDelta.cpp
index 72aae943af06b928015369e0b52a928cfba33c53..1e17b374c32d8eb0f6b65d4889412259471b7c1e 100644
--- a/src/algorithms/SigmaDelta.cpp
+++ b/src/algorithms/SigmaDelta.cpp
@@ -5,7 +5,7 @@ using namespace bgslibrary::algorithms;
 SigmaDelta::SigmaDelta() :
   IBGS(quote(SigmaDelta)),
   ampFactor(1), minVar(15), maxVar(255), 
-  algorithm(sdLaMa091New())
+  algorithm(sigmadelta::sdLaMa091New())
 {
   debug_construction(SigmaDelta);
   initLoadSaveConfig(algorithmName);
@@ -14,7 +14,7 @@ SigmaDelta::SigmaDelta() :
 
 SigmaDelta::~SigmaDelta() {
   debug_destruction(SigmaDelta);
-  sdLaMa091Free(algorithm);
+  sigmadelta::sdLaMa091Free(algorithm);
 }
 
 void SigmaDelta::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
@@ -22,14 +22,14 @@ void SigmaDelta::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat
   init(img_input, img_output, img_bgmodel);
 
   if (firstTime) {
-    sdLaMa091AllocInit_8u_C3R(algorithm, img_input.data, img_input.cols, img_input.rows, img_input.step);
+    sigmadelta::sdLaMa091AllocInit_8u_C3R(algorithm, img_input.data, img_input.cols, img_input.rows, img_input.step);
     img_foreground = cv::Mat(img_input.size(), CV_8UC1);
     img_background = cv::Mat(img_input.size(), CV_8UC3);
     firstTime = false;
   }
   else {
     cv::Mat img_output_tmp(img_input.rows, img_input.cols, CV_8UC3);
-    sdLaMa091Update_8u_C3R(algorithm, img_input.data, img_output_tmp.data);
+    sigmadelta::sdLaMa091Update_8u_C3R(algorithm, img_input.data, img_output_tmp.data);
 
     unsigned char* tmpBuffer = (unsigned char*)img_output_tmp.data;
     unsigned char* outBuffer = (unsigned char*)img_foreground.data;
@@ -65,7 +65,7 @@ void SigmaDelta::load_config(cv::FileStorage &fs) {
 }
 
 void SigmaDelta::applyParams() {
-  sdLaMa091SetAmplificationFactor(algorithm, ampFactor);
-  sdLaMa091SetMinimalVariance(algorithm, minVar);
-  sdLaMa091SetMaximalVariance(algorithm, maxVar);
+  sigmadelta::sdLaMa091SetAmplificationFactor(algorithm, ampFactor);
+  sigmadelta::sdLaMa091SetMinimalVariance(algorithm, minVar);
+  sigmadelta::sdLaMa091SetMaximalVariance(algorithm, maxVar);
 }
diff --git a/src/algorithms/SigmaDelta.h b/src/algorithms/SigmaDelta.h
index f1fb89073296a120a084a1e3e43c025ee8d039c0..adb2a9a7a84d9574294f0f43df1a1473a1a45aca 100644
--- a/src/algorithms/SigmaDelta.h
+++ b/src/algorithms/SigmaDelta.h
@@ -16,7 +16,7 @@ namespace bgslibrary
       int ampFactor;
       int minVar;
       int maxVar;
-      sdLaMa091_t* algorithm;
+      sigmadelta::sdLaMa091_t* algorithm;
 
     public:
       SigmaDelta();
diff --git a/src/algorithms/SigmaDelta/sdLaMa091.cpp b/src/algorithms/SigmaDelta/sdLaMa091.cpp
index 6a8c9a50b037f2e2ae1906fbbcaa435b766a8253..feb8754563311f5ed9ffa919d9fe390506d658dd 100644
--- a/src/algorithms/SigmaDelta/sdLaMa091.cpp
+++ b/src/algorithms/SigmaDelta/sdLaMa091.cpp
@@ -1,641 +1,651 @@
 #include "sdLaMa091.h"
 
-#define DEFAULT_N 1
-#define DEFAULT_VMIN 2
-#define DEFAULT_VMAX 255
-
-#define LIB "sdLaMa091 - "
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define CHANNELS 3
-
-typedef enum {
-  UNKNOWN,
-  C1R,
-  C3R
-} image_t;
-
-struct sdLaMa091 {
-  image_t  imageType;
-
-  uint32_t width;
-  uint32_t rgbWidth;
-  uint32_t height;
-  uint32_t stride;
-  uint32_t numBytes;
-  uint32_t unusedBytes;
-  uint32_t rgbUnusedBytes;
-
-  uint32_t N;
-  uint32_t Vmin;
-  uint32_t Vmax;
-
-  uint8_t* Mt;
-  uint8_t* Ot;
-  uint8_t* Vt;
-};
-
-#if defined(DEFENSIVE_ALLOC) || defined(DEFENSIVE_POINTER) || \
-  defined(DEFENSIVE_PARAM)
-static inline void outputError(char* error);
-#endif
-
-static inline uint8_t absVal(int8_t num);
-static inline uint8_t min(uint8_t a, uint8_t b);
-static inline uint8_t max(uint8_t a, uint8_t b);
-
-#if defined(DEFENSIVE_ALLOC) || defined(DEFENSIVE_POINTER) || \
-  defined(DEFENSIVE_PARAM)
-
-static inline void outputError(char* error) {
-  fprintf(stderr, "%s%s\n", LIB, error);
-}
-#endif
+//using namespace bgslibrary::algorithms::sigmadelta;
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace sigmadelta
+    {
+      const int DEFAULT_N  = 1;
+      const int DEFAULT_VMIN = 2;
+      const int DEFAULT_VMAX = 255;
+
+      const char* LIB = "sdLaMa091 - ";
+      const int RED = 0;
+      const int GREEN = 1;
+      const int BLUE = 2;
+      const int CHANNELS = 3;
+
+      typedef enum {
+        UNKNOWN,
+        C1R,
+        C3R
+      } image_t;
+
+      struct sdLaMa091 {
+        image_t  imageType;
+
+        uint32_t width;
+        uint32_t rgbWidth;
+        uint32_t height;
+        uint32_t stride;
+        uint32_t numBytes;
+        uint32_t unusedBytes;
+        uint32_t rgbUnusedBytes;
+
+        uint32_t N;
+        uint32_t Vmin;
+        uint32_t Vmax;
+
+        uint8_t* Mt;
+        uint8_t* Ot;
+        uint8_t* Vt;
+      };
+
+      #if defined(DEFENSIVE_ALLOC) || defined(DEFENSIVE_POINTER) || \
+        defined(DEFENSIVE_PARAM)
+      static inline void outputError(char* error);
+      #endif
+
+      static inline uint8_t absVal(int8_t num);
+      static inline uint8_t min(uint8_t a, uint8_t b);
+      static inline uint8_t max(uint8_t a, uint8_t b);
+
+      #if defined(DEFENSIVE_ALLOC) || defined(DEFENSIVE_POINTER) || \
+        defined(DEFENSIVE_PARAM)
+
+      static inline void outputError(char* error) {
+        fprintf(stderr, "%s%s\n", LIB, error);
+      }
+      #endif
 
 
-static inline uint8_t absVal(int8_t num) {
-  return (num < 0) ? (uint8_t)-num : (uint8_t)num;
-}
+      static inline uint8_t absVal(int8_t num) {
+        return (num < 0) ? (uint8_t)-num : (uint8_t)num;
+      }
 
-static inline uint8_t min(uint8_t a, uint8_t b) {
-  return (a < b) ? a : b;
-}
+      static inline uint8_t min(uint8_t a, uint8_t b) {
+        return (a < b) ? a : b;
+      }
 
-static inline uint8_t max(uint8_t a, uint8_t b) {
-  return (a > b) ? a : b;
-}
+      static inline uint8_t max(uint8_t a, uint8_t b) {
+        return (a > b) ? a : b;
+      }
 
-sdLaMa091_t* sdLaMa091New(void) {
-  sdLaMa091_t* sdLaMa091 = (sdLaMa091_t*)malloc(sizeof(*sdLaMa091));
+      sdLaMa091_t* sdLaMa091New(void) {
+        sdLaMa091_t* sdLaMa091 = (sdLaMa091_t*)malloc(sizeof(*sdLaMa091));
 
-#ifdef DEFENSIVE_ALLOC
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot allocate sdLaMa091 structure");
-    return NULL;
-  }
-#endif
+      #ifdef DEFENSIVE_ALLOC
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot allocate sdLaMa091 structure");
+          return NULL;
+        }
+      #endif
 
-  sdLaMa091->imageType = UNKNOWN;
+        sdLaMa091->imageType = UNKNOWN;
 
-  sdLaMa091->width = 0;
-  sdLaMa091->rgbWidth = 0;
-  sdLaMa091->height = 0;
-  sdLaMa091->stride = 0;
-  sdLaMa091->numBytes = 0;
-  sdLaMa091->unusedBytes = 0;
-  sdLaMa091->rgbUnusedBytes = 0;
+        sdLaMa091->width = 0;
+        sdLaMa091->rgbWidth = 0;
+        sdLaMa091->height = 0;
+        sdLaMa091->stride = 0;
+        sdLaMa091->numBytes = 0;
+        sdLaMa091->unusedBytes = 0;
+        sdLaMa091->rgbUnusedBytes = 0;
 
-  sdLaMa091->N = DEFAULT_N;
-  sdLaMa091->Vmin = DEFAULT_VMIN;
-  sdLaMa091->Vmax = DEFAULT_VMAX;
+        sdLaMa091->N = DEFAULT_N;
+        sdLaMa091->Vmin = DEFAULT_VMIN;
+        sdLaMa091->Vmax = DEFAULT_VMAX;
 
-  sdLaMa091->Mt = NULL;
-  sdLaMa091->Ot = NULL;
-  sdLaMa091->Vt = NULL;
+        sdLaMa091->Mt = NULL;
+        sdLaMa091->Ot = NULL;
+        sdLaMa091->Vt = NULL;
 
-  return sdLaMa091;
-}
+        return sdLaMa091;
+      }
 
-int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091,
-  const uint8_t* image_data,
-  const uint32_t width,
-  const uint32_t height,
-  const uint32_t stride) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot initialize a NULL structure");
-    return EXIT_FAILURE;
-  }
+      int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091,
+        const uint8_t* image_data,
+        const uint32_t width,
+        const uint32_t height,
+        const uint32_t stride) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot initialize a NULL structure");
+          return EXIT_FAILURE;
+        }
 
-  if (image_data == NULL) {
-    outputError("Cannot allocate ressources for a NULL image");
-    return EXIT_FAILURE;
-  }
-#endif
+        if (image_data == NULL) {
+          outputError("Cannot allocate ressources for a NULL image");
+          return EXIT_FAILURE;
+        }
+      #endif
 
-#ifdef DEFENSIVE_PARAM
-  if (width == 0 || height == 0 || stride == 0) {
-    outputError("Cannot allocate ressources for zero values");
-    return EXIT_FAILURE;
-  }
+      #ifdef DEFENSIVE_PARAM
+        if (width == 0 || height == 0 || stride == 0) {
+          outputError("Cannot allocate ressources for zero values");
+          return EXIT_FAILURE;
+        }
 
-  if (stride < width) {
-    outputError("Cannot allocate ressources for a stride lower than the width");
-    return EXIT_FAILURE;
-  }
-#endif
+        if (stride < width) {
+          outputError("Cannot allocate ressources for a stride lower than the width");
+          return EXIT_FAILURE;
+        }
+      #endif
 
-  sdLaMa091->imageType = C1R;
+        sdLaMa091->imageType = C1R;
 
-  sdLaMa091->width = width;
-  sdLaMa091->height = height;
-  sdLaMa091->stride = stride;
-  sdLaMa091->numBytes = stride * height;
-  sdLaMa091->unusedBytes = stride - sdLaMa091->width;
+        sdLaMa091->width = width;
+        sdLaMa091->height = height;
+        sdLaMa091->stride = stride;
+        sdLaMa091->numBytes = stride * height;
+        sdLaMa091->unusedBytes = stride - sdLaMa091->width;
 
-  sdLaMa091->Mt = (uint8_t*)malloc(sdLaMa091->numBytes);
-#ifdef DEFENSIVE_ALLOC
-  if (sdLaMa091->Mt == NULL) {
-    outputError("Cannot allocate sdLaMa091->Mt table");
-    return EXIT_FAILURE;
-  }
-#endif 
-  memcpy(sdLaMa091->Mt, image_data, sdLaMa091->numBytes);
-
-  sdLaMa091->Ot = (uint8_t*)malloc(sdLaMa091->numBytes);
-#ifdef DEFENSIVE_ALLOC
-  if (sdLaMa091->Ot == NULL) {
-    outputError("Cannot allocate sdLaMa091->Ot table");
-    return EXIT_FAILURE;
-  }
-#endif 
-  uint8_t* workOt = sdLaMa091->Ot;
+        sdLaMa091->Mt = (uint8_t*)malloc(sdLaMa091->numBytes);
+      #ifdef DEFENSIVE_ALLOC
+        if (sdLaMa091->Mt == NULL) {
+          outputError("Cannot allocate sdLaMa091->Mt table");
+          return EXIT_FAILURE;
+        }
+      #endif 
+        memcpy(sdLaMa091->Mt, image_data, sdLaMa091->numBytes);
+
+        sdLaMa091->Ot = (uint8_t*)malloc(sdLaMa091->numBytes);
+      #ifdef DEFENSIVE_ALLOC
+        if (sdLaMa091->Ot == NULL) {
+          outputError("Cannot allocate sdLaMa091->Ot table");
+          return EXIT_FAILURE;
+        }
+      #endif 
+        uint8_t* workOt = sdLaMa091->Ot;
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt)
-      *workOt = 0;
+          for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt)
+            *workOt = 0;
 
 
-    if (sdLaMa091->unusedBytes > 0)
-      workOt += sdLaMa091->unusedBytes;
-  }
+          if (sdLaMa091->unusedBytes > 0)
+            workOt += sdLaMa091->unusedBytes;
+        }
 
-  sdLaMa091->Vt = (uint8_t*)malloc(sdLaMa091->numBytes);
-#ifdef DEFENSIVE_ALLOC
-  if (sdLaMa091->Vt == NULL) {
-    outputError("Cannot allocate sdLaMa091->Vt table");
-    return EXIT_FAILURE;
-  }
-#endif
-  uint8_t* workVt = sdLaMa091->Vt;
+        sdLaMa091->Vt = (uint8_t*)malloc(sdLaMa091->numBytes);
+      #ifdef DEFENSIVE_ALLOC
+        if (sdLaMa091->Vt == NULL) {
+          outputError("Cannot allocate sdLaMa091->Vt table");
+          return EXIT_FAILURE;
+        }
+      #endif
+        uint8_t* workVt = sdLaMa091->Vt;
 
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workVt)
-      *workVt = sdLaMa091->Vmin;
+          for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workVt)
+            *workVt = sdLaMa091->Vmin;
 
 
-    if (sdLaMa091->unusedBytes > 0)
-      workVt += sdLaMa091->unusedBytes;
-  }
+          if (sdLaMa091->unusedBytes > 0)
+            workVt += sdLaMa091->unusedBytes;
+        }
 
-  return EXIT_SUCCESS;
-}
+        return EXIT_SUCCESS;
+      }
 
-int32_t sdLaMa091AllocInit_8u_C3R(sdLaMa091_t* sdLaMa091,
-  const uint8_t* image_data,
-  const uint32_t width,
-  const uint32_t height,
-  const uint32_t stride) {
-  int32_t success = sdLaMa091AllocInit_8u_C1R(sdLaMa091, image_data, width,
-    height, stride);
-
-  if (success == EXIT_SUCCESS) {
-    sdLaMa091->imageType = C3R;
-    sdLaMa091->rgbWidth = sdLaMa091->width * CHANNELS;
-    sdLaMa091->rgbUnusedBytes = stride - sdLaMa091->rgbWidth;
-    sdLaMa091->width = 0;
-    sdLaMa091->unusedBytes = 0;
-  }
+      int32_t sdLaMa091AllocInit_8u_C3R(sdLaMa091_t* sdLaMa091,
+        const uint8_t* image_data,
+        const uint32_t width,
+        const uint32_t height,
+        const uint32_t stride) {
+        int32_t success = sdLaMa091AllocInit_8u_C1R(sdLaMa091, image_data, width,
+          height, stride);
+
+        if (success == EXIT_SUCCESS) {
+          sdLaMa091->imageType = C3R;
+          sdLaMa091->rgbWidth = sdLaMa091->width * CHANNELS;
+          sdLaMa091->rgbUnusedBytes = stride - sdLaMa091->rgbWidth;
+          sdLaMa091->width = 0;
+          sdLaMa091->unusedBytes = 0;
+        }
 
-  return success;
-}
+        return success;
+      }
 
-int32_t sdLaMa091SetAmplificationFactor(sdLaMa091_t* sdLaMa091,
-  const uint32_t amplificationFactor) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot set a parameter of a NULL structure");
-    return EXIT_FAILURE;
-  }
-#endif 
+      int32_t sdLaMa091SetAmplificationFactor(sdLaMa091_t* sdLaMa091,
+        const uint32_t amplificationFactor) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot set a parameter of a NULL structure");
+          return EXIT_FAILURE;
+        }
+      #endif 
 
-#ifdef DEFENSIVE_PARAM
-  if (amplificationFactor == 0) {
-    outputError("Cannot set a parameter with a zero value");
-    return EXIT_FAILURE;
-  }
-#endif 
+      #ifdef DEFENSIVE_PARAM
+        if (amplificationFactor == 0) {
+          outputError("Cannot set a parameter with a zero value");
+          return EXIT_FAILURE;
+        }
+      #endif 
 
-  sdLaMa091->N = amplificationFactor;
+        sdLaMa091->N = amplificationFactor;
 
-  return EXIT_SUCCESS;
-}
+        return EXIT_SUCCESS;
+      }
 
-uint32_t sdLaMa091GetAmplificationFactor(const sdLaMa091_t* sdLaMa091) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot get a parameter of a NULL structure");
-    errno = ERROR_OCCURED;
+      uint32_t sdLaMa091GetAmplificationFactor(const sdLaMa091_t* sdLaMa091) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot get a parameter of a NULL structure");
+          errno = ERROR_OCCURED;
 
-    return EXIT_FAILURE;
-  }
-#endif 
+          return EXIT_FAILURE;
+        }
+      #endif 
 
-  return sdLaMa091->N;
-}
+        return sdLaMa091->N;
+      }
 
-int32_t sdLaMa091SetMaximalVariance(sdLaMa091_t* sdLaMa091,
-  const uint32_t maximalVariance) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot set a parameter of a NULL structure");
-    return EXIT_FAILURE;
-  }
-#endif 
+      int32_t sdLaMa091SetMaximalVariance(sdLaMa091_t* sdLaMa091,
+        const uint32_t maximalVariance) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot set a parameter of a NULL structure");
+          return EXIT_FAILURE;
+        }
+      #endif 
 
-#ifdef DEFENSIVE_PARAM
-  if (maximalVariance == 0) {
-    outputError("Cannot set a parameter with a zero value");
-    return EXIT_FAILURE;
-  }
-#endif 
+      #ifdef DEFENSIVE_PARAM
+        if (maximalVariance == 0) {
+          outputError("Cannot set a parameter with a zero value");
+          return EXIT_FAILURE;
+        }
+      #endif 
 
-  sdLaMa091->Vmax = maximalVariance;
+        sdLaMa091->Vmax = maximalVariance;
 
-  return EXIT_SUCCESS;
-}
+        return EXIT_SUCCESS;
+      }
 
-uint32_t sdLaMa091GetMaximalVariance(const sdLaMa091_t* sdLaMa091) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot get a parameter of a NULL structure");
-    errno = ERROR_OCCURED;
+      uint32_t sdLaMa091GetMaximalVariance(const sdLaMa091_t* sdLaMa091) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot get a parameter of a NULL structure");
+          errno = ERROR_OCCURED;
 
-    return EXIT_FAILURE;
-  }
-#endif
+          return EXIT_FAILURE;
+        }
+      #endif
 
-  return sdLaMa091->Vmax;
-}
+        return sdLaMa091->Vmax;
+      }
 
-int32_t sdLaMa091SetMinimalVariance(sdLaMa091_t* sdLaMa091,
-  const uint32_t minimalVariance) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot set a parameter of a NULL structure");
-    return EXIT_FAILURE;
-  }
-#endif 
+      int32_t sdLaMa091SetMinimalVariance(sdLaMa091_t* sdLaMa091,
+        const uint32_t minimalVariance) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot set a parameter of a NULL structure");
+          return EXIT_FAILURE;
+        }
+      #endif 
 
-  sdLaMa091->Vmin = minimalVariance;
+        sdLaMa091->Vmin = minimalVariance;
 
-  return EXIT_SUCCESS;
-}
+        return EXIT_SUCCESS;
+      }
 
-uint32_t sdLaMa091GetMinimalVariance(const sdLaMa091_t* sdLaMa091) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot get a parameter of a NULL structure");
-    errno = ERROR_OCCURED;
+      uint32_t sdLaMa091GetMinimalVariance(const sdLaMa091_t* sdLaMa091) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot get a parameter of a NULL structure");
+          errno = ERROR_OCCURED;
 
-    return EXIT_FAILURE;
-  }
-#endif 
+          return EXIT_FAILURE;
+        }
+      #endif 
 
-  return sdLaMa091->Vmin;
-}
+        return sdLaMa091->Vmin;
+      }
 
 
-int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091,
-  const uint8_t* image_data,
-  uint8_t* segmentation_map) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot update a NULL structure");
-    return EXIT_FAILURE;
-  }
+      int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091,
+        const uint8_t* image_data,
+        uint8_t* segmentation_map) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot update a NULL structure");
+          return EXIT_FAILURE;
+        }
 
-  if (image_data == NULL) {
-    outputError("Cannot update a structure with a NULL image");
-    return EXIT_FAILURE;
-  }
+        if (image_data == NULL) {
+          outputError("Cannot update a structure with a NULL image");
+          return EXIT_FAILURE;
+        }
 
-  if (segmentation_map == NULL) {
-    outputError("Cannot update a structure with a NULL segmentation map");
-    return EXIT_FAILURE;
-  }
+        if (segmentation_map == NULL) {
+          outputError("Cannot update a structure with a NULL segmentation map");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->Mt == NULL) {
-    outputError("Cannot update a structure with a NULL Mt table");
-    return EXIT_FAILURE;
-  }
+        if (sdLaMa091->Mt == NULL) {
+          outputError("Cannot update a structure with a NULL Mt table");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->Ot == NULL) {
-    outputError("Cannot update a structure with a NULL Ot table");
-    return EXIT_FAILURE;
-  }
+        if (sdLaMa091->Ot == NULL) {
+          outputError("Cannot update a structure with a NULL Ot table");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->Vt == NULL) {
-    outputError("Cannot update a structure with a NULL Vt table");
-    return EXIT_FAILURE;
-  }
-#endif 
+        if (sdLaMa091->Vt == NULL) {
+          outputError("Cannot update a structure with a NULL Vt table");
+          return EXIT_FAILURE;
+        }
+      #endif 
 
-#ifdef DEFENSIVE_PARAM
-  if (sdLaMa091->imageType != C1R) {
-    outputError("Cannot update a structure which is not C1R");
-    return EXIT_FAILURE;
-  }
+      #ifdef DEFENSIVE_PARAM
+        if (sdLaMa091->imageType != C1R) {
+          outputError("Cannot update a structure which is not C1R");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->width == 0 || sdLaMa091->height == 0 ||
-    sdLaMa091->stride == 0) {
-    outputError("Cannot update a structure with zero values");
-    return EXIT_FAILURE;
-  }
+        if (sdLaMa091->width == 0 || sdLaMa091->height == 0 ||
+          sdLaMa091->stride == 0) {
+          outputError("Cannot update a structure with zero values");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->stride < sdLaMa091->width) {
-    outputError("Cannot update a structure with a stride lower than the width");
-    return EXIT_FAILURE;
-  }
+        if (sdLaMa091->stride < sdLaMa091->width) {
+          outputError("Cannot update a structure with a stride lower than the width");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->Vmax < sdLaMa091->Vmin) {
-    outputError("Cannot update a structure with Vmax inferior to Vmin");
-    return EXIT_FAILURE;
-  }
-#endif 
+        if (sdLaMa091->Vmax < sdLaMa091->Vmin) {
+          outputError("Cannot update a structure with Vmax inferior to Vmin");
+          return EXIT_FAILURE;
+        }
+      #endif 
 
 
-  const uint8_t* workImage = image_data;
-  uint8_t* workMt = sdLaMa091->Mt;
+        const uint8_t* workImage = image_data;
+        uint8_t* workMt = sdLaMa091->Mt;
 
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt) {
-      if (*workMt < *workImage)
-        ++(*workMt);
-      else if (*workMt > *workImage)
-        --(*workMt);
-    }
+          for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt) {
+            if (*workMt < *workImage)
+              ++(*workMt);
+            else if (*workMt > *workImage)
+              --(*workMt);
+          }
 
 
-    if (sdLaMa091->unusedBytes > 0) {
-      workImage += sdLaMa091->unusedBytes;
-      workMt += sdLaMa091->unusedBytes;
-    }
-  }
+          if (sdLaMa091->unusedBytes > 0) {
+            workImage += sdLaMa091->unusedBytes;
+            workMt += sdLaMa091->unusedBytes;
+          }
+        }
 
-  workImage = image_data;
-  workMt = sdLaMa091->Mt;
-  uint8_t* workOt = sdLaMa091->Ot;
+        workImage = image_data;
+        workMt = sdLaMa091->Mt;
+        uint8_t* workOt = sdLaMa091->Ot;
 
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt,
-      ++workOt)
-      *workOt = absVal(*workMt - *workImage);
+          for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt,
+            ++workOt)
+            *workOt = absVal(*workMt - *workImage);
 
 
-    if (sdLaMa091->unusedBytes > 0) {
-      workImage += sdLaMa091->unusedBytes;
-      workMt += sdLaMa091->unusedBytes;
-      workOt += sdLaMa091->unusedBytes;
-    }
-  }
+          if (sdLaMa091->unusedBytes > 0) {
+            workImage += sdLaMa091->unusedBytes;
+            workMt += sdLaMa091->unusedBytes;
+            workOt += sdLaMa091->unusedBytes;
+          }
+        }
 
 
-  workOt = sdLaMa091->Ot;
-  uint8_t* workVt = sdLaMa091->Vt;
+        workOt = sdLaMa091->Ot;
+        uint8_t* workVt = sdLaMa091->Vt;
 
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt, ++workVt) {
-      uint32_t ampOt = sdLaMa091->N * *workOt;
+          for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt, ++workVt) {
+            uint32_t ampOt = sdLaMa091->N * *workOt;
 
-      if (*workVt < ampOt)
-        ++(*workVt);
-      else if (*workVt > ampOt)
-        --(*workVt);
+            if (*workVt < ampOt)
+              ++(*workVt);
+            else if (*workVt > ampOt)
+              --(*workVt);
 
-      *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin);
-    }
+            *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin);
+          }
 
 
-    if (sdLaMa091->unusedBytes > 0) {
-      workOt += sdLaMa091->unusedBytes;
-      workVt += sdLaMa091->unusedBytes;
-    }
-  }
+          if (sdLaMa091->unusedBytes > 0) {
+            workOt += sdLaMa091->unusedBytes;
+            workVt += sdLaMa091->unusedBytes;
+          }
+        }
 
 
-  workOt = sdLaMa091->Ot;
-  workVt = sdLaMa091->Vt;
+        workOt = sdLaMa091->Ot;
+        workVt = sdLaMa091->Vt;
 
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++segmentation_map,
-      ++workOt, ++workVt) {
+          for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++segmentation_map,
+            ++workOt, ++workVt) {
 
-      if (*workOt < *workVt)
-        *segmentation_map = BACKGROUND;
-      else
-        *segmentation_map = FOREGROUND;
-    }
+            if (*workOt < *workVt)
+              *segmentation_map = BACKGROUND;
+            else
+              *segmentation_map = FOREGROUND;
+          }
 
 
-    if (sdLaMa091->unusedBytes > 0) {
-      segmentation_map += sdLaMa091->unusedBytes;
-      workOt += sdLaMa091->unusedBytes;
-      workVt += sdLaMa091->unusedBytes;
-    }
-  }
+          if (sdLaMa091->unusedBytes > 0) {
+            segmentation_map += sdLaMa091->unusedBytes;
+            workOt += sdLaMa091->unusedBytes;
+            workVt += sdLaMa091->unusedBytes;
+          }
+        }
 
-  return EXIT_SUCCESS;
-}
+        return EXIT_SUCCESS;
+      }
 
-int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091,
-  const uint8_t* image_data,
-  uint8_t* segmentation_map) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot update a NULL structure");
-    return EXIT_FAILURE;
-  }
+      int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091,
+        const uint8_t* image_data,
+        uint8_t* segmentation_map) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot update a NULL structure");
+          return EXIT_FAILURE;
+        }
 
-  if (image_data == NULL) {
-    outputError("Cannot update a structure with a NULL image");
-    return EXIT_FAILURE;
-  }
+        if (image_data == NULL) {
+          outputError("Cannot update a structure with a NULL image");
+          return EXIT_FAILURE;
+        }
 
-  if (segmentation_map == NULL) {
-    outputError("Cannot update a structure with a NULL segmentation map");
-    return EXIT_FAILURE;
-  }
+        if (segmentation_map == NULL) {
+          outputError("Cannot update a structure with a NULL segmentation map");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->Mt == NULL) {
-    outputError("Cannot update a structure with a NULL Mt table");
-    return EXIT_FAILURE;
-  }
+        if (sdLaMa091->Mt == NULL) {
+          outputError("Cannot update a structure with a NULL Mt table");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->Ot == NULL) {
-    outputError("Cannot update a structure with a NULL Ot table");
-    return EXIT_FAILURE;
-  }
+        if (sdLaMa091->Ot == NULL) {
+          outputError("Cannot update a structure with a NULL Ot table");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->Vt == NULL) {
-    outputError("Cannot update a structure with a NULL Vt table");
-    return EXIT_FAILURE;
-  }
-#endif
+        if (sdLaMa091->Vt == NULL) {
+          outputError("Cannot update a structure with a NULL Vt table");
+          return EXIT_FAILURE;
+        }
+      #endif
 
-#ifdef DEFENSIVE_PARAM
-  if (sdLaMa091->imageType != C3R) {
-    outputError("Cannot update a structure which is not C3R");
-    return EXIT_FAILURE;
-  }
+      #ifdef DEFENSIVE_PARAM
+        if (sdLaMa091->imageType != C3R) {
+          outputError("Cannot update a structure which is not C3R");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->rgbWidth == 0 || sdLaMa091->height == 0 ||
-    sdLaMa091->stride == 0) {
-    outputError("Cannot update a structure with zero values");
-    return EXIT_FAILURE;
-  }
+        if (sdLaMa091->rgbWidth == 0 || sdLaMa091->height == 0 ||
+          sdLaMa091->stride == 0) {
+          outputError("Cannot update a structure with zero values");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->stride < sdLaMa091->rgbWidth) {
-    outputError("Cannot update a structure with a stride lower than the width");
-    return EXIT_FAILURE;
-  }
+        if (sdLaMa091->stride < sdLaMa091->rgbWidth) {
+          outputError("Cannot update a structure with a stride lower than the width");
+          return EXIT_FAILURE;
+        }
 
-  if (sdLaMa091->Vmax < sdLaMa091->Vmin) {
-    outputError("Cannot update a structure with Vmax inferior to Vmin");
-    return EXIT_FAILURE;
-  }
-#endif 
+        if (sdLaMa091->Vmax < sdLaMa091->Vmin) {
+          outputError("Cannot update a structure with Vmax inferior to Vmin");
+          return EXIT_FAILURE;
+        }
+      #endif 
 
 
-  const uint8_t* workImage = image_data;
-  uint8_t* workMt = sdLaMa091->Mt;
+        const uint8_t* workImage = image_data;
+        uint8_t* workMt = sdLaMa091->Mt;
 
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt) {
-      if (*workMt < *workImage)
-        ++(*workMt);
-      else if (*workMt > *workImage)
-        --(*workMt);
-    }
+          for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt) {
+            if (*workMt < *workImage)
+              ++(*workMt);
+            else if (*workMt > *workImage)
+              --(*workMt);
+          }
 
 
-    if (sdLaMa091->rgbUnusedBytes > 0) {
-      workImage += sdLaMa091->rgbUnusedBytes;
-      workMt += sdLaMa091->rgbUnusedBytes;
-    }
-  }
+          if (sdLaMa091->rgbUnusedBytes > 0) {
+            workImage += sdLaMa091->rgbUnusedBytes;
+            workMt += sdLaMa091->rgbUnusedBytes;
+          }
+        }
 
 
-  workImage = image_data;
-  workMt = sdLaMa091->Mt;
-  uint8_t* workOt = sdLaMa091->Ot;
+        workImage = image_data;
+        workMt = sdLaMa091->Mt;
+        uint8_t* workOt = sdLaMa091->Ot;
 
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt,
-      ++workOt)
-      *workOt = absVal(*workMt - *workImage);
+          for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt,
+            ++workOt)
+            *workOt = absVal(*workMt - *workImage);
 
 
-    if (sdLaMa091->rgbUnusedBytes > 0) {
-      workImage += sdLaMa091->rgbUnusedBytes;
-      workMt += sdLaMa091->rgbUnusedBytes;
-      workOt += sdLaMa091->rgbUnusedBytes;
-    }
-  }
+          if (sdLaMa091->rgbUnusedBytes > 0) {
+            workImage += sdLaMa091->rgbUnusedBytes;
+            workMt += sdLaMa091->rgbUnusedBytes;
+            workOt += sdLaMa091->rgbUnusedBytes;
+          }
+        }
 
-  workOt = sdLaMa091->Ot;
-  uint8_t* workVt = sdLaMa091->Vt;
+        workOt = sdLaMa091->Ot;
+        uint8_t* workVt = sdLaMa091->Vt;
 
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) {
-      uint32_t ampOt = sdLaMa091->N * *workOt;
+          for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) {
+            uint32_t ampOt = sdLaMa091->N * *workOt;
 
-      if (*workVt < ampOt)
-        ++(*workVt);
-      else if (*workVt > ampOt)
-        --(*workVt);
+            if (*workVt < ampOt)
+              ++(*workVt);
+            else if (*workVt > ampOt)
+              --(*workVt);
 
-      *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin);
-    }
+            *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin);
+          }
 
 
-    if (sdLaMa091->rgbUnusedBytes > 0) {
-      workOt += sdLaMa091->rgbUnusedBytes;
-      workVt += sdLaMa091->rgbUnusedBytes;
-    }
-  }
+          if (sdLaMa091->rgbUnusedBytes > 0) {
+            workOt += sdLaMa091->rgbUnusedBytes;
+            workVt += sdLaMa091->rgbUnusedBytes;
+          }
+        }
 
-  workOt = sdLaMa091->Ot;
-  workVt = sdLaMa091->Vt;
+        workOt = sdLaMa091->Ot;
+        workVt = sdLaMa091->Vt;
 
 
-  for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
+        for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) {
 
-    uint32_t numColor = 0;
+          uint32_t numColor = 0;
 
-    bool isForeground = false;
+          bool isForeground = false;
 
 
-    for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) {
-      if (*workOt >= *workVt)
-        isForeground = true;
+          for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) {
+            if (*workOt >= *workVt)
+              isForeground = true;
 
 
-      if (numColor == BLUE) {
-        if (isForeground) {
-          *segmentation_map = FOREGROUND;
-          *(++segmentation_map) = FOREGROUND;
-          *(++segmentation_map) = FOREGROUND;
-          ++segmentation_map;
-        }
-        else {
-          *segmentation_map = BACKGROUND;
-          *(++segmentation_map) = BACKGROUND;
-          *(++segmentation_map) = BACKGROUND;
-          ++segmentation_map;
-        }
+            if (numColor == BLUE) {
+              if (isForeground) {
+                *segmentation_map = FOREGROUND;
+                *(++segmentation_map) = FOREGROUND;
+                *(++segmentation_map) = FOREGROUND;
+                ++segmentation_map;
+              }
+              else {
+                *segmentation_map = BACKGROUND;
+                *(++segmentation_map) = BACKGROUND;
+                *(++segmentation_map) = BACKGROUND;
+                ++segmentation_map;
+              }
 
-        isForeground = false;
-      }
+              isForeground = false;
+            }
 
-      numColor = (numColor + 1) % CHANNELS;
-    }
+            numColor = (numColor + 1) % CHANNELS;
+          }
 
 
-    if (sdLaMa091->rgbUnusedBytes > 0) {
-      segmentation_map += sdLaMa091->rgbUnusedBytes;
-      workOt += sdLaMa091->rgbUnusedBytes;
-      workVt += sdLaMa091->rgbUnusedBytes;
-    }
-  }
+          if (sdLaMa091->rgbUnusedBytes > 0) {
+            segmentation_map += sdLaMa091->rgbUnusedBytes;
+            workOt += sdLaMa091->rgbUnusedBytes;
+            workVt += sdLaMa091->rgbUnusedBytes;
+          }
+        }
 
-  return EXIT_SUCCESS;
-}
+        return EXIT_SUCCESS;
+      }
 
-int32_t sdLaMa091Free(sdLaMa091_t* sdLaMa091) {
-#ifdef DEFENSIVE_POINTER
-  if (sdLaMa091 == NULL) {
-    outputError("Cannot free a NULL strucutre");
-    return EXIT_FAILURE;
-  }
-#endif
+      int32_t sdLaMa091Free(sdLaMa091_t* sdLaMa091) {
+      #ifdef DEFENSIVE_POINTER
+        if (sdLaMa091 == NULL) {
+          outputError("Cannot free a NULL strucutre");
+          return EXIT_FAILURE;
+        }
+      #endif
 
-  if (sdLaMa091->Mt != NULL)
-    free(sdLaMa091->Mt);
-  if (sdLaMa091->Ot != NULL)
-    free(sdLaMa091->Ot);
-  if (sdLaMa091->Vt != NULL)
-    free(sdLaMa091->Vt);
+        if (sdLaMa091->Mt != NULL)
+          free(sdLaMa091->Mt);
+        if (sdLaMa091->Ot != NULL)
+          free(sdLaMa091->Ot);
+        if (sdLaMa091->Vt != NULL)
+          free(sdLaMa091->Vt);
 
-  free(sdLaMa091);
+        free(sdLaMa091);
 
-  return EXIT_SUCCESS;
+        return EXIT_SUCCESS;
+      }
+    }
+  }
 }
diff --git a/src/algorithms/SigmaDelta/sdLaMa091.h b/src/algorithms/SigmaDelta/sdLaMa091.h
index 996c1b9405cb14a17407e7327764562128dc9fe2..84eeecb82c725586a758e8b27055f46707dbe6b5 100644
--- a/src/algorithms/SigmaDelta/sdLaMa091.h
+++ b/src/algorithms/SigmaDelta/sdLaMa091.h
@@ -6,47 +6,56 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define BACKGROUND 0
-#define FOREGROUND 255
-#define ERROR_OCCURED 1
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace sigmadelta
+    {
+      const int BACKGROUND = 0;
+      const int FOREGROUND = 255;
+      const int ERROR_OCCURED = 1;
 
-typedef struct sdLaMa091 sdLaMa091_t;
+      typedef struct sdLaMa091 sdLaMa091_t;
 
-sdLaMa091_t* sdLaMa091New(void);
+      sdLaMa091_t* sdLaMa091New(void);
 
-int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091,
-  const uint8_t* image_data,
-  const uint32_t width,
-  const uint32_t height,
-  const uint32_t stride);
+      int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091,
+        const uint8_t* image_data,
+        const uint32_t width,
+        const uint32_t height,
+        const uint32_t stride);
 
-int32_t sdLaMa091AllocInit_8u_C3R(sdLaMa091_t* sdLaMa091,
-  const uint8_t* image_data,
-  const uint32_t width,
-  const uint32_t height,
-  const uint32_t stride);
+      int32_t sdLaMa091AllocInit_8u_C3R(sdLaMa091_t* sdLaMa091,
+        const uint8_t* image_data,
+        const uint32_t width,
+        const uint32_t height,
+        const uint32_t stride);
 
-int32_t sdLaMa091SetAmplificationFactor(sdLaMa091_t* sdLaMa091,
-  const uint32_t amplificationFactor);
+      int32_t sdLaMa091SetAmplificationFactor(sdLaMa091_t* sdLaMa091,
+        const uint32_t amplificationFactor);
 
-uint32_t sdLaMa091GetAmplificationFactor(const sdLaMa091_t* sdLaMa091);
+      uint32_t sdLaMa091GetAmplificationFactor(const sdLaMa091_t* sdLaMa091);
 
-int32_t sdLaMa091SetMaximalVariance(sdLaMa091_t* sdLaMa091,
-  const uint32_t maximalVariance);
+      int32_t sdLaMa091SetMaximalVariance(sdLaMa091_t* sdLaMa091,
+        const uint32_t maximalVariance);
 
-uint32_t sdLaMa091GetMaximalVariance(const sdLaMa091_t* sdLaMa091);
+      uint32_t sdLaMa091GetMaximalVariance(const sdLaMa091_t* sdLaMa091);
 
-int32_t sdLaMa091SetMinimalVariance(sdLaMa091_t* sdLaMa091,
-  const uint32_t minimalVariance);
+      int32_t sdLaMa091SetMinimalVariance(sdLaMa091_t* sdLaMa091,
+        const uint32_t minimalVariance);
 
-uint32_t sdLaMa091GetMinimalVariance(const sdLaMa091_t* sdLaMa091);
+      uint32_t sdLaMa091GetMinimalVariance(const sdLaMa091_t* sdLaMa091);
 
-int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091,
-  const uint8_t* image_data,
-  uint8_t* segmentation_map);
+      int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091,
+        const uint8_t* image_data,
+        uint8_t* segmentation_map);
 
-int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091,
-  const uint8_t* image_data,
-  uint8_t* segmentation_map);
+      int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091,
+        const uint8_t* image_data,
+        uint8_t* segmentation_map);
 
-int32_t sdLaMa091Free(sdLaMa091_t* sdLaMa091);
+      int32_t sdLaMa091Free(sdLaMa091_t* sdLaMa091);
+    }
+  }
+}
diff --git a/src/algorithms/SuBSENSE.cpp b/src/algorithms/SuBSENSE.cpp
index f753a8dbb67a4a540f5000a641875235c204a7a7..c9429023ecc53f9e266ba959ca143192b2311258 100644
--- a/src/algorithms/SuBSENSE.cpp
+++ b/src/algorithms/SuBSENSE.cpp
@@ -5,12 +5,12 @@ using namespace bgslibrary::algorithms;
 SuBSENSE::SuBSENSE() :
   IBGS(quote(SuBSENSE)),
   pSubsense(0),
-  fRelLBSPThreshold(BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD),
-  nDescDistThresholdOffset(BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET),
-  nMinColorDistThreshold(BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD),
-  nBGSamples(BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES),
-  nRequiredBGSamples(BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES),
-  nSamplesForMovingAvgs(BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS)
+  fRelLBSPThreshold(lbsp::BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD),
+  nDescDistThresholdOffset(lbsp::BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET),
+  nMinColorDistThreshold(lbsp::BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD),
+  nBGSamples(lbsp::BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES),
+  nRequiredBGSamples(lbsp::BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES),
+  nSamplesForMovingAvgs(lbsp::BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS)
 {
   debug_construction(SuBSENSE);
   initLoadSaveConfig(algorithmName);
@@ -27,7 +27,7 @@ void SuBSENSE::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &i
   init(img_input, img_output, img_bgmodel);
 
   if (firstTime) {
-    pSubsense = new BackgroundSubtractorSuBSENSE(
+    pSubsense = new lbsp::BackgroundSubtractorSuBSENSE(
       fRelLBSPThreshold, nDescDistThresholdOffset, nMinColorDistThreshold,
       nBGSamples, nRequiredBGSamples, nSamplesForMovingAvgs);
 
diff --git a/src/algorithms/SuBSENSE.h b/src/algorithms/SuBSENSE.h
index 73edc268061553410046b6684e946b7799ba023f..e309776da5a607d8f8c10ecf5fc4402a94b54526 100644
--- a/src/algorithms/SuBSENSE.h
+++ b/src/algorithms/SuBSENSE.h
@@ -10,7 +10,7 @@ namespace bgslibrary
     class SuBSENSE : public IBGS
     {
     private:
-      BackgroundSubtractorSuBSENSE* pSubsense;
+      lbsp::BackgroundSubtractorSuBSENSE* pSubsense;
 
       float fRelLBSPThreshold;
       int nDescDistThresholdOffset;
diff --git a/src/algorithms/T2F/FuzzyUtils.h b/src/algorithms/T2F/FuzzyUtils.h
deleted file mode 100644
index 43918535957ddb34827eb8f8ecfad3b8c7c62663..0000000000000000000000000000000000000000
--- a/src/algorithms/T2F/FuzzyUtils.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-#include "../../tools/PixelUtils.h"
-
-class FuzzyUtils
-{
-public:
-  FuzzyUtils(void);
-  ~FuzzyUtils(void);
-
-  void LBP(IplImage* InputImage, IplImage* LBP);
-  void getBinValue(float* neighberGrayPixel, float* BinaryValue, int m, int n);
-
-  void SimilarityDegreesImage(IplImage* CurrentImage, IplImage* BGImage, IplImage* DeltaImage, int n, int color_space);
-  void RatioPixels(float* CurrentPixel, float* BGPixel, float* DeltaPixel, int n);
-
-  void getFuzzyIntegralSugeno(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage);
-  void getFuzzyIntegralChoquet(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage);
-  void FuzzyMeasureG(float g1, float g2, float g3, float *G);
-  void Trier(float* g, int n, int* index);
-  float min(float *a, float *b);
-  float max(float *g, int n);
-  void gDeDeux(float* a, float* b, float* lambda);
-  void getLambda(float* g);
-
-  void AdaptativeSelectiveBackgroundModelUpdate(IplImage* CurrentImage, IplImage* BGImage, IplImage* OutputImage, IplImage* Integral, float seuil, float alpha);
-};
diff --git a/src/algorithms/T2F/MRF.cpp b/src/algorithms/T2F/MRF.cpp
index aeaa0d19ea0a7d49e50404e741489e023deb2b25..2d6d18b4f5c306de93922582c39bbf9a6daf6d69 100644
--- a/src/algorithms/T2F/MRF.cpp
+++ b/src/algorithms/T2F/MRF.cpp
@@ -2,7 +2,7 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+using namespace bgslibrary::algorithms::dp;
 
 //init the basic MRF
 MRF::MRF()
diff --git a/src/algorithms/T2F/MRF.h b/src/algorithms/T2F/MRF.h
index 82fd283d6f2713d0355eed1dbc12c0a5ffb48746..2f773c86cb47311d0508e48bfece28c84ade9074 100644
--- a/src/algorithms/T2F/MRF.h
+++ b/src/algorithms/T2F/MRF.h
@@ -5,88 +5,91 @@
 
 #include "T2FMRF.h"
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
-    // base class
-    class MRF
+    namespace dp
     {
-    public:
-      IplImage *in_image, *out_image;
-      //image's width and height
-      int width, height;
+      // base class
+      class MRF
+      {
+      public:
+        IplImage *in_image, *out_image;
+        //image's width and height
+        int width, height;
 
-    public:
-      MRF();
+      public:
+        MRF();
 
-    protected:
+      protected:
 
-      //////////////////////////////////////////////////////////////////////////
-      //the number of labeling
-      int no_regions;
-      //potential of Space  Constraint
-      double beta;
-      //terminal condition when (deltaE < t)
-      double t;
+        //////////////////////////////////////////////////////////////////////////
+        //the number of labeling
+        int no_regions;
+        //potential of Space  Constraint
+        double beta;
+        //terminal condition when (deltaE < t)
+        double t;
 
-      //////////////////////////////////////////////////////////////////////////
-      //for gibbs
-      double T0;
-      //current temperature
-      double T;
-      double c;
+        //////////////////////////////////////////////////////////////////////////
+        //for gibbs
+        double T0;
+        //current temperature
+        double T;
+        double c;
 
-      //////////////////////////////////////////////////////////////////////////
-      // alpha value for MMD
-      double alpha;
+        //////////////////////////////////////////////////////////////////////////
+        // alpha value for MMD
+        double alpha;
 
-      //////////////////////////////////////////////////////////////////////////
-      //current global energy
-      double E;
-      //old global energy
-      double E_old;
-      //number of iteration
-      int K;
+        //////////////////////////////////////////////////////////////////////////
+        //current global energy
+        double E;
+        //old global energy
+        double E_old;
+        //number of iteration
+        int K;
 
-      //////////////////////////////////////////////////////////////////////////
-      //labeling image
-      int **classes;
-      //input image
-      int **in_image_data;
-      //evidence
-      float ** local_evidence;
-    };
+        //////////////////////////////////////////////////////////////////////////
+        //labeling image
+        int **classes;
+        //input image
+        int **in_image_data;
+        //evidence
+        float ** local_evidence;
+      };
 
-    /************************************************************************/
-    /* the Markov Random Field with time constraints for T2FGMM   */
-    /************************************************************************/
-    class MRF_TC : public MRF
-    {
-    private:
-      double beta_time;
+      /************************************************************************/
+      /* the Markov Random Field with time constraints for T2FGMM   */
+      /************************************************************************/
+      class MRF_TC : public MRF
+      {
+      private:
+        double beta_time;
 
-    public:
-      IplImage *background2;
-      RgbImage background;
-      int **old_labeling;
+      public:
+        IplImage *background2;
+        RgbImage background;
+        int **old_labeling;
 
-    public:
-      MRF_TC();
-      ~MRF_TC();
-      double TimeEnergy2(int i, int j, int label);
-      void OnIterationOver2(void);
-      void Build_Classes_OldLabeling_InImage_LocalEnergy();
-      void InitEvidence2(GMM *gmm, HMM *hmm, IplImage *labeling);
-      void CreateOutput2();
-      double CalculateEnergy2();
-      double LocalEnergy2(int i, int j, int label);
-      double Doubleton2(int i, int j, int label);
+      public:
+        MRF_TC();
+        ~MRF_TC();
+        double TimeEnergy2(int i, int j, int label);
+        void OnIterationOver2(void);
+        void Build_Classes_OldLabeling_InImage_LocalEnergy();
+        void InitEvidence2(GMM *gmm, HMM *hmm, IplImage *labeling);
+        void CreateOutput2();
+        double CalculateEnergy2();
+        double LocalEnergy2(int i, int j, int label);
+        double Doubleton2(int i, int j, int label);
 
-      void Gibbs2();
-      void ICM2();
-      void Metropolis2(bool mmd);
-    };
+        void Gibbs2();
+        void ICM2();
+        void Metropolis2(bool mmd);
+      };
+    }
   }
 }
 
diff --git a/src/algorithms/T2F/T2FGMM.cpp b/src/algorithms/T2F/T2FGMM.cpp
index abba7129770d8aec7496873f723f026c7217a775..7d7b35e4f95d6e1a53258cefbf52c1e9b1d6d618 100644
--- a/src/algorithms/T2F/T2FGMM.cpp
+++ b/src/algorithms/T2F/T2FGMM.cpp
@@ -2,311 +2,320 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+//using namespace bgslibrary::algorithms::dp;
 
-int compareT2FGMM(const void* _gmm1, const void* _gmm2)
+namespace bgslibrary
 {
-  GMM gmm1 = *(GMM*)_gmm1;
-  GMM gmm2 = *(GMM*)_gmm2;
-
-  if (gmm1.significants < gmm2.significants)
-    return 1;
-  else if (gmm1.significants == gmm2.significants)
-    return 0;
-  else
-    return -1;
-}
-
-T2FGMM::T2FGMM()
-{
-  m_modes = NULL;
-}
-
-T2FGMM::~T2FGMM()
-{
-  delete[] m_modes;
-}
-
-void T2FGMM::Initalize(const BgsParams& param)
-{
-  m_params = (T2FGMMParams&)param;
-
-  // Tbf - the threshold
-  m_bg_threshold = 0.75f;	// 1-cf from the paper
-
-  // Tgenerate - the threshold
-  m_variance = 36.0f;		// sigma for the new mode
-
-  // GMM for each pixel
-  m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
-
-  // used modes per pixel
-  m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
-
-  m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+  namespace algorithms
+  {
+    namespace dp
+    {
+      int compareT2FGMM(const void* _gmm1, const void* _gmm2)
+      {
+        GMM gmm1 = *(GMM*)_gmm1;
+        GMM gmm2 = *(GMM*)_gmm2;
 
-  // Factor control for the T2FGMM-UM [0,3]
-  //km = (float) 1.5;
-  km = (float)m_params.KM();
+        if (gmm1.significants < gmm2.significants)
+          return 1;
+        else if (gmm1.significants == gmm2.significants)
+          return 0;
+        else
+          return -1;
+      }
 
-  // Factor control for the T2FGMM-UV [0.3,1]
-  //kv = (float) 0.6;
-  kv = (float)m_params.KV();
-}
+      T2FGMM::T2FGMM()
+      {
+        m_modes = NULL;
+      }
 
-RgbImage* T2FGMM::Background()
-{
-  return &m_background;
-}
+      T2FGMM::~T2FGMM()
+      {
+        delete[] m_modes;
+      }
 
-void T2FGMM::InitModel(const RgbImage& data)
-{
-  m_modes_per_pixel.Clear();
+      void T2FGMM::Initalize(const BgsParams& param)
+      {
+        m_params = (T2FGMMParams&)param;
 
-  for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
-  {
-    m_modes[i].weight = 0;
-    m_modes[i].variance = 0;
-    m_modes[i].muR = 0;
-    m_modes[i].muG = 0;
-    m_modes[i].muB = 0;
-    m_modes[i].significants = 0;
-  }
-}
+        // Tbf - the threshold
+        m_bg_threshold = 0.75f;	// 1-cf from the paper
 
-void T2FGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask)
-{
-  // it doesn't make sense to have conditional updates in the GMM framework
-}
+        // Tgenerate - the threshold
+        m_variance = 36.0f;		// sigma for the new mode
 
-void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes,
-  unsigned char& low_threshold, unsigned char& high_threshold)
-{
-  // calculate distances to the modes (+ sort???)
-  // here we need to go in descending order!!!
-  long pos;
-  bool bFitsPDF = false;
-  bool bBackgroundLow = false;
-  bool bBackgroundHigh = false;
-
-  float fOneMinAlpha = 1 - m_params.Alpha();
-  float totalWeight = 0.0f;
-
-  // calculate number of Gaussians to include in the background model
-  int backgroundGaussians = 0;
-  double sum = 0.0;
-  for (int i = 0; i < numModes; ++i)
-  {
-    if (sum < m_bg_threshold)
-    {
-      backgroundGaussians++;
-      sum += m_modes[posPixel + i].weight;
-    }
-    else
-      break;
-  }
+        // GMM for each pixel
+        m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
 
-  // update all distributions and check for match with current pixel
-  for (int iModes = 0; iModes < numModes; iModes++)
-  {
-    pos = posPixel + iModes;
-    float weight = m_modes[pos].weight;
+        // used modes per pixel
+        m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
 
-    // fit not found yet
-    if (!bFitsPDF)
-    {
-      //check if it belongs to some of the modes
-      //calculate distance
-      float var = m_modes[pos].variance;
-      float muR = m_modes[pos].muR;
-      float muG = m_modes[pos].muG;
-      float muB = m_modes[pos].muB;
-
-      //float km = 2;
-      //float kv = 0.9;
-
-      float dR = fabs(muR - pixel(0));
-      float dG = fabs(muG - pixel(1));
-      float dB = fabs(muB - pixel(2));
-
-      // calculate the squared distance
-      float HR;
-      float HG;
-      float HB;
-
-      // T2FGMM-UM
-      if (m_params.Type() == TYPE_T2FGMM_UM)
-      {
-        if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var))
-          HR = 2 * km*dR / var;
-        else
-          HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2;
+        m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
 
-        if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var))
-          HG = 2 * km*dG / var;
-        else
-          HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2;
+        // Factor control for the T2FGMM-UM [0,3]
+        //km = (float) 1.5;
+        km = (float)m_params.KM();
 
-        if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var))
-          HB = 2 * km*dB / var;
-        else
-          HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2;
+        // Factor control for the T2FGMM-UV [0.3,1]
+        //kv = (float) 0.6;
+        kv = (float)m_params.KV();
       }
 
-      // T2FGMM-UV
-      if (m_params.Type() == TYPE_T2FGMM_UV)
+      RgbImage* T2FGMM::Background()
       {
-        HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var);
-        HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var);
-        HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var);
+        return &m_background;
       }
 
-      // calculate the squared distance
-      float dist = (HR*HR + HG*HG + HB*HB);
+      void T2FGMM::InitModel(const RgbImage& data)
+      {
+        m_modes_per_pixel.Clear();
 
-      if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
-        bBackgroundHigh = true;
+        for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
+        {
+          m_modes[i].weight = 0;
+          m_modes[i].variance = 0;
+          m_modes[i].muR = 0;
+          m_modes[i].muG = 0;
+          m_modes[i].muB = 0;
+          m_modes[i].significants = 0;
+        }
+      }
 
-      // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution
-      if (dist < m_params.LowThreshold()*var)
+      void T2FGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask)
       {
-        bFitsPDF = true;
-
-        // check if this Gaussian is part of the background model
-        if (iModes < backgroundGaussians)
-          bBackgroundLow = true;
-
-        //update distribution
-        float k = m_params.Alpha() / weight;
-        weight = fOneMinAlpha*weight + m_params.Alpha();
-        m_modes[pos].weight = weight;
-        m_modes[pos].muR = muR - k*(dR);
-        m_modes[pos].muG = muG - k*(dG);
-        m_modes[pos].muB = muB - k*(dB);
-
-        //limit the variance
-        float sigmanew = var + k*(dist - var);
-        m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew;
-        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+        // it doesn't make sense to have conditional updates in the GMM framework
       }
-      else
+
+      void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes,
+        unsigned char& low_threshold, unsigned char& high_threshold)
       {
-        weight = fOneMinAlpha*weight;
-        if (weight < 0.0)
+        // calculate distances to the modes (+ sort???)
+        // here we need to go in descending order!!!
+        long pos;
+        bool bFitsPDF = false;
+        bool bBackgroundLow = false;
+        bool bBackgroundHigh = false;
+
+        float fOneMinAlpha = 1 - m_params.Alpha();
+        float totalWeight = 0.0f;
+
+        // calculate number of Gaussians to include in the background model
+        int backgroundGaussians = 0;
+        double sum = 0.0;
+        for (int i = 0; i < numModes; ++i)
         {
-          weight = 0.0;
-          numModes--;
+          if (sum < m_bg_threshold)
+          {
+            backgroundGaussians++;
+            sum += m_modes[posPixel + i].weight;
+          }
+          else
+            break;
         }
 
-        m_modes[pos].weight = weight;
-        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
-      }
-    }
-    else
-    {
-      weight = fOneMinAlpha*weight;
-      if (weight < 0.0)
-      {
-        weight = 0.0;
-        numModes--;
-      }
-      m_modes[pos].weight = weight;
-      m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
-    }
-
-    totalWeight += weight;
-  }
+        // update all distributions and check for match with current pixel
+        for (int iModes = 0; iModes < numModes; iModes++)
+        {
+          pos = posPixel + iModes;
+          float weight = m_modes[pos].weight;
+
+          // fit not found yet
+          if (!bFitsPDF)
+          {
+            //check if it belongs to some of the modes
+            //calculate distance
+            float var = m_modes[pos].variance;
+            float muR = m_modes[pos].muR;
+            float muG = m_modes[pos].muG;
+            float muB = m_modes[pos].muB;
+
+            //float km = 2;
+            //float kv = 0.9;
+
+            float dR = fabs(muR - pixel(0));
+            float dG = fabs(muG - pixel(1));
+            float dB = fabs(muB - pixel(2));
+
+            // calculate the squared distance
+            float HR;
+            float HG;
+            float HB;
+
+            // T2FGMM-UM
+            if (m_params.Type() == TYPE_T2FGMM_UM)
+            {
+              if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var))
+                HR = 2 * km*dR / var;
+              else
+                HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2;
+
+              if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var))
+                HG = 2 * km*dG / var;
+              else
+                HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2;
+
+              if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var))
+                HB = 2 * km*dB / var;
+              else
+                HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2;
+            }
+
+            // T2FGMM-UV
+            if (m_params.Type() == TYPE_T2FGMM_UV)
+            {
+              HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var);
+              HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var);
+              HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var);
+            }
+
+            // calculate the squared distance
+            float dist = (HR*HR + HG*HG + HB*HB);
+
+            if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
+              bBackgroundHigh = true;
+
+            // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution
+            if (dist < m_params.LowThreshold()*var)
+            {
+              bFitsPDF = true;
+
+              // check if this Gaussian is part of the background model
+              if (iModes < backgroundGaussians)
+                bBackgroundLow = true;
+
+              //update distribution
+              float k = m_params.Alpha() / weight;
+              weight = fOneMinAlpha*weight + m_params.Alpha();
+              m_modes[pos].weight = weight;
+              m_modes[pos].muR = muR - k*(dR);
+              m_modes[pos].muG = muG - k*(dG);
+              m_modes[pos].muB = muB - k*(dB);
+
+              //limit the variance
+              float sigmanew = var + k*(dist - var);
+              m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew;
+              m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+            }
+            else
+            {
+              weight = fOneMinAlpha*weight;
+              if (weight < 0.0)
+              {
+                weight = 0.0;
+                numModes--;
+              }
+
+              m_modes[pos].weight = weight;
+              m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+            }
+          }
+          else
+          {
+            weight = fOneMinAlpha*weight;
+            if (weight < 0.0)
+            {
+              weight = 0.0;
+              numModes--;
+            }
+            m_modes[pos].weight = weight;
+            m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+          }
+
+          totalWeight += weight;
+        }
 
-  // renormalize weights so they add to one
-  double invTotalWeight = 1.0 / totalWeight;
-  for (int iLocal = 0; iLocal < numModes; iLocal++)
-  {
-    m_modes[posPixel + iLocal].weight *= (float)invTotalWeight;
-    m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight
-      / sqrt(m_modes[posPixel + iLocal].variance);
-  }
+        // renormalize weights so they add to one
+        double invTotalWeight = 1.0 / totalWeight;
+        for (int iLocal = 0; iLocal < numModes; iLocal++)
+        {
+          m_modes[posPixel + iLocal].weight *= (float)invTotalWeight;
+          m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight
+            / sqrt(m_modes[posPixel + iLocal].variance);
+        }
 
-  // Sort significance values so they are in desending order.
-  qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareT2FGMM);
+        // Sort significance values so they are in desending order.
+        qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareT2FGMM);
 
-  // make new mode if needed and exit
-  if (!bFitsPDF)
-  {
-    if (numModes < m_params.MaxModes())
-      numModes++;
-    //else
-    // the weakest mode will be replaced
-
-    pos = posPixel + numModes - 1;
-
-    m_modes[pos].muR = pixel.ch[0];
-    m_modes[pos].muG = pixel.ch[1];
-    m_modes[pos].muB = pixel.ch[2];
-    m_modes[pos].variance = m_variance;
-    m_modes[pos].significants = 0;			// will be set below
-
-    if (numModes == 1)
-      m_modes[pos].weight = 1;
-    else
-      m_modes[pos].weight = m_params.Alpha();
-
-    //renormalize weights
-    int iLocal;
-    float sum = 0.0;
-    for (iLocal = 0; iLocal < numModes; iLocal++)
-      sum += m_modes[posPixel + iLocal].weight;
-
-    double invSum = 1.0 / sum;
-    for (iLocal = 0; iLocal < numModes; iLocal++)
-    {
-      m_modes[posPixel + iLocal].weight *= (float)invSum;
-      m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posPixel + iLocal].variance);
-    }
-  }
+        // make new mode if needed and exit
+        if (!bFitsPDF)
+        {
+          if (numModes < m_params.MaxModes())
+            numModes++;
+          //else
+          // the weakest mode will be replaced
+
+          pos = posPixel + numModes - 1;
+
+          m_modes[pos].muR = pixel.ch[0];
+          m_modes[pos].muG = pixel.ch[1];
+          m_modes[pos].muB = pixel.ch[2];
+          m_modes[pos].variance = m_variance;
+          m_modes[pos].significants = 0;			// will be set below
+
+          if (numModes == 1)
+            m_modes[pos].weight = 1;
+          else
+            m_modes[pos].weight = m_params.Alpha();
+
+          //renormalize weights
+          int iLocal;
+          float sum = 0.0;
+          for (iLocal = 0; iLocal < numModes; iLocal++)
+            sum += m_modes[posPixel + iLocal].weight;
+
+          double invSum = 1.0 / sum;
+          for (iLocal = 0; iLocal < numModes; iLocal++)
+          {
+            m_modes[posPixel + iLocal].weight *= (float)invSum;
+            m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posPixel + iLocal].variance);
+          }
+        }
 
-  // Sort significance values so they are in desending order.
-  qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareT2FGMM);
+        // Sort significance values so they are in desending order.
+        qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareT2FGMM);
 
-  if (bBackgroundLow)
-    low_threshold = BACKGROUND;
-  else
-    low_threshold = FOREGROUND;
+        if (bBackgroundLow)
+          low_threshold = BACKGROUND;
+        else
+          low_threshold = FOREGROUND;
 
-  if (bBackgroundHigh)
-    high_threshold = BACKGROUND;
-  else
-    high_threshold = FOREGROUND;
-}
+        if (bBackgroundHigh)
+          high_threshold = BACKGROUND;
+        else
+          high_threshold = FOREGROUND;
+      }
 
-///////////////////////////////////////////////////////////////////////////////
-//Input:
-//  data - a pointer to the data of a RGB image of the same size
-//Output:
-//  output - a pointer to the data of a gray value image of the same size 
-//					(the memory should already be reserved) 
-//					values: 255-foreground, 125-shadow, 0-background
-///////////////////////////////////////////////////////////////////////////////
-void T2FGMM::Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask)
-{
-  unsigned char low_threshold, high_threshold;
-  long posPixel;
+      ///////////////////////////////////////////////////////////////////////////////
+      //Input:
+      //  data - a pointer to the data of a RGB image of the same size
+      //Output:
+      //  output - a pointer to the data of a gray value image of the same size 
+      //					(the memory should already be reserved) 
+      //					values: 255-foreground, 125-shadow, 0-background
+      ///////////////////////////////////////////////////////////////////////////////
+      void T2FGMM::Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+      {
+        unsigned char low_threshold, high_threshold;
+        long posPixel;
 
-  // update each pixel of the image
-  for (unsigned int r = 0; r < m_params.Height(); ++r)
-  {
-    for (unsigned int c = 0; c < m_params.Width(); ++c)
-    {
-      // update model + background subtract
-      posPixel = (r*m_params.Width() + c) * m_params.MaxModes();
+        // update each pixel of the image
+        for (unsigned int r = 0; r < m_params.Height(); ++r)
+        {
+          for (unsigned int c = 0; c < m_params.Width(); ++c)
+          {
+            // update model + background subtract
+            posPixel = (r*m_params.Width() + c) * m_params.MaxModes();
 
-      SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold);
+            SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold);
 
-      low_threshold_mask(r, c) = low_threshold;
-      high_threshold_mask(r, c) = high_threshold;
+            low_threshold_mask(r, c) = low_threshold;
+            high_threshold_mask(r, c) = high_threshold;
 
-      m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR;
-      m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG;
-      m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB;
+            m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR;
+            m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG;
+            m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB;
+          }
+        }
+      }
     }
   }
 }
diff --git a/src/algorithms/T2F/T2FGMM.h b/src/algorithms/T2F/T2FGMM.h
index 5c13069911be09f185c3d9c961e24cca6e09f352..4a7cfc38414fec28e34deaf442d90910b6df2608 100644
--- a/src/algorithms/T2F/T2FGMM.h
+++ b/src/algorithms/T2F/T2FGMM.h
@@ -6,101 +6,104 @@
 #include "../dp/Bgs.h"
 #include "../dp/GrimsonGMM.h"
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
-    const int TYPE_T2FGMM_UM = 0;
-    const int TYPE_T2FGMM_UV = 1;
-
-    // --- User adjustable parameters used by the T2F GMM BGS algorithm ---
-    class T2FGMMParams : public BgsParams
-    {
-    public:
-      float &LowThreshold() { return m_low_threshold; }
-      float &HighThreshold() { return m_high_threshold; }
-
-      float &Alpha() { return m_alpha; }
-      int &MaxModes() { return m_max_modes; }
-      int &Type() { return m_type; }
-      float &KM() { return m_km; }
-      float &KV() { return m_kv; }
-
-    private:
-      // Threshold on the squared dist. to decide when a sample is close to an existing
-      // components. If it is not close to any a new component will be generated.
-      // Smaller threshold values lead to more generated components and higher threshold values
-      // lead to a small number of components but they can grow too large.
-      //
-      // It is usual easiest to think of these thresholds as being the number of variances away
-      // from the mean of a pixel before it is considered to be from the foreground.
-      float m_low_threshold;
-      float m_high_threshold;
-
-      // alpha - speed of update - if the time interval you want to average over is T
-      // set alpha=1/T.
-      float m_alpha;
-
-      // Maximum number of modes (Gaussian components) that will be used per pixel
-      int m_max_modes;
-
-      // T2FGMM_UM / T2FGMM_UV
-      int m_type;
-
-      // Factor control for the T2FGMM-UM
-      float m_km;
-
-      // Factor control for the T2FGMM-UV
-      float m_kv;
-    };
-
-    // --- T2FGMM BGS algorithm ---
-    class T2FGMM : public Bgs
+    namespace dp
     {
-    public:
-      T2FGMM();
-      ~T2FGMM();
-
-      void Initalize(const BgsParams& param);
-
-      void InitModel(const RgbImage& data);
-      void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask);
-      void Update(int frame_num, const RgbImage& data, const BwImage& update_mask);
-
-      RgbImage* Background();
-
-    private:
-      void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold);
-
-      // User adjustable parameters
-      T2FGMMParams m_params;
-
-      // Threshold when the component becomes significant enough to be included into
-      // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9
-      // For alpha=0.001 it means that the mode should exist for approximately 105 frames before
-      // it is considered foreground
-      float m_bg_threshold; //1-cf from the paper
-
-      // Initial variance for the newly generated components.
-      // It will will influence the speed of adaptation. A good guess should be made.
-      // A simple way is to estimate the typical standard deviation from the images.
-      float m_variance;
-
-      // Dynamic array for the mixture of Gaussians
-      GMM* m_modes;
-
-      // Number of Gaussian components per pixel
-      BwImage m_modes_per_pixel;
-
-      // Current background model
-      RgbImage m_background;
-
-      // Factor control for the T2FGMM-UM
-      float km;
-
-      // Factor control for the T2FGMM-UV
-      float kv;
-    };
+      const int TYPE_T2FGMM_UM = 0;
+      const int TYPE_T2FGMM_UV = 1;
+
+      // --- User adjustable parameters used by the T2F GMM BGS algorithm ---
+      class T2FGMMParams : public BgsParams
+      {
+      public:
+        float &LowThreshold() { return m_low_threshold; }
+        float &HighThreshold() { return m_high_threshold; }
+
+        float &Alpha() { return m_alpha; }
+        int &MaxModes() { return m_max_modes; }
+        int &Type() { return m_type; }
+        float &KM() { return m_km; }
+        float &KV() { return m_kv; }
+
+      private:
+        // Threshold on the squared dist. to decide when a sample is close to an existing
+        // components. If it is not close to any a new component will be generated.
+        // Smaller threshold values lead to more generated components and higher threshold values
+        // lead to a small number of components but they can grow too large.
+        //
+        // It is usual easiest to think of these thresholds as being the number of variances away
+        // from the mean of a pixel before it is considered to be from the foreground.
+        float m_low_threshold;
+        float m_high_threshold;
+
+        // alpha - speed of update - if the time interval you want to average over is T
+        // set alpha=1/T.
+        float m_alpha;
+
+        // Maximum number of modes (Gaussian components) that will be used per pixel
+        int m_max_modes;
+
+        // T2FGMM_UM / T2FGMM_UV
+        int m_type;
+
+        // Factor control for the T2FGMM-UM
+        float m_km;
+
+        // Factor control for the T2FGMM-UV
+        float m_kv;
+      };
+
+      // --- T2FGMM BGS algorithm ---
+      class T2FGMM : public Bgs
+      {
+      public:
+        T2FGMM();
+        ~T2FGMM();
+
+        void Initalize(const BgsParams& param);
+
+        void InitModel(const RgbImage& data);
+        void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask);
+        void Update(int frame_num, const RgbImage& data, const BwImage& update_mask);
+
+        RgbImage* Background();
+
+      private:
+        void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold);
+
+        // User adjustable parameters
+        T2FGMMParams m_params;
+
+        // Threshold when the component becomes significant enough to be included into
+        // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9
+        // For alpha=0.001 it means that the mode should exist for approximately 105 frames before
+        // it is considered foreground
+        float m_bg_threshold; //1-cf from the paper
+
+        // Initial variance for the newly generated components.
+        // It will will influence the speed of adaptation. A good guess should be made.
+        // A simple way is to estimate the typical standard deviation from the images.
+        float m_variance;
+
+        // Dynamic array for the mixture of Gaussians
+        GMM* m_modes;
+
+        // Number of Gaussian components per pixel
+        BwImage m_modes_per_pixel;
+
+        // Current background model
+        RgbImage m_background;
+
+        // Factor control for the T2FGMM-UM
+        float km;
+
+        // Factor control for the T2FGMM-UV
+        float kv;
+      };
+    }
   }
 }
 
diff --git a/src/algorithms/T2F/T2FMRF.cpp b/src/algorithms/T2F/T2FMRF.cpp
index 417aa27dc84e92851a0c42732bd7d4c932054b1b..3a264c14b88c8543f5d78fd97dcfc2703f5bd45c 100644
--- a/src/algorithms/T2F/T2FMRF.cpp
+++ b/src/algorithms/T2F/T2FMRF.cpp
@@ -2,402 +2,411 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+//using namespace bgslibrary::algorithms::dp;
 
-int compareT2FMRF(const void* _gmm1, const void* _gmm2)
+namespace bgslibrary
 {
-  GMM gmm1 = *(GMM*)_gmm1;
-  GMM gmm2 = *(GMM*)_gmm2;
-
-  if (gmm1.significants < gmm2.significants)
-    return 1;
-  else if (gmm1.significants == gmm2.significants)
-    return 0;
-  else
-    return -1;
-}
-
-GMM* T2FMRF::gmm()
-{
-  return m_modes;
-}
-HMM* T2FMRF::hmm()
-{
-  return m_state;
-}
-
-T2FMRF::T2FMRF()
-{
-  m_modes = NULL;
-}
-
-T2FMRF::~T2FMRF()
-{
-  delete[] m_modes;
-}
-
-void T2FMRF::Initalize(const BgsParams& param)
-{
-  m_params = (T2FMRFParams&)param;
-
-  // Tbf - the threshold
-  m_bg_threshold = 0.75f;	// 1-cf from the paper
-
-  // Tgenerate - the threshold
-  m_variance = 36.0f;		// sigma for the new mode
-
-  // GMM for each pixel
-  m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
-
-  //HMM for each pixel
-  m_state = new HMM[m_params.Size()];
-
-  // used modes per pixel
-  m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
-
-  m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
-
-  // Factor control for the T2FGMM-UM [0,3]
-  // km = (float) 2; //1.5;
-  km = (float)m_params.KM();
-
-  // Factor control for the T2FGMM-UV [0.3,1]
-  // kv = (float) 0.9; //0.6;
-  kv = (float)m_params.KV();
-}
-
-RgbImage* T2FMRF::Background()
-{
-  return &m_background;
-}
-
-void T2FMRF::InitModel(const RgbImage& data)
-{
-  m_modes_per_pixel.Clear();
-
-  for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
+  namespace algorithms
   {
-    m_modes[i].weight = 0;
-    m_modes[i].variance = 0;
-    m_modes[i].muR = 0;
-    m_modes[i].muG = 0;
-    m_modes[i].muB = 0;
-    m_modes[i].significants = 0;
-  }
-
-  for (unsigned int j = 0; j < m_params.Size(); ++j)
-  {
-    m_state[j].State = background;
-    m_state[j].Ab2b = 0.7f;
-    m_state[j].Ab2f = 0.3f;
-    m_state[j].Af2b = 0.4f;
-    m_state[j].Af2f = 0.6f;
-    m_state[j].T = 0.7f;
-  }
-}
-
-void T2FMRF::Update(int frame_num, const RgbImage& data, const BwImage& update_mask)
-{
-  // it doesn't make sense to have conditional updates in the GMM framework
-}
-
-void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes,
-  unsigned char& low_threshold, unsigned char& high_threshold)
-{
-  // calculate distances to the modes (+ sort???)
-  // here we need to go in descending order!!!
-  long pos;
-  bool bFitsPDF = false;
-  bool bBackgroundLow = false;
-  bool bBackgroundHigh = false;
-
-  HiddenState CurrentState = m_state[posPixel].State;
-  float Ab2b = m_state[posPixel].Ab2b;
-  float Ab2f = m_state[posPixel].Ab2f;
-  float Af2b = m_state[posPixel].Af2b;
-  float Af2f = m_state[posPixel].Af2f;
-  //float T = m_state[posPixel].T;
-
-  float fOneMinAlpha = 1 - m_params.Alpha();
-  float totalWeight = 0.0f;
-
-  // calculate number of Gaussians to include in the background model
-  int backgroundGaussians = 0;
-  double sum = 0.0;
-  for (int i = 0; i < numModes; ++i)
-  {
-    if (sum < m_bg_threshold)
+    namespace dp
     {
-      backgroundGaussians++;
-      sum += m_modes[posGMode + i].weight;
-    }
-    else
-      break;
-  }
-
-  // update all distributions and check for match with current pixel
-  for (int iModes = 0; iModes < numModes; iModes++)
-  {
-    pos = posGMode + iModes;
-    float weight = m_modes[pos].weight;
-
-    // fit not found yet
-    if (!bFitsPDF)
-    {
-      //check if it belongs to some of the modes
-      //calculate distance
-      float var = m_modes[pos].variance;
-      float muR = m_modes[pos].muR;
-      float muG = m_modes[pos].muG;
-      float muB = m_modes[pos].muB;
-
-      //float km = 2;
-      //float kv = 0.9;
-
-      float dR = fabs(muR - pixel(0));
-      float dG = fabs(muG - pixel(1));
-      float dB = fabs(muB - pixel(2));
-
-      // calculate the squared distance
-      float HR;
-      float HG;
-      float HB;
-
-      // T2FMRF-UM
-      if (m_params.Type() == TYPE_T2FMRF_UM)
+      int compareT2FMRF(const void* _gmm1, const void* _gmm2)
       {
-        if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var))
-          HR = 2 * km*dR / var;
-        else
-          HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2;
-
-        if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var))
-          HG = 2 * km*dG / var;
-        else
-          HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2;
+        GMM gmm1 = *(GMM*)_gmm1;
+        GMM gmm2 = *(GMM*)_gmm2;
 
-        if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var))
-          HB = 2 * km*dB / var;
+        if (gmm1.significants < gmm2.significants)
+          return 1;
+        else if (gmm1.significants == gmm2.significants)
+          return 0;
         else
-          HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2;
+          return -1;
       }
 
-      // T2FGMM-UV
-      if (m_params.Type() == TYPE_T2FMRF_UV)
+      GMM* T2FMRF::gmm()
       {
-        HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var);
-        HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var);
-        HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var);
+        return m_modes;
+      }
+      HMM* T2FMRF::hmm()
+      {
+        return m_state;
       }
 
-      float ro;
-      if (CurrentState == background)
+      T2FMRF::T2FMRF()
       {
-        if (Ab2b != 0) ro = (Ab2f / Ab2b);
-        else ro = 10;
+        m_modes = NULL;
       }
-      else
+
+      T2FMRF::~T2FMRF()
       {
-        if (Af2b != 0) ro = (Af2f / Af2b);
-        else ro = 10;
+        delete[] m_modes;
       }
 
-      // calculate the squared distance
-      float dist = (HR*HR + HG*HG + HB*HB);
+      void T2FMRF::Initalize(const BgsParams& param)
+      {
+        m_params = (T2FMRFParams&)param;
+
+        // Tbf - the threshold
+        m_bg_threshold = 0.75f;	// 1-cf from the paper
+
+        // Tgenerate - the threshold
+        m_variance = 36.0f;		// sigma for the new mode
+
+        // GMM for each pixel
+        m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
+
+        //HMM for each pixel
+        m_state = new HMM[m_params.Size()];
+
+        // used modes per pixel
+        m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
+
+        m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
 
-      if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
-        bBackgroundHigh = true;
+        // Factor control for the T2FGMM-UM [0,3]
+        // km = (float) 2; //1.5;
+        km = (float)m_params.KM();
 
-      // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution
-      if (dist < m_params.LowThreshold()*var)
+        // Factor control for the T2FGMM-UV [0.3,1]
+        // kv = (float) 0.9; //0.6;
+        kv = (float)m_params.KV();
+      }
+
+      RgbImage* T2FMRF::Background()
       {
-        bFitsPDF = true;
-
-        // check if this Gaussian is part of the background model
-        if (iModes < backgroundGaussians)
-          bBackgroundLow = true;
-
-        //update distribution
-        float k = m_params.Alpha() / weight;
-        weight = fOneMinAlpha*weight + m_params.Alpha();
-        m_modes[pos].weight = weight;
-        m_modes[pos].muR = muR - k*(dR);
-        m_modes[pos].muG = muG - k*(dG);
-        m_modes[pos].muB = muB - k*(dB);
-
-        //limit the variance
-        float sigmanew = var + k*(dist - var);
-        m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew;
-        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+        return &m_background;
       }
-      else
+
+      void T2FMRF::InitModel(const RgbImage& data)
       {
-        weight = fOneMinAlpha*weight;
-        if (weight < 0.0)
+        m_modes_per_pixel.Clear();
+
+        for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
         {
-          weight = 0.0;
-          numModes--;
+          m_modes[i].weight = 0;
+          m_modes[i].variance = 0;
+          m_modes[i].muR = 0;
+          m_modes[i].muG = 0;
+          m_modes[i].muB = 0;
+          m_modes[i].significants = 0;
         }
 
-        m_modes[pos].weight = weight;
-        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+        for (unsigned int j = 0; j < m_params.Size(); ++j)
+        {
+          m_state[j].State = background;
+          m_state[j].Ab2b = 0.7f;
+          m_state[j].Ab2f = 0.3f;
+          m_state[j].Af2b = 0.4f;
+          m_state[j].Af2f = 0.6f;
+          m_state[j].T = 0.7f;
+        }
       }
-    }
-    else
-    {
-      weight = fOneMinAlpha*weight;
-      if (weight < 0.0)
+
+      void T2FMRF::Update(int frame_num, const RgbImage& data, const BwImage& update_mask)
       {
-        weight = 0.0;
-        numModes--;
+        // it doesn't make sense to have conditional updates in the GMM framework
       }
-      m_modes[pos].weight = weight;
-      m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
-    }
-
-    totalWeight += weight;
-  }
-
-  // renormalize weights so they add to one
-  double invTotalWeight = 1.0 / totalWeight;
-  for (int iLocal = 0; iLocal < numModes; iLocal++)
-  {
-    m_modes[posGMode + iLocal].weight *= (float)invTotalWeight;
-    m_modes[posGMode + iLocal].significants = m_modes[posGMode + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance);
-  }
 
-  // Sort significance values so they are in desending order.
-  qsort(&m_modes[posGMode], numModes, sizeof(GMM), compareT2FMRF);
-
-  // make new mode if needed and exit
-  if (!bFitsPDF)
-  {
-    if (numModes < m_params.MaxModes())
-      numModes++;
-    //else
-    // the weakest mode will be replaced
-
-    pos = posGMode + numModes - 1;
-
-    m_modes[pos].muR = pixel.ch[0];
-    m_modes[pos].muG = pixel.ch[1];
-    m_modes[pos].muB = pixel.ch[2];
-    m_modes[pos].variance = m_variance;
-    m_modes[pos].significants = 0;			// will be set below
-
-    if (numModes == 1)
-      m_modes[pos].weight = 1;
-    else
-      m_modes[pos].weight = m_params.Alpha();
-
-    //renormalize weights
-    int iLocal;
-    float sum = 0.0;
-    for (iLocal = 0; iLocal < numModes; iLocal++)
-      sum += m_modes[posGMode + iLocal].weight;
-
-    double invSum = 1.0 / sum;
-    for (iLocal = 0; iLocal < numModes; iLocal++)
-    {
-      m_modes[posGMode + iLocal].weight *= (float)invSum;
-      m_modes[posGMode + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance);
-    }
-  }
-
-  // Sort significance values so they are in desending order.
-  qsort(&(m_modes[posGMode]), numModes, sizeof(GMM), compareT2FMRF);
-
-  if (bBackgroundLow)
-  {
-    low_threshold = BACKGROUND;
-    m_state[posPixel].State = background;
+      void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes,
+        unsigned char& low_threshold, unsigned char& high_threshold)
+      {
+        // calculate distances to the modes (+ sort???)
+        // here we need to go in descending order!!!
+        long pos;
+        bool bFitsPDF = false;
+        bool bBackgroundLow = false;
+        bool bBackgroundHigh = false;
+
+        HiddenState CurrentState = m_state[posPixel].State;
+        float Ab2b = m_state[posPixel].Ab2b;
+        float Ab2f = m_state[posPixel].Ab2f;
+        float Af2b = m_state[posPixel].Af2b;
+        float Af2f = m_state[posPixel].Af2f;
+        //float T = m_state[posPixel].T;
+
+        float fOneMinAlpha = 1 - m_params.Alpha();
+        float totalWeight = 0.0f;
+
+        // calculate number of Gaussians to include in the background model
+        int backgroundGaussians = 0;
+        double sum = 0.0;
+        for (int i = 0; i < numModes; ++i)
+        {
+          if (sum < m_bg_threshold)
+          {
+            backgroundGaussians++;
+            sum += m_modes[posGMode + i].weight;
+          }
+          else
+            break;
+        }
 
-    if (CurrentState == background)
-    {
-      float b2b = fOneMinAlpha*Ab2b + m_params.Alpha();
-      float b2f = fOneMinAlpha*Ab2f;
+        // update all distributions and check for match with current pixel
+        for (int iModes = 0; iModes < numModes; iModes++)
+        {
+          pos = posGMode + iModes;
+          float weight = m_modes[pos].weight;
+
+          // fit not found yet
+          if (!bFitsPDF)
+          {
+            //check if it belongs to some of the modes
+            //calculate distance
+            float var = m_modes[pos].variance;
+            float muR = m_modes[pos].muR;
+            float muG = m_modes[pos].muG;
+            float muB = m_modes[pos].muB;
+
+            //float km = 2;
+            //float kv = 0.9;
+
+            float dR = fabs(muR - pixel(0));
+            float dG = fabs(muG - pixel(1));
+            float dB = fabs(muB - pixel(2));
+
+            // calculate the squared distance
+            float HR;
+            float HG;
+            float HB;
+
+            // T2FMRF-UM
+            if (m_params.Type() == TYPE_T2FMRF_UM)
+            {
+              if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var))
+                HR = 2 * km*dR / var;
+              else
+                HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2;
+
+              if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var))
+                HG = 2 * km*dG / var;
+              else
+                HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2;
+
+              if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var))
+                HB = 2 * km*dB / var;
+              else
+                HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2;
+            }
+
+            // T2FGMM-UV
+            if (m_params.Type() == TYPE_T2FMRF_UV)
+            {
+              HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var);
+              HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var);
+              HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var);
+            }
+
+            float ro;
+            if (CurrentState == background)
+            {
+              if (Ab2b != 0) ro = (Ab2f / Ab2b);
+              else ro = 10;
+            }
+            else
+            {
+              if (Af2b != 0) ro = (Af2f / Af2b);
+              else ro = 10;
+            }
+
+            // calculate the squared distance
+            float dist = (HR*HR + HG*HG + HB*HB);
+
+            if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
+              bBackgroundHigh = true;
+
+            // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution
+            if (dist < m_params.LowThreshold()*var)
+            {
+              bFitsPDF = true;
+
+              // check if this Gaussian is part of the background model
+              if (iModes < backgroundGaussians)
+                bBackgroundLow = true;
+
+              //update distribution
+              float k = m_params.Alpha() / weight;
+              weight = fOneMinAlpha*weight + m_params.Alpha();
+              m_modes[pos].weight = weight;
+              m_modes[pos].muR = muR - k*(dR);
+              m_modes[pos].muG = muG - k*(dG);
+              m_modes[pos].muB = muB - k*(dB);
+
+              //limit the variance
+              float sigmanew = var + k*(dist - var);
+              m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew;
+              m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+            }
+            else
+            {
+              weight = fOneMinAlpha*weight;
+              if (weight < 0.0)
+              {
+                weight = 0.0;
+                numModes--;
+              }
+
+              m_modes[pos].weight = weight;
+              m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+            }
+          }
+          else
+          {
+            weight = fOneMinAlpha*weight;
+            if (weight < 0.0)
+            {
+              weight = 0.0;
+              numModes--;
+            }
+            m_modes[pos].weight = weight;
+            m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+          }
+
+          totalWeight += weight;
+        }
 
-      float b = b2b + b2f;
-      m_state[posPixel].Ab2b = b2b / b;
-      m_state[posPixel].Ab2f = b2f / b;
-      m_state[posPixel].T = m_state[posPixel].Ab2b;
-    }
-    else
-    {
-      float f2b = fOneMinAlpha*Af2b + m_params.Alpha();
-      float f2f = fOneMinAlpha*Af2f;
+        // renormalize weights so they add to one
+        double invTotalWeight = 1.0 / totalWeight;
+        for (int iLocal = 0; iLocal < numModes; iLocal++)
+        {
+          m_modes[posGMode + iLocal].weight *= (float)invTotalWeight;
+          m_modes[posGMode + iLocal].significants = m_modes[posGMode + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance);
+        }
 
-      float f = f2b + f2f;
-      m_state[posPixel].Af2b = f2b / f;
-      m_state[posPixel].Af2f = f2f / f;
-      m_state[posPixel].T = m_state[posPixel].Af2b;
-    }
-  }
-  else
-  {
-    low_threshold = FOREGROUND;
-    m_state[posPixel].State = foreground;
+        // Sort significance values so they are in desending order.
+        qsort(&m_modes[posGMode], numModes, sizeof(GMM), compareT2FMRF);
 
-    if (CurrentState == background)
-    {
-      float b2b = fOneMinAlpha*Ab2b;
-      float b2f = fOneMinAlpha*Ab2f + m_params.Alpha();
+        // make new mode if needed and exit
+        if (!bFitsPDF)
+        {
+          if (numModes < m_params.MaxModes())
+            numModes++;
+          //else
+          // the weakest mode will be replaced
+
+          pos = posGMode + numModes - 1;
+
+          m_modes[pos].muR = pixel.ch[0];
+          m_modes[pos].muG = pixel.ch[1];
+          m_modes[pos].muB = pixel.ch[2];
+          m_modes[pos].variance = m_variance;
+          m_modes[pos].significants = 0;			// will be set below
+
+          if (numModes == 1)
+            m_modes[pos].weight = 1;
+          else
+            m_modes[pos].weight = m_params.Alpha();
+
+          //renormalize weights
+          int iLocal;
+          float sum = 0.0;
+          for (iLocal = 0; iLocal < numModes; iLocal++)
+            sum += m_modes[posGMode + iLocal].weight;
+
+          double invSum = 1.0 / sum;
+          for (iLocal = 0; iLocal < numModes; iLocal++)
+          {
+            m_modes[posGMode + iLocal].weight *= (float)invSum;
+            m_modes[posGMode + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance);
+          }
+        }
 
-      float b = b2b + b2f;
-      m_state[posPixel].Ab2b = b2b / b;
-      m_state[posPixel].Ab2f = b2f / b;
-      m_state[posPixel].T = m_state[posPixel].Ab2b;
-    }
-    else
-    {
-      float f2b = fOneMinAlpha*Af2b;
-      float f2f = fOneMinAlpha*Af2f + m_params.Alpha();
+        // Sort significance values so they are in desending order.
+        qsort(&(m_modes[posGMode]), numModes, sizeof(GMM), compareT2FMRF);
 
-      float f = f2b + f2f;
-      m_state[posPixel].Af2b = f2b / f;
-      m_state[posPixel].Af2f = f2f / f;
-      m_state[posPixel].T = m_state[posPixel].Af2b;
-    }
-  }
+        if (bBackgroundLow)
+        {
+          low_threshold = BACKGROUND;
+          m_state[posPixel].State = background;
+
+          if (CurrentState == background)
+          {
+            float b2b = fOneMinAlpha*Ab2b + m_params.Alpha();
+            float b2f = fOneMinAlpha*Ab2f;
+
+            float b = b2b + b2f;
+            m_state[posPixel].Ab2b = b2b / b;
+            m_state[posPixel].Ab2f = b2f / b;
+            m_state[posPixel].T = m_state[posPixel].Ab2b;
+          }
+          else
+          {
+            float f2b = fOneMinAlpha*Af2b + m_params.Alpha();
+            float f2f = fOneMinAlpha*Af2f;
+
+            float f = f2b + f2f;
+            m_state[posPixel].Af2b = f2b / f;
+            m_state[posPixel].Af2f = f2f / f;
+            m_state[posPixel].T = m_state[posPixel].Af2b;
+          }
+        }
+        else
+        {
+          low_threshold = FOREGROUND;
+          m_state[posPixel].State = foreground;
+
+          if (CurrentState == background)
+          {
+            float b2b = fOneMinAlpha*Ab2b;
+            float b2f = fOneMinAlpha*Ab2f + m_params.Alpha();
+
+            float b = b2b + b2f;
+            m_state[posPixel].Ab2b = b2b / b;
+            m_state[posPixel].Ab2f = b2f / b;
+            m_state[posPixel].T = m_state[posPixel].Ab2b;
+          }
+          else
+          {
+            float f2b = fOneMinAlpha*Af2b;
+            float f2f = fOneMinAlpha*Af2f + m_params.Alpha();
+
+            float f = f2b + f2f;
+            m_state[posPixel].Af2b = f2b / f;
+            m_state[posPixel].Af2f = f2f / f;
+            m_state[posPixel].T = m_state[posPixel].Af2b;
+          }
+        }
 
-  if (bBackgroundHigh)
-    high_threshold = BACKGROUND;
-  else
-    high_threshold = FOREGROUND;
-}
+        if (bBackgroundHigh)
+          high_threshold = BACKGROUND;
+        else
+          high_threshold = FOREGROUND;
+      }
 
-///////////////////////////////////////////////////////////////////////////////
-//Input:
-//  data - a pointer to the data of a RGB image of the same size
-//Output:
-//  output - a pointer to the data of a gray value image of the same size 
-//					(the memory should already be reserved) 
-//					values: 255-foreground, 125-shadow, 0-background
-///////////////////////////////////////////////////////////////////////////////
-void T2FMRF::Subtract(int frame_num, const RgbImage& data,
-  BwImage& low_threshold_mask, BwImage& high_threshold_mask)
-{
-  unsigned char low_threshold, high_threshold;
-  long posPixel;
-  long posGMode;
+      ///////////////////////////////////////////////////////////////////////////////
+      //Input:
+      //  data - a pointer to the data of a RGB image of the same size
+      //Output:
+      //  output - a pointer to the data of a gray value image of the same size 
+      //					(the memory should already be reserved) 
+      //					values: 255-foreground, 125-shadow, 0-background
+      ///////////////////////////////////////////////////////////////////////////////
+      void T2FMRF::Subtract(int frame_num, const RgbImage& data,
+        BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+      {
+        unsigned char low_threshold, high_threshold;
+        long posPixel;
+        long posGMode;
 
-  // update each pixel of the image
-  for (unsigned int r = 0; r < m_params.Height(); ++r)
-  {
-    for (unsigned int c = 0; c < m_params.Width(); ++c)
-    {
-      // update model + background subtract
-      posPixel = r*m_params.Width() + c;
-      posGMode = (r*m_params.Width() + c) * m_params.MaxModes();
+        // update each pixel of the image
+        for (unsigned int r = 0; r < m_params.Height(); ++r)
+        {
+          for (unsigned int c = 0; c < m_params.Width(); ++c)
+          {
+            // update model + background subtract
+            posPixel = r*m_params.Width() + c;
+            posGMode = (r*m_params.Width() + c) * m_params.MaxModes();
 
-      SubtractPixel(posPixel, posGMode, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold);
+            SubtractPixel(posPixel, posGMode, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold);
 
-      low_threshold_mask(r, c) = low_threshold;
-      high_threshold_mask(r, c) = high_threshold;
+            low_threshold_mask(r, c) = low_threshold;
+            high_threshold_mask(r, c) = high_threshold;
 
-      m_background(r, c, 0) = (unsigned char)m_modes[posGMode].muR;
-      m_background(r, c, 1) = (unsigned char)m_modes[posGMode].muG;
-      m_background(r, c, 2) = (unsigned char)m_modes[posGMode].muB;
+            m_background(r, c, 0) = (unsigned char)m_modes[posGMode].muR;
+            m_background(r, c, 1) = (unsigned char)m_modes[posGMode].muG;
+            m_background(r, c, 2) = (unsigned char)m_modes[posGMode].muB;
+          }
+        }
+      }
     }
   }
 }
diff --git a/src/algorithms/T2F/T2FMRF.h b/src/algorithms/T2F/T2FMRF.h
index a3a3a17317f57d0498528f3adc5e408082eab622..8f79e802634b7655041d2fb4f9dc1d3a198514b7 100644
--- a/src/algorithms/T2F/T2FMRF.h
+++ b/src/algorithms/T2F/T2FMRF.h
@@ -6,130 +6,133 @@
 #include "../dp/Bgs.h"
 #include "../dp/GrimsonGMM.h"
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
-    const int TYPE_T2FMRF_UM = 0;
-    const int TYPE_T2FMRF_UV = 1;
-
-    enum HiddenState { background, foreground };
-
-    typedef struct HMMState
-    {
-      float T;
-      //Hidden State
-      HiddenState State;
-      //transition probability
-      float Ab2b;
-      float Ab2f;
-      float Af2f;
-      float Af2b;
-    } HMM;
-
-    //typedef struct GMMGaussian
-    //{
-    //  float variance;
-    //  float muR;
-    //  float muG;
-    //  float muB;
-    //  float weight;
-    //  float significants; // this is equal to weight / standard deviation and is used to
-    //  // determine which Gaussians should be part of the background model
-    //} GMM;
-
-    // --- User adjustable parameters used by the T2F GMM BGS algorithm ---
-    class T2FMRFParams : public BgsParams
-    {
-    public:
-      float &LowThreshold() { return m_low_threshold; }
-      float &HighThreshold() { return m_high_threshold; }
-
-      float &Alpha() { return m_alpha; }
-      int &MaxModes() { return m_max_modes; }
-      int &Type() { return m_type; }
-      float &KM() { return m_km; }
-      float &KV() { return m_kv; }
-
-    private:
-      // Threshold on the squared dist. to decide when a sample is close to an existing
-      // components. If it is not close to any a new component will be generated.
-      // Smaller threshold values lead to more generated components and higher threshold values
-      // lead to a small number of components but they can grow too large.
-      //
-      // It is usual easiest to think of these thresholds as being the number of variances away
-      // from the mean of a pixel before it is considered to be from the foreground.
-      float m_low_threshold;
-      float m_high_threshold;
-
-      // alpha - speed of update - if the time interval you want to average over is T
-      // set alpha=1/T.
-      float m_alpha;
-
-      // Maximum number of modes (Gaussian components) that will be used per pixel
-      int m_max_modes;
-
-      // T2FMRF_UM / T2FMRF_UV
-      int m_type;
-
-      // Factor control for the T2FMRF-UM
-      float m_km;
-
-      // Factor control for the T2FMRF-UV
-      float m_kv;
-    };
-
-    // --- T2FGMM BGS algorithm ---
-    class T2FMRF : public Bgs
+    namespace dp
     {
-    public:
-      T2FMRF();
-      ~T2FMRF();
-
-      void Initalize(const BgsParams& param);
-      void InitModel(const RgbImage& data);
-      void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask);
-      void Update(int frame_num, const RgbImage& data, const BwImage& update_mask);
-
-      RgbImage* Background();
-
-      GMM *gmm(void);
-      HMM *hmm(void);
-
-    private:
-      void SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold);
-
-      // User adjustable parameters
-      T2FMRFParams m_params;
-
-      // Threshold when the component becomes significant enough to be included into
-      // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9
-      // For alpha=0.001 it means that the mode should exist for approximately 105 frames before
-      // it is considered foreground
-      float m_bg_threshold; //1-cf from the paper
-
-      // Initial variance for the newly generated components.
-      // It will will influence the speed of adaptation. A good guess should be made.
-      // A simple way is to estimate the typical standard deviation from the images.
-      float m_variance;
-
-      // Dynamic array for the mixture of Gaussians
-      GMM* m_modes;
-
-      //Dynamic array for the hidden state
-      HMM* m_state;
-
-      // Number of Gaussian components per pixel
-      BwImage m_modes_per_pixel;
-
-      // Current background model
-      RgbImage m_background;
-
-      // Factor control for the T2FGMM-UM
-      float km;
-      // Factor control for the T2FGMM-UV
-      float kv;
-    };
+      const int TYPE_T2FMRF_UM = 0;
+      const int TYPE_T2FMRF_UV = 1;
+
+      enum HiddenState { background, foreground };
+
+      typedef struct HMMState
+      {
+        float T;
+        //Hidden State
+        HiddenState State;
+        //transition probability
+        float Ab2b;
+        float Ab2f;
+        float Af2f;
+        float Af2b;
+      } HMM;
+
+      //typedef struct GMMGaussian
+      //{
+      //  float variance;
+      //  float muR;
+      //  float muG;
+      //  float muB;
+      //  float weight;
+      //  float significants; // this is equal to weight / standard deviation and is used to
+      //  // determine which Gaussians should be part of the background model
+      //} GMM;
+
+      // --- User adjustable parameters used by the T2F GMM BGS algorithm ---
+      class T2FMRFParams : public BgsParams
+      {
+      public:
+        float &LowThreshold() { return m_low_threshold; }
+        float &HighThreshold() { return m_high_threshold; }
+
+        float &Alpha() { return m_alpha; }
+        int &MaxModes() { return m_max_modes; }
+        int &Type() { return m_type; }
+        float &KM() { return m_km; }
+        float &KV() { return m_kv; }
+
+      private:
+        // Threshold on the squared dist. to decide when a sample is close to an existing
+        // components. If it is not close to any a new component will be generated.
+        // Smaller threshold values lead to more generated components and higher threshold values
+        // lead to a small number of components but they can grow too large.
+        //
+        // It is usual easiest to think of these thresholds as being the number of variances away
+        // from the mean of a pixel before it is considered to be from the foreground.
+        float m_low_threshold;
+        float m_high_threshold;
+
+        // alpha - speed of update - if the time interval you want to average over is T
+        // set alpha=1/T.
+        float m_alpha;
+
+        // Maximum number of modes (Gaussian components) that will be used per pixel
+        int m_max_modes;
+
+        // T2FMRF_UM / T2FMRF_UV
+        int m_type;
+
+        // Factor control for the T2FMRF-UM
+        float m_km;
+
+        // Factor control for the T2FMRF-UV
+        float m_kv;
+      };
+
+      // --- T2FGMM BGS algorithm ---
+      class T2FMRF : public Bgs
+      {
+      public:
+        T2FMRF();
+        ~T2FMRF();
+
+        void Initalize(const BgsParams& param);
+        void InitModel(const RgbImage& data);
+        void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask);
+        void Update(int frame_num, const RgbImage& data, const BwImage& update_mask);
+
+        RgbImage* Background();
+
+        GMM *gmm(void);
+        HMM *hmm(void);
+
+      private:
+        void SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold);
+
+        // User adjustable parameters
+        T2FMRFParams m_params;
+
+        // Threshold when the component becomes significant enough to be included into
+        // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9
+        // For alpha=0.001 it means that the mode should exist for approximately 105 frames before
+        // it is considered foreground
+        float m_bg_threshold; //1-cf from the paper
+
+        // Initial variance for the newly generated components.
+        // It will will influence the speed of adaptation. A good guess should be made.
+        // A simple way is to estimate the typical standard deviation from the images.
+        float m_variance;
+
+        // Dynamic array for the mixture of Gaussians
+        GMM* m_modes;
+
+        //Dynamic array for the hidden state
+        HMM* m_state;
+
+        // Number of Gaussian components per pixel
+        BwImage m_modes_per_pixel;
+
+        // Current background model
+        RgbImage m_background;
+
+        // Factor control for the T2FGMM-UM
+        float km;
+        // Factor control for the T2FGMM-UV
+        float kv;
+      };
+    }
   }
 }
 
diff --git a/src/algorithms/T2FGMM_UM.cpp b/src/algorithms/T2FGMM_UM.cpp
index 44904da8079e30cb3a74b1407ff5f6d9a4204606..7c95dfe58cab47bd1f9f2c36c50bc6776bb62fa2 100644
--- a/src/algorithms/T2FGMM_UM.cpp
+++ b/src/algorithms/T2FGMM_UM.cpp
@@ -41,7 +41,7 @@ void T2FGMM_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &
     params.HighThreshold() = 2 * params.LowThreshold();
     params.Alpha() = alpha;
     params.MaxModes() = gaussians;
-    params.Type() = TYPE_T2FGMM_UM;
+    params.Type() = dp::TYPE_T2FGMM_UM;
     params.KM() = km; // Factor control for the T2FGMM-UM [0,3] default: 1.5
     params.KV() = kv; // Factor control for the T2FGMM-UV [0.3,1] default: 0.6
 
diff --git a/src/algorithms/T2FGMM_UM.h b/src/algorithms/T2FGMM_UM.h
index c5a6ebd0e91c0024ee147816cae203dc23a11c2b..0f3185a042faff634afa03d7661f050a4eea1b21 100644
--- a/src/algorithms/T2FGMM_UM.h
+++ b/src/algorithms/T2FGMM_UM.h
@@ -6,8 +6,6 @@
 #include "IBGS.h"
 #include "T2F/T2FGMM.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -16,19 +14,17 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage* frame;
-      RgbImage frame_data;
-
-      T2FGMMParams params;
-      T2FGMM bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       double threshold;
       double alpha;
       float km;
       float kv;
       int gaussians;
+      IplImage* frame;
+      dp::RgbImage frame_data;
+      dp::T2FGMMParams params;
+      dp::T2FGMM bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
 
     public:
       T2FGMM_UM();
diff --git a/src/algorithms/T2FGMM_UV.cpp b/src/algorithms/T2FGMM_UV.cpp
index 3b411351b7fd26697f08810ded00ad44e3916be3..cff817bd82f0266bedea0cb809edbcbdc1a21084 100644
--- a/src/algorithms/T2FGMM_UV.cpp
+++ b/src/algorithms/T2FGMM_UV.cpp
@@ -41,7 +41,7 @@ void T2FGMM_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &
     params.HighThreshold() = 2 * params.LowThreshold();
     params.Alpha() = alpha;
     params.MaxModes() = gaussians;
-    params.Type() = TYPE_T2FGMM_UV;
+    params.Type() = dp::TYPE_T2FGMM_UV;
     params.KM() = km; // Factor control for the T2FGMM-UM [0,3] default: 1.5
     params.KV() = kv; // Factor control for the T2FGMM-UV [0.3,1] default: 0.6
 
diff --git a/src/algorithms/T2FGMM_UV.h b/src/algorithms/T2FGMM_UV.h
index 75f931f4aa94ffa57eba17bc59b266a5fbaeafc1..6c00688642637f9e66274058c393f51e26359661 100644
--- a/src/algorithms/T2FGMM_UV.h
+++ b/src/algorithms/T2FGMM_UV.h
@@ -6,8 +6,6 @@
 #include "IBGS.h"
 #include "T2F/T2FGMM.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -16,19 +14,17 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage* frame;
-      RgbImage frame_data;
-
-      T2FGMMParams params;
-      T2FGMM bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       double threshold;
       double alpha;
       float km;
       float kv;
       int gaussians;
+      IplImage* frame;
+      dp::RgbImage frame_data;
+      dp::T2FGMMParams params;
+      dp::T2FGMM bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
 
     public:
       T2FGMM_UV();
diff --git a/src/algorithms/T2FMRF_UM.cpp b/src/algorithms/T2FMRF_UM.cpp
index 487b72e6b973c1da899a38ae91707e7b8006513d..208be5d63d5fa7199e79885fd76fd2a44d6fac40 100644
--- a/src/algorithms/T2FMRF_UM.cpp
+++ b/src/algorithms/T2FMRF_UM.cpp
@@ -41,7 +41,7 @@ void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &
     params.HighThreshold() = 2 * params.LowThreshold();
     params.Alpha() = alpha;
     params.MaxModes() = gaussians;
-    params.Type() = TYPE_T2FMRF_UM;
+    params.Type() = dp::TYPE_T2FMRF_UM;
     params.KM() = km; // Factor control for the T2FMRF-UM [0,3] default: 2
     params.KV() = kv; // Factor control for the T2FMRF-UV [0.3,1] default: 0.9
 
diff --git a/src/algorithms/T2FMRF_UM.h b/src/algorithms/T2FMRF_UM.h
index ba27e6e67f8e4c67f8f1088e1b1a4d6145079f7c..9761ae6b15025516f0773df390681922bff492e2 100644
--- a/src/algorithms/T2FMRF_UM.h
+++ b/src/algorithms/T2FMRF_UM.h
@@ -6,8 +6,6 @@
 #include "IBGS.h"
 #include "T2F/MRF.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -16,26 +14,22 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage *frame;
-      RgbImage frame_data;
-
-      IplImage *old_labeling;
-      IplImage *old;
-
-      T2FMRFParams params;
-      T2FMRF bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       double threshold;
       double alpha;
       float km;
       float kv;
       int gaussians;
-
-      MRF_TC mrf;
-      GMM *gmm;
-      HMM *hmm;
+      IplImage *frame;
+      IplImage *old_labeling;
+      IplImage *old;
+      dp::RgbImage frame_data;
+      dp::T2FMRFParams params;
+      dp::T2FMRF bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
+      dp::MRF_TC mrf;
+      dp::GMM *gmm;
+      dp::HMM *hmm;
 
     public:
       T2FMRF_UM();
diff --git a/src/algorithms/T2FMRF_UV.cpp b/src/algorithms/T2FMRF_UV.cpp
index 5c96be89b3a49fac9650afd0787b12885ce46e2e..c0a1c5ff65c2f13f3427f44178c43bfdb807934d 100644
--- a/src/algorithms/T2FMRF_UV.cpp
+++ b/src/algorithms/T2FMRF_UV.cpp
@@ -41,7 +41,7 @@ void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &
     params.HighThreshold() = 2 * params.LowThreshold();
     params.Alpha() = alpha;
     params.MaxModes() = gaussians;
-    params.Type() = TYPE_T2FMRF_UV;
+    params.Type() = dp::TYPE_T2FMRF_UV;
     params.KM() = km; // Factor control for the T2FMRF-UM [0,3] default: 2
     params.KV() = kv; // Factor control for the T2FMRF-UV [0.3,1] default: 0.9
 
diff --git a/src/algorithms/T2FMRF_UV.h b/src/algorithms/T2FMRF_UV.h
index f9b6e0f9a6075a618ef59f642059b76b27f7af92..ef2519b6d3f1db68e7b5f2caa4b844fd0540bd9d 100644
--- a/src/algorithms/T2FMRF_UV.h
+++ b/src/algorithms/T2FMRF_UV.h
@@ -6,8 +6,6 @@
 #include "IBGS.h"
 #include "T2F/MRF.h"
 
-using namespace Algorithms::BackgroundSubtraction;
-
 namespace bgslibrary
 {
   namespace algorithms
@@ -16,26 +14,22 @@ namespace bgslibrary
     {
     private:
       long frameNumber;
-      IplImage *frame;
-      RgbImage frame_data;
-
-      IplImage *old_labeling;
-      IplImage *old;
-
-      T2FMRFParams params;
-      T2FMRF bgs;
-      BwImage lowThresholdMask;
-      BwImage highThresholdMask;
-
       double threshold;
       double alpha;
       float km;
       float kv;
       int gaussians;
-
-      MRF_TC mrf;
-      GMM *gmm;
-      HMM *hmm;
+      IplImage *frame;
+      IplImage *old_labeling;
+      IplImage *old;
+      dp::RgbImage frame_data;
+      dp::T2FMRFParams params;
+      dp::T2FMRF bgs;
+      dp::BwImage lowThresholdMask;
+      dp::BwImage highThresholdMask;
+      dp::MRF_TC mrf;
+      dp::GMM *gmm;
+      dp::HMM *hmm;
 
     public:
       T2FMRF_UV();
diff --git a/src/algorithms/TwoPoints.cpp b/src/algorithms/TwoPoints.cpp
index ec2c134e1222e56712fbdd926c7fd105c39cce5e..6b554ea8eb11d7feec1309f84885b848d558f3ab 100644
--- a/src/algorithms/TwoPoints.cpp
+++ b/src/algorithms/TwoPoints.cpp
@@ -10,12 +10,12 @@ TwoPoints::TwoPoints() :
   debug_construction(TwoPoints);
   initLoadSaveConfig(algorithmName);
   //model = static_cast<twopointsModel_t*>(libtwopointsModel_New());
-  model = libtwopointsModel_New();
+  model = twopoints::libtwopointsModel_New();
 }
 
 TwoPoints::~TwoPoints() {
   debug_destruction(TwoPoints);
-  libtwopointsModel_Free(model);
+  twopoints::libtwopointsModel_Free(model);
 }
 
 void TwoPoints::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
@@ -36,14 +36,14 @@ void TwoPoints::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &
     //img_output = Mat(img_input.rows, img_input.cols, CV_8UC1);
 
     // Initialization of the ViBe model.
-    libtwopointsModel_AllocInit_8u_C1R(model, img_input_grayscale.data, img_input.cols, img_input.rows);
+    twopoints::libtwopointsModel_AllocInit_8u_C1R(model, img_input_grayscale.data, img_input.cols, img_input.rows);
 
     // Sets default model values.
-    // libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold);
-    // libvibeModel_Sequential_SetUpdateFactor(model, updateFactor);
+    // twopoints::libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold);
+    // twopoints::libvibeModel_Sequential_SetUpdateFactor(model, updateFactor);
   }
 
-  libtwopointsModel_Segmentation_8u_C1R(model, img_input_grayscale.data, img_output.data);
+  twopoints::libtwopointsModel_Segmentation_8u_C1R(model, img_input_grayscale.data, img_output.data);
 
   updatingMask = cv::Mat(img_input.rows, img_input.cols, CV_8UC1);
   // Work on the output and define the updating mask
@@ -58,7 +58,7 @@ void TwoPoints::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &
     }
   }
 
-  libtwopointsModel_Update_8u_C1R(model, img_input_grayscale.data, updatingMask.data);
+  twopoints::libtwopointsModel_Update_8u_C1R(model, img_input_grayscale.data, updatingMask.data);
 
 #ifndef MEX_COMPILE_FLAG
   if (showOutput)
diff --git a/src/algorithms/TwoPoints.h b/src/algorithms/TwoPoints.h
index 65cff47eb97cab995c34972a10a60883cb4f8d6a..1a1ef25a73c36ec63129a68856c7760442ce8a2d 100644
--- a/src/algorithms/TwoPoints.h
+++ b/src/algorithms/TwoPoints.h
@@ -14,7 +14,7 @@ namespace bgslibrary
       static const int DEFAULT_UPDATE_FACTOR = 16;
       int matchingThreshold;
       int updateFactor;
-      twopointsModel_t* model;
+      twopoints::twopointsModel_t* model;
 
     public:
       TwoPoints();
diff --git a/src/algorithms/TwoPoints/two_points.cpp b/src/algorithms/TwoPoints/two_points.cpp
index 1c0c121fe109cce30b656e96605b9a474e6d1056..2ba29ed822d67411eb3ce8f3416431ce08a265b3 100644
--- a/src/algorithms/TwoPoints/two_points.cpp
+++ b/src/algorithms/TwoPoints/two_points.cpp
@@ -2,377 +2,387 @@
 
 #include "two_points.h"
 
-static unsigned int abs_uint(const int i)
+//using namespace bgslibrary::algorithms::twopoints;
+namespace bgslibrary
 {
-  return (i >= 0) ? i : -i;
-}
-
-struct twopointsModel
-{
-  /* Parameters. */
-  uint32_t width;
-  uint32_t height;
-  uint32_t numberOfSamples;
-  uint32_t matchingThreshold;
-  uint32_t matchingNumber;
-  uint32_t updateFactor;
-
-  /* Storage for the history. */
-  uint8_t *historyImage1;
-  uint8_t *historyImage2;
-
-  /* Buffers with random values. */
-  uint32_t *jump;
-  int *neighbor;
-};
-
-// -----------------------------------------------------------------------------
-// Creates the data structure
-// -----------------------------------------------------------------------------
-twopointsModel_t *libtwopointsModel_New()
-{
-  /* Model structure alloc. */
-  twopointsModel_t *model = NULL;
-  model = (twopointsModel_t*)calloc(1, sizeof(*model));
-  assert(model != NULL);
-
-  /* Default parameters values. */
-  model->matchingThreshold = 20;
-  model->updateFactor = 16;
-
-  /* Storage for the history. */
-  model->historyImage1 = NULL;
-  model->historyImage2 = NULL;
-
-  /* Buffers with random values. */
-  model->jump = NULL;
-  model->neighbor = NULL;
-
-  return(model);
-}
-
-// ----------------------------------------------------------------------------
-// Frees the structure
-// ----------------------------------------------------------------------------
-int32_t libtwopointsModel_Free(twopointsModel_t *model)
-{
-  if (model == NULL)
-    return(-1);
-
-  if (model->historyImage1 != NULL) {
-    free(model->historyImage1);
-    model->historyImage1 = NULL;
-  }
-  if (model->historyImage2 != NULL) {
-    free(model->historyImage2);
-    model->historyImage2 = NULL;
-  }
-  if (model->jump != NULL) {
-    free(model->jump);
-    model->jump = NULL;
-  }
-  if (model->neighbor != NULL) {
-    free(model->neighbor);
-    model->neighbor = NULL;
-  }
-  free(model);
-
-  return(0);
-}
-
-// -----------------------------------------------------------------------------
-// Allocates and initializes a C1R model structure
-// -----------------------------------------------------------------------------
-int32_t libtwopointsModel_AllocInit_8u_C1R(
-  twopointsModel_t *model,
-  const uint8_t *image_data,
-  const uint32_t width,
-  const uint32_t height
-)
-{
-  // Some basic checks. */
-  assert((image_data != NULL) && (model != NULL));
-  assert((width > 0) && (height > 0));
-
-  /* Finish model alloc - parameters values cannot be changed anymore. */
-  model->width = width;
-  model->height = height;
-
-  /* Creates the historyImage structure. */
-  model->historyImage1 = NULL;
-  model->historyImage1 = (uint8_t*)malloc(width * height * sizeof(uint8_t));
-  model->historyImage2 = NULL;
-  model->historyImage2 = (uint8_t*)malloc(width * height * sizeof(uint8_t));
-
-  assert(model->historyImage1 != NULL);
-  assert(model->historyImage2 != NULL);
-
-  for (int index = width * height - 1; index >= 0; --index) {
-    uint8_t value = image_data[index];
-
-    int value_plus_noise = value - 10;
-    if (value_plus_noise < 0) { value_plus_noise = 0; }
-    if (value_plus_noise > 255) { value_plus_noise = 255; }
-    model->historyImage1[index] = value_plus_noise;
-
-    value_plus_noise = value + 10;
-    if (value_plus_noise < 0) { value_plus_noise = 0; }
-    if (value_plus_noise > 255) { value_plus_noise = 255; }
-    model->historyImage2[index] = value_plus_noise;
-
-    // Swaps the two values if needed
-    if (model->historyImage1[index] > model->historyImage2[index]) {
-      uint8_t val = model->historyImage1[index];
-      model->historyImage1[index] = model->historyImage2[index];
-      model->historyImage2[index] = val;
-    }
-  }
-
-  /* Fills the buffers with random values. */
-  int size = (width > height) ? 2 * width + 1 : 2 * height + 1;
-
-  model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump)));
-  assert(model->jump != NULL);
-
-  model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor)));
-  assert(model->neighbor != NULL);
-
-
-  for (int i = 0; i < size; ++i) {
-    model->jump[i] = (rand() % (2 * model->updateFactor)) + 1;            // Values between 1 and 2 * updateFactor.
-    model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }.
-  }
-
-  return(0);
-}
-
-// -----------------------------------------------------------------------------
-// Segmentation of a C1R model
-// -----------------------------------------------------------------------------
-int32_t libtwopointsModel_Segmentation_8u_C1R(
-  twopointsModel_t *model,
-  const uint8_t *image_data,
-  uint8_t *segmentation_map
-)
-{
-  assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL));
-  assert((model->width > 0) && (model->height > 0));
-  assert((model->jump != NULL) && (model->neighbor != NULL));
-
-  /* Some variables. */
-  uint32_t width = model->width;
-  uint32_t height = model->height;
-  uint32_t matchingThreshold = model->matchingThreshold;
-
-  uint8_t *historyImage1 = model->historyImage1;
-  uint8_t *historyImage2 = model->historyImage2;
-
-  /* Segmentation. */
-  memset(segmentation_map, 0, width * height);
-
-  uint8_t *first = historyImage1;
-  for (int index = width * height - 1; index >= 0; --index) {
-    // We adapt the threshold
-    matchingThreshold = model->matchingThreshold;
-    if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) {
-      matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]);
-    }
-    if (abs_uint(image_data[index] - first[index]) <= matchingThreshold)
-      segmentation_map[index]++;
-  }
-
-  first = historyImage2;
-  for (int index = width * height - 1; index >= 0; --index) {
-    // We adapt the threshold
-    matchingThreshold = model->matchingThreshold;
-    if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) {
-      matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]);
-    }
-    if (abs_uint(image_data[index] - first[index]) <= matchingThreshold)
-      segmentation_map[index]++;
-  }
-
-  return(0);
-}
-
-// ----------------------------------------------------------------------------
-// Update a C1R model
-// ----------------------------------------------------------------------------
-int doUpdate(const uint8_t value)
-{
-  if (value == 0) return 0;
-  else return 1;
-}
+  namespace algorithms
+  {
+    namespace twopoints
+    {
+      static unsigned int abs_uint(const int i)
+      {
+        return (i >= 0) ? i : -i;
+      }
 
+      struct twopointsModel
+      {
+        /* Parameters. */
+        uint32_t width;
+        uint32_t height;
+        uint32_t numberOfSamples;
+        uint32_t matchingThreshold;
+        uint32_t matchingNumber;
+        uint32_t updateFactor;
+
+        /* Storage for the history. */
+        uint8_t *historyImage1;
+        uint8_t *historyImage2;
+
+        /* Buffers with random values. */
+        uint32_t *jump;
+        int *neighbor;
+      };
+
+      // -----------------------------------------------------------------------------
+      // Creates the data structure
+      // -----------------------------------------------------------------------------
+      twopointsModel_t *libtwopointsModel_New()
+      {
+        /* Model structure alloc. */
+        twopointsModel_t *model = NULL;
+        model = (twopointsModel_t*)calloc(1, sizeof(*model));
+        assert(model != NULL);
+
+        /* Default parameters values. */
+        model->matchingThreshold = 20;
+        model->updateFactor = 16;
+
+        /* Storage for the history. */
+        model->historyImage1 = NULL;
+        model->historyImage2 = NULL;
+
+        /* Buffers with random values. */
+        model->jump = NULL;
+        model->neighbor = NULL;
+
+        return(model);
+      }
 
-int32_t libtwopointsModel_Update_8u_C1R(
-  twopointsModel_t *model,
-  const uint8_t *image_data,
-  uint8_t *updating_mask
-)
-{
-  assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL));
-  assert((model->width > 0) && (model->height > 0));
-  assert((model->jump != NULL) && (model->neighbor != NULL));
-
-  // Some variables.
-  uint32_t width = model->width;
-  uint32_t height = model->height;
-
-  uint8_t *historyImage1 = model->historyImage1;
-  uint8_t *historyImage2 = model->historyImage2;
-
-  // Updating.
-  uint32_t *jump = model->jump;
-  int *neighbor = model->neighbor;
-
-  // All the frame, except the border.
-  uint32_t shift, indX, indY;
-  unsigned int x, y;
-
-  for (y = 1; y < height - 1; ++y) {
-    shift = rand() % width;
-    indX = jump[shift]; // index_jump should never be zero (> 1).
-
-    while (indX < width - 1) {
-      int index = indX + y * width;
-
-      if (doUpdate(updating_mask[index])) {
-        uint8_t value = image_data[index];
-        // In-place substitution.
-        // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
-        if (rand() % 2 == 0) {
-          historyImage1[index] = value;
+      // ----------------------------------------------------------------------------
+      // Frees the structure
+      // ----------------------------------------------------------------------------
+      int32_t libtwopointsModel_Free(twopointsModel_t *model)
+      {
+        if (model == NULL)
+          return(-1);
+
+        if (model->historyImage1 != NULL) {
+          free(model->historyImage1);
+          model->historyImage1 = NULL;
         }
-        else {
-          historyImage2[index] = value;
+        if (model->historyImage2 != NULL) {
+          free(model->historyImage2);
+          model->historyImage2 = NULL;
         }
-
-        // Propagation
-        int index_neighbor = index + neighbor[shift];
-        if (2 * value < (historyImage1[index_neighbor] + historyImage2[index_neighbor])) {
-          // if (rand()%2 == 0 ) {
-          historyImage1[index_neighbor] = value;
+        if (model->jump != NULL) {
+          free(model->jump);
+          model->jump = NULL;
         }
-        else {
-          historyImage2[index_neighbor] = value;
+        if (model->neighbor != NULL) {
+          free(model->neighbor);
+          model->neighbor = NULL;
         }
-      }
+        free(model);
 
-      ++shift;
-      indX += jump[shift];
-    }
-  }
+        return(0);
+      }
 
-  // First row.
-  y = 0;
-  shift = rand() % width;
-  indX = jump[shift]; // index_jump should never be zero (> 1).
+      // -----------------------------------------------------------------------------
+      // Allocates and initializes a C1R model structure
+      // -----------------------------------------------------------------------------
+      int32_t libtwopointsModel_AllocInit_8u_C1R(
+        twopointsModel_t *model,
+        const uint8_t *image_data,
+        const uint32_t width,
+        const uint32_t height
+      )
+      {
+        // Some basic checks. */
+        assert((image_data != NULL) && (model != NULL));
+        assert((width > 0) && (height > 0));
+
+        /* Finish model alloc - parameters values cannot be changed anymore. */
+        model->width = width;
+        model->height = height;
+
+        /* Creates the historyImage structure. */
+        model->historyImage1 = NULL;
+        model->historyImage1 = (uint8_t*)malloc(width * height * sizeof(uint8_t));
+        model->historyImage2 = NULL;
+        model->historyImage2 = (uint8_t*)malloc(width * height * sizeof(uint8_t));
+
+        assert(model->historyImage1 != NULL);
+        assert(model->historyImage2 != NULL);
+
+        for (int index = width * height - 1; index >= 0; --index) {
+          uint8_t value = image_data[index];
+
+          int value_plus_noise = value - 10;
+          if (value_plus_noise < 0) { value_plus_noise = 0; }
+          if (value_plus_noise > 255) { value_plus_noise = 255; }
+          model->historyImage1[index] = value_plus_noise;
+
+          value_plus_noise = value + 10;
+          if (value_plus_noise < 0) { value_plus_noise = 0; }
+          if (value_plus_noise > 255) { value_plus_noise = 255; }
+          model->historyImage2[index] = value_plus_noise;
+
+          // Swaps the two values if needed
+          if (model->historyImage1[index] > model->historyImage2[index]) {
+            uint8_t val = model->historyImage1[index];
+            model->historyImage1[index] = model->historyImage2[index];
+            model->historyImage2[index] = val;
+          }
+        }
 
-  while (indX <= width - 1) {
-    int index = indX + y * width;
+        /* Fills the buffers with random values. */
+        int size = (width > height) ? 2 * width + 1 : 2 * height + 1;
 
-    if (doUpdate(updating_mask[index])) {
-      uint8_t value = image_data[index];
-      // In-place substitution.
-      // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
-      if (rand() % 2 == 0) {
-        historyImage1[index] = value;
-      }
-      else {
-        historyImage2[index] = value;
-      }
-    }
+        model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump)));
+        assert(model->jump != NULL);
 
-    ++shift;
-    indX += jump[shift];
-  }
+        model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor)));
+        assert(model->neighbor != NULL);
 
-  // Last row.
-  y = height - 1;
-  shift = rand() % width;
-  indX = jump[shift]; // index_jump should never be zero (> 1).
 
-  while (indX <= width - 1) {
-    int index = indX + y * width;
+        for (int i = 0; i < size; ++i) {
+          model->jump[i] = (rand() % (2 * model->updateFactor)) + 1;            // Values between 1 and 2 * updateFactor.
+          model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }.
+        }
 
-    if (doUpdate(updating_mask[index])) {
-      uint8_t value = image_data[index];
-      // In-place substitution.
-      // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
-      if (rand() % 2 == 0) {
-        historyImage1[index] = value;
-      }
-      else {
-        historyImage2[index] = value;
+        return(0);
       }
-    }
-
-    ++shift;
-    indX += jump[shift];
-  }
 
-  // First column.
-  x = 0;
-  shift = rand() % height;
-  indY = jump[shift]; // index_jump should never be zero (> 1).
+      // -----------------------------------------------------------------------------
+      // Segmentation of a C1R model
+      // -----------------------------------------------------------------------------
+      int32_t libtwopointsModel_Segmentation_8u_C1R(
+        twopointsModel_t *model,
+        const uint8_t *image_data,
+        uint8_t *segmentation_map
+      )
+      {
+        assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL));
+        assert((model->width > 0) && (model->height > 0));
+        assert((model->jump != NULL) && (model->neighbor != NULL));
+
+        /* Some variables. */
+        uint32_t width = model->width;
+        uint32_t height = model->height;
+        uint32_t matchingThreshold = model->matchingThreshold;
+
+        uint8_t *historyImage1 = model->historyImage1;
+        uint8_t *historyImage2 = model->historyImage2;
+
+        /* Segmentation. */
+        memset(segmentation_map, 0, width * height);
+
+        uint8_t *first = historyImage1;
+        for (int index = width * height - 1; index >= 0; --index) {
+          // We adapt the threshold
+          matchingThreshold = model->matchingThreshold;
+          if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) {
+            matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]);
+          }
+          if (abs_uint(image_data[index] - first[index]) <= matchingThreshold)
+            segmentation_map[index]++;
+        }
 
-  while (indY <= height - 1) {
-    int index = x + indY * width;
+        first = historyImage2;
+        for (int index = width * height - 1; index >= 0; --index) {
+          // We adapt the threshold
+          matchingThreshold = model->matchingThreshold;
+          if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) {
+            matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]);
+          }
+          if (abs_uint(image_data[index] - first[index]) <= matchingThreshold)
+            segmentation_map[index]++;
+        }
 
-    if (doUpdate(updating_mask[index])) {
-      uint8_t value = image_data[index];
-      // In-place substitution.
-      // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
-      if (rand() % 2 == 0) {
-        historyImage1[index] = value;
+        return(0);
       }
-      else {
-        historyImage2[index] = value;
+
+      // ----------------------------------------------------------------------------
+      // Update a C1R model
+      // ----------------------------------------------------------------------------
+      int doUpdate(const uint8_t value)
+      {
+        if (value == 0) return 0;
+        else return 1;
       }
-    }
 
-    ++shift;
-    indY += jump[shift];
-  }
 
-  // Last column.
-  x = width - 1;
-  shift = rand() % height;
-  indY = jump[shift]; // index_jump should never be zero (> 1).
+      int32_t libtwopointsModel_Update_8u_C1R(
+        twopointsModel_t *model,
+        const uint8_t *image_data,
+        uint8_t *updating_mask
+      )
+      {
+        assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL));
+        assert((model->width > 0) && (model->height > 0));
+        assert((model->jump != NULL) && (model->neighbor != NULL));
+
+        // Some variables.
+        uint32_t width = model->width;
+        uint32_t height = model->height;
+
+        uint8_t *historyImage1 = model->historyImage1;
+        uint8_t *historyImage2 = model->historyImage2;
+
+        // Updating.
+        uint32_t *jump = model->jump;
+        int *neighbor = model->neighbor;
+
+        // All the frame, except the border.
+        uint32_t shift, indX, indY;
+        unsigned int x, y;
+
+        for (y = 1; y < height - 1; ++y) {
+          shift = rand() % width;
+          indX = jump[shift]; // index_jump should never be zero (> 1).
+
+          while (indX < width - 1) {
+            int index = indX + y * width;
+
+            if (doUpdate(updating_mask[index])) {
+              uint8_t value = image_data[index];
+              // In-place substitution.
+              // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
+              if (rand() % 2 == 0) {
+                historyImage1[index] = value;
+              }
+              else {
+                historyImage2[index] = value;
+              }
+
+              // Propagation
+              int index_neighbor = index + neighbor[shift];
+              if (2 * value < (historyImage1[index_neighbor] + historyImage2[index_neighbor])) {
+                // if (rand()%2 == 0 ) {
+                historyImage1[index_neighbor] = value;
+              }
+              else {
+                historyImage2[index_neighbor] = value;
+              }
+            }
+
+            ++shift;
+            indX += jump[shift];
+          }
+        }
 
-  while (indY <= height - 1) {
-    int index = x + indY * width;
+        // First row.
+        y = 0;
+        shift = rand() % width;
+        indX = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indX <= width - 1) {
+          int index = indX + y * width;
+
+          if (doUpdate(updating_mask[index])) {
+            uint8_t value = image_data[index];
+            // In-place substitution.
+            // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
+            if (rand() % 2 == 0) {
+              historyImage1[index] = value;
+            }
+            else {
+              historyImage2[index] = value;
+            }
+          }
+
+          ++shift;
+          indX += jump[shift];
+        }
 
-    if (doUpdate(updating_mask[index])) {
-      uint8_t value = image_data[index];
-      // In-place substitution.
-      // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
-      if (rand() % 2 == 0) {
-        historyImage1[index] = value;
-      }
-      else {
-        historyImage2[index] = value;
-      }
-    }
+        // Last row.
+        y = height - 1;
+        shift = rand() % width;
+        indX = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indX <= width - 1) {
+          int index = indX + y * width;
+
+          if (doUpdate(updating_mask[index])) {
+            uint8_t value = image_data[index];
+            // In-place substitution.
+            // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
+            if (rand() % 2 == 0) {
+              historyImage1[index] = value;
+            }
+            else {
+              historyImage2[index] = value;
+            }
+          }
+
+          ++shift;
+          indX += jump[shift];
+        }
 
-    ++shift;
-    indY += jump[shift];
-  }
+        // First column.
+        x = 0;
+        shift = rand() % height;
+        indY = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indY <= height - 1) {
+          int index = x + indY * width;
+
+          if (doUpdate(updating_mask[index])) {
+            uint8_t value = image_data[index];
+            // In-place substitution.
+            // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
+            if (rand() % 2 == 0) {
+              historyImage1[index] = value;
+            }
+            else {
+              historyImage2[index] = value;
+            }
+          }
+
+          ++shift;
+          indY += jump[shift];
+        }
 
-  // The first pixel!
-  if (rand() % model->updateFactor == 0) {
-    if (doUpdate(updating_mask[0])) {
-      uint8_t value = image_data[0];
-      // In-place substitution.
-      if (rand() % 2 == 0) {
-        historyImage1[0] = value;
-      }
-      else {
-        historyImage2[0] = value;
+        // Last column.
+        x = width - 1;
+        shift = rand() % height;
+        indY = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indY <= height - 1) {
+          int index = x + indY * width;
+
+          if (doUpdate(updating_mask[index])) {
+            uint8_t value = image_data[index];
+            // In-place substitution.
+            // if (2*value < (historyImage1[index]+historyImage2[index]) ) {
+            if (rand() % 2 == 0) {
+              historyImage1[index] = value;
+            }
+            else {
+              historyImage2[index] = value;
+            }
+          }
+
+          ++shift;
+          indY += jump[shift];
+        }
+
+        // The first pixel!
+        if (rand() % model->updateFactor == 0) {
+          if (doUpdate(updating_mask[0])) {
+            uint8_t value = image_data[0];
+            // In-place substitution.
+            if (rand() % 2 == 0) {
+              historyImage1[0] = value;
+            }
+            else {
+              historyImage2[0] = value;
+            }
+          }
+        }
+
+        return(0);
       }
     }
   }
-
-  return(0);
 }
diff --git a/src/algorithms/TwoPoints/two_points.h b/src/algorithms/TwoPoints/two_points.h
index ecf8b6f419de4197c1d3b4bdc5068aea11433850..f249fd3dd60dfc1ed4d3a21c52564723cb9c0fd1 100644
--- a/src/algorithms/TwoPoints/two_points.h
+++ b/src/algorithms/TwoPoints/two_points.h
@@ -5,30 +5,39 @@
 #include <stdio.h>
 #include <string.h>
 
-#define COLOR_BACKGROUND   0 /*!< Default label for background pixels */
-#define COLOR_FOREGROUND 255 /*!< Default label for foreground pixels. Note that some authors chose any value different from 0 instead */
-
-typedef struct twopointsModel twopointsModel_t;
-
-twopointsModel_t *libtwopointsModel_New();
-
-int32_t libtwopointsModel_Free(twopointsModel_t *model);
-
-int32_t libtwopointsModel_AllocInit_8u_C1R(
-  twopointsModel_t *model,
-  const uint8_t *image_data,
-  const uint32_t width,
-  const uint32_t height
-);
-
-int32_t libtwopointsModel_Segmentation_8u_C1R(
-  twopointsModel_t *model,
-  const uint8_t *image_data,
-  uint8_t *segmentation_map
-);
-
-int32_t libtwopointsModel_Update_8u_C1R(
-  twopointsModel_t *model,
-  const uint8_t *image_data,
-  uint8_t *updating_mask
-);
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace twopoints
+    {
+      const int COLOR_BACKGROUND = 0; /*!< Default label for background pixels */
+      const int COLOR_FOREGROUND = 255; /*!< Default label for foreground pixels. Note that some authors chose any value different from 0 instead */
+
+      typedef struct twopointsModel twopointsModel_t;
+
+      twopointsModel_t *libtwopointsModel_New();
+
+      int32_t libtwopointsModel_Free(twopointsModel_t *model);
+
+      int32_t libtwopointsModel_AllocInit_8u_C1R(
+        twopointsModel_t *model,
+        const uint8_t *image_data,
+        const uint32_t width,
+        const uint32_t height
+      );
+
+      int32_t libtwopointsModel_Segmentation_8u_C1R(
+        twopointsModel_t *model,
+        const uint8_t *image_data,
+        uint8_t *segmentation_map
+      );
+
+      int32_t libtwopointsModel_Update_8u_C1R(
+        twopointsModel_t *model,
+        const uint8_t *image_data,
+        uint8_t *updating_mask
+      );
+    }
+  }
+}
diff --git a/src/algorithms/ViBe.cpp b/src/algorithms/ViBe.cpp
index 16b9df1ccfb90283baa21fc593155d7f4518c30e..460b92673f62ddca29df0b8830c7a1a4aaeb1497 100644
--- a/src/algorithms/ViBe.cpp
+++ b/src/algorithms/ViBe.cpp
@@ -1,6 +1,7 @@
 #include "ViBe.h"
 
 using namespace bgslibrary::algorithms;
+//using namespace bgslibrary::algorithms::vibe;
 
 ViBe::ViBe() :
   IBGS(quote(ViBe)),
@@ -12,12 +13,12 @@ ViBe::ViBe() :
 {
   debug_construction(ViBe);
   initLoadSaveConfig(algorithmName);
-  model = libvibeModel_Sequential_New();
+  model = vibe::libvibeModel_Sequential_New();
 }
 
 ViBe::~ViBe() {
   debug_destruction(ViBe);
-  libvibeModel_Sequential_Free(model);
+  vibe::libvibeModel_Sequential_Free(model);
 }
 
 void ViBe::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
@@ -32,18 +33,18 @@ void ViBe::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_b
     //img_output = cv::Mat(img_input.rows, img_input.cols, CV_8UC1);
 
     /* Initialization of the ViBe model. */
-    libvibeModel_Sequential_AllocInit_8u_C3R(model, img_input.data, img_input.cols, img_input.rows);
+    vibe::libvibeModel_Sequential_AllocInit_8u_C3R(model, img_input.data, img_input.cols, img_input.rows);
 
     /* Sets default model values. */
-    //libvibeModel_Sequential_SetNumberOfSamples(model, numberOfSamples);
-    libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold);
-    libvibeModel_Sequential_SetMatchingNumber(model, matchingNumber);
-    libvibeModel_Sequential_SetUpdateFactor(model, updateFactor);
+    //vibe::libvibeModel_Sequential_SetNumberOfSamples(model, numberOfSamples);
+    vibe::libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold);
+    vibe::libvibeModel_Sequential_SetMatchingNumber(model, matchingNumber);
+    vibe::libvibeModel_Sequential_SetUpdateFactor(model, updateFactor);
   }
 
-  libvibeModel_Sequential_Segmentation_8u_C3R(model, img_input.data, img_output.data);
-  //libvibeModel_Sequential_Update_8u_C3R(model, model_img_input.data, img_output.data);
-  libvibeModel_Sequential_Update_8u_C3R(model, img_input.data, img_output.data);
+  vibe::libvibeModel_Sequential_Segmentation_8u_C3R(model, img_input.data, img_output.data);
+  //vibe::libvibeModel_Sequential_Update_8u_C3R(model, model_img_input.data, img_output.data);
+  vibe::libvibeModel_Sequential_Update_8u_C3R(model, img_input.data, img_output.data);
 
 #ifndef MEX_COMPILE_FLAG
   if (showOutput)
diff --git a/src/algorithms/ViBe.h b/src/algorithms/ViBe.h
index 84f000e3c3aa543edce3469b7fe9e80c8ee6a631..067d0834b11ec0dca559173a2603c6de1068d6a4 100644
--- a/src/algorithms/ViBe.h
+++ b/src/algorithms/ViBe.h
@@ -20,7 +20,7 @@ namespace bgslibrary
       int matchingThreshold;
       int matchingNumber;
       int updateFactor;
-      vibeModel_Sequential_t* model;
+      vibe::vibeModel_Sequential_t* model;
 
     public:
       ViBe();
diff --git a/src/algorithms/ViBe/vibe-background-sequential.cpp b/src/algorithms/ViBe/vibe-background-sequential.cpp
index 6210733f646cc393ebb08e26f6ce9576839d3955..4bec4e6d0b197ae2542b50fbf2e532b5e76c0950 100644
--- a/src/algorithms/ViBe/vibe-background-sequential.cpp
+++ b/src/algorithms/ViBe/vibe-background-sequential.cpp
@@ -3,905 +3,913 @@
 
 #include "vibe-background-sequential.h"
 
-#define NUMBER_OF_HISTORY_IMAGES 2
-
-uint32_t distance_Han2014Improved(uint8_t pixel, uint8_t bg)
-{
-  uint8_t min, max;
-
-  // Computes R = 0.13 min{ max[bg,26], 230}
-  max = 26;
-  if (bg > max) { max = bg; }
-
-  min = 230;
-  if (min > max) { min = max; }
-
-  return (uint32_t)(0.13*min);
-}
-
-static int abs_uint(const int i)
-{
-  return (i >= 0) ? i : -i;
-}
-
-static int32_t distance_is_close_8u_C3R(uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2, uint8_t g2, uint8_t b2, uint32_t threshold)
-{
-  return (abs_uint(r1 - r2) + abs_uint(g1 - g2) + abs_uint(b1 - b2) <= 4.5 * threshold);
-}
-
-struct vibeModel_Sequential
-{
-  /* Parameters. */
-  uint32_t width;
-  uint32_t height;
-  uint32_t numberOfSamples;
-  uint32_t matchingThreshold;
-  uint32_t matchingNumber;
-  uint32_t updateFactor;
-
-  /* Storage for the history. */
-  uint8_t *historyImage;
-  uint8_t *historyBuffer;
-  uint32_t lastHistoryImageSwapped;
-
-  /* Buffers with random values. */
-  uint32_t *jump;
-  int *neighbor;
-  uint32_t *position;
-};
-
-// -----------------------------------------------------------------------------
-// Print parameters
-// -----------------------------------------------------------------------------
-uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model)
-{
-  printf(
-    "Using ViBe background subtraction algorithm\n"
-    "  - Number of samples per pixel:       %03d\n"
-    "  - Number of matches needed:          %03d\n"
-    "  - Matching threshold:                %03d\n"
-    "  - Model update subsampling factor:   %03d\n",
-    libvibeModel_Sequential_GetNumberOfSamples(model),
-    libvibeModel_Sequential_GetMatchingNumber(model),
-    libvibeModel_Sequential_GetMatchingThreshold(model),
-    libvibeModel_Sequential_GetUpdateFactor(model)
-  );
-
-  return(0);
-}
-
-// -----------------------------------------------------------------------------
-// Creates the data structure
-// -----------------------------------------------------------------------------
-vibeModel_Sequential_t *libvibeModel_Sequential_New()
-{
-  /* Model structure alloc. */
-  vibeModel_Sequential_t *model = NULL;
-  model = (vibeModel_Sequential_t*)calloc(1, sizeof(*model));
-  assert(model != NULL);
-
-  /* Default parameters values. */
-  model->numberOfSamples = 20;
-  model->matchingThreshold = 20;
-  model->matchingNumber = 2;
-  model->updateFactor = 16;
-
-  /* Storage for the history. */
-  model->historyImage = NULL;
-  model->historyBuffer = NULL;
-  model->lastHistoryImageSwapped = 0;
-
-  /* Buffers with random values. */
-  model->jump = NULL;
-  model->neighbor = NULL;
-  model->position = NULL;
-
-  return(model);
-}
-
-// -----------------------------------------------------------------------------
-// Some "Get-ers"
-// -----------------------------------------------------------------------------
-uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model)
+//using namespace bgslibrary::algorithms::vibe;
+namespace bgslibrary
 {
-  assert(model != NULL); return(model->numberOfSamples);
-}
-
-uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model)
-{
-  assert(model != NULL); return(model->matchingNumber);
-}
-
-uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model)
-{
-  assert(model != NULL); return(model->matchingThreshold);
-}
-
-uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model)
-{
-  assert(model != NULL); return(model->updateFactor);
-}
-
-// -----------------------------------------------------------------------------
-// Some "Set-ers"
-// -----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_SetMatchingThreshold(
-  vibeModel_Sequential_t *model,
-  const uint32_t matchingThreshold
-) {
-  assert(model != NULL);
-  assert(matchingThreshold > 0);
-
-  model->matchingThreshold = matchingThreshold;
-
-  return(0);
-}
-
-// -----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_SetMatchingNumber(
-  vibeModel_Sequential_t *model,
-  const uint32_t matchingNumber
-) {
-  assert(model != NULL);
-  assert(matchingNumber > 0);
-
-  model->matchingNumber = matchingNumber;
-
-  return(0);
-}
-
-// -----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_SetUpdateFactor(
-  vibeModel_Sequential_t *model,
-  const uint32_t updateFactor
-) {
-  assert(model != NULL);
-  assert(updateFactor > 0);
-
-  model->updateFactor = updateFactor;
-
-  /* We also need to change the values of the jump buffer ! */
-  assert(model->jump != NULL);
-
-  /* Shifts. */
-  int size = (model->width > model->height) ? 2 * model->width + 1 : 2 * model->height + 1;
-
-  for (int i = 0; i < size; ++i)
-    model->jump[i] = (updateFactor == 1) ? 1 : (rand() % (2 * model->updateFactor)) + 1; // 1 or values between 1 and 2 * updateFactor.
-
-  return(0);
-}
-
-// ----------------------------------------------------------------------------
-// Frees the structure
-// ----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model)
-{
-  if (model == NULL)
-    return(-1);
-
-  if (model->historyBuffer == NULL) {
-    free(model);
-    return(0);
-  }
-
-  free(model->historyImage);
-  free(model->historyBuffer);
-  free(model->jump);
-  free(model->neighbor);
-  free(model->position);
-  free(model);
-
-  return(0);
-}
-
-// -----------------------------------------------------------------------------
-// Allocates and initializes a C1R model structure
-// -----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_AllocInit_8u_C1R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  const uint32_t width,
-  const uint32_t height
-) {
-  // Some basic checks. */
-  assert((image_data != NULL) && (model != NULL));
-  assert((width > 0) && (height > 0));
-
-  /* Finish model alloc - parameters values cannot be changed anymore. */
-  model->width = width;
-  model->height = height;
-
-  /* Creates the historyImage structure. */
-  model->historyImage = NULL;
-  model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * width * height * sizeof(*(model->historyImage)));
-
-  assert(model->historyImage != NULL);
-
-  for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
-    for (int index = width * height - 1; index >= 0; --index)
-      model->historyImage[i * width * height + index] = image_data[index];
-  }
-
-  /* Now creates and fills the history buffer. */
-  model->historyBuffer = (uint8_t*)malloc(width * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t));
-  assert(model->historyBuffer != NULL);
-
-  for (int index = width * height - 1; index >= 0; --index) {
-    uint8_t value = image_data[index];
-
-    for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) {
-      int value_plus_noise = value + rand() % 20 - 10;
-
-      if (value_plus_noise < 0) { value_plus_noise = 0; }
-      if (value_plus_noise > 255) { value_plus_noise = 255; }
-
-      model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise;
-    }
-  }
-
-  /* Fills the buffers with random values. */
-  int size = (width > height) ? 2 * width + 1 : 2 * height + 1;
-
-  model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump)));
-  assert(model->jump != NULL);
-
-  model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor)));
-  assert(model->neighbor != NULL);
-
-  model->position = (uint32_t*)malloc(size * sizeof(*(model->position)));
-  assert(model->position != NULL);
-
-  for (int i = 0; i < size; ++i) {
-    model->jump[i] = (rand() % (2 * model->updateFactor)) + 1;            // Values between 1 and 2 * updateFactor.
-    model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }.
-    model->position[i] = rand() % (model->numberOfSamples);               // Values between 0 and numberOfSamples - 1.
-  }
-
-  return(0);
-}
-
-// -----------------------------------------------------------------------------
-// Segmentation of a C1R model
-// -----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_Segmentation_8u_C1R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  uint8_t *segmentation_map
-) {
-  /* Basic checks. */
-  assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL));
-  assert((model->width > 0) && (model->height > 0));
-  assert(model->historyBuffer != NULL);
-  assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
-
-  /* Some variables. */
-  uint32_t width = model->width;
-  uint32_t height = model->height;
-  uint32_t matchingNumber = model->matchingNumber;
-  //uint32_t matchingThreshold = model->matchingThreshold;
-
-  uint8_t *historyImage = model->historyImage;
-  uint8_t *historyBuffer = model->historyBuffer;
-
-  /* Segmentation. */
-  memset(segmentation_map, matchingNumber - 1, width * height);
-
-  /* First history Image structure. */
-  for (int index = width * height - 1; index >= 0; --index) {
-    //if (abs_uint(image_data[index] - historyImage[index]) > matchingThreshold)
-    if (abs_uint(image_data[index] - historyImage[index]) > distance_Han2014Improved(image_data[index], historyImage[index]))
-      segmentation_map[index] = matchingNumber;
-  }
-
-  /* Next historyImages. */
-  for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
-    uint8_t *pels = historyImage + i * width * height;
-
-    for (int index = width * height - 1; index >= 0; --index) {
-      // if (abs_uint(image_data[index] - pels[index]) <= matchingThreshold)
-      if (abs_uint(image_data[index] - pels[index]) <= distance_Han2014Improved(image_data[index], pels[index]))
-        --segmentation_map[index];
-    }
-  }
-
-  /* For swapping. */
-  model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES;
-  uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * width * height;
-
-  /* Now, we move in the buffer and leave the historyImages. */
-  int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
-
-  for (int index = width * height - 1; index >= 0; --index) {
-    if (segmentation_map[index] > 0) {
-      /* We need to check the full border and swap values with the first or second historyImage.
-       * We still need to find a match before we can stop our search.
-       */
-      uint32_t indexHistoryBuffer = index * numberOfTests;
-      uint8_t currentValue = image_data[index];
-
-      for (int i = numberOfTests; i > 0; --i, ++indexHistoryBuffer) {
-        // if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= matchingThreshold) {
-        if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= distance_Han2014Improved(currentValue, historyBuffer[indexHistoryBuffer])) {
-          --segmentation_map[index];
-
-          /* Swaping: Putting found value in history image buffer. */
-          uint8_t temp = swappingImageBuffer[index];
-          swappingImageBuffer[index] = historyBuffer[indexHistoryBuffer];
-          historyBuffer[indexHistoryBuffer] = temp;
-
-          /* Exit inner loop. */
-          if (segmentation_map[index] <= 0) break;
-        }
-      } // for
-    } // if
-  } // for
+  namespace algorithms
+  {
+    namespace vibe
+    {
+      uint32_t distance_Han2014Improved(uint8_t pixel, uint8_t bg)
+      {
+        uint8_t min, max;
+
+        // Computes R = 0.13 min{ max[bg,26], 230}
+        max = 26;
+        if (bg > max) { max = bg; }
+
+        min = 230;
+        if (min > max) { min = max; }
+
+        return (uint32_t)(0.13*min);
+      }
 
-  /* Produces the output. Note that this step is application-dependent. */
-  for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask)
-    if (*mask > 0) *mask = COLOR_FOREGROUND;
+      static int abs_uint(const int i)
+      {
+        return (i >= 0) ? i : -i;
+      }
 
-  return(0);
-}
+      static int32_t distance_is_close_8u_C3R(uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2, uint8_t g2, uint8_t b2, uint32_t threshold)
+      {
+        return (abs_uint(r1 - r2) + abs_uint(g1 - g2) + abs_uint(b1 - b2) <= 4.5 * threshold);
+      }
 
-// ----------------------------------------------------------------------------
-// Update a C1R model
-// ----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_Update_8u_C1R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  uint8_t *updating_mask
-) {
-  /* Basic checks . */
-  assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL));
-  assert((model->width > 0) && (model->height > 0));
-  assert(model->historyBuffer != NULL);
-  assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
-
-  /* Some variables. */
-  uint32_t width = model->width;
-  uint32_t height = model->height;
-
-  uint8_t *historyImage = model->historyImage;
-  uint8_t *historyBuffer = model->historyBuffer;
-
-  /* Some utility variable. */
-  int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
-
-  /* Updating. */
-  uint32_t *jump = model->jump;
-  int *neighbor = model->neighbor;
-  uint32_t *position = model->position;
-
-  /* All the frame, except the border. */
-  uint32_t shift, indX, indY;
-  unsigned int x, y;
-
-  for (y = 1; y < height - 1; ++y) {
-    shift = rand() % width;
-    indX = jump[shift]; // index_jump should never be zero (> 1).
-
-    while (indX < width - 1) {
-      int index = indX + y * width;
-
-      if (updating_mask[index] == COLOR_BACKGROUND) {
-        /* In-place substitution. */
-        uint8_t value = image_data[index];
-        int index_neighbor = index + neighbor[shift];
-
-        if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
-          historyImage[index + position[shift] * width * height] = value;
-          historyImage[index_neighbor + position[shift] * width * height] = value;
-        }
-        else {
-          int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
-          historyBuffer[index * numberOfTests + pos] = value;
-          historyBuffer[index_neighbor * numberOfTests + pos] = value;
-        }
+      struct vibeModel_Sequential
+      {
+        /* Parameters. */
+        uint32_t width;
+        uint32_t height;
+        uint32_t numberOfSamples;
+        uint32_t matchingThreshold;
+        uint32_t matchingNumber;
+        uint32_t updateFactor;
+
+        /* Storage for the history. */
+        uint8_t *historyImage;
+        uint8_t *historyBuffer;
+        uint32_t lastHistoryImageSwapped;
+
+        /* Buffers with random values. */
+        uint32_t *jump;
+        int *neighbor;
+        uint32_t *position;
+      };
+
+      // -----------------------------------------------------------------------------
+      // Print parameters
+      // -----------------------------------------------------------------------------
+      uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model)
+      {
+        printf(
+          "Using ViBe background subtraction algorithm\n"
+          "  - Number of samples per pixel:       %03d\n"
+          "  - Number of matches needed:          %03d\n"
+          "  - Matching threshold:                %03d\n"
+          "  - Model update subsampling factor:   %03d\n",
+          libvibeModel_Sequential_GetNumberOfSamples(model),
+          libvibeModel_Sequential_GetMatchingNumber(model),
+          libvibeModel_Sequential_GetMatchingThreshold(model),
+          libvibeModel_Sequential_GetUpdateFactor(model)
+        );
+
+        return(0);
       }
 
-      ++shift;
-      indX += jump[shift];
-    }
-  }
+      // -----------------------------------------------------------------------------
+      // Creates the data structure
+      // -----------------------------------------------------------------------------
+      vibeModel_Sequential_t *libvibeModel_Sequential_New()
+      {
+        /* Model structure alloc. */
+        vibeModel_Sequential_t *model = NULL;
+        model = (vibeModel_Sequential_t*)calloc(1, sizeof(*model));
+        assert(model != NULL);
+
+        /* Default parameters values. */
+        model->numberOfSamples = 20;
+        model->matchingThreshold = 20;
+        model->matchingNumber = 2;
+        model->updateFactor = 16;
+
+        /* Storage for the history. */
+        model->historyImage = NULL;
+        model->historyBuffer = NULL;
+        model->lastHistoryImageSwapped = 0;
+
+        /* Buffers with random values. */
+        model->jump = NULL;
+        model->neighbor = NULL;
+        model->position = NULL;
+
+        return(model);
+      }
 
-  /* First row. */
-  y = 0;
-  shift = rand() % width;
-  indX = jump[shift]; // index_jump should never be zero (> 1).
+      // -----------------------------------------------------------------------------
+      // Some "Get-ers"
+      // -----------------------------------------------------------------------------
+      uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model)
+      {
+        assert(model != NULL); return(model->numberOfSamples);
+      }
 
-  while (indX <= width - 1) {
-    int index = indX + y * width;
+      uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model)
+      {
+        assert(model != NULL); return(model->matchingNumber);
+      }
 
-    if (updating_mask[index] == COLOR_BACKGROUND) {
-      if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
-        historyImage[index + position[shift] * width * height] = image_data[index];
-      else {
-        int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
-        historyBuffer[index * numberOfTests + pos] = image_data[index];
+      uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model)
+      {
+        assert(model != NULL); return(model->matchingThreshold);
       }
-    }
 
-    ++shift;
-    indX += jump[shift];
-  }
+      uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model)
+      {
+        assert(model != NULL); return(model->updateFactor);
+      }
 
-  /* Last row. */
-  y = height - 1;
-  shift = rand() % width;
-  indX = jump[shift]; // index_jump should never be zero (> 1).
+      // -----------------------------------------------------------------------------
+      // Some "Set-ers"
+      // -----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_SetMatchingThreshold(
+        vibeModel_Sequential_t *model,
+        const uint32_t matchingThreshold
+      ) {
+        assert(model != NULL);
+        assert(matchingThreshold > 0);
 
-  while (indX <= width - 1) {
-    int index = indX + y * width;
+        model->matchingThreshold = matchingThreshold;
 
-    if (updating_mask[index] == COLOR_BACKGROUND) {
-      if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
-        historyImage[index + position[shift] * width * height] = image_data[index];
-      else {
-        int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
-        historyBuffer[index * numberOfTests + pos] = image_data[index];
+        return(0);
       }
-    }
-
-    ++shift;
-    indX += jump[shift];
-  }
 
-  /* First column. */
-  x = 0;
-  shift = rand() % height;
-  indY = jump[shift]; // index_jump should never be zero (> 1).
+      // -----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_SetMatchingNumber(
+        vibeModel_Sequential_t *model,
+        const uint32_t matchingNumber
+      ) {
+        assert(model != NULL);
+        assert(matchingNumber > 0);
 
-  while (indY <= height - 1) {
-    int index = x + indY * width;
+        model->matchingNumber = matchingNumber;
 
-    if (updating_mask[index] == COLOR_BACKGROUND) {
-      if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
-        historyImage[index + position[shift] * width * height] = image_data[index];
-      else {
-        int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
-        historyBuffer[index * numberOfTests + pos] = image_data[index];
+        return(0);
       }
-    }
 
-    ++shift;
-    indY += jump[shift];
-  }
+      // -----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_SetUpdateFactor(
+        vibeModel_Sequential_t *model,
+        const uint32_t updateFactor
+      ) {
+        assert(model != NULL);
+        assert(updateFactor > 0);
 
-  /* Last column. */
-  x = width - 1;
-  shift = rand() % height;
-  indY = jump[shift]; // index_jump should never be zero (> 1).
+        model->updateFactor = updateFactor;
 
-  while (indY <= height - 1) {
-    int index = x + indY * width;
+        /* We also need to change the values of the jump buffer ! */
+        assert(model->jump != NULL);
 
-    if (updating_mask[index] == COLOR_BACKGROUND) {
-      if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
-        historyImage[index + position[shift] * width * height] = image_data[index];
-      else {
-        int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
-        historyBuffer[index * numberOfTests + pos] = image_data[index];
-      }
-    }
+        /* Shifts. */
+        int size = (model->width > model->height) ? 2 * model->width + 1 : 2 * model->height + 1;
 
-    ++shift;
-    indY += jump[shift];
-  }
+        for (int i = 0; i < size; ++i)
+          model->jump[i] = (updateFactor == 1) ? 1 : (rand() % (2 * model->updateFactor)) + 1; // 1 or values between 1 and 2 * updateFactor.
 
-  /* The first pixel! */
-  if (rand() % model->updateFactor == 0) {
-    if (updating_mask[0] == 0) {
-      int position = rand() % model->numberOfSamples;
-
-      if (position < NUMBER_OF_HISTORY_IMAGES)
-        historyImage[position * width * height] = image_data[0];
-      else {
-        int pos = position - NUMBER_OF_HISTORY_IMAGES;
-        historyBuffer[pos] = image_data[0];
+        return(0);
       }
-    }
-  }
 
-  return(0);
-}
+      // ----------------------------------------------------------------------------
+      // Frees the structure
+      // ----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model)
+      {
+        if (model == NULL)
+          return(-1);
+
+        if (model->historyBuffer == NULL) {
+          free(model);
+          return(0);
+        }
 
-// ----------------------------------------------------------------------------
-// -------------------------- The same for C3R models -------------------------
-// ----------------------------------------------------------------------------
-
-// -----------------------------------------------------------------------------
-// Allocates and initializes a C3R model structure
-// -----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_AllocInit_8u_C3R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  const uint32_t width,
-  const uint32_t height
-) {
-  /* Some basic checks. */
-  assert((image_data != NULL) && (model != NULL));
-  assert((width > 0) && (height > 0));
-
-  /* Finish model alloc - parameters values cannot be changed anymore. */
-  model->width = width;
-  model->height = height;
-
-  /* Creates the historyImage structure. */
-  model->historyImage = NULL;
-  model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * (3 * width) * height * sizeof(uint8_t));
-  assert(model->historyImage != NULL);
-
-  for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
-    for (int index = (3 * width) * height - 1; index >= 0; --index)
-      model->historyImage[i * (3 * width) * height + index] = image_data[index];
-  }
+        free(model->historyImage);
+        free(model->historyBuffer);
+        free(model->jump);
+        free(model->neighbor);
+        free(model->position);
+        free(model);
 
-  assert(model->historyImage != NULL);
+        return(0);
+      }
 
-  /* Now creates and fills the history buffer. */
-  model->historyBuffer = (uint8_t *)malloc((3 * width) * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t));
-  assert(model->historyBuffer != NULL);
+      // -----------------------------------------------------------------------------
+      // Allocates and initializes a C1R model structure
+      // -----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_AllocInit_8u_C1R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        const uint32_t width,
+        const uint32_t height
+      ) {
+        // Some basic checks. */
+        assert((image_data != NULL) && (model != NULL));
+        assert((width > 0) && (height > 0));
+
+        /* Finish model alloc - parameters values cannot be changed anymore. */
+        model->width = width;
+        model->height = height;
+
+        /* Creates the historyImage structure. */
+        model->historyImage = NULL;
+        model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * width * height * sizeof(*(model->historyImage)));
+
+        assert(model->historyImage != NULL);
+
+        for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
+          for (int index = width * height - 1; index >= 0; --index)
+            model->historyImage[i * width * height + index] = image_data[index];
+        }
 
-  for (int index = (3 * width) * height - 1; index >= 0; --index) {
-    uint8_t value = image_data[index];
+        /* Now creates and fills the history buffer. */
+        model->historyBuffer = (uint8_t*)malloc(width * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t));
+        assert(model->historyBuffer != NULL);
 
-    for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) {
-      int value_plus_noise = value + rand() % 20 - 10;
+        for (int index = width * height - 1; index >= 0; --index) {
+          uint8_t value = image_data[index];
 
-      if (value_plus_noise < 0) { value_plus_noise = 0; }
-      if (value_plus_noise > 255) { value_plus_noise = 255; }
+          for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) {
+            int value_plus_noise = value + rand() % 20 - 10;
 
-      model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise;
-    }
-  }
+            if (value_plus_noise < 0) { value_plus_noise = 0; }
+            if (value_plus_noise > 255) { value_plus_noise = 255; }
 
-  /* Fills the buffers with random values. */
-  int size = (width > height) ? 2 * width + 1 : 2 * height + 1;
+            model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise;
+          }
+        }
 
-  model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump)));
-  assert(model->jump != NULL);
+        /* Fills the buffers with random values. */
+        int size = (width > height) ? 2 * width + 1 : 2 * height + 1;
 
-  model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor)));
-  assert(model->neighbor != NULL);
+        model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump)));
+        assert(model->jump != NULL);
 
-  model->position = (uint32_t*)malloc(size * sizeof(*(model->position)));
-  assert(model->position != NULL);
+        model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor)));
+        assert(model->neighbor != NULL);
 
-  for (int i = 0; i < size; ++i) {
-    model->jump[i] = (rand() % (2 * model->updateFactor)) + 1;            // Values between 1 and 2 * updateFactor.
-    model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { width - 1, ... , width + 1 }.
-    model->position[i] = rand() % (model->numberOfSamples);               // Values between 0 and numberOfSamples - 1.
-  }
+        model->position = (uint32_t*)malloc(size * sizeof(*(model->position)));
+        assert(model->position != NULL);
 
-  return(0);
-}
+        for (int i = 0; i < size; ++i) {
+          model->jump[i] = (rand() % (2 * model->updateFactor)) + 1;            // Values between 1 and 2 * updateFactor.
+          model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }.
+          model->position[i] = rand() % (model->numberOfSamples);               // Values between 0 and numberOfSamples - 1.
+        }
 
-// -----------------------------------------------------------------------------
-// Segmentation of a C3R model
-// -----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_Segmentation_8u_C3R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  uint8_t *segmentation_map
-) {
-  /* Basic checks. */
-  assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL));
-  assert((model->width > 0) && (model->height > 0));
-  assert(model->historyBuffer != NULL);
-  assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
-
-  /* Some variables. */
-  uint32_t width = model->width;
-  uint32_t height = model->height;
-  uint32_t matchingNumber = model->matchingNumber;
-  uint32_t matchingThreshold = model->matchingThreshold;
-
-  uint8_t *historyImage = model->historyImage;
-  uint8_t *historyBuffer = model->historyBuffer;
-
-  /* Segmentation. */
-  memset(segmentation_map, matchingNumber - 1, width * height);
-
-  /* First history Image structure. */
-  uint8_t *first = historyImage;
-
-  for (int index = width * height - 1; index >= 0; --index) {
-    if (
-      !distance_is_close_8u_C3R(
-        image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2],
-        first[3 * index], first[3 * index + 1], first[3 * index + 2], matchingThreshold
-      )
-      )
-      segmentation_map[index] = matchingNumber;
-  }
+        return(0);
+      }
 
-  /* Next historyImages. */
-  for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
-    uint8_t *pels = historyImage + i * (3 * width) * height;
-
-    for (int index = width * height - 1; index >= 0; --index) {
-      if (
-        distance_is_close_8u_C3R(
-          image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2],
-          pels[3 * index], pels[3 * index + 1], pels[3 * index + 2], matchingThreshold
-        )
-        )
-        --segmentation_map[index];
-    }
-  }
+      // -----------------------------------------------------------------------------
+      // Segmentation of a C1R model
+      // -----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_Segmentation_8u_C1R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        uint8_t *segmentation_map
+      ) {
+        /* Basic checks. */
+        assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL));
+        assert((model->width > 0) && (model->height > 0));
+        assert(model->historyBuffer != NULL);
+        assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
+
+        /* Some variables. */
+        uint32_t width = model->width;
+        uint32_t height = model->height;
+        uint32_t matchingNumber = model->matchingNumber;
+        //uint32_t matchingThreshold = model->matchingThreshold;
+
+        uint8_t *historyImage = model->historyImage;
+        uint8_t *historyBuffer = model->historyBuffer;
+
+        /* Segmentation. */
+        memset(segmentation_map, matchingNumber - 1, width * height);
+
+        /* First history Image structure. */
+        for (int index = width * height - 1; index >= 0; --index) {
+          //if (abs_uint(image_data[index] - historyImage[index]) > matchingThreshold)
+          if (abs_uint(image_data[index] - historyImage[index]) > distance_Han2014Improved(image_data[index], historyImage[index]))
+            segmentation_map[index] = matchingNumber;
+        }
 
-  // For swapping
-  model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES;
-  uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * (3 * width) * height;
-
-  // Now, we move in the buffer and leave the historyImages
-  int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
-
-  for (int index = width * height - 1; index >= 0; --index) {
-    if (segmentation_map[index] > 0) {
-      /* We need to check the full border and swap values with the first or second historyImage.
-       * We still need to find a match before we can stop our search.
-       */
-      uint32_t indexHistoryBuffer = (3 * index) * numberOfTests;
-
-      for (int i = numberOfTests; i > 0; --i, indexHistoryBuffer += 3) {
-        if (
-          distance_is_close_8u_C3R(
-            image_data[(3 * index)], image_data[(3 * index) + 1], image_data[(3 * index) + 2],
-            historyBuffer[indexHistoryBuffer], historyBuffer[indexHistoryBuffer + 1], historyBuffer[indexHistoryBuffer + 2],
-            matchingThreshold
-          )
-          )
-          --segmentation_map[index];
-
-        /* Swaping: Putting found value in history image buffer. */
-        uint8_t temp_r = swappingImageBuffer[(3 * index)];
-        uint8_t temp_g = swappingImageBuffer[(3 * index) + 1];
-        uint8_t temp_b = swappingImageBuffer[(3 * index) + 2];
-
-        swappingImageBuffer[(3 * index)] = historyBuffer[indexHistoryBuffer];
-        swappingImageBuffer[(3 * index) + 1] = historyBuffer[indexHistoryBuffer + 1];
-        swappingImageBuffer[(3 * index) + 2] = historyBuffer[indexHistoryBuffer + 2];
-
-        historyBuffer[indexHistoryBuffer] = temp_r;
-        historyBuffer[indexHistoryBuffer + 1] = temp_g;
-        historyBuffer[indexHistoryBuffer + 2] = temp_b;
-
-        /* Exit inner loop. */
-        if (segmentation_map[index] <= 0) break;
-      } // for
-    } // if
-  } // for
-
-  /* Produces the output. Note that this step is application-dependent. */
-  for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask)
-    if (*mask > 0) *mask = COLOR_FOREGROUND;
-
-  return(0);
-}
+        /* Next historyImages. */
+        for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
+          uint8_t *pels = historyImage + i * width * height;
 
-// ----------------------------------------------------------------------------
-// Update a C3R model
-// ----------------------------------------------------------------------------
-int32_t libvibeModel_Sequential_Update_8u_C3R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  uint8_t *updating_mask
-) {
-  /* Basic checks. */
-  assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL));
-  assert((model->width > 0) && (model->height > 0));
-  assert(model->historyBuffer != NULL);
-  assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
-
-  /* Some variables. */
-  uint32_t width = model->width;
-  uint32_t height = model->height;
-
-  uint8_t *historyImage = model->historyImage;
-  uint8_t *historyBuffer = model->historyBuffer;
-
-  /* Some utility variable. */
-  int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
-
-  /* Updating. */
-  uint32_t *jump = model->jump;
-  int *neighbor = model->neighbor;
-  uint32_t *position = model->position;
-
-  /* All the frame, except the border. */
-  uint32_t shift, indX, indY;
-  int x, y;
-
-  for (y = 1; y < height - 1; ++y) {
-    shift = rand() % width;
-    indX = jump[shift]; // index_jump should never be zero (> 1).
-
-    while (indX < width - 1) {
-      int index = indX + y * width;
-
-      if (updating_mask[index] == COLOR_BACKGROUND) {
-        /* In-place substitution. */
-        uint8_t r = image_data[3 * index];
-        uint8_t g = image_data[3 * index + 1];
-        uint8_t b = image_data[3 * index + 2];
-
-        int index_neighbor = 3 * (index + neighbor[shift]);
-
-        if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
-          historyImage[3 * index + position[shift] * (3 * width) * height] = r;
-          historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
-          historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
-
-          historyImage[index_neighbor + position[shift] * (3 * width) * height] = r;
-          historyImage[index_neighbor + position[shift] * (3 * width) * height + 1] = g;
-          historyImage[index_neighbor + position[shift] * (3 * width) * height + 2] = b;
+          for (int index = width * height - 1; index >= 0; --index) {
+            // if (abs_uint(image_data[index] - pels[index]) <= matchingThreshold)
+            if (abs_uint(image_data[index] - pels[index]) <= distance_Han2014Improved(image_data[index], pels[index]))
+              --segmentation_map[index];
+          }
         }
-        else {
-          int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
 
-          historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
-          historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
-          historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
+        /* For swapping. */
+        model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES;
+        uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * width * height;
+
+        /* Now, we move in the buffer and leave the historyImages. */
+        int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
+
+        for (int index = width * height - 1; index >= 0; --index) {
+          if (segmentation_map[index] > 0) {
+            /* We need to check the full border and swap values with the first or second historyImage.
+             * We still need to find a match before we can stop our search.
+             */
+            uint32_t indexHistoryBuffer = index * numberOfTests;
+            uint8_t currentValue = image_data[index];
+
+            for (int i = numberOfTests; i > 0; --i, ++indexHistoryBuffer) {
+              // if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= matchingThreshold) {
+              if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= distance_Han2014Improved(currentValue, historyBuffer[indexHistoryBuffer])) {
+                --segmentation_map[index];
+
+                /* Swaping: Putting found value in history image buffer. */
+                uint8_t temp = swappingImageBuffer[index];
+                swappingImageBuffer[index] = historyBuffer[indexHistoryBuffer];
+                historyBuffer[indexHistoryBuffer] = temp;
+
+                /* Exit inner loop. */
+                if (segmentation_map[index] <= 0) break;
+              }
+            } // for
+          } // if
+        } // for
+
+        /* Produces the output. Note that this step is application-dependent. */
+        for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask)
+          if (*mask > 0) *mask = COLOR_FOREGROUND;
+
+        return(0);
+      }
 
-          historyBuffer[index_neighbor * numberOfTests + 3 * pos] = r;
-          historyBuffer[index_neighbor * numberOfTests + 3 * pos + 1] = g;
-          historyBuffer[index_neighbor * numberOfTests + 3 * pos + 2] = b;
+      // ----------------------------------------------------------------------------
+      // Update a C1R model
+      // ----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_Update_8u_C1R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        uint8_t *updating_mask
+      ) {
+        /* Basic checks . */
+        assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL));
+        assert((model->width > 0) && (model->height > 0));
+        assert(model->historyBuffer != NULL);
+        assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
+
+        /* Some variables. */
+        uint32_t width = model->width;
+        uint32_t height = model->height;
+
+        uint8_t *historyImage = model->historyImage;
+        uint8_t *historyBuffer = model->historyBuffer;
+
+        /* Some utility variable. */
+        int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
+
+        /* Updating. */
+        uint32_t *jump = model->jump;
+        int *neighbor = model->neighbor;
+        uint32_t *position = model->position;
+
+        /* All the frame, except the border. */
+        uint32_t shift, indX, indY;
+        unsigned int x, y;
+
+        for (y = 1; y < height - 1; ++y) {
+          shift = rand() % width;
+          indX = jump[shift]; // index_jump should never be zero (> 1).
+
+          while (indX < width - 1) {
+            int index = indX + y * width;
+
+            if (updating_mask[index] == COLOR_BACKGROUND) {
+              /* In-place substitution. */
+              uint8_t value = image_data[index];
+              int index_neighbor = index + neighbor[shift];
+
+              if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
+                historyImage[index + position[shift] * width * height] = value;
+                historyImage[index_neighbor + position[shift] * width * height] = value;
+              }
+              else {
+                int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+                historyBuffer[index * numberOfTests + pos] = value;
+                historyBuffer[index_neighbor * numberOfTests + pos] = value;
+              }
+            }
+
+            ++shift;
+            indX += jump[shift];
+          }
         }
-      }
 
-      ++shift;
-      indX += jump[shift];
-    }
-  }
+        /* First row. */
+        y = 0;
+        shift = rand() % width;
+        indX = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indX <= width - 1) {
+          int index = indX + y * width;
+
+          if (updating_mask[index] == COLOR_BACKGROUND) {
+            if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
+              historyImage[index + position[shift] * width * height] = image_data[index];
+            else {
+              int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+              historyBuffer[index * numberOfTests + pos] = image_data[index];
+            }
+          }
+
+          ++shift;
+          indX += jump[shift];
+        }
 
-  /* First row. */
-  y = 0;
-  shift = rand() % width;
-  indX = jump[shift]; // index_jump should never be zero (> 1).
+        /* Last row. */
+        y = height - 1;
+        shift = rand() % width;
+        indX = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indX <= width - 1) {
+          int index = indX + y * width;
+
+          if (updating_mask[index] == COLOR_BACKGROUND) {
+            if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
+              historyImage[index + position[shift] * width * height] = image_data[index];
+            else {
+              int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+              historyBuffer[index * numberOfTests + pos] = image_data[index];
+            }
+          }
+
+          ++shift;
+          indX += jump[shift];
+        }
 
-  while (indX <= width - 1) {
-    int index = indX + y * width;
+        /* First column. */
+        x = 0;
+        shift = rand() % height;
+        indY = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indY <= height - 1) {
+          int index = x + indY * width;
+
+          if (updating_mask[index] == COLOR_BACKGROUND) {
+            if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
+              historyImage[index + position[shift] * width * height] = image_data[index];
+            else {
+              int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+              historyBuffer[index * numberOfTests + pos] = image_data[index];
+            }
+          }
+
+          ++shift;
+          indY += jump[shift];
+        }
 
-    uint8_t r = image_data[3 * index];
-    uint8_t g = image_data[3 * index + 1];
-    uint8_t b = image_data[3 * index + 2];
+        /* Last column. */
+        x = width - 1;
+        shift = rand() % height;
+        indY = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indY <= height - 1) {
+          int index = x + indY * width;
+
+          if (updating_mask[index] == COLOR_BACKGROUND) {
+            if (position[shift] < NUMBER_OF_HISTORY_IMAGES)
+              historyImage[index + position[shift] * width * height] = image_data[index];
+            else {
+              int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+              historyBuffer[index * numberOfTests + pos] = image_data[index];
+            }
+          }
+
+          ++shift;
+          indY += jump[shift];
+        }
 
-    if (updating_mask[index] == COLOR_BACKGROUND) {
-      if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
-        historyImage[3 * index + position[shift] * (3 * width) * height] = r;
-        historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
-        historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
-      }
-      else {
-        int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+        /* The first pixel! */
+        if (rand() % model->updateFactor == 0) {
+          if (updating_mask[0] == 0) {
+            int position = rand() % model->numberOfSamples;
+
+            if (position < NUMBER_OF_HISTORY_IMAGES)
+              historyImage[position * width * height] = image_data[0];
+            else {
+              int pos = position - NUMBER_OF_HISTORY_IMAGES;
+              historyBuffer[pos] = image_data[0];
+            }
+          }
+        }
 
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
+        return(0);
       }
-    }
 
-    ++shift;
-    indX += jump[shift];
-  }
+      // ----------------------------------------------------------------------------
+      // -------------------------- The same for C3R models -------------------------
+      // ----------------------------------------------------------------------------
+
+      // -----------------------------------------------------------------------------
+      // Allocates and initializes a C3R model structure
+      // -----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_AllocInit_8u_C3R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        const uint32_t width,
+        const uint32_t height
+      ) {
+        /* Some basic checks. */
+        assert((image_data != NULL) && (model != NULL));
+        assert((width > 0) && (height > 0));
+
+        /* Finish model alloc - parameters values cannot be changed anymore. */
+        model->width = width;
+        model->height = height;
+
+        /* Creates the historyImage structure. */
+        model->historyImage = NULL;
+        model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * (3 * width) * height * sizeof(uint8_t));
+        assert(model->historyImage != NULL);
+
+        for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
+          for (int index = (3 * width) * height - 1; index >= 0; --index)
+            model->historyImage[i * (3 * width) * height + index] = image_data[index];
+        }
 
-  /* Last row. */
-  y = height - 1;
-  shift = rand() % width;
-  indX = jump[shift]; // index_jump should never be zero (> 1).
+        assert(model->historyImage != NULL);
 
-  while (indX <= width - 1) {
-    int index = indX + y * width;
+        /* Now creates and fills the history buffer. */
+        model->historyBuffer = (uint8_t *)malloc((3 * width) * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t));
+        assert(model->historyBuffer != NULL);
 
-    uint8_t r = image_data[3 * index];
-    uint8_t g = image_data[3 * index + 1];
-    uint8_t b = image_data[3 * index + 2];
+        for (int index = (3 * width) * height - 1; index >= 0; --index) {
+          uint8_t value = image_data[index];
 
-    if (updating_mask[index] == COLOR_BACKGROUND) {
-      if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
-        historyImage[3 * index + position[shift] * (3 * width) * height] = r;
-        historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
-        historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
-      }
-      else {
-        int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+          for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) {
+            int value_plus_noise = value + rand() % 20 - 10;
 
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
-      }
-    }
+            if (value_plus_noise < 0) { value_plus_noise = 0; }
+            if (value_plus_noise > 255) { value_plus_noise = 255; }
 
-    ++shift;
-    indX += jump[shift];
-  }
+            model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise;
+          }
+        }
 
-  /* First column. */
-  x = 0;
-  shift = rand() % height;
-  indY = jump[shift]; // index_jump should never be zero (> 1).
+        /* Fills the buffers with random values. */
+        int size = (width > height) ? 2 * width + 1 : 2 * height + 1;
 
-  while (indY <= height - 1) {
-    int index = x + indY * width;
+        model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump)));
+        assert(model->jump != NULL);
 
-    uint8_t r = image_data[3 * index];
-    uint8_t g = image_data[3 * index + 1];
-    uint8_t b = image_data[3 * index + 2];
+        model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor)));
+        assert(model->neighbor != NULL);
 
-    if (updating_mask[index] == COLOR_BACKGROUND) {
-      if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
-        historyImage[3 * index + position[shift] * (3 * width) * height] = r;
-        historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
-        historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
-      }
-      else {
-        int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
-      }
-    }
+        model->position = (uint32_t*)malloc(size * sizeof(*(model->position)));
+        assert(model->position != NULL);
 
-    ++shift;
-    indY += jump[shift];
-  }
+        for (int i = 0; i < size; ++i) {
+          model->jump[i] = (rand() % (2 * model->updateFactor)) + 1;            // Values between 1 and 2 * updateFactor.
+          model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { width - 1, ... , width + 1 }.
+          model->position[i] = rand() % (model->numberOfSamples);               // Values between 0 and numberOfSamples - 1.
+        }
 
-  /* Last column. */
-  x = width - 1;
-  shift = rand() % height;
-  indY = jump[shift]; // index_jump should never be zero (> 1).
+        return(0);
+      }
 
-  while (indY <= height - 1) {
-    int index = x + indY * width;
+      // -----------------------------------------------------------------------------
+      // Segmentation of a C3R model
+      // -----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_Segmentation_8u_C3R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        uint8_t *segmentation_map
+      ) {
+        /* Basic checks. */
+        assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL));
+        assert((model->width > 0) && (model->height > 0));
+        assert(model->historyBuffer != NULL);
+        assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
+
+        /* Some variables. */
+        uint32_t width = model->width;
+        uint32_t height = model->height;
+        uint32_t matchingNumber = model->matchingNumber;
+        uint32_t matchingThreshold = model->matchingThreshold;
+
+        uint8_t *historyImage = model->historyImage;
+        uint8_t *historyBuffer = model->historyBuffer;
+
+        /* Segmentation. */
+        memset(segmentation_map, matchingNumber - 1, width * height);
+
+        /* First history Image structure. */
+        uint8_t *first = historyImage;
+
+        for (int index = width * height - 1; index >= 0; --index) {
+          if (
+            !distance_is_close_8u_C3R(
+              image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2],
+              first[3 * index], first[3 * index + 1], first[3 * index + 2], matchingThreshold
+            )
+            )
+            segmentation_map[index] = matchingNumber;
+        }
 
-    uint8_t r = image_data[3 * index];
-    uint8_t g = image_data[3 * index + 1];
-    uint8_t b = image_data[3 * index + 2];
+        /* Next historyImages. */
+        for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) {
+          uint8_t *pels = historyImage + i * (3 * width) * height;
+
+          for (int index = width * height - 1; index >= 0; --index) {
+            if (
+              distance_is_close_8u_C3R(
+                image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2],
+                pels[3 * index], pels[3 * index + 1], pels[3 * index + 2], matchingThreshold
+              )
+              )
+              --segmentation_map[index];
+          }
+        }
 
-    if (updating_mask[index] == COLOR_BACKGROUND) {
-      if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
-        historyImage[3 * index + position[shift] * (3 * width) * height] = r;
-        historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
-        historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
+        // For swapping
+        model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES;
+        uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * (3 * width) * height;
+
+        // Now, we move in the buffer and leave the historyImages
+        int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
+
+        for (int index = width * height - 1; index >= 0; --index) {
+          if (segmentation_map[index] > 0) {
+            /* We need to check the full border and swap values with the first or second historyImage.
+             * We still need to find a match before we can stop our search.
+             */
+            uint32_t indexHistoryBuffer = (3 * index) * numberOfTests;
+
+            for (int i = numberOfTests; i > 0; --i, indexHistoryBuffer += 3) {
+              if (
+                distance_is_close_8u_C3R(
+                  image_data[(3 * index)], image_data[(3 * index) + 1], image_data[(3 * index) + 2],
+                  historyBuffer[indexHistoryBuffer], historyBuffer[indexHistoryBuffer + 1], historyBuffer[indexHistoryBuffer + 2],
+                  matchingThreshold
+                )
+                )
+                --segmentation_map[index];
+
+              /* Swaping: Putting found value in history image buffer. */
+              uint8_t temp_r = swappingImageBuffer[(3 * index)];
+              uint8_t temp_g = swappingImageBuffer[(3 * index) + 1];
+              uint8_t temp_b = swappingImageBuffer[(3 * index) + 2];
+
+              swappingImageBuffer[(3 * index)] = historyBuffer[indexHistoryBuffer];
+              swappingImageBuffer[(3 * index) + 1] = historyBuffer[indexHistoryBuffer + 1];
+              swappingImageBuffer[(3 * index) + 2] = historyBuffer[indexHistoryBuffer + 2];
+
+              historyBuffer[indexHistoryBuffer] = temp_r;
+              historyBuffer[indexHistoryBuffer + 1] = temp_g;
+              historyBuffer[indexHistoryBuffer + 2] = temp_b;
+
+              /* Exit inner loop. */
+              if (segmentation_map[index] <= 0) break;
+            } // for
+          } // if
+        } // for
+
+        /* Produces the output. Note that this step is application-dependent. */
+        for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask)
+          if (*mask > 0) *mask = COLOR_FOREGROUND;
+
+        return(0);
       }
-      else {
-        int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
 
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
-        historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
-      }
-    }
+      // ----------------------------------------------------------------------------
+      // Update a C3R model
+      // ----------------------------------------------------------------------------
+      int32_t libvibeModel_Sequential_Update_8u_C3R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        uint8_t *updating_mask
+      ) {
+        /* Basic checks. */
+        assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL));
+        assert((model->width > 0) && (model->height > 0));
+        assert(model->historyBuffer != NULL);
+        assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL));
+
+        /* Some variables. */
+        uint32_t width = model->width;
+        uint32_t height = model->height;
+
+        uint8_t *historyImage = model->historyImage;
+        uint8_t *historyBuffer = model->historyBuffer;
+
+        /* Some utility variable. */
+        int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES);
+
+        /* Updating. */
+        uint32_t *jump = model->jump;
+        int *neighbor = model->neighbor;
+        uint32_t *position = model->position;
+
+        /* All the frame, except the border. */
+        uint32_t shift, indX, indY;
+        int x, y;
+
+        for (y = 1; y < height - 1; ++y) {
+          shift = rand() % width;
+          indX = jump[shift]; // index_jump should never be zero (> 1).
+
+          while (indX < width - 1) {
+            int index = indX + y * width;
+
+            if (updating_mask[index] == COLOR_BACKGROUND) {
+              /* In-place substitution. */
+              uint8_t r = image_data[3 * index];
+              uint8_t g = image_data[3 * index + 1];
+              uint8_t b = image_data[3 * index + 2];
+
+              int index_neighbor = 3 * (index + neighbor[shift]);
+
+              if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
+                historyImage[3 * index + position[shift] * (3 * width) * height] = r;
+                historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
+                historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
+
+                historyImage[index_neighbor + position[shift] * (3 * width) * height] = r;
+                historyImage[index_neighbor + position[shift] * (3 * width) * height + 1] = g;
+                historyImage[index_neighbor + position[shift] * (3 * width) * height + 2] = b;
+              }
+              else {
+                int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+
+                historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
+                historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
+                historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
+
+                historyBuffer[index_neighbor * numberOfTests + 3 * pos] = r;
+                historyBuffer[index_neighbor * numberOfTests + 3 * pos + 1] = g;
+                historyBuffer[index_neighbor * numberOfTests + 3 * pos + 2] = b;
+              }
+            }
+
+            ++shift;
+            indX += jump[shift];
+          }
+        }
 
-    ++shift;
-    indY += jump[shift];
-  }
+        /* First row. */
+        y = 0;
+        shift = rand() % width;
+        indX = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indX <= width - 1) {
+          int index = indX + y * width;
+
+          uint8_t r = image_data[3 * index];
+          uint8_t g = image_data[3 * index + 1];
+          uint8_t b = image_data[3 * index + 2];
+
+          if (updating_mask[index] == COLOR_BACKGROUND) {
+            if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
+              historyImage[3 * index + position[shift] * (3 * width) * height] = r;
+              historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
+              historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
+            }
+            else {
+              int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
+            }
+          }
+
+          ++shift;
+          indX += jump[shift];
+        }
 
-  /* The first pixel! */
-  if (rand() % model->updateFactor == 0) {
-    if (updating_mask[0] == 0) {
-      int position = rand() % model->numberOfSamples;
+        /* Last row. */
+        y = height - 1;
+        shift = rand() % width;
+        indX = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indX <= width - 1) {
+          int index = indX + y * width;
+
+          uint8_t r = image_data[3 * index];
+          uint8_t g = image_data[3 * index + 1];
+          uint8_t b = image_data[3 * index + 2];
+
+          if (updating_mask[index] == COLOR_BACKGROUND) {
+            if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
+              historyImage[3 * index + position[shift] * (3 * width) * height] = r;
+              historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
+              historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
+            }
+            else {
+              int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
+            }
+          }
+
+          ++shift;
+          indX += jump[shift];
+        }
 
-      uint8_t r = image_data[0];
-      uint8_t g = image_data[1];
-      uint8_t b = image_data[2];
+        /* First column. */
+        x = 0;
+        shift = rand() % height;
+        indY = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indY <= height - 1) {
+          int index = x + indY * width;
+
+          uint8_t r = image_data[3 * index];
+          uint8_t g = image_data[3 * index + 1];
+          uint8_t b = image_data[3 * index + 2];
+
+          if (updating_mask[index] == COLOR_BACKGROUND) {
+            if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
+              historyImage[3 * index + position[shift] * (3 * width) * height] = r;
+              historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
+              historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
+            }
+            else {
+              int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
+            }
+          }
+
+          ++shift;
+          indY += jump[shift];
+        }
 
-      if (position < NUMBER_OF_HISTORY_IMAGES) {
-        historyImage[position * (3 * width) * height] = r;
-        historyImage[position * (3 * width) * height + 1] = g;
-        historyImage[position * (3 * width) * height + 2] = b;
-      }
-      else {
-        int pos = position - NUMBER_OF_HISTORY_IMAGES;
+        /* Last column. */
+        x = width - 1;
+        shift = rand() % height;
+        indY = jump[shift]; // index_jump should never be zero (> 1).
+
+        while (indY <= height - 1) {
+          int index = x + indY * width;
+
+          uint8_t r = image_data[3 * index];
+          uint8_t g = image_data[3 * index + 1];
+          uint8_t b = image_data[3 * index + 2];
+
+          if (updating_mask[index] == COLOR_BACKGROUND) {
+            if (position[shift] < NUMBER_OF_HISTORY_IMAGES) {
+              historyImage[3 * index + position[shift] * (3 * width) * height] = r;
+              historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g;
+              historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b;
+            }
+            else {
+              int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES;
+
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r;
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g;
+              historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b;
+            }
+          }
+
+          ++shift;
+          indY += jump[shift];
+        }
+
+        /* The first pixel! */
+        if (rand() % model->updateFactor == 0) {
+          if (updating_mask[0] == 0) {
+            int position = rand() % model->numberOfSamples;
+
+            uint8_t r = image_data[0];
+            uint8_t g = image_data[1];
+            uint8_t b = image_data[2];
+
+            if (position < NUMBER_OF_HISTORY_IMAGES) {
+              historyImage[position * (3 * width) * height] = r;
+              historyImage[position * (3 * width) * height + 1] = g;
+              historyImage[position * (3 * width) * height + 2] = b;
+            }
+            else {
+              int pos = position - NUMBER_OF_HISTORY_IMAGES;
+
+              historyBuffer[3 * pos] = r;
+              historyBuffer[3 * pos + 1] = g;
+              historyBuffer[3 * pos + 2] = b;
+            }
+          }
+        }
 
-        historyBuffer[3 * pos] = r;
-        historyBuffer[3 * pos + 1] = g;
-        historyBuffer[3 * pos + 2] = b;
+        return(0);
       }
     }
   }
-
-  return(0);
 }
diff --git a/src/algorithms/ViBe/vibe-background-sequential.h b/src/algorithms/ViBe/vibe-background-sequential.h
index c119be4cbd9a9e49c013cbc067edcff40df4b9af..e68ba0aecaf3c845262ee82dd7d2ce451c115a98 100644
--- a/src/algorithms/ViBe/vibe-background-sequential.h
+++ b/src/algorithms/ViBe/vibe-background-sequential.h
@@ -5,239 +5,249 @@
 #include <stdio.h>
 #include <string.h>
 
-#define COLOR_BACKGROUND   0 /*!< Default label for background pixels */
-#define COLOR_FOREGROUND 255 /*!< Default label for foreground pixels. Note that some authors chose any value different from 0 instead */
-
-/**
- * \typedef struct vibeModel_Sequential_t
- * \brief Data structure for the background subtraction model.
- *
- * This data structure contains the background model as well as some paramaters value.
- * The code is designed to hide all the implementation details to the user to ease its use.
- */
-typedef struct vibeModel_Sequential vibeModel_Sequential_t;
-
-/**
- * Allocation of a new data structure where the background model will be stored.
- * Please note that this function only creates the structure to host the data.
- * This data structures will only be filled with a call to \ref libvibeModel_Sequential_AllocInit_8u_C1R.
- *
- * \result A pointer to a newly allocated \ref vibeModel_Sequential_t
- * structure, or <tt>NULL</tt> in the case of an error.
- */
-vibeModel_Sequential_t *libvibeModel_Sequential_New();
-
-/**
- * ViBe uses several parameters.
- * You can print and change some of them if you want. However, default
- * value should meet your needs for most videos.
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @return
- */
-uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model);
-
-/**
- * Setter.
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @param numberOfSamples
- * @return
- */
-int32_t libvibeModel_Sequential_SetNumberOfSamples(
-  vibeModel_Sequential_t *model,
-  const uint32_t numberOfSamples
-);
-
-/**
- * Setter.
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @return
- */
-uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model);
-
-/**
- * Setter.
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @param matchingThreshold
- * @return
- */
-int32_t libvibeModel_Sequential_SetMatchingThreshold(
-  vibeModel_Sequential_t *model,
-  const uint32_t matchingThreshold
-);
-
-/**
- * Setter.
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @return
- */
-uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model);
-
-/**
- * Setter.
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @param matchingNumber
- * @return
- */
-int32_t libvibeModel_Sequential_SetMatchingNumber(
-  vibeModel_Sequential_t *model,
-  const uint32_t matchingNumber
-);
-
-/**
- * Setter.
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @param updateFactor New value for the update factor. Please note that the update factor is to be understood as a probability of updating. More specifically, an update factor of 16 means that 1 out of every 16 background pixels is updated. Likewise, an update factor of 1 means that every background pixel is updated.
- * @return
- */
-int32_t libvibeModel_Sequential_SetUpdateFactor(
-  vibeModel_Sequential_t *model,
-  const uint32_t updateFactor
-);
-
-/**
- * Getter.
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @return
- */
-uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model);
-
-
-/**
- * Getter.
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @return
- */
-uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model);
-
-/**
- * \brief Frees all the memory used by the <tt>model</tt> and deallocates the structure.
- *
- * This function frees all the memory allocated by \ref libvibeModel_SequentialNew and
- * \ref libvibeModel_Sequential_AllocInit_8u_C1R or \ref libvibeModel_Sequential_AllocInit_8u_C3R.
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @return
- */
-int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model);
-
-/**
- * The two following functions allocate the required memory according to the
- * model parameters and the dimensions of the input images.
- * You must use the "C1R" function for grayscale images and the "C3R" for color
- * images.
- * These 2 functions also initialize the background model using the content
- * of *image_data which is the pixel buffer of the first image of your stream.
- */
- // -------------------------  Single channel images ----------------------------
- /**
-  *
-  * @param model The data structure with ViBe's background subtraction model and parameters.
-  * @param image_data
-  * @param width
-  * @param height
-  * @return
-  */
-int32_t libvibeModel_Sequential_AllocInit_8u_C1R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  const uint32_t width,
-  const uint32_t height
-);
-
-/* These 2 functions perform 2 operations:
- *   - they classify the pixels *image_data using the provided model and store
- *     the results in *segmentation_map.
- *   - they update *model according to these results and the content of
- *     *image_data.
- * You must use the "C1R" function for grayscale images and the "C3R" for color
- * images.
- */
- /**
-  *
-  * @param model The data structure with ViBe's background subtraction model and parameters.
-  * @param image_data
-  * @param segmentation_map
-  * @return
-  */
-int32_t libvibeModel_Sequential_Segmentation_8u_C1R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  uint8_t *segmentation_map
-);
-
-/**
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @param image_data
- * @param updating_mask
- * @return
- */
-int32_t libvibeModel_Sequential_Update_8u_C1R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  uint8_t *updating_mask
-);
-
-// -------------------------  Three channel images -----------------------------
-/**
- * The pixel values of color images are arranged in the following order
- * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...)
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @param image_data
- * @param width
- * @param height
- * @return
- */
-int32_t libvibeModel_Sequential_AllocInit_8u_C3R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  const uint32_t width,
-  const uint32_t height
-);
-
-/* These 2 functions perform 2 operations:
- *   - they classify the pixels *image_data using the provided model and store
- *     the results in *segmentation_map.
- *   - they update *model according to these results and the content of
- *     *image_data.
- * You must use the "C1R" function for grayscale images and the "C3R" for color
- * images.
- */
- /**
-  * The pixel values of color images are arranged in the following order
-  * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...)
-  *
-  * @param model The data structure with ViBe's background subtraction model and parameters.
-  * @param image_data
-  * @param segmentation_map
-  * @return
-  */
-int32_t libvibeModel_Sequential_Segmentation_8u_C3R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  uint8_t *segmentation_map
-);
-
-/**
- * The pixel values of color images are arranged in the following order
- * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...)
- *
- * @param model The data structure with ViBe's background subtraction model and parameters.
- * @param image_data
- * @param updating_mask
- * @return
- */
-int32_t libvibeModel_Sequential_Update_8u_C3R(
-  vibeModel_Sequential_t *model,
-  const uint8_t *image_data,
-  uint8_t *updating_mask
-);
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace vibe
+    {
+      const int COLOR_BACKGROUND = 0; // Default label for background pixels
+      const int COLOR_FOREGROUND = 255; // Default label for foreground pixels. Note that some authors chose any value different from 0 instead
+      const int NUMBER_OF_HISTORY_IMAGES = 2;
+
+      /**
+       * \typedef struct vibeModel_Sequential_t
+       * \brief Data structure for the background subtraction model.
+       *
+       * This data structure contains the background model as well as some paramaters value.
+       * The code is designed to hide all the implementation details to the user to ease its use.
+       */
+      typedef struct vibeModel_Sequential vibeModel_Sequential_t;
+
+      /**
+       * Allocation of a new data structure where the background model will be stored.
+       * Please note that this function only creates the structure to host the data.
+       * This data structures will only be filled with a call to \ref libvibeModel_Sequential_AllocInit_8u_C1R.
+       *
+       * \result A pointer to a newly allocated \ref vibeModel_Sequential_t
+       * structure, or <tt>NULL</tt> in the case of an error.
+       */
+      vibeModel_Sequential_t *libvibeModel_Sequential_New();
+
+      /**
+       * ViBe uses several parameters.
+       * You can print and change some of them if you want. However, default
+       * value should meet your needs for most videos.
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @return
+       */
+      uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model);
+
+      /**
+       * Setter.
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @param numberOfSamples
+       * @return
+       */
+      int32_t libvibeModel_Sequential_SetNumberOfSamples(
+        vibeModel_Sequential_t *model,
+        const uint32_t numberOfSamples
+      );
+
+      /**
+       * Setter.
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @return
+       */
+      uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model);
+
+      /**
+       * Setter.
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @param matchingThreshold
+       * @return
+       */
+      int32_t libvibeModel_Sequential_SetMatchingThreshold(
+        vibeModel_Sequential_t *model,
+        const uint32_t matchingThreshold
+      );
+
+      /**
+       * Setter.
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @return
+       */
+      uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model);
+
+      /**
+       * Setter.
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @param matchingNumber
+       * @return
+       */
+      int32_t libvibeModel_Sequential_SetMatchingNumber(
+        vibeModel_Sequential_t *model,
+        const uint32_t matchingNumber
+      );
+
+      /**
+       * Setter.
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @param updateFactor New value for the update factor. Please note that the update factor is to be understood as a probability of updating. More specifically, an update factor of 16 means that 1 out of every 16 background pixels is updated. Likewise, an update factor of 1 means that every background pixel is updated.
+       * @return
+       */
+      int32_t libvibeModel_Sequential_SetUpdateFactor(
+        vibeModel_Sequential_t *model,
+        const uint32_t updateFactor
+      );
+
+      /**
+       * Getter.
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @return
+       */
+      uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model);
+
+
+      /**
+       * Getter.
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @return
+       */
+      uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model);
+
+      /**
+       * \brief Frees all the memory used by the <tt>model</tt> and deallocates the structure.
+       *
+       * This function frees all the memory allocated by \ref libvibeModel_SequentialNew and
+       * \ref libvibeModel_Sequential_AllocInit_8u_C1R or \ref libvibeModel_Sequential_AllocInit_8u_C3R.
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @return
+       */
+      int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model);
+
+      /**
+       * The two following functions allocate the required memory according to the
+       * model parameters and the dimensions of the input images.
+       * You must use the "C1R" function for grayscale images and the "C3R" for color
+       * images.
+       * These 2 functions also initialize the background model using the content
+       * of *image_data which is the pixel buffer of the first image of your stream.
+       */
+      // -------------------------  Single channel images ----------------------------
+      /**
+        *
+        * @param model The data structure with ViBe's background subtraction model and parameters.
+        * @param image_data
+        * @param width
+        * @param height
+        * @return
+        */
+      int32_t libvibeModel_Sequential_AllocInit_8u_C1R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        const uint32_t width,
+        const uint32_t height
+      );
+
+      /* These 2 functions perform 2 operations:
+      *   - they classify the pixels *image_data using the provided model and store
+      *     the results in *segmentation_map.
+      *   - they update *model according to these results and the content of
+      *     *image_data.
+      * You must use the "C1R" function for grayscale images and the "C3R" for color
+      * images.
+      */
+      /**
+        *
+        * @param model The data structure with ViBe's background subtraction model and parameters.
+        * @param image_data
+        * @param segmentation_map
+        * @return
+        */
+      int32_t libvibeModel_Sequential_Segmentation_8u_C1R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        uint8_t *segmentation_map
+      );
+
+      /**
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @param image_data
+       * @param updating_mask
+       * @return
+       */
+      int32_t libvibeModel_Sequential_Update_8u_C1R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        uint8_t *updating_mask
+      );
+
+      // -------------------------  Three channel images -----------------------------
+      /**
+       * The pixel values of color images are arranged in the following order
+       * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...)
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @param image_data
+       * @param width
+       * @param height
+       * @return
+       */
+      int32_t libvibeModel_Sequential_AllocInit_8u_C3R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        const uint32_t width,
+        const uint32_t height
+      );
+
+      /* These 2 functions perform 2 operations:
+      *   - they classify the pixels *image_data using the provided model and store
+      *     the results in *segmentation_map.
+      *   - they update *model according to these results and the content of
+      *     *image_data.
+      * You must use the "C1R" function for grayscale images and the "C3R" for color
+      * images.
+      */
+      /**
+        * The pixel values of color images are arranged in the following order
+        * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...)
+        *
+        * @param model The data structure with ViBe's background subtraction model and parameters.
+        * @param image_data
+        * @param segmentation_map
+        * @return
+        */
+      int32_t libvibeModel_Sequential_Segmentation_8u_C3R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        uint8_t *segmentation_map
+      );
+
+      /**
+       * The pixel values of color images are arranged in the following order
+       * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...)
+       *
+       * @param model The data structure with ViBe's background subtraction model and parameters.
+       * @param image_data
+       * @param updating_mask
+       * @return
+       */
+      int32_t libvibeModel_Sequential_Update_8u_C3R(
+        vibeModel_Sequential_t *model,
+        const uint8_t *image_data,
+        uint8_t *updating_mask
+      );
+    }
+  }
+}
diff --git a/src/algorithms/VuMeter.h b/src/algorithms/VuMeter.h
index d10591400ecf1ff04929deb70633c9d4c2ae6908..50f62382940346b47852384654c2519b906e369a 100644
--- a/src/algorithms/VuMeter.h
+++ b/src/algorithms/VuMeter.h
@@ -13,13 +13,11 @@ namespace bgslibrary
     class VuMeter : public IBGS
     {
     private:
-      TBackgroundVuMeter bgs;
-
+      vumeter::TBackgroundVuMeter bgs;
       IplImage *frame;
       IplImage *gray;
       IplImage *background;
       IplImage *mask;
-
       bool enableFilter;
       int binSize;
       double alpha;
diff --git a/src/algorithms/VuMeter/TBackground.cpp b/src/algorithms/VuMeter/TBackground.cpp
index e961ee8912dd002d58ac3d25b81812c9b6b1bee9..19f26f8ee7b9c8f10cfa247056f46778ca19fa47 100644
--- a/src/algorithms/VuMeter/TBackground.cpp
+++ b/src/algorithms/VuMeter/TBackground.cpp
@@ -1,46 +1,37 @@
 #include "TBackground.h"
 
-TBackground::TBackground(void)
-{
+using namespace bgslibrary::algorithms::vumeter;
+
+TBackground::TBackground(){
   std::cout << "TBackground()" << std::endl;
 }
 
-TBackground::~TBackground(void)
-{
+TBackground::~TBackground(){
   Clear();
   std::cout << "~TBackground()" << std::endl;
 }
 
-void TBackground::Clear(void)
-{
-}
+void TBackground::Clear(){}
 
-void TBackground::Reset(void)
-{
-}
+void TBackground::Reset(){}
 
-int TBackground::GetParameterCount(void)
-{
+int TBackground::GetParameterCount(void){
   return 0;
 }
 
-std::string TBackground::GetParameterName(int nInd)
-{
+std::string TBackground::GetParameterName(int nInd){
   return "";
 }
 
-std::string TBackground::GetParameterValue(int nInd)
-{
+std::string TBackground::GetParameterValue(int nInd){
   return "";
 }
 
-int TBackground::SetParameterValue(int nInd, std::string csNew)
-{
+int TBackground::SetParameterValue(int nInd, std::string csNew){
   return 0;
 }
 
-int TBackground::Init(IplImage * pSource)
-{
+int TBackground::Init(IplImage * pSource){
   return 0;
 }
 
@@ -67,8 +58,7 @@ bool TBackground::isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *
   return bResult;
 }
 
-int TBackground::UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask)
-{
+int TBackground::UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask){
   return 0;
 }
 
diff --git a/src/algorithms/VuMeter/TBackground.h b/src/algorithms/VuMeter/TBackground.h
index 8f66fe2506e72f5db94cc41f7a959928c7b01599..612060da9ca22ab744b1f654261d72271fd6e518 100644
--- a/src/algorithms/VuMeter/TBackground.h
+++ b/src/algorithms/VuMeter/TBackground.h
@@ -6,25 +6,34 @@
 #include <opencv2/core/core_c.h>
 #include <opencv2/imgproc/imgproc_c.h>
 
-class TBackground
+namespace bgslibrary
 {
-public:
-  TBackground(void);
-  virtual ~TBackground(void);
+  namespace algorithms
+  {
+    namespace vumeter
+    {
+      class TBackground
+      {
+      public:
+        TBackground();
+        virtual ~TBackground();
 
-  virtual void Clear(void);
-  virtual void Reset(void);
+        virtual void Clear();
+        virtual void Reset();
 
-  virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
-  virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd);
-  virtual IplImage *CreateTestImg();
+        virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
+        virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd);
+        virtual IplImage *CreateTestImg();
 
-  virtual int GetParameterCount(void);
-  virtual std::string GetParameterName(int nInd);
-  virtual std::string GetParameterValue(int nInd);
-  virtual int SetParameterValue(int nInd, std::string csNew);
+        virtual int GetParameterCount();
+        virtual std::string GetParameterName(int nInd);
+        virtual std::string GetParameterValue(int nInd);
+        virtual int SetParameterValue(int nInd, std::string csNew);
 
-protected:
-  virtual int Init(IplImage * pSource);
-  virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
-};
+      protected:
+        virtual int Init(IplImage * pSource);
+        virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
+      };
+    }
+  }
+}
diff --git a/src/algorithms/VuMeter/TBackgroundVuMeter.cpp b/src/algorithms/VuMeter/TBackgroundVuMeter.cpp
index b0a0d4c5e01e375b79c38d4511cb9a6028ec5c70..5e5f4db349e399e352882c4b63ef7a552f80d6bc 100644
--- a/src/algorithms/VuMeter/TBackgroundVuMeter.cpp
+++ b/src/algorithms/VuMeter/TBackgroundVuMeter.cpp
@@ -1,349 +1,360 @@
 #include "TBackgroundVuMeter.h"
 
-#define PROCESS_PAR_COUNT 3
-
-TBackgroundVuMeter::TBackgroundVuMeter(void)
-  : m_pHist(NULL)
-  , m_nBinCount(0)
-  , m_nBinSize(8)
-  , m_nCount(0)
-  , m_fAlpha(0.995)
-  , m_fThreshold(0.03)
-{
-  std::cout << "TBackgroundVuMeter()" << std::endl;
-}
+//using namespace bgslibrary::algorithms::vumeter;
 
-TBackgroundVuMeter::~TBackgroundVuMeter(void)
+namespace bgslibrary
 {
-  Clear();
-  std::cout << "~TBackgroundVuMeter()" << std::endl;
-}
-
-void TBackgroundVuMeter::Clear(void)
-{
-  TBackground::Clear();
-
-  if (m_pHist != NULL)
+  namespace algorithms
   {
-    for (int i = 0; i < m_nBinCount; ++i)
+    namespace vumeter
     {
-      if (m_pHist[i] != NULL)
-        cvReleaseImage(&m_pHist[i]);
-    }
-
-    delete[] m_pHist;
-    m_pHist = NULL;
-    m_nBinCount = 0;
-  }
-
-  m_nCount = 0;
-}
-
-void TBackgroundVuMeter::Reset(void)
-{
-  float fVal = 0.0;
-
-  TBackground::Reset();
-
-  if (m_pHist != NULL)
-  {
-    //		fVal = (m_nBinCount != 0) ? (float)(1.0 / (double)m_nBinCount) : (float)0.0;
-    fVal = 0.0;
-
-    for (int i = 0; i < m_nBinCount; ++i)
-    {
-      if (m_pHist[i] != NULL)
+      const int PROCESS_PAR_COUNT = 3;
+
+      TBackgroundVuMeter::TBackgroundVuMeter(void)
+        : m_pHist(NULL)
+        , m_nBinCount(0)
+        , m_nBinSize(8)
+        , m_nCount(0)
+        , m_fAlpha(0.995)
+        , m_fThreshold(0.03)
       {
-        cvSetZero(m_pHist[i]);
-        cvAddS(m_pHist[i], cvScalar(fVal), m_pHist[i]);
+        std::cout << "TBackgroundVuMeter()" << std::endl;
       }
-    }
-  }
-
-  m_nCount = 0;
-}
-
-int TBackgroundVuMeter::GetParameterCount(void)
-{
-  return TBackground::GetParameterCount() + PROCESS_PAR_COUNT;
-}
-
-std::string TBackgroundVuMeter::GetParameterName(int nInd)
-{
-  std::string csResult;
-  int nNb;
 
-  nNb = TBackground::GetParameterCount();
+      TBackgroundVuMeter::~TBackgroundVuMeter(void)
+      {
+        Clear();
+        std::cout << "~TBackgroundVuMeter()" << std::endl;
+      }
 
-  if (nInd >= nNb)
-  {
-    nInd -= nNb;
+      void TBackgroundVuMeter::Clear(void)
+      {
+        TBackground::Clear();
+
+        if (m_pHist != NULL)
+        {
+          for (int i = 0; i < m_nBinCount; ++i)
+          {
+            if (m_pHist[i] != NULL)
+              cvReleaseImage(&m_pHist[i]);
+          }
+
+          delete[] m_pHist;
+          m_pHist = NULL;
+          m_nBinCount = 0;
+        }
+
+        m_nCount = 0;
+      }
 
-    switch (nInd)
-    {
-    case 0: csResult = "Bin size"; break;
-    case 1: csResult = "Alpha"; break;
-    case 2: csResult = "Threshold"; break;
-    }
-  }
-  else
-    csResult = TBackground::GetParameterName(nInd);
+      void TBackgroundVuMeter::Reset(void)
+      {
+        float fVal = 0.0;
+
+        TBackground::Reset();
+
+        if (m_pHist != NULL)
+        {
+          //		fVal = (m_nBinCount != 0) ? (float)(1.0 / (double)m_nBinCount) : (float)0.0;
+          fVal = 0.0;
+
+          for (int i = 0; i < m_nBinCount; ++i)
+          {
+            if (m_pHist[i] != NULL)
+            {
+              cvSetZero(m_pHist[i]);
+              cvAddS(m_pHist[i], cvScalar(fVal), m_pHist[i]);
+            }
+          }
+        }
+
+        m_nCount = 0;
+      }
 
-  return csResult;
-}
+      int TBackgroundVuMeter::GetParameterCount(void)
+      {
+        return TBackground::GetParameterCount() + PROCESS_PAR_COUNT;
+      }
 
-std::string TBackgroundVuMeter::GetParameterValue(int nInd)
-{
-  std::string csResult;
-  int nNb;
+      std::string TBackgroundVuMeter::GetParameterName(int nInd)
+      {
+        std::string csResult;
+        int nNb;
+
+        nNb = TBackground::GetParameterCount();
+
+        if (nInd >= nNb)
+        {
+          nInd -= nNb;
+
+          switch (nInd)
+          {
+          case 0: csResult = "Bin size"; break;
+          case 1: csResult = "Alpha"; break;
+          case 2: csResult = "Threshold"; break;
+          }
+        }
+        else
+          csResult = TBackground::GetParameterName(nInd);
+
+        return csResult;
+      }
 
-  nNb = TBackground::GetParameterCount();
+      std::string TBackgroundVuMeter::GetParameterValue(int nInd)
+      {
+        std::string csResult;
+        int nNb;
 
-  if (nInd >= nNb)
-  {
-    nInd -= nNb;
+        nNb = TBackground::GetParameterCount();
 
-    char buff[100];
+        if (nInd >= nNb)
+        {
+          nInd -= nNb;
 
-    switch (nInd)
-    {
-    case 0: sprintf(buff, "%d", m_nBinSize); break;
-    case 1: sprintf(buff, "%.3f", m_fAlpha); break;
-    case 2: sprintf(buff, "%.2f", m_fThreshold); break;
-    }
+          char buff[100];
 
-    csResult = buff;
-  }
-  else
-    csResult = TBackground::GetParameterValue(nInd);
+          switch (nInd)
+          {
+          case 0: sprintf_s(buff, "%d", m_nBinSize); break;
+          case 1: sprintf_s(buff, "%.3f", m_fAlpha); break;
+          case 2: sprintf_s(buff, "%.2f", m_fThreshold); break;
+          }
 
-  return csResult;
-}
+          csResult = buff;
+        }
+        else
+          csResult = TBackground::GetParameterValue(nInd);
 
-int TBackgroundVuMeter::SetParameterValue(int nInd, std::string csNew)
-{
-  int nErr = 0;
+        return csResult;
+      }
 
-  int nNb;
+      int TBackgroundVuMeter::SetParameterValue(int nInd, std::string csNew)
+      {
+        int nErr = 0;
 
-  nNb = TBackground::GetParameterCount();
+        int nNb;
 
-  if (nInd >= nNb)
-  {
-    nInd -= nNb;
+        nNb = TBackground::GetParameterCount();
 
-    switch (nInd)
-    {
-    case 0: SetBinSize(atoi(csNew.c_str())); break;
-    case 1: SetAlpha(atof(csNew.c_str())); break;
-    case 2: SetThreshold(atof(csNew.c_str())); break;
-    default: nErr = 1;
-    }
-  }
-  else
-    nErr = TBackground::SetParameterValue(nInd, csNew);
+        if (nInd >= nNb)
+        {
+          nInd -= nNb;
 
-  return nErr;
-}
+          switch (nInd)
+          {
+          case 0: SetBinSize(atoi(csNew.c_str())); break;
+          case 1: SetAlpha(atof(csNew.c_str())); break;
+          case 2: SetThreshold(atof(csNew.c_str())); break;
+          default: nErr = 1;
+          }
+        }
+        else
+          nErr = TBackground::SetParameterValue(nInd, csNew);
 
-int TBackgroundVuMeter::Init(IplImage * pSource)
-{
-  int nErr = 0;
-  int nbl, nbc;
+        return nErr;
+      }
 
-  Clear();
+      int TBackgroundVuMeter::Init(IplImage * pSource)
+      {
+        int nErr = 0;
+        int nbl, nbc;
+
+        Clear();
+
+        nErr = TBackground::Init(pSource);
+
+        if (pSource == NULL)
+          nErr = 1;
+
+        // calcul le nb de bin
+        if (!nErr)
+        {
+          nbl = pSource->height;
+          nbc = pSource->width;
+          m_nBinCount = (m_nBinSize != 0) ? 256 / m_nBinSize : 0;
+
+          if (m_nBinCount <= 0 || m_nBinCount > 256)
+            nErr = 1;
+        }
+
+        // creation du tableau de pointeur
+        if (!nErr)
+        {
+          m_pHist = new IplImage *[m_nBinCount];
+
+          if (m_pHist == NULL)
+            nErr = 1;
+        }
+
+        // creation des images
+        if (!nErr)
+        {
+          for (int i = 0; i < m_nBinCount; ++i)
+          {
+            m_pHist[i] = cvCreateImage(cvSize(nbc, nbl), IPL_DEPTH_32F, 1);
+
+            if (m_pHist[i] == NULL)
+              nErr = 1;
+          }
+        }
+
+        if (!nErr)
+          Reset();
+        else
+          Clear();
+
+        return nErr;
+      }
 
-  nErr = TBackground::Init(pSource);
+      bool TBackgroundVuMeter::isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask)
+      {
+        bool bResult = true;
+        int i;
 
-  if (pSource == NULL)
-    nErr = 1;
+        bResult = TBackground::isInitOk(pSource, pBackground, pMotionMask);
 
-  // calcul le nb de bin
-  if (!nErr)
-  {
-    nbl = pSource->height;
-    nbc = pSource->width;
-    m_nBinCount = (m_nBinSize != 0) ? 256 / m_nBinSize : 0;
+        if (pSource == NULL)
+          bResult = false;
 
-    if (m_nBinCount <= 0 || m_nBinCount > 256)
-      nErr = 1;
-  }
+        if (m_nBinSize == 0)
+          bResult = false;
 
-  // creation du tableau de pointeur
-  if (!nErr)
-  {
-    m_pHist = new IplImage *[m_nBinCount];
+        if (bResult)
+        {
+          i = (m_nBinSize != 0) ? 256 / m_nBinSize : 0;
 
-    if (m_pHist == NULL)
-      nErr = 1;
-  }
+          if (i != m_nBinCount || m_pHist == NULL)
+            bResult = false;
+        }
 
-  // creation des images
-  if (!nErr)
-  {
-    for (int i = 0; i < m_nBinCount; ++i)
-    {
-      m_pHist[i] = cvCreateImage(cvSize(nbc, nbl), IPL_DEPTH_32F, 1);
+        if (bResult)
+        {
+          int nbl = pSource->height;
+          int nbc = pSource->width;
 
-      if (m_pHist[i] == NULL)
-        nErr = 1;
-    }
-  }
+          for (i = 0; i < m_nBinCount; ++i)
+          {
+            if (m_pHist[i] == NULL || m_pHist[i]->width != nbc || m_pHist[i]->height != nbl)
+              bResult = false;
+          }
+        }
 
-  if (!nErr)
-    Reset();
-  else
-    Clear();
+        return bResult;
+      }
 
-  return nErr;
-}
+      int TBackgroundVuMeter::UpdateBackground(IplImage *pSource, IplImage *pBackground, IplImage *pMotionMask)
+      {
+        int nErr = 0;
+        unsigned char *ptrs, *ptrb, *ptrm;
+        float *ptr1, *ptr2;
 
-bool TBackgroundVuMeter::isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask)
-{
-  bool bResult = true;
-  int i;
+        if (!isInitOk(pSource, pBackground, pMotionMask))
+          nErr = Init(pSource);
 
-  bResult = TBackground::isInitOk(pSource, pBackground, pMotionMask);
+        if (!nErr)
+        {
+          m_nCount++;
+          int nbc = pSource->width;
+          int nbl = pSource->height;
+          unsigned char v = m_nBinSize;
 
-  if (pSource == NULL)
-    bResult = false;
+          // multiplie tout par alpha
+          for (int i = 0; i < m_nBinCount; ++i)
+            cvConvertScale(m_pHist[i], m_pHist[i], m_fAlpha, 0.0);
 
-  if (m_nBinSize == 0)
-    bResult = false;
+          for (int l = 0; l < nbl; ++l)
+          {
+            ptrs = (unsigned char *)(pSource->imageData + pSource->widthStep * l);
+            ptrm = (unsigned char *)(pMotionMask->imageData + pMotionMask->widthStep * l);
+            ptrb = (unsigned char *)(pBackground->imageData + pBackground->widthStep * l);
 
-  if (bResult)
-  {
-    i = (m_nBinSize != 0) ? 256 / m_nBinSize : 0;
+            for (int c = 0; c < nbc; ++c, ptrs++, ptrb++, ptrm++)
+            {
+              // recherche le bin à augmenter
+              int i = *ptrs / v;
 
-    if (i != m_nBinCount || m_pHist == NULL)
-      bResult = false;
-  }
+              if (i < 0 || i >= m_nBinCount)
+                i = 0;
 
-  if (bResult)
-  {
-    int nbl = pSource->height;
-    int nbc = pSource->width;
+              ptr1 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l);
+              ptr1 += c;
 
-    for (i = 0; i < m_nBinCount; ++i)
-    {
-      if (m_pHist[i] == NULL || m_pHist[i]->width != nbc || m_pHist[i]->height != nbl)
-        bResult = false;
-    }
-  }
+              *ptr1 += (float)(1.0 - m_fAlpha);
+              *ptrm = (*ptr1 < m_fThreshold) ? 255 : 0;
 
-  return bResult;
-}
+              // recherche le bin du fond actuel
+              i = *ptrb / v;
 
-int TBackgroundVuMeter::UpdateBackground(IplImage *pSource, IplImage *pBackground, IplImage *pMotionMask)
-{
-  int nErr = 0;
-  unsigned char *ptrs, *ptrb, *ptrm;
-  float *ptr1, *ptr2;
+              if (i < 0 || i >= m_nBinCount)
+                i = 0;
 
-  if (!isInitOk(pSource, pBackground, pMotionMask))
-    nErr = Init(pSource);
+              ptr2 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l);
+              ptr2 += c;
 
-  if (!nErr)
-  {
-    m_nCount++;
-    int nbc = pSource->width;
-    int nbl = pSource->height;
-    unsigned char v = m_nBinSize;
+              if (*ptr2 < *ptr1)
+                *ptrb = *ptrs;
+            }
+          }
 
-    // multiplie tout par alpha
-    for (int i = 0; i < m_nBinCount; ++i)
-      cvConvertScale(m_pHist[i], m_pHist[i], m_fAlpha, 0.0);
+          if (m_nCount < 5)
+            cvSetZero(pMotionMask);
+        }
 
-    for (int l = 0; l < nbl; ++l)
-    {
-      ptrs = (unsigned char *)(pSource->imageData + pSource->widthStep * l);
-      ptrm = (unsigned char *)(pMotionMask->imageData + pMotionMask->widthStep * l);
-      ptrb = (unsigned char *)(pBackground->imageData + pBackground->widthStep * l);
+        return nErr;
+      }
 
-      for (int c = 0; c < nbc; ++c, ptrs++, ptrb++, ptrm++)
+      IplImage *TBackgroundVuMeter::CreateTestImg()
       {
-        // recherche le bin à augmenter
-        int i = *ptrs / v;
-
-        if (i < 0 || i >= m_nBinCount)
-          i = 0;
-
-        ptr1 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l);
-        ptr1 += c;
+        IplImage *pImage = NULL;
 
-        *ptr1 += (float)(1.0 - m_fAlpha);
-        *ptrm = (*ptr1 < m_fThreshold) ? 255 : 0;
+        if (m_nBinCount > 0)
+          pImage = cvCreateImage(cvSize(m_nBinCount, 100), IPL_DEPTH_8U, 3);
 
-        // recherche le bin du fond actuel
-        i = *ptrb / v;
+        if (pImage != NULL)
+          cvSetZero(pImage);
 
-        if (i < 0 || i >= m_nBinCount)
-          i = 0;
-
-        ptr2 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l);
-        ptr2 += c;
-
-        if (*ptr2 < *ptr1)
-          *ptrb = *ptrs;
+        return pImage;
       }
-    }
-
-    if (m_nCount < 5)
-      cvSetZero(pMotionMask);
-  }
-
-  return nErr;
-}
 
-IplImage *TBackgroundVuMeter::CreateTestImg()
-{
-  IplImage *pImage = NULL;
+      int TBackgroundVuMeter::UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd)
+      {
+        int nErr = 0;
+        float *ptrf;
 
-  if (m_nBinCount > 0)
-    pImage = cvCreateImage(cvSize(m_nBinCount, 100), IPL_DEPTH_8U, 3);
+        if (pTest == NULL || !isInitOk(pSource, pBackground, pSource))
+          nErr = 1;
 
-  if (pImage != NULL)
-    cvSetZero(pImage);
+        if (!nErr)
+        {
+          int nbl = pTest->height;
+          int nbc = pTest->width;
 
-  return pImage;
-}
+          if (nbl != 100 || nbc != m_nBinCount)
+            nErr = 1;
 
-int TBackgroundVuMeter::UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd)
-{
-  int nErr = 0;
-  float *ptrf;
+          if (nX < 0 || nX >= pSource->width || nY < 0 || nY >= pSource->height)
+            nErr = 1;
+        }
 
-  if (pTest == NULL || !isInitOk(pSource, pBackground, pSource))
-    nErr = 1;
+        if (!nErr)
+        {
+          cvSetZero(pTest);
 
-  if (!nErr)
-  {
-    int nbl = pTest->height;
-    int nbc = pTest->width;
+          for (int i = 0; i < m_nBinCount; ++i)
+          {
+            ptrf = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * nY);
+            ptrf += nX;
 
-    if (nbl != 100 || nbc != m_nBinCount)
-      nErr = 1;
+            if (*ptrf >= 0 || *ptrf <= 1.0) {
+              cvLine(pTest, cvPoint(i, 100), cvPoint(i, (int)(100.0 * (1.0 - *ptrf))), cvScalar(0, 255, 0));
+            }
+          }
 
-    if (nX < 0 || nX >= pSource->width || nY < 0 || nY >= pSource->height)
-      nErr = 1;
-  }
+          cvLine(pTest, cvPoint(0, (int)(100.0 * (1.0 - m_fThreshold))), cvPoint(m_nBinCount, (int)(100.0 * (1.0 - m_fThreshold))), cvScalar(0, 128, 0));
+        }
 
-  if (!nErr)
-  {
-    cvSetZero(pTest);
-
-    for (int i = 0; i < m_nBinCount; ++i)
-    {
-      ptrf = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * nY);
-      ptrf += nX;
-
-      if (*ptrf >= 0 || *ptrf <= 1.0) {
-        cvLine(pTest, cvPoint(i, 100), cvPoint(i, (int)(100.0 * (1.0 - *ptrf))), cvScalar(0, 255, 0));
+        return nErr;
       }
     }
-
-    cvLine(pTest, cvPoint(0, (int)(100.0 * (1.0 - m_fThreshold))), cvPoint(m_nBinCount, (int)(100.0 * (1.0 - m_fThreshold))), cvScalar(0, 128, 0));
   }
-
-  return nErr;
 }
diff --git a/src/algorithms/VuMeter/TBackgroundVuMeter.h b/src/algorithms/VuMeter/TBackgroundVuMeter.h
index 1d63aecab2d0867bafe492fdb27bcf8481dbc435..89cfc22351d9659d7c6697cd97aca4d6a5174eaa 100644
--- a/src/algorithms/VuMeter/TBackgroundVuMeter.h
+++ b/src/algorithms/VuMeter/TBackgroundVuMeter.h
@@ -2,43 +2,52 @@
 
 #include "TBackground.h"
 
-class TBackgroundVuMeter : public TBackground
+namespace bgslibrary
 {
-public:
-  TBackgroundVuMeter(void);
-  virtual ~TBackgroundVuMeter(void);
-
-  virtual void Clear(void);
-  virtual void Reset(void);
-
-  virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
-
-  virtual IplImage *CreateTestImg();
-  virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd);
-
-  virtual int GetParameterCount(void);
-  virtual std::string GetParameterName(int nInd);
-  virtual std::string GetParameterValue(int nInd);
-  virtual int SetParameterValue(int nInd, std::string csNew);
-
-  inline void SetBinSize(int nNew) { m_nBinSize = (nNew > 0 && nNew < 255) ? nNew : 8; }
-  inline double GetBinSize() { return m_nBinSize; }
-
-  inline void SetAlpha(double fNew) { m_fAlpha = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.995; }
-  inline double GetAlpha() { return m_fAlpha; }
-
-  inline void SetThreshold(double fNew) { m_fThreshold = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.03; }
-  inline double GetThreshold() { return m_fThreshold; }
-
-protected:
-  IplImage **m_pHist;
-
-  int m_nBinCount;
-  int m_nBinSize;
-  int m_nCount;
-  double m_fAlpha;
-  double m_fThreshold;
-
-  virtual int Init(IplImage * pSource);
-  virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
-};
+  namespace algorithms
+  {
+    namespace vumeter
+    {
+      class TBackgroundVuMeter : public TBackground
+      {
+      public:
+        TBackgroundVuMeter(void);
+        virtual ~TBackgroundVuMeter(void);
+
+        virtual void Clear(void);
+        virtual void Reset(void);
+
+        virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
+
+        virtual IplImage *CreateTestImg();
+        virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd);
+
+        virtual int GetParameterCount(void);
+        virtual std::string GetParameterName(int nInd);
+        virtual std::string GetParameterValue(int nInd);
+        virtual int SetParameterValue(int nInd, std::string csNew);
+
+        inline void SetBinSize(int nNew) { m_nBinSize = (nNew > 0 && nNew < 255) ? nNew : 8; }
+        inline double GetBinSize() { return m_nBinSize; }
+
+        inline void SetAlpha(double fNew) { m_fAlpha = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.995; }
+        inline double GetAlpha() { return m_fAlpha; }
+
+        inline void SetThreshold(double fNew) { m_fThreshold = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.03; }
+        inline double GetThreshold() { return m_fThreshold; }
+
+      protected:
+        IplImage **m_pHist;
+
+        int m_nBinCount;
+        int m_nBinSize;
+        int m_nCount;
+        double m_fAlpha;
+        double m_fThreshold;
+
+        virtual int Init(IplImage * pSource);
+        virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
+      };
+    }
+  }
+}
diff --git a/src/algorithms/dp/AdaptiveMedianBGS.cpp b/src/algorithms/dp/AdaptiveMedianBGS.cpp
index 231a6b59ceb2669dc0cdf275aed6bd533a2ab184..2609fb0906cc11900502b8fa6afb650b64db5471 100644
--- a/src/algorithms/dp/AdaptiveMedianBGS.cpp
+++ b/src/algorithms/dp/AdaptiveMedianBGS.cpp
@@ -2,12 +2,11 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+using namespace bgslibrary::algorithms::dp;
 
 void AdaptiveMedianBGS::Initalize(const BgsParams& param)
 {
   m_params = (AdaptiveMedianParams&)param;
-
   m_median = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
   cvSet(m_median.Ptr(), CV_RGB(BACKGROUND, BACKGROUND, BACKGROUND));
 }
diff --git a/src/algorithms/dp/AdaptiveMedianBGS.h b/src/algorithms/dp/AdaptiveMedianBGS.h
index 55a68190d7295eceb0297b85e16589b388f76723..0a9d1c7f2fff306ac1fb6534ed70de9d27506120 100644
--- a/src/algorithms/dp/AdaptiveMedianBGS.h
+++ b/src/algorithms/dp/AdaptiveMedianBGS.h
@@ -9,10 +9,12 @@
 
 #include "Bgs.h"
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
+    namespace dp
+    {
     // --- Parameters used by the Adaptive Median BGS algorithm ---
     class AdaptiveMedianParams : public BgsParams
     {
@@ -55,6 +57,7 @@ namespace Algorithms
 
       RgbImage m_median;
     };
+    }
   }
 }
 
diff --git a/src/algorithms/dp/Bgs.h b/src/algorithms/dp/Bgs.h
index b083d5f318c2ef8565d576e061bc9c9b20bfc6c5..7f1c1ea93be7b7e361f54cecab64407df5ce5ff3 100644
--- a/src/algorithms/dp/Bgs.h
+++ b/src/algorithms/dp/Bgs.h
@@ -6,10 +6,12 @@
 #include "Image.h"
 #include "BgsParams.h"
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
+    namespace dp
+    {
     class Bgs
     {
     public:
@@ -37,6 +39,7 @@ namespace Algorithms
       // Return the current background model.
       virtual RgbImage *Background() = 0;
     };
+    }
   }
 }
 
diff --git a/src/algorithms/dp/BgsParams.h b/src/algorithms/dp/BgsParams.h
index 79539b7f19285231815c8ab6669811c5e340c0a3..5f1ed6b0960fbfd82405ef7a540a52d789952d63 100644
--- a/src/algorithms/dp/BgsParams.h
+++ b/src/algorithms/dp/BgsParams.h
@@ -1,9 +1,11 @@
 #pragma once
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
+    namespace dp
+    {
     class BgsParams
     {
     public:
@@ -25,5 +27,6 @@ namespace Algorithms
       unsigned int m_height;
       unsigned int m_size;
     };
+    }
   }
 }
diff --git a/src/algorithms/dp/Eigenbackground.cpp b/src/algorithms/dp/Eigenbackground.cpp
index c207fbb1199c8548c18d294cbe7f7417524f7fda..e8c3aea034baed42b7a65a8402b35c7f08335fb6 100644
--- a/src/algorithms/dp/Eigenbackground.cpp
+++ b/src/algorithms/dp/Eigenbackground.cpp
@@ -2,7 +2,7 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+using namespace bgslibrary::algorithms::dp;
 
 Eigenbackground::Eigenbackground()
 {
diff --git a/src/algorithms/dp/Eigenbackground.h b/src/algorithms/dp/Eigenbackground.h
index 4808493f652f7519d52c9c93362414abf960a4cd..9f44e42846b3d33aa6d0b6e505bae27120d7a6e9 100644
--- a/src/algorithms/dp/Eigenbackground.h
+++ b/src/algorithms/dp/Eigenbackground.h
@@ -5,10 +5,12 @@
 
 #include "Bgs.h"
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
+    namespace dp
+    {
     // --- Parameters used by the Mean BGS algorithm ---
     class EigenbackgroundParams : public BgsParams
     {
@@ -57,6 +59,7 @@ namespace Algorithms
 
       RgbImage m_background;
     };
+    }
   }
 }
 
diff --git a/src/algorithms/dp/Error.cpp b/src/algorithms/dp/Error.cpp
index 0ccb18091022eb582b0b795c7810b0e8830320eb..f2958cd91ae1863c767106f2ff2c067c6c445578 100644
--- a/src/algorithms/dp/Error.cpp
+++ b/src/algorithms/dp/Error.cpp
@@ -3,29 +3,37 @@
 
 #include "Error.h"
 
-using namespace std;
+//using namespace bgslibrary::algorithms::dp;
 
-ofstream traceFile;
-
-bool Error(const char* msg, const char* code, int data)
-{
-  cerr << code << ": " << msg << endl;
-
-  return false;
-}
-
-bool TraceInit(const char* filename)
-{
-  traceFile.open(filename);
-  return traceFile.is_open();
-}
-
-void Trace(const char* msg)
-{
-  traceFile << msg << endl;
-}
-
-void TraceClose()
+namespace bgslibrary
 {
-  traceFile.close();
+  namespace algorithms
+  {
+    namespace dp
+    {
+      std::ofstream traceFile;
+
+      bool Error(const char* msg, const char* code, int data)
+      {
+        std::cerr << code << ": " << msg << std::endl;
+        return false;
+      }
+
+      bool TraceInit(const char* filename)
+      {
+        traceFile.open(filename);
+        return traceFile.is_open();
+      }
+
+      void Trace(const char* msg)
+      {
+        traceFile << msg << std::endl;
+      }
+
+      void TraceClose()
+      {
+        traceFile.close();
+      }
+    }
+  }
 }
diff --git a/src/algorithms/dp/Error.h b/src/algorithms/dp/Error.h
index a499e00534ebf6b992634f1d34ca11699494755b..3695f8e0410a74ddf519d2e4ee88cc0e6fd9d345 100644
--- a/src/algorithms/dp/Error.h
+++ b/src/algorithms/dp/Error.h
@@ -1,6 +1,15 @@
 #pragma once
 
-bool Error(const char* msg, const char* code, int data);
-bool TraceInit(const char* filename);
-void Trace(const char* msg);
-void TraceClose();
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    namespace dp
+    {
+      bool Error(const char* msg, const char* code, int data);
+      bool TraceInit(const char* filename);
+      void Trace(const char* msg);
+      void TraceClose();
+    }
+  }
+}
diff --git a/src/algorithms/dp/GrimsonGMM.cpp b/src/algorithms/dp/GrimsonGMM.cpp
index b60e0f63d01234f16db8265de9fbc4537a1acf17..cc6111fcbc41779f9c5990aac0c775c79e70ddac 100644
--- a/src/algorithms/dp/GrimsonGMM.cpp
+++ b/src/algorithms/dp/GrimsonGMM.cpp
@@ -2,288 +2,297 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+//using namespace bgslibrary::algorithms::dp;
 
-int compareGMM(const void* _gmm1, const void* _gmm2)
+namespace bgslibrary
 {
-  GMM gmm1 = *(GMM*)_gmm1;
-  GMM gmm2 = *(GMM*)_gmm2;
-
-  if (gmm1.significants < gmm2.significants)
-    return 1;
-  else if (gmm1.significants == gmm2.significants)
-    return 0;
-  else
-    return -1;
-}
-
-GrimsonGMM::GrimsonGMM()
-{
-  m_modes = NULL;
-}
-
-GrimsonGMM::~GrimsonGMM()
-{
-  delete[] m_modes;
-}
-
-void GrimsonGMM::Initalize(const BgsParams& param)
-{
-  m_params = (GrimsonParams&)param;
-
-  // Tbf - the threshold
-  m_bg_threshold = 0.75f;	// 1-cf from the paper
-
-  // Tgenerate - the threshold
-  m_variance = 36.0f;		// sigma for the new mode
-
-  // GMM for each pixel
-  m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
-
-  // used modes per pixel
-  m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
-
-  m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
-}
-
-RgbImage* GrimsonGMM::Background()
-{
-  return &m_background;
-}
-
-void GrimsonGMM::InitModel(const RgbImage& data)
-{
-  m_modes_per_pixel.Clear();
-
-  for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
+  namespace algorithms
   {
-    m_modes[i].weight = 0;
-    m_modes[i].variance = 0;
-    m_modes[i].muR = 0;
-    m_modes[i].muG = 0;
-    m_modes[i].muB = 0;
-    m_modes[i].significants = 0;
-  }
-}
-
-void GrimsonGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask)
-{
-  // it doesn't make sense to have conditional updates in the GMM framework
-}
-
-void GrimsonGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes,
-  unsigned char& low_threshold, unsigned char& high_threshold)
-{
-  // calculate distances to the modes (+ sort???)
-  // here we need to go in descending order!!!
-  long pos;
-  bool bFitsPDF = false;
-  bool bBackgroundLow = false;
-  bool bBackgroundHigh = false;
+    namespace dp
+    {
+      int compareGMM(const void* _gmm1, const void* _gmm2)
+      {
+        GMM gmm1 = *(GMM*)_gmm1;
+        GMM gmm2 = *(GMM*)_gmm2;
+
+        if (gmm1.significants < gmm2.significants)
+          return 1;
+        else if (gmm1.significants == gmm2.significants)
+          return 0;
+        else
+          return -1;
+      }
 
-  float fOneMinAlpha = 1 - m_params.Alpha();
+      GrimsonGMM::GrimsonGMM()
+      {
+        m_modes = NULL;
+      }
 
-  float totalWeight = 0.0f;
+      GrimsonGMM::~GrimsonGMM()
+      {
+        delete[] m_modes;
+      }
 
-  // calculate number of Gaussians to include in the background model
-  int backgroundGaussians = 0;
-  double sum = 0.0;
-  for (int i = 0; i < numModes; ++i)
-  {
-    if (sum < m_bg_threshold)
-    {
-      backgroundGaussians++;
-      sum += m_modes[posPixel + i].weight;
-    }
-    else
-    {
-      break;
-    }
-  }
+      void GrimsonGMM::Initalize(const BgsParams& param)
+      {
+        m_params = (GrimsonParams&)param;
 
-  // update all distributions and check for match with current pixel
-  for (int iModes = 0; iModes < numModes; iModes++)
-  {
-    pos = posPixel + iModes;
-    float weight = m_modes[pos].weight;
+        // Tbf - the threshold
+        m_bg_threshold = 0.75f;	// 1-cf from the paper
 
-    // fit not found yet
-    if (!bFitsPDF)
-    {
-      //check if it belongs to some of the modes
-      //calculate distance
-      float var = m_modes[pos].variance;
-      float muR = m_modes[pos].muR;
-      float muG = m_modes[pos].muG;
-      float muB = m_modes[pos].muB;
+        // Tgenerate - the threshold
+        m_variance = 36.0f;		// sigma for the new mode
 
-      float dR = muR - pixel(0);
-      float dG = muG - pixel(1);
-      float dB = muB - pixel(2);
+        // GMM for each pixel
+        m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
 
-      // calculate the squared distance
-      float dist = (dR*dR + dG*dG + dB*dB);
+        // used modes per pixel
+        m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
 
-      if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
-        bBackgroundHigh = true;
+        m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+      }
 
-      // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution
-      if (dist < m_params.LowThreshold()*var)
+      RgbImage* GrimsonGMM::Background()
       {
-        bFitsPDF = true;
-
-        // check if this Gaussian is part of the background model
-        if (iModes < backgroundGaussians)
-          bBackgroundLow = true;
-
-        //update distribution
-        float k = m_params.Alpha() / weight;
-        weight = fOneMinAlpha*weight + m_params.Alpha();
-        m_modes[pos].weight = weight;
-        m_modes[pos].muR = muR - k*(dR);
-        m_modes[pos].muG = muG - k*(dG);
-        m_modes[pos].muB = muB - k*(dB);
-
-        //limit the variance
-        float sigmanew = var + k*(dist - var);
-        m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew;
-        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+        return &m_background;
       }
-      else
+
+      void GrimsonGMM::InitModel(const RgbImage& data)
       {
-        weight = fOneMinAlpha*weight;
-        if (weight < 0.0)
+        m_modes_per_pixel.Clear();
+
+        for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
         {
-          weight = 0.0;
-          numModes--;
+          m_modes[i].weight = 0;
+          m_modes[i].variance = 0;
+          m_modes[i].muR = 0;
+          m_modes[i].muG = 0;
+          m_modes[i].muB = 0;
+          m_modes[i].significants = 0;
         }
-
-        m_modes[pos].weight = weight;
-        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
       }
-    }
-    else
-    {
-      weight = fOneMinAlpha*weight;
-      if (weight < 0.0)
+
+      void GrimsonGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask)
       {
-        weight = 0.0;
-        numModes--;
+        // it doesn't make sense to have conditional updates in the GMM framework
       }
-      m_modes[pos].weight = weight;
-      m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
-    }
 
-    totalWeight += weight;
-  }
+      void GrimsonGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes,
+        unsigned char& low_threshold, unsigned char& high_threshold)
+      {
+        // calculate distances to the modes (+ sort???)
+        // here we need to go in descending order!!!
+        long pos;
+        bool bFitsPDF = false;
+        bool bBackgroundLow = false;
+        bool bBackgroundHigh = false;
 
-  // renormalize weights so they add to one
-  double invTotalWeight = 1.0 / totalWeight;
-  for (int iLocal = 0; iLocal < numModes; iLocal++)
-  {
-    m_modes[posPixel + iLocal].weight *= (float)invTotalWeight;
-    m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight
-      / sqrt(m_modes[posPixel + iLocal].variance);
-  }
+        float fOneMinAlpha = 1 - m_params.Alpha();
 
-  // Sort significance values so they are in desending order.
-  qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareGMM);
+        float totalWeight = 0.0f;
 
-  // make new mode if needed and exit
-  if (!bFitsPDF)
-  {
-    if (numModes < m_params.MaxModes())
-    {
-      numModes++;
-    }
-    else
-    {
-      // the weakest mode will be replaced
-    }
-
-    pos = posPixel + numModes - 1;
-
-    m_modes[pos].muR = pixel.ch[0];
-    m_modes[pos].muG = pixel.ch[1];
-    m_modes[pos].muB = pixel.ch[2];
-    m_modes[pos].variance = m_variance;
-    m_modes[pos].significants = 0;			// will be set below
+        // calculate number of Gaussians to include in the background model
+        int backgroundGaussians = 0;
+        double sum = 0.0;
+        for (int i = 0; i < numModes; ++i)
+        {
+          if (sum < m_bg_threshold)
+          {
+            backgroundGaussians++;
+            sum += m_modes[posPixel + i].weight;
+          }
+          else
+          {
+            break;
+          }
+        }
 
-    if (numModes == 1)
-      m_modes[pos].weight = 1;
-    else
-      m_modes[pos].weight = m_params.Alpha();
+        // update all distributions and check for match with current pixel
+        for (int iModes = 0; iModes < numModes; iModes++)
+        {
+          pos = posPixel + iModes;
+          float weight = m_modes[pos].weight;
+
+          // fit not found yet
+          if (!bFitsPDF)
+          {
+            //check if it belongs to some of the modes
+            //calculate distance
+            float var = m_modes[pos].variance;
+            float muR = m_modes[pos].muR;
+            float muG = m_modes[pos].muG;
+            float muB = m_modes[pos].muB;
+
+            float dR = muR - pixel(0);
+            float dG = muG - pixel(1);
+            float dB = muB - pixel(2);
+
+            // calculate the squared distance
+            float dist = (dR*dR + dG*dG + dB*dB);
+
+            if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
+              bBackgroundHigh = true;
+
+            // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution
+            if (dist < m_params.LowThreshold()*var)
+            {
+              bFitsPDF = true;
+
+              // check if this Gaussian is part of the background model
+              if (iModes < backgroundGaussians)
+                bBackgroundLow = true;
+
+              //update distribution
+              float k = m_params.Alpha() / weight;
+              weight = fOneMinAlpha*weight + m_params.Alpha();
+              m_modes[pos].weight = weight;
+              m_modes[pos].muR = muR - k*(dR);
+              m_modes[pos].muG = muG - k*(dG);
+              m_modes[pos].muB = muB - k*(dB);
+
+              //limit the variance
+              float sigmanew = var + k*(dist - var);
+              m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew;
+              m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+            }
+            else
+            {
+              weight = fOneMinAlpha*weight;
+              if (weight < 0.0)
+              {
+                weight = 0.0;
+                numModes--;
+              }
+
+              m_modes[pos].weight = weight;
+              m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+            }
+          }
+          else
+          {
+            weight = fOneMinAlpha*weight;
+            if (weight < 0.0)
+            {
+              weight = 0.0;
+              numModes--;
+            }
+            m_modes[pos].weight = weight;
+            m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+          }
+
+          totalWeight += weight;
+        }
 
-    //renormalize weights
-    int iLocal;
-    float sum = 0.0;
-    for (iLocal = 0; iLocal < numModes; iLocal++)
-    {
-      sum += m_modes[posPixel + iLocal].weight;
-    }
+        // renormalize weights so they add to one
+        double invTotalWeight = 1.0 / totalWeight;
+        for (int iLocal = 0; iLocal < numModes; iLocal++)
+        {
+          m_modes[posPixel + iLocal].weight *= (float)invTotalWeight;
+          m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight
+            / sqrt(m_modes[posPixel + iLocal].variance);
+        }
 
-    double invSum = 1.0 / sum;
-    for (iLocal = 0; iLocal < numModes; iLocal++)
-    {
-      m_modes[posPixel + iLocal].weight *= (float)invSum;
-      m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight
-        / sqrt(m_modes[posPixel + iLocal].variance);
+        // Sort significance values so they are in desending order.
+        qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareGMM);
 
-    }
-  }
+        // make new mode if needed and exit
+        if (!bFitsPDF)
+        {
+          if (numModes < m_params.MaxModes())
+          {
+            numModes++;
+          }
+          else
+          {
+            // the weakest mode will be replaced
+          }
+
+          pos = posPixel + numModes - 1;
+
+          m_modes[pos].muR = pixel.ch[0];
+          m_modes[pos].muG = pixel.ch[1];
+          m_modes[pos].muB = pixel.ch[2];
+          m_modes[pos].variance = m_variance;
+          m_modes[pos].significants = 0;			// will be set below
+
+          if (numModes == 1)
+            m_modes[pos].weight = 1;
+          else
+            m_modes[pos].weight = m_params.Alpha();
+
+          //renormalize weights
+          int iLocal;
+          float sum = 0.0;
+          for (iLocal = 0; iLocal < numModes; iLocal++)
+          {
+            sum += m_modes[posPixel + iLocal].weight;
+          }
+
+          double invSum = 1.0 / sum;
+          for (iLocal = 0; iLocal < numModes; iLocal++)
+          {
+            m_modes[posPixel + iLocal].weight *= (float)invSum;
+            m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight
+              / sqrt(m_modes[posPixel + iLocal].variance);
+
+          }
+        }
 
-  // Sort significance values so they are in desending order.
-  qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareGMM);
+        // Sort significance values so they are in desending order.
+        qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareGMM);
 
-  if (bBackgroundLow)
-  {
-    low_threshold = BACKGROUND;
-  }
-  else
-  {
-    low_threshold = FOREGROUND;
-  }
+        if (bBackgroundLow)
+        {
+          low_threshold = BACKGROUND;
+        }
+        else
+        {
+          low_threshold = FOREGROUND;
+        }
 
-  if (bBackgroundHigh)
-  {
-    high_threshold = BACKGROUND;
-  }
-  else
-  {
-    high_threshold = FOREGROUND;
-  }
-}
+        if (bBackgroundHigh)
+        {
+          high_threshold = BACKGROUND;
+        }
+        else
+        {
+          high_threshold = FOREGROUND;
+        }
+      }
 
-///////////////////////////////////////////////////////////////////////////////
-//Input:
-//  data - a pointer to the data of a RGB image of the same size
-//Output:
-//  output - a pointer to the data of a gray value image of the same size 
-//					(the memory should already be reserved) 
-//					values: 255-foreground, 125-shadow, 0-background
-///////////////////////////////////////////////////////////////////////////////
-void GrimsonGMM::Subtract(int frame_num, const RgbImage& data,
-  BwImage& low_threshold_mask, BwImage& high_threshold_mask)
-{
-  unsigned char low_threshold, high_threshold;
-  long posPixel;
+      ///////////////////////////////////////////////////////////////////////////////
+      //Input:
+      //  data - a pointer to the data of a RGB image of the same size
+      //Output:
+      //  output - a pointer to the data of a gray value image of the same size 
+      //					(the memory should already be reserved) 
+      //					values: 255-foreground, 125-shadow, 0-background
+      ///////////////////////////////////////////////////////////////////////////////
+      void GrimsonGMM::Subtract(int frame_num, const RgbImage& data,
+        BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+      {
+        unsigned char low_threshold, high_threshold;
+        long posPixel;
 
-  // update each pixel of the image
-  for (unsigned int r = 0; r < m_params.Height(); ++r)
-  {
-    for (unsigned int c = 0; c < m_params.Width(); ++c)
-    {
-      // update model + background subtract
-      posPixel = (r*m_params.Width() + c)*m_params.MaxModes();
+        // update each pixel of the image
+        for (unsigned int r = 0; r < m_params.Height(); ++r)
+        {
+          for (unsigned int c = 0; c < m_params.Width(); ++c)
+          {
+            // update model + background subtract
+            posPixel = (r*m_params.Width() + c)*m_params.MaxModes();
 
-      SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold);
+            SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold);
 
-      low_threshold_mask(r, c) = low_threshold;
-      high_threshold_mask(r, c) = high_threshold;
+            low_threshold_mask(r, c) = low_threshold;
+            high_threshold_mask(r, c) = high_threshold;
 
-      m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR;
-      m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG;
-      m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB;
+            m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR;
+            m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG;
+            m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB;
+          }
+        }
+      }
     }
   }
 }
diff --git a/src/algorithms/dp/GrimsonGMM.h b/src/algorithms/dp/GrimsonGMM.h
index d07e4da489bf3f25d22da9910de221adffb2aee8..a89a0eacfef97edfdac3f62a26a9510fe4868aea 100644
--- a/src/algorithms/dp/GrimsonGMM.h
+++ b/src/algorithms/dp/GrimsonGMM.h
@@ -4,10 +4,12 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
+    namespace dp
+    {
     typedef struct GMMGaussian
     {
       float variance;
@@ -91,6 +93,7 @@ namespace Algorithms
       // Current background model
       RgbImage m_background;
     };
+    }
   }
 }
 
diff --git a/src/algorithms/dp/Image.cpp b/src/algorithms/dp/Image.cpp
index d54587eb997b7a36ead1110ade9eae9be7dc76ec..8089ef42cb73062e8fee5f20e9bae778199e22d3 100644
--- a/src/algorithms/dp/Image.cpp
+++ b/src/algorithms/dp/Image.cpp
@@ -2,47 +2,58 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-ImageBase::~ImageBase()
-{
-  if (imgp != NULL && m_bReleaseMemory)
-    cvReleaseImage(&imgp);
-  imgp = NULL;
-}
+//using namespace bgslibrary::algorithms::dp;
 
-void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue)
+namespace bgslibrary
 {
-  for (int r = 1; r < image.Ptr()->height - 1; ++r)
+  namespace algorithms
   {
-    for (int c = 1; c < image.Ptr()->width - 1; ++c)
+    namespace dp
     {
-      int count = 0;
-      if (image(r, c) == fgValue)
+      ImageBase::~ImageBase()
       {
-        if (image(r - 1, c - 1) == fgValue)
-          count++;
-        if (image(r - 1, c) == fgValue)
-          count++;
-        if (image(r - 1, c + 1) == fgValue)
-          count++;
-        if (image(r, c - 1) == fgValue)
-          count++;
-        if (image(r, c + 1) == fgValue)
-          count++;
-        if (image(r + 1, c - 1) == fgValue)
-          count++;
-        if (image(r + 1, c) == fgValue)
-          count++;
-        if (image(r + 1, c + 1) == fgValue)
-          count++;
-
-        if (count < minDensity)
-          filtered(r, c) = 0;
-        else
-          filtered(r, c) = fgValue;
+        if (imgp != NULL && m_bReleaseMemory)
+          cvReleaseImage(&imgp);
+        imgp = NULL;
       }
-      else
+
+      void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue)
       {
-        filtered(r, c) = 0;
+        for (int r = 1; r < image.Ptr()->height - 1; ++r)
+        {
+          for (int c = 1; c < image.Ptr()->width - 1; ++c)
+          {
+            int count = 0;
+            if (image(r, c) == fgValue)
+            {
+              if (image(r - 1, c - 1) == fgValue)
+                count++;
+              if (image(r - 1, c) == fgValue)
+                count++;
+              if (image(r - 1, c + 1) == fgValue)
+                count++;
+              if (image(r, c - 1) == fgValue)
+                count++;
+              if (image(r, c + 1) == fgValue)
+                count++;
+              if (image(r + 1, c - 1) == fgValue)
+                count++;
+              if (image(r + 1, c) == fgValue)
+                count++;
+              if (image(r + 1, c + 1) == fgValue)
+                count++;
+
+              if (count < minDensity)
+                filtered(r, c) = 0;
+              else
+                filtered(r, c) = fgValue;
+            }
+            else
+            {
+              filtered(r, c) = 0;
+            }
+          }
+        }
       }
     }
   }
diff --git a/src/algorithms/dp/Image.h b/src/algorithms/dp/Image.h
index de20d421a32184c4722fdb92ff9c20b06d0ab14a..f923cbd4ca46b11bd56594d6b4ebab5efa6cdd10 100644
--- a/src/algorithms/dp/Image.h
+++ b/src/algorithms/dp/Image.h
@@ -4,329 +4,338 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-template <class T>
-class ImageIterator
+namespace bgslibrary
 {
-public:
-  ImageIterator(IplImage* image, int x = 0, int y = 0, int dx = 0, int dy = 0) :
-    i(x), j(y), i0(0)
+  namespace algorithms
   {
-    data = reinterpret_cast<T*>(image->imageData);
-    step = image->widthStep / sizeof(T);
-
-    nl = image->height;
-    if ((y + dy) > 0 && (y + dy) < nl)
-      nl = y + dy;
-
-    if (y < 0)
-      j = 0;
-
-    data += step*j;
-
-    nc = image->width;
-    if ((x + dx) > 0 && (x + dx) < nc)
-      nc = x + dx;
-
-    nc *= image->nChannels;
-    if (x > 0)
-      i0 = x*image->nChannels;
-    i = i0;
-
-    nch = image->nChannels;
-  }
-
-  /* has next ? */
-  bool operator!() const { return j < nl; }
-
-  /* next pixel */
-  ImageIterator& operator++()
-  {
-    i++;
-    if (i >= nc)
+    namespace dp
     {
-      i = i0;
-      j++;
-      data += step;
+      template <class T>
+      class ImageIterator
+      {
+      public:
+        ImageIterator(IplImage* image, int x = 0, int y = 0, int dx = 0, int dy = 0) :
+          i(x), j(y), i0(0)
+        {
+          data = reinterpret_cast<T*>(image->imageData);
+          step = image->widthStep / sizeof(T);
+
+          nl = image->height;
+          if ((y + dy) > 0 && (y + dy) < nl)
+            nl = y + dy;
+
+          if (y < 0)
+            j = 0;
+
+          data += step*j;
+
+          nc = image->width;
+          if ((x + dx) > 0 && (x + dx) < nc)
+            nc = x + dx;
+
+          nc *= image->nChannels;
+          if (x > 0)
+            i0 = x*image->nChannels;
+          i = i0;
+
+          nch = image->nChannels;
+        }
+
+        /* has next ? */
+        bool operator!() const { return j < nl; }
+
+        /* next pixel */
+        ImageIterator& operator++()
+        {
+          i++;
+          if (i >= nc)
+          {
+            i = i0;
+            j++;
+            data += step;
+          }
+          return *this;
+        }
+
+        ImageIterator& operator+=(int s)
+        {
+          i += s;
+          if (i >= nc)
+          {
+            i = i0;
+            j++;
+            data += step;
+          }
+          return *this;
+        }
+
+        /* pixel access */
+        T& operator*() { return data[i]; }
+
+        const T operator*() const { return data[i]; }
+
+        const T neighbor(int dx, int dy) const
+        {
+          return *(data + dy*step + i + dx);
+        }
+
+        T* operator&() const { return data + i; }
+
+        /* current pixel coordinates */
+        int column() const { return i / nch; }
+        int line() const { return j; }
+
+      private:
+        int i, i0, j;
+        T* data;
+        int step;
+        int nl, nc;
+        int nch;
+      };
+
+      // --- Constants --------------------------------------------------------------
+
+      const unsigned char NUM_CHANNELS = 3;
+
+      // --- Pixel Types ------------------------------------------------------------
+
+      class RgbPixel
+      {
+      public:
+        RgbPixel() { ; }
+        RgbPixel(unsigned char _r, unsigned char _g, unsigned char _b)
+        {
+          ch[0] = _r; ch[1] = _g; ch[2] = _b;
+        }
+
+        RgbPixel& operator=(const RgbPixel& rhs)
+        {
+          ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2];
+          return *this;
+        }
+
+        inline unsigned char& operator()(const int _ch)
+        {
+          return ch[_ch];
+        }
+
+        inline unsigned char operator()(const int _ch) const
+        {
+          return ch[_ch];
+        }
+
+        unsigned char ch[3];
+      };
+
+      class RgbPixelFloat
+      {
+      public:
+        RgbPixelFloat() { ; }
+        RgbPixelFloat(float _r, float _g, float _b)
+        {
+          ch[0] = _r; ch[1] = _g; ch[2] = _b;
+        }
+
+        RgbPixelFloat& operator=(const RgbPixelFloat& rhs)
+        {
+          ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2];
+          return *this;
+        }
+
+        inline float& operator()(const int _ch)
+        {
+          return ch[_ch];
+        }
+
+        inline float operator()(const int _ch) const
+        {
+          return ch[_ch];
+        }
+
+        float ch[3];
+      };
+
+      // --- Image Types ------------------------------------------------------------
+
+      class ImageBase
+      {
+      public:
+        ImageBase(IplImage* img = NULL) { imgp = img; m_bReleaseMemory = true; }
+        ~ImageBase();
+
+        void ReleaseMemory(bool b) { m_bReleaseMemory = b; }
+
+        IplImage* Ptr() { return imgp; }
+        const IplImage* Ptr() const { return imgp; }
+
+        void ReleaseImage()
+        {
+          cvReleaseImage(&imgp);
+        }
+
+        void operator=(IplImage* img)
+        {
+          imgp = img;
+        }
+
+        // copy-constructor
+        ImageBase(const ImageBase& rhs)
+        {
+          // it is very inefficent if this copy-constructor is called
+          assert(false);
+        }
+
+        // assignment operator
+        ImageBase& operator=(const ImageBase& rhs)
+        {
+          // it is very inefficent if operator= is called
+          assert(false);
+
+          return *this;
+        }
+
+        virtual void Clear() = 0;
+
+      protected:
+        IplImage* imgp;
+        bool m_bReleaseMemory;
+      };
+
+      class RgbImage : public ImageBase
+      {
+      public:
+        RgbImage(IplImage* img = NULL) : ImageBase(img) { ; }
+
+        virtual void Clear()
+        {
+          cvZero(imgp);
+        }
+
+        void operator=(IplImage* img)
+        {
+          imgp = img;
+        }
+
+        // channel-level access using image(row, col, channel)
+        inline unsigned char& operator()(const int r, const int c, const int ch)
+        {
+          return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch];
+        }
+
+        inline const unsigned char& operator()(const int r, const int c, const int ch) const
+        {
+          return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch];
+        }
+
+        // RGB pixel-level access using image(row, col)
+        inline RgbPixel& operator()(const int r, const int c)
+        {
+          return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels];
+        }
+
+        inline const RgbPixel& operator()(const int r, const int c) const
+        {
+          return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels];
+        }
+      };
+
+      class RgbImageFloat : public ImageBase
+      {
+      public:
+        RgbImageFloat(IplImage* img = NULL) : ImageBase(img) { ; }
+
+        virtual void Clear()
+        {
+          cvZero(imgp);
+        }
+
+        void operator=(IplImage* img)
+        {
+          imgp = img;
+        }
+
+        // channel-level access using image(row, col, channel)
+        inline float& operator()(const int r, const int c, const int ch)
+        {
+          return (float &)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)];
+        }
+
+        inline float operator()(const int r, const int c, const int ch) const
+        {
+          return (float)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)];
+        }
+
+        // RGB pixel-level access using image(row, col)
+        inline RgbPixelFloat& operator()(const int r, const int c)
+        {
+          return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)];
+        }
+
+        inline const RgbPixelFloat& operator()(const int r, const int c) const
+        {
+          return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)];
+        }
+      };
+
+      class BwImage : public ImageBase
+      {
+      public:
+        BwImage(IplImage* img = NULL) : ImageBase(img) { ; }
+
+        virtual void Clear()
+        {
+          cvZero(imgp);
+        }
+
+        void operator=(IplImage* img)
+        {
+          imgp = img;
+        }
+
+        // pixel-level access using image(row, col)
+        inline unsigned char& operator()(const int r, const int c)
+        {
+          return (unsigned char &)imgp->imageData[r*imgp->widthStep + c];
+        }
+
+        inline unsigned char operator()(const int r, const int c) const
+        {
+          return (unsigned char)imgp->imageData[r*imgp->widthStep + c];
+        }
+      };
+
+      class BwImageFloat : public ImageBase
+      {
+      public:
+        BwImageFloat(IplImage* img = NULL) : ImageBase(img) { ; }
+
+        virtual void Clear()
+        {
+          cvZero(imgp);
+        }
+
+        void operator=(IplImage* img)
+        {
+          imgp = img;
+        }
+
+        // pixel-level access using image(row, col)
+        inline float& operator()(const int r, const int c)
+        {
+          return (float &)imgp->imageData[r*imgp->widthStep + c * sizeof(float)];
+        }
+
+        inline float operator()(const int r, const int c) const
+        {
+          return (float)imgp->imageData[r*imgp->widthStep + c * sizeof(float)];
+        }
+      };
+
+      // --- Image Functions --------------------------------------------------------
+
+      //void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue);
     }
-    return *this;
-  }
-
-  ImageIterator& operator+=(int s)
-  {
-    i += s;
-    if (i >= nc)
-    {
-      i = i0;
-      j++;
-      data += step;
-    }
-    return *this;
-  }
-
-  /* pixel access */
-  T& operator*() { return data[i]; }
-
-  const T operator*() const { return data[i]; }
-
-  const T neighbor(int dx, int dy) const
-  {
-    return *(data + dy*step + i + dx);
-  }
-
-  T* operator&() const { return data + i; }
-
-  /* current pixel coordinates */
-  int column() const { return i / nch; }
-  int line() const { return j; }
-
-private:
-  int i, i0, j;
-  T* data;
-  int step;
-  int nl, nc;
-  int nch;
-};
-
-// --- Constants --------------------------------------------------------------
-
-const unsigned char NUM_CHANNELS = 3;
-
-// --- Pixel Types ------------------------------------------------------------
-
-class RgbPixel
-{
-public:
-  RgbPixel() { ; }
-  RgbPixel(unsigned char _r, unsigned char _g, unsigned char _b)
-  {
-    ch[0] = _r; ch[1] = _g; ch[2] = _b;
-  }
-
-  RgbPixel& operator=(const RgbPixel& rhs)
-  {
-    ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2];
-    return *this;
-  }
-
-  inline unsigned char& operator()(const int _ch)
-  {
-    return ch[_ch];
-  }
-
-  inline unsigned char operator()(const int _ch) const
-  {
-    return ch[_ch];
-  }
-
-  unsigned char ch[3];
-};
-
-class RgbPixelFloat
-{
-public:
-  RgbPixelFloat() { ; }
-  RgbPixelFloat(float _r, float _g, float _b)
-  {
-    ch[0] = _r; ch[1] = _g; ch[2] = _b;
-  }
-
-  RgbPixelFloat& operator=(const RgbPixelFloat& rhs)
-  {
-    ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2];
-    return *this;
-  }
-
-  inline float& operator()(const int _ch)
-  {
-    return ch[_ch];
-  }
-
-  inline float operator()(const int _ch) const
-  {
-    return ch[_ch];
-  }
-
-  float ch[3];
-};
-
-// --- Image Types ------------------------------------------------------------
-
-class ImageBase
-{
-public:
-  ImageBase(IplImage* img = NULL) { imgp = img; m_bReleaseMemory = true; }
-  ~ImageBase();
-
-  void ReleaseMemory(bool b) { m_bReleaseMemory = b; }
-
-  IplImage* Ptr() { return imgp; }
-  const IplImage* Ptr() const { return imgp; }
-
-  void ReleaseImage()
-  {
-    cvReleaseImage(&imgp);
-  }
-
-  void operator=(IplImage* img)
-  {
-    imgp = img;
-  }
-
-  // copy-constructor
-  ImageBase(const ImageBase& rhs)
-  {
-    // it is very inefficent if this copy-constructor is called
-    assert(false);
-  }
-
-  // assignment operator
-  ImageBase& operator=(const ImageBase& rhs)
-  {
-    // it is very inefficent if operator= is called
-    assert(false);
-
-    return *this;
   }
-
-  virtual void Clear() = 0;
-
-protected:
-  IplImage* imgp;
-  bool m_bReleaseMemory;
-};
-
-class RgbImage : public ImageBase
-{
-public:
-  RgbImage(IplImage* img = NULL) : ImageBase(img) { ; }
-
-  virtual void Clear()
-  {
-    cvZero(imgp);
-  }
-
-  void operator=(IplImage* img)
-  {
-    imgp = img;
-  }
-
-  // channel-level access using image(row, col, channel)
-  inline unsigned char& operator()(const int r, const int c, const int ch)
-  {
-    return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch];
-  }
-
-  inline const unsigned char& operator()(const int r, const int c, const int ch) const
-  {
-    return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch];
-  }
-
-  // RGB pixel-level access using image(row, col)
-  inline RgbPixel& operator()(const int r, const int c)
-  {
-    return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels];
-  }
-
-  inline const RgbPixel& operator()(const int r, const int c) const
-  {
-    return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels];
-  }
-};
-
-class RgbImageFloat : public ImageBase
-{
-public:
-  RgbImageFloat(IplImage* img = NULL) : ImageBase(img) { ; }
-
-  virtual void Clear()
-  {
-    cvZero(imgp);
-  }
-
-  void operator=(IplImage* img)
-  {
-    imgp = img;
-  }
-
-  // channel-level access using image(row, col, channel)
-  inline float& operator()(const int r, const int c, const int ch)
-  {
-    return (float &)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)];
-  }
-
-  inline float operator()(const int r, const int c, const int ch) const
-  {
-    return (float)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)];
-  }
-
-  // RGB pixel-level access using image(row, col)
-  inline RgbPixelFloat& operator()(const int r, const int c)
-  {
-    return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)];
-  }
-
-  inline const RgbPixelFloat& operator()(const int r, const int c) const
-  {
-    return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)];
-  }
-};
-
-class BwImage : public ImageBase
-{
-public:
-  BwImage(IplImage* img = NULL) : ImageBase(img) { ; }
-
-  virtual void Clear()
-  {
-    cvZero(imgp);
-  }
-
-  void operator=(IplImage* img)
-  {
-    imgp = img;
-  }
-
-  // pixel-level access using image(row, col)
-  inline unsigned char& operator()(const int r, const int c)
-  {
-    return (unsigned char &)imgp->imageData[r*imgp->widthStep + c];
-  }
-
-  inline unsigned char operator()(const int r, const int c) const
-  {
-    return (unsigned char)imgp->imageData[r*imgp->widthStep + c];
-  }
-};
-
-class BwImageFloat : public ImageBase
-{
-public:
-  BwImageFloat(IplImage* img = NULL) : ImageBase(img) { ; }
-
-  virtual void Clear()
-  {
-    cvZero(imgp);
-  }
-
-  void operator=(IplImage* img)
-  {
-    imgp = img;
-  }
-
-  // pixel-level access using image(row, col)
-  inline float& operator()(const int r, const int c)
-  {
-    return (float &)imgp->imageData[r*imgp->widthStep + c * sizeof(float)];
-  }
-
-  inline float operator()(const int r, const int c) const
-  {
-    return (float)imgp->imageData[r*imgp->widthStep + c * sizeof(float)];
-  }
-};
-
-// --- Image Functions --------------------------------------------------------
-
-void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue);
+}
 
 #endif
diff --git a/src/algorithms/dp/MeanBGS.cpp b/src/algorithms/dp/MeanBGS.cpp
index 95aa72f1371b940c87d17f4ee9eb1f64aa10c32a..8b419b0d3de93496af764e55a6749c1e1c22f063 100644
--- a/src/algorithms/dp/MeanBGS.cpp
+++ b/src/algorithms/dp/MeanBGS.cpp
@@ -2,7 +2,7 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+using namespace bgslibrary::algorithms::dp;
 
 void MeanBGS::Initalize(const BgsParams& param)
 {
diff --git a/src/algorithms/dp/MeanBGS.h b/src/algorithms/dp/MeanBGS.h
index 7ed8baf86cbdc34c7c480b60c25c9e906e6302a8..11238353497f3e9a216b597cfc2ce49e3a967b58 100644
--- a/src/algorithms/dp/MeanBGS.h
+++ b/src/algorithms/dp/MeanBGS.h
@@ -4,10 +4,12 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
+    namespace dp
+    {
     // --- Parameters used by the Mean BGS algorithm ---
     class MeanParams : public BgsParams
     {
@@ -53,6 +55,7 @@ namespace Algorithms
       RgbImageFloat m_mean;
       RgbImage m_background;
     };
+    }
   }
 }
 
diff --git a/src/algorithms/dp/PratiMediodBGS.cpp b/src/algorithms/dp/PratiMediodBGS.cpp
index 984240c01074d9704e0039dc1f27b2cb8ecba38c..8c9ee81e522da8073c3de684434739bd33dc0edf 100644
--- a/src/algorithms/dp/PratiMediodBGS.cpp
+++ b/src/algorithms/dp/PratiMediodBGS.cpp
@@ -2,7 +2,7 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+using namespace bgslibrary::algorithms::dp;
 
 PratiMediodBGS::PratiMediodBGS()
 {
diff --git a/src/algorithms/dp/PratiMediodBGS.h b/src/algorithms/dp/PratiMediodBGS.h
index 8a38515e23a321b732b9b8a3bdde55421d88ce8f..203746f5075ba82b832e6ce4a64876a73649637e 100644
--- a/src/algorithms/dp/PratiMediodBGS.h
+++ b/src/algorithms/dp/PratiMediodBGS.h
@@ -5,10 +5,12 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
+    namespace dp
+    {
     // --- Parameters used by the Prati Mediod BGS algorithm ---
     class PratiParams : public BgsParams
     {
@@ -82,6 +84,7 @@ namespace Algorithms
       BwImage m_mask_low_threshold;
       BwImage m_mask_high_threshold;
     };
+    }
   }
 }
 
diff --git a/src/algorithms/dp/TextureBGS.cpp b/src/algorithms/dp/TextureBGS.cpp
index faa466af51af476162eed650e0da7012b98ea15a..b0adc222207e7c397b9882c1ca1f8bd9db13fdd6 100644
--- a/src/algorithms/dp/TextureBGS.cpp
+++ b/src/algorithms/dp/TextureBGS.cpp
@@ -2,6 +2,8 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
+using namespace bgslibrary::algorithms::dp;
+
 TextureBGS::TextureBGS() {}
 TextureBGS::~TextureBGS() {}
 
diff --git a/src/algorithms/dp/TextureBGS.h b/src/algorithms/dp/TextureBGS.h
index 93328b5907edff28d8efd78b1f2270f651a6c0ca..da850fdad30083496f2ccfd7c0c9a316221a7c9f 100644
--- a/src/algorithms/dp/TextureBGS.h
+++ b/src/algorithms/dp/TextureBGS.h
@@ -5,41 +5,50 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-const int REGION_R = 5;			// Note: the code currently assumes this value is <= 7
-const int TEXTURE_POINTS = 6;	// Note: the code currently assumes this value is 6
-const int TEXTURE_R = 2;		// Note: the code currently assumes this value is 2
-const int NUM_BINS = 64;		// 2^TEXTURE_POINTS
-const int HYSTERSIS = 3;
-const double ALPHA = 0.05f;
-const double THRESHOLD = 0.5*(REGION_R + REGION_R + 1)*(REGION_R + REGION_R + 1)*NUM_CHANNELS;
-const int NUM_MODES = 1;		// The paper describes how multiple modes can be maintained,
-// but this implementation does not fully support more than one
-
-struct TextureHistogram
+namespace bgslibrary
 {
-  unsigned char r[NUM_BINS];	// histogram for red channel
-  unsigned char g[NUM_BINS];	// histogram for green channel
-  unsigned char b[NUM_BINS];	// histogram for blue channel
-};
-
-struct TextureArray
-{
-  TextureHistogram mode[NUM_MODES];
-};
-
-class TextureBGS
-{
-public:
-  TextureBGS();
-  ~TextureBGS();
-
-  void LBP(RgbImage& image, RgbImage& texture);
-  void Histogram(RgbImage& texture, TextureHistogram* curTextureHist);
-  int ProximityMeasure(TextureHistogram& bgTexture, TextureHistogram& curTextureHist);
-  void BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist,
-    unsigned char* modeArray, float threshold, BwImage& fgMask);
-  void UpdateModel(BwImage& fgMask, TextureArray* bgModel,
-    TextureHistogram* curTextureHist, unsigned char* modeArray);
-};
+  namespace algorithms
+  {
+    namespace dp
+    {
+      const int REGION_R = 5;			// Note: the code currently assumes this value is <= 7
+      const int TEXTURE_POINTS = 6;	// Note: the code currently assumes this value is 6
+      const int TEXTURE_R = 2;		// Note: the code currently assumes this value is 2
+      const int NUM_BINS = 64;		// 2^TEXTURE_POINTS
+      const int HYSTERSIS = 3;
+      const double ALPHA = 0.05f;
+      const double THRESHOLD = 0.5*(REGION_R + REGION_R + 1)*(REGION_R + REGION_R + 1)*NUM_CHANNELS;
+      const int NUM_MODES = 1;		// The paper describes how multiple modes can be maintained,
+      // but this implementation does not fully support more than one
+
+      struct TextureHistogram
+      {
+        unsigned char r[NUM_BINS];	// histogram for red channel
+        unsigned char g[NUM_BINS];	// histogram for green channel
+        unsigned char b[NUM_BINS];	// histogram for blue channel
+      };
+
+      struct TextureArray
+      {
+        TextureHistogram mode[NUM_MODES];
+      };
+
+      class TextureBGS
+      {
+      public:
+        TextureBGS();
+        ~TextureBGS();
+
+        void LBP(RgbImage& image, RgbImage& texture);
+        void Histogram(RgbImage& texture, TextureHistogram* curTextureHist);
+        int ProximityMeasure(TextureHistogram& bgTexture, TextureHistogram& curTextureHist);
+        void BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist,
+          unsigned char* modeArray, float threshold, BwImage& fgMask);
+        void UpdateModel(BwImage& fgMask, TextureArray* bgModel,
+          TextureHistogram* curTextureHist, unsigned char* modeArray);
+      };
+    }
+  }
+}
 
 #endif
diff --git a/src/algorithms/dp/WrenGA.cpp b/src/algorithms/dp/WrenGA.cpp
index 17a67b7736e9231d54ecadf59dba684ce00cec0c..d29b2061d8ddab3c0c95e75d4f4261b7af7af46c 100644
--- a/src/algorithms/dp/WrenGA.cpp
+++ b/src/algorithms/dp/WrenGA.cpp
@@ -2,7 +2,7 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+using namespace bgslibrary::algorithms::dp;
 
 WrenGA::WrenGA()
 {
diff --git a/src/algorithms/dp/WrenGA.h b/src/algorithms/dp/WrenGA.h
index dc3d70fa47852aa2a4597dd13308fe9833ded038..ede4cf5cbce4fd9de1c01345781f48ef1565d469 100644
--- a/src/algorithms/dp/WrenGA.h
+++ b/src/algorithms/dp/WrenGA.h
@@ -4,10 +4,12 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
+    namespace dp
+    {
     // --- Parameters used by the Mean BGS algorithm ---
     class WrenParams : public BgsParams
     {
@@ -65,6 +67,7 @@ namespace Algorithms
 
       RgbImage m_background;
     };
+    }
   }
 }
 
diff --git a/src/algorithms/dp/ZivkovicAGMM.cpp b/src/algorithms/dp/ZivkovicAGMM.cpp
index bcbc8272b2ce31082291daf7d0174d99260875dd..382fbb330c84fe7495a0afdf05cc79c880071eae 100644
--- a/src/algorithms/dp/ZivkovicAGMM.cpp
+++ b/src/algorithms/dp/ZivkovicAGMM.cpp
@@ -2,7 +2,7 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-using namespace Algorithms::BackgroundSubtraction;
+using namespace bgslibrary::algorithms::dp;
 
 ZivkovicAGMM::ZivkovicAGMM()
 {
diff --git a/src/algorithms/dp/ZivkovicAGMM.h b/src/algorithms/dp/ZivkovicAGMM.h
index 9566d019b288196d587dad71df71f0f1c5a6c99d..b06293531ad1b0df43390227eb7764c9e51419f0 100644
--- a/src/algorithms/dp/ZivkovicAGMM.h
+++ b/src/algorithms/dp/ZivkovicAGMM.h
@@ -4,10 +4,12 @@
 
 #if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3
 
-namespace Algorithms
+namespace bgslibrary
 {
-  namespace BackgroundSubtraction
+  namespace algorithms
   {
+    namespace dp
+    {
     // --- User adjustable parameters used by the Grimson GMM BGS algorithm ---
     class ZivkovicParams : public BgsParams
     {
@@ -96,6 +98,7 @@ namespace Algorithms
       //number of Gaussian components per pixel
       unsigned char* m_modes_per_pixel;
     };
+    }
   }
 }
 
diff --git a/src/algorithms/lb/BGModel.cpp b/src/algorithms/lb/BGModel.cpp
index 26d97125bbc98e281a4ac73294d682dae11e3807..b4f71a8f4e22218f54e5e6fb575388d5222eef2f 100644
--- a/src/algorithms/lb/BGModel.cpp
+++ b/src/algorithms/lb/BGModel.cpp
@@ -1,51 +1,50 @@
 #include "BGModel.h"
 
-namespace lb_library
+using namespace bgslibrary::algorithms::lb;
+
+BGModel::BGModel(int width, int height) : m_width(width), m_height(height)
+{
+  m_SrcImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3);
+  m_BGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3);
+  m_FGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3);
+
+  cvZero(m_SrcImage);
+  cvZero(m_BGImage);
+  cvZero(m_FGImage);
+}
+
+BGModel::~BGModel()
+{
+  if (m_SrcImage != NULL) cvReleaseImage(&m_SrcImage);
+  if (m_BGImage != NULL) cvReleaseImage(&m_BGImage);
+  if (m_FGImage != NULL) cvReleaseImage(&m_FGImage);
+}
+
+IplImage* BGModel::GetSrc()
+{
+  return m_SrcImage;
+}
+
+IplImage* BGModel::GetFG()
+{
+  return m_FGImage;
+}
+
+IplImage* BGModel::GetBG()
+{
+  return m_BGImage;
+}
+
+void BGModel::InitModel(IplImage* image)
+{
+  cvCopy(image, m_SrcImage);
+  Init();
+  return;
+}
+
+void BGModel::UpdateModel(IplImage* image)
 {
-  BGModel::BGModel(int width, int height) : m_width(width), m_height(height)
-  {
-    m_SrcImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3);
-    m_BGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3);
-    m_FGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3);
-
-    cvZero(m_SrcImage);
-    cvZero(m_BGImage);
-    cvZero(m_FGImage);
-  }
-
-  BGModel::~BGModel()
-  {
-    if (m_SrcImage != NULL) cvReleaseImage(&m_SrcImage);
-    if (m_BGImage != NULL) cvReleaseImage(&m_BGImage);
-    if (m_FGImage != NULL) cvReleaseImage(&m_FGImage);
-  }
-
-  IplImage* BGModel::GetSrc()
-  {
-    return m_SrcImage;
-  }
-
-  IplImage* BGModel::GetFG()
-  {
-    return m_FGImage;
-  }
-
-  IplImage* BGModel::GetBG()
-  {
-    return m_BGImage;
-  }
-
-  void BGModel::InitModel(IplImage* image)
-  {
-    cvCopy(image, m_SrcImage);
-    Init();
-    return;
-  }
-
-  void BGModel::UpdateModel(IplImage* image)
-  {
-    cvCopy(image, m_SrcImage);
-    Update();
-    return;
-  }
+  cvCopy(image, m_SrcImage);
+  Update();
+  return;
 }
diff --git a/src/algorithms/lb/BGModel.h b/src/algorithms/lb/BGModel.h
index abe43afb7fddfb90b28d87d7c27ec6c25f02844e..fb0bb4c09b1838564300c6cbf9c29ddfc2046b95 100644
--- a/src/algorithms/lb/BGModel.h
+++ b/src/algorithms/lb/BGModel.h
@@ -7,34 +7,40 @@
 
 #include "Types.h"
 
-namespace lb_library
+namespace bgslibrary
 {
-  class BGModel
+  namespace algorithms
   {
-  public:
+    namespace lb
+    {
+      class BGModel
+      {
+      public:
 
-    BGModel(int width, int height);
-    virtual ~BGModel();
+        BGModel(int width, int height);
+        virtual ~BGModel();
 
-    void InitModel(IplImage* image);
-    void UpdateModel(IplImage* image);
+        void InitModel(IplImage* image);
+        void UpdateModel(IplImage* image);
 
-    virtual void setBGModelParameter(int id, int value) {};
+        virtual void setBGModelParameter(int id, int value) {};
 
-    virtual IplImage* GetSrc();
-    virtual IplImage* GetFG();
-    virtual IplImage* GetBG();
+        virtual IplImage* GetSrc();
+        virtual IplImage* GetFG();
+        virtual IplImage* GetBG();
 
-  protected:
+      protected:
 
-    IplImage* m_SrcImage;
-    IplImage* m_BGImage;
-    IplImage* m_FGImage;
+        IplImage* m_SrcImage;
+        IplImage* m_BGImage;
+        IplImage* m_FGImage;
 
-    const unsigned int m_width;
-    const unsigned int m_height;
+        const unsigned int m_width;
+        const unsigned int m_height;
 
-    virtual void Init() = 0;
-    virtual void Update() = 0;
-  };
+        virtual void Init() = 0;
+        virtual void Update() = 0;
+      };
+    }
+  }
 }
diff --git a/src/algorithms/lb/BGModelFuzzyGauss.cpp b/src/algorithms/lb/BGModelFuzzyGauss.cpp
index 46c793fa5bac27e211352d771f7ca5d996b15a27..3ead2406ff00a3afe14a85fddde795a1ebc0114b 100644
--- a/src/algorithms/lb/BGModelFuzzyGauss.cpp
+++ b/src/algorithms/lb/BGModelFuzzyGauss.cpp
@@ -1,174 +1,171 @@
 #include "BGModelFuzzyGauss.h"
 
-namespace lb_library
+using namespace bgslibrary::algorithms::lb;
+using namespace bgslibrary::algorithms::lb::BGModelFuzzyGaussParams;
+
+BGModelFuzzyGauss::BGModelFuzzyGauss(int width, int height) : BGModel(width, height)
 {
-  namespace FuzzyGaussian
+  m_alphamax = ALPHAFUZZYGAUSS;
+  m_threshold = THRESHOLDFUZZYGAUSS * THRESHOLDFUZZYGAUSS;
+  m_threshBG = THRESHOLDBG;
+  m_noise = NOISEFUZZYGAUSS;
+
+  m_pMu = new DBLRGB[m_width * m_height];
+  m_pVar = new DBLRGB[m_width * m_height];
+
+  DBLRGB *pMu = m_pMu;
+  DBLRGB *pVar = m_pVar;
+
+  for (unsigned int k = 0; k < (m_width * m_height); k++)
   {
-    BGModelFuzzyGauss::BGModelFuzzyGauss(int width, int height) : BGModel(width, height)
-    {
-      m_alphamax = ALPHAFUZZYGAUSS;
-      m_threshold = THRESHOLDFUZZYGAUSS * THRESHOLDFUZZYGAUSS;
-      m_threshBG = THRESHOLDBG;
-      m_noise = NOISEFUZZYGAUSS;
-
-      m_pMu = new DBLRGB[m_width * m_height];
-      m_pVar = new DBLRGB[m_width * m_height];
-
-      DBLRGB *pMu = m_pMu;
-      DBLRGB *pVar = m_pVar;
-
-      for (unsigned int k = 0; k < (m_width * m_height); k++)
-      {
-        pMu->Red = 0.0;
-        pMu->Green = 0.0;
-        pMu->Blue = 0.0;
-
-        pVar->Red = m_noise;
-        pVar->Green = m_noise;
-        pVar->Blue = m_noise;
-
-        pMu++;
-        pVar++;
-      }
-    }
+    pMu->Red = 0.0;
+    pMu->Green = 0.0;
+    pMu->Blue = 0.0;
 
-    BGModelFuzzyGauss::~BGModelFuzzyGauss()
-    {
-      delete[] m_pMu;
-      delete[] m_pVar;
-    }
+    pVar->Red = m_noise;
+    pVar->Green = m_noise;
+    pVar->Blue = m_noise;
 
-    void BGModelFuzzyGauss::setBGModelParameter(int id, int value)
-    {
-      double dvalue = (double)value / 255.0;
+    pMu++;
+    pVar++;
+  }
+}
 
-      switch (id)
-      {
-      case 0:
-        m_threshold = 100.0*dvalue*dvalue;
-        break;
+BGModelFuzzyGauss::~BGModelFuzzyGauss()
+{
+  delete[] m_pMu;
+  delete[] m_pVar;
+}
+
+void BGModelFuzzyGauss::setBGModelParameter(int id, int value)
+{
+  double dvalue = (double)value / 255.0;
 
-      case 1:
-        m_threshBG = dvalue;
-        break;
+  switch (id)
+  {
+  case 0:
+    m_threshold = 100.0*dvalue*dvalue;
+    break;
 
-      case 2:
-        m_alphamax = dvalue*dvalue*dvalue;
-        break;
+  case 1:
+    m_threshBG = dvalue;
+    break;
 
-      case 3:
-        m_noise = 100.0*dvalue;
-        break;
-      }
+  case 2:
+    m_alphamax = dvalue*dvalue*dvalue;
+    break;
 
-      return;
-    }
+  case 3:
+    m_noise = 100.0*dvalue;
+    break;
+  }
 
-    void BGModelFuzzyGauss::Init()
-    {
-      DBLRGB *pMu = m_pMu;
-      DBLRGB *pVar = m_pVar;
+  return;
+}
 
-      Image<BYTERGB> prgbSrc(m_SrcImage);
+void BGModelFuzzyGauss::Init()
+{
+  DBLRGB *pMu = m_pMu;
+  DBLRGB *pVar = m_pVar;
 
-      for (unsigned int i = 0; i < m_height; i++)
-      {
-        for (unsigned int j = 0; j < m_width; j++)
-        {
-          pMu->Red = prgbSrc[i][j].Red;
-          pMu->Green = prgbSrc[i][j].Green;
-          pMu->Blue = prgbSrc[i][j].Blue;
+  Image<BYTERGB> prgbSrc(m_SrcImage);
 
-          pVar->Red = m_noise;
-          pVar->Green = m_noise;
-          pVar->Blue = m_noise;
+  for (unsigned int i = 0; i < m_height; i++)
+  {
+    for (unsigned int j = 0; j < m_width; j++)
+    {
+      pMu->Red = prgbSrc[i][j].Red;
+      pMu->Green = prgbSrc[i][j].Green;
+      pMu->Blue = prgbSrc[i][j].Blue;
 
-          pMu++;
-          pVar++;
-        }
-      }
+      pVar->Red = m_noise;
+      pVar->Green = m_noise;
+      pVar->Blue = m_noise;
 
-      return;
+      pMu++;
+      pVar++;
     }
+  }
 
-    void BGModelFuzzyGauss::Update()
-    {
-      DBLRGB *pMu = m_pMu;
-      DBLRGB *pVar = m_pVar;
+  return;
+}
 
-      Image<BYTERGB> prgbSrc(m_SrcImage);
-      Image<BYTERGB> prgbBG(m_BGImage);
-      Image<BYTERGB> prgbFG(m_FGImage);
+void BGModelFuzzyGauss::Update()
+{
+  DBLRGB *pMu = m_pMu;
+  DBLRGB *pVar = m_pVar;
 
-      for (unsigned int i = 0; i < m_height; i++)
-      {
-        for (unsigned int j = 0; j < m_width; j++)
-        {
-          double srcR = (double)prgbSrc[i][j].Red;
-          double srcG = (double)prgbSrc[i][j].Green;
-          double srcB = (double)prgbSrc[i][j].Blue;
+  Image<BYTERGB> prgbSrc(m_SrcImage);
+  Image<BYTERGB> prgbBG(m_BGImage);
+  Image<BYTERGB> prgbFG(m_FGImage);
 
-          // Fuzzy background subtraction (Mahalanobis distance)
+  for (unsigned int i = 0; i < m_height; i++)
+  {
+    for (unsigned int j = 0; j < m_width; j++)
+    {
+      double srcR = (double)prgbSrc[i][j].Red;
+      double srcG = (double)prgbSrc[i][j].Green;
+      double srcB = (double)prgbSrc[i][j].Blue;
 
-          double dr = srcR - pMu->Red;
-          double dg = srcG - pMu->Green;
-          double db = srcB - pMu->Blue;
+      // Fuzzy background subtraction (Mahalanobis distance)
 
-          double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue;
+      double dr = srcR - pMu->Red;
+      double dg = srcG - pMu->Green;
+      double db = srcB - pMu->Blue;
 
-          double fuzzyBG = 1.0;
+      double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue;
 
-          if (d2 < m_threshold)
-            fuzzyBG = d2 / m_threshold;
+      double fuzzyBG = 1.0;
 
-          // Fuzzy running average
+      if (d2 < m_threshold)
+        fuzzyBG = d2 / m_threshold;
 
-          double alpha = m_alphamax*exp(FUZZYEXP*fuzzyBG);
+      // Fuzzy running average
 
-          if (dr*dr > DBL_MIN)
-            pMu->Red += alpha*dr;
+      double alpha = m_alphamax*exp(FUZZYEXP*fuzzyBG);
 
-          if (dg*dg > DBL_MIN)
-            pMu->Green += alpha*dg;
+      if (dr*dr > DBL_MIN)
+        pMu->Red += alpha*dr;
 
-          if (db*db > DBL_MIN)
-            pMu->Blue += alpha*db;
+      if (dg*dg > DBL_MIN)
+        pMu->Green += alpha*dg;
 
-          double d;
+      if (db*db > DBL_MIN)
+        pMu->Blue += alpha*db;
 
-          d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red;
-          if (d*d > DBL_MIN)
-            pVar->Red += alpha*d;
+      double d;
 
-          d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green;
-          if (d*d > DBL_MIN)
-            pVar->Green += alpha*d;
+      d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red;
+      if (d*d > DBL_MIN)
+        pVar->Red += alpha*d;
 
-          d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue;
-          if (d*d > DBL_MIN)
-            pVar->Blue += alpha*d;
+      d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green;
+      if (d*d > DBL_MIN)
+        pVar->Green += alpha*d;
 
-          pVar->Red = (std::max)(pVar->Red, m_noise);
-          pVar->Green = (std::max)(pVar->Green, m_noise);
-          pVar->Blue = (std::max)(pVar->Blue, m_noise);
+      d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue;
+      if (d*d > DBL_MIN)
+        pVar->Blue += alpha*d;
 
-          // Set foreground and background
+      pVar->Red = (std::max)(pVar->Red, m_noise);
+      pVar->Green = (std::max)(pVar->Green, m_noise);
+      pVar->Blue = (std::max)(pVar->Blue, m_noise);
 
-          if (fuzzyBG >= m_threshBG)
-            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255;
-          else
-            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0;
+      // Set foreground and background
 
-          prgbBG[i][j].Red = (unsigned char)pMu->Red;
-          prgbBG[i][j].Green = (unsigned char)pMu->Green;
-          prgbBG[i][j].Blue = (unsigned char)pMu->Blue;
+      if (fuzzyBG >= m_threshBG)
+        prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255;
+      else
+        prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0;
 
-          pMu++;
-          pVar++;
-        }
-      }
+      prgbBG[i][j].Red = (unsigned char)pMu->Red;
+      prgbBG[i][j].Green = (unsigned char)pMu->Green;
+      prgbBG[i][j].Blue = (unsigned char)pMu->Blue;
 
-      return;
+      pMu++;
+      pVar++;
     }
   }
+
+  return;
 }
diff --git a/src/algorithms/lb/BGModelFuzzyGauss.h b/src/algorithms/lb/BGModelFuzzyGauss.h
index 0d473b2e5b4dbc43322fc949b60669af3f1a2936..1d4070e4501e820852ec5dcf2777894b4808c1c4 100644
--- a/src/algorithms/lb/BGModelFuzzyGauss.h
+++ b/src/algorithms/lb/BGModelFuzzyGauss.h
@@ -2,35 +2,40 @@
 
 #include "BGModel.h"
 
-namespace lb_library
+namespace bgslibrary
 {
-  namespace FuzzyGaussian
+  namespace algorithms
   {
-    const float ALPHAFUZZYGAUSS = 0.02f;
-    const float THRESHOLDFUZZYGAUSS = 3.5f;
-    const float THRESHOLDBG = 0.5f;
-    const float NOISEFUZZYGAUSS = 50.0f;
-    const float FUZZYEXP = -5.0f;
-
-    class BGModelFuzzyGauss : public BGModel
+    namespace lb
     {
-    public:
-      BGModelFuzzyGauss(int width, int height);
-      ~BGModelFuzzyGauss();
+      namespace BGModelFuzzyGaussParams {
+        const float ALPHAFUZZYGAUSS = 0.02f;
+        const float THRESHOLDFUZZYGAUSS = 3.5f;
+        const float THRESHOLDBG = 0.5f;
+        const float NOISEFUZZYGAUSS = 50.0f;
+        const float FUZZYEXP = -5.0f;
+      }
+
+      class BGModelFuzzyGauss : public BGModel
+      {
+      public:
+        BGModelFuzzyGauss(int width, int height);
+        ~BGModelFuzzyGauss();
 
-      void setBGModelParameter(int id, int value);
+        void setBGModelParameter(int id, int value);
 
-    protected:
-      double m_alphamax;
-      double m_threshold;
-      double m_threshBG;
-      double m_noise;
+      protected:
+        double m_alphamax;
+        double m_threshold;
+        double m_threshBG;
+        double m_noise;
 
-      DBLRGB* m_pMu;
-      DBLRGB* m_pVar;
+        DBLRGB* m_pMu;
+        DBLRGB* m_pVar;
 
-      void Init();
-      void Update();
-    };
+        void Init();
+        void Update();
+      };
+    }
   }
 }
diff --git a/src/algorithms/lb/BGModelFuzzySom.cpp b/src/algorithms/lb/BGModelFuzzySom.cpp
index 2d85c50fcd12615c501debc0ce386bda6ca0ac74..74eef2cf875665391c7c40700954fe767c1797f2 100644
--- a/src/algorithms/lb/BGModelFuzzySom.cpp
+++ b/src/algorithms/lb/BGModelFuzzySom.cpp
@@ -1,262 +1,259 @@
 #include "BGModelFuzzySom.h"
 
-namespace lb_library
+using namespace bgslibrary::algorithms::lb;
+using namespace bgslibrary::algorithms::lb::BGModelFuzzySomParams;
+
+BGModelFuzzySom::BGModelFuzzySom(int width, int height) : BGModel(width, height)
 {
-  namespace FuzzyAdaptiveSOM
-  {
-    BGModelFuzzySom::BGModelFuzzySom(int width, int height) : BGModel(width, height)
-    {
-      m_offset = (KERNEL - 1) / 2;
+  m_offset = (KERNEL - 1) / 2;
 
-      if (SPAN_NEIGHBORS)
-        m_pad = 0;
-      else
-        m_pad = m_offset;
+  if (SPAN_NEIGHBORS)
+    m_pad = 0;
+  else
+    m_pad = m_offset;
 
-      // SOM models
+  // SOM models
 
-      m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad;
-      m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad;
+  m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad;
+  m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad;
 
-      m_ppSOM = new DBLRGB*[m_heightSOM];
-      for (int n = 0; n < m_heightSOM; n++)
-        m_ppSOM[n] = new DBLRGB[m_widthSOM];
+  m_ppSOM = new DBLRGB*[m_heightSOM];
+  for (int n = 0; n < m_heightSOM; n++)
+    m_ppSOM[n] = new DBLRGB[m_widthSOM];
 
-      for (int j = 0; j < m_heightSOM; j++)
-      {
-        for (int i = 0; i < m_widthSOM; i++)
-        {
-          m_ppSOM[j][i].Red = 0.0;
-          m_ppSOM[j][i].Green = 0.0;
-          m_ppSOM[j][i].Blue = 0.0;
-        }
-      }
+  for (int j = 0; j < m_heightSOM; j++)
+  {
+    for (int i = 0; i < m_widthSOM; i++)
+    {
+      m_ppSOM[j][i].Red = 0.0;
+      m_ppSOM[j][i].Green = 0.0;
+      m_ppSOM[j][i].Blue = 0.0;
+    }
+  }
 
-      // Create weights
+  // Create weights
 
-      m_ppW = new double*[KERNEL];
-      for (int n = 0; n < KERNEL; n++)
-        m_ppW[n] = new double[KERNEL];
+  m_ppW = new double*[KERNEL];
+  for (int n = 0; n < KERNEL; n++)
+    m_ppW[n] = new double[KERNEL];
 
-      // Construct Gaussian kernel using Pascal's triangle
+  // Construct Gaussian kernel using Pascal's triangle
 
-      int cM;
-      int cN;
-      m_Wmax = DBL_MIN;
+  int cM;
+  int cN;
+  m_Wmax = DBL_MIN;
 
-      cN = 1;
-      for (int j = 0; j < KERNEL; j++)
-      {
-        cM = 1;
+  cN = 1;
+  for (int j = 0; j < KERNEL; j++)
+  {
+    cM = 1;
 
-        for (int i = 0; i < KERNEL; i++)
-        {
-          m_ppW[j][i] = cN*cM;
+    for (int i = 0; i < KERNEL; i++)
+    {
+      m_ppW[j][i] = cN*cM;
 
-          if (m_ppW[j][i] > m_Wmax)
-            m_Wmax = m_ppW[j][i];
+      if (m_ppW[j][i] > m_Wmax)
+        m_Wmax = m_ppW[j][i];
 
-          cM = cM * (KERNEL - 1 - i) / (i + 1);
-        }
+      cM = cM * (KERNEL - 1 - i) / (i + 1);
+    }
 
-        cN = cN * (KERNEL - 1 - j) / (j + 1);
-      }
+    cN = cN * (KERNEL - 1 - j) / (j + 1);
+  }
 
-      // Parameters
+  // Parameters
 
-      m_epsilon1 = EPS1*EPS1;
-      m_epsilon2 = EPS2*EPS2;
+  m_epsilon1 = EPS1*EPS1;
+  m_epsilon2 = EPS2*EPS2;
 
-      m_alpha1 = C1 / m_Wmax;
-      m_alpha2 = C2 / m_Wmax;
+  m_alpha1 = C1 / m_Wmax;
+  m_alpha2 = C2 / m_Wmax;
 
-      m_K = 0;
-      m_TSteps = TRAINING_STEPS;
-    }
+  m_K = 0;
+  m_TSteps = TRAINING_STEPS;
+}
 
-    BGModelFuzzySom::~BGModelFuzzySom()
-    {
-      for (int n = 0; n < m_heightSOM; n++)
-        delete[] m_ppSOM[n];
+BGModelFuzzySom::~BGModelFuzzySom()
+{
+  for (int n = 0; n < m_heightSOM; n++)
+    delete[] m_ppSOM[n];
 
-      delete[] m_ppSOM;
+  delete[] m_ppSOM;
 
-      for (int n = 0; n < KERNEL; n++)
-        delete[] m_ppW[n];
+  for (int n = 0; n < KERNEL; n++)
+    delete[] m_ppW[n];
 
-      delete[] m_ppW;
-    }
+  delete[] m_ppW;
+}
 
-    void BGModelFuzzySom::setBGModelParameter(int id, int value)
-    {
-      double dvalue = (double)value / 255.0;
+void BGModelFuzzySom::setBGModelParameter(int id, int value)
+{
+  double dvalue = (double)value / 255.0;
 
-      switch (id)
-      {
-      case 0:
-        m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
-        break;
+  switch (id)
+  {
+  case 0:
+    m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
+    break;
 
-      case 1:
-        m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
-        break;
+  case 1:
+    m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
+    break;
 
-      case 2:
-        m_alpha2 = dvalue*dvalue*dvalue / m_Wmax;
-        break;
+  case 2:
+    m_alpha2 = dvalue*dvalue*dvalue / m_Wmax;
+    break;
 
-      case 3:
-        m_alpha1 = dvalue*dvalue*dvalue / m_Wmax;
-        break;
+  case 3:
+    m_alpha1 = dvalue*dvalue*dvalue / m_Wmax;
+    break;
 
-      case 5:
-        m_TSteps = (int)(255.0*dvalue);
-        break;
-      }
+  case 5:
+    m_TSteps = (int)(255.0*dvalue);
+    break;
+  }
 
-      return;
-    }
+  return;
+}
+
+void BGModelFuzzySom::Init()
+{
+  Image<BYTERGB> prgbSrc(m_SrcImage);
+
+  for (unsigned int j = 0; j < m_height; j++)
+  {
+    int jj = m_offset + j*(N + m_pad);
 
-    void BGModelFuzzySom::Init()
+    for (unsigned int i = 0; i < m_width; i++)
     {
-      Image<BYTERGB> prgbSrc(m_SrcImage);
+      int ii = m_offset + i*(M + m_pad);
 
-      for (unsigned int j = 0; j < m_height; j++)
+      for (int l = 0; l < N; l++)
       {
-        int jj = m_offset + j*(N + m_pad);
-
-        for (unsigned int i = 0; i < m_width; i++)
+        for (int k = 0; k < M; k++)
         {
-          int ii = m_offset + i*(M + m_pad);
-
-          for (int l = 0; l < N; l++)
-          {
-            for (int k = 0; k < M; k++)
-            {
-              m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red;
-              m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green;
-              m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue;
-            }
-          }
+          m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red;
+          m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green;
+          m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue;
         }
       }
+    }
+  }
 
-      m_K = 0;
+  m_K = 0;
 
-      return;
-    }
+  return;
+}
 
-    void BGModelFuzzySom::Update()
-    {
-      double alpha, a;
-      double epsilon;
+void BGModelFuzzySom::Update()
+{
+  double alpha, a;
+  double epsilon;
 
-      // calibration phase
-      if (m_K <= m_TSteps)
-      {
-        epsilon = m_epsilon1;
-        alpha = (m_alpha1 - m_K * (m_alpha1 - m_alpha2) / m_TSteps);
-        m_K++;
-      }
-      else // online phase
-      {
-        epsilon = m_epsilon2;
-        alpha = m_alpha2;
-      }
+  // calibration phase
+  if (m_K <= m_TSteps)
+  {
+    epsilon = m_epsilon1;
+    alpha = (m_alpha1 - m_K * (m_alpha1 - m_alpha2) / m_TSteps);
+    m_K++;
+  }
+  else // online phase
+  {
+    epsilon = m_epsilon2;
+    alpha = m_alpha2;
+  }
 
-      Image<BYTERGB> prgbSrc(m_SrcImage);
-      Image<BYTERGB> prgbBG(m_BGImage);
-      Image<BYTERGB> prgbFG(m_FGImage);
+  Image<BYTERGB> prgbSrc(m_SrcImage);
+  Image<BYTERGB> prgbBG(m_BGImage);
+  Image<BYTERGB> prgbFG(m_FGImage);
 
-      for (unsigned int j = 0; j < m_height; j++)
-      {
-        int jj = m_offset + j*(N + m_pad);
+  for (unsigned int j = 0; j < m_height; j++)
+  {
+    int jj = m_offset + j*(N + m_pad);
 
-        for (unsigned int i = 0; i < m_width; i++)
-        {
-          int ii = m_offset + i*(M + m_pad);
+    for (unsigned int i = 0; i < m_width; i++)
+    {
+      int ii = m_offset + i*(M + m_pad);
 
-          double srcR = (double)prgbSrc[j][i].Red;
-          double srcG = (double)prgbSrc[j][i].Green;
-          double srcB = (double)prgbSrc[j][i].Blue;
+      double srcR = (double)prgbSrc[j][i].Red;
+      double srcG = (double)prgbSrc[j][i].Green;
+      double srcB = (double)prgbSrc[j][i].Blue;
 
-          // Find BMU
+      // Find BMU
 
-          double d2min = DBL_MAX;
-          int iiHit = ii;
-          int jjHit = jj;
+      double d2min = DBL_MAX;
+      int iiHit = ii;
+      int jjHit = jj;
 
-          for (int l = 0; l < N; l++)
-          {
-            for (int k = 0; k < M; k++)
-            {
-              double dr = srcR - m_ppSOM[jj + l][ii + k].Red;
-              double dg = srcG - m_ppSOM[jj + l][ii + k].Green;
-              double db = srcB - m_ppSOM[jj + l][ii + k].Blue;
-
-              double d2 = dr*dr + dg*dg + db*db;
-
-              if (d2 < d2min)
-              {
-                d2min = d2;
-                iiHit = ii + k;
-                jjHit = jj + l;
-              }
-            }
-          }
+      for (int l = 0; l < N; l++)
+      {
+        for (int k = 0; k < M; k++)
+        {
+          double dr = srcR - m_ppSOM[jj + l][ii + k].Red;
+          double dg = srcG - m_ppSOM[jj + l][ii + k].Green;
+          double db = srcB - m_ppSOM[jj + l][ii + k].Blue;
 
-          double fuzzyBG = 1.0;
+          double d2 = dr*dr + dg*dg + db*db;
 
-          if (d2min < epsilon)
-            fuzzyBG = d2min / epsilon;
+          if (d2 < d2min)
+          {
+            d2min = d2;
+            iiHit = ii + k;
+            jjHit = jj + l;
+          }
+        }
+      }
 
-          // Update SOM
+      double fuzzyBG = 1.0;
 
-          double alphamax = alpha*exp(FUZZYEXP*fuzzyBG);
+      if (d2min < epsilon)
+        fuzzyBG = d2min / epsilon;
 
-          for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++)
-          {
-            for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++)
-            {
-              a = alphamax * m_ppW[l - jjHit + m_offset][k - iiHit + m_offset];
+      // Update SOM
 
-              // speed hack.. avoid very small increment values. abs() is sloooow.
+      double alphamax = alpha*exp(FUZZYEXP*fuzzyBG);
 
-              double d;
+      for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++)
+      {
+        for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++)
+        {
+          a = alphamax * m_ppW[l - jjHit + m_offset][k - iiHit + m_offset];
 
-              d = srcR - m_ppSOM[l][k].Red;
-              if (d*d > DBL_MIN)
-                m_ppSOM[l][k].Red += a*d;
+          // speed hack.. avoid very small increment values. abs() is sloooow.
 
-              d = srcG - m_ppSOM[l][k].Green;
-              if (d*d > DBL_MIN)
-                m_ppSOM[l][k].Green += a*d;
+          double d;
 
-              d = srcB - m_ppSOM[l][k].Blue;
-              if (d*d > DBL_MIN)
-                m_ppSOM[l][k].Blue += a*d;
-            }
-          }
+          d = srcR - m_ppSOM[l][k].Red;
+          if (d*d > DBL_MIN)
+            m_ppSOM[l][k].Red += a*d;
 
-          if (fuzzyBG >= FUZZYTHRESH)
-          {
-            // Set foreground image
-            prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255;
-          }
-          else
-          {
-            // Set background image
-            prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red;
-            prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green;
-            prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue;
+          d = srcG - m_ppSOM[l][k].Green;
+          if (d*d > DBL_MIN)
+            m_ppSOM[l][k].Green += a*d;
 
-            // Set foreground image
-            prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0;
-          }
+          d = srcB - m_ppSOM[l][k].Blue;
+          if (d*d > DBL_MIN)
+            m_ppSOM[l][k].Blue += a*d;
         }
       }
 
-      return;
+      if (fuzzyBG >= FUZZYTHRESH)
+      {
+        // Set foreground image
+        prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255;
+      }
+      else
+      {
+        // Set background image
+        prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red;
+        prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green;
+        prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue;
+
+        // Set foreground image
+        prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0;
+      }
     }
   }
+
+  return;
 }
diff --git a/src/algorithms/lb/BGModelFuzzySom.h b/src/algorithms/lb/BGModelFuzzySom.h
index 8469ae6e39017018abb1ce1a31482dc8445fa4ad..58a477a890703c956c2d026a8cae622f63cf5179 100644
--- a/src/algorithms/lb/BGModelFuzzySom.h
+++ b/src/algorithms/lb/BGModelFuzzySom.h
@@ -2,54 +2,55 @@
 
 #include "BGModel.h"
 
-namespace lb_library
+namespace bgslibrary
 {
-  namespace FuzzyAdaptiveSOM
+  namespace algorithms
   {
-    // SOM parameters
-    const int M = 3;				// width SOM (per pixel)
-    const int N = 3;				// height SOM (per pixel)
-    const int KERNEL = 3; 	// size Gaussian kernel
-
-    const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels			//
-    const int TRAINING_STEPS = 100;			// number of training steps
-
-    const double EPS1 = 100.0; // model match distance during training
-    const double EPS2 = 20.0;  // model match distance
-    const double C1 = 1.0;     // learning rate during training
-    const double C2 = 0.05;    // learning rate
-
-    const double FUZZYEXP = -5.0;
-    const double FUZZYTHRESH = 0.8;
-
-    class BGModelFuzzySom : public BGModel
+    namespace lb
     {
-    public:
-      BGModelFuzzySom(int width, int height);
-      ~BGModelFuzzySom();
-
-      void setBGModelParameter(int id, int value);
-
-    protected:
-      int m_widthSOM;
-      int m_heightSOM;
-      int m_offset;
-      int m_pad;
-      int m_K;
-      int m_TSteps;
-
-      double m_Wmax;
-
-      double m_epsilon1;
-      double m_epsilon2;
-      double m_alpha1;
-      double m_alpha2;
-
-      DBLRGB** m_ppSOM;					// SOM grid
-      double** m_ppW;						// Weights
-
-      void Init();
-      void Update();
-    };
+      namespace BGModelFuzzySomParams {
+        const int M = 3;      // width SOM (per pixel)
+        const int N = 3;      // height SOM (per pixel)
+        const int KERNEL = 3; // size Gaussian kernel
+        const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels			//
+        const int TRAINING_STEPS = 100;    // number of training steps
+        const double EPS1 = 100.0; // model match distance during training
+        const double EPS2 = 20.0;  // model match distance
+        const double C1 = 1.0;     // learning rate during training
+        const double C2 = 0.05;    // learning rate
+        const double FUZZYEXP = -5.0;
+        const double FUZZYTHRESH = 0.8;
+      }
+
+      class BGModelFuzzySom : public BGModel
+      {
+      public:
+        BGModelFuzzySom(int width, int height);
+        ~BGModelFuzzySom();
+
+        void setBGModelParameter(int id, int value);
+
+      protected:
+        int m_widthSOM;
+        int m_heightSOM;
+        int m_offset;
+        int m_pad;
+        int m_K;
+        int m_TSteps;
+
+        double m_Wmax;
+
+        double m_epsilon1;
+        double m_epsilon2;
+        double m_alpha1;
+        double m_alpha2;
+
+        DBLRGB** m_ppSOM;  // SOM grid
+        double** m_ppW;    // Weights
+
+        void Init();
+        void Update();
+      };
+    }
   }
 }
diff --git a/src/algorithms/lb/BGModelGauss.cpp b/src/algorithms/lb/BGModelGauss.cpp
index 6a4b4233efdeb45e68f0d4dcf3e08a444cb94ca7..fbb006a0bc2cd69b719960e5685946df568bca16 100644
--- a/src/algorithms/lb/BGModelGauss.cpp
+++ b/src/algorithms/lb/BGModelGauss.cpp
@@ -1,164 +1,161 @@
 #include "BGModelGauss.h"
 
-namespace lb_library
-{
-  namespace SimpleGaussian
-  {
-    BGModelGauss::BGModelGauss(int width, int height) : BGModel(width, height)
-    {
-      m_alpha = ALPHAGAUSS;
-      m_threshold = THRESHGAUSS*THRESHGAUSS;
-      m_noise = NOISEGAUSS;
+using namespace bgslibrary::algorithms::lb;
+using namespace bgslibrary::algorithms::lb::BGModelGaussParams;
 
-      m_pMu = new DBLRGB[m_width * m_height];
-      m_pVar = new DBLRGB[m_width * m_height];
+BGModelGauss::BGModelGauss(int width, int height) : BGModel(width, height)
+{
+  m_alpha = ALPHAGAUSS;
+  m_threshold = THRESHGAUSS*THRESHGAUSS;
+  m_noise = NOISEGAUSS;
 
-      DBLRGB *pMu = m_pMu;
-      DBLRGB *pVar = m_pVar;
+  m_pMu = new DBLRGB[m_width * m_height];
+  m_pVar = new DBLRGB[m_width * m_height];
 
-      for (unsigned int k = 0; k < (m_width * m_height); k++)
-      {
-        pMu->Red = 0.0;
-        pMu->Green = 0.0;
-        pMu->Blue = 0.0;
+  DBLRGB *pMu = m_pMu;
+  DBLRGB *pVar = m_pVar;
 
-        pVar->Red = m_noise;
-        pVar->Green = m_noise;
-        pVar->Blue = m_noise;
+  for (unsigned int k = 0; k < (m_width * m_height); k++)
+  {
+    pMu->Red = 0.0;
+    pMu->Green = 0.0;
+    pMu->Blue = 0.0;
 
-        pMu++;
-        pVar++;
-      }
-    }
+    pVar->Red = m_noise;
+    pVar->Green = m_noise;
+    pVar->Blue = m_noise;
 
-    BGModelGauss::~BGModelGauss()
-    {
-      delete[] m_pMu;
-      delete[] m_pVar;
-    }
+    pMu++;
+    pVar++;
+  }
+}
 
-    void BGModelGauss::setBGModelParameter(int id, int value)
-    {
-      double dvalue = (double)value / 255.0;
+BGModelGauss::~BGModelGauss()
+{
+  delete[] m_pMu;
+  delete[] m_pVar;
+}
 
-      switch (id)
-      {
-      case 0:
-        m_threshold = 100.0*dvalue*dvalue;
-        break;
+void BGModelGauss::setBGModelParameter(int id, int value)
+{
+  double dvalue = (double)value / 255.0;
 
-      case 1:
-        m_noise = 100.0*dvalue;
-        break;
+  switch (id)
+  {
+  case 0:
+    m_threshold = 100.0*dvalue*dvalue;
+    break;
 
-      case 2:
-        m_alpha = dvalue*dvalue*dvalue;
-        break;
-      }
+  case 1:
+    m_noise = 100.0*dvalue;
+    break;
 
-      return;
-    }
+  case 2:
+    m_alpha = dvalue*dvalue*dvalue;
+    break;
+  }
 
-    void BGModelGauss::Init()
-    {
-      DBLRGB *pMu = m_pMu;
-      DBLRGB *pVar = m_pVar;
+  return;
+}
 
-      Image<BYTERGB> prgbSrc(m_SrcImage);
+void BGModelGauss::Init()
+{
+  DBLRGB *pMu = m_pMu;
+  DBLRGB *pVar = m_pVar;
 
-      for (unsigned int i = 0; i < m_height; i++)
-      {
-        for (unsigned int j = 0; j < m_width; j++)
-        {
-          pMu->Red = prgbSrc[i][j].Red;
-          pMu->Green = prgbSrc[i][j].Green;
-          pMu->Blue = prgbSrc[i][j].Blue;
+  Image<BYTERGB> prgbSrc(m_SrcImage);
 
-          pVar->Red = m_noise;
-          pVar->Green = m_noise;
-          pVar->Blue = m_noise;
+  for (unsigned int i = 0; i < m_height; i++)
+  {
+    for (unsigned int j = 0; j < m_width; j++)
+    {
+      pMu->Red = prgbSrc[i][j].Red;
+      pMu->Green = prgbSrc[i][j].Green;
+      pMu->Blue = prgbSrc[i][j].Blue;
 
-          pMu++;
-          pVar++;
-        }
-      }
+      pVar->Red = m_noise;
+      pVar->Green = m_noise;
+      pVar->Blue = m_noise;
 
-      return;
+      pMu++;
+      pVar++;
     }
+  }
 
-    void BGModelGauss::Update()
-    {
-      DBLRGB *pMu = m_pMu;
-      DBLRGB *pVar = m_pVar;
+  return;
+}
 
-      Image<BYTERGB> prgbSrc(m_SrcImage);
-      Image<BYTERGB> prgbBG(m_BGImage);
-      Image<BYTERGB> prgbFG(m_FGImage);
+void BGModelGauss::Update()
+{
+  DBLRGB *pMu = m_pMu;
+  DBLRGB *pVar = m_pVar;
 
-      for (unsigned int i = 0; i < m_height; i++)
-      {
-        for (unsigned int j = 0; j < m_width; j++)
-        {
-          double srcR = (double)prgbSrc[i][j].Red;
-          double srcG = (double)prgbSrc[i][j].Green;
-          double srcB = (double)prgbSrc[i][j].Blue;
+  Image<BYTERGB> prgbSrc(m_SrcImage);
+  Image<BYTERGB> prgbBG(m_BGImage);
+  Image<BYTERGB> prgbFG(m_FGImage);
 
-          // Mahalanobis distance
+  for (unsigned int i = 0; i < m_height; i++)
+  {
+    for (unsigned int j = 0; j < m_width; j++)
+    {
+      double srcR = (double)prgbSrc[i][j].Red;
+      double srcG = (double)prgbSrc[i][j].Green;
+      double srcB = (double)prgbSrc[i][j].Blue;
 
-          double dr = srcR - pMu->Red;
-          double dg = srcG - pMu->Green;
-          double db = srcB - pMu->Blue;
+      // Mahalanobis distance
 
-          double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue;
+      double dr = srcR - pMu->Red;
+      double dg = srcG - pMu->Green;
+      double db = srcB - pMu->Blue;
 
-          // Classify
+      double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue;
 
-          if (d2 < m_threshold)
-            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0;
-          else
-            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255;
+      // Classify
 
-          // Update parameters
+      if (d2 < m_threshold)
+        prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0;
+      else
+        prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255;
 
-          if (dr*dr > DBL_MIN)
-            pMu->Red += m_alpha*dr;
+      // Update parameters
 
-          if (dg*dg > DBL_MIN)
-            pMu->Green += m_alpha*dg;
+      if (dr*dr > DBL_MIN)
+        pMu->Red += m_alpha*dr;
 
-          if (db*db > DBL_MIN)
-            pMu->Blue += m_alpha*db;
+      if (dg*dg > DBL_MIN)
+        pMu->Green += m_alpha*dg;
 
-          double d;
+      if (db*db > DBL_MIN)
+        pMu->Blue += m_alpha*db;
 
-          d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red;
-          if (d*d > DBL_MIN)
-            pVar->Red += m_alpha*d;
+      double d;
 
-          d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green;
-          if (d*d > DBL_MIN)
-            pVar->Green += m_alpha*d;
+      d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red;
+      if (d*d > DBL_MIN)
+        pVar->Red += m_alpha*d;
 
-          d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue;
-          if (d*d > DBL_MIN)
-            pVar->Blue += m_alpha*d;
+      d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green;
+      if (d*d > DBL_MIN)
+        pVar->Green += m_alpha*d;
 
-          pVar->Red = (std::min)(pVar->Red, m_noise);
-          pVar->Green = (std::min)(pVar->Green, m_noise);
-          pVar->Blue = (std::min)(pVar->Blue, m_noise);
+      d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue;
+      if (d*d > DBL_MIN)
+        pVar->Blue += m_alpha*d;
 
-          // Set background
+      pVar->Red = (std::min)(pVar->Red, m_noise);
+      pVar->Green = (std::min)(pVar->Green, m_noise);
+      pVar->Blue = (std::min)(pVar->Blue, m_noise);
 
-          prgbBG[i][j].Red = (unsigned char)pMu->Red;
-          prgbBG[i][j].Green = (unsigned char)pMu->Green;
-          prgbBG[i][j].Blue = (unsigned char)pMu->Blue;
+      // Set background
 
-          pMu++;
-          pVar++;
-        }
-      }
+      prgbBG[i][j].Red = (unsigned char)pMu->Red;
+      prgbBG[i][j].Green = (unsigned char)pMu->Green;
+      prgbBG[i][j].Blue = (unsigned char)pMu->Blue;
 
-      return;
+      pMu++;
+      pVar++;
     }
   }
+
+  return;
 }
diff --git a/src/algorithms/lb/BGModelGauss.h b/src/algorithms/lb/BGModelGauss.h
index 5dffa0948ac16436a0debdd4947778e8a3a9ab29..42945c14209741bef773ca95d1a3a9642f71b131 100644
--- a/src/algorithms/lb/BGModelGauss.h
+++ b/src/algorithms/lb/BGModelGauss.h
@@ -2,33 +2,37 @@
 
 #include "BGModel.h"
 
-namespace lb_library
+namespace bgslibrary
 {
-  namespace SimpleGaussian
+  namespace algorithms
   {
-    // Parameters
-    const double THRESHGAUSS = 2.5;   // Threshold
-    const double ALPHAGAUSS = 0.0001; // Learning rate
-    const double NOISEGAUSS = 50.0;   // Minimum variance (noise)
-
-    class BGModelGauss : public BGModel
+    namespace lb
     {
-    public:
-      BGModelGauss(int width, int height);
-      ~BGModelGauss();
+      namespace BGModelGaussParams {
+        const double THRESHGAUSS = 2.5;   // Threshold
+        const double ALPHAGAUSS = 0.0001; // Learning rate
+        const double NOISEGAUSS = 50.0;   // Minimum variance (noise)
+      }
+      
+      class BGModelGauss : public BGModel
+      {
+      public:
+        BGModelGauss(int width, int height);
+        ~BGModelGauss();
 
-      void setBGModelParameter(int id, int value);
+        void setBGModelParameter(int id, int value);
 
-    protected:
-      double m_alpha;
-      double m_threshold;
-      double m_noise;
+      protected:
+        double m_alpha;
+        double m_threshold;
+        double m_noise;
 
-      DBLRGB* m_pMu;
-      DBLRGB* m_pVar;
+        DBLRGB* m_pMu;
+        DBLRGB* m_pVar;
 
-      void Init();
-      void Update();
-    };
+        void Init();
+        void Update();
+      };
+    }
   }
 }
diff --git a/src/algorithms/lb/BGModelMog.cpp b/src/algorithms/lb/BGModelMog.cpp
index e52c6fb62d065c774e6d2cfeb60e2fbf2d2713e5..c23055f281ec3cd083cf7c1196792134f80bd95c 100644
--- a/src/algorithms/lb/BGModelMog.cpp
+++ b/src/algorithms/lb/BGModelMog.cpp
@@ -1,273 +1,270 @@
 #include "BGModelMog.h"
 
-namespace lb_library
-{
-  namespace MixtureOfGaussians
-  {
-    BGModelMog::BGModelMog(int width, int height) : BGModel(width, height)
-    {
-      m_alpha = LEARNINGRATEMOG;
-      m_threshold = THRESHOLDMOG*THRESHOLDMOG;
-      m_noise = INITIALVARMOG;
+using namespace bgslibrary::algorithms::lb;
+using namespace bgslibrary::algorithms::lb::BGModelMogParams;
 
-      m_T = BGTHRESHOLDMOG;
+BGModelMog::BGModelMog(int width, int height) : BGModel(width, height)
+{
+  m_alpha = LEARNINGRATEMOG;
+  m_threshold = THRESHOLDMOG*THRESHOLDMOG;
+  m_noise = INITIALVARMOG;
 
-      m_pMOG = new MOGDATA[NUMBERGAUSSIANS*m_width*m_height];
-      m_pK = new int[m_width*m_height];
+  m_T = BGTHRESHOLDMOG;
 
-      MOGDATA *pMOG = m_pMOG;
-      int *pK = m_pK;
+  m_pMOG = new MOGDATA[NUMBERGAUSSIANS*m_width*m_height];
+  m_pK = new int[m_width*m_height];
 
-      for (unsigned int i = 0; i < (m_width * m_height); i++)
-      {
-        for (unsigned int k = 0; k < NUMBERGAUSSIANS; k++)
-        {
-          pMOG->mu.Red = 0.0;
-          pMOG->mu.Green = 0.0;
-          pMOG->mu.Blue = 0.0;
+  MOGDATA *pMOG = m_pMOG;
+  int *pK = m_pK;
 
-          pMOG->var.Red = 0.0;
-          pMOG->var.Green = 0.0;
-          pMOG->var.Blue = 0.0;
+  for (unsigned int i = 0; i < (m_width * m_height); i++)
+  {
+    for (unsigned int k = 0; k < NUMBERGAUSSIANS; k++)
+    {
+      pMOG->mu.Red = 0.0;
+      pMOG->mu.Green = 0.0;
+      pMOG->mu.Blue = 0.0;
 
-          pMOG->w = 0.0;
-          pMOG->sortKey = 0.0;
+      pMOG->var.Red = 0.0;
+      pMOG->var.Green = 0.0;
+      pMOG->var.Blue = 0.0;
 
-          pMOG++;
-        }
+      pMOG->w = 0.0;
+      pMOG->sortKey = 0.0;
 
-        pK[i] = 0;
-      }
+      pMOG++;
     }
 
-    BGModelMog::~BGModelMog()
-    {
-      delete[] m_pMOG;
-      delete[] m_pK;
-    }
+    pK[i] = 0;
+  }
+}
 
-    void BGModelMog::setBGModelParameter(int id, int value)
-    {
-      double dvalue = (double)value / 255.0;
+BGModelMog::~BGModelMog()
+{
+  delete[] m_pMOG;
+  delete[] m_pK;
+}
 
-      switch (id)
-      {
-      case 0:
-        m_threshold = 100.0*dvalue*dvalue;
-        break;
+void BGModelMog::setBGModelParameter(int id, int value)
+{
+  double dvalue = (double)value / 255.0;
 
-      case 1:
-        m_T = dvalue;
-        break;
+  switch (id)
+  {
+  case 0:
+    m_threshold = 100.0*dvalue*dvalue;
+    break;
 
-      case 2:
-        m_alpha = dvalue*dvalue*dvalue;
-        break;
+  case 1:
+    m_T = dvalue;
+    break;
 
-      case 3:
-        m_noise = 100.0*dvalue;;
-        break;
-      }
+  case 2:
+    m_alpha = dvalue*dvalue*dvalue;
+    break;
 
-      return;
-    }
+  case 3:
+    m_noise = 100.0*dvalue;;
+    break;
+  }
 
-    void BGModelMog::Init()
-    {
-      MOGDATA *pMOG = m_pMOG;
-      int *pK = m_pK;
+  return;
+}
 
-      Image<BYTERGB> prgbSrc(m_SrcImage);
+void BGModelMog::Init()
+{
+  MOGDATA *pMOG = m_pMOG;
+  int *pK = m_pK;
 
-      int n = 0;
-      for (unsigned int i = 0; i < m_height; i++)
-      {
-        for (unsigned int j = 0; j < m_width; j++)
-        {
-          pMOG[0].mu.Red = prgbSrc[i][j].Red;
-          pMOG[0].mu.Green = prgbSrc[i][j].Green;
-          pMOG[0].mu.Blue = prgbSrc[i][j].Blue;
+  Image<BYTERGB> prgbSrc(m_SrcImage);
 
-          pMOG[0].var.Red = m_noise;
-          pMOG[0].var.Green = m_noise;
-          pMOG[0].var.Blue = m_noise;
+  int n = 0;
+  for (unsigned int i = 0; i < m_height; i++)
+  {
+    for (unsigned int j = 0; j < m_width; j++)
+    {
+      pMOG[0].mu.Red = prgbSrc[i][j].Red;
+      pMOG[0].mu.Green = prgbSrc[i][j].Green;
+      pMOG[0].mu.Blue = prgbSrc[i][j].Blue;
 
-          pMOG[0].w = 1.0;
-          pMOG[0].sortKey = pMOG[0].w / sqrt(pMOG[0].var.Red + pMOG[0].var.Green + pMOG[0].var.Blue);
+      pMOG[0].var.Red = m_noise;
+      pMOG[0].var.Green = m_noise;
+      pMOG[0].var.Blue = m_noise;
 
-          pK[n] = 1;
-          n++;
+      pMOG[0].w = 1.0;
+      pMOG[0].sortKey = pMOG[0].w / sqrt(pMOG[0].var.Red + pMOG[0].var.Green + pMOG[0].var.Blue);
 
-          pMOG += NUMBERGAUSSIANS;
-        }
-      }
+      pK[n] = 1;
+      n++;
 
-      return;
+      pMOG += NUMBERGAUSSIANS;
     }
+  }
+
+  return;
+}
+
+void BGModelMog::Update()
+{
+  int kBG;
+
+  MOGDATA *pMOG = m_pMOG;
+  int *pK = m_pK;
+
+  Image<BYTERGB> prgbSrc(m_SrcImage);
+  Image<BYTERGB> prgbBG(m_BGImage);
+  Image<BYTERGB> prgbFG(m_FGImage);
 
-    void BGModelMog::Update()
+  int n = 0;
+  for (unsigned int i = 0; i < m_height; i++)
+  {
+    for (unsigned int j = 0; j < m_width; j++)
     {
-      int kBG;
+      double srcR = (double)prgbSrc[i][j].Red;
+      double srcG = (double)prgbSrc[i][j].Green;
+      double srcB = (double)prgbSrc[i][j].Blue;
 
-      MOGDATA *pMOG = m_pMOG;
-      int *pK = m_pK;
+      // Find matching distribution
 
-      Image<BYTERGB> prgbSrc(m_SrcImage);
-      Image<BYTERGB> prgbBG(m_BGImage);
-      Image<BYTERGB> prgbFG(m_FGImage);
+      int kHit = -1;
 
-      int n = 0;
-      for (unsigned int i = 0; i < m_height; i++)
+      for (int k = 0; k < pK[n]; k++)
       {
-        for (unsigned int j = 0; j < m_width; j++)
-        {
-          double srcR = (double)prgbSrc[i][j].Red;
-          double srcG = (double)prgbSrc[i][j].Green;
-          double srcB = (double)prgbSrc[i][j].Blue;
+        // Mahalanobis distance
+        double dr = srcR - pMOG[k].mu.Red;
+        double dg = srcG - pMOG[k].mu.Green;
+        double db = srcB - pMOG[k].mu.Blue;
+        double d2 = dr*dr / pMOG[k].var.Red + dg*dg / pMOG[k].var.Green + db*db / pMOG[k].var.Blue;
 
-          // Find matching distribution
+        if (d2 < m_threshold)
+        {
+          kHit = k;
+          break;
+        }
+      }
 
-          int kHit = -1;
+      // Adjust parameters
 
-          for (int k = 0; k < pK[n]; k++)
+      // matching distribution found
+      if (kHit != -1)
+      {
+        for (int k = 0; k < pK[n]; k++)
+        {
+          if (k == kHit)
           {
-            // Mahalanobis distance
-            double dr = srcR - pMOG[k].mu.Red;
-            double dg = srcG - pMOG[k].mu.Green;
-            double db = srcB - pMOG[k].mu.Blue;
-            double d2 = dr*dr / pMOG[k].var.Red + dg*dg / pMOG[k].var.Green + db*db / pMOG[k].var.Blue;
-
-            if (d2 < m_threshold)
-            {
-              kHit = k;
-              break;
-            }
-          }
+            pMOG[k].w = pMOG[k].w + m_alpha*(1.0f - pMOG[k].w);
 
-          // Adjust parameters
+            double d;
 
-          // matching distribution found
-          if (kHit != -1)
-          {
-            for (int k = 0; k < pK[n]; k++)
-            {
-              if (k == kHit)
-              {
-                pMOG[k].w = pMOG[k].w + m_alpha*(1.0f - pMOG[k].w);
-
-                double d;
-
-                d = srcR - pMOG[k].mu.Red;
-                if (d*d > DBL_MIN)
-                  pMOG[k].mu.Red += m_alpha*d;
-
-                d = srcG - pMOG[k].mu.Green;
-                if (d*d > DBL_MIN)
-                  pMOG[k].mu.Green += m_alpha*d;
-
-                d = srcB - pMOG[k].mu.Blue;
-                if (d*d > DBL_MIN)
-                  pMOG[k].mu.Blue += m_alpha*d;
-
-                d = (srcR - pMOG[k].mu.Red)*(srcR - pMOG[k].mu.Red) - pMOG[k].var.Red;
-                if (d*d > DBL_MIN)
-                  pMOG[k].var.Red += m_alpha*d;
-
-                d = (srcG - pMOG[k].mu.Green)*(srcG - pMOG[k].mu.Green) - pMOG[k].var.Green;
-                if (d*d > DBL_MIN)
-                  pMOG[k].var.Green += m_alpha*d;
-
-                d = (srcB - pMOG[k].mu.Blue)*(srcB - pMOG[k].mu.Blue) - pMOG[k].var.Blue;
-                if (d*d > DBL_MIN)
-                  pMOG[k].var.Blue += m_alpha*d;
-
-                pMOG[k].var.Red = (std::max)(pMOG[k].var.Red, m_noise);
-                pMOG[k].var.Green = (std::max)(pMOG[k].var.Green, m_noise);
-                pMOG[k].var.Blue = (std::max)(pMOG[k].var.Blue, m_noise);
-              }
-              else
-                pMOG[k].w = (1.0 - m_alpha)*pMOG[k].w;
-            }
-          }
-          // no match found... create new one
-          else
-          {
-            if (pK[n] < NUMBERGAUSSIANS)
-              pK[n]++;
+            d = srcR - pMOG[k].mu.Red;
+            if (d*d > DBL_MIN)
+              pMOG[k].mu.Red += m_alpha*d;
+
+            d = srcG - pMOG[k].mu.Green;
+            if (d*d > DBL_MIN)
+              pMOG[k].mu.Green += m_alpha*d;
 
-            kHit = pK[n] - 1;
+            d = srcB - pMOG[k].mu.Blue;
+            if (d*d > DBL_MIN)
+              pMOG[k].mu.Blue += m_alpha*d;
 
-            if (pK[n] == 1)
-              pMOG[kHit].w = 1.0;
-            else
-              pMOG[kHit].w = LEARNINGRATEMOG;
+            d = (srcR - pMOG[k].mu.Red)*(srcR - pMOG[k].mu.Red) - pMOG[k].var.Red;
+            if (d*d > DBL_MIN)
+              pMOG[k].var.Red += m_alpha*d;
 
-            pMOG[kHit].mu.Red = srcR;
-            pMOG[kHit].mu.Green = srcG;
-            pMOG[kHit].mu.Blue = srcB;
+            d = (srcG - pMOG[k].mu.Green)*(srcG - pMOG[k].mu.Green) - pMOG[k].var.Green;
+            if (d*d > DBL_MIN)
+              pMOG[k].var.Green += m_alpha*d;
 
-            pMOG[kHit].var.Red = m_noise;
-            pMOG[kHit].var.Green = m_noise;
-            pMOG[kHit].var.Blue = m_noise;
+            d = (srcB - pMOG[k].mu.Blue)*(srcB - pMOG[k].mu.Blue) - pMOG[k].var.Blue;
+            if (d*d > DBL_MIN)
+              pMOG[k].var.Blue += m_alpha*d;
+
+            pMOG[k].var.Red = (std::max)(pMOG[k].var.Red, m_noise);
+            pMOG[k].var.Green = (std::max)(pMOG[k].var.Green, m_noise);
+            pMOG[k].var.Blue = (std::max)(pMOG[k].var.Blue, m_noise);
           }
+          else
+            pMOG[k].w = (1.0 - m_alpha)*pMOG[k].w;
+        }
+      }
+      // no match found... create new one
+      else
+      {
+        if (pK[n] < NUMBERGAUSSIANS)
+          pK[n]++;
 
-          // Normalize weights
+        kHit = pK[n] - 1;
 
-          double wsum = 0.0;
+        if (pK[n] == 1)
+          pMOG[kHit].w = 1.0;
+        else
+          pMOG[kHit].w = LEARNINGRATEMOG;
 
-          for (int k = 0; k < pK[n]; k++)
-            wsum += pMOG[k].w;
+        pMOG[kHit].mu.Red = srcR;
+        pMOG[kHit].mu.Green = srcG;
+        pMOG[kHit].mu.Blue = srcB;
 
-          double wfactor = 1.0 / wsum;
+        pMOG[kHit].var.Red = m_noise;
+        pMOG[kHit].var.Green = m_noise;
+        pMOG[kHit].var.Blue = m_noise;
+      }
 
-          for (int k = 0; k < pK[n]; k++)
-          {
-            pMOG[k].w *= wfactor;
-            pMOG[k].sortKey = pMOG[k].w / sqrt(pMOG[k].var.Red + pMOG[k].var.Green + pMOG[k].var.Blue);
-          }
+      // Normalize weights
 
-          // Sort distributions
+      double wsum = 0.0;
 
-          for (int k = 0; k < kHit; k++)
-          {
-            if (pMOG[kHit].sortKey > pMOG[k].sortKey)
-            {
-              std::swap(pMOG[kHit], pMOG[k]);
-              break;
-            }
-          }
+      for (int k = 0; k < pK[n]; k++)
+        wsum += pMOG[k].w;
 
-          // Determine background distributions
+      double wfactor = 1.0 / wsum;
 
-          wsum = 0.0;
+      for (int k = 0; k < pK[n]; k++)
+      {
+        pMOG[k].w *= wfactor;
+        pMOG[k].sortKey = pMOG[k].w / sqrt(pMOG[k].var.Red + pMOG[k].var.Green + pMOG[k].var.Blue);
+      }
 
-          for (int k = 0; k < pK[n]; k++)
-          {
-            wsum += pMOG[k].w;
+      // Sort distributions
 
-            if (wsum > m_T)
-            {
-              kBG = k;
-              break;
-            }
-          }
+      for (int k = 0; k < kHit; k++)
+      {
+        if (pMOG[kHit].sortKey > pMOG[k].sortKey)
+        {
+          std::swap(pMOG[kHit], pMOG[k]);
+          break;
+        }
+      }
 
-          if (kHit > kBG)
-            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255;
-          else
-            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0;
+      // Determine background distributions
 
-          prgbBG[i][j].Red = (unsigned char)pMOG[0].mu.Red;
-          prgbBG[i][j].Green = (unsigned char)pMOG[0].mu.Green;
-          prgbBG[i][j].Blue = (unsigned char)pMOG[0].mu.Blue;
+      wsum = 0.0;
 
-          pMOG += NUMBERGAUSSIANS;
+      for (int k = 0; k < pK[n]; k++)
+      {
+        wsum += pMOG[k].w;
 
-          n++;
+        if (wsum > m_T)
+        {
+          kBG = k;
+          break;
         }
       }
 
-      return;
+      if (kHit > kBG)
+        prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255;
+      else
+        prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0;
+
+      prgbBG[i][j].Red = (unsigned char)pMOG[0].mu.Red;
+      prgbBG[i][j].Green = (unsigned char)pMOG[0].mu.Green;
+      prgbBG[i][j].Blue = (unsigned char)pMOG[0].mu.Blue;
+
+      pMOG += NUMBERGAUSSIANS;
+
+      n++;
     }
   }
+
+  return;
 }
diff --git a/src/algorithms/lb/BGModelMog.h b/src/algorithms/lb/BGModelMog.h
index 6fd6e90cecdca4ced1c306f20f8a23db4f9291fd..06fd1d066c9e4939f32b858752810c12c05724e7 100644
--- a/src/algorithms/lb/BGModelMog.h
+++ b/src/algorithms/lb/BGModelMog.h
@@ -2,43 +2,48 @@
 
 #include "BGModel.h"
 
-namespace lb_library
+namespace bgslibrary
 {
-  namespace MixtureOfGaussians
+  namespace algorithms
   {
-    const unsigned int NUMBERGAUSSIANS = 3;
-    const float LEARNINGRATEMOG = 0.001f;
-    const float THRESHOLDMOG = 2.5f;
-    const float BGTHRESHOLDMOG = 0.5f;
-    const float INITIALVARMOG = 50.0f;
-
-    typedef struct tagMOGDATA
-    {
-      DBLRGB mu;
-      DBLRGB var;
-      double w;
-      double sortKey;
-    } MOGDATA;
-
-    class BGModelMog : public BGModel
+    namespace lb
     {
-    public:
-      BGModelMog(int width, int height);
-      ~BGModelMog();
-
-      void setBGModelParameter(int id, int value);
-
-    protected:
-      double m_alpha;
-      double m_threshold;
-      double m_noise;
-      double m_T;
-
-      MOGDATA* m_pMOG;
-      int* m_pK;				// number of distributions per pixel
-
-      void Init();
-      void Update();
-    };
+      namespace BGModelMogParams {
+        const unsigned int NUMBERGAUSSIANS = 3;
+        const float LEARNINGRATEMOG = 0.001f;
+        const float THRESHOLDMOG = 2.5f;
+        const float BGTHRESHOLDMOG = 0.5f;
+        const float INITIALVARMOG = 50.0f;
+      }
+
+      typedef struct tagMOGDATA
+      {
+        DBLRGB mu;
+        DBLRGB var;
+        double w;
+        double sortKey;
+      } MOGDATA;
+
+      class BGModelMog : public BGModel
+      {
+      public:
+        BGModelMog(int width, int height);
+        ~BGModelMog();
+
+        void setBGModelParameter(int id, int value);
+
+      protected:
+        double m_alpha;
+        double m_threshold;
+        double m_noise;
+        double m_T;
+
+        MOGDATA* m_pMOG;
+        int* m_pK;				// number of distributions per pixel
+
+        void Init();
+        void Update();
+      };
+    }
   }
 }
diff --git a/src/algorithms/lb/BGModelSom.cpp b/src/algorithms/lb/BGModelSom.cpp
index e19b8eb28e40648f6b9511c6c8be7740554be4be..040a1daadb31fcbf80266c2ce21824c206162dbd 100644
--- a/src/algorithms/lb/BGModelSom.cpp
+++ b/src/algorithms/lb/BGModelSom.cpp
@@ -1,255 +1,252 @@
 #include "BGModelSom.h"
 
-namespace lb_library
+using namespace bgslibrary::algorithms::lb;
+using namespace bgslibrary::algorithms::lb::BGModelSomParams;
+
+BGModelSom::BGModelSom(int width, int height) : BGModel(width, height)
 {
-  namespace AdaptiveSOM
-  {
-    BGModelSom::BGModelSom(int width, int height) : BGModel(width, height)
-    {
-      m_offset = (KERNEL - 1) / 2;
+  m_offset = (KERNEL - 1) / 2;
 
-      if (SPAN_NEIGHBORS)
-        m_pad = 0;
-      else
-        m_pad = m_offset;
+  if (SPAN_NEIGHBORS)
+    m_pad = 0;
+  else
+    m_pad = m_offset;
 
-      // SOM models
+  // SOM models
 
-      m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad;
-      m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad;
+  m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad;
+  m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad;
 
-      m_ppSOM = new DBLRGB*[m_heightSOM];
-      for (int n = 0; n < m_heightSOM; n++)
-        m_ppSOM[n] = new DBLRGB[m_widthSOM];
+  m_ppSOM = new DBLRGB*[m_heightSOM];
+  for (int n = 0; n < m_heightSOM; n++)
+    m_ppSOM[n] = new DBLRGB[m_widthSOM];
 
-      for (int j = 0; j < m_heightSOM; j++)
-      {
-        for (int i = 0; i < m_widthSOM; i++)
-        {
-          m_ppSOM[j][i].Red = 0.0;
-          m_ppSOM[j][i].Green = 0.0;
-          m_ppSOM[j][i].Blue = 0.0;
-        }
-      }
+  for (int j = 0; j < m_heightSOM; j++)
+  {
+    for (int i = 0; i < m_widthSOM; i++)
+    {
+      m_ppSOM[j][i].Red = 0.0;
+      m_ppSOM[j][i].Green = 0.0;
+      m_ppSOM[j][i].Blue = 0.0;
+    }
+  }
 
-      // Create weights
+  // Create weights
 
-      m_ppW = new double*[KERNEL];
-      for (int n = 0; n < KERNEL; n++)
-        m_ppW[n] = new double[KERNEL];
+  m_ppW = new double*[KERNEL];
+  for (int n = 0; n < KERNEL; n++)
+    m_ppW[n] = new double[KERNEL];
 
-      // Construct Gaussian kernel using Pascal's triangle
+  // Construct Gaussian kernel using Pascal's triangle
 
-      int cM;
-      int cN;
-      m_Wmax = DBL_MIN;
+  int cM;
+  int cN;
+  m_Wmax = DBL_MIN;
 
-      cN = 1;
-      for (int j = 0; j < KERNEL; j++)
-      {
-        cM = 1;
+  cN = 1;
+  for (int j = 0; j < KERNEL; j++)
+  {
+    cM = 1;
 
-        for (int i = 0; i < KERNEL; i++)
-        {
-          m_ppW[j][i] = cN*cM;
+    for (int i = 0; i < KERNEL; i++)
+    {
+      m_ppW[j][i] = cN*cM;
 
-          if (m_ppW[j][i] > m_Wmax)
-            m_Wmax = m_ppW[j][i];
+      if (m_ppW[j][i] > m_Wmax)
+        m_Wmax = m_ppW[j][i];
 
-          cM = cM * (KERNEL - 1 - i) / (i + 1);
-        }
+      cM = cM * (KERNEL - 1 - i) / (i + 1);
+    }
 
-        cN = cN * (KERNEL - 1 - j) / (j + 1);
-      }
+    cN = cN * (KERNEL - 1 - j) / (j + 1);
+  }
 
-      // Parameters
+  // Parameters
 
-      m_epsilon1 = EPS1*EPS1;
-      m_epsilon2 = EPS2*EPS2;
+  m_epsilon1 = EPS1*EPS1;
+  m_epsilon2 = EPS2*EPS2;
 
-      m_alpha1 = C1 / m_Wmax;
-      m_alpha2 = C2 / m_Wmax;
+  m_alpha1 = C1 / m_Wmax;
+  m_alpha2 = C2 / m_Wmax;
 
-      m_K = 0;
-      m_TSteps = TRAINING_STEPS;
-    }
+  m_K = 0;
+  m_TSteps = TRAINING_STEPS;
+}
 
-    BGModelSom::~BGModelSom()
-    {
-      for (int n = 0; n < m_heightSOM; n++)
-        delete[] m_ppSOM[n];
+BGModelSom::~BGModelSom()
+{
+  for (int n = 0; n < m_heightSOM; n++)
+    delete[] m_ppSOM[n];
 
-      delete[] m_ppSOM;
+  delete[] m_ppSOM;
 
-      for (int n = 0; n < KERNEL; n++)
-        delete[] m_ppW[n];
+  for (int n = 0; n < KERNEL; n++)
+    delete[] m_ppW[n];
 
-      delete[] m_ppW;
-    }
+  delete[] m_ppW;
+}
 
-    void BGModelSom::setBGModelParameter(int id, int value)
-    {
-      double dvalue = (double)value / 255.0;
+void BGModelSom::setBGModelParameter(int id, int value)
+{
+  double dvalue = (double)value / 255.0;
 
-      switch (id)
-      {
-      case 0:
-        m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
-        break;
+  switch (id)
+  {
+  case 0:
+    m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
+    break;
 
-      case 1:
-        m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
-        break;
+  case 1:
+    m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
+    break;
 
-      case 2:
-        m_alpha2 = dvalue*dvalue*dvalue / m_Wmax;
-        break;
+  case 2:
+    m_alpha2 = dvalue*dvalue*dvalue / m_Wmax;
+    break;
 
-      case 3:
-        m_alpha1 = dvalue*dvalue*dvalue / m_Wmax;
-        break;
+  case 3:
+    m_alpha1 = dvalue*dvalue*dvalue / m_Wmax;
+    break;
 
-      case 5:
-        m_TSteps = (int)(255.0*dvalue);
-        break;
-      }
+  case 5:
+    m_TSteps = (int)(255.0*dvalue);
+    break;
+  }
 
-      return;
-    }
+  return;
+}
+
+void BGModelSom::Init()
+{
+  Image<BYTERGB> prgbSrc(m_SrcImage);
+
+  for (unsigned int j = 0; j < m_height; j++)
+  {
+    int jj = m_offset + j*(N + m_pad);
 
-    void BGModelSom::Init()
+    for (unsigned int i = 0; i < m_width; i++)
     {
-      Image<BYTERGB> prgbSrc(m_SrcImage);
+      int ii = m_offset + i*(M + m_pad);
 
-      for (unsigned int j = 0; j < m_height; j++)
+      for (int l = 0; l < N; l++)
       {
-        int jj = m_offset + j*(N + m_pad);
-
-        for (unsigned int i = 0; i < m_width; i++)
+        for (int k = 0; k < M; k++)
         {
-          int ii = m_offset + i*(M + m_pad);
-
-          for (int l = 0; l < N; l++)
-          {
-            for (int k = 0; k < M; k++)
-            {
-              m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red;
-              m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green;
-              m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue;
-            }
-          }
+          m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red;
+          m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green;
+          m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue;
         }
       }
+    }
+  }
 
-      m_K = 0;
+  m_K = 0;
 
-      return;
-    }
+  return;
+}
 
-    void BGModelSom::Update()
-    {
-      double alpha, a;
-      double epsilon;
+void BGModelSom::Update()
+{
+  double alpha, a;
+  double epsilon;
 
-      // calibration phase
-      if (m_K <= m_TSteps)
-      {
-        epsilon = m_epsilon1;
-        alpha = (m_alpha1 - m_K*(m_alpha1 - m_alpha2) / m_TSteps);
-        m_K++;
-      }
-      else // online phase
-      {
-        epsilon = m_epsilon2;
-        alpha = m_alpha2;
-      }
+  // calibration phase
+  if (m_K <= m_TSteps)
+  {
+    epsilon = m_epsilon1;
+    alpha = (m_alpha1 - m_K*(m_alpha1 - m_alpha2) / m_TSteps);
+    m_K++;
+  }
+  else // online phase
+  {
+    epsilon = m_epsilon2;
+    alpha = m_alpha2;
+  }
 
-      Image<BYTERGB> prgbSrc(m_SrcImage);
-      Image<BYTERGB> prgbBG(m_BGImage);
-      Image<BYTERGB> prgbFG(m_FGImage);
+  Image<BYTERGB> prgbSrc(m_SrcImage);
+  Image<BYTERGB> prgbBG(m_BGImage);
+  Image<BYTERGB> prgbFG(m_FGImage);
 
-      for (unsigned int j = 0; j < m_height; j++)
-      {
-        int jj = m_offset + j*(N + m_pad);
+  for (unsigned int j = 0; j < m_height; j++)
+  {
+    int jj = m_offset + j*(N + m_pad);
 
-        for (unsigned int i = 0; i < m_width; i++)
-        {
-          int ii = m_offset + i*(M + m_pad);
+    for (unsigned int i = 0; i < m_width; i++)
+    {
+      int ii = m_offset + i*(M + m_pad);
 
-          double srcR = (double)prgbSrc[j][i].Red;
-          double srcG = (double)prgbSrc[j][i].Green;
-          double srcB = (double)prgbSrc[j][i].Blue;
+      double srcR = (double)prgbSrc[j][i].Red;
+      double srcG = (double)prgbSrc[j][i].Green;
+      double srcB = (double)prgbSrc[j][i].Blue;
 
-          // Find BMU
+      // Find BMU
 
-          double d2min = DBL_MAX;
-          int iiHit = ii;
-          int jjHit = jj;
+      double d2min = DBL_MAX;
+      int iiHit = ii;
+      int jjHit = jj;
 
-          for (int l = 0; l < N; l++)
-          {
-            for (int k = 0; k < M; k++)
-            {
-              double dr = srcR - m_ppSOM[jj + l][ii + k].Red;
-              double dg = srcG - m_ppSOM[jj + l][ii + k].Green;
-              double db = srcB - m_ppSOM[jj + l][ii + k].Blue;
-
-              double d2 = dr*dr + dg*dg + db*db;
-
-              if (d2 < d2min)
-              {
-                d2min = d2;
-                iiHit = ii + k;
-                jjHit = jj + l;
-              }
-            }
-          }
+      for (int l = 0; l < N; l++)
+      {
+        for (int k = 0; k < M; k++)
+        {
+          double dr = srcR - m_ppSOM[jj + l][ii + k].Red;
+          double dg = srcG - m_ppSOM[jj + l][ii + k].Green;
+          double db = srcB - m_ppSOM[jj + l][ii + k].Blue;
 
-          // Update SOM
+          double d2 = dr*dr + dg*dg + db*db;
 
-          if (d2min <= epsilon) // matching model found
+          if (d2 < d2min)
           {
-            for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++)
-            {
-              for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++)
-              {
-                a = alpha*m_ppW[l - jjHit + m_offset][k - iiHit + m_offset];
+            d2min = d2;
+            iiHit = ii + k;
+            jjHit = jj + l;
+          }
+        }
+      }
 
-                // speed hack.. avoid very small increment values. abs() is sloooow.
+      // Update SOM
 
-                double d;
+      if (d2min <= epsilon) // matching model found
+      {
+        for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++)
+        {
+          for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++)
+          {
+            a = alpha*m_ppW[l - jjHit + m_offset][k - iiHit + m_offset];
 
-                d = srcR - m_ppSOM[l][k].Red;
-                if (d*d > DBL_MIN)
-                  m_ppSOM[l][k].Red += a*d;
+            // speed hack.. avoid very small increment values. abs() is sloooow.
 
-                d = srcG - m_ppSOM[l][k].Green;
-                if (d*d > DBL_MIN)
-                  m_ppSOM[l][k].Green += a*d;
+            double d;
 
-                d = srcB - m_ppSOM[l][k].Blue;
-                if (d*d > DBL_MIN)
-                  m_ppSOM[l][k].Blue += a*d;
-              }
-            }
+            d = srcR - m_ppSOM[l][k].Red;
+            if (d*d > DBL_MIN)
+              m_ppSOM[l][k].Red += a*d;
 
-            // Set background image
-            prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red;
-            prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green;
-            prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue;
+            d = srcG - m_ppSOM[l][k].Green;
+            if (d*d > DBL_MIN)
+              m_ppSOM[l][k].Green += a*d;
 
-            // Set foreground image
-            prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0;
-          }
-          else
-          {
-            // Set foreground image
-            prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255;
+            d = srcB - m_ppSOM[l][k].Blue;
+            if (d*d > DBL_MIN)
+              m_ppSOM[l][k].Blue += a*d;
           }
         }
-      }
 
-      return;
+        // Set background image
+        prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red;
+        prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green;
+        prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue;
+
+        // Set foreground image
+        prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0;
+      }
+      else
+      {
+        // Set foreground image
+        prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255;
+      }
     }
   }
+
+  return;
 }
diff --git a/src/algorithms/lb/BGModelSom.h b/src/algorithms/lb/BGModelSom.h
index 91a5ec2dba6b64595ff25602c8c05f7e4b7378fb..9774fcab2d2c3a46c0cb2edd8d7a66b50144767c 100644
--- a/src/algorithms/lb/BGModelSom.h
+++ b/src/algorithms/lb/BGModelSom.h
@@ -2,51 +2,53 @@
 
 #include "BGModel.h"
 
-namespace lb_library
+namespace bgslibrary
 {
-  namespace AdaptiveSOM
+  namespace algorithms
   {
-    // SOM parameters
-    const int M = 3;				// width SOM (per pixel)
-    const int N = 3;				// height SOM (per pixel)
-    const int KERNEL = 3; 	// size Gaussian kernel
-
-    const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels			//
-    const int TRAINING_STEPS = 100;			// number of training steps
-
-    const float EPS1 = 100.0; // model match distance during training
-    const float EPS2 = 20.0;  // model match distance
-    const float C1 = 1.0;     // learning rate during training
-    const float C2 = 0.05f;    // learning rate
-
-    class BGModelSom : public BGModel
+    namespace lb
     {
-    public:
-      BGModelSom(int width, int height);
-      ~BGModelSom();
-
-      void setBGModelParameter(int id, int value);
-
-    protected:
-      int m_widthSOM;
-      int m_heightSOM;
-      int m_offset;
-      int m_pad;
-      int m_K;
-      int m_TSteps;
-
-      double m_Wmax;
-
-      double m_epsilon1;
-      double m_epsilon2;
-      double m_alpha1;
-      double m_alpha2;
-
-      DBLRGB** m_ppSOM;					// SOM grid
-      double** m_ppW;						// Weights
-
-      void Init();
-      void Update();
-    };
+      namespace BGModelSomParams {
+        const int M = 3;         // width SOM (per pixel)
+        const int N = 3;         // height SOM (per pixel)
+        const int KERNEL = 3;    // size Gaussian kernel
+        const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels			//
+        const int TRAINING_STEPS = 100;    // number of training steps
+        const float EPS1 = 100.0; // model match distance during training
+        const float EPS2 = 20.0;  // model match distance
+        const float C1 = 1.0;     // learning rate during training
+        const float C2 = 0.05f;   // learning rate
+      }
+
+      class BGModelSom : public BGModel
+      {
+      public:
+        BGModelSom(int width, int height);
+        ~BGModelSom();
+
+        void setBGModelParameter(int id, int value);
+
+      protected:
+        int m_widthSOM;
+        int m_heightSOM;
+        int m_offset;
+        int m_pad;
+        int m_K;
+        int m_TSteps;
+
+        double m_Wmax;
+
+        double m_epsilon1;
+        double m_epsilon2;
+        double m_alpha1;
+        double m_alpha2;
+
+        DBLRGB** m_ppSOM;					// SOM grid
+        double** m_ppW;						// Weights
+
+        void Init();
+        void Update();
+      };
+    }
   }
 }
diff --git a/src/algorithms/lb/Types.h b/src/algorithms/lb/Types.h
index b6f5ccdb2ddbeb953d4dd69ea7d92fb307fb18c3..1ec3a9855e77be7d1b41ba81fdad3c2a651ca09c 100644
--- a/src/algorithms/lb/Types.h
+++ b/src/algorithms/lb/Types.h
@@ -1,59 +1,66 @@
 #pragma once
 
 #include <opencv2/opencv.hpp>
+// opencv legacy includes
 #include <opencv2/core/core_c.h>
 
-namespace lb_library
+namespace bgslibrary
 {
-template<class T> class Image
-{
-private:
-  IplImage* imgp;
-
-public:
-  Image(IplImage* img=0) {imgp=img;}
-  ~Image(){imgp=0;}
-  
-  void operator=(IplImage* img) {imgp=img;}
-  
-  inline T* operator[](const int rowIndx)
+  namespace algorithms
   {
-    return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));
+    namespace lb
+    {
+      template<class T> class Image
+      {
+      private:
+        IplImage* imgp;
+
+      public:
+        Image(IplImage* img=0) {imgp=img;}
+        ~Image(){imgp=0;}
+        
+        void operator=(IplImage* img) {imgp=img;}
+        
+        inline T* operator[](const int rowIndx)
+        {
+          return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));
+        }
+      };
+
+      typedef struct{
+        unsigned char b,g,r;
+      } RgbPixel;
+
+      typedef struct{
+        unsigned char Blue,Green,Red;
+      } BYTERGB;
+
+      typedef struct{
+        unsigned int Blue,Green,Red;
+      } INTRGB;
+
+      typedef struct{
+        float b,g,r;
+      }RgbPixelFloat;
+
+      typedef struct{
+        double Blue,Green,Red;
+      } DBLRGB;
+
+      typedef Image<RgbPixel>       RgbImage;
+      typedef Image<RgbPixelFloat>  RgbImageFloat;
+      typedef Image<unsigned char>  BwImage;
+      typedef Image<float>          BwImageFloat;
+
+      /*
+        IplImage* img = cvCreateImage(cvSize(640,480), IPL_DEPTH_32F, 3);
+        RgbImageFloat imgA(img);
+        for(int i = 0; i < m_height; i++)
+          for(int j = 0; j < m_width; j++)
+            imgA[i][j].b = 111;
+            imgA[i][j].g = 111;
+            imgA[i][j].r = 111;
+        */
+    }
   }
-};
-
-typedef struct{
-  unsigned char b,g,r;
-} RgbPixel;
-
-typedef struct{
-  unsigned char Blue,Green,Red;
-} BYTERGB;
-
-typedef struct{
-  unsigned int Blue,Green,Red;
-} INTRGB;
-
-typedef struct{
-  float b,g,r;
-}RgbPixelFloat;
-
-typedef struct{
-  double Blue,Green,Red;
-} DBLRGB;
-
-typedef Image<RgbPixel>       RgbImage;
-typedef Image<RgbPixelFloat>  RgbImageFloat;
-typedef Image<unsigned char>  BwImage;
-typedef Image<float>          BwImageFloat;
-
-/*
-  IplImage* img = cvCreateImage(cvSize(640,480), IPL_DEPTH_32F, 3);
-  RgbImageFloat imgA(img);
-  for(int i = 0; i < m_height; i++)
-    for(int j = 0; j < m_width; j++)
-      imgA[i][j].b = 111;
-      imgA[i][j].g = 111;
-      imgA[i][j].r = 111;
-  */
 }
diff --git a/src/tools/ForegroundMaskAnalysis.cpp b/src/tools/ForegroundMaskAnalysis.cpp
index beff632e6ce97ae6ea1f8aba8474fa03ae7f0966..75231a773f9553e6f6d613ab5038ad79d1d73601 100644
--- a/src/tools/ForegroundMaskAnalysis.cpp
+++ b/src/tools/ForegroundMaskAnalysis.cpp
@@ -1,69 +1,68 @@
 #include "ForegroundMaskAnalysis.h"
 
-namespace bgslibrary
-{
-  ForegroundMaskAnalysis::ForegroundMaskAnalysis() :
-    firstTime(true), showOutput(true),
-    stopAt(0), img_ref_path("")
-  {
-    debug_construction(ForegroundMaskAnalysis);
-    initLoadSaveConfig(quote(ForegroundMaskAnalysis));
-  }
-
-  ForegroundMaskAnalysis::~ForegroundMaskAnalysis() {
-    debug_destruction(ForegroundMaskAnalysis);
-  }
+using namespace bgslibrary::tools;
 
-  void ForegroundMaskAnalysis::process(const long &frameNumber, const std::string &name, const cv::Mat &img_input)
-  {
-    if (img_input.empty())
-      return;
+ForegroundMaskAnalysis::ForegroundMaskAnalysis() :
+  firstTime(true), showOutput(true),
+  stopAt(0), img_ref_path("")
+{
+  debug_construction(ForegroundMaskAnalysis);
+  initLoadSaveConfig(quote(ForegroundMaskAnalysis));
+}
 
-    if (stopAt == frameNumber && img_ref_path.empty() == false)
-    {
-      cv::Mat img_ref = cv::imread(img_ref_path, 0);
+ForegroundMaskAnalysis::~ForegroundMaskAnalysis() {
+  debug_destruction(ForegroundMaskAnalysis);
+}
 
-      if (showOutput)
-        cv::imshow("ForegroundMaskAnalysis", img_ref);
+void ForegroundMaskAnalysis::process(const long &frameNumber, const std::string &name, const cv::Mat &img_input)
+{
+  if (img_input.empty())
+    return;
 
-      int rn = cv::countNonZero(img_ref);
-      cv::Mat i;
-      cv::Mat u;
+  if (stopAt == frameNumber && img_ref_path.empty() == false)
+  {
+    cv::Mat img_ref = cv::imread(img_ref_path, 0);
 
-      if (rn > 0) {
-        i = img_input & img_ref;
-        u = img_input | img_ref;
-      }
-      else {
-        i = (~img_input) & (~img_ref);
-        u = (~img_input) | (~img_ref);
-      }
+    if (showOutput)
+      cv::imshow("ForegroundMaskAnalysis", img_ref);
 
-      int in = cv::countNonZero(i);
-      int un = cv::countNonZero(u);
+    int rn = cv::countNonZero(img_ref);
+    cv::Mat i;
+    cv::Mat u;
 
-      double s = (((double)in) / ((double)un));
+    if (rn > 0) {
+      i = img_input & img_ref;
+      u = img_input | img_ref;
+    }
+    else {
+      i = (~img_input) & (~img_ref);
+      u = (~img_input) | (~img_ref);
+    }
 
-      if (showOutput) {
-        cv::imshow("A^B", i);
-        cv::imshow("AvB", u);
-      }
+    int in = cv::countNonZero(i);
+    int un = cv::countNonZero(u);
 
-      std::cout << name << " - Similarity Measure: " << s << " press ENTER to continue" << std::endl;
+    double s = (((double)in) / ((double)un));
 
-      cv::waitKey(0);
+    if (showOutput) {
+      cv::imshow("A^B", i);
+      cv::imshow("AvB", u);
     }
 
-    firstTime = false;
-  }
+    std::cout << name << " - Similarity Measure: " << s << " press ENTER to continue" << std::endl;
 
-  void ForegroundMaskAnalysis::save_config(cv::FileStorage &fs) {
-    fs << "stopAt" << stopAt;
-    fs << "img_ref_path" << img_ref_path;
+    cv::waitKey(0);
   }
 
-  void ForegroundMaskAnalysis::load_config(cv::FileStorage &fs) {
-    fs["stopAt"] >> stopAt;
-    fs["img_ref_path"] >> img_ref_path;
-  }
+  firstTime = false;
+}
+
+void ForegroundMaskAnalysis::save_config(cv::FileStorage &fs) {
+  fs << "stopAt" << stopAt;
+  fs << "img_ref_path" << img_ref_path;
+}
+
+void ForegroundMaskAnalysis::load_config(cv::FileStorage &fs) {
+  fs["stopAt"] >> stopAt;
+  fs["img_ref_path"] >> img_ref_path;
 }
diff --git a/src/tools/ForegroundMaskAnalysis.h b/src/tools/ForegroundMaskAnalysis.h
index 89f46cc3298e8c5b9aa507d5103044c7591c58f5..60d6878c6a4eb351118d85c3ed4e1b1e69331631 100644
--- a/src/tools/ForegroundMaskAnalysis.h
+++ b/src/tools/ForegroundMaskAnalysis.h
@@ -7,6 +7,7 @@
 #include <opencv2/highgui/highgui.hpp>
 #include <opencv2/imgproc/imgproc.hpp>
 #include <opencv2/features2d/features2d.hpp>
+// opencv legacy includes
 #include <opencv2/imgproc/types_c.h>
 #include <opencv2/imgproc/imgproc_c.h>
 #include <opencv2/highgui/highgui_c.h>
@@ -15,23 +16,26 @@
 
 namespace bgslibrary
 {
-  class ForegroundMaskAnalysis: public ILoadSaveConfig
+  namespace tools
   {
-  private:
-    bool firstTime;
-    bool showOutput;
+    class ForegroundMaskAnalysis: public ILoadSaveConfig
+    {
+    private:
+      bool firstTime;
+      bool showOutput;
 
-  public:
-    ForegroundMaskAnalysis();
-    ~ForegroundMaskAnalysis();
+    public:
+      ForegroundMaskAnalysis();
+      ~ForegroundMaskAnalysis();
 
-    int stopAt;
-    std::string img_ref_path;
+      int stopAt;
+      std::string img_ref_path;
 
-    void process(const long &frameNumber, const std::string &name, const cv::Mat &img_input);
+      void process(const long &frameNumber, const std::string &name, const cv::Mat &img_input);
 
-  private:
-    void save_config(cv::FileStorage &fs);
-    void load_config(cv::FileStorage &fs);
-  };
+    private:
+      void save_config(cv::FileStorage &fs);
+      void load_config(cv::FileStorage &fs);
+    };
+  }
 }
diff --git a/src/algorithms/T2F/FuzzyUtils.cpp b/src/tools/FuzzyUtils.cpp
similarity index 99%
rename from src/algorithms/T2F/FuzzyUtils.cpp
rename to src/tools/FuzzyUtils.cpp
index 8728f861d78a27f187caa9f3d5225ff579b1e747..7fc37e4f587d39bc6c687f87762c1a10d7fa053e 100644
--- a/src/algorithms/T2F/FuzzyUtils.cpp
+++ b/src/tools/FuzzyUtils.cpp
@@ -1,8 +1,10 @@
 #include "FuzzyUtils.h"
 
-FuzzyUtils::FuzzyUtils(void) {}
+using namespace bgslibrary::tools;
 
-FuzzyUtils::~FuzzyUtils(void) {}
+FuzzyUtils::FuzzyUtils() {}
+
+FuzzyUtils::~FuzzyUtils() {}
 
 void FuzzyUtils::LBP(IplImage* InputImage, IplImage* LBPimage)
 {
diff --git a/src/tools/FuzzyUtils.h b/src/tools/FuzzyUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..4b5b993afe1a04823d67f294a91fcba033b47fd9
--- /dev/null
+++ b/src/tools/FuzzyUtils.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "PixelUtils.h"
+
+namespace bgslibrary
+{
+  namespace tools
+  {
+    class FuzzyUtils
+    {
+    public:
+      FuzzyUtils(void);
+      ~FuzzyUtils(void);
+
+      void LBP(IplImage* InputImage, IplImage* LBP);
+      void getBinValue(float* neighberGrayPixel, float* BinaryValue, int m, int n);
+
+      void SimilarityDegreesImage(IplImage* CurrentImage, IplImage* BGImage, IplImage* DeltaImage, int n, int color_space);
+      void RatioPixels(float* CurrentPixel, float* BGPixel, float* DeltaPixel, int n);
+
+      void getFuzzyIntegralSugeno(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage);
+      void getFuzzyIntegralChoquet(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage);
+      void FuzzyMeasureG(float g1, float g2, float g3, float *G);
+      void Trier(float* g, int n, int* index);
+      float min(float *a, float *b);
+      float max(float *g, int n);
+      void gDeDeux(float* a, float* b, float* lambda);
+      void getLambda(float* g);
+
+      void AdaptativeSelectiveBackgroundModelUpdate(IplImage* CurrentImage, IplImage* BGImage, IplImage* OutputImage, IplImage* Integral, float seuil, float alpha);
+    };
+  }
+}
diff --git a/src/tools/PerformanceUtils.cpp b/src/tools/PerformanceUtils.cpp
index 0e70fd63d670122fe576879126bf8d8064d0513d..c81702a7e7ed343dd3ee526913b451c812838446 100644
--- a/src/tools/PerformanceUtils.cpp
+++ b/src/tools/PerformanceUtils.cpp
@@ -1,6 +1,6 @@
 #include "PerformanceUtils.h"
-//#include <opencv2/legacy/compat.hpp>
-//#include <opencv2/highgui/highgui_c.h>
+
+using namespace bgslibrary::tools;
 
 PerformanceUtils::PerformanceUtils() {
   //debug_construction(PerformanceUtils);
diff --git a/src/tools/PerformanceUtils.h b/src/tools/PerformanceUtils.h
index ce4549d5b59e00a4490a285d4ff2571f78efca89..e0d69c5ed2fcfc099f2c182e4e046bcc752208ce 100644
--- a/src/tools/PerformanceUtils.h
+++ b/src/tools/PerformanceUtils.h
@@ -6,20 +6,26 @@
 
 #include "PixelUtils.h"
 
-class PerformanceUtils
+namespace bgslibrary
 {
-public:
-  PerformanceUtils();
-  ~PerformanceUtils();
+  namespace tools
+  {
+    class PerformanceUtils
+    {
+    public:
+      PerformanceUtils();
+      ~PerformanceUtils();
 
-  float NrPixels(IplImage *image);
-  float NrAllDetectedPixNotNULL(IplImage *image, IplImage *ground_truth);
-  float NrTruePositives(IplImage *image, IplImage *ground_truth, bool debug = false);
-  float NrTrueNegatives(IplImage *image, IplImage *ground_truth, bool debug = false);
-  float NrFalsePositives(IplImage *image, IplImage *ground_truth, bool debug = false);
-  float NrFalseNegatives(IplImage *image, IplImage *ground_truth, bool debug = false);
-  float SimilarityMeasure(IplImage *image, IplImage *ground_truth, bool debug = false);
+      float NrPixels(IplImage *image);
+      float NrAllDetectedPixNotNULL(IplImage *image, IplImage *ground_truth);
+      float NrTruePositives(IplImage *image, IplImage *ground_truth, bool debug = false);
+      float NrTrueNegatives(IplImage *image, IplImage *ground_truth, bool debug = false);
+      float NrFalsePositives(IplImage *image, IplImage *ground_truth, bool debug = false);
+      float NrFalseNegatives(IplImage *image, IplImage *ground_truth, bool debug = false);
+      float SimilarityMeasure(IplImage *image, IplImage *ground_truth, bool debug = false);
 
-  void ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults = false, std::string filename = "");
-  void PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults = false, std::string filename = "", bool debug = false);
-};
+      void ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults = false, std::string filename = "");
+      void PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults = false, std::string filename = "", bool debug = false);
+    };
+  }
+}
diff --git a/src/tools/PixelUtils.cpp b/src/tools/PixelUtils.cpp
index 3770e7eaf925d6c2fcfe86bf73bd21270c224245..2ca5a6c500a661b6e0553732ed21ee09a8c3d877 100644
--- a/src/tools/PixelUtils.cpp
+++ b/src/tools/PixelUtils.cpp
@@ -1,5 +1,7 @@
 #include "PixelUtils.h"
 
+using namespace bgslibrary::tools;
+
 PixelUtils::PixelUtils() {
   //debug_construction(PixelUtils);
 }
diff --git a/src/tools/PixelUtils.h b/src/tools/PixelUtils.h
index 51aade49b62f3918b77d69faa08b1ac2dcf46cb8..fd0842015b4da05292fe243749f49164466e4ee0 100644
--- a/src/tools/PixelUtils.h
+++ b/src/tools/PixelUtils.h
@@ -2,35 +2,44 @@
 
 #include <stdio.h>
 #include <opencv2/opencv.hpp>
+// opencv legacy includes
+//#include <opencv2/legacy/compat.hpp>
+//#include <opencv2/highgui/highgui_c.h>
 #include <opencv2/imgproc/types_c.h>
 #include <opencv2/imgproc/imgproc_c.h>
 #include <opencv2/highgui/highgui_c.h>
 
-class PixelUtils
+namespace bgslibrary
 {
-public:
-  PixelUtils();
-  ~PixelUtils();
-
-  void ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space);
-  void cvttoOTHA(IplImage* RGBImage, IplImage* OthaImage);
-
-  void PostProcessing(IplImage *InputImage);
-
-  void GetPixel(IplImage *image, int m, int n, unsigned char *pixelcourant);
-  void GetGrayPixel(IplImage *image, int m, int n, unsigned char *pixelcourant);
-
-  void PutPixel(IplImage *image, int p, int q, unsigned char *pixelcourant);
-  void PutGrayPixel(IplImage *image, int p, int q, unsigned char pixelcourant);
-
-  void GetPixel(IplImage *image, int m, int n, float *pixelcourant);
-  void GetGrayPixel(IplImage *image, int m, int n, float *pixelcourant);
-
-  void PutPixel(IplImage *image, int p, int q, float *pixelcourant);
-  void PutGrayPixel(IplImage *image, int p, int q, float pixelcourant);
-
-  void getNeighberhoodGrayPixel(IplImage* InputImage, int x, int y, float* neighberPixel);
-  void ForegroundMaximum(IplImage *Foreground, float *Maximum, int n);
-  void ForegroundMinimum(IplImage *Foreground, float *Minimum, int n);
-  void ComplementaryAlphaImageCreation(IplImage *AlphaImage, IplImage *ComplementaryAlphaImage, int n);
-};
+  namespace tools
+  {
+    class PixelUtils
+    {
+    public:
+      PixelUtils();
+      ~PixelUtils();
+
+      void ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space);
+      void cvttoOTHA(IplImage* RGBImage, IplImage* OthaImage);
+
+      void PostProcessing(IplImage *InputImage);
+
+      void GetPixel(IplImage *image, int m, int n, unsigned char *pixelcourant);
+      void GetGrayPixel(IplImage *image, int m, int n, unsigned char *pixelcourant);
+
+      void PutPixel(IplImage *image, int p, int q, unsigned char *pixelcourant);
+      void PutGrayPixel(IplImage *image, int p, int q, unsigned char pixelcourant);
+
+      void GetPixel(IplImage *image, int m, int n, float *pixelcourant);
+      void GetGrayPixel(IplImage *image, int m, int n, float *pixelcourant);
+
+      void PutPixel(IplImage *image, int p, int q, float *pixelcourant);
+      void PutGrayPixel(IplImage *image, int p, int q, float pixelcourant);
+
+      void getNeighberhoodGrayPixel(IplImage* InputImage, int x, int y, float* neighberPixel);
+      void ForegroundMaximum(IplImage *Foreground, float *Maximum, int n);
+      void ForegroundMinimum(IplImage *Foreground, float *Minimum, int n);
+      void ComplementaryAlphaImageCreation(IplImage *AlphaImage, IplImage *ComplementaryAlphaImage, int n);
+    };
+  }
+}