mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Add Temperature adjustment
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#ifndef COLORADJUSTMENT_H
|
||||
#define COLORADJUSTMENT_H
|
||||
|
||||
// STL includes
|
||||
// Qt includes
|
||||
#include <QString>
|
||||
|
||||
// Utils includes
|
||||
|
18
include/hyperion/ColorCorrection.h
Normal file
18
include/hyperion/ColorCorrection.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
// Qt includes
|
||||
#include <QString>
|
||||
|
||||
// Utils includes
|
||||
#include <utils/RgbChannelCorrection.h>
|
||||
|
||||
class ColorCorrection
|
||||
{
|
||||
public:
|
||||
|
||||
/// Unique identifier for this color correction
|
||||
QString _id;
|
||||
|
||||
/// The RGB correction
|
||||
RgbChannelCorrection _rgbCorrection;
|
||||
};
|
@@ -22,6 +22,7 @@
|
||||
#include <hyperion/LedString.h>
|
||||
#include <hyperion/PriorityMuxer.h>
|
||||
#include <hyperion/ColorAdjustment.h>
|
||||
#include <hyperion/ColorCorrection.h>
|
||||
#include <hyperion/ComponentRegister.h>
|
||||
|
||||
#if defined(ENABLE_EFFECTENGINE)
|
||||
@@ -48,6 +49,7 @@ class LinearColorSmoothing;
|
||||
class EffectEngine;
|
||||
#endif
|
||||
class MultiColorAdjustment;
|
||||
class MultiColorCorrection;
|
||||
class ColorAdjustment;
|
||||
class SettingsManager;
|
||||
class BGEffectHandler;
|
||||
@@ -181,15 +183,30 @@ public slots:
|
||||
///
|
||||
QStringList getAdjustmentIds() const;
|
||||
|
||||
///
|
||||
/// Returns the list with unique correction identifiers
|
||||
/// @return The list with correction identifiers
|
||||
///
|
||||
QStringList getTemperatureIds() const;
|
||||
|
||||
///
|
||||
/// Returns the ColorAdjustment with the given identifier
|
||||
/// @return The adjustment with the given identifier (or nullptr if the identifier does not exist)
|
||||
///
|
||||
ColorAdjustment * getAdjustment(const QString& id) const;
|
||||
|
||||
///
|
||||
/// Returns the ColorCorrection with the given identifier
|
||||
/// @return The correction with the given identifier (or nullptr if the identifier does not exist)
|
||||
///
|
||||
ColorCorrection * getTemperature(const QString& id) const;
|
||||
|
||||
/// Tell Hyperion that the corrections have changed and the leds need to be updated
|
||||
void adjustmentsUpdated();
|
||||
|
||||
/// Tell Hyperion that the corrections have changed and the leds need to be updated
|
||||
void temperaturesUpdated();
|
||||
|
||||
///
|
||||
/// Clears the given priority channel. This will switch the led-colors to the colors of the next
|
||||
/// lower priority channel (or off if no more channels are set)
|
||||
@@ -566,6 +583,9 @@ private:
|
||||
/// The adjustment from raw colors to led colors
|
||||
MultiColorAdjustment * _raw2ledAdjustment;
|
||||
|
||||
/// The temperature from raw colors to led colors
|
||||
MultiColorCorrection * _raw2ledTemperature;
|
||||
|
||||
/// The actual LedDeviceWrapper
|
||||
LedDeviceWrapper* _ledDeviceWrapper;
|
||||
|
||||
|
69
include/hyperion/MultiColorCorrection.h
Normal file
69
include/hyperion/MultiColorCorrection.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
// STL includes
|
||||
|
||||
#include <vector>
|
||||
|
||||
// Utils includes
|
||||
#include <utils/ColorRgb.h>
|
||||
#include "utils/Logger.h"
|
||||
|
||||
// Hyperion includes
|
||||
#include <hyperion/ColorCorrection.h>
|
||||
|
||||
///
|
||||
/// The LedColorCorrection is responsible for performing color correction from 'raw' colors
|
||||
/// received as input to colors mapped to match the color-properties of the leds.
|
||||
///
|
||||
class MultiColorCorrection
|
||||
{
|
||||
public:
|
||||
MultiColorCorrection(int ledCnt);
|
||||
~MultiColorCorrection();
|
||||
|
||||
/**
|
||||
* Adds a new ColorCorrection to this MultiColorCorrection
|
||||
*
|
||||
* @param Correction The new ColorCorrection (ownership is transfered)
|
||||
*/
|
||||
void addCorrection(ColorCorrection * correction);
|
||||
|
||||
void setCorrectionForLed(const QString& id, int startLed, int endLed);
|
||||
|
||||
bool verifyCorrections() const;
|
||||
|
||||
///
|
||||
/// Returns the identifier of all the unique ColorCorrection
|
||||
///
|
||||
/// @return The list with unique id's of the ColorCorrections
|
||||
QStringList & getCorrectionIds();
|
||||
|
||||
///
|
||||
/// Returns the pointer to the ColorCorrection with the given id
|
||||
///
|
||||
/// @param id The identifier of the ColorCorrection
|
||||
///
|
||||
/// @return The ColorCorrection with the given id (or nullptr if it does not exist)
|
||||
///
|
||||
ColorCorrection* getCorrection(const QString& id);
|
||||
|
||||
///
|
||||
/// Performs the color transoformation from raw-color to led-color
|
||||
///
|
||||
/// @param ledColors The list with raw colors
|
||||
///
|
||||
void applyCorrection(std::vector<ColorRgb>& ledColors);
|
||||
|
||||
private:
|
||||
/// List with Correction ids
|
||||
QStringList _correctionIds;
|
||||
|
||||
/// List with unique ColorCorrections
|
||||
std::vector<ColorCorrection*> _correction;
|
||||
|
||||
/// List with a pointer to the ColorCorrection for each individual led
|
||||
std::vector<ColorCorrection*> _ledCorrections;
|
||||
|
||||
// logger instance
|
||||
Logger * _log;
|
||||
};
|
72
include/utils/KelvinToRgb.h
Normal file
72
include/utils/KelvinToRgb.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef KELVINTORGB_H
|
||||
#define KELVINTORGB_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <utils/ColorRgb.h>
|
||||
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
const int TEMPERATURE_MINIMUM = 1000;
|
||||
const int TEMPERATUR_MAXIMUM = 40000;
|
||||
} //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(TEMPERATURE_MINIMUM, temperature, TEMPERATUR_MAXIMUM);
|
||||
|
||||
// All calculations require temperature / 100, so only do the conversion once.
|
||||
temperature /= 100;
|
||||
|
||||
// Compute each color in turn.
|
||||
int red, green, blue;
|
||||
|
||||
// red
|
||||
if (temperature <= 66)
|
||||
{
|
||||
red = 255;
|
||||
}
|
||||
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 = 255;
|
||||
}
|
||||
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, 255)),
|
||||
static_cast<uint8_t>(qBound(0, green, 255)),
|
||||
static_cast<uint8_t>(qBound(0, blue, 255)),
|
||||
};
|
||||
}
|
||||
|
||||
#endif // KELVINTORGB_H
|
66
include/utils/RgbChannelCorrection.h
Normal file
66
include/utils/RgbChannelCorrection.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
// STL includes
|
||||
#include <cstdint>
|
||||
|
||||
/// Correction for a single color byte value
|
||||
/// All configuration values are unsigned int and assume the color value to be between 0 and 255
|
||||
class RgbChannelCorrection
|
||||
{
|
||||
public:
|
||||
/// Default constructor
|
||||
RgbChannelCorrection();
|
||||
|
||||
/// Constructor
|
||||
/// @param correctionR
|
||||
/// @param correctionG
|
||||
/// @param correctionB
|
||||
|
||||
RgbChannelCorrection(int correctionR, int correctionG, int correctionB);
|
||||
|
||||
/// Destructor
|
||||
~RgbChannelCorrection();
|
||||
|
||||
/// @return The current correctionR value
|
||||
uint8_t getcorrectionR() const;
|
||||
|
||||
/// @param threshold New correctionR value
|
||||
void setcorrectionR(uint8_t correctionR);
|
||||
|
||||
/// @return The current correctionG value
|
||||
uint8_t getcorrectionG() const;
|
||||
|
||||
/// @param gamma New correctionG value
|
||||
void setcorrectionG(uint8_t correctionG);
|
||||
|
||||
/// @return The current correctionB value
|
||||
uint8_t getcorrectionB() const;
|
||||
|
||||
/// @param blacklevel New correctionB value
|
||||
void setcorrectionB(uint8_t correctionB);
|
||||
|
||||
/// Transform the given array value
|
||||
/// @param input The input color bytes
|
||||
/// @return The corrected byte value
|
||||
uint8_t correctionR(uint8_t inputR) const;
|
||||
uint8_t correctionG(uint8_t inputG) const;
|
||||
uint8_t correctionB(uint8_t inputB) const;
|
||||
|
||||
|
||||
private:
|
||||
/// (re)-initilize the color mapping
|
||||
void initializeMapping();
|
||||
|
||||
private:
|
||||
/// The correction of R channel
|
||||
int _correctionR;
|
||||
/// The correction of G channel
|
||||
int _correctionG;
|
||||
/// The correction of B channel
|
||||
int _correctionB;
|
||||
|
||||
/// The mapping from input color to output color
|
||||
int _mappingR[256];
|
||||
int _mappingG[256];
|
||||
int _mappingB[256];
|
||||
};
|
@@ -4,8 +4,10 @@
|
||||
|
||||
#include <hyperion/ColorAdjustment.h>
|
||||
#include <hyperion/MultiColorAdjustment.h>
|
||||
#include "hyperion/MultiColorCorrection.h"
|
||||
#include <hyperion/LedString.h>
|
||||
#include <QRegularExpression>
|
||||
#include <utils/KelvinToRgb.h>
|
||||
|
||||
// fg effect
|
||||
#include <hyperion/Hyperion.h>
|
||||
@@ -14,6 +16,8 @@
|
||||
#include <effectengine/Effect.h>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
///
|
||||
/// @brief Provide utility methods for Hyperion class
|
||||
///
|
||||
@@ -100,6 +104,32 @@ namespace hyperion {
|
||||
);
|
||||
}
|
||||
|
||||
RgbChannelCorrection* createRgbChannelCorrection(const QJsonObject& colorConfig)
|
||||
{
|
||||
int varR = colorConfig["red"].toInt(255);
|
||||
int varG = colorConfig["green"].toInt(255);
|
||||
int varB = colorConfig["blue"].toInt(255);
|
||||
|
||||
RgbChannelCorrection* correction = new RgbChannelCorrection(varR, varG, varB);
|
||||
return correction;
|
||||
}
|
||||
|
||||
ColorCorrection * createColorCorrection(const QJsonObject& correctionConfig)
|
||||
{
|
||||
const QString id = correctionConfig["id"].toString("default");
|
||||
|
||||
RgbChannelCorrection * rgbCorrection = createRgbChannelCorrection(correctionConfig);
|
||||
|
||||
ColorCorrection * correction = new ColorCorrection();
|
||||
correction->_id = id;
|
||||
correction->_rgbCorrection = *rgbCorrection;
|
||||
|
||||
// Cleanup the allocated individual transforms
|
||||
delete rgbCorrection;
|
||||
|
||||
return correction;
|
||||
}
|
||||
|
||||
ColorAdjustment* createColorAdjustment(const QJsonObject & adjustmentConfig)
|
||||
{
|
||||
const QString id = adjustmentConfig["id"].toString("default");
|
||||
@@ -179,6 +209,77 @@ namespace hyperion {
|
||||
return adjustment;
|
||||
}
|
||||
|
||||
MultiColorCorrection * createLedColorsTemperature(int ledCnt, const QJsonObject & colorConfig)
|
||||
{
|
||||
// Create the result, the corrections are added to this
|
||||
MultiColorCorrection * correction = new MultiColorCorrection(ledCnt);
|
||||
|
||||
const QJsonValue adjustmentConfig = colorConfig["channelAdjustment"];
|
||||
const QRegularExpression overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*");
|
||||
|
||||
const QJsonArray & adjustmentConfigArray = adjustmentConfig.toArray();
|
||||
for (signed i = 0; i < adjustmentConfigArray.size(); ++i)
|
||||
{
|
||||
const QJsonObject & config = adjustmentConfigArray.at(i).toObject();
|
||||
ColorAdjustment * colorAdjustment = createColorAdjustment(config);
|
||||
|
||||
int temperature = config["temperature"].toInt();
|
||||
|
||||
ColorRgb rgb = getRgbFromTemperature(temperature);
|
||||
|
||||
qDebug() << "createLedColorsTemperature: adjustment[temperture]: " << temperature << "-> " << rgb.toQString();
|
||||
|
||||
QJsonObject correctionConfig {
|
||||
{"red", rgb.red},
|
||||
{"green", rgb.green},
|
||||
{"blue", rgb.blue}
|
||||
};
|
||||
|
||||
ColorCorrection * colorCorrection = createColorCorrection(correctionConfig);
|
||||
correction->addCorrection(colorCorrection);
|
||||
|
||||
const QString ledIndicesStr = config["leds"].toString("").trimmed();
|
||||
if (ledIndicesStr.compare("*") == 0)
|
||||
{
|
||||
// Special case for indices '*' => all leds
|
||||
correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1);
|
||||
Info(Logger::getInstance("HYPERION"), "ColorCorrection '%s' => [0-%d]", QSTRING_CSTR(colorCorrection->_id), ledCnt-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!overallExp.match(ledIndicesStr).hasMatch())
|
||||
{
|
||||
Error(Logger::getInstance("HYPERION"), "Given led indices %d not correct format: %s", i, QSTRING_CSTR(ledIndicesStr));
|
||||
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();
|
||||
correction->setCorrectionForLed(colorCorrection->_id, startInd, endInd);
|
||||
ss << startInd << "-" << endInd;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = ledIndexList[i].toInt();
|
||||
correction->setCorrectionForLed(colorCorrection->_id, index, index);
|
||||
ss << index;
|
||||
}
|
||||
}
|
||||
Info(Logger::getInstance("HYPERION"), "ColorCorrection '%s' => [%s]", QSTRING_CSTR(colorAdjustment->_id), ss.str().c_str());
|
||||
}
|
||||
return correction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the 'led-string' with the integration area definition per led and the color
|
||||
* ordering of the RGB channels
|
||||
|
Reference in New Issue
Block a user