diff --git a/components/operators/include/ftl/operators/cuda/disparity.hpp b/components/operators/include/ftl/operators/cuda/disparity.hpp
index de4648f6f4c4d2dfe8681aea6a96d7fbc40b40af..75034d9e1808e6023712988e1a66ec2d8f118a0d 100644
--- a/components/operators/include/ftl/operators/cuda/disparity.hpp
+++ b/components/operators/include/ftl/operators/cuda/disparity.hpp
@@ -19,6 +19,16 @@ void mask_occlusions(const cv::cuda::GpuMat &depth,
 		cv::cuda::GpuMat &mask,
 		const ftl::rgbd::Camera &c, cudaStream_t stream);
 
+void check_reprojection(const cv::cuda::GpuMat &disp,
+			const ftl::cuda::TextureObject<uchar4> &left, const ftl::cuda::TextureObject<uchar4> &right,
+			cudaStream_t stream);
+
+void show_rpe(const cv::cuda::GpuMat &disp, cv::cuda::GpuMat &left, const cv::cuda::GpuMat &right,
+			float scale, cudaStream_t stream);
+
+void show_disp_density(const cv::cuda::GpuMat &disp, cv::cuda::GpuMat &left,
+			float scale, cudaStream_t stream);
+
 
 void optflow_filter(cv::cuda::GpuMat &disp, const cv::cuda::GpuMat &optflow,
 					cv::cuda::GpuMat &history, cv::cuda::GpuMat &support, int n_max, float threshold, bool fill,
diff --git a/components/operators/src/disparity/disp2depth.cu b/components/operators/src/disparity/disp2depth.cu
index c0011adf4d92ea9d30a4f56e1ad9ccbe4c06b976..bed3bc3e88dbeb83fdbcd35b78ec31abad76c019 100644
--- a/components/operators/src/disparity/disp2depth.cu
+++ b/components/operators/src/disparity/disp2depth.cu
@@ -137,3 +137,107 @@ void ftl::cuda::mask_occlusions(const cv::cuda::GpuMat &depth, const cv::cuda::G
 		depth, depthR, mask, c);
 	cudaSafeCall( cudaGetLastError() );
 }
+
+
+// =============================================================================
+
+__global__ void check_reprojection_kernel(cv::cuda::PtrStepSz<short> disp,
+	ftl::cuda::TextureObject<uchar4> left,
+	ftl::cuda::TextureObject<uchar4> right)
+{
+	for (STRIDE_Y(v,disp.rows)) {
+	for (STRIDE_X(u,disp.cols)) {
+		const float d = float(disp(v,u)) / 16.0f;
+		const float4 l = left.tex2D(float(u)+0.5f, float(v)+0.5f);
+
+		if (d > 0) {
+			const float4 r = right.tex2D(float(u-d)+0.5f, float(v)+0.5f);
+			const float diff = max(fabsf(l.x-r.x),max(fabsf(l.y-r.y), fabsf(l.z-r.z)));
+			if (diff > 10.0f) disp(v,u) = 0;
+		}
+	}
+	}
+}
+
+void ftl::cuda::check_reprojection(const cv::cuda::GpuMat &disp, const ftl::cuda::TextureObject<uchar4> &left, const ftl::cuda::TextureObject<uchar4> &right, cudaStream_t stream) {
+	dim3 grid(1,1,1);
+	dim3 threads(128, 4, 1);
+	grid.x = cv::cuda::device::divUp(disp.cols, 128);
+	grid.y = cv::cuda::device::divUp(disp.rows, 4);
+
+	check_reprojection_kernel<<<grid, threads, 0, stream>>>(disp, left, right);
+
+	cudaSafeCall( cudaGetLastError() );
+}
+
+
+// =============================================================================
+
+
+__global__ void show_rpe_kernel(cv::cuda::PtrStepSz<short> disp,
+	cv::cuda::PtrStepSz<uchar4> left,
+	cv::cuda::PtrStepSz<uchar4> right,
+	float scale)
+{
+	for (STRIDE_Y(v,left.rows)) {
+	for (STRIDE_X(u,left.cols)) {
+		short d = disp(v,u) / 16;
+
+		if (d > 0 && u-d >= 0) {
+			uchar4 l = left(v,u);
+			uchar4 r = right(v,u-d);
+			float d = max(abs(int(l.x)-int(r.x)),max(abs(int(l.y)-int(r.y)), abs(int(l.z)-int(r.z))));
+
+			left(v,u) = make_uchar4(0,0,min(255.0f, (d/scale) * 255.0f),255);
+		}
+	}
+	}
+}
+
+void ftl::cuda::show_rpe(const cv::cuda::GpuMat &disp, cv::cuda::GpuMat &left, const cv::cuda::GpuMat &right,
+			float scale, cudaStream_t stream) {
+	dim3 grid(1,1,1);
+	dim3 threads(128, 4, 1);
+	grid.x = cv::cuda::device::divUp(disp.cols, 128);
+	grid.y = cv::cuda::device::divUp(disp.rows, 4);
+	show_rpe_kernel<<<grid, threads, 0, stream>>>(
+		disp, left, right, scale);
+	cudaSafeCall( cudaGetLastError() );
+}
+
+// =============================================================================
+
+
+template <int MAX_DISP>
+__global__ void show_disp_density_kernel(cv::cuda::PtrStepSz<short> disp,
+	cv::cuda::PtrStepSz<uchar4> left,
+	float scale)
+{
+	for (STRIDE_Y(v,disp.rows)) {
+	for (STRIDE_X(u,disp.cols)) {
+		short d = disp(v,u) / 16;
+		int count = 0;
+
+		for (int i=1; i<MAX_DISP; ++i) {
+			if (u+i-d < disp.cols && u+i-d >= 0) {
+				short dd = disp(v,u+i-d) / 16;
+				if (d > 0 && dd == i) ++count;
+			}
+		}
+
+		count = max(0,count-1);
+		left(v,u) = make_uchar4(0,0,min(255.0f, (float(count)/4.0f) * 255.0f),255);
+	}
+	}
+}
+
+void ftl::cuda::show_disp_density(const cv::cuda::GpuMat &disp, cv::cuda::GpuMat &left,
+			float scale, cudaStream_t stream) {
+	dim3 grid(1,1,1);
+	dim3 threads(128, 4, 1);
+	grid.x = cv::cuda::device::divUp(disp.cols, 128);
+	grid.y = cv::cuda::device::divUp(disp.rows, 4);
+	show_disp_density_kernel<256><<<grid, threads, 0, stream>>>(
+		disp, left, scale);
+	cudaSafeCall( cudaGetLastError() );
+}
diff --git a/components/operators/src/disparity/fixstars_sgm.cpp b/components/operators/src/disparity/fixstars_sgm.cpp
index a473585ec935419684df68fa66cd825ef87a03fe..b55a7af6d7f7c4b006f1e8988aa4369be7db82e9 100644
--- a/components/operators/src/disparity/fixstars_sgm.cpp
+++ b/components/operators/src/disparity/fixstars_sgm.cpp
@@ -1,6 +1,7 @@
 #include <loguru.hpp>
 
 #include "ftl/operators/disparity.hpp"
+#include <ftl/operators/cuda/disparity.hpp>
 
 #include <opencv2/cudaimgproc.hpp>
 #include <opencv2/cudaarithm.hpp>
@@ -146,7 +147,7 @@ bool FixstarsSGM::apply(Frame &in, Frame &out, cudaStream_t stream) {
 		return false;
 	}
 
-	const auto &l = in.get<GpuMat>(Channel::Left);
+	auto &l = in.get<GpuMat>(Channel::Left);
 	const auto &r = in.get<GpuMat>(Channel::Right);
 
 	if (l.size() != size_) {
@@ -170,9 +171,21 @@ bool FixstarsSGM::apply(Frame &in, Frame &out, cudaStream_t stream) {
 
 	cv::cuda::threshold(disp_int_, disp, 4096.0f, 0.0f, cv::THRESH_TOZERO_INV, cvstream);
 
+	if (config()->value("check_reprojection", false)) {
+		ftl::cuda::check_reprojection(disp, in.getTexture<uchar4>(Channel::Colour),
+			in.createTexture<uchar4>(Channel::Colour2, true),
+			stream);
+	}
+
 	if (config()->value("show_P2_map", false)) {
 		cv::cuda::cvtColor(P2_map_, out.get<GpuMat>(Channel::Colour), cv::COLOR_GRAY2BGRA);
 	}
+	if (config()->value("show_rpe", false)) {
+		ftl::cuda::show_rpe(disp, l, r, 100.0f, stream);
+	}
+	if (config()->value("show_disp_density", false)) {
+		ftl::cuda::show_disp_density(disp, l, 100.0f, stream);
+	}
 
 	//disp_int_.convertTo(disp, CV_32F, 1.0f / 16.0f, cvstream);
 	return true;