diff --git a/Src/CMakeLists.txt b/Src/CMakeLists.txt
index 8e6b18bd27d0e36e00ae7e94a912bc0d88f5b20f..8dc0aae19d643b26a11869fd1d106484f2f205ea 100644
--- a/Src/CMakeLists.txt
+++ b/Src/CMakeLists.txt
@@ -21,6 +21,8 @@ add_behavior_plugin(${target}
     "Model/TrackedComponents/TrackedTrajectory.cpp"
     "Model/TrackedComponents/pose/FishPose.cpp"
     "Model/TrackingAlgorithm/NN2dMapper.cpp"
+    "Model/TrackingAlgorithm/imageProcessor/preprocessor/CustomBackgroundSubtractor.h"
+    "Model/TrackingAlgorithm/imageProcessor/preprocessor/CustomBackgroundSubtractor.cpp"
     "Model/TrackingAlgorithm/imageProcessor/preprocessor/ImagePreProcessor.cpp"
     "Model/TrackingAlgorithm/imageProcessor/cvblobs/blob.cpp"
     "Model/TrackingAlgorithm/imageProcessor/cvblobs/BlobContour.cpp"
diff --git a/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/CustomBackgroundSubtractor.cpp b/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/CustomBackgroundSubtractor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..62653744096999a7dc6a5129bf67b3bd7abfff58
--- /dev/null
+++ b/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/CustomBackgroundSubtractor.cpp
@@ -0,0 +1,53 @@
+#include "CustomBackgroundSubtractor.h"
+
+#include <vector>
+#include <future>
+
+void CustomBackgroundSubtractor::getBackgroundImage(cv::OutputArray backgroundImage) const
+{
+	m_background.copyTo(backgroundImage);
+}
+
+void CustomBackgroundSubtractor::apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate)
+{
+	if (!m_background.data) {
+		image.copyTo(m_background);
+	}
+
+	const int imageWidth = m_background.cols;
+	const int imageHeight = m_background.rows;
+	const int totalRegionsX = 4;
+	const int totalRegionsY = 4;
+	const int totalRegions = totalRegionsX * totalRegionsY;
+	const int regionWidth = imageWidth / totalRegionsX;
+	const int regionHeight = imageHeight / totalRegionsY;
+
+	fgmask.create(imageHeight, imageWidth, image.type());
+
+	auto workOnRegion = [&](int x, int y) {
+		const int startingX = x * regionWidth;
+		const int startingY = y * regionHeight;
+		const cv::Rect subArea = cv::Rect(startingX, startingY, regionWidth, regionHeight);
+		cv::Mat subBackground = m_background(subArea);
+		cv::Mat subImage = image.getMat()(subArea);
+		cv::Mat subResults = fgmask.getMat()(subArea);
+
+		subResults = (subBackground - subImage);
+		subBackground = (1.0 - learningRate) * subBackground + learningRate * subImage;
+	};
+
+	std::vector<std::future<void>> merger;
+	merger.reserve(totalRegions);
+
+	for (int x = 0; x < totalRegionsX; ++x)
+	{
+		for (int y = 0; y < totalRegionsY; ++y)
+		{
+			merger.push_back(std::async([&, x, y] { workOnRegion(x, y); }));
+		}
+	}
+
+	for (const auto & asyncResult : merger) {
+		asyncResult.wait();
+	}
+}
diff --git a/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/CustomBackgroundSubtractor.h b/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/CustomBackgroundSubtractor.h
new file mode 100644
index 0000000000000000000000000000000000000000..0f28bc2f8061899187f442d8d5174b10b558d1ea
--- /dev/null
+++ b/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/CustomBackgroundSubtractor.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <opencv2/video/background_segm.hpp>
+
+class CustomBackgroundSubtractor : public cv::BackgroundSubtractor
+{
+public:
+	void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = -1) override;
+
+	void getBackgroundImage(cv::OutputArray backgroundImage) const override;
+
+private:
+	cv::Mat m_background;
+};
diff --git a/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/ImagePreProcessor.cpp b/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/ImagePreProcessor.cpp
index b44a2536da158ed36126510e8bc210c764cfb303..cac1f19c30d8f4c9641fb0b52cf538dcd4de350c 100644
--- a/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/ImagePreProcessor.cpp
+++ b/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/ImagePreProcessor.cpp
@@ -2,15 +2,17 @@
 
 #include <opencv2/highgui.hpp>
 
-#include <future>
 #include <QMutex>
 
+#include "CustomBackgroundSubtractor.h"
+
 QMutex bgsMutex;
 QMutex oriImageMutex;
 QMutex initBgkFrameNumMutex;
 
 ImagePreProcessor::ImagePreProcessor(TrackerParameter* p_TrackingParameter) :
 	_maxBackgroundImageInitTime(0)
+	, m_subtractor(new CustomBackgroundSubtractor())
 {
 	_TrackingParameter = p_TrackingParameter;
 	init();
@@ -100,49 +102,10 @@ cv::Mat ImagePreProcessor::dilate(cv::Mat& image)
 
 cv::Mat ImagePreProcessor::backgroundSubtraction(cv::Mat& image)
 {
-	if (!m_backgroundImage->data)
-		image.copyTo(*m_backgroundImage);
-
-	// calculate the image difference
-	const double alpha = m_TrackingParameter->getBackgroundRatio();
-
-	const int &imageWidth = m_backgroundImage->cols;
-	const int &imageHeight = m_backgroundImage->rows;
-	const int totalRegionsX = 4;
-	const int totalRegionsY = 4;
-	const int totalRegions = totalRegionsX * totalRegionsY;
-	const int regionWidth = imageWidth / totalRegionsX;
-	const int regionHeight = imageHeight / totalRegionsY;
-
-	cv::Mat results(imageHeight, imageWidth, image.type());
-
-	auto workOnRegion = [&](int x, int y) {
-		const int startingX = x * regionWidth;
-		const int startingY = y * regionHeight;
-		const cv::Rect subArea = cv::Rect(startingX, startingY, regionWidth, regionHeight);
-		cv::Mat subBackground = (*m_backgroundImage)(subArea);
-		cv::Mat subImage = image(subArea);
-		cv::Mat subResults = results(subArea);
-
-		subResults = (subBackground - subImage);
-		subBackground = (1.0 - alpha) * subBackground + alpha * subImage;
-	};
-
-	std::vector<std::future<void>> merger;
-	merger.reserve(totalRegions);
-
-	for (int x = 0; x < totalRegionsX; ++x)
-	{
-		for (int y = 0; y < totalRegionsY; ++y)
-		{
-			merger.push_back(std::async([&, x, y] { workOnRegion(x, y); }));
-		}
-	}
-
-	for (const auto & asyncResult : merger)
-		asyncResult.wait();
-
-	return results;
+	cv::Mat foreground;
+	m_subtractor->apply(image, foreground, m_TrackingParameter->getBackgroundRatio());
+	m_subtractor->getBackgroundImage(*m_backgroundImage);
+	return foreground;
 }
 
 std::map<std::string, std::shared_ptr<cv::Mat>> ImagePreProcessor::preProcess(std::shared_ptr<cv::Mat> p_image)
diff --git a/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/ImagePreProcessor.h b/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/ImagePreProcessor.h
index 70b6709c7d5a22066eaf90cc65fab6d883cc0ec3..925e5d261547a0bdaf5ff322905967ff9ff72826 100644
--- a/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/ImagePreProcessor.h
+++ b/Src/Model/TrackingAlgorithm/imageProcessor/preprocessor/ImagePreProcessor.h
@@ -97,6 +97,8 @@ private:
 
 	TrackerParameter* _TrackingParameter;
 
+	cv::BackgroundSubtractor* m_subtractor;
+
 	// functions
 	void setBkgFrameNum(int);
 	int getBkgFrameNum();