diff --git a/CMakeLists.txt b/CMakeLists.txt
index 47991799f0de39a238f10a18c28466b71c05b50c..b9baa55a9a0887646df1d30f66188f698ac68155 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -193,10 +193,10 @@ if (BUILD_CALIBRATION)
 endif()
 
 if (HAVE_PCL)
-	add_subdirectory(applications/registration)
+	#add_subdirectory(applications/registration)
 endif()
 
-if (BUILD_RECONSTRUCT AND HAVE_PCL)
+if (BUILD_RECONSTRUCT)
 	add_subdirectory(applications/reconstruct)
 endif()
 
diff --git a/applications/reconstruct/include/ftl/matrix_conversion.hpp b/applications/reconstruct/include/ftl/matrix_conversion.hpp
index ac0bff14da8ad6be553943db2c04f6b9ef22844f..2888e928ebbe13c54585837882e81ad9c32cdad9 100644
--- a/applications/reconstruct/include/ftl/matrix_conversion.hpp
+++ b/applications/reconstruct/include/ftl/matrix_conversion.hpp
@@ -2,7 +2,7 @@
 
 #pragma once
 
-#include <eigen3/Eigen/Eigen>
+#include <Eigen/Eigen>
 // #include "d3dx9math.h"
 #include <ftl/cuda_matrix_util.hpp>
 
diff --git a/applications/reconstruct/include/ftl/registration.hpp b/applications/reconstruct/include/ftl/registration.hpp
index 20f8eac6ab9ad751bc4021d6f5469d6480affb2d..1af4de8a5e3cbc8b64b291e4e115165e197cf28a 100644
--- a/applications/reconstruct/include/ftl/registration.hpp
+++ b/applications/reconstruct/include/ftl/registration.hpp
@@ -6,10 +6,6 @@
 #include <ftl/rgbd.hpp>
 #include <opencv2/opencv.hpp>
 
-#ifdef HAVE_PCL
-
-#include <pcl/common/common_headers.h>
-#include <pcl/point_cloud.h>
 
 namespace ftl {
 namespace registration {
@@ -20,187 +16,7 @@ void from_json(nlohmann::json &json, std::map<std::string, Eigen::Matrix4d> &tra
 bool loadTransformations(const std::string &path, std::map<std::string, Eigen::Matrix4d> &data);
 bool saveTransformations(const std::string &path, std::map<std::string, Eigen::Matrix4d> &data);
 
-/** @brief	Find transformation matrix for transforming clouds_source to clouds_target.
- *			Assumes that corresponding points in clouds_source[i] and clouds_target[i] have same indices.
- */
-Eigen::Matrix4f findTransformation(	std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> clouds_source,
-									std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> clouds_target);
-
-
-/** @brief Convert chessboard corners found with OpenCV's findChessboardCorners to PCL point cloud. */
-pcl::PointCloud<pcl::PointXYZ>::Ptr cornersToPointCloud(const std::vector<cv::Point2f> &corners, const cv::Mat &disp, const ftl::rgbd::Camera &p);
-
-/** @brief 	Find chessboard corners from image and store them in PCL PointCloud.
- * 	@note	Corners will be drawn in rgb.
- */
-bool findChessboardCorners(cv::Mat &rgb, const cv::Mat &depth, const ftl::rgbd::Camera &p, const cv::Size pattern_size, pcl::PointCloud<pcl::PointXYZ>::Ptr &out, float error_threshold);
-
-/**
- * @brief	Abstract class for registration
- * 
- * Registration procedure 
- * 
- * @todo	Support for multiple features (possibly necessary for other algorithms).
- */
-class Registration : public ftl::Configurable {
-public:
-	explicit Registration(nlohmann::json &config);
-	void addSource(ftl::rgbd::Source* source);
-	size_t getSourcesCount() { return sources_.size(); }
-
-	/**
-	 * @brief	Run registration loop. 
-	 * 
-	 * Loop terminates when processData() returns false.
-	 */
-	virtual void run();
-
-	/**
-	 * @brief	Find registration transformations. run() must be called before
-	 * 			findTransformations(). Transformations are in same order as
-	 * 			sources were added with addSource().
-	 * 
-	 * Transformations are calculated to targetsource if configured. If
-	 * targetsource is not configured or is not found in inputs, which target
-	 * coordinate system is used depends on sub-classes' implementation.
-	 * 
-	 * @param	Output parameter for transformations.
-	 * @return	True if transformations found, otherwise false.
-	 */
-	virtual bool findTransformations(std::vector<Eigen::Matrix4f> &data)=0;
-	
-	/**
-	 * @brief	Overload of findTransformations(). Map keys are source URIs.
-	 */
-	virtual bool findTransformations(std::map<std::string, Eigen::Matrix4f> &data);
-
-protected:
-	ftl::rgbd::Source* getSource(size_t idx);
-
-	bool isTargetSourceSet();
-	bool isTargetSourceFound();
-	bool isTargetSource(ftl::rgbd::Source* source); 
-	bool isTargetSource(size_t idx); 
-	
-	/**
-	 * @brief	Get index for target source. If target source not defined
-	 * 			returns 0. If target source is not found, returns 0.
-	 */
-	size_t getTargetSourceIdx();
-	
-	/**
-	 * @brief	Resets visibility matrix.
-	 */
-	void resetVisibility();
-
-	/**
-	 * @brief	Check if there is enough data to cover all the cameras;
-	 * 			that is visibility is a connected graph. Implemented with BFS.
-	 * 			Implementations of processData() in sub-classes may use this
-	 * 			method (but it is not required).
-	 * 
-	 * @todo	Add support for checking visibility for each different features
-	 * 			found in all images. Also see findFeatures().
-	 */
-	bool connectedVisibility();
-
-	/**
-	 * @brief	Check if there are enough data for all the sources to calculate
-	 * 			transformations. Method may also implement additional processing
-	 * 			for the data. Called once after iteration round. run() stops
-	 * 			when processData() returns false.
-	 */
-	virtual bool processData()=0;
-
-	/**
-	 * @brief	Find features in source, return 
-	 * 
-	 * Called iteratively n times for every input (n * inputs.size()). Exact
-	 * details depend on implementation of processData(). Implementations may
-	 * choose not to set/use visibility information.
-	 * 
-	 * @param	Input source
-	 * @param	Unique index for source provided by run(). Same source will
-	 * 			always have same idx. Implementations may choose to ignore it.
-	 * @return	True/false if feature was found. Used to build adjacency matrix.
-	 */
-	virtual bool findFeatures(ftl::rgbd::Source* source, size_t idx)=0;
-
-	std::vector<std::vector<bool>> visibility_; /*< Adjacency matrix for sources (feature visibility). */
-
-private:
-	std::optional<std::string> target_source_; /*< Reference coordinate system for transformations. */
-	std::vector<ftl::rgbd::Source*> sources_;
-};
-
-/**
- * @brief	Registration using chessboard calibration pattern
- * 
- * Parameters from configuration:
- * 
- * 		patternsize: required
- * 			Chessboard pattern size, inner corners.
- * 
- * 		maxerror: default +inf
- * 			Maximum allowed error value for pattern detection. MSE error between
- * 			estimated plane and points captured from input.
- * 
- * 		delay:	default 500
- * 			Milliseconds between captured images.
- * 
- * 		chain: default false
- * 			Enabling allows camera chaining. In chain mode, pattern is not
- * 			required to be visible in every source. In default (chain: false)
- * 			mode, pattern visibility is required for every source.
- * 
- * 		iter: default 10
- * 			Number of iterations for capturing calibration samples. In
- * 			non-chaining mode, each iteration consists of images where patterns
- * 			were detected on every input. In chaining mode each iteration only
- * 			requires camera visibility to be connected.
- */
-class ChessboardRegistration : public Registration {
-public:
-	explicit ChessboardRegistration(nlohmann::json &config);
-	/** 
-	 * @brief	Creates new ChessboardRegistration or ChessboardRegistrationChain
-	 * 			object depending on chain option in config. User of the method
-	 * 			needs to free the memory.
-	 */
-	static ChessboardRegistration* create(nlohmann::json &config);
-
-	void run() override;
-	bool findTransformations(std::vector<Eigen::Matrix4f> &data) override;
-
-protected:
-	bool findFeatures(ftl::rgbd::Source* source, size_t idx) override;
-	bool processData() override;
-	cv::Size pattern_size_;
-	std::vector<std::vector<std::optional<pcl::PointCloud<pcl::PointXYZ>::Ptr>>> data_;
-	std::vector<Eigen::Matrix4f> T_;
-	float error_threshold_;
-	uint delay_;
-	uint iter_;
-	uint iter_remaining_;
-};
-
-/**
- * @brief Chain registration. Finds visibility and then runs registration.
- */
-class ChessboardRegistrationChain : public ChessboardRegistration {
-public:
-	explicit ChessboardRegistrationChain(nlohmann::json &config);
-	
-	bool findTransformations(std::vector<Eigen::Matrix4f> &data) override;
-
-protected:
-	bool processData() override;
-	std::vector<Eigen::Matrix4f> T_;
-	std::vector<std::vector<std::pair<size_t, size_t>>> edges_;
-};
-
 }
 }
 
-#endif  // HAVE_PCL
 #endif  // _FTL_RECONSTRUCT_REGISTRATION_HPP_
\ No newline at end of file
diff --git a/applications/reconstruct/src/integrators.cu b/applications/reconstruct/src/integrators.cu
index 326c3dd9a59cd776e254149d47e02c684e1d6d36..d23fada9982aed2ff49039aa91bfa8760f91fcd1 100644
--- a/applications/reconstruct/src/integrators.cu
+++ b/applications/reconstruct/src/integrators.cu
@@ -39,7 +39,7 @@ __device__ float colourDistance(const uchar4 &c1, const uchar3 &c2) {
 __device__ bool colordiff(const uchar4 &pa, const uchar3 &pb, float epsilon) {
 	float x_2 = pb.x * pb.x + pb.y * pb.y + pb.z * pb.z;
 	float v_2 = pa.x * pa.x + pa.y * pa.y + pa.z * pa.z;
-	float xv_2 = pow(pb.x * pa.x + pb.y * pa.y + pb.z * pa.z, 2);
+	float xv_2 = powf(float(pb.x * pa.x + pb.y * pa.y + pb.z * pa.z), 2.0f);
 	float p_2 = xv_2 / v_2;
 	return sqrt(x_2 - p_2) < epsilon;
 }
diff --git a/applications/reconstruct/src/mls.cu b/applications/reconstruct/src/mls.cu
index 71201a017cf1ebab6e06257e9425403df50427d3..4de8a07db023d21620f605cd3556913aeafe06cb 100644
--- a/applications/reconstruct/src/mls.cu
+++ b/applications/reconstruct/src/mls.cu
@@ -27,7 +27,7 @@ extern __constant__ HashParams c_hashParams;
  __device__ float colordiffFloat(const uchar4 &pa, const uchar4 &pb) {
 	const float x_2 = pb.x * pb.x + pb.y * pb.y + pb.z * pb.z;
 	const float v_2 = pa.x * pa.x + pa.y * pa.y + pa.z * pa.z;
-	const float xv_2 = pow(pb.x * pa.x + pb.y * pa.y + pb.z * pa.z, 2);
+	const float xv_2 = powf(float(pb.x * pa.x + pb.y * pa.y + pb.z * pa.z), 2.0f);
 	const float p_2 = xv_2 / v_2;
 	return sqrt(x_2 - p_2);
 }
diff --git a/applications/reconstruct/src/registration.cpp b/applications/reconstruct/src/registration.cpp
index 5b828242e168e08c9524e02470c7d187ff4a1279..23ae7e746aaa0b5a1d6c76920a79d366c0a0a310 100644
--- a/applications/reconstruct/src/registration.cpp
+++ b/applications/reconstruct/src/registration.cpp
@@ -1,26 +1,8 @@
 #include <ftl/registration.hpp>
 
-#ifdef HAVE_PCL
-
 #define LOGURU_WITH_STREAMS 1
 #include <loguru.hpp>
-#include <pcl/common/transforms.h>
-
-#include <pcl/registration/transformation_estimation_svd.h>
-#include <pcl/registration/transformation_estimation_svd_scale.h>
-
-#include <pcl/segmentation/sac_segmentation.h>
-#include <pcl/sample_consensus/method_types.h>
-#include <pcl/sample_consensus/model_types.h>
-#include <pcl/filters/project_inliers.h>
-#include <pcl/ModelCoefficients.h>
 
-#include <pcl/io/pcd_io.h>
-
-#include <pcl/registration/transformation_validation.h>
-#include <pcl/registration/transformation_validation_euclidean.h>
-#include <pcl/common/geometry.h>
-//#include <pcl/registration/icp_nl.h>
 
 namespace ftl {
 namespace registration {
@@ -34,10 +16,6 @@ using std::pair;
 using std::map;
 using std::optional;
 
-using pcl::PointCloud;
-using pcl::PointXYZ;
-using pcl::PointXYZRGB;
-
 using cv::Mat;
 using Eigen::Matrix4f;
 using Eigen::Matrix4d;
@@ -86,489 +64,6 @@ bool saveTransformations(const string &path, map<string, Matrix4d> &data) {
 	return true;
 }
 
-// todo template: fitPlane<typename T>(PointCloud<T> cloud_in, PointCloud<T> cloud_out)
-//
-// Fit calibration pattern into plane using RANSAC + project points
-//
-pcl::ModelCoefficients::Ptr fitPlane(PointCloud<PointXYZ>::Ptr cloud_in, float distance_threshold=5.0) {
-	// TODO: include pattern in model (find best alignment of found points and return transformed reference?)
-	
-	pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
-	pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
-	
-	// Estimate plane with RANSAC
-	pcl::SACSegmentation<PointXYZ> seg;
-	
-	seg.setOptimizeCoefficients(true);
-	seg.setModelType(pcl::SACMODEL_PLANE);
-	seg.setMethodType(pcl::SAC_RANSAC);
-	seg.setDistanceThreshold(distance_threshold);
-	seg.setInputCloud(cloud_in);
-	seg.segment(*inliers, *coefficients);
-	
-	return coefficients;
-}
-
-float fitPlaneError(PointCloud<PointXYZ>::Ptr cloud_in, float distance_threshold=5.0) {
-	auto coefficients = fitPlane(cloud_in, distance_threshold);
-	PointCloud<PointXYZ> cloud_proj;
-	
-	// Project points into plane
-	pcl::ProjectInliers<PointXYZ> proj;
-	proj.setModelType(pcl::SACMODEL_PLANE);
-	proj.setInputCloud(cloud_in);
-	proj.setModelCoefficients(coefficients);
-	proj.filter(cloud_proj); 
-	
-	CHECK(cloud_in->size() == cloud_proj.size());
-	
-	// todo: which error score is suitable? (using MSE)
-	float score = 0.0;
-	for(size_t i = 0; i < cloud_proj.size(); i++) {
-		float d = pcl::geometry::distance(cloud_in->points[i], cloud_proj.points[i]);
-		score += d * d;
-	}
-	
-	return (score / cloud_proj.size()) * 10000000.0f;
-}
-
-//template<typename T = PointXYZ> typename
-PointCloud<PointXYZ>::Ptr cornersToPointCloud(const vector<cv::Point2f> &corners, const Mat &depth, const Camera &p) {
-	
-	int corners_len = corners.size();
-	vector<cv::Vec3f> points(corners_len);
-
-	const double CX = p.cx;
-	const double CY = p.cy;
-	const double FX = p.fx;
-	const double FY = p.fy;
-	
-	// Output point cloud
-	PointCloud<PointXYZ>::Ptr cloud(new PointCloud<PointXYZ>);
-	cloud->width = corners_len;
-	cloud->height = 1;
-	
-	// Follows cv::reprojectImageTo3D(..)
-	// https://github.com/opencv/opencv/blob/371bba8f54560b374fbcd47e7e02f015ac4969ad/modules/calib3d/src/calibration.cpp#L2998
-	// documentation suggests using cv::perspectiveTransform(...) with sparse set of points
-	
-	for (int i = 0; i < corners_len; i++) {
-		double x = corners[i].x;
-		double y = corners[i].y;
-		double d = depth.at<float>((int) y, (int) x); // * 1000.0f; // todo: better estimation
-		
-		//cv::Vec4d homg_pt = Q_ * cv::Vec4d(x, y, d, 1.0);
-		//cv::Vec3d p = cv::Vec3d(homg_pt.val) / homg_pt[3];
-
-		PointXYZ point;
-		point.x = (((double)x + CX) / FX) * d; // / 1000.0f;
-		point.y = (((double)y + CY) / FY) * d; // / 1000.0f;
-		point.z = d;
-		
-		cloud->push_back(point);
-	}
-	
-	return cloud;
-}
-
-bool findChessboardCorners(Mat &rgb, const Mat &depth, const Camera &p, const cv::Size pattern_size, PointCloud<PointXYZ>::Ptr &out, float error_threshold) {
-	vector<cv::Point2f> corners(pattern_size.width * pattern_size.height);
-
-#if CV_VERSION_MAJOR >= 4
-	bool retval = cv::findChessboardCornersSB(rgb, pattern_size, corners);
-#else
-	bool retval = cv::findChessboardCorners(rgb, pattern_size, corners);
-#endif
-
-	cv::drawChessboardCorners(rgb, pattern_size, Mat(corners), retval);
-	if (!retval) { return false; }
-	
-	auto corners_cloud = cornersToPointCloud(corners, depth, p);
-	// simple check that the values make some sense
-	float error = fitPlaneError(corners_cloud, error_threshold); // should use different parameter?
-	LOG(INFO) << "MSE against estimated plane: " << error;
-	
-	if (error > error_threshold) {
-		LOG(WARNING) << "too high error score for calibration pattern, threshold " << error_threshold;
-		return false;
-	}
-	
-	if (out) { *out += *corners_cloud; } // if cloud is valid, add the points
-	else { out = corners_cloud; }
-	return true;
-}
-
-Eigen::Matrix4f findTransformation(vector<PointCloud<PointXYZ>::Ptr> clouds_source, vector<PointCloud<PointXYZ>::Ptr> clouds_target) {
-	size_t n_clouds = clouds_source.size();
-	
-	Eigen::Matrix4f T, T_tmp, T_new;
-	T.setIdentity();
-	
-	if ((clouds_source.size() != clouds_target.size()) || (n_clouds == 0)) {
-		LOG(ERROR) << "Input vectors have invalid sizes: clouds_source " << clouds_source.size()
-					<< ", clouds_target " << clouds_target.size() << ", transformation can not be estimated";
-		
-		return T; // identity
-	}
-	
-	// corresponding points have same indices (!!!)
-	int n_points = clouds_source[0]->width * clouds_source[0]->height;
-	vector<int> idx(n_points);
-	for (int i = 0; i < n_points; i++) { idx[i] = i; }
-	
-	pcl::registration::TransformationValidationEuclidean<PointXYZ, PointXYZ> validate;
-	pcl::registration::TransformationEstimationSVD<PointXYZ,PointXYZ> svd;
-	
-	double score_prev = std::numeric_limits<float>::max();
-	
-	for (size_t i = 0; i < n_clouds; ++i) {
-		PointCloud<PointXYZ> source;
-		PointCloud<PointXYZ> target = *clouds_target[i];
-		
-		pcl::transformPointCloud(*clouds_source[i], source, T);
-		svd.estimateRigidTransformation(source, idx, target, idx, T_new);
-		
-		// calculate new transformation
-		T_tmp = T_new * T;
-		
-		// score new transformation
-		double score = 0.0;
-		for (size_t j = 0; j < n_clouds; ++j) {
-			score += validate.validateTransformation(clouds_source[j], clouds_target[j], T_tmp); // CHECK Is use of T here a mistake??
-		}
-		score /= n_clouds;
-		
-		// if score doesn't improve, do not use as T, otherwise update T and score
-		if (score < score_prev) {
-			T = T_tmp;
-			score_prev = score;
-		}
-		
-		LOG(INFO) << "Validation score: " << score;
-	}
-	
-	return T;
-}
-
-Registration::Registration(nlohmann::json &config) :
-	ftl::Configurable(config) {
-	target_source_ = get<string>("targetsource");
-	if (!target_source_) {
-		LOG(WARNING) << "targetsource not set";
-	}
-}
-
-Source* Registration::getSource(size_t idx) {
-	return sources_[idx];
-}
-
-bool Registration::isTargetSourceSet() {
-	return (bool) target_source_;
-}
-
-bool Registration::isTargetSourceFound() {
-	for (Source* source : sources_ ) {
-		if (isTargetSource(source)) return true;
-	}
-	return false;
-}
-
-bool Registration::isTargetSource(Source *source) {
-	if (target_source_) { return source->getID() == *target_source_; }
-	return false;
-}
-
-bool Registration::isTargetSource(size_t idx) {
-	if (idx >= sources_.size()) return false; // assert
-	return isTargetSource(sources_[idx]);
-}
-
-size_t Registration::getTargetSourceIdx() {
-	if (!target_source_) return 0;
-	for (size_t idx = 0; idx < sources_.size(); ++idx) {
-		if (isTargetSource(sources_[idx])) return idx;
-	}
-
-	return 0;
-}
-
-void Registration::addSource(Source *source) {
-	// TODO: check that source is not already included
-	sources_.push_back(source);
-}
-
-/**
- * @param	adjacency matrix
- * @param	index of starting vertex
- * @param	(out) edges connecting each level
- * @returns	true if graph connected (all vertices visited), otherwise false
- * 
- * Breadth First Search
- */
-bool isConnected(vector<vector<bool>> matrix, size_t start_idx, vector<vector<pair<size_t, size_t>>> &edges) {
-vector<bool> visited(matrix.size(), false);
-	DCHECK(start_idx < matrix.size());
-
-	edges.clear();
-	vector<size_t> level { start_idx };
-
-	visited[start_idx] = true;
-	size_t visited_count = 1;
-	
-	while(level.size() != 0) {
-		vector<size_t> level_prev = level;
-		level = {};
-
-		vector<pair<size_t, size_t>> new_edges;
-
-		for (size_t current : level_prev) {
-		for (size_t i = 0; i < matrix.size(); ++i) {
-			if (matrix[current][i] && !visited[i]) {
-				visited[i] = true;
-				visited_count += 1;
-				level.push_back(i);
-				// could also save each level's vertices
-
-				new_edges.push_back(pair(current, i));
-			}
-		}}
-		if (new_edges.size() > 0) edges.push_back(new_edges);
-	}
-
-	return visited_count == matrix.size();
-}
-
-bool isConnected(vector<vector<bool>> matrix, size_t start_idx = 0) {
-	vector<vector<pair<size_t, size_t>>> edges;
-	return isConnected(matrix, start_idx, edges);
-}
-
-/**
- * @param	Adjacency matrix
- * @returns	Vector containing degree of each vertex
-*/
-vector<uint> verticleDegrees(vector<vector<bool>> matrix) {
-	vector<uint> res(matrix.size(), 0);
-	for (size_t i = 0; i < matrix.size(); ++i) {
-	for (size_t j = 0; j < matrix.size(); ++j) {
-		if (matrix[i][j]) res[i] = res[i] + 1;
-	}}
-	return res;
-}
-
-bool Registration::connectedVisibility() {
-	return isConnected(visibility_, getTargetSourceIdx());
-}
-
-void Registration::resetVisibility() {
-	visibility_ = vector(sources_.size(), vector<bool>(sources_.size(), false));
-}
-
-void Registration::run() {
-	resetVisibility();
-
-	do {
-		vector<bool> visible(sources_.size(), false);
-
-		for (size_t i = 0; i < sources_.size(); ++i) {
-			bool retval = findFeatures(sources_[i], i);
-			visible[i] = retval;
-		}
-
-		for (size_t i = 0; i < visible.size(); ++i) {
-		for (size_t j = 0; j < visible.size(); ++j) {
-			bool val = visible[i] && visible[j];
-			visibility_[i][j] = visibility_[i][j] || val;
-			visibility_[j][i] = visibility_[j][i] || val;
-		}}
-	}
-	while(processData());
-}
-
-bool Registration::findTransformations(map<string, Matrix4f> &data) {
-	vector<Matrix4f> T;
-	data.clear();
-
-	if (!findTransformations(T)) return false;
-	for (size_t i = 0; i < sources_.size(); ++i) {
-		data[sources_[i]->getURI()] = T[i];
-	}
-	return true;
-}
-
-ChessboardRegistration* ChessboardRegistration::create(nlohmann::json &config) {
-	if (config.value<bool>("chain", false)) {
-		return new ChessboardRegistrationChain(config);
-	}
-	else {
-		return new ChessboardRegistration(config);
-	}
-}
-
-ChessboardRegistration::ChessboardRegistration(nlohmann::json &config) :
-	Registration(config) {
-	
-	auto patternsize = get<vector<int>>("patternsize");
-	if (!patternsize) { LOG(FATAL) << "Registration run enabled but pattern size not set"; }
-	pattern_size_ = cv::Size((*patternsize)[0], (*patternsize)[1]);
-	
-	auto maxerror = get<float>("maxerror");
-	if (!maxerror) { LOG(WARNING) << "maxerror not set"; }
-	auto delay = get<int>("delay");
-	if (!delay) { LOG(INFO) << "delay not set in configuration"; }
-	auto iter = get<int>("iterations");
-	if (!iter) { LOG(INFO) << "iterations not set in configuration"; }
-	auto chain = get<bool>("chain");
-	if (!chain) { LOG(INFO) << "input chaining disabled"; }
-	else { LOG(INFO) << "Input chaining enabled"; }
-
-	error_threshold_ = maxerror ? *maxerror : std::numeric_limits<float>::infinity();
-	iter_ = iter ? *iter : 10;
-	delay_ = delay ? *delay : 50;
-}
-
-void ChessboardRegistration::run() {
-	if (!isTargetSourceFound()) {
-		LOG(WARNING) << "targetsource not found in sources";
-	}
-
-	if (data_.size() != getSourcesCount()) {
-		data_ = vector<vector<optional<PointCloud<PointXYZ>::Ptr>>>(getSourcesCount());
-	}
-	iter_remaining_ = iter_;
-
-	// TODO: Move GUI elsewhere. Also applies to processData() and findFeatures()
-	for (size_t i = 0; i < getSourcesCount(); ++i) { 
-		cv::namedWindow("Registration: " + getSource(i)->getID(),
-						cv::WINDOW_KEEPRATIO|cv::WINDOW_NORMAL);
-	}
-
-	Registration::run();
-
-	for (size_t i = 0; i < getSourcesCount(); ++i) { 
-		cv::destroyWindow("Registration: " + getSource(i)->getID());
-	}
-}
-
-bool ChessboardRegistration::findFeatures(Source *source, size_t idx) {
-	optional<PointCloud<PointXYZ>::Ptr> result;
-	PointCloud<PointXYZ>::Ptr cloud(new PointCloud<PointXYZ>);
-
-	Mat rgb, depth;
-	source->grab();
-	source->getFrames(rgb, depth);
-
-	bool retval = findChessboardCorners(rgb, depth, source->parameters(), pattern_size_, cloud, error_threshold_);
-	if (retval) {
-		result.emplace(cloud);
-	}
-	data_[idx].push_back(result);
-	
-	cv::imshow("Registration: " + source->getID(), rgb);
-
-	return retval;
-}
-
-bool ChessboardRegistration::processData() {
-	bool retval = connectedVisibility();
-	resetVisibility();
-
-	if (retval) {
-		iter_remaining_--;
-	}
-	else{
-		LOG(INFO) << "Pattern not visible in all inputs";
-		for (auto &sample : data_) { sample.pop_back(); }
-	}
-
-	//std::this_thread::sleep_for(std::chrono::milliseconds(delay_));
-	cv::waitKey(delay_); // OpenCV GUI doesn't show otherwise
-
-	return iter_remaining_ > 0;
-}
-
-bool ChessboardRegistration::findTransformations(vector<Matrix4f> &data) {
-	data.clear();
-	vector<bool> status(getSourcesCount(), false);
-	size_t idx_target = getTargetSourceIdx();
-
-	for (size_t idx = 0; idx < getSourcesCount(); ++idx) {
-		Matrix4f T;
-		if (idx == idx_target) {
-			T.setIdentity(); 
-		}
-		else {
-			vector<PointCloud<PointXYZ>::Ptr> d;
-			vector<PointCloud<PointXYZ>::Ptr> d_target;
-			d.reserve(iter_);
-			d_target.reserve(iter_);
-			
-			for (size_t i = 0; i < iter_; ++i) {
-				auto val = data_[idx][i];
-				auto val_target = data_[idx_target][i];
-				if (val && val_target) {
-					d.push_back(*val);
-					d_target.push_back(*val_target);
-				}
-			}
-			T = findTransformation(d, d_target); 
-		}
-		data.push_back(T);
-	}
-	return true;
-}
-
-ChessboardRegistrationChain::ChessboardRegistrationChain(nlohmann::json &config) :
-							ChessboardRegistration(config) {
-		error_threshold_ = std::numeric_limits<float>::infinity();
-}
-
-bool ChessboardRegistrationChain::processData() {
-	for (auto &sample : data_ ) { sample.clear(); }
-	bool retval = isConnected(visibility_, getTargetSourceIdx(), edges_);
-	
-	if (retval) {
-		LOG(INFO) << "Chain complete, depth: " << edges_.size();
-		return false;
-	}
-	else{
-		LOG(5) << "Chain not complete ";
-	}
-
-	return true;
-}
-
-bool ChessboardRegistrationChain::findTransformations(vector<Matrix4f> &data) {
-	// TODO	Change to group registration: register all sources which have visibility
-	//		to the target source in chain.
-
-	LOG(INFO) << "Running pairwise registration";
-	data = vector<Matrix4f>(getSourcesCount(), Matrix4f::Identity());
-
-	for (vector<pair<size_t, size_t>> level : edges_) {
-		for (pair<size_t, size_t> edge : level) {
-			LOG(INFO) 	<< "Registering source "
-						<< getSource(edge.second)->getID() << " to source"
-						<< getSource(edge.first)->getID();
-			
-			nlohmann::json conf(getConfig());
-			conf["targetsource"] = getSource(edge.first)->getID();
-			conf["chain"] = false;
-
-			vector<Matrix4f> result;
-			ChessboardRegistration reg(conf);
-			reg.addSource(getSource(edge.first));
-			reg.addSource(getSource(edge.second));
-			reg.run();
-			if (!reg.findTransformations(result)) { return false; }
-			data[edge.second] = data[edge.first] * result[1];
-		}
-	}
-	
-	return true;
-}
 
 } // namespace registration
 } // namespace ftl
-
-#endif // HAVE_PCL
\ No newline at end of file