Added 'rainbow' boot sequence

Moved color transform to utils lib
This commit is contained in:
T. van der Zwan
2013-08-23 16:24:10 +00:00
parent 6ee94409dc
commit 3d02fecc7a
20 changed files with 218 additions and 78 deletions

View File

@@ -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;
}
};
///

View File

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

View File

@@ -30,7 +30,7 @@ namespace hyperion
BlackBorder _currentBorder;
BlackBorder _lastDetectedBorder;
BlackBorder _previousDetectedBorder;
unsigned _consistentCnt;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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