Re-add Temperture adjustment (#1710)

* Add Temperature adjustment

* Add Temperature adjustment - add missing cmake updates

* Add missing ENABLE_MDNS guards

* Reapply temperature on JSONAPI

* Integrate color temperature into RGB transformations

* Fix imagestream update

* fix cast

* Cleanups

* Windows Fix

* Fix inner loop

* Simplify

* Reapply default temperature setting

* Fix adjustments calculation

* Updates
This commit is contained in:
LordGrey
2024-12-28 20:45:10 +01:00
committed by GitHub
parent bc3ea9de42
commit d16142d28e
22 changed files with 371 additions and 154 deletions

View File

@@ -33,6 +33,10 @@ struct ColorRgb
static const ColorRgb YELLOW;
/// 'White' RgbColor (255, 255, 255)
static const ColorRgb WHITE;
/// 'Cyan' RgbColor (0, 255, 255)
static const ColorRgb CYAN;
/// 'Magenta' RgbColor (255, 0,255)
static const ColorRgb MAGENTA;
ColorRgb() = default;

View File

@@ -0,0 +1,75 @@
#ifndef KELVINTORGB_H
#define KELVINTORGB_H
#include <cmath>
#include <utils/ColorRgb.h>
// Constants
namespace ColorTemperature {
constexpr int MINIMUM {1000};
constexpr int MAXIMUM {40000};
constexpr int DEFAULT {6600};
}
//End of constants
static ColorRgb getRgbFromTemperature(int temperature)
{
//Temperature input in Kelvin valid in the range 1000 K to 40000 K. White light = 6600K
temperature = qBound(ColorTemperature::MINIMUM, temperature, ColorTemperature::MAXIMUM);
// All calculations require temperature / 100, so only do the conversion once.
temperature /= 100;
// Compute each color in turn.
int red;
int green;
int blue;
// red
if (temperature <= 66)
{
red = UINT8_MAX;
}
else
{
// Note: the R-squared value for this approximation is 0.988.
red = static_cast<int>(329.698727446 * (pow(temperature - 60, -0.1332047592)));
}
// green
if (temperature <= 66)
{
// Note: the R-squared value for this approximation is 0.996.
green = static_cast<int>(99.4708025861 * log(temperature) - 161.1195681661);
}
else
{
// Note: the R-squared value for this approximation is 0.987.
green = static_cast<int>(288.1221695283 * (pow(temperature - 60, -0.0755148492)));
}
// blue
if (temperature >= 66)
{
blue = UINT8_MAX;
}
else if (temperature <= 19)
{
blue = 0;
}
else
{
// Note: the R-squared value for this approximation is 0.998.
blue = static_cast<int>(138.5177312231 * log(temperature - 10) - 305.0447927307);
}
return {
static_cast<uint8_t>(qBound(0, red, static_cast<int>(UINT8_MAX))),
static_cast<uint8_t>(qBound(0, green, static_cast<int>(UINT8_MAX))),
static_cast<uint8_t>(qBound(0, blue, static_cast<int>(UINT8_MAX))),
};
}
#endif // KELVINTORGB_H

View File

@@ -1,23 +1,27 @@
#pragma once
// STL includes
#include <cstdint>
#include <QString>
#include <utils/Logger.h>
#include <utils/ColorRgb.h>
/// 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 RgbChannelAdjustment
{
public:
/// Default constructor
RgbChannelAdjustment(QString channelName="");
explicit RgbChannelAdjustment(const QString& channelName="");
explicit RgbChannelAdjustment(const ColorRgb& adjust, const QString& channelName="");
/// Constructor
/// @param adjustR
/// @param adjustG
/// @param adjustB
RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName="");
explicit RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, const QString& channelName="");
///
/// Transform the given array value
@@ -40,6 +44,7 @@ public:
/// @param adjustB
///
void setAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB);
void setAdjustment(const ColorRgb& adjust);
/// @return The current adjustR value
uint8_t getAdjustmentR() const;
@@ -51,24 +56,28 @@ public:
uint8_t getAdjustmentB() const;
private:
/// color channels
enum ColorChannel { RED=0, GREEN=1, BLUE=2 };
struct ColorMapping {
uint8_t red[256];
uint8_t green[256];
uint8_t blue[256];
};
/// reset init of color mapping
void resetInitialized();
/// The adjustment of RGB channel
uint8_t _adjust[3];
/// The mapping from input color to output color
uint8_t _mapping[3][256];
/// Name of this channel, usefull for debug messages
QString _channelName;
/// Logger instance
Logger * _log;
/// The adjustment of RGB channel
ColorRgb _adjust;
/// The mapping from input color to output color
ColorMapping _mapping;
/// bitfield to determine white value is alreade initialized
bool _initialized[256];

View File

@@ -3,6 +3,8 @@
// STL includes
#include <cstdint>
#include <utils/ColorRgb.h>
///
/// Color transformation to adjust the saturation and value of a RGB color value
///
@@ -23,8 +25,9 @@ public:
/// @param backlightThreshold The used lower brightness
/// @param backlightColored use color in backlight
/// @param brightnessHigh The used higher brightness
/// @param temeprature The given color temperature (in Kelvin)
///
RgbTransform(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation);
RgbTransform(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation, int temperature);
/// @return The current red gamma value
double getGammaR() const;
@@ -79,10 +82,10 @@ public:
///
/// @note The values are updated in place.
///
void getBrightnessComponents(uint8_t & rgb, uint8_t & cmy, uint8_t & w) const;
void getBrightnessComponents(uint8_t & rgb, uint8_t & cmy, uint8_t & white) const;
///
/// Apply the transform the the given RGB values.
/// Apply Gamma the the given RGB values.
///
/// @param red The red color component
/// @param green The green color component
@@ -90,7 +93,22 @@ public:
///
/// @note The values are updated in place.
///
void transform(uint8_t & red, uint8_t & green, uint8_t & blue);
void applyGamma(uint8_t & red, uint8_t & green, uint8_t & blue);
///
/// Apply Backlight 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 applyBacklight(uint8_t & red, uint8_t & green, uint8_t & blue) const;
int getTemperature() const;
void setTemperature(int temperature);
void applyTemperature(ColorRgb& color) const;
private:
///
@@ -103,8 +121,9 @@ private:
/// @param backlightColored en/disable color in backlight
/// @param brightness The used brightness
/// @param brightnessCompensation The used brightness compensation
/// @param temeprature apply the given color temperature (in Kelvin)
///
void init(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation);
void init(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation, int temperature);
/// (re)-initilize the color mapping
void initializeMapping(); /// The saturation gain
@@ -112,25 +131,28 @@ private:
void updateBrightnessComponents();
/// backlight variables
bool _backLightEnabled
, _backlightColored;
double _backlightThreshold
, _sumBrightnessLow;
bool _backLightEnabled;
bool _backlightColored;
double _backlightThreshold;
double _sumBrightnessLow;
/// gamma variables
double _gammaR
, _gammaG
, _gammaB;
double _gammaR;
double _gammaG;
double _gammaB;
/// The mapping from input color to output color
uint8_t _mappingR[256]
, _mappingG[256]
, _mappingB[256];
uint8_t _mappingR[256];
uint8_t _mappingG[256];
uint8_t _mappingB[256];
/// brightness variables
uint8_t _brightness
, _brightnessCompensation
, _brightness_rgb
, _brightness_cmy
, _brightness_w;
uint8_t _brightness;
uint8_t _brightnessCompensation;
uint8_t _brightness_rgb;
uint8_t _brightness_cmy;
uint8_t _brightness_w;
int _temperature;
ColorRgb _temperatureRGB;
};

View File

@@ -1,6 +1,10 @@
#pragma once
#include <cstdint>
#include <QList>
#define QSTRING_CSTR(str) str.toUtf8().constData()
typedef QList< int > QIntList;
constexpr double DOUBLE_UINT8_MAX_SQUARED = static_cast<double>(UINT8_MAX) * UINT8_MAX;

View File

@@ -5,6 +5,7 @@
#include <hyperion/ColorAdjustment.h>
#include <hyperion/MultiColorAdjustment.h>
#include <hyperion/LedString.h>
#include <utils/KelvinToRgb.h>
#include <QRegularExpression>
// fg effect
@@ -77,8 +78,9 @@ namespace hyperion {
const double gammaR = colorConfig["gammaRed"].toDouble(1.0);
const double gammaG = colorConfig["gammaGreen"].toDouble(1.0);
const double gammaB = colorConfig["gammaBlue"].toDouble(1.0);
const int temperature = colorConfig["temperature"].toInt(ColorTemperature::DEFAULT);
return RgbTransform(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, static_cast<uint8_t>(brightness), static_cast<uint8_t>(brightnessComp));
return RgbTransform(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, static_cast<uint8_t>(brightness), static_cast<uint8_t>(brightnessComp), temperature);
}
static OkhsvTransform createOkhsvTransform(const QJsonObject& colorConfig)
@@ -89,13 +91,13 @@ namespace hyperion {
return OkhsvTransform(saturationGain, brightnessGain);
}
static RgbChannelAdjustment createRgbChannelAdjustment(const QJsonObject& colorConfig, const QString& channelName, int defaultR, int defaultG, int defaultB)
static RgbChannelAdjustment createRgbChannelAdjustment(const QJsonObject& colorConfig, const QString& channelName, const ColorRgb& color)
{
const QJsonArray& channelConfig = colorConfig[channelName].toArray();
return RgbChannelAdjustment(
static_cast<uint8_t>(channelConfig[0].toInt(defaultR)),
static_cast<uint8_t>(channelConfig[1].toInt(defaultG)),
static_cast<uint8_t>(channelConfig[2].toInt(defaultB)),
static_cast<uint8_t>(channelConfig[0].toInt(color.red)),
static_cast<uint8_t>(channelConfig[1].toInt(color.green)),
static_cast<uint8_t>(channelConfig[2].toInt(color.blue)),
channelName
);
}
@@ -106,14 +108,14 @@ namespace hyperion {
ColorAdjustment * adjustment = new ColorAdjustment();
adjustment->_id = id;
adjustment->_rgbBlackAdjustment = createRgbChannelAdjustment(adjustmentConfig, "black" , 0, 0, 0);
adjustment->_rgbWhiteAdjustment = createRgbChannelAdjustment(adjustmentConfig, "white" , 255,255,255);
adjustment->_rgbRedAdjustment = createRgbChannelAdjustment(adjustmentConfig, "red" , 255, 0, 0);
adjustment->_rgbGreenAdjustment = createRgbChannelAdjustment(adjustmentConfig, "green" , 0,255, 0);
adjustment->_rgbBlueAdjustment = createRgbChannelAdjustment(adjustmentConfig, "blue" , 0, 0,255);
adjustment->_rgbCyanAdjustment = createRgbChannelAdjustment(adjustmentConfig, "cyan" , 0,255,255);
adjustment->_rgbMagentaAdjustment = createRgbChannelAdjustment(adjustmentConfig, "magenta", 255, 0,255);
adjustment->_rgbYellowAdjustment = createRgbChannelAdjustment(adjustmentConfig, "yellow" , 255,255, 0);
adjustment->_rgbBlackAdjustment = createRgbChannelAdjustment(adjustmentConfig, "black" , ColorRgb::BLACK);
adjustment->_rgbWhiteAdjustment = createRgbChannelAdjustment(adjustmentConfig, "white" , ColorRgb::WHITE);
adjustment->_rgbRedAdjustment = createRgbChannelAdjustment(adjustmentConfig, "red" , ColorRgb::RED);
adjustment->_rgbGreenAdjustment = createRgbChannelAdjustment(adjustmentConfig, "green" , ColorRgb::GREEN);
adjustment->_rgbBlueAdjustment = createRgbChannelAdjustment(adjustmentConfig, "blue" , ColorRgb::BLUE);
adjustment->_rgbCyanAdjustment = createRgbChannelAdjustment(adjustmentConfig, "cyan" , ColorRgb::CYAN);
adjustment->_rgbMagentaAdjustment = createRgbChannelAdjustment(adjustmentConfig, "magenta", ColorRgb::MAGENTA);
adjustment->_rgbYellowAdjustment = createRgbChannelAdjustment(adjustmentConfig, "yellow" , ColorRgb::YELLOW);
adjustment->_rgbTransform = createRgbTransform(adjustmentConfig);
adjustment->_okhsvTransform = createOkhsvTransform(adjustmentConfig);
@@ -149,27 +151,27 @@ namespace hyperion {
continue;
}
std::stringstream ss;
std::stringstream sStream;
const QStringList ledIndexList = ledIndicesStr.split(",");
for (int i=0; i<ledIndexList.size(); ++i) {
if (i > 0)
for (int j=0; j<ledIndexList.size(); ++j) {
if (j > 0)
{
ss << ", ";
sStream << ", ";
}
if (ledIndexList[i].contains("-"))
if (ledIndexList[j].contains("-"))
{
QStringList ledIndices = ledIndexList[i].split("-");
QStringList ledIndices = ledIndexList[j].split("-");
int startInd = ledIndices[0].toInt();
int endInd = ledIndices[1].toInt();
adjustment->setAdjustmentForLed(colorAdjustment->_id, startInd, endInd);
ss << startInd << "-" << endInd;
sStream << startInd << "-" << endInd;
}
else
{
int index = ledIndexList[i].toInt();
adjustment->setAdjustmentForLed(colorAdjustment->_id, index, index);
ss << index;
sStream << index;
}
}
}