diff --git a/README.md b/README.md
index 76d02dbde787d664ca857fc256002329eb69d551..88c4af1b034aa215d143c5f638eb36e7e42c8663 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
 ## BGSLibrary
 A Background Subtraction Library
 
-[![Release](https://img.shields.io/badge/Release-v2.0.0-blue.svg)](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) [![Platform: Windows, Linux, OS X](https://img.shields.io/badge/Platform-Windows%2C%20Linux%2C%20OS%20X-blue.svg)](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [![OpenCV](https://img.shields.io/badge/OpenCV-2.x%2C%203.x-blue.svg)](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [![Wrapper: Python, MATLAB](https://img.shields.io/badge/Wrapper-Python%2C%20MATLAB-orange.svg)](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [![Algorithms](https://img.shields.io/badge/Algorithms-40-red.svg)](https://github.com/andrewssobral/bgslibrary/wiki/List-of-available-algorithms)
+[![Release](https://img.shields.io/badge/Release-v2.0.0-blue.svg)](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) [![Platform: Windows, Linux, OS X](https://img.shields.io/badge/Platform-Windows%2C%20Linux%2C%20OS%20X-blue.svg)](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [![OpenCV](https://img.shields.io/badge/OpenCV-2.x%2C%203.x-blue.svg)](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [![Wrapper: Python, MATLAB](https://img.shields.io/badge/Wrapper-Java%2C%20Python%2C%20MATLAB-orange.svg)](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [![Algorithms](https://img.shields.io/badge/Algorithms-43-red.svg)](https://github.com/andrewssobral/bgslibrary/wiki/List-of-available-algorithms)
 
 [![bgslibrary](http://i.giphy.com/5A94AZahSIVOw.gif)](https://youtu.be/_UbERwuQ0OU)
 
-Page Update: **18/03/2017**
+Page Update: **01/04/2017**
 
 Library Version: **2.0.0** (see **[Build Status](https://github.com/andrewssobral/bgslibrary/wiki/Build-status)** and **[Release Notes](https://github.com/andrewssobral/bgslibrary/wiki/Release-notes)** for more info)
 
-The **BGSLibrary** was developed by [Andrews Sobral](http://andrewssobral.wixsite.com/home) and provides an easy-to-use C++ framework based on [OpenCV](http://www.opencv.org/) to perform foreground-background separation in videos. The bgslibrary is compatible with OpenCV 2.x and 3.x, and compiles under Windows, Linux, and Mac OS X. Currently the library contains **40** algorithms. The source code is available under [GNU GPLv3 license](https://www.gnu.org/licenses/gpl-3.0.en.html), the library is free and open source for academic purposes.
+The **BGSLibrary** was developed by [Andrews Sobral](http://andrewssobral.wixsite.com/home) and provides an easy-to-use C++ framework based on [OpenCV](http://www.opencv.org/) to perform foreground-background separation in videos. The bgslibrary is compatible with OpenCV 2.x and 3.x, and compiles under Windows, Linux, and Mac OS X. Currently the library contains **43** algorithms. The source code is available under [GNU GPLv3 license](https://www.gnu.org/licenses/gpl-3.0.en.html), the library is free and open source for academic purposes.
 
 * [List of available algorithms](https://github.com/andrewssobral/bgslibrary/wiki/List-of-available-algorithms)
 * [Algorithms benchmark](https://github.com/andrewssobral/bgslibrary/wiki/Algorithms-benchmark)
@@ -32,6 +32,7 @@ The **BGSLibrary** was developed by [Andrews Sobral](http://andrewssobral.wixsit
 
 *  * [Python](https://github.com/andrewssobral/bgslibrary/wiki/Wrapper:-Python) ***(NEW)***
 *  * [MATLAB](https://github.com/andrewssobral/bgslibrary/wiki/Wrapper:-MATLAB) ***(NEW)***
+*  * [Java](https://github.com/andrewssobral/bgslibrary/wiki/Wrapper:-Java) ***(NEW)***
 
 * [Docker images](https://github.com/andrewssobral/bgslibrary/wiki/Docker-images)
 * [How to integrate BGSLibrary in your own CPP code](https://github.com/andrewssobral/bgslibrary/wiki/How-to-integrate-BGSLibrary-in-your-own-CPP-code)
diff --git a/wrapper_java/.gitignore b/wrapper_java/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ca2b249f97151067cbc6bf5addbc43f358775d34
--- /dev/null
+++ b/wrapper_java/.gitignore
@@ -0,0 +1,9 @@
+nbproject/
+build.xml
+build/
+dist/
+build_*/
+*.dll
+*.bat
+*.sh
+*.lib
diff --git a/wrapper_java/CMakeLists.txt b/wrapper_java/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..88b984527540d6d0ed1538f224c3f7be6181e783
--- /dev/null
+++ b/wrapper_java/CMakeLists.txt
@@ -0,0 +1,85 @@
+cmake_minimum_required(VERSION 2.8)
+project(libbgs_java_module)
+
+# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+if(UNIX)
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=gnu++0x")
+	set(CMAKE_MACOSX_RPATH 1)
+endif(UNIX)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
+#set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules)
+
+# compilation mode setup
+set(CMAKE_BUILD_TYPE Release)
+#set(CMAKE_BUILD_TYPE Debug)
+
+if(WIN32)
+	set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
+	set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
+endif(WIN32)
+
+set(bgs_out_dir ".")
+# First for the generic no-config case (e.g. with mingw)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${bgs_out_dir})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${bgs_out_dir})
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${bgs_out_dir})
+# Second, for multi-config builds (e.g. msvc)
+foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
+    string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
+    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir})
+    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir})
+    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir})
+endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES)
+
+if(UNIX)
+	# add some standard warnings
+	ADD_DEFINITIONS(-Wno-variadic-macros -Wno-long-long -Wall -Wextra -Winit-self -Woverloaded-virtual -Wsign-promo -Wno-unused-parameter -pedantic -Woverloaded-virtual -Wno-unknown-pragmas)
+
+	# -ansi does not compile with sjn module
+	#ADD_DEFINITIONS(-ansi)
+
+	# if you like to have warinings about conversions, e.g. double->int or double->float etc., or float compare
+	#ADD_DEFINITIONS(-Wconversion -Wfloat-equal)
+endif(UNIX)
+
+find_package(JNI REQUIRED)
+if (JNI_FOUND)
+    message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}")
+    message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}")
+endif()
+
+set(OpenCV_STATIC OFF)
+find_package(OpenCV REQUIRED)
+if (OpenCV_FOUND)
+  message(STATUS "OpenCV library status:")
+  message(STATUS "    version: ${OpenCV_VERSION}")
+  message(STATUS "    libraries: ${OpenCV_LIBS}")
+  message(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")
+endif()
+
+file(GLOB_RECURSE analysis_src ../package_analysis/*.cpp)
+file(GLOB_RECURSE analysis_inc ../package_analysis/*.h)
+file(GLOB_RECURSE bgs_src ../package_bgs/*.cpp package_bgs/*.c)
+file(GLOB_RECURSE bgs_inc ../package_bgs/*.h)
+
+include_directories(${CMAKE_SOURCE_DIR} ${JNI_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})
+
+add_library(libbgs STATIC ${bgs_src} ${analysis_src})
+target_link_libraries(libbgs ${OpenCV_LIBS})
+set_property(TARGET libbgs PROPERTY PUBLIC_HEADER ${bgs_inc} ${analysis_inc})
+if(WIN32)
+	# set_property(TARGET libbgs PROPERTY SUFFIX ".lib")
+else()
+	set_property(TARGET libbgs PROPERTY OUTPUT_NAME "bgs")
+endif()
+
+set(SOURCE_FILES bgslibrary_java_module.cpp)
+add_library(libbgs_java_module SHARED ${SOURCE_FILES})
+set_target_properties(libbgs_java_module PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_link_libraries(libbgs_java_module libbgs ${OpenCV_LIBS})
+if(WIN32)
+	# set_property(TARGET libbgs_java_module PROPERTY SUFFIX ".lib")
+else()
+	set_property(TARGET libbgs_java_module PROPERTY OUTPUT_NAME "bgs_java_module")
+endif()
diff --git a/wrapper_java/README.md b/wrapper_java/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..bd1a59521085ab69d702210cf0a00d29de0e099a
--- /dev/null
+++ b/wrapper_java/README.md
@@ -0,0 +1,55 @@
+### For Windows users
+
+* Running CMAKE with Visual Studio 2015 and OpenCV 3.2.0 (x64)
+
+* * Working directory: **bgslibrary\wrapper_java**
+
+```
+:: Set OpenCV env
+echo "Setting up OpenCV env"
+set OpenCV_DIR=C:\OpenCV3.2.0\build
+set PATH=%PATH%;%OpenCV_DIR%\x64\vc14\bin
+
+:: Run CMake
+echo "Running CMake"
+rmdir /S /Q build_cmake
+if not exist "build_cmake" mkdir build_cmake
+cd build_cmake
+cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 14 Win64" ..
+cd ..
+```
+
+* Open **libbgs_java_module.sln** in your Visual Studio IDE and switch to **RELEASE** mode
+
+* Click on **ALL_BUILD** and build
+
+* Copy **libbgs_java_module.dll** to **bgslibrary\wrapper_java**
+
+* Compile Java source
+
+```
+:: Compile
+echo "Compiling"
+javac -cp .;src/;libs/opencv-320.jar src/bgslibrary/Main.java
+```
+
+* Run
+
+```
+:: Run
+echo "Running Main class"
+java -cp .;src/;libs/opencv-320.jar -Djava.library.path=. bgslibrary.Main
+```
+
+[![bgslibrary](https://sites.google.com/site/andrewssobral/bgslib_java_wrapper_screen.png)]()
+
+
+#### Generating JNI files (optional)
+
+```
+:: Generate JNI
+cd src
+echo "Generating JNI"
+javah -cp .;../libs/opencv-320.jar bgslibrary.Main
+cd ..
+```
diff --git a/wrapper_java/bgslibrary_java_module.cpp b/wrapper_java/bgslibrary_java_module.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..275847022c81bba9e6ca0e69f731dbadcbc8c07f
--- /dev/null
+++ b/wrapper_java/bgslibrary_java_module.cpp
@@ -0,0 +1,298 @@
+/*
+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 <iostream>
+#include <opencv2/opencv.hpp>
+
+#include "bgslibrary_java_module.hpp"
+
+static IBGS *ptrBGS = nullptr;
+static std::string algorithm = "";
+
+namespace bgslibrary
+{
+  IBGS* init_alg(std::string alg_name)
+  {
+    if (alg_name.compare("FrameDifference") == 0)
+      return (IBGS *)malloc(sizeof(FrameDifference));
+    if (alg_name.compare("StaticFrameDifference") == 0)
+      return (IBGS *)malloc(sizeof(StaticFrameDifference));
+    if (alg_name.compare("WeightedMovingMean") == 0)
+      return (IBGS *)malloc(sizeof(WeightedMovingMean));
+    if (alg_name.compare("WeightedMovingVariance") == 0)
+      return (IBGS *)malloc(sizeof(WeightedMovingVariance));
+#if CV_MAJOR_VERSION == 2
+    if (alg_name.compare("MixtureOfGaussianV1") == 0)
+      return (IBGS *)malloc(sizeof(MixtureOfGaussianV1)); // only for OpenCV 2.x
+#endif
+    if (alg_name.compare("MixtureOfGaussianV2") == 0)
+      return (IBGS *)malloc(sizeof(MixtureOfGaussianV2));
+    if (alg_name.compare("AdaptiveBackgroundLearning") == 0)
+      return (IBGS *)malloc(sizeof(AdaptiveBackgroundLearning));
+    if (alg_name.compare("AdaptiveSelectiveBackgroundLearning") == 0)
+      return (IBGS *)malloc(sizeof(AdaptiveSelectiveBackgroundLearning));
+#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+    if (alg_name.compare("GMG") == 0)
+      return (IBGS *)malloc(sizeof(GMG)); // only for OpenCV >= 2.4.3
+#endif
+#if CV_MAJOR_VERSION == 3
+    if (alg_name.compare("KNN") == 0)
+      return (IBGS *)malloc(sizeof(KNN)); // only for OpenCV 3.x
+#endif
+    if (alg_name.compare("DPAdaptiveMedian") == 0)
+      return (IBGS *)malloc(sizeof(DPAdaptiveMedian));
+    if (alg_name.compare("DPGrimsonGMM") == 0)
+      return (IBGS *)malloc(sizeof(DPGrimsonGMM));
+    if (alg_name.compare("DPZivkovicAGMM") == 0)
+      return (IBGS *)malloc(sizeof(DPZivkovicAGMM));
+    if (alg_name.compare("DPMean") == 0)
+      return (IBGS *)malloc(sizeof(DPMean));
+    if (alg_name.compare("DPWrenGA") == 0)
+      return (IBGS *)malloc(sizeof(DPWrenGA));
+    if (alg_name.compare("DPPratiMediod") == 0)
+      return (IBGS *)malloc(sizeof(DPPratiMediod));
+    if (alg_name.compare("DPEigenbackground") == 0)
+      return (IBGS *)malloc(sizeof(DPEigenbackground));
+    if (alg_name.compare("DPTexture") == 0)
+      return (IBGS *)malloc(sizeof(DPTexture));
+    if (alg_name.compare("T2FGMM_UM") == 0)
+      return (IBGS *)malloc(sizeof(T2FGMM_UM));
+    if (alg_name.compare("T2FGMM_UV") == 0)
+      return (IBGS *)malloc(sizeof(T2FGMM_UV));
+    if (alg_name.compare("T2FMRF_UM") == 0)
+      return (IBGS *)malloc(sizeof(T2FMRF_UM));
+    if (alg_name.compare("T2FMRF_UV") == 0)
+      return (IBGS *)malloc(sizeof(T2FMRF_UV));
+    if (alg_name.compare("FuzzySugenoIntegral") == 0)
+      return (IBGS *)malloc(sizeof(FuzzySugenoIntegral));
+    if (alg_name.compare("FuzzyChoquetIntegral") == 0)
+      return (IBGS *)malloc(sizeof(FuzzyChoquetIntegral));
+    if (alg_name.compare("LBSimpleGaussian") == 0)
+      return (IBGS *)malloc(sizeof(LBSimpleGaussian));
+    if (alg_name.compare("LBFuzzyGaussian") == 0)
+      return (IBGS *)malloc(sizeof(LBFuzzyGaussian));
+    if (alg_name.compare("LBMixtureOfGaussians") == 0)
+      return (IBGS *)malloc(sizeof(LBMixtureOfGaussians));
+    if (alg_name.compare("LBAdaptiveSOM") == 0)
+      return (IBGS *)malloc(sizeof(LBAdaptiveSOM));
+    if (alg_name.compare("LBFuzzyAdaptiveSOM") == 0)
+      return (IBGS *)malloc(sizeof(LBFuzzyAdaptiveSOM));
+    if (alg_name.compare("LBP_MRF") == 0)
+      return (IBGS *)malloc(sizeof(LBP_MRF));
+    if (alg_name.compare("MultiLayer") == 0)
+      return (IBGS *)malloc(sizeof(MultiLayer));
+    if (alg_name.compare("PixelBasedAdaptiveSegmenter") == 0)
+      return (IBGS *)malloc(sizeof(PixelBasedAdaptiveSegmenter));
+    if (alg_name.compare("VuMeter") == 0)
+      return (IBGS *)malloc(sizeof(VuMeter));
+    if (alg_name.compare("KDE") == 0)
+      return (IBGS *)malloc(sizeof(KDE));
+    if (alg_name.compare("IndependentMultimodal") == 0)
+      return (IBGS *)malloc(sizeof(IndependentMultimodal));
+    if (alg_name.compare("MultiCue") == 0)
+      return (IBGS *)malloc(sizeof(MultiCue));
+    if (alg_name.compare("SigmaDelta") == 0)
+      return (IBGS *)malloc(sizeof(SigmaDelta));
+    if (alg_name.compare("SuBSENSE") == 0)
+      return (IBGS *)malloc(sizeof(SuBSENSE));
+    if (alg_name.compare("LOBSTER") == 0)
+      return (IBGS *)malloc(sizeof(LOBSTER));
+    if (alg_name.compare("PAWCS") == 0)
+      return (IBGS *)malloc(sizeof(PAWCS));
+    if (alg_name.compare("TwoPoints") == 0)
+      return (IBGS *)malloc(sizeof(TwoPoints));
+    if (alg_name.compare("ViBe") == 0)
+      return (IBGS *)malloc(sizeof(ViBe));
+    if (alg_name.compare("CodeBook") == 0)
+      return (IBGS *)malloc(sizeof(CodeBook));
+    return NULL;
+  }
+
+  IBGS* get_alg(std::string alg_name)
+  {
+    if (alg_name.compare("FrameDifference") == 0)
+      return new (ptrBGS) FrameDifference();
+    if (alg_name.compare("StaticFrameDifference") == 0)
+      return new (ptrBGS) StaticFrameDifference();
+    if (alg_name.compare("WeightedMovingMean") == 0)
+      return new (ptrBGS) WeightedMovingMean();
+    if (alg_name.compare("WeightedMovingVariance") == 0)
+      return new (ptrBGS) WeightedMovingVariance();
+#if CV_MAJOR_VERSION == 2
+    if (alg_name.compare("MixtureOfGaussianV1") == 0)
+      return new (ptrBGS) MixtureOfGaussianV1(); // only for OpenCV 2.x
+#endif
+    if (alg_name.compare("MixtureOfGaussianV2") == 0)
+      return new (ptrBGS) MixtureOfGaussianV2();
+    if (alg_name.compare("AdaptiveBackgroundLearning") == 0)
+      return new (ptrBGS) AdaptiveBackgroundLearning();
+    if (alg_name.compare("AdaptiveSelectiveBackgroundLearning") == 0)
+      return new (ptrBGS) AdaptiveSelectiveBackgroundLearning();
+#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+    if (alg_name.compare("GMG") == 0)
+      return new (ptrBGS) GMG(); // only for OpenCV >= 2.4.3
+#endif
+#if CV_MAJOR_VERSION == 3
+    if (alg_name.compare("KNN") == 0)
+      return new (ptrBGS) KNN(); // only on OpenCV 3.x
+#endif
+    if (alg_name.compare("DPAdaptiveMedian") == 0)
+      return new (ptrBGS) DPAdaptiveMedian();
+    if (alg_name.compare("DPGrimsonGMM") == 0)
+      return new (ptrBGS) DPGrimsonGMM();
+    if (alg_name.compare("DPZivkovicAGMM") == 0)
+      return new (ptrBGS) DPZivkovicAGMM();
+    if (alg_name.compare("DPMean") == 0)
+      return new (ptrBGS) DPMean();
+    if (alg_name.compare("DPWrenGA") == 0)
+      return new (ptrBGS) DPWrenGA();
+    if (alg_name.compare("DPPratiMediod") == 0)
+      return new (ptrBGS) DPPratiMediod();
+    if (alg_name.compare("DPEigenbackground") == 0)
+      return new (ptrBGS) DPEigenbackground();
+    if (alg_name.compare("DPTexture") == 0)
+      return new (ptrBGS) DPTexture();
+    if (alg_name.compare("T2FGMM_UM") == 0)
+      return new (ptrBGS) T2FGMM_UM();
+    if (alg_name.compare("T2FGMM_UV") == 0)
+      return new (ptrBGS) T2FGMM_UV();
+    if (alg_name.compare("T2FMRF_UM") == 0)
+      return new (ptrBGS) T2FMRF_UM();
+    if (alg_name.compare("T2FMRF_UV") == 0)
+      return new (ptrBGS) T2FMRF_UV();
+    if (alg_name.compare("FuzzySugenoIntegral") == 0)
+      return new (ptrBGS) FuzzySugenoIntegral();
+    if (alg_name.compare("FuzzyChoquetIntegral") == 0)
+      return new (ptrBGS) FuzzyChoquetIntegral();
+    if (alg_name.compare("LBSimpleGaussian") == 0)
+      return new (ptrBGS) LBSimpleGaussian();
+    if (alg_name.compare("LBFuzzyGaussian") == 0)
+      return new (ptrBGS) LBFuzzyGaussian();
+    if (alg_name.compare("LBMixtureOfGaussians") == 0)
+      return new (ptrBGS) LBMixtureOfGaussians();
+    if (alg_name.compare("LBAdaptiveSOM") == 0)
+      return new (ptrBGS) LBAdaptiveSOM();
+    if (alg_name.compare("LBFuzzyAdaptiveSOM") == 0)
+      return new (ptrBGS) LBFuzzyAdaptiveSOM();
+    if (alg_name.compare("LBP_MRF") == 0)
+      return new (ptrBGS) LBP_MRF();
+    if (alg_name.compare("MultiLayer") == 0)
+      return new (ptrBGS) MultiLayer();
+    if (alg_name.compare("PixelBasedAdaptiveSegmenter") == 0)
+      return new (ptrBGS) PixelBasedAdaptiveSegmenter();
+    if (alg_name.compare("VuMeter") == 0)
+      return new (ptrBGS) VuMeter();
+    if (alg_name.compare("KDE") == 0)
+      return new (ptrBGS) KDE();
+    if (alg_name.compare("IndependentMultimodal") == 0)
+      return new (ptrBGS) IndependentMultimodal();
+    if (alg_name.compare("MultiCue") == 0)
+      return new (ptrBGS) MultiCue();
+    if (alg_name.compare("SigmaDelta") == 0)
+      return new (ptrBGS) SigmaDelta();
+    if (alg_name.compare("SuBSENSE") == 0)
+      return new (ptrBGS) SuBSENSE();
+    if (alg_name.compare("LOBSTER") == 0)
+      return new (ptrBGS) LOBSTER();
+    if (alg_name.compare("PAWCS") == 0)
+      return new (ptrBGS) PAWCS();
+    if (alg_name.compare("TwoPoints") == 0)
+      return new (ptrBGS) TwoPoints();
+    if (alg_name.compare("ViBe") == 0)
+      return new (ptrBGS) ViBe();
+    if (alg_name.compare("CodeBook") == 0)
+      return new (ptrBGS) CodeBook();
+    return NULL;
+  }
+}
+
+bool constructObject(std::string algorithm)
+{
+  if (ptrBGS != nullptr) destroyObject();
+
+  ptrBGS = bgslibrary::init_alg(algorithm);
+  if (ptrBGS != nullptr)
+  {
+    ptrBGS = bgslibrary::get_alg(algorithm);
+    if (ptrBGS == nullptr)
+    {
+      std::cout << "Failed to construct an object on memory. Algorithm not initialized." << std::endl;
+      return false;
+    }
+    else
+    {
+      ptrBGS->setShowOutput(false);
+      return true;
+    }
+  }
+  else
+  {
+    std::cout << "Failed to allocate memory. Algorithm not found?" << std::endl;
+    return false;
+  }
+}
+
+void computeForegroundMask(const cv::Mat &img_input, cv::Mat &img_output)
+{
+  if (ptrBGS != nullptr)
+  {
+    cv::Mat fgmask, bgmodel;
+
+    ptrBGS->process(img_input, fgmask, bgmodel);
+
+    if (fgmask.empty())
+      fgmask = cv::Mat::zeros(img_input.size(), CV_8UC1);
+    if (bgmodel.empty())
+      bgmodel = cv::Mat::zeros(img_input.size(), CV_8UC3);
+    
+    fgmask.copyTo(img_output);
+    
+    fgmask.release();
+    bgmodel.release();
+  }
+  else
+    std::cout << "Algorithm not initialized." << std::endl;
+}
+
+void destroyObject()
+{
+  if (ptrBGS != nullptr)
+  {
+    // explicitly call destructor for "placement new"
+    ptrBGS->~IBGS();
+    free(ptrBGS);
+    ptrBGS = nullptr;
+  }
+}
+
+JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_constructObject(JNIEnv *env, jclass, jstring jstr)
+{
+  GetJStringContent(env, jstr, algorithm);
+  constructObject(algorithm);
+}
+
+JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_computeForegroundMask
+(JNIEnv *, jclass, jlong input_matPtr, jlong output_matPtr)
+{
+  cv::Mat& in_mat = *reinterpret_cast<cv::Mat*>(input_matPtr);
+  cv::Mat& fg_mat = *reinterpret_cast<cv::Mat*>(output_matPtr);
+  computeForegroundMask(in_mat, fg_mat);
+}
+
+JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_destroyObject(JNIEnv *, jclass)
+{
+  destroyObject();
+}
diff --git a/wrapper_java/bgslibrary_java_module.hpp b/wrapper_java/bgslibrary_java_module.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9f402558e3ceb0b537eb274b1ce16688e5fe1bdd
--- /dev/null
+++ b/wrapper_java/bgslibrary_java_module.hpp
@@ -0,0 +1,55 @@
+/*
+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 <iostream>
+#include <sstream>
+#include <vector>
+#include <string>
+
+#include "src/bgslibrary_BgsLib.h"
+#include "../package_bgs/bgslibrary.h"
+
+bool constructObject(std::string algorithm);
+void computeForegroundMask(const cv::Mat &img_input, cv::Mat &img_output);
+void destroyObject();
+
+template <typename T>
+std::string ToString(T val)
+{
+  std::stringstream stream;
+  stream << val;
+  return stream.str();
+}
+
+jstring StringToJString(JNIEnv * env, const std::string & nativeString)
+{
+  return env->NewStringUTF(nativeString.c_str());
+}
+
+void GetJStringContent(JNIEnv *AEnv, jstring AStr, std::string &ARes)
+{
+  if (!AStr)
+  {
+    ARes.clear();
+    return;
+  }
+
+  const auto *s = AEnv->GetStringUTFChars(AStr, nullptr);
+  ARes = s;
+  AEnv->ReleaseStringUTFChars(AStr, s);
+}
diff --git a/wrapper_java/config/.gitignore b/wrapper_java/config/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4e2a98bb114355ae964e78a929c12d44f75815de
--- /dev/null
+++ b/wrapper_java/config/.gitignore
@@ -0,0 +1,4 @@
+# Ignore everything in this directory
+*
+# Except these files
+!.gitignore
diff --git a/wrapper_java/images/320x240.gif b/wrapper_java/images/320x240.gif
new file mode 100644
index 0000000000000000000000000000000000000000..f88252131ad520f21e6771e62c43e8fbb77db631
Binary files /dev/null and b/wrapper_java/images/320x240.gif differ
diff --git a/wrapper_java/images/640x480.png b/wrapper_java/images/640x480.png
new file mode 100644
index 0000000000000000000000000000000000000000..90dd040b8bcffce6cf7ead7677572c5753d45c87
Binary files /dev/null and b/wrapper_java/images/640x480.png differ
diff --git a/wrapper_java/libs/README.md b/wrapper_java/libs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..15698e23e0903630038eb74b3f2d7841b503c6f3
--- /dev/null
+++ b/wrapper_java/libs/README.md
@@ -0,0 +1,3 @@
+### Windows version
+
+The 'opencv-320.jar' file was copied from 'C:\OpenCV3.2.0\build\java'.
diff --git a/wrapper_java/libs/opencv-320.jar b/wrapper_java/libs/opencv-320.jar
new file mode 100644
index 0000000000000000000000000000000000000000..9542446ca08d3ca26c6ba2a79c887414afbf145a
Binary files /dev/null and b/wrapper_java/libs/opencv-320.jar differ
diff --git a/wrapper_java/src/bgslibrary/.gitignore b/wrapper_java/src/bgslibrary/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6b468b62a9884e67ca19b673f8e14e1931d65036
--- /dev/null
+++ b/wrapper_java/src/bgslibrary/.gitignore
@@ -0,0 +1 @@
+*.class
diff --git a/wrapper_java/src/bgslibrary/BgsLib.java b/wrapper_java/src/bgslibrary/BgsLib.java
new file mode 100644
index 0000000000000000000000000000000000000000..c9b46084da8fd8743df298fb60a9aa716d0a186f
--- /dev/null
+++ b/wrapper_java/src/bgslibrary/BgsLib.java
@@ -0,0 +1,54 @@
+/*
+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/>.
+ */
+package bgslibrary;
+
+import org.opencv.core.Core;
+
+public class BgsLib
+{
+  static
+  {
+    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+    System.loadLibrary("libbgs_java_module");
+  }
+  
+  private static final String[] algorithms =
+    {
+      "FrameDifference", "StaticFrameDifference", "WeightedMovingMean", 
+      "WeightedMovingVariance", "MixtureOfGaussianV1", "MixtureOfGaussianV2", 
+      "AdaptiveBackgroundLearning", "AdaptiveSelectiveBackgroundLearning", 
+      "GMG", "KNN", "DPAdaptiveMedian", "DPGrimsonGMM", "DPZivkovicAGMM", 
+      "DPMean", "DPWrenGA", "DPPratiMediod", "DPEigenbackground", "DPTexture", 
+      "T2FGMM_UM", "T2FGMM_UV", "T2FMRF_UM", "T2FMRF_UV", "FuzzySugenoIntegral", 
+      "FuzzyChoquetIntegral", "LBSimpleGaussian", "LBFuzzyGaussian", 
+      "LBMixtureOfGaussians", "LBAdaptiveSOM", "LBFuzzyAdaptiveSOM", "LBP_MRF", 
+      "MultiLayer", "PixelBasedAdaptiveSegmenter", "VuMeter", "KDE", 
+      "IndependentMultimodal", "MultiCue", "SigmaDelta", "SuBSENSE", "LOBSTER", 
+      "PAWCS", "TwoPoints", "ViBe", "CodeBook"
+    };
+  
+  public static final String[] getListAlgorithms()
+  {
+    return algorithms;
+  }
+
+  public static native void constructObject(String str);
+
+  public static native void computeForegroundMask(long input_matPtr, long output_matPtr);
+
+  public static native void destroyObject();
+}
diff --git a/wrapper_java/src/bgslibrary/ImagePanel.java b/wrapper_java/src/bgslibrary/ImagePanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..d97d548cf4e5b6e38f0cc16578f2c16302d17d61
--- /dev/null
+++ b/wrapper_java/src/bgslibrary/ImagePanel.java
@@ -0,0 +1,44 @@
+package bgslibrary;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Image;
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+
+class ImagePanel extends JPanel
+{
+  private Image img;
+
+  public ImagePanel(String img)
+  {
+    this(new ImageIcon(img).getImage());
+  }
+
+  public ImagePanel(Image img)
+  {
+    this.img = img;
+    Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
+    setPreferredSize(size);
+    setMinimumSize(size);
+    setMaximumSize(size);
+    setSize(size);
+    setLayout(null);
+    setBorder(BorderFactory.createLineBorder(Color.black));
+  }
+
+  public void updateImage(Image img)
+  {
+    this.img = img;
+    validate();
+    repaint();
+  }
+
+  @Override
+  public void paintComponent(Graphics g)
+  {
+    g.drawImage(img, 0, 0, null);
+  }
+}
diff --git a/wrapper_java/src/bgslibrary/Main.java b/wrapper_java/src/bgslibrary/Main.java
new file mode 100644
index 0000000000000000000000000000000000000000..10489ec43f7b18ebd1b11cd30f647f356cbf2461
--- /dev/null
+++ b/wrapper_java/src/bgslibrary/Main.java
@@ -0,0 +1,207 @@
+/*
+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/>.
+ */
+package bgslibrary;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
+import java.io.InputStream;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import org.opencv.core.Core;
+import org.opencv.core.CvType;
+import org.opencv.core.Mat;
+import org.opencv.core.MatOfByte;
+import org.opencv.imgproc.Imgproc;
+import org.opencv.videoio.VideoCapture;
+
+public final class Main
+{
+  static
+  {
+    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+  }
+  
+  private static BgsLib bgslib;
+  
+  private JFrame window;
+  private JButton startButton, stopButton;
+  private ImagePanel image;
+  private JComboBox comboBox;
+  private String selectedAlgorithm;
+
+  public Main()
+  {
+    buildGUI();
+  }
+
+  private void buildGUI()
+  {
+    window = new JFrame("Camera Panel");
+
+    startButton = new JButton("Start");
+    stopButton = new JButton("Stop");
+
+    window.add(startButton, BorderLayout.WEST);
+    window.add(stopButton, BorderLayout.EAST);
+
+    //image = new ImagePanel(new ImageIcon("images/320x240.gif").getImage());
+    image = new ImagePanel(new ImageIcon("images/640x480.png").getImage());
+    window.add(image, BorderLayout.CENTER);
+
+    String[] options = {"* Select a background subtraction algorithm"};
+    options = Utils.generalConcatAll(options, bgslib.getListAlgorithms());
+    
+    comboBox = new JComboBox(options);
+    comboBox.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        if(begin == true)
+        {
+          JOptionPane.showMessageDialog(null, "Stop capture first.", "Warning",
+          JOptionPane.WARNING_MESSAGE);
+          comboBox.setSelectedIndex(0);
+          selectedAlgorithm = null;
+          return;
+        }
+        
+        String item = comboBox.getSelectedItem().toString();
+        
+        if(item.startsWith("*"))
+          selectedAlgorithm = null;
+        else
+          selectedAlgorithm = item;
+        
+        //System.out.println("Selected algorithm: " + selectedAlgorithm);
+      }
+    });
+    window.add(comboBox, BorderLayout.SOUTH);
+
+    window.setSize(default_width + 130, default_height + 28);
+    window.setLocationRelativeTo(null);
+    window.setVisible(true);
+    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+    window.setResizable(false);
+
+    startButton.addActionListener((ActionEvent e) ->
+    {
+      start();
+    });
+
+    stopButton.addActionListener((ActionEvent e) ->
+    {
+      stop();
+    });
+  }
+
+  private Boolean begin = false;
+  private VideoCapture video = null;
+  private CaptureThread thread = null;
+
+  private void start()
+  {
+    if (begin == false)
+    {
+      video = new VideoCapture(0);
+
+      if (video.isOpened())
+      {
+        if(selectedAlgorithm != null)
+          BgsLib.constructObject(selectedAlgorithm);
+        
+        thread = new CaptureThread();
+        thread.start();
+        begin = true;
+      }
+    }
+  }
+
+  private MatOfByte matOfByte = new MatOfByte();
+  private BufferedImage bufImage = null;
+  private InputStream in;
+  private final int default_width = 640;
+  private final int default_height = 480;
+  private Mat frameaux = new Mat();
+  private Mat frame = new Mat(default_height, default_width, CvType.CV_8UC3);
+  private Mat fgmask = new Mat();
+
+  class CaptureThread extends Thread
+  {
+    @Override
+    public void run()
+    {
+      if (video.isOpened())
+      {
+        while (begin == true)
+        {
+          video.retrieve(frameaux);
+          Imgproc.resize(frameaux, frame, frame.size());
+          
+          if(selectedAlgorithm != null)
+          {
+            BgsLib.computeForegroundMask(frame.getNativeObjAddr(), fgmask.getNativeObjAddr());
+            bufImage = Utils.toBufferedImage(fgmask);
+          }
+          else
+            bufImage = Utils.toBufferedImage(frame);
+          
+          image.updateImage(bufImage);
+
+          try
+          {
+            Thread.sleep(5);
+          }
+          catch (Exception ex)
+          {
+          }
+        }
+      }
+    }
+  }
+
+  private void stop()
+  {
+    begin = false;
+    try
+    {
+      Thread.sleep(500);
+    }
+    catch (Exception ex)
+    {
+    }
+    
+    if(video != null)
+    {
+      video.release();
+      video = null;
+    }
+    
+    BgsLib.destroyObject();
+  }
+
+  public static void main(String[] args)
+  {
+    new Main();
+  }
+}
diff --git a/wrapper_java/src/bgslibrary/Utils.java b/wrapper_java/src/bgslibrary/Utils.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd59447dbffc3e4a732d3f41a7c2e2467effe242
--- /dev/null
+++ b/wrapper_java/src/bgslibrary/Utils.java
@@ -0,0 +1,102 @@
+/*
+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/>.
+ */
+package bgslibrary;
+
+import java.awt.FlowLayout;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.UUID;
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import org.opencv.core.Mat;
+import org.opencv.imgcodecs.Imgcodecs;
+
+public class Utils
+{
+  static final private SecureRandom random = new SecureRandom();
+
+  static final public String nextSessionId()
+  {
+    return new BigInteger(130, random).toString(32);
+  }
+
+  static final public String nextUUID()
+  {
+    return UUID.randomUUID().toString();
+  }
+
+  static final public BufferedImage toBufferedImage(Mat m)
+  {
+    int type = BufferedImage.TYPE_BYTE_GRAY;
+    if (m.channels() > 1)
+      type = BufferedImage.TYPE_3BYTE_BGR;
+    int bufferSize = m.channels() * m.cols() * m.rows();
+    byte[] b = new byte[bufferSize];
+    m.get(0, 0, b); // get all the pixels
+    BufferedImage image = new BufferedImage(m.cols(), m.rows(), type);
+    final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
+    System.arraycopy(b, 0, targetPixels, 0, b.length);
+    return image;
+  }
+
+  static final public void imshow(Mat image)
+  {
+    try
+    {
+      BufferedImage bufImage = toBufferedImage(image);
+      JFrame frame = new JFrame("Image");
+      frame.getContentPane().setLayout(new FlowLayout());
+      frame.getContentPane().add(new JLabel(new ImageIcon(bufImage)));
+      frame.pack();
+      frame.setSize(image.width() + 40, image.height() + 60);
+      frame.setLocationRelativeTo(null);
+      frame.setVisible(true);
+      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+    }
+    catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+  static final public void writeImage(Mat image, String fileName)
+  {
+    //System.out.println(String.format("Writing image at %s", fileName));
+    Imgcodecs.imwrite(fileName, image);
+  }
+
+  static final public String[] generalConcatAll(String[]... jobs)
+  {
+    int len = 0;
+    for (final String[] job : jobs)
+      len += job.length;
+
+    final String[] result = new String[len];
+
+    int currentPos = 0;
+    for (final String[] job : jobs)
+    {
+      System.arraycopy(job, 0, result, currentPos, job.length);
+      currentPos += job.length;
+    }
+
+    return result;
+  }
+}
diff --git a/wrapper_java/src/bgslibrary_BgsLib.h b/wrapper_java/src/bgslibrary_BgsLib.h
new file mode 100644
index 0000000000000000000000000000000000000000..06ff9941a00c966877de52c4a59f60f5cdb66335
--- /dev/null
+++ b/wrapper_java/src/bgslibrary_BgsLib.h
@@ -0,0 +1,37 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class bgslibrary_BgsLib */
+
+#ifndef _Included_bgslibrary_BgsLib
+#define _Included_bgslibrary_BgsLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     bgslibrary_BgsLib
+ * Method:    constructObject
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_constructObject
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     bgslibrary_BgsLib
+ * Method:    computeForegroundMask
+ * Signature: (JJ)V
+ */
+JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_computeForegroundMask
+  (JNIEnv *, jclass, jlong, jlong);
+
+/*
+ * Class:     bgslibrary_BgsLib
+ * Method:    destroyObject
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_destroyObject
+  (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif