mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Merge pull request #534 from AEtHeLsYn/master
Color correction Former-commit-id: 7be726f1adb8698684a2b4726650082ed517901f
This commit is contained in:
		| @@ -42,6 +42,32 @@ | |||||||
| 	///            - 'updateDelay'     The delay of the output to leds (in periods of smoothing) | 	///            - 'updateDelay'     The delay of the output to leds (in periods of smoothing) | ||||||
| 	"color" : | 	"color" : | ||||||
| 	{ | 	{ | ||||||
|  | 		"correction" : | ||||||
|  | 		[ | ||||||
|  | 			{ | ||||||
|  | 				"id"   : "default", | ||||||
|  | 				"leds" : "*", | ||||||
|  | 				"correctionValues" : | ||||||
|  | 				{ | ||||||
|  | 					"red"   : 255, | ||||||
|  | 					"green" : 255, | ||||||
|  | 					"blue"  : 255 | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		], | ||||||
|  | 		"temperature" : | ||||||
|  | 		[ | ||||||
|  | 			{ | ||||||
|  | 				"id"   : "default", | ||||||
|  | 				"leds" : "*", | ||||||
|  | 				"temperatureValues" : | ||||||
|  | 				{ | ||||||
|  | 					"red"   : 255, | ||||||
|  | 					"green" : 255, | ||||||
|  | 					"blue"  : 255 | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		], | ||||||
| 		"transform" : | 		"transform" : | ||||||
| 		[ | 		[ | ||||||
| 			{ | 			{ | ||||||
| @@ -52,6 +78,11 @@ | |||||||
| 					"saturationGain" : 1.0000, | 					"saturationGain" : 1.0000, | ||||||
| 					"valueGain"      : 1.0000 | 					"valueGain"      : 1.0000 | ||||||
| 				}, | 				}, | ||||||
|  | 				"hsl" : | ||||||
|  | 				{ | ||||||
|  | 					"saturationGain" : 1.0000, | ||||||
|  | 					"luminanceGain"  : 1.0000 | ||||||
|  | 				}, | ||||||
| 				"red" : | 				"red" : | ||||||
| 				{ | 				{ | ||||||
| 					"threshold"  : 0.0000, | 					"threshold"  : 0.0000, | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								include/hyperion/ColorCorrection.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								include/hyperion/ColorCorrection.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | // STL includes | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | // Utils includes | ||||||
|  | #include <utils/RgbChannelCorrection.h> | ||||||
|  |  | ||||||
|  | class ColorCorrection | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	 | ||||||
|  | 	/// Unique identifier for this color correction | ||||||
|  | 	std::string _id; | ||||||
|  |  | ||||||
|  | 	/// The RGB correction | ||||||
|  | 	RgbChannelCorrection _rgbCorrection; | ||||||
|  | }; | ||||||
| @@ -6,6 +6,7 @@ | |||||||
| // Utils includes | // Utils includes | ||||||
| #include <utils/RgbChannelTransform.h> | #include <utils/RgbChannelTransform.h> | ||||||
| #include <utils/HsvTransform.h> | #include <utils/HsvTransform.h> | ||||||
|  | #include <utils/HslTransform.h> | ||||||
|  |  | ||||||
| class ColorTransform | class ColorTransform | ||||||
| { | { | ||||||
| @@ -23,4 +24,7 @@ public: | |||||||
|  |  | ||||||
| 	/// The HSV Transform for applying Saturation and Value transforms | 	/// The HSV Transform for applying Saturation and Value transforms | ||||||
| 	HsvTransform _hsvTransform; | 	HsvTransform _hsvTransform; | ||||||
|  |  | ||||||
|  | 	/// The HSL Transform for applying Saturation and Value transforms | ||||||
|  | 	HslTransform _hslTransform; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -13,6 +13,8 @@ | |||||||
| // Hyperion includes | // Hyperion includes | ||||||
| #include <hyperion/LedString.h> | #include <hyperion/LedString.h> | ||||||
| #include <hyperion/PriorityMuxer.h> | #include <hyperion/PriorityMuxer.h> | ||||||
|  | #include <hyperion/ColorTransform.h> | ||||||
|  | #include <hyperion/ColorCorrection.h> | ||||||
| #include <hyperion/MessageForwarder.h> | #include <hyperion/MessageForwarder.h> | ||||||
|  |  | ||||||
| // Effect engine includes | // Effect engine includes | ||||||
| @@ -23,8 +25,12 @@ class LedDevice; | |||||||
| class ColorTransform; | class ColorTransform; | ||||||
| class EffectEngine; | class EffectEngine; | ||||||
| class HsvTransform; | class HsvTransform; | ||||||
|  | class HslTransform; | ||||||
| class RgbChannelTransform; | class RgbChannelTransform; | ||||||
|  | class RgbChannelCorrection; | ||||||
| class MultiColorTransform; | class MultiColorTransform; | ||||||
|  | class MultiColorCorrection; | ||||||
|  | class MultiColorTemperature; | ||||||
|  |  | ||||||
| /// | /// | ||||||
| /// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through | /// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through | ||||||
| @@ -117,18 +123,50 @@ public slots: | |||||||
| 	/// | 	/// | ||||||
| 	const std::vector<std::string> & getTransformIds() const; | 	const std::vector<std::string> & getTransformIds() const; | ||||||
| 	 | 	 | ||||||
|  | 	/// | ||||||
|  | 	/// Returns the list with unique correction identifiers | ||||||
|  | 	/// @return The list with correction identifiers | ||||||
|  | 	/// | ||||||
|  | 	const std::vector<std::string> & getCorrectionIds() const; | ||||||
|  | 	 | ||||||
|  | 	/// | ||||||
|  | 	/// Returns the list with unique correction identifiers | ||||||
|  | 	/// @return The list with correction identifiers | ||||||
|  | 	/// | ||||||
|  | 	const std::vector<std::string> & getTemperatureIds() const; | ||||||
|  | 	 | ||||||
| 	/// | 	/// | ||||||
| 	/// Returns the ColorTransform with the given identifier | 	/// Returns the ColorTransform with the given identifier | ||||||
| 	/// @return The transform with the given identifier (or nullptr if the identifier does not exist) | 	/// @return The transform with the given identifier (or nullptr if the identifier does not exist) | ||||||
| 	/// | 	/// | ||||||
| 	ColorTransform * getTransform(const std::string& id); | 	ColorTransform * getTransform(const std::string& id); | ||||||
| 	 | 	 | ||||||
|  | 	/// | ||||||
|  | 	/// Returns the ColorCorrection with the given identifier | ||||||
|  | 	/// @return The correction with the given identifier (or nullptr if the identifier does not exist) | ||||||
|  | 	/// | ||||||
|  | 	ColorCorrection * getCorrection(const std::string& id); | ||||||
|  | 	 | ||||||
|  | 	/// | ||||||
|  | 	/// Returns the ColorCorrection with the given identifier | ||||||
|  | 	/// @return The correction with the given identifier (or nullptr if the identifier does not exist) | ||||||
|  | 	/// | ||||||
|  | 	ColorCorrection * getTemperature(const std::string& id); | ||||||
|  | 	 | ||||||
|  | 	/// | ||||||
|  | 	/// Returns  MessageForwarder Object | ||||||
|  | 	/// @return instance of message forwarder object | ||||||
|  | 	/// | ||||||
|  | 	MessageForwarder * getForwarder(); | ||||||
|  |  | ||||||
| 	/// Tell Hyperion that the transforms have changed and the leds need to be updated | 	/// Tell Hyperion that the transforms have changed and the leds need to be updated | ||||||
| 	void transformsUpdated(); | 	void transformsUpdated(); | ||||||
| 	 | 	 | ||||||
| 	/// Returns  MessageForwarder Object | 	/// Tell Hyperion that the corrections have changed and the leds need to be updated | ||||||
| 	/// @return instance of message forwarder object | 	void correctionsUpdated(); | ||||||
| 	MessageForwarder * getForwarder(); | 	 | ||||||
|  | 	/// Tell Hyperion that the corrections have changed and the leds need to be updated | ||||||
|  | 	void temperaturesUpdated(); | ||||||
|  |  | ||||||
| 	/// | 	/// | ||||||
| 	/// Clears the given priority channel. This will switch the led-colors to the colors of the next | 	/// Clears the given priority channel. This will switch the led-colors to the colors of the next | ||||||
| @@ -168,9 +206,14 @@ public: | |||||||
| 	static LedString createLedString(const Json::Value & ledsConfig, const ColorOrder deviceOrder); | 	static LedString createLedString(const Json::Value & ledsConfig, const ColorOrder deviceOrder); | ||||||
|  |  | ||||||
| 	static MultiColorTransform * createLedColorsTransform(const unsigned ledCnt, const Json::Value & colorTransformConfig); | 	static MultiColorTransform * createLedColorsTransform(const unsigned ledCnt, const Json::Value & colorTransformConfig); | ||||||
|  | 	static MultiColorCorrection * createLedColorsCorrection(const unsigned ledCnt, const Json::Value & colorCorrectionConfig); | ||||||
|  | 	static MultiColorCorrection * createLedColorsTemperature(const unsigned ledCnt, const Json::Value & colorTemperatureConfig); | ||||||
| 	static ColorTransform * createColorTransform(const Json::Value & transformConfig); | 	static ColorTransform * createColorTransform(const Json::Value & transformConfig); | ||||||
|  | 	static ColorCorrection * createColorCorrection(const Json::Value & correctionConfig); | ||||||
| 	static HsvTransform * createHsvTransform(const Json::Value & hsvConfig); | 	static HsvTransform * createHsvTransform(const Json::Value & hsvConfig); | ||||||
|  | 	static HslTransform * createHslTransform(const Json::Value & hslConfig); | ||||||
| 	static RgbChannelTransform * createRgbChannelTransform(const Json::Value& colorConfig); | 	static RgbChannelTransform * createRgbChannelTransform(const Json::Value& colorConfig); | ||||||
|  | 	static RgbChannelCorrection * createRgbChannelCorrection(const Json::Value& colorConfig); | ||||||
|  |  | ||||||
| 	static LedDevice * createColorSmoothing(const Json::Value & smoothingConfig, LedDevice * ledDevice); | 	static LedDevice * createColorSmoothing(const Json::Value & smoothingConfig, LedDevice * ledDevice); | ||||||
| 	static MessageForwarder * createMessageForwarder(const Json::Value & forwarderConfig); | 	static MessageForwarder * createMessageForwarder(const Json::Value & forwarderConfig); | ||||||
| @@ -198,9 +241,15 @@ private: | |||||||
| 	/// The priority muxer | 	/// The priority muxer | ||||||
| 	PriorityMuxer _muxer; | 	PriorityMuxer _muxer; | ||||||
|  |  | ||||||
| 	/// The transformation from raw colors to led colors | 	/// The transformation from corrected colors to led colors | ||||||
| 	MultiColorTransform * _raw2ledTransform; | 	MultiColorTransform * _raw2ledTransform; | ||||||
| 	 | 	 | ||||||
|  | 	/// The correction from raw colors to led colors | ||||||
|  | 	MultiColorCorrection * _raw2ledCorrection; | ||||||
|  | 	 | ||||||
|  | 	/// The temperature from corrected colors to led colors | ||||||
|  | 	MultiColorCorrection * _raw2ledTemperature; | ||||||
|  | 	 | ||||||
| 	/// The actual LedDevice | 	/// The actual LedDevice | ||||||
| 	LedDevice * _device; | 	LedDevice * _device; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										100
									
								
								include/utils/HslTransform.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								include/utils/HslTransform.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | // STL includes | ||||||
|  | #include <cstdint> | ||||||
|  |  | ||||||
|  | /// | ||||||
|  | /// Color transformation to adjust the saturation and luminance of a RGB color value | ||||||
|  | /// | ||||||
|  | class HslTransform | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	/// | ||||||
|  | 	/// Default constructor | ||||||
|  | 	/// | ||||||
|  | 	HslTransform(); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Constructor | ||||||
|  | 	/// | ||||||
|  | 	/// @param saturationGain The used saturation gain | ||||||
|  | 	/// @param luminanceGain The used luminance gain | ||||||
|  | 	/// | ||||||
|  | 	HslTransform(double saturationGain, double luminanceGain); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Destructor | ||||||
|  | 	/// | ||||||
|  | 	~HslTransform(); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Updates the saturation gain | ||||||
|  | 	/// | ||||||
|  | 	/// @param saturationGain New saturationGain | ||||||
|  | 	/// | ||||||
|  | 	void setSaturationGain(double saturationGain); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Returns the saturation gain | ||||||
|  | 	/// | ||||||
|  | 	/// @return The current Saturation gain | ||||||
|  | 	/// | ||||||
|  | 	double getSaturationGain() const; | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Updates the luminance gain | ||||||
|  | 	/// | ||||||
|  | 	/// @param luminanceGain New luminance gain | ||||||
|  | 	/// | ||||||
|  | 	void setLuminanceGain(double luminanceGain); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Returns the luminance gain | ||||||
|  | 	/// | ||||||
|  | 	/// @return The current luminance gain | ||||||
|  | 	/// | ||||||
|  | 	double getLuminanceGain() const; | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Apply the transform the the given RGB values. | ||||||
|  | 	/// | ||||||
|  | 	/// @param red The red color component | ||||||
|  | 	/// @param green The green color component | ||||||
|  | 	/// @param blue The blue color component | ||||||
|  | 	/// | ||||||
|  | 	/// @note The values are updated in place. | ||||||
|  | 	/// | ||||||
|  | 	void transform(uint8_t & red, uint8_t & green, uint8_t & blue) const; | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	///	Translates an RGB (red, green, blue) color to an HSL (hue, saturation, luminance) color | ||||||
|  | 	/// | ||||||
|  | 	/// @param[in] red The red RGB-component | ||||||
|  | 	/// @param[in] green The green RGB-component | ||||||
|  | 	/// @param[in] blue The blue RGB-component | ||||||
|  | 	/// @param[out] hue The hue HSL-component | ||||||
|  | 	/// @param[out] saturation The saturation HSL-component | ||||||
|  | 	/// @param[out] luminance The luminance HSL-component | ||||||
|  | 	/// | ||||||
|  |  | ||||||
|  | 	static void rgb2hsl(uint8_t red, uint8_t green, uint8_t blue, uint16_t & hue, float & saturation, float & luminance); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	///	Translates an HSL (hue, saturation, luminance) color to an RGB (red, green, blue) color | ||||||
|  | 	/// | ||||||
|  | 	/// @param[in] hue The hue HSL-component | ||||||
|  | 	/// @param[in] saturation The saturation HSL-component | ||||||
|  | 	/// @param[in] luminance The luminance HSL-component | ||||||
|  | 	/// @param[out] red The red RGB-component | ||||||
|  | 	/// @param[out] green The green RGB-component | ||||||
|  | 	/// @param[out] blue The blue RGB-component | ||||||
|  | 	/// | ||||||
|  |  | ||||||
|  | 	static void hsl2rgb(uint16_t hue, float saturation, float luminance, uint8_t & red, uint8_t & green, uint8_t & blue); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	/// The saturation gain | ||||||
|  | 	double _saturationGain; | ||||||
|  | 	/// The luminance gain | ||||||
|  | 	double _luminanceGain; | ||||||
|  | }; | ||||||
							
								
								
									
										66
									
								
								include/utils/RgbChannelCorrection.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								include/utils/RgbChannelCorrection.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | // STL includes | ||||||
|  | #include <cstdint> | ||||||
|  |  | ||||||
|  | /// Correction for a single color byte value | ||||||
|  | /// All configuration values are unsigned int and assume the color value to be between 0 and 255 | ||||||
|  | class RgbChannelCorrection | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	/// Default constructor | ||||||
|  | 	RgbChannelCorrection(); | ||||||
|  | 	 | ||||||
|  | 	/// Constructor | ||||||
|  | 	/// @param correctionR   | ||||||
|  | 	/// @param correctionG  | ||||||
|  | 	/// @param correctionB  | ||||||
|  |  | ||||||
|  | 	RgbChannelCorrection(int correctionR, int correctionG, int correctionB); | ||||||
|  |  | ||||||
|  | 	/// Destructor | ||||||
|  | 	~RgbChannelCorrection(); | ||||||
|  |  | ||||||
|  | 	/// @return The current correctionR value | ||||||
|  | 	uint8_t getcorrectionR() const; | ||||||
|  |  | ||||||
|  | 	/// @param threshold New correctionR value | ||||||
|  | 	void setcorrectionR(uint8_t correctionR); | ||||||
|  |  | ||||||
|  | 	/// @return The current correctionG value | ||||||
|  | 	uint8_t getcorrectionG() const; | ||||||
|  |  | ||||||
|  | 	/// @param gamma New correctionG value | ||||||
|  | 	void setcorrectionG(uint8_t correctionG); | ||||||
|  |  | ||||||
|  | 	/// @return The current correctionB value | ||||||
|  | 	uint8_t getcorrectionB() const; | ||||||
|  |  | ||||||
|  | 	/// @param blacklevel New correctionB value | ||||||
|  | 	void setcorrectionB(uint8_t correctionB); | ||||||
|  |  | ||||||
|  | 	/// Transform the given array value | ||||||
|  | 	/// @param input The input color bytes | ||||||
|  | 	/// @return The corrected byte value | ||||||
|  | 	uint8_t correctionR(uint8_t inputR) const; | ||||||
|  | 	uint8_t correctionG(uint8_t inputG) const; | ||||||
|  | 	uint8_t correctionB(uint8_t inputB) const; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	/// (re)-initilize the color mapping | ||||||
|  | 	void initializeMapping(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	/// The correction of R channel | ||||||
|  | 	int _correctionR; | ||||||
|  | 	/// The correction of G channel | ||||||
|  | 	int _correctionG; | ||||||
|  | 	/// The correction of B channel | ||||||
|  | 	int _correctionB; | ||||||
|  | 	 | ||||||
|  | 	/// The mapping from input color to output color | ||||||
|  | 	int _mappingR[256]; | ||||||
|  | 	int _mappingG[256]; | ||||||
|  | 	int _mappingB[256]; | ||||||
|  | }; | ||||||
| @@ -18,6 +18,7 @@ SET(Hyperion_HEADERS | |||||||
| 		${CURRENT_HEADER_DIR}/PriorityMuxer.h | 		${CURRENT_HEADER_DIR}/PriorityMuxer.h | ||||||
|  |  | ||||||
| 		${CURRENT_SOURCE_DIR}/MultiColorTransform.h | 		${CURRENT_SOURCE_DIR}/MultiColorTransform.h | ||||||
|  | 		${CURRENT_SOURCE_DIR}/MultiColorCorrection.h | ||||||
| 		${CURRENT_HEADER_DIR}/MessageForwarder.h | 		${CURRENT_HEADER_DIR}/MessageForwarder.h | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -30,6 +31,7 @@ SET(Hyperion_SOURCES | |||||||
|  |  | ||||||
| 		${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp | 		${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp | ||||||
| 		${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp | 		${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp | ||||||
|  | 		${CURRENT_SOURCE_DIR}/MultiColorCorrection.cpp | ||||||
| 		${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp | 		${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp | ||||||
| 		${CURRENT_SOURCE_DIR}/MessageForwarder.cpp | 		${CURRENT_SOURCE_DIR}/MessageForwarder.cpp | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -15,12 +15,15 @@ | |||||||
| // hyperion include | // hyperion include | ||||||
| #include <hyperion/Hyperion.h> | #include <hyperion/Hyperion.h> | ||||||
| #include <hyperion/ImageProcessorFactory.h> | #include <hyperion/ImageProcessorFactory.h> | ||||||
|  | #include <hyperion/ColorTransform.h> | ||||||
|  | #include <hyperion/ColorCorrection.h> | ||||||
|  |  | ||||||
| // Leddevice includes | // Leddevice includes | ||||||
| #include <leddevice/LedDevice.h> | #include <leddevice/LedDevice.h> | ||||||
| #include <leddevice/LedDeviceFactory.h> | #include <leddevice/LedDeviceFactory.h> | ||||||
|  |  | ||||||
| #include "MultiColorTransform.h" | #include "MultiColorTransform.h" | ||||||
|  | #include "MultiColorCorrection.h" | ||||||
| #include "LinearColorSmoothing.h" | #include "LinearColorSmoothing.h" | ||||||
|  |  | ||||||
| // effect engine includes | // effect engine includes | ||||||
| @@ -77,6 +80,7 @@ ColorTransform * Hyperion::createColorTransform(const Json::Value & transformCon | |||||||
| 	RgbChannelTransform * blueTransform  = createRgbChannelTransform(transformConfig["blue"]); | 	RgbChannelTransform * blueTransform  = createRgbChannelTransform(transformConfig["blue"]); | ||||||
|  |  | ||||||
| 	HsvTransform * hsvTransform = createHsvTransform(transformConfig["hsv"]); | 	HsvTransform * hsvTransform = createHsvTransform(transformConfig["hsv"]); | ||||||
|  | 	HslTransform * hslTransform = createHslTransform(transformConfig["hsl"]); | ||||||
|  |  | ||||||
| 	ColorTransform * transform = new ColorTransform(); | 	ColorTransform * transform = new ColorTransform(); | ||||||
| 	transform->_id = id; | 	transform->_id = id; | ||||||
| @@ -84,16 +88,35 @@ ColorTransform * Hyperion::createColorTransform(const Json::Value & transformCon | |||||||
| 	transform->_rgbGreenTransform = *greenTransform; | 	transform->_rgbGreenTransform = *greenTransform; | ||||||
| 	transform->_rgbBlueTransform  = *blueTransform; | 	transform->_rgbBlueTransform  = *blueTransform; | ||||||
| 	transform->_hsvTransform      = *hsvTransform; | 	transform->_hsvTransform      = *hsvTransform; | ||||||
|  | 	transform->_hslTransform      = *hslTransform; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	// Cleanup the allocated individual transforms | 	// Cleanup the allocated individual transforms | ||||||
| 	delete redTransform; | 	delete redTransform; | ||||||
| 	delete greenTransform; | 	delete greenTransform; | ||||||
| 	delete blueTransform; | 	delete blueTransform; | ||||||
| 	delete hsvTransform; | 	delete hsvTransform; | ||||||
|  | 	delete hslTransform; | ||||||
|  |  | ||||||
| 	return transform; | 	return transform; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | ColorCorrection * Hyperion::createColorCorrection(const Json::Value & correctionConfig) | ||||||
|  | { | ||||||
|  | 	const std::string id = correctionConfig.get("id", "default").asString(); | ||||||
|  |  | ||||||
|  | 	RgbChannelCorrection * rgbCorrection   = createRgbChannelCorrection(correctionConfig["correctionValues"]); | ||||||
|  |  | ||||||
|  | 	ColorCorrection * correction = new ColorCorrection(); | ||||||
|  | 	correction->_id = id; | ||||||
|  | 	correction->_rgbCorrection   = *rgbCorrection; | ||||||
|  |  | ||||||
|  | 	// Cleanup the allocated individual transforms | ||||||
|  | 	delete rgbCorrection; | ||||||
|  |  | ||||||
|  | 	return correction; | ||||||
|  | } | ||||||
|  |  | ||||||
| MultiColorTransform * Hyperion::createLedColorsTransform(const unsigned ledCnt, const Json::Value & colorConfig) | MultiColorTransform * Hyperion::createLedColorsTransform(const unsigned ledCnt, const Json::Value & colorConfig) | ||||||
| { | { | ||||||
| 	// Create the result, the transforms are added to this | 	// Create the result, the transforms are added to this | ||||||
| @@ -168,6 +191,154 @@ MultiColorTransform * Hyperion::createLedColorsTransform(const unsigned ledCnt, | |||||||
| 	return transform; | 	return transform; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | MultiColorCorrection * Hyperion::createLedColorsCorrection(const unsigned ledCnt, const Json::Value & colorConfig) | ||||||
|  | { | ||||||
|  | 	// Create the result, the corrections are added to this | ||||||
|  | 	MultiColorCorrection * correction = new MultiColorCorrection(ledCnt); | ||||||
|  |  | ||||||
|  | 	const Json::Value correctionConfig = colorConfig.get("correction", Json::nullValue); | ||||||
|  | 	if (correctionConfig.isNull()) | ||||||
|  | 	{ | ||||||
|  | 		// Old style color correction config (just one for all leds) | ||||||
|  | 		ColorCorrection * colorCorrection = createColorCorrection(colorConfig); | ||||||
|  | 		correction->addCorrection(colorCorrection); | ||||||
|  | 		correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); | ||||||
|  | 	} | ||||||
|  | 	else if (!correctionConfig.isArray()) | ||||||
|  | 	{ | ||||||
|  | 		ColorCorrection * colorCorrection = createColorCorrection(colorConfig); | ||||||
|  | 		correction->addCorrection(colorCorrection); | ||||||
|  | 		correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		const QRegExp overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*"); | ||||||
|  |  | ||||||
|  | 		for (Json::UInt i = 0; i < correctionConfig.size(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			const Json::Value & config = correctionConfig[i]; | ||||||
|  | 			ColorCorrection * colorCorrection = createColorCorrection(config); | ||||||
|  | 			correction->addCorrection(colorCorrection); | ||||||
|  |  | ||||||
|  | 			const QString ledIndicesStr = QString(config.get("leds", "").asCString()).trimmed(); | ||||||
|  | 			if (ledIndicesStr.compare("*") == 0) | ||||||
|  | 			{ | ||||||
|  | 				// Special case for indices '*' => all leds | ||||||
|  | 				correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); | ||||||
|  | 				std::cout << "ColorCorrection '" << colorCorrection->_id << "' => [0; "<< ledCnt-1 << "]" << std::endl; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (!overallExp.exactMatch(ledIndicesStr)) | ||||||
|  | 			{ | ||||||
|  | 				std::cerr << "Given led indices " << i << " not correct format: " << ledIndicesStr.toStdString() << std::endl; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			std::cout << "ColorCorrection '" << colorCorrection->_id << "' => ["; | ||||||
|  |  | ||||||
|  | 			const QStringList ledIndexList = ledIndicesStr.split(","); | ||||||
|  | 			for (int i=0; i<ledIndexList.size(); ++i) { | ||||||
|  | 				if (i > 0) | ||||||
|  | 				{ | ||||||
|  | 					std::cout << ", "; | ||||||
|  | 				} | ||||||
|  | 				if (ledIndexList[i].contains("-")) | ||||||
|  | 				{ | ||||||
|  | 					QStringList ledIndices = ledIndexList[i].split("-"); | ||||||
|  | 					int startInd = ledIndices[0].toInt(); | ||||||
|  | 					int endInd   = ledIndices[1].toInt(); | ||||||
|  |  | ||||||
|  | 					correction->setCorrectionForLed(colorCorrection->_id, startInd, endInd); | ||||||
|  | 					std::cout << startInd << "-" << endInd; | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					int index = ledIndexList[i].toInt(); | ||||||
|  | 					correction->setCorrectionForLed(colorCorrection->_id, index, index); | ||||||
|  | 					std::cout << index; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			std::cout << "]" << std::endl; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return correction; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MultiColorCorrection * Hyperion::createLedColorsTemperature(const unsigned ledCnt, const Json::Value & colorConfig) | ||||||
|  | { | ||||||
|  | 	// Create the result, the corrections are added to this | ||||||
|  | 	MultiColorCorrection * correction = new MultiColorCorrection(ledCnt); | ||||||
|  |  | ||||||
|  | 	const Json::Value correctionConfig = colorConfig.get("temperature", Json::nullValue); | ||||||
|  | 	if (correctionConfig.isNull()) | ||||||
|  | 	{ | ||||||
|  | 		// Old style color correction config (just one for all leds) | ||||||
|  | 		ColorCorrection * colorCorrection = createColorCorrection(colorConfig); | ||||||
|  | 		correction->addCorrection(colorCorrection); | ||||||
|  | 		correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); | ||||||
|  | 	} | ||||||
|  | 	else if (!correctionConfig.isArray()) | ||||||
|  | 	{ | ||||||
|  | 		ColorCorrection * colorCorrection = createColorCorrection(colorConfig); | ||||||
|  | 		correction->addCorrection(colorCorrection); | ||||||
|  | 		correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		const QRegExp overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*"); | ||||||
|  |  | ||||||
|  | 		for (Json::UInt i = 0; i < correctionConfig.size(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			const Json::Value & config = correctionConfig[i]; | ||||||
|  | 			ColorCorrection * colorCorrection = createColorCorrection(config); | ||||||
|  | 			correction->addCorrection(colorCorrection); | ||||||
|  |  | ||||||
|  | 			const QString ledIndicesStr = QString(config.get("leds", "").asCString()).trimmed(); | ||||||
|  | 			if (ledIndicesStr.compare("*") == 0) | ||||||
|  | 			{ | ||||||
|  | 				// Special case for indices '*' => all leds | ||||||
|  | 				correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); | ||||||
|  | 				std::cout << "ColorCorrection '" << colorCorrection->_id << "' => [0; "<< ledCnt-1 << "]" << std::endl; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (!overallExp.exactMatch(ledIndicesStr)) | ||||||
|  | 			{ | ||||||
|  | 				std::cerr << "Given led indices " << i << " not correct format: " << ledIndicesStr.toStdString() << std::endl; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			std::cout << "ColorCorrection '" << colorCorrection->_id << "' => ["; | ||||||
|  |  | ||||||
|  | 			const QStringList ledIndexList = ledIndicesStr.split(","); | ||||||
|  | 			for (int i=0; i<ledIndexList.size(); ++i) { | ||||||
|  | 				if (i > 0) | ||||||
|  | 				{ | ||||||
|  | 					std::cout << ", "; | ||||||
|  | 				} | ||||||
|  | 				if (ledIndexList[i].contains("-")) | ||||||
|  | 				{ | ||||||
|  | 					QStringList ledIndices = ledIndexList[i].split("-"); | ||||||
|  | 					int startInd = ledIndices[0].toInt(); | ||||||
|  | 					int endInd   = ledIndices[1].toInt(); | ||||||
|  |  | ||||||
|  | 					correction->setCorrectionForLed(colorCorrection->_id, startInd, endInd); | ||||||
|  | 					std::cout << startInd << "-" << endInd; | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					int index = ledIndexList[i].toInt(); | ||||||
|  | 					correction->setCorrectionForLed(colorCorrection->_id, index, index); | ||||||
|  | 					std::cout << index; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			std::cout << "]" << std::endl; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return correction; | ||||||
|  | } | ||||||
|  |  | ||||||
| HsvTransform * Hyperion::createHsvTransform(const Json::Value & hsvConfig) | HsvTransform * Hyperion::createHsvTransform(const Json::Value & hsvConfig) | ||||||
| { | { | ||||||
| 	const double saturationGain = hsvConfig.get("saturationGain", 1.0).asDouble(); | 	const double saturationGain = hsvConfig.get("saturationGain", 1.0).asDouble(); | ||||||
| @@ -176,6 +347,14 @@ HsvTransform * Hyperion::createHsvTransform(const Json::Value & hsvConfig) | |||||||
| 	return new HsvTransform(saturationGain, valueGain); | 	return new HsvTransform(saturationGain, valueGain); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | HslTransform * Hyperion::createHslTransform(const Json::Value & hslConfig) | ||||||
|  | { | ||||||
|  | 	const double saturationGain = hslConfig.get("saturationGain", 1.0).asDouble(); | ||||||
|  | 	const double luminanceGain  = hslConfig.get("luminanceGain",  1.0).asDouble(); | ||||||
|  |  | ||||||
|  | 	return new HslTransform(saturationGain, luminanceGain); | ||||||
|  | } | ||||||
|  |  | ||||||
| RgbChannelTransform* Hyperion::createRgbChannelTransform(const Json::Value& colorConfig) | RgbChannelTransform* Hyperion::createRgbChannelTransform(const Json::Value& colorConfig) | ||||||
| { | { | ||||||
| 	const double threshold  = colorConfig.get("threshold", 0.0).asDouble(); | 	const double threshold  = colorConfig.get("threshold", 0.0).asDouble(); | ||||||
| @@ -187,6 +366,16 @@ RgbChannelTransform* Hyperion::createRgbChannelTransform(const Json::Value& colo | |||||||
| 	return transform; | 	return transform; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | RgbChannelCorrection* Hyperion::createRgbChannelCorrection(const Json::Value& colorConfig) | ||||||
|  | { | ||||||
|  | 	const int varR = colorConfig.get("red", 255).asInt(); | ||||||
|  | 	const int varG = colorConfig.get("green", 255).asInt(); | ||||||
|  | 	const int varB = colorConfig.get("blue", 255).asInt(); | ||||||
|  |  | ||||||
|  | 	RgbChannelCorrection* correction = new RgbChannelCorrection(varR, varG, varB); | ||||||
|  | 	return correction; | ||||||
|  | } | ||||||
|  |  | ||||||
| LedString Hyperion::createLedString(const Json::Value& ledsConfig, const ColorOrder deviceOrder) | LedString Hyperion::createLedString(const Json::Value& ledsConfig, const ColorOrder deviceOrder) | ||||||
| { | { | ||||||
| 	LedString ledString; | 	LedString ledString; | ||||||
| @@ -266,7 +455,6 @@ LedDevice * Hyperion::createColorSmoothing(const Json::Value & smoothingConfig, | |||||||
| 	return ledDevice; | 	return ledDevice; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| MessageForwarder * Hyperion::createMessageForwarder(const Json::Value & forwarderConfig) | MessageForwarder * Hyperion::createMessageForwarder(const Json::Value & forwarderConfig) | ||||||
| { | { | ||||||
| 		MessageForwarder * forwarder = new MessageForwarder(); | 		MessageForwarder * forwarder = new MessageForwarder(); | ||||||
| @@ -302,12 +490,22 @@ MessageForwarder * Hyperion::getForwarder() | |||||||
| Hyperion::Hyperion(const Json::Value &jsonConfig) : | Hyperion::Hyperion(const Json::Value &jsonConfig) : | ||||||
| 	_ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))), | 	_ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))), | ||||||
| 	_muxer(_ledString.leds().size()), | 	_muxer(_ledString.leds().size()), | ||||||
|  | 	_raw2ledCorrection(createLedColorsCorrection(_ledString.leds().size(), jsonConfig["color"])), | ||||||
|  | 	_raw2ledTemperature(createLedColorsTemperature(_ledString.leds().size(), jsonConfig["color"])), | ||||||
| 	_raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])), | 	_raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])), | ||||||
| 	_device(LedDeviceFactory::construct(jsonConfig["device"])), | 	_device(LedDeviceFactory::construct(jsonConfig["device"])), | ||||||
| 	_effectEngine(nullptr), | 	_effectEngine(nullptr), | ||||||
| 	_messageForwarder(createMessageForwarder(jsonConfig["forwarder"])), | 	_messageForwarder(createMessageForwarder(jsonConfig["forwarder"])), | ||||||
| 	_timer() | 	_timer() | ||||||
| { | { | ||||||
|  | 	if (!_raw2ledCorrection->verifyCorrections()) | ||||||
|  | 	{ | ||||||
|  | 		throw std::runtime_error("Color correction incorrectly set"); | ||||||
|  | 	} | ||||||
|  | 	if (!_raw2ledTemperature->verifyCorrections()) | ||||||
|  | 	{ | ||||||
|  | 		throw std::runtime_error("Color temperature incorrectly set"); | ||||||
|  | 	} | ||||||
| 	if (!_raw2ledTransform->verifyTransforms()) | 	if (!_raw2ledTransform->verifyTransforms()) | ||||||
| 	{ | 	{ | ||||||
| 		throw std::runtime_error("Color transformation incorrectly set"); | 		throw std::runtime_error("Color transformation incorrectly set"); | ||||||
| @@ -348,6 +546,12 @@ Hyperion::~Hyperion() | |||||||
| 	// delete the color transform | 	// delete the color transform | ||||||
| 	delete _raw2ledTransform; | 	delete _raw2ledTransform; | ||||||
| 	 | 	 | ||||||
|  | 	// delete the color correction | ||||||
|  | 	delete _raw2ledCorrection; | ||||||
|  |  | ||||||
|  | 	// delete the color temperature correction | ||||||
|  | 	delete _raw2ledTemperature; | ||||||
|  |  | ||||||
| 	// delete the message forwarder | 	// delete the message forwarder | ||||||
| 	delete _messageForwarder; | 	delete _messageForwarder; | ||||||
| } | } | ||||||
| @@ -395,16 +599,46 @@ const std::vector<std::string> & Hyperion::getTransformIds() const | |||||||
| 	return _raw2ledTransform->getTransformIds(); | 	return _raw2ledTransform->getTransformIds(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const std::vector<std::string> & Hyperion::getCorrectionIds() const | ||||||
|  | { | ||||||
|  | 	return _raw2ledCorrection->getCorrectionIds(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const std::vector<std::string> & Hyperion::getTemperatureIds() const | ||||||
|  | { | ||||||
|  | 	return _raw2ledTemperature->getCorrectionIds(); | ||||||
|  | } | ||||||
|  |  | ||||||
| ColorTransform * Hyperion::getTransform(const std::string& id) | ColorTransform * Hyperion::getTransform(const std::string& id) | ||||||
| { | { | ||||||
| 	return _raw2ledTransform->getTransform(id); | 	return _raw2ledTransform->getTransform(id); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | ColorCorrection * Hyperion::getCorrection(const std::string& id) | ||||||
|  | { | ||||||
|  | 	return _raw2ledCorrection->getCorrection(id); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ColorCorrection * Hyperion::getTemperature(const std::string& id) | ||||||
|  | { | ||||||
|  | 	return _raw2ledTemperature->getCorrection(id); | ||||||
|  | } | ||||||
|  |  | ||||||
| void Hyperion::transformsUpdated() | void Hyperion::transformsUpdated() | ||||||
| { | { | ||||||
| 	update(); | 	update(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void Hyperion::correctionsUpdated() | ||||||
|  | { | ||||||
|  | 	update(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Hyperion::temperaturesUpdated() | ||||||
|  | { | ||||||
|  | 	update(); | ||||||
|  | } | ||||||
|  |  | ||||||
| void Hyperion::clear(int priority) | void Hyperion::clear(int priority) | ||||||
| { | { | ||||||
| 	if (_muxer.hasPriority(priority)) | 	if (_muxer.hasPriority(priority)) | ||||||
| @@ -468,8 +702,10 @@ void Hyperion::update() | |||||||
| 	int priority = _muxer.getCurrentPriority(); | 	int priority = _muxer.getCurrentPriority(); | ||||||
| 	const PriorityMuxer::InputInfo & priorityInfo  = _muxer.getInputInfo(priority); | 	const PriorityMuxer::InputInfo & priorityInfo  = _muxer.getInputInfo(priority); | ||||||
|  |  | ||||||
| 	// Apply the transform to each led and color-channel | 	// Apply the correction and the transform to each led and color-channel | ||||||
| 	std::vector<ColorRgb> ledColors = _raw2ledTransform->applyTransform(priorityInfo.ledColors); | 	std::vector<ColorRgb> correctedColors = _raw2ledCorrection->applyCorrection(priorityInfo.ledColors); | ||||||
|  | 	std::vector<ColorRgb> temperatureColors = _raw2ledTemperature->applyCorrection(correctedColors); | ||||||
|  | 	std::vector<ColorRgb> ledColors =_raw2ledTransform->applyTransform(temperatureColors); | ||||||
| 	const std::vector<Led>& leds = _ledString.leds(); | 	const std::vector<Led>& leds = _ledString.leds(); | ||||||
| 	int i = 0; | 	int i = 0; | ||||||
| 	for (ColorRgb& color : ledColors) | 	for (ColorRgb& color : ledColors) | ||||||
|   | |||||||
							
								
								
									
										96
									
								
								libsrc/hyperion/MultiColorCorrection.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								libsrc/hyperion/MultiColorCorrection.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | |||||||
|  |  | ||||||
|  | // STL includes | ||||||
|  | #include <cassert> | ||||||
|  |  | ||||||
|  | // Hyperion includes | ||||||
|  | #include "MultiColorCorrection.h" | ||||||
|  |  | ||||||
|  | MultiColorCorrection::MultiColorCorrection(const unsigned ledCnt) : | ||||||
|  | 	_ledCorrections(ledCnt, nullptr) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MultiColorCorrection::~MultiColorCorrection() | ||||||
|  | { | ||||||
|  | 	// Clean up all the correctinos | ||||||
|  | 	for (ColorCorrection * correction : _correction) | ||||||
|  | 	{ | ||||||
|  | 		delete correction; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MultiColorCorrection::addCorrection(ColorCorrection * correction) | ||||||
|  | { | ||||||
|  | 	_correctionIds.push_back(correction->_id); | ||||||
|  | 	_correction.push_back(correction); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MultiColorCorrection::setCorrectionForLed(const std::string& id, const unsigned startLed, const unsigned endLed) | ||||||
|  | { | ||||||
|  | 	assert(startLed <= endLed); | ||||||
|  | 	assert(endLed < _ledCorrections.size()); | ||||||
|  |  | ||||||
|  | 	// Get the identified correction (don't care if is nullptr) | ||||||
|  | 	ColorCorrection * correction = getCorrection(id); | ||||||
|  | 	for (unsigned iLed=startLed; iLed<=endLed; ++iLed) | ||||||
|  | 	{ | ||||||
|  | 		_ledCorrections[iLed] = correction; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MultiColorCorrection::verifyCorrections() const | ||||||
|  | { | ||||||
|  | 	bool allLedsSet = true; | ||||||
|  | 	for (unsigned iLed=0; iLed<_ledCorrections.size(); ++iLed) | ||||||
|  | 	{ | ||||||
|  | 		if (_ledCorrections[iLed] == nullptr) | ||||||
|  | 		{ | ||||||
|  | 			std::cerr << "No correction set for " << iLed << std::endl; | ||||||
|  | 			allLedsSet = false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return allLedsSet; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const std::vector<std::string> & MultiColorCorrection::getCorrectionIds() | ||||||
|  | { | ||||||
|  | 	return _correctionIds; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ColorCorrection* MultiColorCorrection::getCorrection(const std::string& id) | ||||||
|  | { | ||||||
|  | 	// Iterate through the unique corrections until we find the one with the given id | ||||||
|  | 	for (ColorCorrection * correction : _correction) | ||||||
|  | 	{ | ||||||
|  | 		if (correction->_id == id) | ||||||
|  | 		{ | ||||||
|  | 			return correction; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// The ColorCorrection was not found | ||||||
|  | 	return nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::vector<ColorRgb> MultiColorCorrection::applyCorrection(const std::vector<ColorRgb>& rawColors) | ||||||
|  | { | ||||||
|  | 	// Create a copy, as we will do the rest of the correction in place | ||||||
|  | 	std::vector<ColorRgb> ledColors(rawColors); | ||||||
|  |  | ||||||
|  | 	const size_t itCnt = std::min(_ledCorrections.size(), rawColors.size()); | ||||||
|  | 	for (size_t i=0; i<itCnt; ++i) | ||||||
|  | 	{ | ||||||
|  | 		ColorCorrection * correction = _ledCorrections[i]; | ||||||
|  | 		if (correction == nullptr) | ||||||
|  | 		{ | ||||||
|  | 			// No correction set for this led (do nothing) | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		ColorRgb& color = ledColors[i]; | ||||||
|  |  | ||||||
|  | 		color.red   = correction->_rgbCorrection.correctionR(color.red); | ||||||
|  | 		color.green = correction->_rgbCorrection.correctionG(color.green); | ||||||
|  | 		color.blue  = correction->_rgbCorrection.correctionB(color.blue); | ||||||
|  | 	} | ||||||
|  | 	return ledColors; | ||||||
|  | } | ||||||
							
								
								
									
										66
									
								
								libsrc/hyperion/MultiColorCorrection.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								libsrc/hyperion/MultiColorCorrection.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | // STL includes | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | // Utils includes | ||||||
|  | #include <utils/ColorRgb.h> | ||||||
|  |  | ||||||
|  | // Hyperion includes | ||||||
|  | #include <hyperion/ColorCorrection.h> | ||||||
|  |  | ||||||
|  | /// | ||||||
|  | /// The LedColorCorrection is responsible for performing color correction from 'raw' colors | ||||||
|  | /// received as input to colors mapped to match the color-properties of the leds. | ||||||
|  | /// | ||||||
|  | class MultiColorCorrection | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	MultiColorCorrection(const unsigned ledCnt); | ||||||
|  | 	~MultiColorCorrection(); | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Adds a new ColorCorrection to this MultiColorCorrection | ||||||
|  | 	 * | ||||||
|  | 	 * @param Correction The new ColorCorrection (ownership is transfered) | ||||||
|  | 	 */ | ||||||
|  | 	void addCorrection(ColorCorrection * correction); | ||||||
|  |  | ||||||
|  | 	void setCorrectionForLed(const std::string& id, const unsigned startLed, const unsigned endLed); | ||||||
|  |  | ||||||
|  | 	bool verifyCorrections() const; | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Returns the identifier of all the unique ColorCorrection | ||||||
|  | 	/// | ||||||
|  | 	/// @return The list with unique id's of the ColorCorrections | ||||||
|  | 	const std::vector<std::string> & getCorrectionIds(); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Returns the pointer to the ColorCorrection with the given id | ||||||
|  | 	/// | ||||||
|  | 	/// @param id The identifier of the ColorCorrection | ||||||
|  | 	/// | ||||||
|  | 	/// @return The ColorCorrection with the given id (or nullptr if it does not exist) | ||||||
|  | 	/// | ||||||
|  | 	ColorCorrection* getCorrection(const std::string& id); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Performs the color transoformation from raw-color to led-color | ||||||
|  | 	/// | ||||||
|  | 	/// @param rawColors The list with raw colors | ||||||
|  | 	/// | ||||||
|  | 	/// @return The list with led-colors | ||||||
|  | 	/// | ||||||
|  | 	std::vector<ColorRgb> applyCorrection(const std::vector<ColorRgb>& rawColors); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	/// List with Correction ids | ||||||
|  | 	std::vector<std::string> _correctionIds; | ||||||
|  |  | ||||||
|  | 	/// List with unique ColorCorrections | ||||||
|  | 	std::vector<ColorCorrection*> _correction; | ||||||
|  |  | ||||||
|  | 	/// List with a pointer to the ColorCorrection for each individual led | ||||||
|  | 	std::vector<ColorCorrection*> _ledCorrections; | ||||||
|  | }; | ||||||
| @@ -89,6 +89,7 @@ std::vector<ColorRgb> MultiColorTransform::applyTransform(const std::vector<Colo | |||||||
| 		ColorRgb& color = ledColors[i]; | 		ColorRgb& color = ledColors[i]; | ||||||
|  |  | ||||||
| 		transform->_hsvTransform.transform(color.red, color.green, color.blue); | 		transform->_hsvTransform.transform(color.red, color.green, color.blue); | ||||||
|  | 		transform->_hslTransform.transform(color.red, color.green, color.blue); | ||||||
| 		color.red   = transform->_rgbRedTransform.transform(color.red); | 		color.red   = transform->_rgbRedTransform.transform(color.red); | ||||||
| 		color.green = transform->_rgbGreenTransform.transform(color.green); | 		color.green = transform->_rgbGreenTransform.transform(color.green); | ||||||
| 		color.blue  = transform->_rgbBlueTransform.transform(color.blue); | 		color.blue  = transform->_rgbBlueTransform.transform(color.blue); | ||||||
|   | |||||||
| @@ -54,6 +54,23 @@ | |||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                     "additionalProperties" : false |                     "additionalProperties" : false | ||||||
|  |                 }, | ||||||
|  | 				"hsl" : { | ||||||
|  |                     "type" : "object", | ||||||
|  |                     "required" : false, | ||||||
|  |                     "properties" : { | ||||||
|  |                         "saturationGain" : { | ||||||
|  |                             "type" : "number", | ||||||
|  |                             "required" : false, | ||||||
|  |                             "minimum" : 0.0 | ||||||
|  |                         }, | ||||||
|  |                         "luminanceGain" : { | ||||||
|  |                             "type" : "number", | ||||||
|  |                             "required" : false, | ||||||
|  |                             "minimum" : 0.0 | ||||||
|  |                         } | ||||||
|  |                     }, | ||||||
|  |                     "additionalProperties" : false | ||||||
|                 }, |                 }, | ||||||
|                 "red": { |                 "red": { | ||||||
|                     "type":"object", |                     "type":"object", | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ | |||||||
| #include <hyperion/ImageProcessor.h> | #include <hyperion/ImageProcessor.h> | ||||||
| #include <hyperion/MessageForwarder.h> | #include <hyperion/MessageForwarder.h> | ||||||
| #include <hyperion/ColorTransform.h> | #include <hyperion/ColorTransform.h> | ||||||
|  | #include <hyperion/ColorCorrection.h> | ||||||
| #include <utils/ColorRgb.h> | #include <utils/ColorRgb.h> | ||||||
|  |  | ||||||
| // project includes | // project includes | ||||||
| @@ -247,6 +248,10 @@ void JsonClientConnection::handleMessage(const std::string &messageString) | |||||||
| 		handleClearallCommand(message); | 		handleClearallCommand(message); | ||||||
| 	else if (command == "transform") | 	else if (command == "transform") | ||||||
| 		handleTransformCommand(message); | 		handleTransformCommand(message); | ||||||
|  | 	else if (command == "correction") | ||||||
|  | 		handleCorrectionCommand(message); | ||||||
|  | 	else if (command == "temperature") | ||||||
|  | 		handleTemperatureCommand(message); | ||||||
| 	else | 	else | ||||||
| 		handleNotImplemented(); | 		handleNotImplemented(); | ||||||
| } | } | ||||||
| @@ -388,6 +393,47 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	// collect correction information | ||||||
|  | 	Json::Value & correctionArray = info["correction"]; | ||||||
|  | 	for (const std::string& correctionId : _hyperion->getCorrectionIds()) | ||||||
|  | 	{ | ||||||
|  | 		const ColorCorrection * colorCorrection = _hyperion->getCorrection(correctionId); | ||||||
|  | 		if (colorCorrection == nullptr) | ||||||
|  | 		{ | ||||||
|  | 			std::cerr << "Incorrect color correction id: " << correctionId << std::endl; | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		Json::Value & correction = correctionArray.append(Json::Value()); | ||||||
|  | 		correction["id"] = correctionId; | ||||||
|  | 		 | ||||||
|  | 		Json::Value & corrValues = correction["correctionValues"]; | ||||||
|  | 		corrValues.append(colorCorrection->_rgbCorrection.getcorrectionR()); | ||||||
|  | 		corrValues.append(colorCorrection->_rgbCorrection.getcorrectionG()); | ||||||
|  | 		corrValues.append(colorCorrection->_rgbCorrection.getcorrectionB()); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	// collect temperature correction information | ||||||
|  | 	Json::Value & temperatureArray = info["temperature"]; | ||||||
|  | 	for (const std::string& tempId : _hyperion->getTemperatureIds()) | ||||||
|  | 	{ | ||||||
|  | 		const ColorCorrection * colorTemp = _hyperion->getTemperature(tempId); | ||||||
|  | 		if (colorTemp == nullptr) | ||||||
|  | 		{ | ||||||
|  | 			std::cerr << "Incorrect color temperature correction id: " << tempId << std::endl; | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		Json::Value & temperature = temperatureArray.append(Json::Value()); | ||||||
|  | 		temperature["id"] = tempId; | ||||||
|  | 		 | ||||||
|  | 		Json::Value & tempValues = temperature["correctionValues"]; | ||||||
|  | 		tempValues.append(colorTemp->_rgbCorrection.getcorrectionR()); | ||||||
|  | 		tempValues.append(colorTemp->_rgbCorrection.getcorrectionG()); | ||||||
|  | 		tempValues.append(colorTemp->_rgbCorrection.getcorrectionB()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	// collect transform information | 	// collect transform information | ||||||
| 	Json::Value & transformArray = info["transform"]; | 	Json::Value & transformArray = info["transform"]; | ||||||
| 	for (const std::string& transformId : _hyperion->getTransformIds()) | 	for (const std::string& transformId : _hyperion->getTransformIds()) | ||||||
| @@ -404,6 +450,8 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &) | |||||||
|  |  | ||||||
| 		transform["saturationGain"] = colorTransform->_hsvTransform.getSaturationGain(); | 		transform["saturationGain"] = colorTransform->_hsvTransform.getSaturationGain(); | ||||||
| 		transform["valueGain"]      = colorTransform->_hsvTransform.getValueGain(); | 		transform["valueGain"]      = colorTransform->_hsvTransform.getValueGain(); | ||||||
|  | 		transform["saturationLGain"] = colorTransform->_hslTransform.getSaturationGain(); | ||||||
|  | 		transform["luminanceGain"]   = colorTransform->_hslTransform.getLuminanceGain(); | ||||||
|  |  | ||||||
| 		Json::Value & threshold = transform["threshold"]; | 		Json::Value & threshold = transform["threshold"]; | ||||||
| 		threshold.append(colorTransform->_rgbRedTransform.getThreshold()); | 		threshold.append(colorTransform->_rgbRedTransform.getThreshold()); | ||||||
| @@ -487,6 +535,16 @@ void JsonClientConnection::handleTransformCommand(const Json::Value &message) | |||||||
| 		colorTransform->_hsvTransform.setValueGain(transform["valueGain"].asDouble()); | 		colorTransform->_hsvTransform.setValueGain(transform["valueGain"].asDouble()); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	if (transform.isMember("saturationLGain")) | ||||||
|  | 	{ | ||||||
|  | 		colorTransform->_hslTransform.setSaturationGain(transform["saturationLGain"].asDouble()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (transform.isMember("luminanceGain")) | ||||||
|  | 	{ | ||||||
|  | 		colorTransform->_hslTransform.setLuminanceGain(transform["luminanceGain"].asDouble()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (transform.isMember("threshold")) | 	if (transform.isMember("threshold")) | ||||||
| 	{ | 	{ | ||||||
| 		const Json::Value & values = transform["threshold"]; | 		const Json::Value & values = transform["threshold"]; | ||||||
| @@ -525,6 +583,58 @@ void JsonClientConnection::handleTransformCommand(const Json::Value &message) | |||||||
| 	sendSuccessReply(); | 	sendSuccessReply(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void JsonClientConnection::handleCorrectionCommand(const Json::Value &message) | ||||||
|  | { | ||||||
|  | 	const Json::Value & correction = message["correction"]; | ||||||
|  |  | ||||||
|  | 	const std::string correctionId = correction.get("id", _hyperion->getCorrectionIds().front()).asString(); | ||||||
|  | 	ColorCorrection * colorCorrection = _hyperion->getCorrection(correctionId); | ||||||
|  | 	if (colorCorrection == nullptr) | ||||||
|  | 	{ | ||||||
|  | 		//sendErrorReply(std::string("Incorrect correction identifier: ") + correctionId); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (correction.isMember("correctionValues")) | ||||||
|  | 	{ | ||||||
|  | 		const Json::Value & values = correction["correctionValues"]; | ||||||
|  | 		colorCorrection->_rgbCorrection.setcorrectionR(values[0u].asInt()); | ||||||
|  | 		colorCorrection->_rgbCorrection.setcorrectionG(values[1u].asInt()); | ||||||
|  | 		colorCorrection->_rgbCorrection.setcorrectionB(values[2u].asInt()); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	// commit the changes | ||||||
|  | 	_hyperion->correctionsUpdated(); | ||||||
|  |  | ||||||
|  | 	sendSuccessReply(); | ||||||
|  | } | ||||||
|  | 	 | ||||||
|  | void JsonClientConnection::handleTemperatureCommand(const Json::Value &message) | ||||||
|  | { | ||||||
|  | 	const Json::Value & temperature = message["temperature"]; | ||||||
|  |  | ||||||
|  | 	const std::string tempId = temperature.get("id", _hyperion->getTemperatureIds().front()).asString(); | ||||||
|  | 	ColorCorrection * colorTemperature = _hyperion->getTemperature(tempId); | ||||||
|  | 	if (colorTemperature == nullptr) | ||||||
|  | 	{ | ||||||
|  | 		//sendErrorReply(std::string("Incorrect temperature identifier: ") + tempId); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (temperature.isMember("correctionValues")) | ||||||
|  | 	{ | ||||||
|  | 		const Json::Value & values = temperature["correctionValues"]; | ||||||
|  | 		colorTemperature->_rgbCorrection.setcorrectionR(values[0u].asInt()); | ||||||
|  | 		colorTemperature->_rgbCorrection.setcorrectionG(values[1u].asInt()); | ||||||
|  | 		colorTemperature->_rgbCorrection.setcorrectionB(values[2u].asInt()); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	// commit the changes | ||||||
|  | 	_hyperion->temperaturesUpdated(); | ||||||
|  |  | ||||||
|  | 	sendSuccessReply(); | ||||||
|  | } | ||||||
|  | 	 | ||||||
| void JsonClientConnection::handleNotImplemented() | void JsonClientConnection::handleNotImplemented() | ||||||
| { | { | ||||||
| 	sendErrorReply("Command not implemented"); | 	sendErrorReply("Command not implemented"); | ||||||
|   | |||||||
| @@ -113,6 +113,20 @@ private: | |||||||
| 	/// | 	/// | ||||||
| 	void handleTransformCommand(const Json::Value & message); | 	void handleTransformCommand(const Json::Value & message); | ||||||
| 	 | 	 | ||||||
|  | 	/// | ||||||
|  | 	/// Handle an incoming JSON Correction message | ||||||
|  | 	/// | ||||||
|  | 	/// @param message the incoming message | ||||||
|  | 	/// | ||||||
|  | 	void handleCorrectionCommand(const Json::Value & message); | ||||||
|  | 	 | ||||||
|  | 	/// | ||||||
|  | 	/// Handle an incoming JSON Temperature message | ||||||
|  | 	/// | ||||||
|  | 	/// @param message the incoming message | ||||||
|  | 	/// | ||||||
|  | 	void handleTemperatureCommand(const Json::Value & message); | ||||||
|  |  | ||||||
| 	/// | 	/// | ||||||
| 	/// Handle an incoming JSON message of unknown type | 	/// Handle an incoming JSON message of unknown type | ||||||
| 	/// | 	/// | ||||||
|   | |||||||
| @@ -7,6 +7,8 @@ | |||||||
|         <file alias="schema-clear">schema/schema-clear.json</file> |         <file alias="schema-clear">schema/schema-clear.json</file> | ||||||
|         <file alias="schema-clearall">schema/schema-clearall.json</file> |         <file alias="schema-clearall">schema/schema-clearall.json</file> | ||||||
|         <file alias="schema-transform">schema/schema-transform.json</file> |         <file alias="schema-transform">schema/schema-transform.json</file> | ||||||
|  |         <file alias="schema-correction">schema/schema-correction.json</file> | ||||||
|  |         <file alias="schema-temperature">schema/schema-temperature.json</file> | ||||||
|         <file alias="schema-effect">schema/schema-effect.json</file> |         <file alias="schema-effect">schema/schema-effect.json</file> | ||||||
|     </qresource> |     </qresource> | ||||||
| </RCC> | </RCC> | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								libsrc/jsonserver/schema/schema-correction.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								libsrc/jsonserver/schema/schema-correction.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | { | ||||||
|  | 	"type":"object", | ||||||
|  | 	"required":true, | ||||||
|  | 	"properties":{ | ||||||
|  | 		"command": { | ||||||
|  | 			"type" : "string", | ||||||
|  | 			"required" : true, | ||||||
|  | 			"enum" : ["correction"] | ||||||
|  | 		}, | ||||||
|  | 		"correction": { | ||||||
|  | 			"type": "object", | ||||||
|  | 			"required": true, | ||||||
|  | 			"properties": { | ||||||
|  | 				"id" : { | ||||||
|  | 					"type" : "string", | ||||||
|  | 					"required" : false | ||||||
|  | 				}, | ||||||
|  | 				"correctionValues" : { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"required": false, | ||||||
|  | 					"items" : { | ||||||
|  | 						"type": "integer", | ||||||
|  | 						"minimum": 0, | ||||||
|  | 						"maximum": 255 | ||||||
|  | 					}, | ||||||
|  | 					"minItems": 3, | ||||||
|  | 					"maxItems": 3 | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			"additionalProperties": false | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"additionalProperties": false | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								libsrc/jsonserver/schema/schema-temperature.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								libsrc/jsonserver/schema/schema-temperature.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | { | ||||||
|  | 	"type":"object", | ||||||
|  | 	"required":true, | ||||||
|  | 	"properties":{ | ||||||
|  | 		"command": { | ||||||
|  | 			"type" : "string", | ||||||
|  | 			"required" : true, | ||||||
|  | 			"enum" : ["temperature"] | ||||||
|  | 		}, | ||||||
|  | 		"temperature": { | ||||||
|  | 			"type": "object", | ||||||
|  | 			"required": true, | ||||||
|  | 			"properties": { | ||||||
|  | 				"id" : { | ||||||
|  | 					"type" : "string", | ||||||
|  | 					"required" : false | ||||||
|  | 				}, | ||||||
|  | 				"correctionValues" : { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"required": false, | ||||||
|  | 					"items" : { | ||||||
|  | 						"type": "integer", | ||||||
|  | 						"minimum": 0, | ||||||
|  | 						"maximum": 255 | ||||||
|  | 					}, | ||||||
|  | 					"minItems": 3, | ||||||
|  | 					"maxItems": 3 | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			"additionalProperties": false | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"additionalProperties": false | ||||||
|  | } | ||||||
| @@ -25,6 +25,16 @@ | |||||||
| 					"required" : false, | 					"required" : false, | ||||||
| 					"minimum" : 0.0 | 					"minimum" : 0.0 | ||||||
| 				}, | 				}, | ||||||
|  | 				"saturationLGain" : { | ||||||
|  | 					"type" : "number", | ||||||
|  | 					"required" : false, | ||||||
|  | 					"minimum" : 0.0 | ||||||
|  | 				}, | ||||||
|  | 				"luminanceGain" : { | ||||||
|  | 					"type" : "number", | ||||||
|  | 					"required" : false, | ||||||
|  | 					"minimum" : 0.0 | ||||||
|  | 				}, | ||||||
| 				"threshold": { | 				"threshold": { | ||||||
| 					"type": "array", | 					"type": "array", | ||||||
| 					"required": false, | 					"required": false, | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|         "command": { |         "command": { | ||||||
|             "type" : "string", |             "type" : "string", | ||||||
|             "required" : true, |             "required" : true, | ||||||
|             "enum" : ["color", "image", "effect", "serverinfo", "clear", "clearall", "transform"] |             "enum" : ["color", "image", "effect", "serverinfo", "clear", "clearall", "transform", "correction", "temperature"] | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								libsrc/leddevice/LedDeviceFadeCandy.cpp
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								libsrc/leddevice/LedDeviceFadeCandy.cpp
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
									
										0
									
								
								libsrc/leddevice/LedDeviceFadeCandy.h
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								libsrc/leddevice/LedDeviceFadeCandy.h
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @@ -23,8 +23,12 @@ add_library(hyperion-utils | |||||||
|  |  | ||||||
| 		${CURRENT_HEADER_DIR}/HsvTransform.h | 		${CURRENT_HEADER_DIR}/HsvTransform.h | ||||||
| 		${CURRENT_SOURCE_DIR}/HsvTransform.cpp | 		${CURRENT_SOURCE_DIR}/HsvTransform.cpp | ||||||
|  | 		${CURRENT_HEADER_DIR}/HslTransform.h | ||||||
|  | 		${CURRENT_SOURCE_DIR}/HslTransform.cpp | ||||||
| 		${CURRENT_HEADER_DIR}/RgbChannelTransform.h | 		${CURRENT_HEADER_DIR}/RgbChannelTransform.h | ||||||
| 		${CURRENT_SOURCE_DIR}/RgbChannelTransform.cpp | 		${CURRENT_SOURCE_DIR}/RgbChannelTransform.cpp | ||||||
|  | 		${CURRENT_HEADER_DIR}/RgbChannelCorrection.h | ||||||
|  | 		${CURRENT_SOURCE_DIR}/RgbChannelCorrection.cpp | ||||||
|  |  | ||||||
| 		${CURRENT_HEADER_DIR}/jsonschema/JsonFactory.h | 		${CURRENT_HEADER_DIR}/jsonschema/JsonFactory.h | ||||||
| 		${CURRENT_HEADER_DIR}/jsonschema/JsonSchemaChecker.h | 		${CURRENT_HEADER_DIR}/jsonschema/JsonSchemaChecker.h | ||||||
|   | |||||||
							
								
								
									
										158
									
								
								libsrc/utils/HslTransform.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								libsrc/utils/HslTransform.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | |||||||
|  | #include <algorithm> | ||||||
|  | #include <cmath> | ||||||
|  | #include <utils/HslTransform.h> | ||||||
|  |  | ||||||
|  | HslTransform::HslTransform() : | ||||||
|  | 	_saturationGain(1.0), | ||||||
|  | 	_luminanceGain(1.0) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | HslTransform::HslTransform(double saturationGain, double luminanceGain) : | ||||||
|  | 	_saturationGain(saturationGain), | ||||||
|  | 	_luminanceGain(luminanceGain) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | HslTransform::~HslTransform() | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HslTransform::setSaturationGain(double saturationGain) | ||||||
|  | { | ||||||
|  | 	_saturationGain = saturationGain; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | double HslTransform::getSaturationGain() const | ||||||
|  | { | ||||||
|  | 	return _saturationGain; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HslTransform::setLuminanceGain(double luminanceGain) | ||||||
|  | { | ||||||
|  | 	_luminanceGain = luminanceGain; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | double HslTransform::getLuminanceGain() const | ||||||
|  | { | ||||||
|  | 	return _luminanceGain; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HslTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue) const | ||||||
|  | { | ||||||
|  | 	if (_saturationGain != 1.0 || _luminanceGain != 1.0) | ||||||
|  | 	{ | ||||||
|  | 		uint16_t hue; | ||||||
|  | 		float saturation, luminance; | ||||||
|  | 		rgb2hsl(red, green, blue, hue, saturation, luminance); | ||||||
|  | 		 | ||||||
|  | 		float s = saturation * _saturationGain; | ||||||
|  | 		if (s > 1.0f) | ||||||
|  | 			saturation = 1.0f; | ||||||
|  | 		else | ||||||
|  | 			saturation = s; | ||||||
|  |  | ||||||
|  | 		float l = luminance * _luminanceGain; | ||||||
|  | 		if (l > 1.0f) | ||||||
|  | 			luminance = 1.0f; | ||||||
|  | 		else | ||||||
|  | 			luminance = l; | ||||||
|  | 				 | ||||||
|  | 		hsl2rgb(hue, saturation, luminance, red, green, blue); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HslTransform::rgb2hsl(uint8_t red, uint8_t green, uint8_t blue, uint16_t & hue, float & saturation, float & luminance) | ||||||
|  | { | ||||||
|  | 	float r = red / 255.0f; | ||||||
|  | 	float g = green / 255.0f; | ||||||
|  | 	float b = blue / 255.0f;	 | ||||||
|  | 	 | ||||||
|  | 	float rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b); | ||||||
|  | 	float rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b); | ||||||
|  | 	float diff = rgbMax - rgbMin; | ||||||
|  | 		 | ||||||
|  | 	//luminance | ||||||
|  | 	luminance = (rgbMin + rgbMax) / 2.0f; | ||||||
|  | 	 | ||||||
|  | 	if (diff ==  0.0f) { | ||||||
|  | 		saturation = 0.0f; | ||||||
|  | 		hue        = 0;		 | ||||||
|  | 		return; | ||||||
|  | 	}	 | ||||||
|  | 	 | ||||||
|  | 	//saturation | ||||||
|  | 	if (luminance < 0.5f) | ||||||
|  | 		saturation = diff / (rgbMin + rgbMax); | ||||||
|  | 	else  | ||||||
|  | 		saturation = diff / (2.0f - rgbMin - rgbMax); | ||||||
|  | 	 | ||||||
|  | 	if (rgbMax == r) | ||||||
|  | 	{ | ||||||
|  | 		// start from 360 to be sure that we won't assign a negative number to the unsigned hue value | ||||||
|  | 		hue = 360 + 60 * (g - b) / (rgbMax - rgbMin); | ||||||
|  |  | ||||||
|  | 		if (hue > 359) | ||||||
|  | 			hue -= 360; | ||||||
|  | 	} | ||||||
|  | 	else if (rgbMax == g) | ||||||
|  | 	{ | ||||||
|  | 		hue = 120 + 60 * (b - r) / (rgbMax - rgbMin); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		hue = 240 + 60 * (r - g) / (rgbMax - rgbMin); | ||||||
|  | 	} | ||||||
|  | 		 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HslTransform::hsl2rgb(uint16_t hue, float saturation, float luminance, uint8_t & red, uint8_t & green, uint8_t & blue) | ||||||
|  | { | ||||||
|  | 	if (saturation == 0.0f){ | ||||||
|  | 		red = (uint8_t)(luminance * 255.0f); | ||||||
|  | 		green = (uint8_t)(luminance * 255.0f); | ||||||
|  | 		blue = (uint8_t)(luminance * 255.0f); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	float q; | ||||||
|  | 	 | ||||||
|  | 	if (luminance < 0.5f) | ||||||
|  | 		q = luminance * (1.0f + saturation); | ||||||
|  | 	else | ||||||
|  | 		q = (luminance + saturation) - (luminance * saturation); | ||||||
|  | 	 | ||||||
|  | 	float p = (2.0f * luminance) - q;	 | ||||||
|  | 	float h = hue / 360.0f; | ||||||
|  | 	 | ||||||
|  | 	float t[3]; | ||||||
|  | 	 | ||||||
|  | 	t[0] = h + (1.0f / 3.0f); | ||||||
|  | 	t[1] = h; | ||||||
|  | 	t[2] = h - (1.0f / 3.0f); | ||||||
|  | 	 | ||||||
|  | 	for (int i = 0; i < 3; i++) { | ||||||
|  | 		if (t[i] < 0.0f) | ||||||
|  | 			t[i] += 1.0f; | ||||||
|  | 		if (t[i] > 1.0f) | ||||||
|  | 			t[i] -= 1.0f; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	float out[3]; | ||||||
|  | 	 | ||||||
|  | 	for (int i = 0; i < 3; i++) { | ||||||
|  | 		if (t[i] * 6.0f < 1.0f) | ||||||
|  | 			out[i] = p + (q - p) * 6.0f * t[i]; | ||||||
|  | 		else if (t[i] * 2.0f < 1.0f) | ||||||
|  | 			out[i] = q; | ||||||
|  | 		else if (t[i] * 3.0f < 2.0f) | ||||||
|  | 			out[i] = p + (q - p) * ((2.0f / 3.0f) - t[i]) * 6.0f; | ||||||
|  | 		else out[i] = p; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	//convert back to 0...255 range | ||||||
|  | 	red = (uint8_t)(out[0] * 255.0f); | ||||||
|  | 	green = (uint8_t)(out[1] * 255.0f); | ||||||
|  | 	blue = (uint8_t)(out[2] * 255.0f); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										120
									
								
								libsrc/utils/RgbChannelCorrection.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								libsrc/utils/RgbChannelCorrection.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | |||||||
|  | // STL includes | ||||||
|  | #include <cmath> | ||||||
|  |  | ||||||
|  | // Utils includes | ||||||
|  | #include <utils/RgbChannelCorrection.h> | ||||||
|  |  | ||||||
|  | RgbChannelCorrection::RgbChannelCorrection() : | ||||||
|  | 	_correctionR(255), | ||||||
|  | 	_correctionB(255), | ||||||
|  | 	_correctionG(255) | ||||||
|  | { | ||||||
|  | 	initializeMapping(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | RgbChannelCorrection::RgbChannelCorrection(int correctionR, int correctionG, int correctionB) : | ||||||
|  | 	_correctionR(correctionR), | ||||||
|  | 	_correctionG(correctionG), | ||||||
|  | 	_correctionB(correctionB) | ||||||
|  | { | ||||||
|  | 	initializeMapping(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | RgbChannelCorrection::~RgbChannelCorrection() | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t RgbChannelCorrection::getcorrectionR() const | ||||||
|  | { | ||||||
|  | 	return _correctionR; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void RgbChannelCorrection::setcorrectionR(uint8_t correctionR) | ||||||
|  | { | ||||||
|  | 	_correctionR = correctionR; | ||||||
|  | 	initializeMapping(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t RgbChannelCorrection::getcorrectionG() const | ||||||
|  | { | ||||||
|  | 	return _correctionG; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void RgbChannelCorrection::setcorrectionG(uint8_t correctionG) | ||||||
|  | { | ||||||
|  | 	_correctionG = correctionG; | ||||||
|  | 	initializeMapping(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t RgbChannelCorrection::getcorrectionB() const | ||||||
|  | { | ||||||
|  | 	return _correctionB; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void RgbChannelCorrection::setcorrectionB(uint8_t correctionB) | ||||||
|  | { | ||||||
|  | 	_correctionB = correctionB; | ||||||
|  | 	initializeMapping(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t RgbChannelCorrection::correctionR(uint8_t inputR) const | ||||||
|  | { | ||||||
|  | 	return _mappingR[inputR]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t RgbChannelCorrection::correctionG(uint8_t inputG) const | ||||||
|  | { | ||||||
|  | 	return _mappingG[inputG]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t RgbChannelCorrection::correctionB(uint8_t inputB) const | ||||||
|  | { | ||||||
|  | 	return _mappingB[inputB]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void RgbChannelCorrection::initializeMapping() | ||||||
|  | { | ||||||
|  | 	// initialize the mapping | ||||||
|  | 	for (int i = 0; i < 256; ++i) | ||||||
|  | 	{ | ||||||
|  | 		int outputR = (i * _correctionR) / 255; | ||||||
|  | 		if (outputR < -255) | ||||||
|  | 			{ | ||||||
|  | 				outputR = -255; | ||||||
|  | 			} | ||||||
|  | 		else if (outputR > 255) | ||||||
|  | 			{ | ||||||
|  | 				outputR = 255; | ||||||
|  | 			} | ||||||
|  | 		_mappingR[i] = outputR; | ||||||
|  | 	} | ||||||
|  | 	for (int i = 0; i < 256; ++i) | ||||||
|  | 	{ | ||||||
|  | 		int outputG = (i * _correctionG) / 255; | ||||||
|  | 		if (outputG < -255) | ||||||
|  | 			{ | ||||||
|  | 				outputG = -255; | ||||||
|  | 			} | ||||||
|  | 		else if (outputG > 255) | ||||||
|  | 			{ | ||||||
|  | 				outputG = 255; | ||||||
|  | 			} | ||||||
|  | 		_mappingG[i] = outputG; | ||||||
|  | 	} | ||||||
|  | 	for (int i = 0; i < 256; ++i) | ||||||
|  | 	{ | ||||||
|  | 		int outputB = (i * _correctionB) / 255; | ||||||
|  | 		if (outputB < -255) | ||||||
|  | 			{ | ||||||
|  | 				outputB = -255; | ||||||
|  | 			} | ||||||
|  | 		else if (outputB > 255) | ||||||
|  | 			{ | ||||||
|  | 				outputB = 255; | ||||||
|  | 			} | ||||||
|  | 		_mappingB[i] = outputB; | ||||||
|  | 	} | ||||||
|  | 		 | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								src/hyperion-remote/ColorCorrectionValues.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/hyperion-remote/ColorCorrectionValues.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | /// Simple structure to contain the values of a color transformation | ||||||
|  | struct ColorCorrectionValues | ||||||
|  | { | ||||||
|  | 	/// The value for the red color-channel | ||||||
|  | 	int valueRed; | ||||||
|  | 	/// The value for the green color-channel | ||||||
|  | 	int valueGreen; | ||||||
|  | 	/// The value for the blue color-channel | ||||||
|  | 	int valueBlue; | ||||||
|  | }; | ||||||
| @@ -12,6 +12,7 @@ | |||||||
|  |  | ||||||
| // hyperion-remote includes | // hyperion-remote includes | ||||||
| #include "ColorTransformValues.h" | #include "ColorTransformValues.h" | ||||||
|  | #include "ColorCorrectionValues.h" | ||||||
|  |  | ||||||
| /// Data parameter for a color | /// Data parameter for a color | ||||||
| typedef vlofgren::PODParameter<std::vector<QColor>> ColorParameter; | typedef vlofgren::PODParameter<std::vector<QColor>> ColorParameter; | ||||||
| @@ -22,6 +23,9 @@ typedef vlofgren::PODParameter<QImage> ImageParameter; | |||||||
| /// Data parameter for color transform values (list of three values) | /// Data parameter for color transform values (list of three values) | ||||||
| typedef vlofgren::PODParameter<ColorTransformValues> TransformParameter; | typedef vlofgren::PODParameter<ColorTransformValues> TransformParameter; | ||||||
|  |  | ||||||
|  | /// Data parameter for color correction values (list of three values) | ||||||
|  | typedef vlofgren::PODParameter<ColorCorrectionValues> CorrectionParameter; | ||||||
|  |  | ||||||
| namespace vlofgren { | namespace vlofgren { | ||||||
| 	/// | 	/// | ||||||
| 	/// Translates a string (as passed on the commandline) to a vector of colors | 	/// Translates a string (as passed on the commandline) to a vector of colors | ||||||
| @@ -128,4 +132,33 @@ namespace vlofgren { | |||||||
|  |  | ||||||
| 		return transform; | 		return transform; | ||||||
| 	} | 	} | ||||||
|  | 	 | ||||||
|  | 	template<> | ||||||
|  | 	ColorCorrectionValues CorrectionParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) | ||||||
|  | 	{ | ||||||
|  | 		ColorCorrectionValues correction; | ||||||
|  |  | ||||||
|  | 		// s should be split in 3 parts | ||||||
|  | 		// seperators are either a ',' or a space | ||||||
|  | 		QStringList components = QString(s.c_str()).split(" ", QString::SkipEmptyParts); | ||||||
|  |  | ||||||
|  | 		if (components.size() == 3) | ||||||
|  | 		{ | ||||||
|  | 			bool ok1, ok2, ok3; | ||||||
|  | 			correction.valueRed   = components[0].toInt(&ok1); | ||||||
|  | 			correction.valueGreen = components[1].toInt(&ok2); | ||||||
|  | 			correction.valueBlue  = components[2].toInt(&ok3); | ||||||
|  |  | ||||||
|  | 			if (ok1 && ok2 && ok3) | ||||||
|  | 			{ | ||||||
|  | 				return correction; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		std::stringstream errorMessage; | ||||||
|  | 		errorMessage << "Argument " << s << " can not be parsed to 3 integer values"; | ||||||
|  | 		throw Parameter::ParameterRejected(errorMessage.str()); | ||||||
|  |  | ||||||
|  | 		return correction; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -192,7 +192,7 @@ void JsonConnection::clearAll() | |||||||
| 	parseReply(reply); | 	parseReply(reply); | ||||||
| } | } | ||||||
|  |  | ||||||
| void JsonConnection::setTransform(std::string * transformId, double * saturation, double * value, ColorTransformValues *threshold, ColorTransformValues *gamma, ColorTransformValues *blacklevel, ColorTransformValues *whitelevel) | void JsonConnection::setTransform(std::string * transformId, double * saturation, double * value, double * saturationL, double * luminance, ColorTransformValues *threshold, ColorTransformValues *gamma, ColorTransformValues *blacklevel, ColorTransformValues *whitelevel) | ||||||
| { | { | ||||||
| 	std::cout << "Set color transforms" << std::endl; | 	std::cout << "Set color transforms" << std::endl; | ||||||
|  |  | ||||||
| @@ -216,6 +216,15 @@ void JsonConnection::setTransform(std::string * transformId, double * saturation | |||||||
| 		transform["valueGain"] = *value; | 		transform["valueGain"] = *value; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	if (saturationL != nullptr) | ||||||
|  | 	{ | ||||||
|  | 		transform["saturationLGain"] = *saturationL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (luminance != nullptr) | ||||||
|  | 	{ | ||||||
|  | 		transform["luminanceGain"] = *luminance; | ||||||
|  | 	} | ||||||
| 	if (threshold != nullptr) | 	if (threshold != nullptr) | ||||||
| 	{ | 	{ | ||||||
| 		Json::Value & v = transform["threshold"]; | 		Json::Value & v = transform["threshold"]; | ||||||
| @@ -255,6 +264,64 @@ void JsonConnection::setTransform(std::string * transformId, double * saturation | |||||||
| 	parseReply(reply); | 	parseReply(reply); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void JsonConnection::setCorrection(std::string * correctionId, ColorCorrectionValues *correction) | ||||||
|  | { | ||||||
|  | 	std::cout << "Set color corrections" << std::endl; | ||||||
|  |  | ||||||
|  | 	// create command | ||||||
|  | 	Json::Value command; | ||||||
|  | 	command["command"] = "correction"; | ||||||
|  | 	Json::Value & correct = command["correction"]; | ||||||
|  | 	 | ||||||
|  | 	if (correctionId != nullptr) | ||||||
|  | 	{ | ||||||
|  | 		correct["id"] = *correctionId; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (correction != nullptr) | ||||||
|  | 	{ | ||||||
|  | 		Json::Value & v = correct["correctionValues"]; | ||||||
|  | 		v.append(correction->valueRed); | ||||||
|  | 		v.append(correction->valueGreen); | ||||||
|  | 		v.append(correction->valueBlue); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// send command message | ||||||
|  | 	Json::Value reply = sendMessage(command); | ||||||
|  |  | ||||||
|  | 	// parse reply message | ||||||
|  | 	parseReply(reply); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void JsonConnection::setTemperature(std::string * temperatureId, ColorCorrectionValues *temperature) | ||||||
|  | { | ||||||
|  | 	std::cout << "Set color temperature corrections" << std::endl; | ||||||
|  |  | ||||||
|  | 	// create command | ||||||
|  | 	Json::Value command; | ||||||
|  | 	command["command"] = "temperature"; | ||||||
|  | 	Json::Value & temp = command["temperature"]; | ||||||
|  |  | ||||||
|  | 	if (temperatureId != nullptr) | ||||||
|  | 	{ | ||||||
|  | 		temp["id"] = *temperatureId; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (temperature != nullptr) | ||||||
|  | 	{ | ||||||
|  | 		Json::Value & v = temp["correctionValues"]; | ||||||
|  | 		v.append(temperature->valueRed); | ||||||
|  | 		v.append(temperature->valueGreen); | ||||||
|  | 		v.append(temperature->valueBlue); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// send command message | ||||||
|  | 	Json::Value reply = sendMessage(command); | ||||||
|  |  | ||||||
|  | 	// parse reply message | ||||||
|  | 	parseReply(reply); | ||||||
|  | } | ||||||
|  |  | ||||||
| Json::Value JsonConnection::sendMessage(const Json::Value & message) | Json::Value JsonConnection::sendMessage(const Json::Value & message) | ||||||
| { | { | ||||||
| 	// serialize message (FastWriter already appends a newline) | 	// serialize message (FastWriter already appends a newline) | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ | |||||||
|  |  | ||||||
| // hyperion-remote includes | // hyperion-remote includes | ||||||
| #include "ColorTransformValues.h" | #include "ColorTransformValues.h" | ||||||
|  | #include "ColorCorrectionValues.h" | ||||||
|  |  | ||||||
| /// | /// | ||||||
| /// Connection class to setup an connection to the hyperion server and execute commands | /// Connection class to setup an connection to the hyperion server and execute commands | ||||||
| @@ -89,6 +90,8 @@ public: | |||||||
| 	/// @param transformId The identifier of the transform to set | 	/// @param transformId The identifier of the transform to set | ||||||
| 	/// @param saturation The HSV saturation gain | 	/// @param saturation The HSV saturation gain | ||||||
| 	/// @param value The HSV value gain | 	/// @param value The HSV value gain | ||||||
|  | 	/// @param saturationL The HSL saturation gain | ||||||
|  | 	/// @param luminance The HSL luminance gain | ||||||
| 	/// @param threshold The threshold | 	/// @param threshold The threshold | ||||||
| 	/// @param gamma The gamma value | 	/// @param gamma The gamma value | ||||||
| 	/// @param blacklevel The blacklevel | 	/// @param blacklevel The blacklevel | ||||||
| @@ -98,11 +101,35 @@ public: | |||||||
| 			std::string * transformId, | 			std::string * transformId, | ||||||
| 			double * saturation, | 			double * saturation, | ||||||
| 			double * value, | 			double * value, | ||||||
|  | 			double * saturationL, | ||||||
|  | 			double * luminance, | ||||||
| 			ColorTransformValues * threshold, | 			ColorTransformValues * threshold, | ||||||
| 			ColorTransformValues * gamma, | 			ColorTransformValues * gamma, | ||||||
| 			ColorTransformValues * blacklevel, | 			ColorTransformValues * blacklevel, | ||||||
| 			ColorTransformValues * whitelevel); | 			ColorTransformValues * whitelevel); | ||||||
| 	 | 	 | ||||||
|  | 	/// | ||||||
|  | 	/// Set the color correction of the leds | ||||||
|  | 	/// | ||||||
|  | 	/// @note Note that providing a NULL will leave the settings on the server unchanged | ||||||
|  | 	/// | ||||||
|  | 	/// @param correctionId The identifier of the correction to set | ||||||
|  | 	/// @param correction The correction values | ||||||
|  | 	void setCorrection( | ||||||
|  | 			std::string * correctionId, | ||||||
|  | 			ColorCorrectionValues * correction); | ||||||
|  |  | ||||||
|  | 	/// | ||||||
|  | 	/// Set the color temperature of the leds | ||||||
|  | 	/// | ||||||
|  | 	/// @note Note that providing a NULL will leave the settings on the server unchanged | ||||||
|  | 	/// | ||||||
|  | 	/// @param temperatureId The identifier of the correction to set | ||||||
|  | 	/// @param temperature The temperature correction values | ||||||
|  | 	void setTemperature( | ||||||
|  | 			std::string * temperatureId, | ||||||
|  | 			ColorCorrectionValues * temperature); | ||||||
|  |  | ||||||
| private: | private: | ||||||
| 	/// | 	/// | ||||||
| 	/// Send a json command message and receive its reply | 	/// Send a json command message and receive its reply | ||||||
|   | |||||||
| @@ -69,12 +69,18 @@ int main(int argc, char * argv[]) | |||||||
| 		StringParameter    & argId         = parameters.add<StringParameter>   ('q', "qualifier" , "Identifier(qualifier) of the transform to set"); | 		StringParameter    & argId         = parameters.add<StringParameter>   ('q', "qualifier" , "Identifier(qualifier) of the transform to set"); | ||||||
| 		DoubleParameter    & argSaturation = parameters.add<DoubleParameter>   ('s', "saturation", "Set the HSV saturation gain of the leds"); | 		DoubleParameter    & argSaturation = parameters.add<DoubleParameter>   ('s', "saturation", "Set the HSV saturation gain of the leds"); | ||||||
| 		DoubleParameter    & argValue      = parameters.add<DoubleParameter>   ('v', "value"     , "Set the HSV value gain of the leds"); | 		DoubleParameter    & argValue      = parameters.add<DoubleParameter>   ('v', "value"     , "Set the HSV value gain of the leds"); | ||||||
|  | 		DoubleParameter    & argSaturationL = parameters.add<DoubleParameter>  ('u', "saturationL", "Set the HSL saturation gain of the leds"); | ||||||
|  | 		DoubleParameter    & argLuminance  = parameters.add<DoubleParameter>   ('m', "luminance" , "Set the HSL luminance gain of the leds"); | ||||||
| 		TransformParameter & argGamma      = parameters.add<TransformParameter>('g', "gamma"     , "Set the gamma of the leds (requires 3 space seperated values)"); | 		TransformParameter & argGamma      = parameters.add<TransformParameter>('g', "gamma"     , "Set the gamma of the leds (requires 3 space seperated values)"); | ||||||
| 		TransformParameter & argThreshold  = parameters.add<TransformParameter>('t', "threshold" , "Set the threshold of the leds (requires 3 space seperated values between 0.0 and 1.0)"); | 		TransformParameter & argThreshold  = parameters.add<TransformParameter>('t', "threshold" , "Set the threshold of the leds (requires 3 space seperated values between 0.0 and 1.0)"); | ||||||
| 		TransformParameter & argBlacklevel = parameters.add<TransformParameter>('b', "blacklevel", "Set the blacklevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)"); | 		TransformParameter & argBlacklevel = parameters.add<TransformParameter>('b', "blacklevel", "Set the blacklevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)"); | ||||||
| 		TransformParameter & argWhitelevel = parameters.add<TransformParameter>('w', "whitelevel", "Set the whitelevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)"); | 		TransformParameter & argWhitelevel = parameters.add<TransformParameter>('w', "whitelevel", "Set the whitelevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)"); | ||||||
| 		SwitchParameter<>  & argPrint      = parameters.add<SwitchParameter<> >(0x0, "print"     , "Print the json input and output messages on stdout"); | 		SwitchParameter<>  & argPrint      = parameters.add<SwitchParameter<> >(0x0, "print"     , "Print the json input and output messages on stdout"); | ||||||
| 		SwitchParameter<>  & argHelp       = parameters.add<SwitchParameter<> >('h', "help"      , "Show this help message and exit"); | 		SwitchParameter<>  & argHelp       = parameters.add<SwitchParameter<> >('h', "help"      , "Show this help message and exit"); | ||||||
|  | 		StringParameter    & argIdC        = parameters.add<StringParameter>   ('y', "qualifier" , "Identifier(qualifier) of the correction to set"); | ||||||
|  | 		CorrectionParameter & argCorrection  = parameters.add<CorrectionParameter>('Y', "correction" , "Set the correction of the leds (requires 3 space seperated values between 0 and 255)"); | ||||||
|  | 		StringParameter    & argIdT        = parameters.add<StringParameter>   ('z', "qualifier" , "Identifier(qualifier) of the temperature to set"); | ||||||
|  | 		CorrectionParameter & argTemperature  = parameters.add<CorrectionParameter>('Z', "temperature" , "Set the temperature correction of the leds (requires 3 space seperated values between 0 and 255)"); | ||||||
|  |  | ||||||
| 		// set the default values | 		// set the default values | ||||||
| 		argAddress.setDefault(defaultServerAddress.toStdString()); | 		argAddress.setDefault(defaultServerAddress.toStdString()); | ||||||
| @@ -93,10 +99,10 @@ int main(int argc, char * argv[]) | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// check if at least one of the available color transforms is set | 		// check if at least one of the available color transforms is set | ||||||
| 		bool colorTransform = argSaturation.isSet() || argValue.isSet() || argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet(); | 		bool colorTransform = argSaturation.isSet() || argValue.isSet() || argSaturationL.isSet() || argLuminance.isSet() || argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet(); | ||||||
|  |  | ||||||
| 		// check that exactly one command was given | 		// check that exactly one command was given | ||||||
|         int commandCount = count({argColor.isSet(), argImage.isSet(), argEffect.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), colorTransform}); |         	int commandCount = count({argColor.isSet(), argImage.isSet(), argEffect.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), colorTransform, argCorrection.isSet(), argTemperature.isSet()}); | ||||||
| 		if (commandCount != 1) | 		if (commandCount != 1) | ||||||
| 		{ | 		{ | ||||||
| 			std::cerr << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:" << std::endl; | 			std::cerr << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:" << std::endl; | ||||||
| @@ -106,14 +112,22 @@ int main(int argc, char * argv[]) | |||||||
| 			std::cerr << "  " << argServerInfo.usageLine() << std::endl; | 			std::cerr << "  " << argServerInfo.usageLine() << std::endl; | ||||||
| 			std::cerr << "  " << argClear.usageLine() << std::endl; | 			std::cerr << "  " << argClear.usageLine() << std::endl; | ||||||
| 			std::cerr << "  " << argClearAll.usageLine() << std::endl; | 			std::cerr << "  " << argClearAll.usageLine() << std::endl; | ||||||
| 			std::cerr << "or one or more of the available color transformations:" << std::endl; | 			std::cerr << "one or more of the available color transformations:" << std::endl; | ||||||
| 			std::cerr << "  " << argId.usageLine() << std::endl; | 			std::cerr << "  " << argId.usageLine() << std::endl; | ||||||
| 			std::cerr << "  " << argSaturation.usageLine() << std::endl; | 			std::cerr << "  " << argSaturation.usageLine() << std::endl; | ||||||
| 			std::cerr << "  " << argValue.usageLine() << std::endl; | 			std::cerr << "  " << argValue.usageLine() << std::endl; | ||||||
|  | 			std::cerr << "  " << argSaturationL.usageLine() << std::endl; | ||||||
|  | 			std::cerr << "  " << argLuminance.usageLine() << std::endl; | ||||||
| 			std::cerr << "  " << argThreshold.usageLine() << std::endl; | 			std::cerr << "  " << argThreshold.usageLine() << std::endl; | ||||||
| 			std::cerr << "  " << argGamma.usageLine() << std::endl; | 			std::cerr << "  " << argGamma.usageLine() << std::endl; | ||||||
| 			std::cerr << "  " << argBlacklevel.usageLine() << std::endl; | 			std::cerr << "  " << argBlacklevel.usageLine() << std::endl; | ||||||
| 			std::cerr << "  " << argWhitelevel.usageLine() << std::endl; | 			std::cerr << "  " << argWhitelevel.usageLine() << std::endl; | ||||||
|  | 			std::cerr << "one or more of the available color corrections:" << std::endl; | ||||||
|  | 			std::cerr << "  " << argIdC.usageLine() << std::endl; | ||||||
|  | 			std::cerr << "  " << argCorrection.usageLine() << std::endl; | ||||||
|  | 			std::cerr << "or one or more of the available color temperature adjustment:" << std::endl; | ||||||
|  | 			std::cerr << "  " << argIdT.usageLine() << std::endl; | ||||||
|  | 			std::cerr << "  " << argTemperature.usageLine() << std::endl; | ||||||
| 			return 1; | 			return 1; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -149,12 +163,14 @@ int main(int argc, char * argv[]) | |||||||
| 		else if (colorTransform) | 		else if (colorTransform) | ||||||
| 		{ | 		{ | ||||||
| 			std::string transId; | 			std::string transId; | ||||||
| 			double saturation, value; | 			double saturation, value, saturationL, luminance; | ||||||
| 			ColorTransformValues threshold, gamma, blacklevel, whitelevel; | 			ColorTransformValues threshold, gamma, blacklevel, whitelevel; | ||||||
|  |  | ||||||
| 			if (argId.isSet())         transId    = argId.getValue(); | 			if (argId.isSet())         transId    = argId.getValue(); | ||||||
| 			if (argSaturation.isSet()) saturation = argSaturation.getValue(); | 			if (argSaturation.isSet()) saturation = argSaturation.getValue(); | ||||||
| 			if (argValue.isSet())      value      = argValue.getValue(); | 			if (argValue.isSet())      value      = argValue.getValue(); | ||||||
|  | 			if (argSaturationL.isSet()) saturationL = argSaturationL.getValue(); | ||||||
|  | 			if (argLuminance.isSet())  luminance      = argLuminance.getValue(); | ||||||
| 			if (argThreshold.isSet())  threshold  = argThreshold.getValue(); | 			if (argThreshold.isSet())  threshold  = argThreshold.getValue(); | ||||||
| 			if (argGamma.isSet())      gamma      = argGamma.getValue(); | 			if (argGamma.isSet())      gamma      = argGamma.getValue(); | ||||||
| 			if (argBlacklevel.isSet()) blacklevel = argBlacklevel.getValue(); | 			if (argBlacklevel.isSet()) blacklevel = argBlacklevel.getValue(); | ||||||
| @@ -164,11 +180,37 @@ int main(int argc, char * argv[]) | |||||||
| 						argId.isSet()         ? &transId    : nullptr, | 						argId.isSet()         ? &transId    : nullptr, | ||||||
| 						argSaturation.isSet() ? &saturation : nullptr, | 						argSaturation.isSet() ? &saturation : nullptr, | ||||||
| 						argValue.isSet()      ? &value      : nullptr, | 						argValue.isSet()      ? &value      : nullptr, | ||||||
|  | 						argSaturationL.isSet() ? &saturationL : nullptr, | ||||||
|  | 						argLuminance.isSet()  ? &luminance  : nullptr, | ||||||
| 						argThreshold.isSet()  ? &threshold  : nullptr, | 						argThreshold.isSet()  ? &threshold  : nullptr, | ||||||
| 						argGamma.isSet()      ? &gamma      : nullptr, | 						argGamma.isSet()      ? &gamma      : nullptr, | ||||||
| 						argBlacklevel.isSet() ? &blacklevel : nullptr, | 						argBlacklevel.isSet() ? &blacklevel : nullptr, | ||||||
| 						argWhitelevel.isSet() ? &whitelevel : nullptr); | 						argWhitelevel.isSet() ? &whitelevel : nullptr); | ||||||
| 		} | 		} | ||||||
|  | 		else if (argCorrection.isSet()) | ||||||
|  | 		{ | ||||||
|  | 			std::string corrId; | ||||||
|  | 			ColorCorrectionValues correction; | ||||||
|  |  | ||||||
|  | 			if (argIdC.isSet())	corrId    = argIdC.getValue(); | ||||||
|  | 			if (argCorrection.isSet())  correction = argCorrection.getValue(); | ||||||
|  |  | ||||||
|  | 			connection.setCorrection( | ||||||
|  | 						argIdC.isSet()		? &corrId : nullptr, | ||||||
|  | 						argCorrection.isSet()   ? &correction  : nullptr); | ||||||
|  | 		} | ||||||
|  | 		else if (argTemperature.isSet()) | ||||||
|  | 		{ | ||||||
|  | 			std::string tempId; | ||||||
|  | 			ColorCorrectionValues temperature; | ||||||
|  |  | ||||||
|  | 			if (argIdT.isSet())	tempId    = argIdT.getValue(); | ||||||
|  | 			if (argTemperature.isSet())  temperature = argTemperature.getValue(); | ||||||
|  | 			 | ||||||
|  | 			connection.setTemperature( | ||||||
|  | 						argIdT.isSet()		? &tempId : nullptr, | ||||||
|  | 						argTemperature.isSet()  ? &temperature  : nullptr); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	catch (const std::runtime_error & e) | 	catch (const std::runtime_error & e) | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user