diff --git a/SDK/C++/private/frame_impl.cpp b/SDK/C++/private/frame_impl.cpp
index ae295fe0320e3342a6dd4cecd0a520c2c134d46a..0b0779b6a2a2d23a3250a0cb917e8486e88af4b9 100644
--- a/SDK/C++/private/frame_impl.cpp
+++ b/SDK/C++/private/frame_impl.cpp
@@ -24,6 +24,7 @@ std::list<voltu::ImagePtr> FrameImpl::getImageSet(voltu::Channel c)
 	{
 	case voltu::Channel::kColour	: channel = ftl::codecs::Channel::Colour; break;
 	case voltu::Channel::kDepth		: channel = ftl::codecs::Channel::Depth; break;
+	case voltu::Channel::kNormals	: channel = ftl::codecs::Channel::Normals; break;
 	default: throw voltu::exceptions::BadImageChannel();
 	}
 
diff --git a/SDK/C++/private/image_impl.cpp b/SDK/C++/private/image_impl.cpp
index f8bf63a27001f0540f008eed4a5f4bb5bd8dfb75..76dea9a2234933e6dad53bdaecd7e83f52e257fd 100644
--- a/SDK/C++/private/image_impl.cpp
+++ b/SDK/C++/private/image_impl.cpp
@@ -30,6 +30,10 @@ voltu::ImageData ImageImpl::getHost()
 	{
 		r.format = voltu::ImageFormat::kFloat32;
 	}
+	else if (m.type() == CV_16FC4)
+	{
+		r.format = voltu::ImageFormat::kFloat16_4;
+	}
 
 	return r;
 }
@@ -51,6 +55,10 @@ voltu::ImageData ImageImpl::getDevice()
 	{
 		r.format = voltu::ImageFormat::kFloat32;
 	}
+	else if (m.type() == CV_16FC4)
+	{
+		r.format = voltu::ImageFormat::kFloat16_4;
+	}
 
 	return r;
 }
@@ -66,6 +74,7 @@ voltu::Channel ImageImpl::getChannel()
 	{
 	case ftl::codecs::Channel::Colour		: return voltu::Channel::kColour;
 	case ftl::codecs::Channel::Depth		: return voltu::Channel::kDepth;
+	case ftl::codecs::Channel::Normals		: return voltu::Channel::kNormals;
 	default: return voltu::Channel::kInvalid;
 	}
 }
diff --git a/SDK/C++/public/include/voltu/types/image.hpp b/SDK/C++/public/include/voltu/types/image.hpp
index 6064f894d059dbc77ce87d4ac64fcaf93ed842f4..406c81df8b2f4ba9e2a396b5df56097c50828e0c 100644
--- a/SDK/C++/public/include/voltu/types/image.hpp
+++ b/SDK/C++/public/include/voltu/types/image.hpp
@@ -15,7 +15,8 @@ enum class ImageFormat
 {
 	kInvalid = 0,
 	kFloat32 = 1,
-	kBGRA8 = 2
+	kBGRA8 = 2,
+	kFloat16_4 = 3
 };
 
 PY_NO_SHARED_PTR struct ImageData
@@ -31,7 +32,7 @@ class Image
 {
 public:
 	virtual ~Image() = default;
-	
+
 	PY_API PY_RV_LIFETIME_PARENT virtual ImageData getHost() = 0;
 
 	virtual ImageData getDevice() = 0;
diff --git a/SDK/C++/public/samples/fusion_evaluator/main.cpp b/SDK/C++/public/samples/fusion_evaluator/main.cpp
index 7745484dfea301f842f0ff4db6364bddfd886e89..d388851e9421b531ed7721efa8128d6b4620d76a 100644
--- a/SDK/C++/public/samples/fusion_evaluator/main.cpp
+++ b/SDK/C++/public/samples/fusion_evaluator/main.cpp
@@ -42,7 +42,7 @@ int main(int argc, char **argv)
 	pipe->submit(frame);
 	pipe->waitCompletion(1000);
 
-	auto imgset = frame->getImageSet(voltu::Channel::kColour);
+	auto imgset = frame->getImageSet(voltu::Channel::kNormals);
 
 	for (auto img : imgset)
 	{
diff --git a/SDK/C++/public/voltu_cv.cpp b/SDK/C++/public/voltu_cv.cpp
index 3b77155b6450560eb7808f7294013926fea382e7..d74ad9313c8f6795a2a04113146f47d12c55c49e 100644
--- a/SDK/C++/public/voltu_cv.cpp
+++ b/SDK/C++/public/voltu_cv.cpp
@@ -14,6 +14,10 @@ void voltu::cv::convert(voltu::ImagePtr img, ::cv::Mat &mat)
 	{
 		mat = ::cv::Mat(data.height, data.width, CV_32FC1, data.data);
 	}
+	else if (data.format == voltu::ImageFormat::kFloat16_4)
+	{
+		mat = ::cv::Mat(data.height, data.width, CV_16FC4, data.data);
+	}
 	else
 	{
 		mat = ::cv::Mat();
@@ -47,4 +51,13 @@ void voltu::cv::visualise(voltu::ImagePtr img, ::cv::Mat &mat)
 		::cv::applyColorMap(tmp, mat, ::cv::COLORMAP_INFERNO);
 		//#endif
 	}
+	else if (data.format == voltu::ImageFormat::kFloat16_4)
+	{
+		::cv::Mat tmp;
+		voltu::cv::convert(img, tmp);
+		tmp.convertTo(tmp, CV_32FC4);
+		tmp += 1.0f;
+		tmp *= 127.0f;
+		tmp.convertTo(mat, CV_8UC4);
+	}
 }