mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Added 'rainbow' boot sequence
Moved color transform to utils lib
This commit is contained in:
@@ -27,6 +27,28 @@ namespace hyperion
|
||||
|
||||
/// The size of detected border (negative if not applicable)
|
||||
int size;
|
||||
|
||||
///
|
||||
/// Compares this BlackBorder to the given other BlackBorder
|
||||
///
|
||||
/// @param[in] other The other BlackBorder
|
||||
///
|
||||
/// @return True if this is the same border as other
|
||||
///
|
||||
inline bool operator== (const BlackBorder& other) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case none:
|
||||
case unknown:
|
||||
return other.type == type;
|
||||
case horizontal:
|
||||
case vertical:
|
||||
return type == other.type && size == other.size;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
///
|
||||
|
@@ -13,7 +13,7 @@ BlackBorderProcessor::BlackBorderProcessor(
|
||||
_blurRemoveCnt(blurRemoveCnt),
|
||||
_detector(),
|
||||
_currentBorder({BlackBorder::unknown, 0}),
|
||||
_lastDetectedBorder({BlackBorder::unknown, 0}),
|
||||
_previousDetectedBorder({BlackBorder::unknown, 0}),
|
||||
_consistentCnt(0)
|
||||
{
|
||||
}
|
||||
@@ -32,35 +32,50 @@ bool BlackBorderProcessor::process(const RgbImage& image)
|
||||
{
|
||||
const BlackBorder imageBorder = _detector.process(image);
|
||||
|
||||
if (imageBorder.type == _lastDetectedBorder.type && imageBorder.size == _lastDetectedBorder.size)
|
||||
if (imageBorder == _previousDetectedBorder)
|
||||
{
|
||||
++_consistentCnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastDetectedBorder = imageBorder;
|
||||
_consistentCnt = 0;
|
||||
_previousDetectedBorder = imageBorder;
|
||||
_consistentCnt = 0;
|
||||
}
|
||||
|
||||
if (_currentBorder == imageBorder)
|
||||
{
|
||||
// No change required
|
||||
return false;
|
||||
}
|
||||
|
||||
bool borderChanged = false;
|
||||
switch (_lastDetectedBorder.type)
|
||||
switch (imageBorder.type)
|
||||
{
|
||||
case BlackBorder::none:
|
||||
borderChanged = (_currentBorder.type != BlackBorder::none);
|
||||
_currentBorder = _lastDetectedBorder;
|
||||
if (_consistentCnt == 0)
|
||||
{
|
||||
_currentBorder = imageBorder;
|
||||
borderChanged = true;
|
||||
}
|
||||
break;
|
||||
case BlackBorder::horizontal:
|
||||
case BlackBorder::vertical:
|
||||
if (_consistentCnt == _borderSwitchCnt)
|
||||
if (_currentBorder.type == BlackBorder::vertical || imageBorder.size < _currentBorder.size || _consistentCnt == _borderSwitchCnt)
|
||||
{
|
||||
_currentBorder = _lastDetectedBorder;
|
||||
_currentBorder = imageBorder;
|
||||
borderChanged = true;
|
||||
}
|
||||
break;
|
||||
case BlackBorder::vertical:
|
||||
if (_currentBorder.type == BlackBorder::horizontal || imageBorder.size < _currentBorder.size || _consistentCnt == _borderSwitchCnt)
|
||||
{
|
||||
_currentBorder = imageBorder;
|
||||
borderChanged = true;
|
||||
}
|
||||
break;
|
||||
case BlackBorder::unknown:
|
||||
if (_consistentCnt == _unknownSwitchCnt)
|
||||
{
|
||||
_currentBorder = _lastDetectedBorder;
|
||||
_currentBorder = imageBorder;
|
||||
borderChanged = true;
|
||||
}
|
||||
break;
|
||||
|
@@ -30,7 +30,7 @@ namespace hyperion
|
||||
|
||||
BlackBorder _currentBorder;
|
||||
|
||||
BlackBorder _lastDetectedBorder;
|
||||
BlackBorder _previousDetectedBorder;
|
||||
|
||||
unsigned _consistentCnt;
|
||||
};
|
||||
|
@@ -17,8 +17,6 @@ SET(Hyperion_HEADERS
|
||||
|
||||
${CURRENT_SOURCE_DIR}/BlackBorderDetector.h
|
||||
${CURRENT_SOURCE_DIR}/BlackBorderProcessor.h
|
||||
${CURRENT_SOURCE_DIR}/ColorTransform.h
|
||||
${CURRENT_SOURCE_DIR}/HsvTransform.h
|
||||
${CURRENT_SOURCE_DIR}/ImageToLedsMap.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceTest.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
|
||||
@@ -33,8 +31,6 @@ SET(Hyperion_SOURCES
|
||||
|
||||
${CURRENT_SOURCE_DIR}/BlackBorderDetector.cpp
|
||||
${CURRENT_SOURCE_DIR}/BlackBorderProcessor.cpp
|
||||
${CURRENT_SOURCE_DIR}/ColorTransform.cpp
|
||||
${CURRENT_SOURCE_DIR}/HsvTransform.cpp
|
||||
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceTest.cpp
|
||||
|
@@ -1,105 +0,0 @@
|
||||
// STL includes
|
||||
#include <cmath>
|
||||
|
||||
#include "ColorTransform.h"
|
||||
|
||||
using namespace hyperion;
|
||||
|
||||
ColorTransform::ColorTransform() :
|
||||
_threshold(0),
|
||||
_gamma(1.0),
|
||||
_blacklevel(0.0),
|
||||
_whitelevel(1.0)
|
||||
{
|
||||
initializeMapping();
|
||||
}
|
||||
|
||||
ColorTransform::ColorTransform(double threshold, double gamma, double blacklevel, double whitelevel) :
|
||||
_threshold(threshold),
|
||||
_gamma(gamma),
|
||||
_blacklevel(blacklevel),
|
||||
_whitelevel(whitelevel)
|
||||
{
|
||||
initializeMapping();
|
||||
}
|
||||
|
||||
ColorTransform::~ColorTransform()
|
||||
{
|
||||
}
|
||||
|
||||
double ColorTransform::getThreshold() const
|
||||
{
|
||||
return _threshold;
|
||||
}
|
||||
|
||||
void ColorTransform::setThreshold(double threshold)
|
||||
{
|
||||
_threshold = threshold;
|
||||
initializeMapping();
|
||||
}
|
||||
|
||||
double ColorTransform::getGamma() const
|
||||
{
|
||||
return _gamma;
|
||||
}
|
||||
|
||||
void ColorTransform::setGamma(double gamma)
|
||||
{
|
||||
_gamma = gamma;
|
||||
initializeMapping();
|
||||
}
|
||||
|
||||
double ColorTransform::getBlacklevel() const
|
||||
{
|
||||
return _blacklevel;
|
||||
}
|
||||
|
||||
void ColorTransform::setBlacklevel(double blacklevel)
|
||||
{
|
||||
_blacklevel = blacklevel;
|
||||
initializeMapping();
|
||||
}
|
||||
|
||||
double ColorTransform::getWhitelevel() const
|
||||
{
|
||||
return _whitelevel;
|
||||
}
|
||||
|
||||
void ColorTransform::setWhitelevel(double whitelevel)
|
||||
{
|
||||
_whitelevel = whitelevel;
|
||||
initializeMapping();
|
||||
}
|
||||
|
||||
void ColorTransform::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;
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// STL includes
|
||||
#include <cstdint>
|
||||
|
||||
namespace hyperion
|
||||
{
|
||||
|
||||
/// 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 ColorTransform
|
||||
{
|
||||
public:
|
||||
ColorTransform();
|
||||
ColorTransform(double threshold, double gamma, double blacklevel, double whitelevel);
|
||||
~ColorTransform();
|
||||
|
||||
double getThreshold() const;
|
||||
void setThreshold(double threshold);
|
||||
|
||||
double getGamma() const;
|
||||
void setGamma(double gamma);
|
||||
|
||||
double getBlacklevel() const;
|
||||
void setBlacklevel(double blacklevel);
|
||||
|
||||
double getWhitelevel() const;
|
||||
void setWhitelevel(double whitelevel);
|
||||
|
||||
/// get the transformed value for the given byte value
|
||||
uint8_t transform(uint8_t input) const
|
||||
{
|
||||
return _mapping[input];
|
||||
}
|
||||
|
||||
private:
|
||||
void initializeMapping();
|
||||
|
||||
private:
|
||||
double _threshold;
|
||||
double _gamma;
|
||||
double _blacklevel;
|
||||
double _whitelevel;
|
||||
|
||||
uint8_t _mapping[256];
|
||||
};
|
||||
|
||||
} // end namespace hyperion
|
@@ -1,135 +0,0 @@
|
||||
#include "HsvTransform.h"
|
||||
|
||||
using namespace hyperion;
|
||||
|
||||
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)
|
||||
hue = 0 + 60 * (green - blue) / (rgbMax - rgbMin);
|
||||
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)) * 6;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace hyperion
|
||||
{
|
||||
|
||||
class HsvTransform
|
||||
{
|
||||
public:
|
||||
HsvTransform();
|
||||
HsvTransform(double saturationGain, double valueGain);
|
||||
~HsvTransform();
|
||||
|
||||
void setSaturationGain(double saturationGain);
|
||||
double getSaturationGain() const;
|
||||
|
||||
void setValueGain(double valueGain);
|
||||
double getValueGain() const;
|
||||
|
||||
void transform(uint8_t & red, uint8_t & green, uint8_t & blue) const;
|
||||
|
||||
private:
|
||||
/// integer version of the conversion are faster, but a little less accurate
|
||||
/// all values are unsigned 8 bit values and scaled between 0 and 255 except
|
||||
/// for the hue which is a 16 bit number and scaled between 0 and 360
|
||||
static void rgb2hsv(uint8_t red, uint8_t green, uint8_t blue, uint16_t & hue, uint8_t & saturation, uint8_t & value);
|
||||
static void hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value, uint8_t & red, uint8_t & green, uint8_t & blue);
|
||||
|
||||
private:
|
||||
double _saturationGain;
|
||||
double _valueGain;
|
||||
};
|
||||
|
||||
} // namespace hyperion
|
@@ -13,10 +13,9 @@
|
||||
|
||||
#include "LedDeviceWs2801.h"
|
||||
#include "LedDeviceTest.h"
|
||||
#include "ColorTransform.h"
|
||||
#include "HsvTransform.h"
|
||||
|
||||
using namespace hyperion;
|
||||
#include <utils/ColorTransform.h>
|
||||
#include <utils/HsvTransform.h>
|
||||
|
||||
LedDevice* constructDevice(const Json::Value& deviceConfig)
|
||||
{
|
||||
|
@@ -2,9 +2,10 @@
|
||||
// Hyperion includes
|
||||
#include <hyperion/ImageProcessor.h>
|
||||
|
||||
#include <utils/ColorTransform.h>
|
||||
|
||||
// Local-Hyperion includes
|
||||
#include "BlackBorderProcessor.h"
|
||||
#include "ColorTransform.h"
|
||||
#include "ImageToLedsMap.h"
|
||||
|
||||
using namespace hyperion;
|
||||
|
Reference in New Issue
Block a user