From fdb51c9933396c25062c5e03be86a4fa4390a4e9 Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nwpope@utu.fi>
Date: Tue, 8 Oct 2019 09:26:47 +0300
Subject: [PATCH] WIP: Refactor of render code

---
 applications/gui/src/camera.cpp               |   1 +
 applications/gui/src/media_panel.cpp          |   9 +
 .../cpp/include/ftl/render/splat_render.hpp   |   8 +-
 components/renderers/cpp/src/splat_render.cpp | 222 ++++++++----------
 .../include/ftl/rgbd/channels.hpp             |   2 +
 .../rgbd-sources/include/ftl/rgbd/frame.hpp   |   1 +
 6 files changed, 120 insertions(+), 123 deletions(-)

diff --git a/applications/gui/src/camera.cpp b/applications/gui/src/camera.cpp
index fe9967739..c05580482 100644
--- a/applications/gui/src/camera.cpp
+++ b/applications/gui/src/camera.cpp
@@ -381,6 +381,7 @@ const GLTexture &ftl::gui::Camera::captureFrame() {
 				visualizeEnergy(depth_, tmp, 1.0);
 				texture_.update(tmp);
 				break;
+			case Channel::Density:
 			case Channel::Energy:
 				if (depth_.rows == 0) { break; }
 				visualizeEnergy(depth_, tmp, 10.0);
diff --git a/applications/gui/src/media_panel.cpp b/applications/gui/src/media_panel.cpp
index cb44400bb..9aa81932d 100644
--- a/applications/gui/src/media_panel.cpp
+++ b/applications/gui/src/media_panel.cpp
@@ -191,6 +191,15 @@ MediaPanel::MediaPanel(ftl::gui::Screen *screen) : nanogui::Window(screen, ""),
         }
     });
 
+	button = new Button(popup, "Density");
+    button->setFlags(Button::RadioButton);
+    button->setCallback([this]() {
+        ftl::gui::Camera *cam = screen_->activeCamera();
+        if (cam) {
+            cam->setChannel(Channel::Density);
+        }
+    });
+
 }
 
 MediaPanel::~MediaPanel() {
diff --git a/components/renderers/cpp/include/ftl/render/splat_render.hpp b/components/renderers/cpp/include/ftl/render/splat_render.hpp
index af6affb10..4de9ec491 100644
--- a/components/renderers/cpp/include/ftl/render/splat_render.hpp
+++ b/components/renderers/cpp/include/ftl/render/splat_render.hpp
@@ -26,7 +26,7 @@ class Splatter : public ftl::render::Renderer {
 	//void setOutputDevice(int);
 
 	protected:
-	void renderChannel(ftl::render::SplatParams &params, ftl::rgbd::Frame &out, const ftl::rgbd::Channel &channel, cudaStream_t stream);
+	void _renderChannel(ftl::rgbd::Frame &out, const ftl::rgbd::Channel &channel, cudaStream_t stream);
 
 	private:
 	int device_;
@@ -50,6 +50,12 @@ class Splatter : public ftl::render::Renderer {
 	float3 light_dir_;
 	uchar4 light_diffuse_;
 	uchar4 light_ambient_;
+	ftl::render::SplatParams params_;
+
+	template <typename T>
+	void __blendChannel(ftl::rgbd::Frame &, ftl::rgbd::Channel in, ftl::rgbd::Channel out, cudaStream_t);
+	void _blendChannel(ftl::rgbd::Frame &, ftl::rgbd::Channel in, ftl::rgbd::Channel out, cudaStream_t);
+	void _dibr(cudaStream_t);
 };
 
 }
diff --git a/components/renderers/cpp/src/splat_render.cpp b/components/renderers/cpp/src/splat_render.cpp
index 553bd3ab6..6aaaebb75 100644
--- a/components/renderers/cpp/src/splat_render.cpp
+++ b/components/renderers/cpp/src/splat_render.cpp
@@ -126,23 +126,73 @@ Splatter::~Splatter() {
 
 }
 
-void Splatter::renderChannel(
-					ftl::render::SplatParams &params, ftl::rgbd::Frame &out,
-					const Channel &channel, cudaStream_t stream)
-{
-	if (channel == Channel::None) return;
+template <typename T>
+struct AccumSelector {
+	typedef float4 type;
+	static constexpr Channel channel = Channel::Colour;
+	//static constexpr cv::Scalar value = cv::Scalar(0.0f,0.0f,0.0f,0.0f);
+};
+
+template <>
+struct AccumSelector<float> {
+	typedef float type;
+	static constexpr Channel channel = Channel::Colour2;
+	//static constexpr cv::Scalar value = cv::Scalar(0.0f);
+};
+
+template <typename T>
+void Splatter::__blendChannel(ftl::rgbd::Frame &output, ftl::rgbd::Channel in, ftl::rgbd::Channel out, cudaStream_t stream) {
 	cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream);
-	temp_.get<GpuMat>(Channel::Depth).setTo(cv::Scalar(0x7FFFFFFF), cvstream);
-	temp_.get<GpuMat>(Channel::Depth2).setTo(cv::Scalar(0x7FFFFFFF), cvstream);
-	temp_.get<GpuMat>(Channel::Colour).setTo(cv::Scalar(0.0f,0.0f,0.0f,0.0f), cvstream);
+	temp_.create<GpuMat>(
+		AccumSelector<T>::channel,
+		Format<typename AccumSelector<T>::type>(params_.camera.width, params_.camera.height)
+	).setTo(cv::Scalar(0.0f), cvstream);
 	temp_.get<GpuMat>(Channel::Contribution).setTo(cv::Scalar(0.0f), cvstream);
 
-	if (scene_->frames.size() < 1) return;
-	bool is_float = out.get<GpuMat>(channel).type() == CV_32F; //ftl::rgbd::isFloatChannel(channel);
-	bool is_4chan = out.get<GpuMat>(channel).type() == CV_32FC4;
+	temp_.createTexture<float>(Channel::Contribution);
+
+	for (auto &f : scene_->frames) {
+		if (f.get<GpuMat>(in).type() == CV_8UC3) {
+			// Convert to 4 channel colour
+			auto &col = f.get<GpuMat>(in);
+			GpuMat tmp(col.size(), CV_8UC4);
+			cv::cuda::swap(col, tmp);
+			cv::cuda::cvtColor(tmp,col, cv::COLOR_BGR2BGRA);
+		}
+
+		ftl::cuda::dibr_attribute(
+			f.createTexture<T>(in),
+			f.createTexture<float4>(Channel::Points),
+			temp_.getTexture<int>(Channel::Depth2),
+			temp_.createTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel),
+			temp_.getTexture<float>(Channel::Contribution),
+			params_, stream
+		);
+	}
+
+	ftl::cuda::dibr_normalise(
+		temp_.getTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel),
+		output.createTexture<T>(out),
+		temp_.getTexture<float>(Channel::Contribution),
+		stream
+	);
+}
+
+void Splatter::_blendChannel(ftl::rgbd::Frame &output, ftl::rgbd::Channel in, ftl::rgbd::Channel out, cudaStream_t stream) {
+	int type = output.get<GpuMat>(out).type(); // == CV_32F; //ftl::rgbd::isFloatChannel(channel);
 	
-	// Render each camera into virtual view
-	// TODO: Move out of renderChannel, this is a common step to all channels
+	switch (type) {
+	case CV_32F		: __blendChannel<float>(output, in, out, stream); break;
+	case CV_32FC4	: __blendChannel<float4>(output, in, out, stream); break;
+	case CV_8UC4	: __blendChannel<uchar4>(output, in, out, stream); break;
+	default			: LOG(ERROR) << "Invalid output channel format";
+	}
+}
+
+void Splatter::_dibr(cudaStream_t stream) {
+	cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream);
+	temp_.get<GpuMat>(Channel::Depth2).setTo(cv::Scalar(0x7FFFFFFF), cvstream);
+
 	for (size_t i=0; i < scene_->frames.size(); ++i) {
 		auto &f = scene_->frames[i];
 		auto *s = scene_->sources[i];
@@ -156,129 +206,54 @@ void Splatter::renderChannel(
 			f.createTexture<float4>(Channel::Points),
 			f.createTexture<float4>(Channel::Normals),
 			temp_.createTexture<int>(Channel::Depth2),
-			params, backcull_, stream
+			params_, backcull_, stream
 		);
 
 		//LOG(INFO) << "DIBR DONE";
 	}
+}
 
-	temp_.createTexture<float4>(Channel::Colour);
-	temp_.createTexture<float>(Channel::Contribution);
-	out.create<GpuMat>(Channel::Normals, Format<float4>(params.camera.width, params.camera.height));
-	out.get<GpuMat>(Channel::Normals).setTo(cv::Scalar(0.0f,0.0f,0.0f,0.0f), cvstream);
-
-	// Create normals first
-	for (auto &f : scene_->frames) {
+void Splatter::_renderChannel(
+					ftl::rgbd::Frame &out,
+					const Channel &channel, cudaStream_t stream)
+{
+	if (channel == Channel::None) return;
+	cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream);
 
-		ftl::cuda::dibr_attribute(
-			f.createTexture<float4>(Channel::Normals),
-			f.createTexture<float4>(Channel::Points),
-			temp_.getTexture<int>(Channel::Depth2),
-			out.createTexture<float4>(Channel::Normals),
-			temp_.getTexture<float>(Channel::Contribution),
-			params, stream
-		);
-	}
+	if (scene_->frames.size() < 1) return;
+	bool is_float = out.get<GpuMat>(channel).type() == CV_32F; //ftl::rgbd::isFloatChannel(channel);
+	bool is_4chan = out.get<GpuMat>(channel).type() == CV_32FC4;
 
-	ftl::cuda::dibr_normalise(
-		out.getTexture<float4>(Channel::Normals),
-		out.getTexture<float4>(Channel::Normals),
-		temp_.getTexture<float>(Channel::Contribution),
-		stream
-	);
 
-	//auto &t = out.createTexture<float4>(Channel::Points, Format<float4>(params.camera.width, params.camera.height));
-	//ftl::cuda::point_cloud(t, temp_.getTexture<int>(Channel::Depth2), params.camera, params.m_viewMatrixInverse, 0, stream);
-	/*ftl::cuda::normals(out.createTexture<float4>(Channel::Normals),
-		temp_.getTexture<float4>(Channel::Normals),
-		temp_.getTexture<int>(Channel::Depth2), 
-		9, 0.04f,
-		params.camera, params.m_viewMatrixInverse.getFloat3x3(), params.m_viewMatrix.getFloat3x3(), stream);*/
+	temp_.createTexture<float4>(Channel::Colour);
+	temp_.createTexture<float>(Channel::Contribution);
 
-	//if (norm_filter_ > -0.1f) {
-	//	ftl::cuda::normal_filter(f.getTexture<float4>(Channel::Normals), f.getTexture<float4>(Channel::Points), s->parameters(), pose, norm_filter_, stream);
-	//}
+	// Generate initial normals for the splats
+	out.create<GpuMat>(Channel::Normals, Format<float4>(params_.camera.width, params_.camera.height));
+	_blendChannel(out, Channel::Normals, Channel::Normals, stream);
 
-	temp_.get<GpuMat>(Channel::Colour).setTo(cv::Scalar(0.0f,0.0f,0.0f,0.0f), cvstream);
-	temp_.get<GpuMat>(Channel::Contribution).setTo(cv::Scalar(0.0f), cvstream);
+	// Estimate point density
+	out.create<GpuMat>(Channel::Density, Format<float>(params_.camera.width, params_.camera.height));
+	_blendChannel(out, Channel::Depth, Channel::Density, stream);
 
+	// FIXME: Using colour 2 in this way seems broken since it is already used
 	if (is_4chan) {
-		temp_.create<GpuMat>(Channel::Colour2, Format<float4>(params.camera.width, params.camera.height));
+		temp_.create<GpuMat>(Channel::Colour2, Format<float4>(params_.camera.width, params_.camera.height));
 		temp_.get<GpuMat>(Channel::Colour2).setTo(cv::Scalar(0.0f,0.0f,0.0f,0.0f), cvstream);
 	} else if (is_float) {
-		temp_.create<GpuMat>(Channel::Colour2, Format<float>(params.camera.width, params.camera.height));
+		temp_.create<GpuMat>(Channel::Colour2, Format<float>(params_.camera.width, params_.camera.height));
 		temp_.get<GpuMat>(Channel::Colour2).setTo(cv::Scalar(0.0f), cvstream);
 	} else {
-		temp_.create<GpuMat>(Channel::Colour2, Format<uchar4>(params.camera.width, params.camera.height));
+		temp_.create<GpuMat>(Channel::Colour2, Format<uchar4>(params_.camera.width, params_.camera.height));
 		temp_.get<GpuMat>(Channel::Colour2).setTo(cv::Scalar(0,0,0,0), cvstream);
 	}
 
-	// Create attribute first
-	for (auto &f : scene_->frames) {
-		// Convert colour from BGR to BGRA if needed
-		if (f.get<GpuMat>(channel).type() == CV_8UC3) {
-			// Convert to 4 channel colour
-			auto &col = f.get<GpuMat>(Channel::Colour);
-			GpuMat tmp(col.size(), CV_8UC4);
-			cv::cuda::swap(col, tmp);
-			cv::cuda::cvtColor(tmp,col, cv::COLOR_BGR2BGRA);
-		}
-		
-		if (is_4chan) {
-			ftl::cuda::dibr_attribute(
-				f.createTexture<float4>(channel),
-				f.createTexture<float4>(Channel::Points),
-				temp_.getTexture<int>(Channel::Depth2),
-				temp_.getTexture<float4>(Channel::Colour),
-				temp_.getTexture<float>(Channel::Contribution),
-				params, stream
-			);
-		} else if (is_float) {
-			ftl::cuda::dibr_attribute(
-				f.createTexture<float>(channel),
-				f.createTexture<float4>(Channel::Points),
-				temp_.getTexture<int>(Channel::Depth2),
-				temp_.createTexture<float>(Channel::Colour2),
-				temp_.getTexture<float>(Channel::Contribution),
-				params, stream
-			);
-		} else {
-			ftl::cuda::dibr_attribute(
-				f.createTexture<uchar4>(channel),
-				f.createTexture<float4>(Channel::Points),
-				temp_.getTexture<int>(Channel::Depth2),
-				temp_.createTexture<float4>(Channel::Colour),
-				temp_.getTexture<float>(Channel::Contribution),
-				params, stream
-			);
-		}
-	}
-
-	if (is_4chan) {
-		ftl::cuda::dibr_normalise(
-			temp_.getTexture<float4>(Channel::Colour),
-			(splat_) ? temp_.createTexture<float4>(Channel::Colour2) : out.createTexture<float4>(channel),
-			temp_.getTexture<float>(Channel::Contribution),
-			stream
-		);
-	} else if (is_float) {
-		ftl::cuda::dibr_normalise(
-			temp_.createTexture<float>(Channel::Colour2),
-			(splat_) ? temp_.createTexture<float>(Channel::Colour2) : out.createTexture<float>(channel),
-			temp_.getTexture<float>(Channel::Contribution),
-			stream
-		);
+	if (splat_) {
+		_blendChannel(temp_, channel, Channel::Colour2, stream);
 	} else {
-		ftl::cuda::dibr_normalise(
-			temp_.getTexture<float4>(Channel::Colour),
-			(splat_) ? temp_.createTexture<uchar4>(Channel::Colour2) : out.createTexture<uchar4>(channel),
-			temp_.getTexture<float>(Channel::Contribution),
-			stream
-		);
+		_blendChannel(out, channel, channel, stream);
 	}
 
-	//out.get<GpuMat>(Channel::Left).setTo(cv::Scalar(0,0,0,0), cvstream);
-
 	// Now splat the points
 	if (splat_) {
 		if (is_4chan) {
@@ -288,7 +263,7 @@ void Splatter::renderChannel(
 				temp_.getTexture<int>(Channel::Depth2),
 				out.createTexture<float>(Channel::Depth),
 				out.createTexture<float4>(channel),
-				params, stream
+				params_, stream
 			);
 		} else if (is_float) {
 			ftl::cuda::splat(
@@ -297,7 +272,7 @@ void Splatter::renderChannel(
 				temp_.getTexture<int>(Channel::Depth2),
 				out.createTexture<float>(Channel::Depth),
 				out.createTexture<float>(channel),
-				params, stream
+				params_, stream
 			);
 		} else {
 			ftl::cuda::splat(
@@ -306,7 +281,7 @@ void Splatter::renderChannel(
 				temp_.getTexture<int>(Channel::Depth2),
 				out.createTexture<float>(Channel::Depth),
 				out.createTexture<uchar4>(channel),
-				params, stream
+				params_, stream
 			);
 		}
 	}
@@ -334,7 +309,7 @@ bool Splatter::render(ftl::rgbd::VirtualSource *src, ftl::rgbd::Frame &out, cuda
 	cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream);
 
 	// Parameters object to pass to CUDA describing the camera
-	SplatParams params;
+	SplatParams &params = params_;
 	params.m_flags = 0;
 	if (value("show_discontinuity_mask", false)) params.m_flags |= ftl::render::kShowDisconMask;
 	if (value("normal_weight_colours", true)) params.m_flags |= ftl::render::kNormalWeightColours;
@@ -391,7 +366,8 @@ bool Splatter::render(ftl::rgbd::VirtualSource *src, ftl::rgbd::Frame &out, cuda
 		}
 	}
 
-	renderChannel(params, out, Channel::Colour, stream);
+	_dibr(stream);
+	_renderChannel(out, Channel::Colour, stream);
 	
 	Channel chan = src->getChannel();
 	if (chan == Channel::Depth)
@@ -401,7 +377,7 @@ bool Splatter::render(ftl::rgbd::VirtualSource *src, ftl::rgbd::Frame &out, cuda
 		out.create<GpuMat>(Channel::Normals, Format<float4>(camera.width, camera.height));
 
 		// Render normal attribute
-		renderChannel(params, out, Channel::Normals, stream);
+		_renderChannel(out, Channel::Normals, stream);
 
 		// Convert normal to single float value
 		temp_.create<GpuMat>(Channel::Colour, Format<uchar4>(camera.width, camera.height));
@@ -427,7 +403,9 @@ bool Splatter::render(ftl::rgbd::VirtualSource *src, ftl::rgbd::Frame &out, cuda
 		
 		out.create<GpuMat>(Channel::Right, Format<uchar4>(camera.width, camera.height));
 		out.get<GpuMat>(Channel::Right).setTo(background_, cvstream);
-		renderChannel(params, out, Channel::Right, stream);
+
+		_dibr(stream); // Need to re-dibr due to pose change
+		_renderChannel(out, Channel::Right, stream);
 	} else if (chan != Channel::None) {
 		if (ftl::rgbd::isFloatChannel(chan)) {
 			out.create<GpuMat>(chan, Format<float>(camera.width, camera.height));
@@ -436,7 +414,7 @@ bool Splatter::render(ftl::rgbd::VirtualSource *src, ftl::rgbd::Frame &out, cuda
 			out.create<GpuMat>(chan, Format<uchar4>(camera.width, camera.height));
 			out.get<GpuMat>(chan).setTo(background_, cvstream);
 		}
-		renderChannel(params, out, chan, stream);
+		_renderChannel(out, chan, stream);
 	}
 
 	return true;
diff --git a/components/rgbd-sources/include/ftl/rgbd/channels.hpp b/components/rgbd-sources/include/ftl/rgbd/channels.hpp
index 467df0b1e..e00647271 100644
--- a/components/rgbd-sources/include/ftl/rgbd/channels.hpp
+++ b/components/rgbd-sources/include/ftl/rgbd/channels.hpp
@@ -25,6 +25,7 @@ enum struct Channel : int {
     Flow,               // 32F
     Energy,             // 32F
 	Mask,				// 32U
+	Density,			// 32F
     LeftGray,
     RightGray,
     Overlay1
@@ -106,6 +107,7 @@ inline bool isFloatChannel(ftl::rgbd::Channel chan) {
 	case Channel::Depth		:
     //case Channel::Normals   :
 	case Channel::Confidence:
+	case Channel::Density:
 	case Channel::Energy	: return true;
 	default					: return false;
 	}
diff --git a/components/rgbd-sources/include/ftl/rgbd/frame.hpp b/components/rgbd-sources/include/ftl/rgbd/frame.hpp
index 338674745..e9036fd6c 100644
--- a/components/rgbd-sources/include/ftl/rgbd/frame.hpp
+++ b/components/rgbd-sources/include/ftl/rgbd/frame.hpp
@@ -187,6 +187,7 @@ ftl::cuda::TextureObject<T> &Frame::getTexture(ftl::rgbd::Channel c) {
 	auto &m = _get(c);
 
 	if (m.tex.cvType() != ftl::traits::OpenCVType<T>::value || m.tex.width() != m.gpu.cols || m.tex.height() != m.gpu.rows || m.gpu.type() != m.tex.cvType()) {
+		LOG(ERROR) << "Texture has not been created for channel = " << (int)c;
 		throw ftl::exception("Texture has not been created properly for this channel");
 	}
 
-- 
GitLab