diff --git a/cv-node/CMakeLists.txt b/cv-node/CMakeLists.txt
index 53e6c44ce2ea799d7fc6c6b973239a271895cf67..9e93a7257c6038a9d5b25eb5a0b0e9b719c1a1cb 100644
--- a/cv-node/CMakeLists.txt
+++ b/cv-node/CMakeLists.txt
@@ -60,6 +60,7 @@ set(CVNODESRC
 	src/calibrate.cpp
 	src/local.cpp
 	src/sync.cpp
+	src/rtcensus.cpp
 )
 
 add_executable(cv-node ${CVNODESRC})
diff --git a/cv-node/include/ftl/rtcensus.hpp b/cv-node/include/ftl/rtcensus.hpp
index a717df9e2d10d96d85fddcdbe11aae09cb523fa4..5aec99da914ccf2c6bbf0e7ae91f5411c01bd61d 100644
--- a/cv-node/include/ftl/rtcensus.hpp
+++ b/cv-node/include/ftl/rtcensus.hpp
@@ -1,6 +1,9 @@
 #ifndef _FTL_RTCENSUS_HPP_
 #define _FTL_RTCENSUS_HPP_
 
+#include <opencv2/core.hpp>
+#include <opencv2/opencv.hpp>
+
 namespace ftl {
 class RTCensus {
 	public:
diff --git a/cv-node/src/main.cpp b/cv-node/src/main.cpp
index 7da43575a9ee71670a71d2395eff5c5d45b05bce..9e2034f1fe9ca70a87c1d08a6593dbf6f47a6d79 100644
--- a/cv-node/src/main.cpp
+++ b/cv-node/src/main.cpp
@@ -2,6 +2,7 @@
 #include <ftl/local.hpp>
 #include <ftl/synched.hpp>
 #include <ftl/calibrate.hpp>
+#include <ftl/rtcensus.hpp>
 
 #include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
@@ -101,7 +102,7 @@ int main(int argc, char **argv) {
 		LOG(WARNING) << "Cameras are not calibrated!";
 	}
 
-	int max_disp = 256; //208;
+	/*int max_disp = 256; //208;
 	int wsize = 5;
 	float sigma = 1.5;
 	float lambda = 8000.0;
@@ -113,11 +114,13 @@ int main(int argc, char **argv) {
             left_matcher->setPreFilterCap(63);
             left_matcher->setMode(StereoSGBM::MODE_SGBM_3WAY);
             wls_filter = createDisparityWLSFilter(left_matcher);
-            Ptr<StereoMatcher> right_matcher = createRightMatcher(left_matcher);
+            Ptr<StereoMatcher> right_matcher = createRightMatcher(left_matcher);*/
 	/*Ptr<StereoBM> left_matcher = StereoBM::create(max_disp,wsize);
 	//left_matcher->setPreFilterCap(63);
             wls_filter = createDisparityWLSFilter(left_matcher);
             Ptr<StereoMatcher> right_matcher = createRightMatcher(left_matcher);*/
+            
+    ftl::RTCensus rtc;
 	
 	while (true) {
 		Mat l, r, left_disp, right_disp, filtered_disp;
@@ -142,16 +145,18 @@ int main(int argc, char **argv) {
 		
         cvtColor(l,  l,  COLOR_BGR2GRAY);
         cvtColor(r, r, COLOR_BGR2GRAY);
-        //matching_time = (double)getTickCount();
-        left_matcher-> compute(l, r,left_disp);
+       
+        /*left_matcher-> compute(l, r,left_disp);
         right_matcher->compute(r,l, right_disp);
-       // matching_time = ((double)getTickCount() - matching_time)/getTickFrequency();
 		
 		wls_filter->setLambda(lambda);
         wls_filter->setSigmaColor(sigma);
         //filtering_time = (double)getTickCount();
         wls_filter->filter(left_disp,l,filtered_disp,right_disp);
-        //filtering_time = ((double)getTickCount() - filtering_time)/getTickFrequency();
+        //filtering_time = ((double)getTickCount() - filtering_time)/getTickFrequency();*/
+        
+        rtc.disparity(l,r,filtered_disp,200);
+		LOG(INFO) << "Disparity complete";
 		
 		// TODO Send RGB+D data somewhere
 
@@ -161,7 +166,7 @@ int main(int argc, char **argv) {
 		cv::imshow("Left",filtered_disp);
 		//if (lsrc->isStereo()) cv::imshow("Right",right_disp);
 		
-		if(cv::waitKey(1) == 27){
+		if(cv::waitKey(1000) == 27){
             //exit if ESC is pressed
             break;
         }
diff --git a/cv-node/src/rtcensus.cpp b/cv-node/src/rtcensus.cpp
index 099f827ca06b4c7ec1d37063e532b686f6c1a0b5..12b9be59440fdefbf5cf5bd11a9bc77ab5244bf2 100644
--- a/cv-node/src/rtcensus.cpp
+++ b/cv-node/src/rtcensus.cpp
@@ -1,78 +1,82 @@
 #include <ftl/rtcensus.hpp>
 #include <vector>
+#include <tuple>
+#include <bitset>
+#include <glog/logging.h>
 
 using ftl::RTCensus;
 using std::vector;
+using cv::Mat;
+using cv::Point;
+using cv::Size;
+using std::tuple;
+using std::get;
+using std::make_tuple;
+using std::bitset;
 
 #define XHI(P1,P2) ((P1 <= P2) ? 0 : 1)
 
-static vector<int64_t> sparse_census_16x16(Mat &arr) {
-	vector<int64_t> result;
-	result.resize(arr.cols*arr.rows);
-	
-	auto N = [-7,-5,-3,-1,1,3,5,7];
-	auto M = [-7,-5,-3,-1,1,3,5,7];
+static vector<uint64_t> sparse_census_16x16(Mat &arr) {
+	vector<uint64_t> result;
+	result.resize(arr.cols*arr.rows,0);
 
-	for (size_t v=0; v<arr.cols; v++) {
-	for (size_t u=0; u<arr.rows; u++) {
-		int64_t r = 0;
+	for (size_t v=7; v<arr.rows-7; v++) {
+	for (size_t u=7; u<arr.cols-7; u++) {
+		uint64_t r = 0;
 
-		for (auto n : N) {
-		for (auto m : M) {
-			auto u_ = u + n;
+		for (int n=-7; n<=7; n+=2) {
+		auto u_ = u + n;
+		for (int m=-7; m<=7; m+=2) {
 			auto v_ = v + m;
 
-			if (u_ < 0 || v_ < 0 || u_ >= arr.rows || v_ >= arr.cols) continue;
+			//if (u_ < 0 || v_ < 0 || u_ >= arr.cols || v_ >= arr.rows) continue;
 
-			r << 1;
+			r <<= 1;
 			r |= XHI(arr.at<uint8_t>(v,u), arr.at<uint8_t>(v_,u_));
 		}
 		}
 
-		result[v+u*arr.cols] = r;
+		result[u+v*arr.cols] = r;
 	}
 	}
 
 	return result;
 }
 
-static int hamming(int n1, int n2) { 
-    int x = n1 ^ n2; 
-    int setBits = 0; 
+static inline uint8_t hamming(uint64_t n1, uint64_t n2) { 
+    /*int x = n1 ^ n2; 
+    uint8_t setBits = 0; 
   
     while (x > 0) { 
         setBits += x & 1; 
         x >>= 1; 
     } 
   
-    return setBits; 
+    return setBits; */
+    return bitset<64>(n1^n2).count();
 }
 
-static vector<int64_t> dsi_ca(vector<int64_t> census_R, vector<int64_t> census_L, size_t w, size_t h, size_t d_start, size_t d_stop, int sign=1) {
+static vector<uint16_t> dsi_ca(vector<uint64_t> &census_R, vector<uint64_t> &census_L, size_t w, size_t h, size_t d_start, size_t d_stop, int sign=1) {
 	// TODO Add asserts
+	assert( census_R.size() == w*h);
+	assert( census_L.size() == w*h);
+	assert( d_stop-d_start > 0 );
 
 	auto ds = d_stop - d_start;
-	vector<int64_t> result;
-	result.resize(census_R.size()*ds);
-
-	//auto N = [-2,-1,0,1,2];
-	//auto M = [-2,-1,0,1,2];
+	vector<uint16_t> result(census_R.size()*ds, 0);
 
 	for (size_t d=0; d<ds; d++) {
-		for (size_t v=0; v<w; v++) {
-		for (size_t u=0; u<h; u++) {
-			for (int n=-2; n<=2; n++) {
+		const auto d_ = d * sign;
+		for (size_t v=2; v<h-2; v++) {
+		for (size_t u=2; u<w-2; u++) {
 			for (int n=-2; n<=2; n++) {
-				auto u_ = u + n;
-				auto v_ = v + m;
-				auto d_ = d * sign;
-
-				if (!(0<=(u_+d_) < h) continue;
-				if (!(0<=u_<h) || !(0<=v_<w)) continue;
-
-				auto r = census_R[v_+u_*w];
-				auto l = census_L[v_+(u_+d_)*w];
-				result[v+u*w+d*w*h];
+			const auto u_ = u + n;
+			if (u_+d_ < 0 || u_+d_ >= w) continue;
+			for (int m=-2; m<=2; m++) {
+				const auto v_ = (v + m)*w;
+				auto r = census_R[u_+v_];
+				auto l = census_L[v_+(u_+d_)];
+				result[d+v*w*ds+u*ds] += hamming(r,l);
 			}
 			}
 			
@@ -83,32 +87,46 @@ static vector<int64_t> dsi_ca(vector<int64_t> census_R, vector<int64_t> census_L
 	return result;
 }
 
-int64_t arrmin(vector<int64_t> a, size_t ix, size_t len) {
-	int64_t m = INT64_MAX;
-	for (size_t i=ix,i<ix+len; i++) {
-		if (a[i] < m) m = a[i];
+static size_t arrmin(vector<uint16_t> &a, size_t ix, size_t len) {
+	uint32_t m = UINT32_MAX;
+	size_t mi = 0;
+	for (size_t i=ix; i<ix+len; i++) {
+		if (a[i] < m) {
+			m = a[i];
+			mi = i;
+		}
 	}
-	return m;
+	return mi-ix;
+}
+
+static inline double fit_parabola(tuple<size_t,uint16_t> p, tuple<size_t,uint16_t> pl, tuple<size_t,uint16_t> pr) {
+	double a = get<1>(pr) - get<1>(pl);
+	double b = 2 * (2 * get<1>(p) - get<1>(pl) - get<1>(pr));
+	return static_cast<double>(get<0>(p)) + (a / b);
 }
 
-cv::Mat d_sub(vector<int64_t> dsi, size_t w, size_t h, size_t ds) {
+static cv::Mat d_sub(vector<uint16_t> &dsi, size_t w, size_t h, size_t ds) {
 	Mat result = Mat::zeros(Size(w,h), CV_64FC1);
+	
+	assert( dsi.size() == w*h*ds );
 
-	for (size_t v=0; v<w; v++) {
-	for (size_t u=0; u<h; u++) {
-		auto d_min = arrmin(dsi, v+u*w, ds);
-		decltype(d_min) d_sub;
+	for (size_t v=0; v<h; v++) {
+	const size_t vwds = v * w * ds;
+	for (size_t u=0; u<w; u++) {
+		const size_t uds = u*ds;
+		auto d_min = arrmin(dsi, vwds+uds, ds);
+		double d_sub;
 
 		if (d_min == 0 || d_min == ds-1) d_sub = d_min;
 		else {
-			Point p(d_min, dsi[v+u*w+d_min*w*h]);
-			Point pl(d_min-1, dsi[v+u*w+(d_min-1)*w*h]);
-			Point pr(d_min+1, dsi[v+u*w+(d_min+1)*w*h]);
+			auto p = make_tuple(d_min, dsi[d_min+vwds+uds]);
+			auto pl = make_tuple(d_min-1, dsi[d_min-1+vwds+uds]);
+			auto pr = make_tuple(d_min+1, dsi[d_min+1+vwds+uds]);
 
 			d_sub = fit_parabola(p,pl,pr);
 		}
 
-		result.at<uint8_t>(v,u) = d_sub;
+		result.at<double>(v,u) = d_sub;
 	}
 	}
 
@@ -119,16 +137,20 @@ void RTCensus::disparity(cv::Mat &l, cv::Mat &r, cv::Mat &disp, size_t num_disp,
 	size_t d_min = 0;
 	size_t d_max = num_disp;
 
-	auto census_R = sparse_census_16x16(l);
-	auto census_L = sparse_census_16x16(r);
+	auto census_R = sparse_census_16x16(r);
+	auto census_L = sparse_census_16x16(l);
+	LOG(INFO) << "Census done";
 
 	auto dsi_ca_R = dsi_ca(census_R, census_L, l.cols, l.rows, d_min, d_max);
 	auto dsi_ca_L = dsi_ca(census_L, census_R, l.cols, l.rows, d_min, d_max, -1);
+	LOG(INFO) << "DSI done";
 
-	auto disp_R = d_sub(dsi_ca_R);
-	auto disp_L = d_sub(dsi_ca_L);
+	auto disp_R = d_sub(dsi_ca_R, l.cols, l.rows, d_max-d_min);
+	auto disp_L = d_sub(dsi_ca_L, l.cols, l.rows, d_max-d_min);
+	LOG(INFO) << "Disp done";
 
-	disp = consistency(disp_R, disp_L);
+	disp = disp_L;
+	//disp = consistency(disp_R, disp_L);
 
 	// TODO confidence and texture filtering
 }