From 7fc400f21bd399f6508e0e46ffe0befc6321716e Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nwpope@utu.fi>
Date: Wed, 11 Nov 2020 17:44:45 +0200
Subject: [PATCH] Add initial gpu utility code

---
 SDK/CPP/private/frame_impl.cpp                |  4 +--
 SDK/CPP/private/frame_impl.hpp                |  2 +-
 SDK/CPP/public/CMakeLists.txt                 |  4 +++
 SDK/CPP/public/include/voltu/cuda.hpp         | 27 +++++++++++++++
 SDK/CPP/public/include/voltu/opencv.hpp       | 14 ++++++--
 SDK/CPP/public/include/voltu/system.hpp       |  2 +-
 SDK/CPP/public/include/voltu/types/frame.hpp  |  2 +-
 SDK/CPP/public/samples/basic_file/main.cpp    |  2 +-
 .../public/samples/basic_virtual_cam/main.cpp |  2 +-
 .../public/samples/fusion_evaluator/main.cpp  |  7 +++-
 SDK/CPP/public/voltu.cpp                      | 20 +++++++++++
 SDK/CPP/public/voltu_cv.cpp                   | 33 +++++++++++++++----
 12 files changed, 103 insertions(+), 16 deletions(-)
 create mode 100644 SDK/CPP/public/include/voltu/cuda.hpp

diff --git a/SDK/CPP/private/frame_impl.cpp b/SDK/CPP/private/frame_impl.cpp
index a91ad3e6a..059b508ff 100644
--- a/SDK/CPP/private/frame_impl.cpp
+++ b/SDK/CPP/private/frame_impl.cpp
@@ -15,9 +15,9 @@ FrameImpl::~FrameImpl()
 
 }
 
-std::list<voltu::ImagePtr> FrameImpl::getImageSet(voltu::Channel c)
+std::vector<voltu::ImagePtr> FrameImpl::getImageSet(voltu::Channel c)
 {
-	std::list<voltu::ImagePtr> result;
+	std::vector<voltu::ImagePtr> result;
 	ftl::codecs::Channel channel = ftl::codecs::Channel::Colour;
 
 	switch (c)
diff --git a/SDK/CPP/private/frame_impl.hpp b/SDK/CPP/private/frame_impl.hpp
index eb5caa5a6..38750ce42 100644
--- a/SDK/CPP/private/frame_impl.hpp
+++ b/SDK/CPP/private/frame_impl.hpp
@@ -16,7 +16,7 @@ public:
 	FrameImpl();
 	~FrameImpl() override;
 
-	std::list<voltu::ImagePtr> getImageSet(voltu::Channel) override;
+	std::vector<voltu::ImagePtr> getImageSet(voltu::Channel) override;
 
 	voltu::PointCloudPtr getPointCloud(voltu::PointCloudFormat cloudfmt, voltu::PointFormat pointfmt) override;
 
diff --git a/SDK/CPP/public/CMakeLists.txt b/SDK/CPP/public/CMakeLists.txt
index f1ea62a4e..e3d1c339a 100644
--- a/SDK/CPP/public/CMakeLists.txt
+++ b/SDK/CPP/public/CMakeLists.txt
@@ -43,6 +43,10 @@ endif()
 
 add_library(voltu_sdk STATIC ${VOLTU_SRCS})
 
+if (WITH_OPENCV)
+	target_compile_definitions(voltu_sdk PUBLIC WITH_OPENCV)
+endif()
+
 target_include_directories(voltu_sdk
 	PUBLIC include)
 target_link_libraries(voltu_sdk ${OS_LIBS} Threads::Threads ${OPTIONAL_DEPENDENCIES} Eigen3::Eigen)
diff --git a/SDK/CPP/public/include/voltu/cuda.hpp b/SDK/CPP/public/include/voltu/cuda.hpp
new file mode 100644
index 000000000..972f4964b
--- /dev/null
+++ b/SDK/CPP/public/include/voltu/cuda.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <voltu/types/image.hpp>
+#include 
+#include <memory>
+
+namespace voltu
+{
+
+/**
+ * @brief CUDA Processing Stream.
+ * 
+ * An instance of this class is mapped to a single CUDA stream, so any of the
+ * available operations will occur within that stream. It is therefore
+ * necessary to call `waitCompletion` after all steps have been finished.
+ */
+class CUDAProc
+{
+public:
+	virtual bool waitCompletion(int timeout, bool except=false) = 0;
+
+	virtual void* getInternalStream() = 0;
+
+	virtual void visualiseDepthEnhancement(const voltu::ImagePtr &gt, const voltu::ImagePtr &depth_old, const voltu::ImagePtr &depth_new, const voltu::ImagePtr &colour) = 0;
+};
+
+}
diff --git a/SDK/CPP/public/include/voltu/opencv.hpp b/SDK/CPP/public/include/voltu/opencv.hpp
index 7119cbc87..1e8e858ab 100644
--- a/SDK/CPP/public/include/voltu/opencv.hpp
+++ b/SDK/CPP/public/include/voltu/opencv.hpp
@@ -7,19 +7,29 @@
 #pragma once
 
 #include <opencv2/core/mat.hpp>
-#include <opencv2/core/cuda_types.hpp>
+#include <opencv2/core/cuda.hpp>
 #include <voltu/types/image.hpp>
 
 namespace voltu
 {
-namespace cv
+namespace opencv
 {
 
 void convert(voltu::ImagePtr img, ::cv::Mat &mat);
 
 void convert(voltu::ImagePtr img, ::cv::cuda::GpuMat &mat);
 
+::cv::cuda::GpuMat toGpuMat(voltu::ImagePtr img);
+
 void visualise(voltu::ImagePtr img, ::cv::Mat &mat);
 
 }
+
+struct GpuUtilities
+{
+	void (*visualiseDepthEnhancement)(const voltu::ImagePtr &gt, const voltu::ImagePtr &depth_old, const voltu::ImagePtr &depth_new, const voltu::ImagePtr &colour) = nullptr;
+};
+
+extern GpuUtilities gpu;
+
 }
\ No newline at end of file
diff --git a/SDK/CPP/public/include/voltu/system.hpp b/SDK/CPP/public/include/voltu/system.hpp
index 8fb9c744c..df7b4938e 100644
--- a/SDK/CPP/public/include/voltu/system.hpp
+++ b/SDK/CPP/public/include/voltu/system.hpp
@@ -78,7 +78,7 @@ public:
 	 * Identifiers (URIs), with some non-standard additions. A few examples
 	 * are:
 	 * * `file:///home/user/file.ftl`
-	 * * `tcp://localhost:9001/*`
+	 * * `tcp://localhost:9001/`
 	 * * `ftl://my.stream.name/room1`
 	 * * `ws://ftlab.utu.fi/lab/`
 	 * * `./file.ftl`
diff --git a/SDK/CPP/public/include/voltu/types/frame.hpp b/SDK/CPP/public/include/voltu/types/frame.hpp
index 30b7c4ddc..7f03fc604 100644
--- a/SDK/CPP/public/include/voltu/types/frame.hpp
+++ b/SDK/CPP/public/include/voltu/types/frame.hpp
@@ -22,7 +22,7 @@ class Frame
 public:
 	virtual ~Frame() = default;
 	
-	PY_API PY_RV_LIFETIME_PARENT virtual std::list<voltu::ImagePtr> getImageSet(voltu::Channel channel) = 0;
+	PY_API PY_RV_LIFETIME_PARENT virtual std::vector<voltu::ImagePtr> getImageSet(voltu::Channel channel) = 0;
 
 	PY_API PY_RV_LIFETIME_PARENT virtual voltu::PointCloudPtr getPointCloud(voltu::PointCloudFormat cloudfmt, voltu::PointFormat pointfmt) = 0;
 
diff --git a/SDK/CPP/public/samples/basic_file/main.cpp b/SDK/CPP/public/samples/basic_file/main.cpp
index c98386427..9af26c1c0 100644
--- a/SDK/CPP/public/samples/basic_file/main.cpp
+++ b/SDK/CPP/public/samples/basic_file/main.cpp
@@ -45,7 +45,7 @@ int main(int argc, char **argv)
 		for (auto img : imgset)
 		{
 			cv::Mat m;
-			voltu::cv::visualise(img, m);
+			voltu::opencv::visualise(img, m);
 			cv::imshow(string("Image-") + img->getName(), m);
 		}
 
diff --git a/SDK/CPP/public/samples/basic_virtual_cam/main.cpp b/SDK/CPP/public/samples/basic_virtual_cam/main.cpp
index f1b2634b7..47dea0583 100644
--- a/SDK/CPP/public/samples/basic_virtual_cam/main.cpp
+++ b/SDK/CPP/public/samples/basic_virtual_cam/main.cpp
@@ -69,7 +69,7 @@ int main(int argc, char **argv)
 		for (auto img : imgset)
 		{
 			cv::Mat m;
-			voltu::cv::convert(img, m);
+			voltu::opencv::convert(img, m);
 			cv::imshow(string("Camera-") + img->getName(), m);
 		}
 
diff --git a/SDK/CPP/public/samples/fusion_evaluator/main.cpp b/SDK/CPP/public/samples/fusion_evaluator/main.cpp
index c4073baf4..f9b96468c 100644
--- a/SDK/CPP/public/samples/fusion_evaluator/main.cpp
+++ b/SDK/CPP/public/samples/fusion_evaluator/main.cpp
@@ -107,6 +107,10 @@ int main(int argc, char **argv)
 	op1->property("visibility_carving")->setBool(do_carving);
 	op1->property("mls_iterations")->setInt(iters);
 
+	cv::Mat old_depth;
+	auto oldimgset = frame->getImageSet(voltu::Channel::kDepth);
+	voltu::opencv::toGpuMat(oldimgset[sourceno]).download(old_depth);
+
 	pipe->submit(frame);
 	pipe->waitCompletion(3000, true);
 
@@ -123,7 +127,8 @@ int main(int argc, char **argv)
 	{
 		if (srccount++ < sourceno) continue;
 		cv::Mat m;
-		voltu::cv::visualise(img, m);
+		voltu::opencv::toGpuMat(img).download(m);
+		voltu::opencv::visualise(img, m);
 		cv::imshow(string("Image-") + img->getName(), m);
 		break;
 	}
diff --git a/SDK/CPP/public/voltu.cpp b/SDK/CPP/public/voltu.cpp
index 2c4d19712..d558ff7b0 100644
--- a/SDK/CPP/public/voltu.cpp
+++ b/SDK/CPP/public/voltu.cpp
@@ -8,6 +8,10 @@
 #include <voltu/types/errors.hpp>
 #include <voltu/voltu.hpp>
 
+#ifdef WITH_OPENCV
+#include <voltu/opencv.hpp>
+#endif
+
 #if defined(WIN32)
 #include <windows.h>
 #pragma comment(lib, "User32.lib")
@@ -23,6 +27,10 @@
 
 static bool g_init = false;
 
+#ifdef WITH_OPENCV
+voltu::GpuUtilities voltu::gpu;
+#endif
+
 typedef void* Library;
 
 static Library loadLibrary(const char *file)
@@ -132,6 +140,18 @@ std::shared_ptr<voltu::System> voltu::instance()
 				throw voltu::exceptions::RuntimeVersionMismatch();
 			}
 
+#ifdef WITH_OPENCV
+			auto gpuinit = (voltu::GpuUtilities* (*)())getFunction(handle, "voltu_utilities_gpu");
+			if (gpuinit)
+			{
+				gpu = *gpuinit();
+			}
+			else
+			{
+				//throw voltu::exceptions::LibraryLoadFailed();	
+			}
+#endif
+
 			return instance;
 		}
 		else
diff --git a/SDK/CPP/public/voltu_cv.cpp b/SDK/CPP/public/voltu_cv.cpp
index e9951dc37..5e55e7908 100644
--- a/SDK/CPP/public/voltu_cv.cpp
+++ b/SDK/CPP/public/voltu_cv.cpp
@@ -9,7 +9,7 @@
 
 #include <opencv2/imgproc.hpp>
 
-void voltu::cv::convert(voltu::ImagePtr img, ::cv::Mat &mat)
+void voltu::opencv::convert(voltu::ImagePtr img, ::cv::Mat &mat)
 {
 	voltu::ImageData data = img->getHost();
 
@@ -31,23 +31,44 @@ void voltu::cv::convert(voltu::ImagePtr img, ::cv::Mat &mat)
 	}
 }
 
-void voltu::cv::convert(voltu::ImagePtr img, ::cv::cuda::GpuMat &mat)
+void voltu::opencv::convert(voltu::ImagePtr img, ::cv::cuda::GpuMat &mat)
 {
+	mat = voltu::opencv::toGpuMat(img);
+}
+
+cv::cuda::GpuMat voltu::opencv::toGpuMat(voltu::ImagePtr img)
+{
+	voltu::ImageData data = img->getDevice();
+
+	if (data.format == voltu::ImageFormat::kBGRA8)
+	{
+
+	}
+	else if (data.format == voltu::ImageFormat::kFloat32)
+	{
+		return ::cv::cuda::GpuMat(
+			data.height,
+			data.width,
+			CV_32F,
+			data.data
+		);
+	}
+
 	throw voltu::exceptions::NotImplemented();
 }
 
-void voltu::cv::visualise(voltu::ImagePtr img, ::cv::Mat &mat)
+void voltu::opencv::visualise(voltu::ImagePtr img, ::cv::Mat &mat)
 {
 	voltu::ImageData data = img->getHost();
 
 	if (data.format == voltu::ImageFormat::kBGRA8)
 	{
-		voltu::cv::convert(img, mat);
+		voltu::opencv::convert(img, mat);
 	}
 	else if (data.format == voltu::ImageFormat::kFloat32)
 	{
 		::cv::Mat tmp;
-		voltu::cv::convert(img, tmp);
+		voltu::opencv::convert(img, tmp);
 
 		float maxdepth = 8.0f;  // TODO: Get from intrinsics
 
@@ -65,7 +86,7 @@ void voltu::cv::visualise(voltu::ImagePtr img, ::cv::Mat &mat)
 	else if (data.format == voltu::ImageFormat::kFloat16_4)
 	{
 		::cv::Mat tmp;
-		voltu::cv::convert(img, tmp);
+		voltu::opencv::convert(img, tmp);
 		tmp.convertTo(tmp, CV_32FC4);
 		tmp += 1.0f;
 		tmp *= 127.0f;
-- 
GitLab