diff --git a/lib/libstereo/CMakeLists.txt b/lib/libstereo/CMakeLists.txt
index a5fe73958e3a2910d1aea58ef813a2b3bab0623f..fba64234b8c6a726eaac775aaeb3c6ae5c17852d 100644
--- a/lib/libstereo/CMakeLists.txt
+++ b/lib/libstereo/CMakeLists.txt
@@ -43,6 +43,7 @@ if (LIBSTEREO_SHARED)
                 src/algorithms/tcensussgm.cu
                 src/algorithms/hcensussgm.cu
                 src/algorithms/brefcensussgm.cu
+                src/algorithms/meancensussgm.cu
                 #src/stereo_hier_census.cu
                 src/stereo_wcensussgm.cu
                 src/stereo_census_adaptive.cu
@@ -75,6 +76,7 @@ else()
                 src/algorithms/tcensussgm.cu
                 src/algorithms/hcensussgm.cu
                 src/algorithms/brefcensussgm.cu
+                src/algorithms/meancensussgm.cu
                 #src/stereo_hier_census.cu
                 src/stereo_wcensussgm.cu
                 src/stereo_census_adaptive.cu
diff --git a/lib/libstereo/include/stereo.hpp b/lib/libstereo/include/stereo.hpp
index ea40a6386b7d8f85276718a9ffd2ce9b689bfcff..4c802da27d7e98228436bde624e1724501fe5492 100644
--- a/lib/libstereo/include/stereo.hpp
+++ b/lib/libstereo/include/stereo.hpp
@@ -86,7 +86,43 @@ private:
 };
 
 /**
- * Bilateral filtering for reference pixel. Doesn't make things better
+ * Mean reference pixel. Doesn't work since detail is lost form reference
+ * 
+ * @see "A robust local census-based stereo matching insensitive to illumination changes" (2012)
+ * @see "A stereo matching algorithm based on four-moded census and relative confidence plane fitting" (2015)
+ * @see "Stereo matching based on improved census transform" (2018)
+ */
+class StereoMeanCensusSgm {
+public:
+	StereoMeanCensusSgm();
+	~StereoMeanCensusSgm();
+
+	void compute(cv::InputArray l, cv::InputArray r, cv::OutputArray disparity);
+	void setPrior(cv::InputArray disp) {};
+
+	struct Parameters {
+		int d_min = 0;
+		int d_max = 0;
+		unsigned short P1 = 5;
+		unsigned short P2 = 25;
+		float uniqueness = std::numeric_limits<unsigned short>::max();
+		int subpixel = 1; // subpixel interpolation method
+		bool lr_consistency = true;
+		int paths = AggregationDirections::HORIZONTAL |
+					AggregationDirections::VERTICAL |
+					AggregationDirections::DIAGONAL;
+		bool debug = false;
+	};
+	Parameters params;
+
+private:
+	struct Impl;
+	Impl *impl_;
+};
+
+/**
+ * Bilateral filtering for reference pixel. Doesn't make things better, but
+ * still better than mean value for reference.
  */
 class StereoBRefCensusSgm {
 public:
diff --git a/lib/libstereo/middlebury/main.cpp b/lib/libstereo/middlebury/main.cpp
index 0c627989d7088fdbbfd17f5befaeb87e2a1c048f..ec40c620eda82d7bff143da3a7fa82f2c96a9e75 100644
--- a/lib/libstereo/middlebury/main.cpp
+++ b/lib/libstereo/middlebury/main.cpp
@@ -27,6 +27,19 @@ static void run_censussgm(MiddleburyData &data, cv::Mat &disparity) {
 	stereo.compute(data.imL, data.imR, disparity);
 }
 
+static void run_meancensussgm(MiddleburyData &data, cv::Mat &disparity) {
+	auto stereo = StereoMeanCensusSgm();
+	stereo.params.P1 = 12;
+	stereo.params.P2 = 32;
+
+	stereo.params.d_min = data.calib.vmin;
+	stereo.params.d_max = data.calib.vmax;
+	stereo.params.subpixel = 1;
+	stereo.params.lr_consistency = true;
+	stereo.params.debug = false;
+	stereo.compute(data.imL, data.imR, disparity);
+}
+
 static void run_brefcensussgm(MiddleburyData &data, cv::Mat &disparity) {
 	auto stereo = StereoBRefCensusSgm();
 	stereo.params.P1 = 12;
@@ -193,6 +206,7 @@ static const std::map<std::string, std::function<void(MiddleburyData&, cv::Mat&)
 	{ "hcensussgm", run_hcensussgm },
 	{ "wcensussgm", run_wcensussgm },
 	{ "brefcensus", run_brefcensussgm },
+	{ "mcensussgm", run_meancensussgm },
 	//{ "misgm", run_misgm },
 	{ "varcensus", run_varcensus },
 	{ "stablesgm", run_stablesgm },
diff --git a/lib/libstereo/src/algorithms/meancensussgm.cu b/lib/libstereo/src/algorithms/meancensussgm.cu
new file mode 100644
index 0000000000000000000000000000000000000000..e0c1d49d7bb4569faa9086d39a5e16deaa9cd5a5
--- /dev/null
+++ b/lib/libstereo/src/algorithms/meancensussgm.cu
@@ -0,0 +1,48 @@
+#include "stereo.hpp"
+#include "stereosgm.hpp"
+#include "../costs/census.hpp"
+#include <opencv2/cudafilters.hpp>
+
+struct StereoMeanCensusSgm::Impl : public StereoSgm<CensusMatchingCost, StereoMeanCensusSgm::Parameters> {
+	Array2D<uchar> l;
+    Array2D<uchar> r;
+    Array2D<uchar> ml;
+    Array2D<uchar> mr;
+
+	Impl(StereoMeanCensusSgm::Parameters &params, int width, int height, int dmin, int dmax) :
+        StereoSgm(params, width, height, dmin, dmax), l(width, height), r(width, height),
+        ml(width, height), mr(width, height) {}
+};
+
+StereoMeanCensusSgm::StereoMeanCensusSgm() : impl_(nullptr) {
+	impl_ = new Impl(params, 0, 0, 0, 0);
+}
+
+void StereoMeanCensusSgm::compute(cv::InputArray l, cv::InputArray r, cv::OutputArray disparity) {
+
+	cudaSetDevice(0);
+
+	if (l.rows() != impl_->cost.height() || r.cols() != impl_->cost.width()) {
+		delete impl_; impl_ = nullptr;
+		impl_ = new Impl(params, l.cols(), l.rows(), params.d_min, params.d_max);
+	}
+
+	mat2gray(l, impl_->l);
+	mat2gray(r, impl_->r);
+    
+    auto filter = cv::cuda::createBoxFilter(CV_8UC1, CV_8UC1, cv::Size(5,5));
+    filter->apply(impl_->l.toGpuMat(), impl_->ml.toGpuMat());   // E[X]
+    filter->apply(impl_->r.toGpuMat(), impl_->mr.toGpuMat());   // E[X]
+
+    impl_->cost.set(impl_->ml, impl_->mr);
+
+	cudaSafeCall(cudaDeviceSynchronize());
+	impl_->compute(disparity);
+}
+
+StereoMeanCensusSgm::~StereoMeanCensusSgm() {
+	if (impl_) {
+		delete impl_;
+		impl_ = nullptr;
+	}
+}