diff --git a/applications/reconstruct/src/main.cpp b/applications/reconstruct/src/main.cpp
index 8954a4c62ff980c163f4c83fc9f7e77adb4b0f7e..d8dd66b59323d5ddf5aa0f136f4c25f83213441a 100644
--- a/applications/reconstruct/src/main.cpp
+++ b/applications/reconstruct/src/main.cpp
@@ -250,20 +250,18 @@ static void run(ftl::Configurable *root) {
 	bool busy = false;
 
 	// Create the source depth map pipeline
-	auto *prefilter = ftl::config::create<ftl::operators::Graph>(root, "pre_filters");
-	prefilter->append<ftl::operators::ColourChannels>("colour");
-	prefilter->append<ftl::operators::HFSmoother>("hfnoise");
-	prefilter->append<ftl::operators::Normals>("normals");
-	prefilter->append<ftl::operators::SimpleMLS>("mls");
+	auto *pipeline1 = ftl::config::create<ftl::operators::Graph>(root, "pre_filters");
+	pipeline1->append<ftl::operators::ColourChannels>("colour");  // Convert BGR to BGRA
+	pipeline1->append<ftl::operators::HFSmoother>("hfnoise");  // Remove high-frequency noise
+	pipeline1->append<ftl::operators::Normals>("normals");  // Estimate surface normals
+	pipeline1->append<ftl::operators::SmoothChannel>("smoothing");  // Generate a smoothing channel
+	pipeline1->append<ftl::operators::SimpleMLS>("mls");  // Perform MLS (using smoothing channel)
 	// Alignment
 
-	//auto *postfilter = ftl::config::create<ftl::Filters>(root, "post_filters");
-	//postfilter->create<ftl::filters::DepthSmoother>("hfnoise");
-	//postfilter->create<ftl::filters::MLSSmoother>("mls");
 
 	group->setLatency(4);
 	group->setName("ReconGroup");
-	group->sync([splat,virt,&busy,&slave,&scene_A,&scene_B,&align,controls,prefilter](ftl::rgbd::FrameSet &fs) -> bool {
+	group->sync([splat,virt,&busy,&slave,&scene_A,&scene_B,&align,controls,pipeline1](ftl::rgbd::FrameSet &fs) -> bool {
 		//cudaSetDevice(scene->getCUDADevice());
 
 		//if (slave.isPaused()) return true;
@@ -278,32 +276,16 @@ static void run(ftl::Configurable *root) {
 		// Swap the entire frameset to allow rapid return
 		fs.swapTo(scene_A);
 
-		ftl::pool.push([&scene_B,&scene_A,&busy,&slave,&align, prefilter](int id) {
+		ftl::pool.push([&scene_B,&scene_A,&busy,&slave,&align, pipeline1](int id) {
 			//cudaSetDevice(scene->getCUDADevice());
 			// TODO: Release frameset here...
 			//cudaSafeCall(cudaStreamSynchronize(scene->getIntegrationStream()));
 
 			UNIQUE_LOCK(scene_A.mtx, lk);
 
-			// Apply pre-filters to all frames
-			/*for (int i=0; i<scene_A.frames.size(); ++i) {
-				auto &f = scene_A.frames[i];
-				auto s = scene_A.sources[i];
-				prefilter->apply(f, f, s, 0);
-			}*/
-
-			prefilter->apply(scene_A, scene_A, 0);
-
-			// Send all frames to GPU, block until done?
-			//scene_A.upload(Channel::Colour + Channel::Depth);  // TODO: (Nick) Add scene stream.
+			pipeline1->apply(scene_A, scene_A, 0);
 			align->process(scene_A);
 
-			// Apply post-filters to all frames
-			/*for (int i=0; i<scene_A.frames.size(); ++i) {
-				auto &f = scene_A.frames[i];
-				auto s = scene_A.sources[i];
-				postfilter->filter(f, s, 0);
-			}*/
 
 			// TODO: To use second GPU, could do a download, swap, device change,
 			// then upload to other device. Or some direct device-2-device copy.
diff --git a/components/operators/include/ftl/operators/smoothing.hpp b/components/operators/include/ftl/operators/smoothing.hpp
index 14917303657e4e5d5ada358ec509b5e96afdc763..bd3827a4f39e74ff51670f126296a289088abaac 100644
--- a/components/operators/include/ftl/operators/smoothing.hpp
+++ b/components/operators/include/ftl/operators/smoothing.hpp
@@ -26,6 +26,24 @@ class HFSmoother : public ftl::operators::Operator {
     ftl::rgbd::Frame frames_[4];
 };
 
+/**
+ * Generate a smoothing channel from the colour image that provides a smoothing
+ * factor for each pixel. It uses colour gradient at multiple resolutions to
+ * decide on how much a given pixel needs smoothing, large single colour areas
+ * will generate a large smoothing value, whilst sharp colour edges will have
+ * no smoothing.
+ */
+class SmoothChannel : public ftl::operators::Operator {
+    public:
+    explicit SmoothChannel(ftl::Configurable*);
+    ~SmoothChannel();
+
+	inline Operator::Type type() const override { return Operator::Type::OneToOne; }
+
+    bool apply(ftl::rgbd::Frame &in, ftl::rgbd::Frame &out, ftl::rgbd::Source *src, cudaStream_t stream) override;
+
+};
+
 /**
  * Perform Moving Least Squares smoothing with a constant smoothing amount and
  * neighbourhood size. Requires channels: Depth + Normals.
diff --git a/components/operators/src/smoothing.cpp b/components/operators/src/smoothing.cpp
index 38576b5cbd8b220ee25c10a64ffb8ceb16cb5c8b..2059e29f83b49f45df840719c751a5efc59d5f8f 100644
--- a/components/operators/src/smoothing.cpp
+++ b/components/operators/src/smoothing.cpp
@@ -5,6 +5,7 @@
 
 using ftl::operators::HFSmoother;
 using ftl::operators::SimpleMLS;
+using ftl::operators::SmoothChannel;
 using ftl::codecs::Channel;
 using cv::cuda::GpuMat;
 
@@ -57,6 +58,22 @@ bool HFSmoother::apply(ftl::rgbd::Frame &in, ftl::rgbd::Frame &out, ftl::rgbd::S
 	return true;
 }
 
+// ====== Smoothing Channel ====================================================
+
+SmoothChannel::SmoothChannel(ftl::Configurable *cfg) : ftl::operators::Operator(cfg) {
+
+}
+
+SmoothChannel::~SmoothChannel() {
+
+}
+
+bool SmoothChannel::apply(ftl::rgbd::Frame &in, ftl::rgbd::Frame &out, ftl::rgbd::Source *s, cudaStream_t stream) {
+    
+	return true;
+}
+
+
 
 // ===== MLS ===================================================================