Adjustment merge + new brightness settings (#359)

* add new rgbtransform

* activate rgbtransform

* integrate new transform and gamma in adjustment, disable transform

* fix brighness limit

* advance upper and lower thresholds

* start removing color transform

* adjust configs/schema

* implement json for new color adjustment

* finish hyperion-remote extension for new adjustment settings

* fix typos

* rename luminance to brightness
fix jsonapi for new adjustment

* fix some bugs in adjustments

* fix i18n

* fix gamma via json

* now brighness values goes from 0-1 with 0.5 is the default for all brighness is equal between the channels. less 0.5 all channels scaled down
to new brighness, above 0.5 if possible channel gets brighter - but brighness is not equal between the channels anymore
brighness value curve is now exponential instead of linear - this feels more natural

* hslv cleanup
This commit is contained in:
redPanther 2017-01-06 14:25:55 +01:00 committed by GitHub
parent c433504b81
commit caab8e819b
34 changed files with 645 additions and 1807 deletions

View File

@ -314,6 +314,11 @@
"edt_conf_color_cyan" : "Cyan",
"edt_conf_color_magenta" : "Magenta",
"edt_conf_color_yellow" : "Gelb",
"edt_conf_color_gamma_red" : "Gamma rot",
"edt_conf_color_gamma_green" : "Gamma grün",
"edt_conf_color_gamma_blue" : "Gamma blau",
"edt_conf_color_brightness_min" : "Minimale Helligkeit",
"edt_conf_color_brightness" : "Maximale Helligkeit",
"edt_conf_smooth_heading_title" : "Glättung",
"edt_conf_smooth_type_title" : "Art",
"edt_conf_smooth_type_expl" : "Algorithmus der Glättung.",

View File

@ -315,6 +315,11 @@
"edt_conf_color_cyan" : "cyan",
"edt_conf_color_magenta" : "magenta",
"edt_conf_color_yellow" : "yellow",
"edt_conf_color_gamma_red" : "gamma red",
"edt_conf_color_gamma_green" : "gamma green",
"edt_conf_color_gamma_blue" : "gamma blue",
"edt_conf_color_brightness_min" : "minimal brightness",
"edt_conf_color_brightness" : "maximal brightness",
"edt_conf_smooth_heading_title" : "Smoothing",
"edt_conf_smooth_type_title" : "Type",
"edt_conf_smooth_type_expl" : "Type of smoothing.",

View File

@ -81,37 +81,12 @@
"blue" : [0,0,255],
"cyan" : [0,255,255],
"magenta" : [255,0,255],
"yellow" : [255,255,0]
}
],
"transform_enable" : true,
"transform_v4l_only" : false,
"transform" :
[
{
"id" : "default",
"leds" : "*",
"hsl" :
{
"saturationGain" : 1.0000,
"luminanceGain" : 1.0000,
"luminanceMinimum" : 0.0000
},
"red" :
{
"threshold" : 0.0000,
"gamma" : 2.5000
},
"green" :
{
"threshold" : 0.0000,
"gamma" : 2.5000
},
"blue" :
{
"threshold" : 0.0000,
"gamma" : 2.5000
}
"yellow" : [255,255,0],
"gammaRed" : 1.0,
"gammaGreen" : 1.0,
"gammaBlue" : 1.0,
"brightnessMin" : 0.0,
"brightness" : 0.5
}
]
},

View File

@ -36,37 +36,12 @@
"blue" : [0,0,255],
"cyan" : [0,255,255],
"magenta" : [255,0,255],
"yellow" : [255,255,0]
}
],
"transform_enable" : true,
"transform_v4l_only" : false,
"transform" :
[
{
"id" : "default",
"leds" : "*",
"hsl" :
{
"saturationGain" : 1.0000,
"luminanceGain" : 1.0000,
"luminanceMinimum" : 0.0000
},
"red" :
{
"threshold" : 0.0000,
"gamma" : 2.5000
},
"green" :
{
"threshold" : 0.0000,
"gamma" : 2.5000
},
"blue" :
{
"threshold" : 0.0000,
"gamma" : 2.5000
}
"yellow" : [255,255,0],
"gammaRed" : 1.0,
"gammaGreen" : 1.0,
"gammaBlue" : 1.0,
"brightnessMin" : 0.0,
"brightness" : 0.5
}
]
},

View File

@ -5,6 +5,7 @@
// Utils includes
#include <utils/RgbChannelAdjustment.h>
#include <utils/RgbTransform.h>
class ColorAdjustment
{
@ -29,4 +30,6 @@ public:
RgbChannelAdjustment _rgbMagentaAdjustment;
/// The YELLOW (RGB-Channel) adjustment
RgbChannelAdjustment _rgbYellowAdjustment;
RgbTransform _rgbTransform;
};

View File

@ -1,30 +0,0 @@
#pragma once
// STL includes
#include <string>
// Utils includes
#include <utils/RgbChannelTransform.h>
#include <utils/HsvTransform.h>
#include <utils/HslTransform.h>
class ColorTransform
{
public:
/// Unique identifier for this color transform
std::string _id;
/// The RED-Channel (RGB) transform
RgbChannelTransform _rgbRedTransform;
/// The GREEN-Channel (RGB) transform
RgbChannelTransform _rgbGreenTransform;
/// The BLUE-Channel (RGB) transform
RgbChannelTransform _rgbBlueTransform;
/// The HSV Transform for applying Saturation and Value transforms
HsvTransform _hsvTransform;
/// The HSL Transform for applying Saturation and Value transforms
HslTransform _hslTransform;
};

View File

@ -22,7 +22,6 @@
// Hyperion includes
#include <hyperion/LedString.h>
#include <hyperion/PriorityMuxer.h>
#include <hyperion/ColorTransform.h>
#include <hyperion/ColorAdjustment.h>
#include <hyperion/MessageForwarder.h>
#include <hyperion/ComponentRegister.h>
@ -38,13 +37,9 @@
// Forward class declaration
class LedDevice;
class LinearColorSmoothing;
class ColorTransform;
class RgbTransform;
class EffectEngine;
class HsvTransform;
class HslTransform;
class RgbChannelTransform;
class RgbChannelAdjustment;
class MultiColorTransform;
class MultiColorAdjustment;
class KODIVideoChecker;
///
@ -67,14 +62,6 @@ public:
BLACK, WHITE, RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW, INVALID
};
///
/// Enumeration of the possible color (color-channel) transforms
///
enum Transform
{
SATURATION_GAIN, VALUE_GAIN, THRESHOLD, GAMMA, BLACKLEVEL, WHITELEVEL
};
///
/// Destructor; cleans up resources
///
@ -216,23 +203,11 @@ public slots:
///
void setImage(int priority, const Image<ColorRgb> & image, int duration_ms);
///
/// Returns the list with unique transform identifiers
/// @return The list with transform identifiers
///
const std::vector<std::string> & getTransformIds() const;
///
/// Returns the list with unique adjustment identifiers
/// @return The list with adjustment identifiers
///
const std::vector<std::string> & getAdjustmentIds() const;
///
/// Returns the ColorTransform with the given identifier
/// @return The transform with the given identifier (or nullptr if the identifier does not exist)
///
ColorTransform * getTransform(const std::string& id);
///
/// Returns the ColorAdjustment with the given identifier
@ -246,9 +221,6 @@ public slots:
///
MessageForwarder * getForwarder();
/// Tell Hyperion that the transforms have changed and the leds need to be updated
void transformsUpdated();
/// Tell Hyperion that the corrections have changed and the leds need to be updated
void adjustmentsUpdated();
@ -295,14 +267,9 @@ public:
static LedString createLedString(const QJsonValue & ledsConfig, const ColorOrder deviceOrder);
static LedString createLedStringClone(const QJsonValue & ledsConfig, const ColorOrder deviceOrder);
static MultiColorTransform * createLedColorsTransform(const unsigned ledCnt, const QJsonObject & colorTransformConfig);
static MultiColorAdjustment * createLedColorsAdjustment(const unsigned ledCnt, const QJsonObject & colorAdjustmentConfig);
static ColorTransform * createColorTransform(const QJsonObject & transformConfig);
static ColorAdjustment * createColorAdjustment(const QJsonObject & adjustmentConfig);
static HsvTransform * createHsvTransform(const QJsonObject & hsvConfig);
static HslTransform * createHslTransform(const QJsonObject & hslConfig);
static RgbChannelTransform * createRgbChannelTransform(const QJsonObject& colorConfig);
static RgbChannelAdjustment * createRgbChannelCorrection(const QJsonObject& colorConfig);
static RgbTransform * createRgbTransform(const QJsonObject& colorConfig);
static RgbChannelAdjustment * createRgbChannelAdjustment(const QJsonArray& colorConfig, const RgbChannel color);
static LinearColorSmoothing * createColorSmoothing(const QJsonObject & smoothingConfig, LedDevice* leddevice);
@ -349,9 +316,6 @@ private:
/// The priority muxer
PriorityMuxer _muxer;
/// The transformation from raw colors to led colors
MultiColorTransform * _raw2ledTransform;
/// The adjustment from raw colors to led colors
MultiColorAdjustment * _raw2ledAdjustment;
@ -393,12 +357,6 @@ private:
/// flag for v4l color correction
bool _colorAdjustmentV4Lonly;
/// flag for v4l color correction
bool _colorTransformV4Lonly;
/// flag for color transform enable
bool _transformEnabled;
/// flag for color adjustment enable
bool _adjustmentEnabled;

View File

@ -4,68 +4,36 @@
#include <cstdint>
///
/// Color transformation to adjust the saturation and value of a RGB color value
/// Color transformation to adjust the saturation and luminance of a RGB color value
///
class HsvTransform
class ColorSys
{
public:
///
/// Default constructor
/// Translates an RGB (red, green, blue) color to an HSL (hue, saturation, luminance) color
///
HsvTransform();
/// @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);
///
/// Constructor
/// Translates an HSL (hue, saturation, luminance) color to an RGB (red, green, blue) color
///
/// @param saturationGain The used saturation gain
/// @param valueGain The used value gain
/// @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
///
HsvTransform(double saturationGain, double valueGain);
///
/// Destructor
///
~HsvTransform();
///
/// 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 value gain
///
/// @param valueGain New value gain
///
void setValueGain(double valueGain);
///
/// Returns the value gain
///
/// @return The current value gain
///
double getValueGain() 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;
static void hsl2rgb(uint16_t hue, float saturation, float luminance, uint8_t & red, uint8_t & green, uint8_t & blue);
///
/// Translates an RGB (red, green, blue) color to an HSV (hue, saturation, value) color
///
@ -97,10 +65,4 @@ public:
/// number and scaled between 0 and 360
///
static void hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value, uint8_t & red, uint8_t & green, uint8_t & blue);
private:
/// The saturation gain
double _saturationGain;
/// The value gain
double _valueGain;
};

View File

@ -1,116 +0,0 @@
#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, double luminanceMinimum);
///
/// 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;
///
/// Updates the luminance minimum
///
/// @param luminanceMinimum New luminance minimum
///
void setLuminanceMinimum(double luminanceMinimum);
///
/// Returns the luminance minimum
///
/// @return The current luminance minimum
///
double getLuminanceMinimum() 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;
/// The luminance minimum
double _luminanceMinimum;
};

View File

@ -1,86 +0,0 @@
#pragma once
// STL includes
#include <cstdint>
/// Transform for a single color byte value
///
/// Transforms are applied in the following order:
/// 1) a threshold is applied. All values below threshold will be set to zero
/// 2) gamma color correction is applied
/// 3) the output value is scaled from the [0:1] to [blacklevel:whitelevel]
/// 4) finally, in case of a weird choice of parameters, the output is clamped between [0:1]
///
/// All configuration values are doubles and assume the color value to be between 0 and 1
class RgbChannelTransform
{
public:
/// Default constructor
RgbChannelTransform();
/// Constructor
/// @param threshold The minimum threshold
/// @param gamma The gamma of the gamma-curve correction
/// @param blacklevel The minimum value for the RGB-Channel
/// @param whitelevel The maximum value for the RGB-Channel
RgbChannelTransform(double threshold, double gamma, double blacklevel, double whitelevel);
/// Destructor
~RgbChannelTransform();
/// setAdjustment RGB
/// @param threshold The minimum threshold
/// @param gamma The gamma of the gamma-curve correction
/// @param blacklevel The minimum value for the RGB-Channel
/// @param whitelevel The maximum value for the RGB-Channel
void setTransform(double threshold, double gamma, double blacklevel, double whitelevel);
/// @return The current threshold value
double getThreshold() const;
/// @param threshold New threshold value
void setThreshold(double threshold);
/// @return The current gamma value
double getGamma() const;
/// @param gamma New gamma value
void setGamma(double gamma);
/// @return The current blacklevel value
double getBlacklevel() const;
/// @param blacklevel New blacklevel value
void setBlacklevel(double blacklevel);
/// @return The current whitelevel value
double getWhitelevel() const;
/// @param whitelevel New whitelevel value
void setWhitelevel(double whitelevel);
/// Transform the given byte value
/// @param input The input color byte
/// @return The transformed byte value
uint8_t transform(uint8_t input) const
{
return _mapping[input];
}
private:
/// (re)-initilize the color mapping
void initializeMapping();
private:
/// The threshold value
double _threshold;
/// The gamma value
double _gamma;
/// The blacklevel
double _blacklevel;
/// The whitelevel
double _whitelevel;
/// The mapping from input color to output color
uint8_t _mapping[256];
};

View File

@ -0,0 +1,96 @@
#pragma once
// STL includes
#include <cstdint>
///
/// Color transformation to adjust the saturation and value of a RGB color value
///
class RgbTransform
{
public:
///
/// Default constructor
///
RgbTransform();
///
/// Constructor
///
/// @param gammaR The used red gamma
/// @param gammaG The used green gamma
/// @param gammab The used blue gamma
/// @param brightnessLow The used lower brightness
/// @param brightnessHigh The used higher brightness
///
RgbTransform(double gammaR, double gammaG, double gammaB, double brightnessLow, double brightnessHigh);
///
/// Destructor
///
~RgbTransform();
/// @return The current red gamma value
double getGammaR() const;
/// @return The current green gamma value
double getGammaG() const;
/// @return The current blue gamma value
double getGammaB() const;
/// @param gamma New gamma value
void setGamma(double gammaR,double gammaG=-1, double gammaB=-1);
/// @return The current lower brightness
double getBrightnessMin() const;
/// @param gamma New lower brightness
void setBrightnessMin(double brightness);
/// @return The current lower brightness
double getBrightness() const;
/// @param gamma New lower brightness
void setBrightness(double brightness);
///
/// 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);
private:
///
/// init
///
/// @param gammaR The used red gamma
/// @param gammaG The used green gamma
/// @param gammab The used blue gamma
/// @param brightnessLow The used lower brightness
/// @param brightnessHigh The used higher brightness
///
void init(double gammaR, double gammaG, double gammaB, double brightnessLow, double brightnessHigh);
/// (re)-initilize the color mapping
void initializeMapping(); /// The saturation gain
double _brightnessLow;
double _brightnessHigh;
double _sumBrightnessLow;
double _sumBrightnessHigh;
double _gammaR;
double _gammaG;
double _gammaB;
/// The mapping from input color to output color
uint8_t _mappingR[256];
uint8_t _mappingG[256];
uint8_t _mappingB[256];
};

View File

@ -19,7 +19,6 @@ SET(Hyperion_HEADERS
${CURRENT_HEADER_DIR}/LedString.h
${CURRENT_HEADER_DIR}/PriorityMuxer.h
${CURRENT_SOURCE_DIR}/MultiColorTransform.h
${CURRENT_SOURCE_DIR}/MultiColorAdjustment.h
${CURRENT_HEADER_DIR}/MessageForwarder.h
)
@ -32,7 +31,6 @@ SET(Hyperion_SOURCES
${CURRENT_SOURCE_DIR}/PriorityMuxer.cpp
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp
${CURRENT_SOURCE_DIR}/MultiColorAdjustment.cpp
${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp
${CURRENT_SOURCE_DIR}/MessageForwarder.cpp

View File

@ -18,14 +18,12 @@
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessorFactory.h>
#include <hyperion/ImageProcessor.h>
#include <hyperion/ColorTransform.h>
#include <hyperion/ColorAdjustment.h>
// Leddevice includes
#include <leddevice/LedDevice.h>
#include <leddevice/LedDeviceFactory.h>
#include "MultiColorTransform.h"
#include "MultiColorAdjustment.h"
#include "LinearColorSmoothing.h"
@ -56,37 +54,6 @@ ColorOrder Hyperion::createColorOrder(const QJsonObject &deviceConfig)
return stringToColorOrder(deviceConfig["colorOrder"].toString("rgb"));
}
ColorTransform * Hyperion::createColorTransform(const QJsonObject & transformConfig)
{
const std::string id = transformConfig["id"].toString("default").toStdString();
RgbChannelTransform * redTransform = createRgbChannelTransform(transformConfig["red"].toObject());
RgbChannelTransform * greenTransform = createRgbChannelTransform(transformConfig["green"].toObject());
RgbChannelTransform * blueTransform = createRgbChannelTransform(transformConfig["blue"].toObject());
HsvTransform * hsvTransform = createHsvTransform(transformConfig["hsv"].toObject());
HslTransform * hslTransform = createHslTransform(transformConfig["hsl"].toObject());
ColorTransform * transform = new ColorTransform();
transform->_id = id;
transform->_rgbRedTransform = *redTransform;
transform->_rgbGreenTransform = *greenTransform;
transform->_rgbBlueTransform = *blueTransform;
transform->_hsvTransform = *hsvTransform;
transform->_hslTransform = *hslTransform;
// Cleanup the allocated individual transforms
delete redTransform;
delete greenTransform;
delete blueTransform;
delete hsvTransform;
delete hslTransform;
return transform;
}
ColorAdjustment * Hyperion::createColorAdjustment(const QJsonObject & adjustmentConfig)
{
const std::string id = adjustmentConfig["id"].toString("default").toStdString();
@ -109,7 +76,8 @@ ColorAdjustment * Hyperion::createColorAdjustment(const QJsonObject & adjustment
RgbChannelAdjustment * cyanAdjustment = createRgbChannelAdjustment(adjustmentConfig["cyan"].toArray(),CYAN);
RgbChannelAdjustment * magentaAdjustment = createRgbChannelAdjustment(adjustmentConfig["magenta"].toArray(),MAGENTA);
RgbChannelAdjustment * yellowAdjustment = createRgbChannelAdjustment(adjustmentConfig["yellow"].toArray(),YELLOW);
RgbTransform * rgbTransform = createRgbTransform(adjustmentConfig);
ColorAdjustment * adjustment = new ColorAdjustment();
adjustment->_id = id;
adjustment->_rgbBlackAdjustment = *blackAdjustment;
@ -120,6 +88,7 @@ ColorAdjustment * Hyperion::createColorAdjustment(const QJsonObject & adjustment
adjustment->_rgbCyanAdjustment = *cyanAdjustment;
adjustment->_rgbMagentaAdjustment = *magentaAdjustment;
adjustment->_rgbYellowAdjustment = *yellowAdjustment;
adjustment->_rgbTransform = *rgbTransform;
// Cleanup the allocated individual adjustments
delete blackAdjustment;
@ -130,86 +99,12 @@ ColorAdjustment * Hyperion::createColorAdjustment(const QJsonObject & adjustment
delete cyanAdjustment;
delete magentaAdjustment;
delete yellowAdjustment;
delete rgbTransform;
return adjustment;
}
MultiColorTransform * Hyperion::createLedColorsTransform(const unsigned ledCnt, const QJsonObject & colorConfig)
{
// Create the result, the transforms are added to this
MultiColorTransform * transform = new MultiColorTransform(ledCnt);
Logger * log = Logger::getInstance("Core");
const QJsonValue transformConfig = colorConfig["transform"];
if (transformConfig.isNull())
{
// Old style color transformation config (just one for all leds)
ColorTransform * colorTransform = createColorTransform(colorConfig);
transform->addTransform(colorTransform);
transform->setTransformForLed(colorTransform->_id, 0, ledCnt-1);
}
else if (transformConfig.isObject())
{
ColorTransform * colorTransform = createColorTransform(transformConfig.toObject());
transform->addTransform(colorTransform);
transform->setTransformForLed(colorTransform->_id, 0, ledCnt-1);
}
else if (transformConfig.isArray())
{
const QRegExp overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*");
const QJsonArray & transformConfigArray = transformConfig.toArray();
for (signed i = 0; i < transformConfigArray.size(); ++i)
{
const QJsonObject & config = transformConfigArray[i].toObject();
ColorTransform * colorTransform = createColorTransform(config);
transform->addTransform(colorTransform);
const QString ledIndicesStr = config["leds"].toString("").trimmed();
if (ledIndicesStr.compare("*") == 0)
{
// Special case for indices '*' => all leds
transform->setTransformForLed(colorTransform->_id, 0, ledCnt-1);
Info(log, "ColorTransform '%s' => [0; %d]", colorTransform->_id.c_str(), ledCnt-1);
continue;
}
if (!overallExp.exactMatch(ledIndicesStr))
{
Error(log, "Given led indices %d not correct format: %s", i, ledIndicesStr.toStdString().c_str());
continue;
}
std::stringstream ss;
const QStringList ledIndexList = ledIndicesStr.split(",");
for (int i=0; i<ledIndexList.size(); ++i) {
if (i > 0)
{
ss << ", ";
}
if (ledIndexList[i].contains("-"))
{
QStringList ledIndices = ledIndexList[i].split("-");
int startInd = ledIndices[0].toInt();
int endInd = ledIndices[1].toInt();
transform->setTransformForLed(colorTransform->_id, startInd, endInd);
ss << startInd << "-" << endInd;
}
else
{
int index = ledIndexList[i].toInt();
transform->setTransformForLed(colorTransform->_id, index, index);
ss << index;
}
}
Info(log, "ColorTransform '%s' => [%s]", colorTransform->_id.c_str(), ss.str().c_str());
}
}
return transform;
}
MultiColorAdjustment * Hyperion::createLedColorsAdjustment(const unsigned ledCnt, const QJsonObject & colorConfig)
{
// Create the result, the transforms are added to this
@ -285,31 +180,15 @@ MultiColorAdjustment * Hyperion::createLedColorsAdjustment(const unsigned ledCnt
return adjustment;
}
HsvTransform * Hyperion::createHsvTransform(const QJsonObject & hsvConfig)
RgbTransform* Hyperion::createRgbTransform(const QJsonObject& colorConfig)
{
const double saturationGain = hsvConfig["saturationGain"].toDouble(1.0);
const double valueGain = hsvConfig["valueGain"].toDouble(1.0);
const double brightnessMin = colorConfig["brightnessMin"].toDouble(0.0);
const double brightness = colorConfig["brightness"].toDouble(0.5);
const double gammaR = colorConfig["gammaRed"].toDouble(1.0);
const double gammaG = colorConfig["gammaGreen"].toDouble(1.0);
const double gammaB = colorConfig["gammaBlue"].toDouble(1.0);
return new HsvTransform(saturationGain, valueGain);
}
HslTransform * Hyperion::createHslTransform(const QJsonObject & hslConfig)
{
const double saturationGain = hslConfig["saturationGain"].toDouble(1.0);
const double luminanceGain = hslConfig["luminanceGain"].toDouble(1.0);
const double luminanceMinimum = hslConfig["luminanceMinimum"].toDouble(0.0);
return new HslTransform(saturationGain, luminanceGain, luminanceMinimum);
}
RgbChannelTransform* Hyperion::createRgbChannelTransform(const QJsonObject& colorConfig)
{
const double threshold = colorConfig["threshold"].toDouble(0.0);
const double gamma = colorConfig["gamma"].toDouble(1.0);
const double blacklevel = colorConfig["blacklevel"].toDouble(0.0);
const double whitelevel = colorConfig["whitelevel"].toDouble(1.0);
RgbChannelTransform* transform = new RgbChannelTransform(threshold, gamma, blacklevel, whitelevel);
RgbTransform* transform = new RgbTransform(gammaR, gammaG, gammaB, brightnessMin, brightness);
return transform;
}
@ -575,7 +454,6 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile)
: _ledString(createLedString(qjsonConfig["leds"], createColorOrder(qjsonConfig["device"].toObject())))
, _ledStringClone(createLedStringClone(qjsonConfig["leds"], createColorOrder(qjsonConfig["device"].toObject())))
, _muxer(_ledString.leds().size())
, _raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), qjsonConfig["color"].toObject()))
, _raw2ledAdjustment(createLedColorsAdjustment(_ledString.leds().size(), qjsonConfig["color"].toObject()))
, _effectEngine(nullptr)
, _messageForwarder(createMessageForwarder(qjsonConfig["forwarder"].toObject()))
@ -585,33 +463,22 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile)
, _log(Logger::getInstance("Core"))
, _hwLedCount(_ledString.leds().size())
, _colorAdjustmentV4Lonly(false)
, _colorTransformV4Lonly(false)
, _sourceAutoSelectEnabled(true)
, _configHash()
, _ledGridSize(getLedLayoutGridSize(qjsonConfig["leds"]))
{
registerPriority("Off", PriorityMuxer::LOWEST_PRIORITY);
if (!_raw2ledAdjustment->verifyAdjustments())
{
throw std::runtime_error("Color adjustment incorrectly set");
}
if (!_raw2ledTransform->verifyTransforms())
{
throw std::runtime_error("Color transformation incorrectly set");
}
// set color correction activity state
const QJsonObject& color = qjsonConfig["color"].toObject();
_transformEnabled = color["transform_enable"].toBool(true);
_adjustmentEnabled = color["channelAdjustment_enable"].toBool(true);
_colorTransformV4Lonly = color["transform_v4l_only"].toBool(false);
_colorAdjustmentV4Lonly = color["channelAdjustment_v4l_only"].toBool(false);
InfoIf(!_transformEnabled , _log, "Color transformation disabled" );
InfoIf(!_adjustmentEnabled , _log, "Color adjustment disabled" );
InfoIf(_colorTransformV4Lonly , _log, "Color transformation for v4l inputs only" );
InfoIf(_colorAdjustmentV4Lonly , _log, "Color adjustment for v4l inputs only" );
// initialize the image processor factory
@ -659,7 +526,6 @@ void Hyperion::freeObjects()
// delete components on exit of hyperion core
delete _effectEngine;
delete _device;
delete _raw2ledTransform;
delete _raw2ledAdjustment;
delete _messageForwarder;
}
@ -805,31 +671,16 @@ void Hyperion::setImage(int priority, const Image<ColorRgb> & image, int duratio
}
}
const std::vector<std::string> & Hyperion::getTransformIds() const
{
return _raw2ledTransform->getTransformIds();
}
const std::vector<std::string> & Hyperion::getAdjustmentIds() const
{
return _raw2ledAdjustment->getAdjustmentIds();
}
ColorTransform * Hyperion::getTransform(const std::string& id)
{
return _raw2ledTransform->getTransform(id);
}
ColorAdjustment * Hyperion::getAdjustment(const std::string& id)
{
return _raw2ledAdjustment->getAdjustment(id);
}
void Hyperion::transformsUpdated()
{
update();
}
void Hyperion::adjustmentsUpdated()
{
update();
@ -929,11 +780,7 @@ void Hyperion::update()
_ledBuffer.reserve(_hwLedCount);
_ledBuffer = priorityInfo.ledColors;
if ( _transformEnabled && (!_colorTransformV4Lonly || priorityInfo.componentId == hyperion::COMP_V4L) )
{
_raw2ledTransform->applyTransform(_ledBuffer);
}
if ( _adjustmentEnabled && (!_colorAdjustmentV4Lonly || priorityInfo.componentId == hyperion::COMP_V4L) )
if ( _adjustmentEnabled && priority < PriorityMuxer::LOWEST_PRIORITY && (!_colorAdjustmentV4Lonly || priorityInfo.componentId == hyperion::COMP_V4L) )
{
_raw2ledAdjustment->applyAdjustment(_ledBuffer);
}

View File

@ -43,11 +43,19 @@ bool MultiColorAdjustment::verifyAdjustments() const
{
for (unsigned iLed=0; iLed<_ledAdjustments.size(); ++iLed)
{
if (_ledAdjustments[iLed] == nullptr)
ColorAdjustment * adjustment = _ledAdjustments[iLed];
if (adjustment == nullptr)
{
Warning(Logger::getInstance("ColorAdjust"), "No adjustment set for %d", iLed);
Error(Logger::getInstance("ColorAdjust"), "No adjustment set for %d", iLed);
return false;
}
if (adjustment->_rgbTransform.getBrightness() <= adjustment->_rgbTransform.getBrightnessMin() )
{
adjustment->_rgbTransform.setBrightnessMin(0);
adjustment->_rgbTransform.setBrightness(0.5);
Warning(Logger::getInstance("ColorAdjust"), "Adjustment for %d has invalid Brightness values, values set to default. (brightnessMin is bigger then brightness)", iLed);
}
}
return true;
}
@ -84,20 +92,26 @@ void MultiColorAdjustment::applyAdjustment(std::vector<ColorRgb>& ledColors)
continue;
}
ColorRgb& color = ledColors[i];
uint8_t ored = color.red;
uint8_t ogreen = color.green;
uint8_t oblue = color.blue;
uint32_t nrng = (uint32_t) (255-color.red)*(255-color.green);
uint32_t rng = (uint32_t) (color.red) *(255-color.green);
uint32_t nrg = (uint32_t) (255-color.red)*(color.green);
uint32_t rg = (uint32_t) (color.red) *(color.green);
adjustment->_rgbTransform.transform(ored,ogreen,oblue);
uint32_t nrng = (uint32_t) (255-ored)*(255-ogreen);
uint32_t rng = (uint32_t) (ored) *(255-ogreen);
uint32_t nrg = (uint32_t) (255-ored)*(ogreen);
uint32_t rg = (uint32_t) (ored) *(ogreen);
uint8_t black = nrng*(255-color.blue)/65025;
uint8_t red = rng *(255-color.blue)/65025;
uint8_t green = nrg *(255-color.blue)/65025;
uint8_t blue = nrng*(color.blue) /65025;
uint8_t cyan = nrg *(color.blue) /65025;
uint8_t magenta = rng *(color.blue) /65025;
uint8_t yellow = rg *(255-color.blue)/65025;
uint8_t white = rg *(color.blue) /65025;
uint8_t black = nrng*(255-oblue)/65025;
uint8_t red = rng *(255-oblue)/65025;
uint8_t green = nrg *(255-oblue)/65025;
uint8_t blue = nrng*(oblue) /65025;
uint8_t cyan = nrg *(oblue) /65025;
uint8_t magenta = rng *(oblue) /65025;
uint8_t yellow = rg *(255-oblue)/65025;
uint8_t white = rg *(oblue) /65025;
uint8_t OR = adjustment->_rgbBlackAdjustment.getAdjustmentR(black);
uint8_t OG = adjustment->_rgbBlackAdjustment.getAdjustmentG(black);

View File

@ -1,94 +0,0 @@
// STL includes
#include <cassert>
// Hyperion includes
#include <utils/Logger.h>
#include "MultiColorTransform.h"
MultiColorTransform::MultiColorTransform(const unsigned ledCnt) :
_ledTransforms(ledCnt, nullptr)
{
}
MultiColorTransform::~MultiColorTransform()
{
// Clean up all the transforms
for (ColorTransform * transform : _transform)
{
delete transform;
}
}
void MultiColorTransform::addTransform(ColorTransform * transform)
{
_transformIds.push_back(transform->_id);
_transform.push_back(transform);
}
void MultiColorTransform::setTransformForLed(const std::string& id, const unsigned startLed, const unsigned endLed)
{
assert(startLed <= endLed);
assert(endLed < _ledTransforms.size());
// Get the identified transform (don't care if is nullptr)
ColorTransform * transform = getTransform(id);
for (unsigned iLed=startLed; iLed<=endLed; ++iLed)
{
_ledTransforms[iLed] = transform;
}
}
bool MultiColorTransform::verifyTransforms() const
{
for (unsigned iLed=0; iLed<_ledTransforms.size(); ++iLed)
{
if (_ledTransforms[iLed] == nullptr)
{
Warning(Logger::getInstance("ColorTransform"), "No adjustment set for %d", iLed);
return false;
}
}
return true;
}
const std::vector<std::string> & MultiColorTransform::getTransformIds()
{
return _transformIds;
}
ColorTransform* MultiColorTransform::getTransform(const std::string& id)
{
// Iterate through the unique transforms until we find the one with the given id
for (ColorTransform* transform : _transform)
{
if (transform->_id == id)
{
return transform;
}
}
// The ColorTransform was not found
return nullptr;
}
void MultiColorTransform::applyTransform(std::vector<ColorRgb>& ledColors)
{
const size_t itCnt = std::min(_ledTransforms.size(), ledColors.size());
for (size_t i=0; i<itCnt; ++i)
{
ColorTransform* transform = _ledTransforms[i];
if (transform == nullptr)
{
// No transform set for this led (do nothing)
continue;
}
ColorRgb& color = ledColors[i];
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.green = transform->_rgbGreenTransform.transform(color.green);
color.blue = transform->_rgbBlueTransform.transform(color.blue);
}
}

View File

@ -1,64 +0,0 @@
#pragma once
// STL includes
#include <vector>
// Utils includes
#include <utils/ColorRgb.h>
// Hyperion includes
#include <hyperion/ColorTransform.h>
///
/// The LedColorTransform is responsible for performing color transformation from 'raw' colors
/// received as input to colors mapped to match the color-properties of the leds.
///
class MultiColorTransform
{
public:
MultiColorTransform(const unsigned ledCnt);
~MultiColorTransform();
/**
* Adds a new ColorTransform to this MultiColorTransform
*
* @param transform The new ColorTransform (ownership is transfered)
*/
void addTransform(ColorTransform * transform);
void setTransformForLed(const std::string& id, const unsigned startLed, const unsigned endLed);
bool verifyTransforms() const;
///
/// Returns the identifier of all the unique ColorTransform
///
/// @return The list with unique id's of the ColorTransforms
const std::vector<std::string> & getTransformIds();
///
/// Returns the pointer to the ColorTransform with the given id
///
/// @param id The identifier of the ColorTransform
///
/// @return The ColorTransform with the given id (or nullptr if it does not exist)
///
ColorTransform* getTransform(const std::string& id);
///
/// Performs the color transoformation from raw-color to led-color
///
/// @param ledColors The list with raw colors
///
void applyTransform(std::vector<ColorRgb>& ledColors);
private:
/// List with transform ids
std::vector<std::string> _transformIds;
/// List with unique ColorTransforms
std::vector<ColorTransform*> _transform;
/// List with a pointer to the ColorTransform for each individual led
std::vector<ColorTransform*> _ledTransforms;
};

View File

@ -90,7 +90,7 @@
"append" : "edt_append_ms",
"minimum": 0,
"access" : "expert",
"propertOrder" : 4
"propertyOrder" : 4
}
},
"additionalProperties" : true
@ -100,7 +100,7 @@
"type":"object",
"title" : "edt_conf_color_heading_title",
"required" : true,
"defaultProperties": ["imageToLedMappingType","channelAdjustment_enable","channelAdjustment","transform_enable","transform"],
"defaultProperties": ["imageToLedMappingType","channelAdjustment_enable","channelAdjustment"],
"properties":
{
"imageToLedMappingType" :
@ -283,153 +283,61 @@
"minItems" : 3,
"maxItems" : 3,
"propertyOrder" : 10
}
},
"additionalProperties" : false
}
},
"transform_enable" :
{
"type" : "boolean",
"default" : true,
"propertyOrder" : 5
},
"transform_v4l_only" :
{
"type" : "boolean",
"default" : false,
"propertyOrder" : 6
},
"transform" :
{
"type" : "array",
"required" : true,
"propertyOrder" : 7,
"items" :
{
"type" : "object",
"required" : true,
"properties" :
{
"id" :
{
"type" : "string",
"required" : true
},
"leds" :
"brightnessMin" :
{
"type" : "string",
"required" : true
},
"hsv" : {
"type" : "object",
"properties" : {
"saturationGain" : {
"type" : "number",
"minimum" : 0.0
},
"valueGain" : {
"type" : "number",
"minimum" : 0.0
}
},
"additionalProperties" : false
},
"hsl" :
{
"type":"object",
"type" : "number",
"title" : "edt_conf_color_brightness_min",
"required" : true,
"properties":
{
"saturationGain" :
{
"type" : "number",
"required" : true,
"minimum" : 0.0
},
"luminanceGain" :
{
"type" : "number",
"required" : true,
"minimum" : 0.0
},
"luminanceMinimum" :
{
"type" : "number",
"required" : true,
"minimum" : 0.0
}
},
"additionalProperties" : false
"minimum" : 0.0,
"maximum": 1.0,
"default" : 0.0,
"step" : 0.05,
"propertyOrder" : 11
},
"red" :
"brightness" :
{
"type":"object",
"type" : "number",
"title" : "edt_conf_color_brightness",
"required" : true,
"properties":
{
"threshold" :
{
"type" : "number",
"required" : true,
"minimum" : 0.0,
"maximum": 1.0
},
"gamma" :
{
"type" : "number",
"required" : true,
"minimum" : 0.0,
"maximum": 100.0
}
},
"additionalProperties" : false
"minimum" : 0.0,
"maximum": 1.0,
"default" : 1.0,
"step" : 0.05,
"propertyOrder" : 12
},
"green" :
"gammaRed" :
{
"type":"object",
"type" : "number",
"title" : "edt_conf_color_gamma_red",
"required" : true,
"properties":
{
"threshold" :
{
"type" : "number",
"required" : true,
"minimum" : 0.0,
"maximum": 1.0
},
"gamma" :
{
"type" : "number",
"required" : true,
"minimum" : 0.0,
"maximum": 100.0
}
},
"additionalProperties" : false
"minimum" : 0.0,
"maximum": 100.0,
"default" : 1.0,
"step" : 0.1,
"propertyOrder" : 13
},
"blue" :
"gammaGreen" :
{
"type":"object",
"type" : "number",
"title" : "edt_conf_color_gamma_green",
"required" : true,
"properties":
{
"threshold" :
{
"type" : "number",
"required" : true,
"minimum" : 0.0,
"maximum": 1.0
},
"gamma" :
{
"type" : "number",
"required" : true,
"minimum" : 0.0,
"maximum": 100.0
}
},
"additionalProperties" : false
"minimum" : 0.0,
"maximum": 100.0,
"default" : 1.0,
"step" : 0.1,
"propertyOrder" : 14
},
"gammaBlue" :
{
"type" : "number",
"title" : "edt_conf_color_gamma_blue",
"required" : true,
"minimum" : 0.0,
"maximum": 100.0,
"default" : 1.0,
"step" : 0.1,
"propertyOrder" : 15
}
},
"additionalProperties" : false

View File

@ -32,8 +32,8 @@
#include <hyperion/ImageProcessorFactory.h>
#include <hyperion/ImageProcessor.h>
#include <hyperion/MessageForwarder.h>
#include <hyperion/ColorTransform.h>
#include <hyperion/ColorAdjustment.h>
#include <utils/ColorSys.h>
#include <utils/ColorRgb.h>
#include <leddevice/LedDevice.h>
#include <HyperionConfig.h>
@ -305,8 +305,6 @@ void JsonClientConnection::handleMessage(const QString& messageString)
handleClearCommand(message, command, tan);
else if (command == "clearall")
handleClearallCommand(message, command, tan);
else if (command == "transform")
handleTransformCommand(message, command, tan);
else if (command == "adjustment")
handleAdjustmentCommand(message, command, tan);
else if (command == "sourceselect")
@ -627,56 +625,7 @@ void JsonClientConnection::handleServerInfoCommand(const QJsonObject&, const QSt
info["priorities"] = priorities;
info["priorities_autoselect"] = _hyperion->sourceAutoSelectEnabled();
// collect transform information
QJsonArray transformArray;
for (const std::string& transformId : _hyperion->getTransformIds())
{
const ColorTransform * colorTransform = _hyperion->getTransform(transformId);
if (colorTransform == nullptr)
{
Error(_log, "Incorrect color transform id: %s", transformId.c_str());
continue;
}
QJsonObject transform;
transform["id"] = QString::fromStdString(transformId);
transform["saturationGain"] = colorTransform->_hsvTransform.getSaturationGain();
transform["valueGain"] = colorTransform->_hsvTransform.getValueGain();
transform["saturationLGain"] = colorTransform->_hslTransform.getSaturationGain();
transform["luminanceGain"] = colorTransform->_hslTransform.getLuminanceGain();
transform["luminanceMinimum"] = colorTransform->_hslTransform.getLuminanceMinimum();
QJsonArray threshold;
threshold.append(colorTransform->_rgbRedTransform.getThreshold());
threshold.append(colorTransform->_rgbGreenTransform.getThreshold());
threshold.append(colorTransform->_rgbBlueTransform.getThreshold());
transform.insert("threshold", threshold);
QJsonArray gamma;
gamma.append(colorTransform->_rgbRedTransform.getGamma());
gamma.append(colorTransform->_rgbGreenTransform.getGamma());
gamma.append(colorTransform->_rgbBlueTransform.getGamma());
transform.insert("gamma", gamma);
QJsonArray blacklevel;
blacklevel.append(colorTransform->_rgbRedTransform.getBlacklevel());
blacklevel.append(colorTransform->_rgbGreenTransform.getBlacklevel());
blacklevel.append(colorTransform->_rgbBlueTransform.getBlacklevel());
transform.insert("blacklevel", blacklevel);
QJsonArray whitelevel;
whitelevel.append(colorTransform->_rgbRedTransform.getWhitelevel());
whitelevel.append(colorTransform->_rgbGreenTransform.getWhitelevel());
whitelevel.append(colorTransform->_rgbBlueTransform.getWhitelevel());
transform.insert("whitelevel", whitelevel);
transformArray.append(transform);
}
info["transform"] = transformArray;
// collect adjustment information
QJsonArray adjustmentArray;
for (const std::string& adjustmentId : _hyperion->getAdjustmentIds())
@ -779,7 +728,7 @@ void JsonClientConnection::handleServerInfoCommand(const QJsonObject&, const QSt
// add HSL Value to Array
QJsonArray HSLValue;
HslTransform::rgb2hsl(priorityInfo.ledColors.begin()->red,
ColorSys::rgb2hsl(priorityInfo.ledColors.begin()->red,
priorityInfo.ledColors.begin()->green,
priorityInfo.ledColors.begin()->blue,
Hue, Saturation, Luminace);
@ -882,83 +831,6 @@ void JsonClientConnection::handleClearallCommand(const QJsonObject& message, con
sendSuccessReply(command, tan);
}
void JsonClientConnection::handleTransformCommand(const QJsonObject& message, const QString& command, const int tan)
{
const QJsonObject & transform = message["transform"].toObject();
const QString transformId = transform["id"].toString(QString::fromStdString(_hyperion->getTransformIds().front()));
ColorTransform * colorTransform = _hyperion->getTransform(transformId.toStdString());
if (colorTransform == nullptr)
{
Warning(_log, "Incorrect transform identifier: %s", transformId.toStdString().c_str());
return;
}
if (transform.contains("saturationGain"))
{
colorTransform->_hsvTransform.setSaturationGain(transform["saturationGain"].toDouble());
}
if (transform.contains("valueGain"))
{
colorTransform->_hsvTransform.setValueGain(transform["valueGain"].toDouble());
}
if (transform.contains("saturationLGain"))
{
colorTransform->_hslTransform.setSaturationGain(transform["saturationLGain"].toDouble());
}
if (transform.contains("luminanceGain"))
{
colorTransform->_hslTransform.setLuminanceGain(transform["luminanceGain"].toDouble());
}
if (transform.contains("luminanceMinimum"))
{
colorTransform->_hslTransform.setLuminanceMinimum(transform["luminanceMinimum"].toDouble());
}
if (transform.contains("threshold"))
{
const QJsonArray & values = transform["threshold"].toArray();
colorTransform->_rgbRedTransform .setThreshold(values[0u].toDouble());
colorTransform->_rgbGreenTransform.setThreshold(values[1u].toDouble());
colorTransform->_rgbBlueTransform .setThreshold(values[2u].toDouble());
}
if (transform.contains("gamma"))
{
const QJsonArray & values = transform["gamma"].toArray();
colorTransform->_rgbRedTransform .setGamma(values[0u].toDouble());
colorTransform->_rgbGreenTransform.setGamma(values[1u].toDouble());
colorTransform->_rgbBlueTransform .setGamma(values[2u].toDouble());
}
if (transform.contains("blacklevel"))
{
const QJsonArray & values = transform["blacklevel"].toArray();
colorTransform->_rgbRedTransform .setBlacklevel(values[0u].toDouble());
colorTransform->_rgbGreenTransform.setBlacklevel(values[1u].toDouble());
colorTransform->_rgbBlueTransform .setBlacklevel(values[2u].toDouble());
}
if (transform.contains("whitelevel"))
{
const QJsonArray & values = transform["whitelevel"].toArray();
colorTransform->_rgbRedTransform .setWhitelevel(values[0u].toDouble());
colorTransform->_rgbGreenTransform.setWhitelevel(values[1u].toDouble());
colorTransform->_rgbBlueTransform .setWhitelevel(values[2u].toDouble());
}
// commit the changes
_hyperion->transformsUpdated();
sendSuccessReply(command, tan);
}
void JsonClientConnection::handleAdjustmentCommand(const QJsonObject& message, const QString& command, const int tan)
{
const QJsonObject & adjustment = message["adjustment"].toObject();
@ -994,6 +866,64 @@ void JsonClientConnection::handleAdjustmentCommand(const QJsonObject& message, c
colorAdjustment->_rgbBlueAdjustment.setAdjustmentG(values[1u].toInt());
colorAdjustment->_rgbBlueAdjustment.setAdjustmentB(values[2u].toInt());
}
if (adjustment.contains("cyanAdjust"))
{
const QJsonArray & values = adjustment["cyanAdjust"].toArray();
colorAdjustment->_rgbCyanAdjustment.setAdjustmentR(values[0u].toInt());
colorAdjustment->_rgbCyanAdjustment.setAdjustmentG(values[1u].toInt());
colorAdjustment->_rgbCyanAdjustment.setAdjustmentB(values[2u].toInt());
}
if (adjustment.contains("magentaAdjust"))
{
const QJsonArray & values = adjustment["magentaAdjust"].toArray();
colorAdjustment->_rgbMagentaAdjustment.setAdjustmentR(values[0u].toInt());
colorAdjustment->_rgbMagentaAdjustment.setAdjustmentG(values[1u].toInt());
colorAdjustment->_rgbMagentaAdjustment.setAdjustmentB(values[2u].toInt());
}
if (adjustment.contains("yellowAdjust"))
{
const QJsonArray & values = adjustment["yellowAdjust"].toArray();
colorAdjustment->_rgbYellowAdjustment.setAdjustmentR(values[0u].toInt());
colorAdjustment->_rgbYellowAdjustment.setAdjustmentG(values[1u].toInt());
colorAdjustment->_rgbYellowAdjustment.setAdjustmentB(values[2u].toInt());
}
if (adjustment.contains("blackAdjust"))
{
const QJsonArray & values = adjustment["blackAdjust"].toArray();
colorAdjustment->_rgbBlackAdjustment.setAdjustmentR(values[0u].toInt());
colorAdjustment->_rgbBlackAdjustment.setAdjustmentG(values[1u].toInt());
colorAdjustment->_rgbBlackAdjustment.setAdjustmentB(values[2u].toInt());
}
if (adjustment.contains("whiteAdjust"))
{
const QJsonArray & values = adjustment["whiteAdjust"].toArray();
colorAdjustment->_rgbWhiteAdjustment.setAdjustmentR(values[0u].toInt());
colorAdjustment->_rgbWhiteAdjustment.setAdjustmentG(values[1u].toInt());
colorAdjustment->_rgbWhiteAdjustment.setAdjustmentB(values[2u].toInt());
}
if (adjustment.contains("gammaR"))
{
colorAdjustment->_rgbTransform.setGamma(adjustment["gammaR"].toDouble(), colorAdjustment->_rgbTransform.getGammaG(), colorAdjustment->_rgbTransform.getGammaB());
}
if (adjustment.contains("gammaG"))
{
colorAdjustment->_rgbTransform.setGamma(colorAdjustment->_rgbTransform.getGammaR(), adjustment["gammaG"].toDouble(), colorAdjustment->_rgbTransform.getGammaB());
}
if (adjustment.contains("gammaB"))
{
colorAdjustment->_rgbTransform.setGamma(colorAdjustment->_rgbTransform.getGammaR(), colorAdjustment->_rgbTransform.getGammaG(), adjustment["gammaB"].toDouble());
}
if (adjustment.contains("brightnessMin"))
{
colorAdjustment->_rgbTransform.setBrightnessMin(adjustment["brightnessMin"].toDouble());
}
if (adjustment.contains("brightness"))
{
colorAdjustment->_rgbTransform.setBrightness(adjustment["brightness"].toDouble());
}
// commit the changes
_hyperion->adjustmentsUpdated();

View File

@ -202,13 +202,6 @@ private:
///
void handleClearallCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Transform message
///
/// @param message the incoming message
///
void handleTransformCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Adjustment message
///

View File

@ -6,7 +6,6 @@
<file alias="schema-serverinfo">schema/schema-serverinfo.json</file>
<file alias="schema-clear">schema/schema-clear.json</file>
<file alias="schema-clearall">schema/schema-clearall.json</file>
<file alias="schema-transform">schema/schema-transform.json</file>
<file alias="schema-adjustment">schema/schema-adjustment.json</file>
<file alias="schema-effect">schema/schema-effect.json</file>
<file alias="schema-create-effect">schema/schema-create-effect.json</file>

View File

@ -50,6 +50,91 @@
},
"minItems": 3,
"maxItems": 3
},
"yellowAdjust": {
"type": "array",
"required": false,
"items" : {
"type": "integer",
"minimum": 0,
"maximum": 255
},
"minItems": 3,
"maxItems": 3
},
"magentaAdjust": {
"type": "array",
"required": false,
"items" : {
"type": "integer",
"minimum": 0,
"maximum": 255
},
"minItems": 3,
"maxItems": 3
},
"cyanAdjust": {
"type": "array",
"required": false,
"items" : {
"type": "integer",
"minimum": 0,
"maximum": 255
},
"minItems": 3,
"maxItems": 3
},
"blackAdjust": {
"type": "array",
"required": false,
"items" : {
"type": "integer",
"minimum": 0,
"maximum": 255
},
"minItems": 3,
"maxItems": 3
},
"whiteAdjust": {
"type": "array",
"required": false,
"items" : {
"type": "integer",
"minimum": 0,
"maximum": 255
},
"minItems": 3,
"maxItems": 3
},
"gammaR": {
"type" : "number",
"required" : false,
"minimum" : 0.0,
"maximum" : 100.0
},
"gammaG": {
"type" : "number",
"required" : false,
"minimum" : 0.0,
"maximum" : 100.0
},
"gammaB": {
"type" : "number",
"required" : false,
"minimum" : 0.0,
"maximum" : 100.0
},
"brightnessMin" : {
"type" : "number",
"required" : false,
"minimum" : 0.0,
"maximum" : 1.0
},
"brightness" : {
"type" : "number",
"required" : false,
"minimum" : 0.0,
"maximum" : 1.0
}
},
"additionalProperties": false

View File

@ -1,90 +0,0 @@
{
"type":"object",
"required":true,
"properties":{
"command": {
"type" : "string",
"required" : true,
"enum" : ["transform"]
},
"tan" : {
"type" : "integer"
},
"transform": {
"type": "object",
"required": true,
"properties": {
"id" : {
"type" : "string",
"required" : false
},
"saturationGain" : {
"type" : "number",
"required" : false,
"minimum" : 0.0
},
"valueGain" : {
"type" : "number",
"required" : false,
"minimum" : 0.0
},
"saturationLGain" : {
"type" : "number",
"required" : false,
"minimum" : 0.0
},
"luminanceGain" : {
"type" : "number",
"required" : false,
"minimum" : 0.0
},
"luminanceMinimum" : {
"type" : "number",
"required" : false,
"minimum" : 0.0
},
"threshold": {
"type": "array",
"required": false,
"items" : {
"type": "number",
"minimum": 0.0,
"maximum": 1.0
},
"minItems": 3,
"maxItems": 3
},
"gamma": {
"type": "array",
"required": false,
"items" : {
"type": "number",
"minimum": 0.0
},
"minItems": 3,
"maxItems": 3
},
"blacklevel": {
"type": "array",
"required": false,
"items" : {
"type": "number"
},
"minItems": 3,
"maxItems": 3
},
"whitelevel": {
"type": "array",
"required": false,
"items" : {
"type": "number"
},
"minItems": 3,
"maxItems": 3
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}

View File

@ -5,7 +5,7 @@
"command": {
"type" : "string",
"required" : true,
"enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "transform", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing"]
"enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing"]
}
}
}

View File

@ -19,9 +19,8 @@ SET(Utils_HEADERS
${CURRENT_HEADER_DIR}/PixelFormat.h
${CURRENT_HEADER_DIR}/VideoMode.h
${CURRENT_HEADER_DIR}/ImageResampler.h
${CURRENT_HEADER_DIR}/HsvTransform.h
${CURRENT_HEADER_DIR}/HslTransform.h
${CURRENT_HEADER_DIR}/RgbChannelTransform.h
${CURRENT_HEADER_DIR}/RgbTransform.h
${CURRENT_HEADER_DIR}/ColorSys.h
${CURRENT_HEADER_DIR}/RgbChannelAdjustment.h
${CURRENT_HEADER_DIR}/RgbToRgbw.h
${CURRENT_HEADER_DIR}/jsonschema/QJsonFactory.h
@ -38,10 +37,9 @@ SET(Utils_SOURCES
${CURRENT_SOURCE_DIR}/Process.cpp
${CURRENT_SOURCE_DIR}/Logger.cpp
${CURRENT_SOURCE_DIR}/ImageResampler.cpp
${CURRENT_SOURCE_DIR}/HsvTransform.cpp
${CURRENT_SOURCE_DIR}/HslTransform.cpp
${CURRENT_SOURCE_DIR}/RgbChannelTransform.cpp
${CURRENT_SOURCE_DIR}/ColorSys.cpp
${CURRENT_SOURCE_DIR}/RgbChannelAdjustment.cpp
${CURRENT_SOURCE_DIR}/RgbTransform.cpp
${CURRENT_SOURCE_DIR}/RgbToRgbw.cpp
${CURRENT_SOURCE_DIR}/jsonschema/QJsonSchemaChecker.cpp
)
@ -61,7 +59,7 @@ add_library(hyperion-utils
${PROFILER_SOURCE}
)
qt5_use_modules(hyperion-utils Core)
qt5_use_modules(hyperion-utils Core Gui)
target_link_libraries(hyperion-utils
${QT_LIBRARIES})

36
libsrc/utils/ColorSys.cpp Normal file
View File

@ -0,0 +1,36 @@
#include <utils/ColorSys.h>
#include <QColor>
void ColorSys::rgb2hsl(uint8_t red, uint8_t green, uint8_t blue, uint16_t & hue, float & saturation, float & luminance)
{
QColor color(red,green,blue);
qreal h,s,l;
color.getHslF(&h,&s,&l);
hue = h;
saturation = s;
luminance = l;
}
void ColorSys::hsl2rgb(uint16_t hue, float saturation, float luminance, uint8_t & red, uint8_t & green, uint8_t & blue)
{
QColor color(QColor::fromHslF(hue,(qreal)saturation,(qreal)luminance));
red = (uint8_t)color.red();
green = (uint8_t)color.green();
blue = (uint8_t)color.blue();
}
void ColorSys::rgb2hsv(uint8_t red, uint8_t green, uint8_t blue, uint16_t & hue, uint8_t & saturation, uint8_t & value)
{
QColor color(red,green,blue);
hue = color.hsvHue();
saturation = color.hsvSaturation();
value = color.value();
}
void ColorSys::hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value, uint8_t & red, uint8_t & green, uint8_t & blue)
{
QColor color(QColor::fromHsv(hue,saturation,value));
red = (uint8_t)color.red();
green = (uint8_t)color.green();
blue = (uint8_t)color.blue();
}

View File

@ -1,169 +0,0 @@
#include <algorithm>
#include <cmath>
#include <utils/HslTransform.h>
HslTransform::HslTransform()
: _saturationGain(1.0)
, _luminanceGain(1.0)
, _luminanceMinimum(0.0)
{
}
HslTransform::HslTransform(double saturationGain, double luminanceGain, double luminanceMinimum) :
_saturationGain(saturationGain),
_luminanceGain(luminanceGain),
_luminanceMinimum(luminanceMinimum)
{
}
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::setLuminanceMinimum(double luminanceMinimum)
{
_luminanceMinimum = luminanceMinimum;
}
double HslTransform::getLuminanceMinimum() const
{
return _luminanceMinimum;
}
void HslTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue) const
{
if (_saturationGain != 1.0 || _luminanceGain != 1.0 || _luminanceMinimum != 0.0)
{
uint16_t hue;
float saturation, luminance;
rgb2hsl(red, green, blue, hue, saturation, luminance);
float s = saturation * _saturationGain;
saturation = std::min(s, 1.0f);
float l = luminance * _luminanceGain;
if (l < _luminanceMinimum)
{
saturation = 0;
l = _luminanceMinimum;
}
luminance = std::min(l, 1.0f);
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 = (float)red / 255.0f;
float g = (float)green / 255.0f;
float b = (float)blue / 255.0f;
float rgbMin = std::min(r,std::min(g,b));
float rgbMax = std::max(r,std::max(g,b));
float diff = rgbMax - rgbMin;
//luminance
luminance = (rgbMin + rgbMax) / 2.0f;
if (diff == 0.0f)
{
saturation = 0.0f;
hue = 0;
return;
}
//saturation
saturation = (luminance < 0.5f)
? (diff / (rgbMin + rgbMax))
: (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 = (luminance < 0.5f)
? luminance * (1.0f + saturation)
: (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);
}

View File

@ -1,144 +0,0 @@
#include <iostream>
#include <utils/HsvTransform.h>
HsvTransform::HsvTransform()
: _saturationGain(1.0)
, _valueGain(1.0)
{
}
HsvTransform::HsvTransform(double saturationGain, double valueGain) :
_saturationGain(saturationGain),
_valueGain(valueGain)
{
}
HsvTransform::~HsvTransform()
{
}
void HsvTransform::setSaturationGain(double saturationGain)
{
_saturationGain = saturationGain;
}
double HsvTransform::getSaturationGain() const
{
return _saturationGain;
}
void HsvTransform::setValueGain(double valueGain)
{
_valueGain = valueGain;
}
double HsvTransform::getValueGain() const
{
return _valueGain;
}
void HsvTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue) const
{
if (_saturationGain != 1.0 || _valueGain != 1.0)
{
uint16_t hue;
uint8_t saturation, value;
rgb2hsv(red, green, blue, hue, saturation, value);
int s = saturation * _saturationGain;
if (s > 255)
saturation = 255;
else
saturation = s;
int v = value * _valueGain;
if (v > 255)
value = 255;
else
value = v;
hsv2rgb(hue, saturation, value, red, green, blue);
}
}
void HsvTransform::rgb2hsv(uint8_t red, uint8_t green, uint8_t blue, uint16_t & hue, uint8_t & saturation, uint8_t & value)
{
uint8_t rgbMin, rgbMax;
rgbMin = red < green ? (red < blue ? red : blue) : (green < blue ? green : blue);
rgbMax = red > green ? (red > blue ? red : blue) : (green > blue ? green : blue);
value = rgbMax;
if (value == 0)
{
hue = 0;
saturation = 0;
return;
}
saturation = 255 * long(rgbMax - rgbMin) / value;
if (saturation == 0)
{
hue = 0;
return;
}
if (rgbMax == red)
{
// start from 360 to be sure that we won't assign a negative number to the unsigned hue value
hue = 360 + 60 * (green - blue) / (rgbMax - rgbMin);
if (hue > 359)
hue -= 360;
}
else if (rgbMax == green)
{
hue = 120 + 60 * (blue - red) / (rgbMax - rgbMin);
}
else
{
hue = 240 + 60 * (red - green) / (rgbMax - rgbMin);
}
}
void HsvTransform::hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value, uint8_t & red, uint8_t & green, uint8_t & blue)
{
uint8_t region, remainder, p, q, t;
if (saturation == 0)
{
red = value;
green = value;
blue = value;
return;
}
region = hue / 60;
remainder = (hue - (region * 60)) * 256 / 60;
p = (value * (255 - saturation)) >> 8;
q = (value * (255 - ((saturation * remainder) >> 8))) >> 8;
t = (value * (255 - ((saturation * (255 - remainder)) >> 8))) >> 8;
switch (region)
{
case 0:
red = value; green = t; blue = p;
break;
case 1:
red = q; green = value; blue = p;
break;
case 2:
red = p; green = value; blue = t;
break;
case 3:
red = p; green = q; blue = value;
break;
case 4:
red = t; green = p; blue = value;
break;
default:
red = value; green = p; blue = q;
break;
}
}

View File

@ -1,101 +0,0 @@
// STL includes
#include <cmath>
// Utils includes
#include <utils/RgbChannelTransform.h>
RgbChannelTransform::RgbChannelTransform()
{
setTransform(0.0, 1.0, 0.0, 1.0);
}
RgbChannelTransform::RgbChannelTransform(double threshold, double gamma, double blacklevel, double whitelevel)
{
setTransform(threshold, gamma, blacklevel, whitelevel);
}
RgbChannelTransform::~RgbChannelTransform()
{
}
void RgbChannelTransform::setTransform(double threshold, double gamma, double blacklevel, double whitelevel)
{
_threshold = threshold;
_gamma = gamma;
_blacklevel = blacklevel;
_whitelevel = whitelevel;
initializeMapping();
}
double RgbChannelTransform::getThreshold() const
{
return _threshold;
}
void RgbChannelTransform::setThreshold(double threshold)
{
setTransform(threshold, _gamma, _blacklevel, _whitelevel);
}
double RgbChannelTransform::getGamma() const
{
return _gamma;
}
void RgbChannelTransform::setGamma(double gamma)
{
setTransform(_threshold, gamma, _blacklevel, _whitelevel);
}
double RgbChannelTransform::getBlacklevel() const
{
return _blacklevel;
}
void RgbChannelTransform::setBlacklevel(double blacklevel)
{
setTransform(_threshold, _gamma, blacklevel, _whitelevel);
}
double RgbChannelTransform::getWhitelevel() const
{
return _whitelevel;
}
void RgbChannelTransform::setWhitelevel(double whitelevel)
{
setTransform(_threshold, _gamma, _blacklevel, whitelevel);
}
void RgbChannelTransform::initializeMapping()
{
// initialize the mapping as a linear array
for (int i = 0; i < 256; ++i)
{
double output = i / 255.0;
// apply linear transform
if (output < _threshold)
{
output = 0.0;
}
// apply gamma correction
output = std::pow(output, _gamma);
// apply blacklevel and whitelevel
output = _blacklevel + (_whitelevel - _blacklevel) * output;
// calc mapping
int mappingValue = output * 255;
if (mappingValue < 0)
{
mappingValue = 0;
}
else if (mappingValue > 255)
{
mappingValue = 255;
}
_mapping[i] = mappingValue;
}
}

View File

@ -0,0 +1,114 @@
#include <iostream>
#include <cmath>
#include <utils/RgbTransform.h>
RgbTransform::RgbTransform()
{
init(1.0, 1.0, 1.0, 0.0, 1.0);
}
RgbTransform::RgbTransform(double gammaR, double gammaG, double gammaB, double brightnessLow, double brightnessHigh)
{
init(gammaR, gammaG, gammaB, brightnessLow, brightnessHigh);
}
void RgbTransform::init(double gammaR, double gammaG, double gammaB, double brightnessLow, double brightnessHigh)
{
setGamma(gammaR,gammaG,gammaB);
setBrightnessMin(brightnessLow);
setBrightness(brightnessHigh);
initializeMapping();
}
RgbTransform::~RgbTransform()
{
}
double RgbTransform::getGammaR() const
{
return _gammaR;
}
double RgbTransform::getGammaG() const
{
return _gammaG;
}
double RgbTransform::getGammaB() const
{
return _gammaB;
}
void RgbTransform::setGamma(double gammaR, double gammaG, double gammaB)
{
_gammaR = gammaR;
_gammaG = (gammaG < 0.0) ? _gammaR : gammaG;
_gammaB = (gammaB < 0.0) ? _gammaR : gammaB;
initializeMapping();
}
void RgbTransform::initializeMapping()
{
for (int i = 0; i < 256; ++i)
{
_mappingR[i] = std::min(std::max((int)(std::pow(i / 255.0, _gammaR) * 255), 0), 255);
_mappingG[i] = std::min(std::max((int)(std::pow(i / 255.0, _gammaG) * 255), 0), 255);
_mappingB[i] = std::min(std::max((int)(std::pow(i / 255.0, _gammaB) * 255), 0), 255);
}
}
double RgbTransform::getBrightnessMin() const
{
return _brightnessLow;
}
void RgbTransform::setBrightnessMin(double brightness)
{
_brightnessLow = brightness;
_sumBrightnessLow = 765.0 * ((std::pow(2.0,brightness*2)-1) / 3.0);
}
double RgbTransform::getBrightness() const
{
return _brightnessHigh;
}
void RgbTransform::setBrightness(double brightness)
{
_brightnessHigh = brightness;
_sumBrightnessHigh = 765.0 * ((std::pow(2.0,brightness*2)-1) / 3.0);
}
void RgbTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue)
{
// apply gamma
red = _mappingR[red];
green = _mappingR[green];
blue = _mappingR[blue];
//std::cout << (int)red << " " << (int)green << " " << (int)blue << " => ";
// apply brightnesss
if (red ==0) red = 1;
if (green==0) green = 1;
if (blue ==0) blue = 1;
int rgbSum = red+green+blue;
if (rgbSum > _sumBrightnessHigh)
{
double cH = _sumBrightnessHigh / rgbSum;
red *= cH;
green *= cH;
blue *= cH;
}
else if (rgbSum < _sumBrightnessLow)
{
double cL = _sumBrightnessLow / rgbSum;
red *= cL;
green *= cL;
blue *= cL;
}
//std::cout << (int)red << " " << (int)green << " " << (int)blue << std::endl;
}

View File

@ -401,102 +401,21 @@ void JsonConnection::setConfig(const QString &jsonString)
parseReply(reply);
}
void JsonConnection::setTransform(const QString &transformId,
double *saturation,
double *value,
double *saturationL,
double *luminance,
double *luminanceMin,
QColor threshold,
QColor gamma,
QColor blacklevel,
QColor whitelevel)
{
qDebug() << "Set color transforms";
// create command
QJsonObject command, transform;
command["command"] = QString("transform");
if (!transformId.isNull())
{
transform["id"] = transformId;
}
if (saturation != nullptr)
{
transform["saturationGain"] = *saturation;
}
if (value != nullptr)
{
transform["valueGain"] = *value;
}
if (saturationL != nullptr)
{
transform["saturationLGain"] = *saturationL;
}
if (luminance != nullptr)
{
transform["luminanceGain"] = *luminance;
}
if (luminanceMin != nullptr)
{
transform["luminanceMinimum"] = *luminanceMin;
}
if (threshold.isValid())
{
QJsonArray t;
t.append(threshold.red());
t.append(threshold.green());
t.append(threshold.blue());
transform["threshold"] = t;
}
if (gamma.isValid())
{
QJsonArray g;
g.append(gamma.red());
g.append(gamma.green());
g.append(gamma.blue());
transform["gamma"] = g;
}
if (blacklevel.isValid())
{
QJsonArray b;
b.append(blacklevel.red());
b.append(blacklevel.green());
b.append(blacklevel.blue());
transform["blacklevel"] = b;
}
if (whitelevel.isValid())
{
QJsonArray w;
w.append(whitelevel.red());
w.append(whitelevel.green());
w.append(whitelevel.blue());
transform["whitelevel"] = w;
}
command["transform"] = transform;
// send command message
QJsonObject reply = sendMessage(command);
// parse reply message
parseReply(reply);
}
void JsonConnection::setAdjustment(const QString &adjustmentId,
const QColor & redAdjustment,
const QColor & greenAdjustment,
const QColor & blueAdjustment)
void JsonConnection::setAdjustment(
const QString & adjustmentId,
const QColor & redAdjustment,
const QColor & greenAdjustment,
const QColor & blueAdjustment,
const QColor & cyanAdjustment,
const QColor & magentaAdjustment,
const QColor & yellowAdjustment,
const QColor & whiteAdjustment,
const QColor & blackAdjustment,
double *gammaR,
double *gammaG,
double *gammaB,
double *brightnessMin,
double *brightness)
{
qDebug() << "Set color adjustments";
@ -535,7 +454,51 @@ void JsonConnection::setAdjustment(const QString &adjustmentId,
blue.append(blueAdjustment.blue());
adjust["blueAdjust"] = blue;
}
if (cyanAdjustment.isValid())
{
QJsonArray cyan;
cyan.append(cyanAdjustment.red());
cyan.append(cyanAdjustment.green());
cyan.append(cyanAdjustment.blue());
adjust["cyanAdjust"] = cyan;
}
if (magentaAdjustment.isValid())
{
QJsonArray magenta;
magenta.append(magentaAdjustment.red());
magenta.append(magentaAdjustment.green());
magenta.append(magentaAdjustment.blue());
adjust["magentaAdjust"] = magenta;
}
if (yellowAdjustment.isValid())
{
QJsonArray yellow;
yellow.append(yellowAdjustment.red());
yellow.append(yellowAdjustment.green());
yellow.append(yellowAdjustment.blue());
adjust["yellowAdjust"] = yellow;
}
if (brightnessMin != nullptr)
{
adjust["brightnessMin"] = *brightnessMin;
}
if (brightness != nullptr)
{
adjust["brightness"] = *brightness;
}
if (gammaR != nullptr)
{
adjust["gammaR"] = *gammaR;
}
if (gammaG != nullptr)
{
adjust["gammaG"] = *gammaG;
}
if (gammaB != nullptr)
{
adjust["gammaB"] = *gammaB;
}
command["adjustment"] = adjust;
// send command message

View File

@ -124,34 +124,6 @@ public:
///
void setConfig(const QString &jsonString);
///
/// Set the color transform of the leds
///
/// @note Note that providing a NULL will leave the settings on the server unchanged
///
/// @param transformId The identifier of the transform to set
/// @param saturation The HSV saturation gain
/// @param value The HSV value gain
/// @param saturationL The HSL saturation gain
/// @param luminance The HSL luminance gain
/// @param luminanceMin The HSL luminance minimum
/// @param threshold The threshold
/// @param gamma The gamma value
/// @param blacklevel The blacklevel
/// @param whitelevel The whitelevel
///
void setTransform(
const QString &transformId,
double *saturation,
double *value,
double *saturationL,
double *luminance,
double *luminanceMin,
QColor threshold,
QColor gamma,
QColor blacklevel,
QColor whitelevel);
///
/// Set the color adjustment of the leds
///
@ -161,11 +133,25 @@ public:
/// @param redAdjustment The red channel adjustment values
/// @param greenAdjustment The green channel adjustment values
/// @param blueAdjustment The blue channel adjustment values
/// @param gamma The gamma value
/// @param brightnessMin The threshold aka backlight
/// @param brightness The threshold aka upper brightness limit
void setAdjustment(
const QString & adjustmentId,
const QColor & redAdjustment,
const QColor & greenAdjustment,
const QColor & blueAdjustment);
const QColor & blueAdjustment,
const QColor & cyanAdjustment,
const QColor & magentaAdjustment,
const QColor & yellowAdjustment,
const QColor & blackAdjustment,
const QColor & whiteAdjustment,
double *gammaR,
double *gammaG,
double *gammaB,
double *brightnessMin,
double *brightness);
///
/// sets the image to leds mapping type

View File

@ -54,7 +54,7 @@ int main(int argc, char * argv[])
try
{
// create the option parser and initialize all parameters
Parser parser("Simple application to send a command to hyperion using the Json interface");
Parser parser("Application to send a command to hyperion using the Json interface");
Option & argAddress = parser.add<Option> ('a', "address" , "Set the address of the hyperion server [default: %1]", "localhost:19444");
IntOption & argPriority = parser.add<IntOption> ('p', "priority" , "Use to the provided priority channel (the lower the number, the higher the priority) [default: %1]", "100");
@ -71,29 +71,27 @@ int main(int argc, char * argv[])
BooleanOption & argClearAll = parser.add<BooleanOption>(0x0, "clearall" , "Clear data for all active priority channels");
Option & argEnableComponent = parser.add<Option> ('E', "enable" , "Enable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, KODICHECKER, FORWARDER, UDPLISTENER, BOBLIGHT_SERVER, GRABBER, V4L]");
Option & argDisableComponent = parser.add<Option> ('D', "disable" , "Disable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, KODICHECKER, FORWARDER, UDPLISTENER, BOBLIGHT_SERVER, GRABBER, V4L]");
Option & argId = parser.add<Option> ('q', "qualifier" , "Identifier(qualifier) of the transform to set");
DoubleOption & argSaturation = parser.add<DoubleOption> ('s', "saturation", "!DEPRECATED! Will be removed soon! Set the HSV saturation gain of the leds");
DoubleOption & argValue = parser.add<DoubleOption> ('v', "getColors" , "!DEPRECATED! Will be removed soon! Set the HSV getColors gain of the leds");
DoubleOption & argSaturationL = parser.add<DoubleOption> ('u', "saturationL", "Set the HSL saturation gain of the leds");
DoubleOption & argLuminance = parser.add<DoubleOption> ('m', "luminance" , "Set the HSL luminance gain of the leds");
DoubleOption & argLuminanceMin= parser.add<DoubleOption> ('n', "luminanceMin" , "Set the HSL luminance minimum of the leds (backlight)");
ColorOption & argGamma = parser.add<ColorOption> ('g', "gamma" , "Set the gamma of the leds (requires colors in hex format as RRGGBB)");
ColorOption & argThreshold = parser.add<ColorOption> ('t', "threshold" , "Set the threshold of the leds (requires colors in hex format as RRGGBB)");
ColorOption & argBlacklevel = parser.add<ColorOption> ('b', "blacklevel", "!DEPRECATED! Will be removed soon! Set the blacklevel of the leds (requires colors in hex format as RRGGBB which are normally between 0.0 and 1.0)");
ColorOption & argWhitelevel = parser.add<ColorOption> ('w', "whitelevel", "!DEPRECATED! Will be removed soon! Set the whitelevel of the leds (requires colors in hex format as RRGGBB which are normally between 0.0 and 1.0)");
Option & argId = parser.add<Option> ('q', "qualifier" , "Identifier(qualifier) of the adjustment to set");
DoubleOption & argBrightness = parser.add<DoubleOption> ('L', "brightness" , "Set the brightness gain of the leds");
DoubleOption & argBrightnessMin= parser.add<DoubleOption> ('n', "brightnessMin" , "Set the brightness minimum of the leds (backlight)");
DoubleOption & argGamma = parser.add<DoubleOption> ('g', "gamma" , "Set the overall gamma of the leds");
BooleanOption & argPrint = parser.add<BooleanOption>(0x0, "print" , "Print the json input and output messages on stdout");
BooleanOption & argHelp = parser.add<BooleanOption>('h', "help" , "Show this help message and exit");
Option & argIdA = parser.add<Option> ('j', "qualifier-a" , "Identifier(qualifier) of the adjustment to set");
ColorOption & argRAdjust = parser.add<ColorOption> ('R', "redAdjustment" , "Set the adjustment of the red color (requires colors in hex format as RRGGBB)");
ColorOption & argGAdjust = parser.add<ColorOption> ('G', "greenAdjustment", "Set the adjustment of the green color (requires colors in hex format as RRGGBB)");
ColorOption & argBAdjust = parser.add<ColorOption> ('B', "blueAdjustment", "Set the adjustment of the blue color (requires colors in hex format as RRGGBB)");
Option & argMapping = parser.add<Option> ('M', "ledMapping" , "Set the methode for image to led mapping valif values: multicolor:mean, unicolor_mean");
ColorOption & argCAdjust = parser.add<ColorOption> ('C', "cyanAdjustment" , "Set the adjustment of the cyan color (requires colors in hex format as RRGGBB)");
ColorOption & argMAdjust = parser.add<ColorOption> ('M', "magentaAdjustment", "Set the adjustment of the magenta color (requires colors in hex format as RRGGBB)");
ColorOption & argYAdjust = parser.add<ColorOption> ('Y', "yellowAdjustment", "Set the adjustment of the yellow color (requires colors in hex format as RRGGBB)");
ColorOption & argWAdjust = parser.add<ColorOption> ('W', "whiteAdjustment", "Set the adjustment of the white color (requires colors in hex format as RRGGBB)");
ColorOption & argbAdjust = parser.add<ColorOption> ('b', "blackAdjustment", "Set the adjustment of the black color (requires colors in hex format as RRGGBB)");
Option & argMapping = parser.add<Option> ('m', "ledMapping" , "Set the methode for image to led mapping valif values: multicolor:mean, unicolor_mean");
IntOption & argSource = parser.add<IntOption> (0x0, "sourceSelect" , "Set current active priority channel and deactivate auto source switching");
BooleanOption & argSourceAuto = parser.add<BooleanOption>(0x0, "sourceAutoSelect", "Enables auto source, if disabled prio by manual selecting input source");
BooleanOption & argSourceOff = parser.add<BooleanOption>(0x0, "sourceOff", "select no source, this results in leds activly set to black (=off)");
BooleanOption & argConfigGet = parser.add<BooleanOption>(0x0, "configGet" , "Print the current loaded Hyperion configuration file");
BooleanOption & argSchemaGet = parser.add<BooleanOption>(0x0, "schemaGet" , "Print the json schema for Hyperion configuration");
Option & argConfigSet = parser.add<Option> ('W', "configSet", "Write to the actual loaded configuration file. Should be a Json object string.");
Option & argConfigSet = parser.add<Option> (0x0, "configSet", "Write to the actual loaded configuration file. Should be a Json object string.");
// parse all _options
parser.process(app);
@ -105,14 +103,12 @@ int main(int argc, char * argv[])
}
// check if at least one of the available color transforms is set
bool colorTransform = parser.isSet(argSaturation) || parser.isSet(argValue) || parser.isSet(argSaturationL) || parser.isSet(argLuminance)
|| parser.isSet(argLuminanceMin) || parser.isSet(argThreshold) || parser.isSet(argGamma) || parser.isSet(argBlacklevel) || parser.isSet(argWhitelevel);
bool colorAdjust = parser.isSet(argRAdjust) || parser.isSet(argGAdjust) || parser.isSet(argBAdjust);
bool colorModding = colorTransform || colorAdjust;
bool colorAdjust = parser.isSet(argRAdjust) || parser.isSet(argGAdjust) || parser.isSet(argBAdjust) || parser.isSet(argCAdjust) || parser.isSet(argMAdjust)
|| parser.isSet(argYAdjust) || parser.isSet(argWAdjust) || parser.isSet(argbAdjust) || parser.isSet(argGamma)|| parser.isSet(argBrightness)|| parser.isSet(argBrightnessMin);
// check that exactly one command was given
int commandCount = count({ parser.isSet(argColor), parser.isSet(argImage), parser.isSet(argEffect), parser.isSet(argCreateEffect), parser.isSet(argDeleteEffect),
parser.isSet(argServerInfo), parser.isSet(argClear), parser.isSet(argClearAll), parser.isSet(argEnableComponent), parser.isSet(argDisableComponent), colorModding,
parser.isSet(argServerInfo), parser.isSet(argClear), parser.isSet(argClearAll), parser.isSet(argEnableComponent), parser.isSet(argDisableComponent), colorAdjust,
parser.isSet(argSource), parser.isSet(argSourceAuto), parser.isSet(argSourceOff), parser.isSet(argConfigGet), parser.isSet(argSchemaGet), parser.isSet(argConfigSet),
parser.isSet(argMapping) });
if (commandCount != 1)
@ -133,19 +129,15 @@ int main(int argc, char * argv[])
showHelp(argConfigGet);
qWarning() << "or one or more of the available color modding operations:";
showHelp(argId);
showHelp(argSaturation);
showHelp(argValue);
showHelp(argSaturationL);
showHelp(argLuminance);
showHelp(argLuminanceMin);
showHelp(argThreshold);
showHelp(argBrightness);
showHelp(argBrightnessMin);
showHelp(argGamma);
showHelp(argBlacklevel);
showHelp(argWhitelevel);
showHelp(argIdA);
showHelp(argRAdjust);
showHelp(argGAdjust);
showHelp(argBAdjust);
showHelp(argCAdjust);
showHelp(argMAdjust);
showHelp(argYAdjust);
return 1;
}
@ -155,7 +147,7 @@ int main(int argc, char * argv[])
// now execute the given command
if (parser.isSet(argColor))
{
// TODO: make sure setColor accepts a QList<QColor>
// TODO: make sure setColor accepts a QList<QColor>
connection.setColor(argColor.getColors(parser).toVector().toStdVector(), argPriority.getInt(parser), argDuration.getInt(parser));
}
else if (parser.isSet(argImage))
@ -225,32 +217,24 @@ int main(int argc, char * argv[])
{
connection.setLedMapping(argMapping.value(parser));
}
else if (colorModding)
{
if (colorAdjust)
{
connection.setAdjustment(
argIdA.value(parser),
argRAdjust.getColor(parser),
argGAdjust.getColor(parser),
argBAdjust.getColor(parser)
);
}
if (colorTransform)
{
connection.setTransform(
argId.value(parser),
argSaturation.getDoublePtr(parser),
argValue.getDoublePtr(parser),
argSaturationL.getDoublePtr(parser),
argLuminance.getDoublePtr(parser),
argLuminanceMin.getDoublePtr(parser),
argThreshold.getColor(parser),
argGamma.getColor(parser),
argBlacklevel.getColor(parser),
argWhitelevel.getColor(parser));
}
else if (colorAdjust)
{
connection.setAdjustment(
argId.value(parser),
argRAdjust.getColor(parser),
argGAdjust.getColor(parser),
argBAdjust.getColor(parser),
argCAdjust.getColor(parser),
argMAdjust.getColor(parser),
argYAdjust.getColor(parser),
argWAdjust.getColor(parser),
argbAdjust.getColor(parser),
argGamma.getDoublePtr(parser),
argGamma.getDoublePtr(parser),
argGamma.getDoublePtr(parser),
argBrightnessMin.getDoublePtr(parser),
argBrightness.getDoublePtr(parser)
);
}
}
catch (const std::runtime_error & e)

View File

@ -23,13 +23,6 @@ add_executable(test_ImageRgb
target_link_libraries(test_ImageRgb
hyperion-utils)
add_executable(test_colortransform
TestColorTransform.cpp)
target_link_libraries(test_colortransform
hyperion
effectengine
)
add_executable(test_image2ledsmap
TestImage2LedsMap.cpp)
target_link_libraries(test_image2ledsmap

View File

@ -1,95 +0,0 @@
// STL includes
#include <iostream>
#include <cmath>
// Utils includes
#include <utils/RgbChannelTransform.h>
int main()
{
{
std::cout << "Testing linear transform" << std::endl;
RgbChannelTransform t;
for (int i = 0; i < 256; ++i)
{
uint8_t input = i;
uint8_t output = t.transform(input);
uint8_t expected = input;
if (output != expected)
{
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
return 1;
}
else
{
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
}
}
}
{
std::cout << "Testing threshold" << std::endl;
RgbChannelTransform t(.10, 1.0, 0.0, 1.0);
for (int i = 0; i < 256; ++i)
{
uint8_t input = i;
uint8_t output = t.transform(input);
uint8_t expected = ((i/255.0) < t.getThreshold() ? 0 : output);
if (output != expected)
{
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
return 1;
}
else
{
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
}
}
}
{
std::cout << "Testing blacklevel and whitelevel" << std::endl;
RgbChannelTransform t(0, 1.0, 0.2, 0.8);
for (int i = 0; i < 256; ++i)
{
uint8_t input = i;
uint8_t output = t.transform(input);
uint8_t expected = (uint8_t)(input * (t.getWhitelevel()-t.getBlacklevel()) + 255 * t.getBlacklevel());
if (output != expected)
{
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
return 1;
}
else
{
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
}
}
}
{
std::cout << "Testing gamma" << std::endl;
RgbChannelTransform t(0, 2.0, 0.0, 1.0);
for (int i = 0; i < 256; ++i)
{
uint8_t input = i;
uint8_t output = t.transform(input);
uint8_t expected = (uint8_t)(255 * std::pow(i / 255.0, 2));
if (output != expected)
{
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
return 1;
}
else
{
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
}
}
}
return 0;
}