ColorTransform functions added to repo

This commit is contained in:
johan 2013-08-05 23:49:17 +02:00
parent cbbb1d740b
commit 491d6ff608
5 changed files with 257 additions and 5 deletions

View File

@ -14,6 +14,8 @@ add_library(hyperion
${CURRENT_SOURCE_DIR}/LedString.cpp ${CURRENT_SOURCE_DIR}/LedString.cpp
${CURRENT_SOURCE_DIR}/Hyperion.cpp ${CURRENT_SOURCE_DIR}/Hyperion.cpp
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp ${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
${CURRENT_SOURCE_DIR}/ColorTransform.h
${CURRENT_SOURCE_DIR}/ColorTransform.cpp
) )
target_link_libraries(hyperion target_link_libraries(hyperion

View File

@ -0,0 +1,102 @@
#include <cmath>
#include "ColorTransform.h"
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

@ -0,0 +1,49 @@
#pragma once
#include "stdint.h"
/// 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 whitelevel, double blacklevel);
~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];
};

View File

@ -1,3 +1,5 @@
# Needed for testing non-public components
include_directories(../libsrc)
# Add the simple test executable 'TestSpi' # Add the simple test executable 'TestSpi'
add_executable(TestSpi add_executable(TestSpi
@ -25,13 +27,17 @@ add_executable(TestRgbImage
target_link_libraries(TestRgbImage target_link_libraries(TestRgbImage
hyperion-utils) hyperion-utils)
add_executable(TestColorTransform
TestColorTransform.cpp)
target_link_libraries(TestColorTransform
hyperion)
# Find the libPNG # Find the libPNG
find_package(PNG REQUIRED QUIET) find_package(PNG REQUIRED QUIET)
# Add additional includes dirs
include_directories(${PNG_INCLUDE_DIR})
#if(PNG_FOUND) #if(PNG_FOUND)
# Add additional includes dirs
include_directories(${PNG_INCLUDE_DIR})
add_executable(TestHyperionPng add_executable(TestHyperionPng
TestHyperionPng.cpp) TestHyperionPng.cpp)

View File

@ -0,0 +1,93 @@
#include <iostream>
#include <cmath>
#include <hyperion/ColorTransform.h>
int main()
{
{
std::cout << "Testing linear transform" << std::endl;
ColorTransform t;
for (int i = 0; i < 256; ++i)
{
uint8_t input = i;
uint8_t output = t.transform(input);
uint8_t expected = input;
if (output != expected)
{
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
return 1;
}
else
{
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
}
}
}
{
std::cout << "Testing threshold" << std::endl;
ColorTransform t(.10, 1.0, 0.0, 1.0);
for (int i = 0; i < 256; ++i)
{
uint8_t input = i;
uint8_t output = t.transform(input);
uint8_t expected = ((i/255.0) < t.getThreshold() ? 0 : output);
if (output != expected)
{
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
return 1;
}
else
{
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
}
}
}
{
std::cout << "Testing blacklevel and whitelevel" << std::endl;
ColorTransform t(0, 1.0, 0.2, 0.8);
for (int i = 0; i < 256; ++i)
{
uint8_t input = i;
uint8_t output = t.transform(input);
uint8_t expected = (uint8_t)(input * (t.getWhitelevel()-t.getBlacklevel()) + 255 * t.getBlacklevel());
if (output != expected)
{
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
return 1;
}
else
{
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
}
}
}
{
std::cout << "Testing gamma" << std::endl;
ColorTransform t(0, 2.0, 0.0, 1.0);
for (int i = 0; i < 256; ++i)
{
uint8_t input = i;
uint8_t output = t.transform(input);
uint8_t expected = (uint8_t)(255 * std::pow(i / 255.0, 2));
if (output != expected)
{
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
return 1;
}
else
{
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
}
}
}
return 0;
}