Add Temperature adjustment

This commit is contained in:
LordGrey
2022-12-22 20:10:44 +01:00
parent 1189f86c1a
commit 30b1a1b25f
18 changed files with 666 additions and 12 deletions

View 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

View 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];
};

View File

@@ -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