From 9f3cc4df74bfb1035e085120eb19364ee0e43310 Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nicolas.pope@utu.fi>
Date: Sat, 22 Jun 2019 21:35:01 +0300
Subject: [PATCH] Implements #41 colour correction

---
 components/rgbd-sources/CMakeLists.txt        |  1 +
 components/rgbd-sources/src/colour.cpp        | 73 +++++++++++++++++++
 components/rgbd-sources/src/colour.hpp        | 15 ++++
 components/rgbd-sources/src/net.cpp           |  8 ++
 components/rgbd-sources/src/net.hpp           |  2 +
 .../rgbd-sources/src/snapshot_source.cpp      |  7 ++
 6 files changed, 106 insertions(+)
 create mode 100644 components/rgbd-sources/src/colour.cpp
 create mode 100644 components/rgbd-sources/src/colour.hpp

diff --git a/components/rgbd-sources/CMakeLists.txt b/components/rgbd-sources/CMakeLists.txt
index 19aaf7458..96c709b6e 100644
--- a/components/rgbd-sources/CMakeLists.txt
+++ b/components/rgbd-sources/CMakeLists.txt
@@ -6,6 +6,7 @@ set(RGBDSRC
 	src/stereovideo.cpp
 	src/net.cpp
 	src/streamer.cpp
+	src/colour.cpp
 #	src/algorithms/rtcensus.cpp
 #	src/algorithms/rtcensus_sgm.cpp
 #	src/algorithms/opencv_sgbm.cpp
diff --git a/components/rgbd-sources/src/colour.cpp b/components/rgbd-sources/src/colour.cpp
new file mode 100644
index 000000000..c476ee8e2
--- /dev/null
+++ b/components/rgbd-sources/src/colour.cpp
@@ -0,0 +1,73 @@
+#include "colour.hpp"
+
+#include <vector>
+#include <tuple>
+
+using std::vector;
+
+static void gammaCorrection(const cv::Mat &img, const double gamma_){
+	using namespace cv;
+
+    Mat lookUpTable(1, 256, CV_8U);
+    uchar* p = lookUpTable.ptr();
+    for( int i = 0; i < 256; ++i)
+        p[i] = saturate_cast<uchar>(pow(i / 255.0, gamma_) * 255.0);
+
+    Mat res = img.clone();
+    LUT(img, lookUpTable, img);
+}
+
+static const std::vector<std::tuple<uchar,uchar,uchar>> kelvin_table = {
+    {255,56,0},		// 1000
+    {255,109,0},		// 1500
+    {255,137,18},		// 2000
+    {255,161,72},		// 2500
+    {255,180,107},	// 3000
+    {255,196,137},	// 3500
+    {255,209,163},	// 4000
+    {255,219,186},	// 4500
+    {255,228,206},	// 5000
+    {255,236,224},	// 5500
+    {255,243,239},	// 6000
+    {255,249,253},	// 6500
+    {245,243,255},	// 7000
+    {235,238,255},	// 7500
+    {227,233,255},	// 8000
+    {220,229,255},	// 8500
+    {214,225,255},	// 9000
+    {208,222,255},	// 9500
+    {204,219,255}};	// 10000
+
+template <int C>
+inline float kelvinFactor(int temp) {
+	int index = (temp / 500) - 2;
+	if (index >= kelvin_table.size()) index = kelvin_table.size();
+	else if (index < 0) index = 0;
+	return (float)std::get<C>(kelvin_table[index]) / 255.0f;
+}
+
+void ftl::rgbd::colourCorrection(cv::Mat &img, float gamma, int temp) {
+	using namespace cv;
+
+	Mat lutRed(1, 256, CV_8U);
+	Mat lutGreen(1, 256, CV_8U);
+	Mat lutBlue(1, 256, CV_8U);
+
+	// TODO(Nick): Cache these lookup tables if used every frame...
+    uchar* pr = lutRed.ptr();
+	uchar* pg = lutGreen.ptr();
+	uchar* pb = lutBlue.ptr();
+    for( int i = 0; i < 256; ++i) {
+        float g = pow(i / 255.0f, gamma) * 255.0f;
+		pr[i] = saturate_cast<uchar>(g * kelvinFactor<2>(temp));
+		pg[i] = saturate_cast<uchar>(g * kelvinFactor<1>(temp));
+		pb[i] = saturate_cast<uchar>(g * kelvinFactor<0>(temp));
+	}
+
+	vector<Mat> channels(3);
+	split(img, channels);
+    LUT(channels[0], lutBlue, channels[0]);
+	LUT(channels[1], lutGreen, channels[1]);
+	LUT(channels[2], lutRed, channels[2]);
+	merge(channels, img);
+} 
diff --git a/components/rgbd-sources/src/colour.hpp b/components/rgbd-sources/src/colour.hpp
new file mode 100644
index 000000000..be88853a5
--- /dev/null
+++ b/components/rgbd-sources/src/colour.hpp
@@ -0,0 +1,15 @@
+#ifndef _FTL_RGBD_COLOUR_HPP_
+#define _FTL_RGBD_COLOUR_HPP_
+
+#include <opencv2/opencv.hpp>
+
+namespace ftl {
+namespace rgbd {
+
+void colourCorrection(cv::Mat &img, float gamma, int temp);
+// void colourCorrection(cv::GpuMat &img, float gamma, int temp);
+
+}
+}
+
+#endif  // _FTL_RGBD_COLOUR_HPP_
diff --git a/components/rgbd-sources/src/net.cpp b/components/rgbd-sources/src/net.cpp
index 674bc2471..6f915f127 100644
--- a/components/rgbd-sources/src/net.cpp
+++ b/components/rgbd-sources/src/net.cpp
@@ -4,6 +4,8 @@
 #include <chrono>
 #include <shared_mutex>
 
+#include "colour.hpp"
+
 #include <ftl/rgbd/streamer.hpp>
 
 using ftl::rgbd::detail::NetSource;
@@ -46,6 +48,9 @@ bool NetSource::_getCalibration(Universe &net, const UUID &peer, const string &s
 NetSource::NetSource(ftl::rgbd::Source *host)
 		: ftl::rgbd::detail::Source(host), active_(false) {
 
+	gamma_ = host->value("gamma", 1.0f);
+	temperature_ = host->value("temperature", 6500);
+
 	_updateURI();
 
 	h_ = host_->getNet()->onConnect([this](ftl::net::Peer *p) {
@@ -90,6 +95,9 @@ void NetSource::_recvChunk(int frame, int chunk, bool delta, const vector<unsign
 	cv::imdecode(jpg, cv::IMREAD_COLOR, &tmp_rgb);
 	cv::imdecode(d, cv::IMREAD_UNCHANGED, &tmp_depth);
 
+	// Apply colour correction to chunk
+	ftl::rgbd::colourCorrection(tmp_rgb, gamma_, temperature_);
+
 	// Build chunk head
 	int cx = (chunk % chunks_dim_) * chunk_width_;
 	int cy = (chunk / chunks_dim_) * chunk_height_;
diff --git a/components/rgbd-sources/src/net.hpp b/components/rgbd-sources/src/net.hpp
index ce88d10c3..5a5639273 100644
--- a/components/rgbd-sources/src/net.hpp
+++ b/components/rgbd-sources/src/net.hpp
@@ -41,6 +41,8 @@ class NetSource : public detail::Source {
 	int chunk_width_;
 	int chunk_height_;
 	cv::Mat idepth_;
+	float gamma_;
+	int temperature_;
 
 	bool _getCalibration(ftl::net::Universe &net, const ftl::UUID &peer, const std::string &src, ftl::rgbd::Camera &p);
 	void _recv(const std::vector<unsigned char> &jpg, const std::vector<unsigned char> &d);
diff --git a/components/rgbd-sources/src/snapshot_source.cpp b/components/rgbd-sources/src/snapshot_source.cpp
index 367fc2861..686e55b93 100644
--- a/components/rgbd-sources/src/snapshot_source.cpp
+++ b/components/rgbd-sources/src/snapshot_source.cpp
@@ -1,16 +1,23 @@
 #include "snapshot_source.hpp"
+#include "colour.hpp"
+#include <loguru.hpp>
 
 #include <opencv2/opencv.hpp>
 #include <Eigen/Eigen>
 #include <opencv2/core/eigen.hpp>
+#include <vector>
 
 using namespace ftl::rgbd;
 using ftl::rgbd::detail::SnapshotSource;
 
 using std::string;
+using std::vector;
 
 SnapshotSource::SnapshotSource(ftl::rgbd::Source *host, SnapshotReader &reader, const string &id) : detail::Source(host) {
     Eigen::Matrix4d pose;
     reader.getCameraRGBD(id, rgb_, depth_, pose, params_);
+
+	ftl::rgbd::colourCorrection(rgb_, host->value("gamma", 1.0f), host->value("temperature", 6500));
+
     setPose(pose);
 }
-- 
GitLab