diff --git a/Demo.cpp b/Demo.cpp
index fec54d85fe804e6bece7ec0bd1e6d5c2b7fe7626..f1022a50c5b140a0a94bfa3e07cc4cf8ff0c0186 100644
--- a/Demo.cpp
+++ b/Demo.cpp
@@ -84,6 +84,7 @@ int main(int argc, char **argv)
   //bgs = new PAWCS;
   //bgs = new TwoPoints;
   //bgs = new ViBe;
+  //bgs = new CodeBook;
 
   int key = 0;
   cv::Mat img_input;
diff --git a/Demo.py b/Demo.py
index 71bc35232e73fe4ff54b70d40d3690b274c31af7..b1f6c02e954144f25b9b08dd6725c42afe665766 100644
--- a/Demo.py
+++ b/Demo.py
@@ -71,7 +71,7 @@ while True:
 
 	else:
 		capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, pos_frame-1)
-		print "frame is not ready"
+		print "Frame is not ready"
 		cv2.waitKey(1000)
 		# break
 	
diff --git a/Demo2.cpp b/Demo2.cpp
index 22c6ffc36d5100967cfd2873b82f0bdb13b61268..75c906beedcd2be7de7a66377bb501234ee8d960 100644
--- a/Demo2.cpp
+++ b/Demo2.cpp
@@ -68,6 +68,7 @@ int main(int argc, char **argv)
   //bgs = new PAWCS;
   //bgs = new TwoPoints;
   //bgs = new ViBe;
+  //bgs = new CodeBook;
 
   int frameNumber = 1;
   int key = 0;
diff --git a/FrameProcessor.cpp b/FrameProcessor.cpp
index 50881219f6d4bf5e703840f3912204b006777686..3180589a6cab0d8c29399530a645f6c8d0d30f65 100644
--- a/FrameProcessor.cpp
+++ b/FrameProcessor.cpp
@@ -65,6 +65,11 @@ namespace bgslibrary
       gmg = new GMG;
 #endif
 
+#if CV_MAJOR_VERSION == 3
+    if (enableKNN)
+      knn = new KNN;
+#endif
+
     if (enableDPAdaptiveMedian)
       dpAdaptiveMedian = new DPAdaptiveMedian;
 
@@ -125,10 +130,8 @@ namespace bgslibrary
     if (enableLbpMrf)
       lbpMrf = new LBP_MRF;
 
-#if CV_MAJOR_VERSION == 2
     if (enableMultiLayer)
       multiLayer = new MultiLayer;
-#endif
 
     if (enablePBAS)
       pixelBasedAdaptiveSegmenter = new PixelBasedAdaptiveSegmenter;
@@ -154,6 +157,18 @@ namespace bgslibrary
     if (enableLOBSTER)
       lobster = new LOBSTER;
 
+    if (enablePAWCS)
+      pawcs = new PAWCS;
+
+    if (enableTwoPoints)
+      twoPoints = new TwoPoints;
+
+    if (enableViBe)
+      vibe = new ViBe;
+
+    if (enableCodeBook)
+      codeBook = new CodeBook;
+
     if (enableForegroundMaskAnalysis)
       foregroundMaskAnalysis = new ForegroundMaskAnalysis;
   }
@@ -205,6 +220,11 @@ namespace bgslibrary
       process("GMG", gmg, img_preProcessor, img_gmg);
 #endif
 
+#if CV_MAJOR_VERSION == 3
+    if (enableKNN)
+      process("KNN", knn, img_preProcessor, img_knn);
+#endif
+
     if (enableDPAdaptiveMedian)
       process("DPAdaptiveMedian", dpAdaptiveMedian, img_preProcessor, img_dpAdaptiveMedian);
 
@@ -265,14 +285,12 @@ namespace bgslibrary
     if (enableLbpMrf)
       process("LbpMrf", lbpMrf, img_preProcessor, img_lbpMrf);
 
-#if CV_MAJOR_VERSION == 2
     if (enableMultiLayer)
     {
       multiLayer->setStatus(MultiLayer::MLBGS_LEARN);
       //multiLayer->setStatus(MultiLayer::MLBGS_DETECT);
       process("MultiLayer", multiLayer, img_preProcessor, img_multiLayer);
     }
-#endif
 
     if (enablePBAS)
       process("PBAS", pixelBasedAdaptiveSegmenter, img_preProcessor, img_pixelBasedAdaptiveSegmenter);
@@ -298,6 +316,18 @@ namespace bgslibrary
     if (enableLOBSTER)
       process("LOBSTER", lobster, img_preProcessor, img_lobster);
 
+    if (enablePAWCS)
+      process("PAWCS", pawcs, img_preProcessor, img_pawcs);
+
+    if (enableTwoPoints)
+      process("TwoPoints", twoPoints, img_preProcessor, img_twoPoints);
+
+    if (enableViBe)
+      process("ViBe", vibe, img_preProcessor, img_vibe);
+
+    if (enableCodeBook)
+      process("CodeBook", codeBook, img_preProcessor, img_codeBook);
+
     if (enableForegroundMaskAnalysis)
     {
       foregroundMaskAnalysis->stopAt = frameToStop;
@@ -314,6 +344,9 @@ namespace bgslibrary
       foregroundMaskAnalysis->process(frameNumber, "AdaptiveBackgroundLearning", img_adaptiveBackgroundLearning);
 #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
       foregroundMaskAnalysis->process(frameNumber, "GMG", img_gmg);
+#endif
+#if CV_MAJOR_VERSION == 3
+      foregroundMaskAnalysis->process(frameNumber, "KNN", img_knn);
 #endif
       foregroundMaskAnalysis->process(frameNumber, "DPAdaptiveMedian", img_dpAdaptiveMedian);
       foregroundMaskAnalysis->process(frameNumber, "DPGrimsonGMM", img_dpGrimsonGMM);
@@ -335,9 +368,7 @@ namespace bgslibrary
       foregroundMaskAnalysis->process(frameNumber, "LBAdaptiveSOM", img_lbAdaptiveSOM);
       foregroundMaskAnalysis->process(frameNumber, "LBFuzzyAdaptiveSOM", img_lbFuzzyAdaptiveSOM);
       foregroundMaskAnalysis->process(frameNumber, "LbpMrf", img_lbpMrf);
-#if CV_MAJOR_VERSION == 2
       foregroundMaskAnalysis->process(frameNumber, "MultiLayer", img_multiLayer);
-#endif
       foregroundMaskAnalysis->process(frameNumber, "PBAS", img_pixelBasedAdaptiveSegmenter);
       foregroundMaskAnalysis->process(frameNumber, "VuMeter", img_vumeter);
       foregroundMaskAnalysis->process(frameNumber, "KDE", img_kde);
@@ -346,6 +377,10 @@ namespace bgslibrary
       foregroundMaskAnalysis->process(frameNumber, "SigmaDelta", img_sigmaDelta);
       foregroundMaskAnalysis->process(frameNumber, "SuBSENSE", img_subSENSE);
       foregroundMaskAnalysis->process(frameNumber, "LOBSTER", img_lobster);
+      foregroundMaskAnalysis->process(frameNumber, "PAWCS", img_pawcs);
+      foregroundMaskAnalysis->process(frameNumber, "TwoPoints", img_twoPoints);
+      foregroundMaskAnalysis->process(frameNumber, "ViBe", img_vibe);
+      foregroundMaskAnalysis->process(frameNumber, "CodeBook", img_codeBook);
     }
 
     firstTime = false;
@@ -374,6 +409,18 @@ namespace bgslibrary
     if (enableForegroundMaskAnalysis)
       delete foregroundMaskAnalysis;
 
+    if (enableCodeBook)
+      delete codeBook;
+
+    if (enableViBe)
+      delete vibe;
+
+    if (enableTwoPoints)
+      delete twoPoints;
+
+    if (enablePAWCS)
+      delete pawcs;
+
     if (enableLOBSTER)
       delete lobster;
 
@@ -398,10 +445,8 @@ namespace bgslibrary
     if (enablePBAS)
       delete pixelBasedAdaptiveSegmenter;
 
-#if CV_MAJOR_VERSION == 2
     if (enableMultiLayer)
       delete multiLayer;
-#endif
 
     if (enableLBFuzzyAdaptiveSOM)
       delete lbFuzzyAdaptiveSOM;
@@ -418,10 +463,8 @@ namespace bgslibrary
     if (enableLBSimpleGaussian)
       delete lbSimpleGaussian;
 
-#if !defined(_WIN32)
     if (enableLbpMrf)
       delete lbpMrf;
-#endif
 
     if (enableFuzzyChoquetIntegral)
       delete fuzzyChoquetIntegral;
@@ -470,6 +513,11 @@ namespace bgslibrary
       delete gmg;
 #endif
 
+#if CV_MAJOR_VERSION == 3
+    if (enableKNN)
+      delete knn;
+#endif
+
     if (enableAdaptiveBackgroundLearning)
       delete adaptiveBackgroundLearning;
 
@@ -531,6 +579,9 @@ namespace bgslibrary
 #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
     cvWriteInt(fs, "enableGMG", enableGMG);
 #endif
+#if CV_MAJOR_VERSION == 3
+    cvWriteInt(fs, "enableKNN", enableKNN);
+#endif
 
     cvWriteInt(fs, "enableDPAdaptiveMedian", enableDPAdaptiveMedian);
     cvWriteInt(fs, "enableDPGrimsonGMM", enableDPGrimsonGMM);
@@ -555,10 +606,7 @@ namespace bgslibrary
     cvWriteInt(fs, "enableLBFuzzyAdaptiveSOM", enableLBFuzzyAdaptiveSOM);
 
     cvWriteInt(fs, "enableLbpMrf", enableLbpMrf);
-
-#if CV_MAJOR_VERSION == 2
     cvWriteInt(fs, "enableMultiLayer", enableMultiLayer);
-#endif
     cvWriteInt(fs, "enablePBAS", enablePBAS);
     cvWriteInt(fs, "enableVuMeter", enableVuMeter);
     cvWriteInt(fs, "enableKDE", enableKDE);
@@ -567,6 +615,10 @@ namespace bgslibrary
     cvWriteInt(fs, "enableSigmaDelta", enableSigmaDelta);
     cvWriteInt(fs, "enableSuBSENSE", enableSuBSENSE);
     cvWriteInt(fs, "enableLOBSTER", enableLOBSTER);
+    cvWriteInt(fs, "enablePAWCS", enablePAWCS);
+    cvWriteInt(fs, "enableTwoPoints", enableTwoPoints);
+    cvWriteInt(fs, "enableViBe", enableViBe);
+    cvWriteInt(fs, "enableCodeBook", enableCodeBook);
 
     cvReleaseFileStorage(&fs);
   }
@@ -593,6 +645,9 @@ namespace bgslibrary
 #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
     enableGMG = cvReadIntByName(fs, 0, "enableGMG", false);
 #endif
+#if CV_MAJOR_VERSION == 3
+    enableKNN = cvReadIntByName(fs, 0, "enableKNN", false);
+#endif
 
     enableDPAdaptiveMedian = cvReadIntByName(fs, 0, "enableDPAdaptiveMedian", false);
     enableDPGrimsonGMM = cvReadIntByName(fs, 0, "enableDPGrimsonGMM", false);
@@ -617,10 +672,7 @@ namespace bgslibrary
     enableLBFuzzyAdaptiveSOM = cvReadIntByName(fs, 0, "enableLBFuzzyAdaptiveSOM", false);
 
     enableLbpMrf = cvReadIntByName(fs, 0, "enableLbpMrf", false);
-
-#if CV_MAJOR_VERSION == 2
     enableMultiLayer = cvReadIntByName(fs, 0, "enableMultiLayer", false);
-#endif
     enablePBAS = cvReadIntByName(fs, 0, "enablePBAS", false);
     enableVuMeter = cvReadIntByName(fs, 0, "enableVuMeter", false);
     enableKDE = cvReadIntByName(fs, 0, "enableKDE", false);
@@ -629,6 +681,10 @@ namespace bgslibrary
     enableSigmaDelta = cvReadIntByName(fs, 0, "enableSigmaDelta", false);
     enableSuBSENSE = cvReadIntByName(fs, 0, "enableSuBSENSE", false);
     enableLOBSTER = cvReadIntByName(fs, 0, "enableLOBSTER", false);
+    enablePAWCS = cvReadIntByName(fs, 0, "enablePAWCS", false);
+    enableTwoPoints = cvReadIntByName(fs, 0, "enableTwoPoints", false);
+    enableViBe = cvReadIntByName(fs, 0, "enableViBe", false);
+    enableCodeBook = cvReadIntByName(fs, 0, "enableCodeBook", false);
 
     cvReleaseFileStorage(&fs);
   }
diff --git a/FrameProcessor.h b/FrameProcessor.h
index 228fa4c0e8a8b57f0d1a345f0d35700c25a60715..025984a56c4e422d366edfd9cf76ed42bcbf8f39 100644
--- a/FrameProcessor.h
+++ b/FrameProcessor.h
@@ -75,6 +75,12 @@ namespace bgslibrary
     bool enableGMG;
 #endif
 
+#if CV_MAJOR_VERSION == 3
+    cv::Mat img_knn;
+    KNN* knn;
+    bool enableKNN;
+#endif
+
     cv::Mat img_dpAdaptiveMedian;
     DPAdaptiveMedian* dpAdaptiveMedian;
     bool enableDPAdaptiveMedian;
@@ -155,11 +161,9 @@ namespace bgslibrary
     LBP_MRF* lbpMrf;
     bool enableLbpMrf;
 
-#if CV_MAJOR_VERSION == 2
     cv::Mat img_multiLayer;
     MultiLayer* multiLayer;
     bool enableMultiLayer;
-#endif
 
     cv::Mat img_pixelBasedAdaptiveSegmenter;
     PixelBasedAdaptiveSegmenter* pixelBasedAdaptiveSegmenter;
@@ -193,6 +197,22 @@ namespace bgslibrary
     LOBSTER* lobster;
     bool enableLOBSTER;
 
+    cv::Mat img_pawcs;
+    PAWCS* pawcs;
+    bool enablePAWCS;
+
+    cv::Mat img_twoPoints;
+    TwoPoints* twoPoints;
+    bool enableTwoPoints;
+
+    cv::Mat img_vibe;
+    ViBe* vibe;
+    bool enableViBe;
+
+    cv::Mat img_codeBook;
+    CodeBook* codeBook;
+    bool enableCodeBook;
+
     ForegroundMaskAnalysis* foregroundMaskAnalysis;
     bool enableForegroundMaskAnalysis;
 
diff --git a/VideoCapture.cpp b/VideoCapture.cpp
index b302a3f5e2921bef2c1424819f244efd5b76ac18..c7e12ea13739f5c6872af4477cf252d996be3898 100644
--- a/VideoCapture.cpp
+++ b/VideoCapture.cpp
@@ -82,6 +82,7 @@ namespace bgslibrary
     enableFlip(false), cameraIndex(0)
   {
     std::cout << "VideoCapture()" << std::endl;
+    setup("./config/VideoCapture.xml");
   }
 
   VideoCapture::~VideoCapture()
@@ -94,11 +95,10 @@ namespace bgslibrary
     frameProcessor = frameProcessorPtr;
   }
 
-  void VideoCapture::setCamera(int index)
+  void VideoCapture::setCamera(int _index)
   {
     useCamera = true;
-    cameraIndex = index;
-
+    cameraIndex = _index;
     useVideo = false;
   }
 
@@ -111,11 +111,10 @@ namespace bgslibrary
       std::cerr << "Cannot initialize webcam!\n" << std::endl;
   }
 
-  void VideoCapture::setVideo(std::string filename)
+  void VideoCapture::setVideo(std::string _filename)
   {
     useVideo = true;
-    videoFileName = filename;
-
+    videoFileName = _filename;
     useCamera = false;
   }
 
@@ -132,43 +131,49 @@ namespace bgslibrary
 
   void VideoCapture::start()
   {
-    loadConfig();
-
     if (useCamera) setUpCamera();
     if (useVideo)  setUpVideo();
     //if (!capture)  std::cerr << "Capture error..." << std::endl;
 
+    using namespace std::chrono_literals;
+    do
+    {
+      capture >> frame;
+      if (frame.empty())
+      {
+        std::cout << "Frame is not ready" << std::endl;
+        std::this_thread::sleep_for(1s);
+      }
+      else
+        break;
+    } while (1);
+
     int input_fps = capture.get(CV_CAP_PROP_FPS);
     std::cout << "input->fps:" << input_fps << std::endl;
+    std::cout << "input->width:" << frame.size().width << std::endl;
+    std::cout << "input->height:" << frame.size().height << std::endl;
 
-    /*
-    IplImage* frame1 = cvQueryFrame(capture);
-    frame = cvCreateImage(cvSize(
-      (int)((frame1->width*input_resize_percent) / 100),
-      (int)((frame1->height*input_resize_percent) / 100)), frame1->depth, frame1->nChannels);
-    //cvCreateImage(cvSize(frame1->width/input_resize_factor, frame1->height/input_resize_factor), frame1->depth, frame1->nChannels);
-    std::cout << "input->resize_percent:" << input_resize_percent << std::endl;
-    std::cout << "input->width:" << frame->width << std::endl;
-    std::cout << "input->height:" << frame->height << std::endl;
-    */
-
-    double loopDelay = 33.333;
     if (input_fps > 0)
       loopDelay = (1. / input_fps)*1000.;
     std::cout << "loopDelay:" << loopDelay << std::endl;
 
     std::cout << "Press 'ESC' to stop..." << std::endl;
-    bool firstTime = true;
     do
     {
       frameNumber++;
 
-      cv::Mat frame;
       capture >> frame;
       if (frame.empty()) break;
 
-      //cvResize(frame1, frame);
+      cv::resize(frame, frame, cv::Size(), input_resize_percent/100., input_resize_percent / 100.);
 
+      if (firstTime && input_resize_percent != 100)
+      {
+        std::cout << "Resized to:" << std::endl;
+        std::cout << "input->width:" << frame.size().width << std::endl;
+        std::cout << "input->height:" << frame.size().height << std::endl;
+      }
+      
       //if (enableFlip)
       //  cvFlip(frame, frame, 0);
 
@@ -178,7 +183,6 @@ namespace bgslibrary
 
         do
         {
-          //cv::Mat img_input = cv::cvarrToMat(frame);
           cv::Mat img_input;
           frame.copyTo(img_input);
 
@@ -220,16 +224,12 @@ namespace bgslibrary
         frame = frame(roi);
       }
 
-      //cv::Mat img_input = cv::cvarrToMat(frame);
       cv::Mat img_input;
       frame.copyTo(img_input);
 
       if (showOutput)
         cv::imshow("Input", img_input);
 
-      if (firstTime)
-        saveConfig();
-
       start_time = cv::getTickCount();
       frameProcessor->process(img_input);
       int64 delta_time = cv::getTickCount() - start_time;
@@ -259,7 +259,7 @@ namespace bgslibrary
 
   void VideoCapture::saveConfig()
   {
-    CvFileStorage* fs = cvOpenFileStorage("./config/VideoCapture.xml", 0, CV_STORAGE_WRITE);
+    CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), 0, CV_STORAGE_WRITE);
 
     cvWriteInt(fs, "stopAt", stopAt);
     cvWriteInt(fs, "input_resize_percent", input_resize_percent);
@@ -277,18 +277,18 @@ namespace bgslibrary
 
   void VideoCapture::loadConfig()
   {
-    CvFileStorage* fs = cvOpenFileStorage("./config/VideoCapture.xml", 0, CV_STORAGE_READ);
-
-    stopAt = cvReadIntByName(fs, 0, "stopAt", 0);
-    input_resize_percent = cvReadIntByName(fs, 0, "input_resize_percent", 100);
-    enableFlip = cvReadIntByName(fs, 0, "enableFlip", false);
-    VC_ROI::use_roi = cvReadIntByName(fs, 0, "use_roi", true);
-    VC_ROI::roi_defined = cvReadIntByName(fs, 0, "roi_defined", false);
-    VC_ROI::roi_x0 = cvReadIntByName(fs, 0, "roi_x0", 0);
-    VC_ROI::roi_y0 = cvReadIntByName(fs, 0, "roi_y0", 0);
-    VC_ROI::roi_x1 = cvReadIntByName(fs, 0, "roi_x1", 0);
-    VC_ROI::roi_y1 = cvReadIntByName(fs, 0, "roi_y1", 0);
-    showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+    CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ);
+
+    stopAt = cvReadIntByName(fs, nullptr, "stopAt", 0);
+    input_resize_percent = cvReadIntByName(fs, nullptr, "input_resize_percent", 100);
+    enableFlip = cvReadIntByName(fs, nullptr, "enableFlip", false);
+    VC_ROI::use_roi = cvReadIntByName(fs, nullptr, "use_roi", true);
+    VC_ROI::roi_defined = cvReadIntByName(fs, nullptr, "roi_defined", false);
+    VC_ROI::roi_x0 = cvReadIntByName(fs, nullptr, "roi_x0", 0);
+    VC_ROI::roi_y0 = cvReadIntByName(fs, nullptr, "roi_y0", 0);
+    VC_ROI::roi_x1 = cvReadIntByName(fs, nullptr, "roi_x1", 0);
+    VC_ROI::roi_y1 = cvReadIntByName(fs, nullptr, "roi_y1", 0);
+    showOutput = cvReadIntByName(fs, nullptr, "showOutput", true);
 
     cvReleaseFileStorage(&fs);
   }
diff --git a/VideoCapture.h b/VideoCapture.h
index 0e88c87023b8fedbb4f089e0bf19dfc0222c3d28..b7876824cde2b2b5f27641f1cff785d620d61091 100644
--- a/VideoCapture.h
+++ b/VideoCapture.h
@@ -17,6 +17,8 @@ along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
 #pragma once
 
 #include <iostream>
+#include <chrono>
+#include <thread>
 #include <opencv2/opencv.hpp>
 #include <opencv2/imgproc/imgproc_c.h>
 #include <opencv2/imgproc/types_c.h>
@@ -31,13 +33,13 @@ namespace bgslibrary
   private:
     IFrameProcessor* frameProcessor;
     cv::VideoCapture capture;
-    IplImage* frame;
+    cv::Mat frame;
     int key;
     int64 start_time;
     int64 delta_time;
     double freq;
     double fps;
-    long frameNumber;
+    long long frameNumber;
     long stopAt;
     bool useCamera;
     int cameraIndex;
@@ -46,6 +48,17 @@ namespace bgslibrary
     int input_resize_percent;
     bool showOutput;
     bool enableFlip;
+    double loopDelay = 33.333;
+    bool firstTime = true;
+    std::string config_xml;
+    void setup(const std::string _config_xml) {
+      config_xml = _config_xml;
+      if (!config_xml.empty()) {
+        if (!std::ifstream(config_xml))
+          saveConfig();
+        loadConfig();
+      }
+    }
 
   public:
     VideoCapture();
diff --git a/config/FrameProcessor.xml b/config/FrameProcessor.xml
index 3cf398cc4f421bd0c42bf3a19631c425af5add42..91c3466779fc01c8d430647f83078928d477a6e1 100644
--- a/config/FrameProcessor.xml
+++ b/config/FrameProcessor.xml
@@ -7,10 +7,9 @@
 <enableStaticFrameDifference>0</enableStaticFrameDifference>
 <enableWeightedMovingMean>0</enableWeightedMovingMean>
 <enableWeightedMovingVariance>0</enableWeightedMovingVariance>
-<enableMixtureOfGaussianV1>0</enableMixtureOfGaussianV1>
 <enableMixtureOfGaussianV2>0</enableMixtureOfGaussianV2>
 <enableAdaptiveBackgroundLearning>0</enableAdaptiveBackgroundLearning>
-<enableGMG>0</enableGMG>
+<enableKNN>0</enableKNN>
 <enableDPAdaptiveMedian>0</enableDPAdaptiveMedian>
 <enableDPGrimsonGMM>0</enableDPGrimsonGMM>
 <enableDPZivkovicAGMM>0</enableDPZivkovicAGMM>
@@ -40,4 +39,8 @@
 <enableSigmaDelta>0</enableSigmaDelta>
 <enableSuBSENSE>0</enableSuBSENSE>
 <enableLOBSTER>0</enableLOBSTER>
+<enablePAWCS>0</enablePAWCS>
+<enableTwoPoints>0</enableTwoPoints>
+<enableViBe>0</enableViBe>
+<enableCodeBook>0</enableCodeBook>
 </opencv_storage>
diff --git a/package_bgs/CodeBook.cpp b/package_bgs/CodeBook.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a1e4056de98c4391fc9751a16f501d6740fbce84
--- /dev/null
+++ b/package_bgs/CodeBook.cpp
@@ -0,0 +1,216 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "CodeBook.h"
+
+using namespace bgslibrary::algorithms;
+
+CodeBook::CodeBook() :
+  t(0), learningFrames(DEFAULT_LEARNFRAMES), alpha(DEFAULT_ALPHA), beta(DEFAULT_BETA)
+{
+  std::cout << "CodeBook()" << std::endl;
+  setup("./config/CodeBook.xml");
+}
+
+CodeBook::~CodeBook()
+{
+  std::cout << "~CodeBook()" << std::endl;
+}
+
+void CodeBook::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  init(img_input, img_output, img_bgmodel);
+  
+  if(firstTime)
+  {
+    img_foreground = cv::Mat::zeros(img_input.size(), CV_8UC1);
+    //img_background = cv::Mat::zeros(img_input.size(), CV_8UC3);
+
+    initializeCodebook(img_input.rows, img_input.cols);
+  } 
+
+  cv::Mat img_input_gray;
+  cv::cvtColor(img_input, img_input_gray, CV_BGR2GRAY);
+
+  fg_cb(img_input_gray, img_foreground);
+
+#ifndef MEX_COMPILE_FLAG
+  if (showOutput)
+  {
+    cv::imshow("Codebook FG", img_foreground);
+    //cv::imshow("Codebook BG", img_background);
+  }
+#endif
+
+  img_foreground.copyTo(img_output);
+  //img_background.copyTo(img_bgmodel);
+
+  firstTime = false;
+}
+
+void CodeBook::initializeCodebook(int w, int h)
+{
+  cbMain = new std::vector<codeword>*[w];
+  for (int i = 0; i < w; ++i)
+    cbMain[i] = new std::vector<codeword>[h];
+
+  cbCache = new std::vector<codeword>*[w];
+  for (int i = 0; i < w; ++i)
+    cbCache[i] = new std::vector<codeword>[h];
+}
+
+void CodeBook::update_cb(const cv::Mat& frame)
+{
+  if (t > learningFrames)
+    return;
+
+  for (int i = 0; i < frame.rows; i++)
+  {
+    for (int j = 0; j < frame.cols; j++)
+    {
+      int pix = frame.at<uchar>(i, j);
+      std::vector<codeword>& cm = cbMain[i][j];
+      bool found = false;
+      for (int k = 0; k<cm.size(); k++)
+      {
+        if (cm[k].min <= pix && pix <= cm[k].max && !found)
+        {
+          found = true;
+          cm[k].min = ((pix - alpha) + (cm[k].f*cm[k].min)) / (cm[k].f + 1);
+          cm[k].max = ((pix + alpha) + (cm[k].f*cm[k].max)) / (cm[k].f + 1);
+          cm[k].l = 0;
+          cm[k].last = t;
+          cm[k].f++;
+        }
+        else
+        {
+          cm[k].l++;
+        }
+      }
+      if (!found)
+      {
+        codeword n = {};
+        n.min = std::max(0, pix - alpha);
+        n.max = std::min(255, pix + alpha);
+        n.f = 1;
+        n.l = 0;
+        n.first = t;
+        n.last = t;
+        cm.push_back(n);
+      }
+    }
+  }
+  t++;
+}
+
+void CodeBook::fg_cb(const cv::Mat& frame, cv::Mat& fg)
+{
+  //fg = cv::Mat::zeros(frame.size(), CV_8UC1);
+  //if (cbMain == 0) initializeCodebook(frame.rows, frame.cols);
+  
+  if (t <= learningFrames)
+  {
+    update_cb(frame);
+    return;
+  }
+
+  for (int i = 0; i<frame.rows; i++)
+  {
+    for (int j = 0; j<frame.cols; j++)
+    {
+      int pix = frame.at<uchar>(i, j);
+      std::vector<codeword>& cm = cbMain[i][j];
+      bool found = false;
+      for (int k = 0; k<cm.size(); k++)
+      {
+        if (cm[k].min <= pix && pix <= cm[k].max && !found)
+        {
+          cm[k].min = ((1 - beta)*(pix - alpha)) + (beta*cm[k].min);
+          cm[k].max = ((1 - beta)*(pix + alpha)) + (beta*cm[k].max);
+          cm[k].l = 0;
+          cm[k].first = t;
+          cm[k].f++;
+          found = true;
+        }
+        else
+          cm[k].l++;
+      }
+      cm.erase(remove_if(cm.begin(), cm.end(), [](codeword& c) { return c.l >= Tdel; }), cm.end());
+      fg.at<uchar>(i, j) = found ? 0 : 255;
+      if (found) continue;
+      found = false;
+      std::vector<codeword>& cc = cbCache[i][j];
+      for (int k = 0; k<cc.size(); k++)
+      {
+        if (cc[k].min <= pix && pix <= cc[k].max && !found)
+        {
+          cc[k].min = ((1 - beta)*(pix - alpha)) + (beta*cc[k].min);
+          cc[k].max = ((1 - beta)*(pix + alpha)) + (beta*cc[k].max);
+          cc[k].l = 0;
+          cc[k].first = t;
+          cc[k].f++;
+          found = true;
+        }
+        else
+          cc[k].l++;
+      }
+
+      if (!found)
+      {
+        codeword n = {};
+        n.min = std::max(0, pix - alpha);
+        n.max = std::min(255, pix + alpha);
+        n.f = 1;
+        n.l = 0;
+        n.first = t;
+        n.last = t;
+        cc.push_back(n);
+      }
+
+      cc.erase(remove_if(cc.begin(), cc.end(), [](codeword& c) { return c.l >= Th; }), cc.end());
+
+      for (std::vector<codeword>::iterator it = cc.begin(); it != cc.end(); it++)
+        if (it->f > Tadd)
+          cm.push_back(*it);
+
+      cc.erase(remove_if(cc.begin(), cc.end(), [](codeword& c) { return c.f > Tadd; }), cc.end());
+    }
+  }
+}
+
+void CodeBook::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "alpha", alpha);
+  cvWriteReal(fs, "beta", beta);
+  cvWriteInt(fs, "learningFrames", learningFrames);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void CodeBook::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ);
+
+  alpha = cvReadIntByName(fs, nullptr, "alpha", DEFAULT_ALPHA);
+  beta = cvReadRealByName(fs, nullptr, "beta", DEFAULT_BETA);
+  learningFrames = cvReadIntByName(fs, nullptr, "learningFrames", DEFAULT_LEARNFRAMES);
+  showOutput = cvReadIntByName(fs, nullptr, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/CodeBook.h b/package_bgs/CodeBook.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec224ab1eda74360f09d19c06046595c8da57117
--- /dev/null
+++ b/package_bgs/CodeBook.h
@@ -0,0 +1,68 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <opencv2/opencv.hpp>
+
+#include "IBGS.h"
+
+namespace bgslibrary
+{
+  namespace algorithms
+  {
+    struct codeword {
+      float min;
+      float max;
+      float f;
+      float l;
+      int first;
+      int last;
+      bool isStale;
+    };
+
+    class CodeBook : public IBGS
+    {
+    private:
+      static const int Tdel = 200;
+      static const int Tadd = 150;
+      static const int Th = 200;
+      const int DEFAULT_ALPHA = 10;
+      const float DEFAULT_BETA = 1.;
+      const int DEFAULT_LEARNFRAMES = 10;
+      int t = 0;
+      int learningFrames = 10;
+      int alpha = 10;
+      float beta = 1;
+      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);
+
+      void saveConfig();
+      void loadConfig();
+    };
+  }
+}
diff --git a/package_bgs/bgslibrary.h b/package_bgs/bgslibrary.h
index 3895ba85b6f9e646e76965506563f3a0c635eb26..e95a06d25688d79b257ebb971034f1e82d406e07 100644
--- a/package_bgs/bgslibrary.h
+++ b/package_bgs/bgslibrary.h
@@ -58,6 +58,7 @@ along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
 #include "PAWCS.h"
 #include "TwoPoints.h"
 #include "ViBe.h"
+#include "CodeBook.h"
 
 //#include "_template_/MyBGS.h"
 //#include "_template_/Amber.h"