mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Added simple QT-based grabber.
Moved ImageToLedsMap from include to libsrc. Moved instantiation of objects to Hyperion (no JSON required outside this class).
This commit is contained in:
parent
491d6ff608
commit
39b98386dd
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
# define the minimum cmake version (as required by cmake)
|
# define the minimum cmake version (as required by cmake)
|
||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
#set(CMAKE_TOOLCHAIN_FILE /opt/raspberrypi/Toolchain-RaspberryPi.cmake)
|
set(CMAKE_TOOLCHAIN_FILE /opt/raspberrypi/Toolchain-RaspberryPi.cmake)
|
||||||
|
|
||||||
# Define the main-project name
|
# Define the main-project name
|
||||||
project(Hyperion)
|
project(Hyperion)
|
||||||
@ -28,6 +28,15 @@ set(CMAKE_BUILD_TYPE "Release")
|
|||||||
# enable C++11
|
# enable C++11
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
|
||||||
|
|
||||||
|
# Configure the use of QT4
|
||||||
|
find_package(Qt4 COMPONENTS QtCore REQUIRED QUIET)
|
||||||
|
|
||||||
|
SET(QT_DONT_USE_QTGUI TRUE)
|
||||||
|
SET(QT_USE_QTCONSOLE TRUE)
|
||||||
|
include(${QT_USE_FILE})
|
||||||
|
add_definitions(${QT_DEFINITIONS})
|
||||||
|
link_directories(${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf)
|
||||||
|
|
||||||
configure_file(bin/install_hyperion.sh ${LIBRARY_OUTPUT_PATH} @ONLY)
|
configure_file(bin/install_hyperion.sh ${LIBRARY_OUTPUT_PATH} @ONLY)
|
||||||
configure_file(config/hyperion.config.json ${LIBRARY_OUTPUT_PATH} @ONLY)
|
configure_file(config/hyperion.config.json ${LIBRARY_OUTPUT_PATH} @ONLY)
|
||||||
configure_file(config/hyperion.schema.json ${LIBRARY_OUTPUT_PATH} @ONLY)
|
configure_file(config/hyperion.schema.json ${LIBRARY_OUTPUT_PATH} @ONLY)
|
||||||
|
32
include/hyperion/DispmanxWrapper.h
Normal file
32
include/hyperion/DispmanxWrapper.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// QT includes
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
// Forward class declaration
|
||||||
|
class ImageProcessor;
|
||||||
|
class DispmanxFrameGrabber;
|
||||||
|
|
||||||
|
class DispmanxWrapper: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DispmanxWrapper();
|
||||||
|
|
||||||
|
virtual ~DispmanxWrapper();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void action();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTimer _timer;
|
||||||
|
|
||||||
|
DispmanxFrameGrabber* _frameGrabber;
|
||||||
|
ImageProcessor* _processor;
|
||||||
|
};
|
||||||
|
|
@ -4,9 +4,14 @@
|
|||||||
// hyperion-utils includes
|
// hyperion-utils includes
|
||||||
#include <utils/RgbImage.h>
|
#include <utils/RgbImage.h>
|
||||||
|
|
||||||
|
// Hyperion includes
|
||||||
#include <hyperion/LedString.h>
|
#include <hyperion/LedString.h>
|
||||||
#include <hyperion/ImageToLedsMap.h>
|
|
||||||
#include <hyperion/LedDevice.h>
|
#include <hyperion/LedDevice.h>
|
||||||
|
#include <hyperion/PriorityMuxer.h>
|
||||||
|
|
||||||
|
// Forward class declaration
|
||||||
|
namespace hyperion { class ColorTransform; }
|
||||||
|
|
||||||
|
|
||||||
class Hyperion
|
class Hyperion
|
||||||
{
|
{
|
||||||
@ -15,27 +20,18 @@ public:
|
|||||||
|
|
||||||
~Hyperion();
|
~Hyperion();
|
||||||
|
|
||||||
void setInputSize(const unsigned width, const unsigned height);
|
void setValue(int priority, std::vector<RgbColor> &ledColors);
|
||||||
|
|
||||||
RgbImage& image()
|
|
||||||
{
|
|
||||||
return *mImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
void commit();
|
|
||||||
|
|
||||||
void operator() (const RgbImage& inputImage);
|
|
||||||
|
|
||||||
void setColor(const RgbColor& color);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void applyTransform(std::vector<RgbColor>& colors) const;
|
void applyTransform(std::vector<RgbColor>& colors) const;
|
||||||
|
|
||||||
LedString mLedString;
|
LedString mLedString;
|
||||||
|
|
||||||
RgbImage* mImage;
|
PriorityMuxer mMuxer;
|
||||||
|
|
||||||
ImageToLedsMap mLedsMap;
|
hyperion::ColorTransform* mRedTransform;
|
||||||
|
hyperion::ColorTransform* mGreenTransform;
|
||||||
|
hyperion::ColorTransform* mBlueTransform;
|
||||||
|
|
||||||
LedDevice* mDevice;
|
LedDevice* mDevice;
|
||||||
};
|
};
|
||||||
|
72
include/hyperion/ImageProcessor.h
Normal file
72
include/hyperion/ImageProcessor.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Utils includes
|
||||||
|
#include <utils/RgbImage.h>
|
||||||
|
|
||||||
|
#include <hyperion/LedString.h>
|
||||||
|
#include <hyperion/ImageProcessorFactory.h>
|
||||||
|
|
||||||
|
// Forward class declaration
|
||||||
|
namespace hyperion { class ImageToLedsMap;
|
||||||
|
class ColorTransform; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ImageProcessor translates an RGB-image to RGB-values for the leds. The processing is
|
||||||
|
* performed in two steps. First the average color per led-region is computed. Second a
|
||||||
|
* color-tranform is applied based on a gamma-correction.
|
||||||
|
*/
|
||||||
|
class ImageProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Processes the image to a list of led colors. This will update the size of the buffer-image
|
||||||
|
* if required and call the image-to-leds mapping to determine the mean color per led.
|
||||||
|
*
|
||||||
|
* @param[in] image The image to translate to led values
|
||||||
|
*
|
||||||
|
* @return The color value per led
|
||||||
|
*/
|
||||||
|
std::vector<RgbColor> process(const RgbImage& image);
|
||||||
|
|
||||||
|
// 'IN PLACE' processing functions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the width and height of 'incomming' images. This will resize the buffer-image to
|
||||||
|
* match the given size.
|
||||||
|
* NB All earlier obtained references will be invalid.
|
||||||
|
*
|
||||||
|
* @param[in] width The new width of the buffer-image
|
||||||
|
* @param[in] height The new height of the buffer-image
|
||||||
|
*/
|
||||||
|
void setSize(const unsigned width, const unsigned height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference of the underlying image-buffer. This can be used to write data directly
|
||||||
|
* into the buffer, avoiding a copy inside the process method.
|
||||||
|
*
|
||||||
|
* @return The reference of the underlying image-buffer.
|
||||||
|
*/
|
||||||
|
RgbImage& image();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the led colors of the image in the buffer.
|
||||||
|
*
|
||||||
|
* @param[out] ledColors The color value per led
|
||||||
|
*/
|
||||||
|
void inplace_process(std::vector<RgbColor>& ledColors);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ImageProcessorFactory;
|
||||||
|
|
||||||
|
ImageProcessor(const LedString &ledString);
|
||||||
|
|
||||||
|
~ImageProcessor();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const LedString mLedString;
|
||||||
|
|
||||||
|
RgbImage *mBuffer;
|
||||||
|
hyperion::ImageToLedsMap* mImageToLeds;
|
||||||
|
};
|
||||||
|
|
26
include/hyperion/ImageProcessorFactory.h
Normal file
26
include/hyperion/ImageProcessorFactory.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// Jsoncpp includes
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
#include <hyperion/LedString.h>
|
||||||
|
|
||||||
|
// Forward class declaration
|
||||||
|
class ImageProcessor;
|
||||||
|
|
||||||
|
class ImageProcessorFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static ImageProcessorFactory& getInstance();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void init(const LedString& ledString);
|
||||||
|
|
||||||
|
ImageProcessor* newImageProcessor() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LedString _ledString;
|
||||||
|
};
|
@ -1,27 +0,0 @@
|
|||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// hyperion-utils includes
|
|
||||||
#include <utils/RgbImage.h>
|
|
||||||
|
|
||||||
// hyperion includes
|
|
||||||
#include <hyperion/LedString.h>
|
|
||||||
|
|
||||||
class ImageToLedsMap
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
ImageToLedsMap();
|
|
||||||
|
|
||||||
void createMapping(const RgbImage& image, const std::vector<Led>& leds);
|
|
||||||
|
|
||||||
std::vector<RgbColor> getMeanLedColor();
|
|
||||||
|
|
||||||
RgbColor findMeanColor(const std::vector<const RgbColor*>& colors);
|
|
||||||
|
|
||||||
std::vector<RgbColor> getMedianLedColor();
|
|
||||||
|
|
||||||
RgbColor findMedianColor(std::vector<const RgbColor*>& colors);
|
|
||||||
private:
|
|
||||||
std::vector<std::vector<const RgbColor*> > mColorsMap;
|
|
||||||
};
|
|
@ -45,28 +45,16 @@ struct Led
|
|||||||
class LedString
|
class LedString
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static LedString construct(const Json::Value& ledConfig, const Json::Value& colorConfig);
|
static LedString construct(const Json::Value& ledConfig);
|
||||||
|
|
||||||
LedString();
|
LedString();
|
||||||
|
|
||||||
~LedString();
|
~LedString();
|
||||||
|
|
||||||
|
std::vector<Led>& leds();
|
||||||
|
|
||||||
const std::vector<Led>& leds() const;
|
const std::vector<Led>& leds() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Led> mLeds;
|
std::vector<Led> mLeds;
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Color adjustements per color
|
|
||||||
*/
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
/** The color gradient */
|
|
||||||
double gamma;
|
|
||||||
/** The color offset */
|
|
||||||
double adjust;
|
|
||||||
/** The minimum required level for the led to turn on */
|
|
||||||
double blacklevel;
|
|
||||||
} red, green, blue;
|
|
||||||
};
|
};
|
||||||
|
55
include/hyperion/PriorityMuxer.h
Normal file
55
include/hyperion/PriorityMuxer.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
// QT includes
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
// Utils includes
|
||||||
|
#include <utils/RgbColor.h>
|
||||||
|
|
||||||
|
// Hyperion includes
|
||||||
|
#include <hyperion/LedDevice.h>
|
||||||
|
|
||||||
|
class PriorityMuxer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct InputInfo
|
||||||
|
{
|
||||||
|
int priority;
|
||||||
|
|
||||||
|
int64_t timeoutTime_ms;
|
||||||
|
std::vector<RgbColor> ledColors;
|
||||||
|
};
|
||||||
|
|
||||||
|
PriorityMuxer();
|
||||||
|
|
||||||
|
~PriorityMuxer();
|
||||||
|
|
||||||
|
int getCurrentPriority() const;
|
||||||
|
|
||||||
|
bool hasPriority(const int priority) const;
|
||||||
|
|
||||||
|
QList<int> getPriorities() const;
|
||||||
|
|
||||||
|
const InputInfo& getInputInfo(const int priority) const;
|
||||||
|
|
||||||
|
void setInput(const int priority, const std::vector<RgbColor>& ledColors, const int64_t timeoutTime_ms=-1);
|
||||||
|
|
||||||
|
void clearInput(const int priority);
|
||||||
|
|
||||||
|
void clearAll();
|
||||||
|
|
||||||
|
void setCurrentTime(const int64_t& now);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mCurrentPriority;
|
||||||
|
|
||||||
|
QMap<int, InputInfo> mActiveInputs;
|
||||||
|
|
||||||
|
const static int MAX_PRIORITY = std::numeric_limits<int>::max();
|
||||||
|
};
|
@ -5,7 +5,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
// Forward class declaration
|
// Forward class declaration
|
||||||
struct RgbColor;
|
struct RgbColor;
|
||||||
|
|
||||||
@ -21,8 +20,12 @@ struct RgbColor
|
|||||||
static RgbColor BLUE;
|
static RgbColor BLUE;
|
||||||
static RgbColor YELLOW;
|
static RgbColor YELLOW;
|
||||||
static RgbColor WHITE;
|
static RgbColor WHITE;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(RgbColor) == 3, "Incorrect size of RgbColor");
|
||||||
|
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, const RgbColor& color)
|
inline std::ostream& operator<<(std::ostream& os, const RgbColor& color)
|
||||||
{
|
{
|
||||||
os << "{" << unsigned(color.red) << "," << unsigned(color.green) << "," << unsigned(color.blue) << "}";
|
os << "{" << unsigned(color.red) << "," << unsigned(color.green) << "," << unsigned(color.blue) << "}";
|
||||||
|
@ -10,18 +10,22 @@ target_link_libraries(bob2hyperion
|
|||||||
hyperion
|
hyperion
|
||||||
hyperion-utils)
|
hyperion-utils)
|
||||||
|
|
||||||
|
add_subdirectory(hyperion)
|
||||||
|
add_subdirectory(utils)
|
||||||
|
|
||||||
# Find the libPNG
|
# Find the libPNG
|
||||||
find_package(PNG REQUIRED QUIET)
|
find_package(PNG REQUIRED QUIET)
|
||||||
|
|
||||||
# Add additional includes dirs
|
if (PNG_FOUND)
|
||||||
include_directories(${PNG_INCLUDE_DIR})
|
# Add additional includes dirs
|
||||||
|
include_directories(${PNG_INCLUDE_DIR})
|
||||||
|
|
||||||
add_library(bob2hyperion-png SHARED
|
add_library(bob2hyperion-png SHARED
|
||||||
hyperion-png.cpp)
|
hyperion-png.cpp)
|
||||||
|
|
||||||
target_link_libraries(bob2hyperion-png
|
target_link_libraries(bob2hyperion-png
|
||||||
hyperion-png)
|
hyperion-png)
|
||||||
|
|
||||||
|
add_subdirectory(hyperionpng)
|
||||||
|
endif(PNG_FOUND)
|
||||||
|
|
||||||
add_subdirectory(hyperion)
|
|
||||||
add_subdirectory(hyperionpng)
|
|
||||||
add_subdirectory(utils)
|
|
||||||
|
@ -51,7 +51,7 @@ void boblight_destroy(void* hyperion_ptr)
|
|||||||
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
||||||
|
|
||||||
// Switch all leds to black (off)
|
// Switch all leds to black (off)
|
||||||
raspiLight->setColor(RgbColor::BLACK);
|
// raspiLight->setColor(RgbColor::BLACK);
|
||||||
|
|
||||||
delete raspiLight;
|
delete raspiLight;
|
||||||
|
|
||||||
@ -64,20 +64,20 @@ void boblight_setscanrange(void* hyperion_ptr, int width, int height)
|
|||||||
syslog(LOG_INFO, "Configuring scan range [%dx%d]", width, height);
|
syslog(LOG_INFO, "Configuring scan range [%dx%d]", width, height);
|
||||||
|
|
||||||
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
||||||
raspiLight->setInputSize(width, height);
|
// raspiLight->setInputSize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void boblight_addpixelxy(void* hyperion_ptr, int x, int y, int* rgb)
|
void boblight_addpixelxy(void* hyperion_ptr, int x, int y, int* rgb)
|
||||||
{
|
{
|
||||||
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
||||||
const RgbColor color = {uint8_t(rgb[0]), uint8_t(rgb[1]), uint8_t(rgb[2])};
|
const RgbColor color = {uint8_t(rgb[0]), uint8_t(rgb[1]), uint8_t(rgb[2])};
|
||||||
raspiLight->image().setPixel(x, y, color);
|
// raspiLight->image().setPixel(x, y, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
int boblight_sendrgb(void* hyperion_ptr, int sync, int* outputused)
|
int boblight_sendrgb(void* hyperion_ptr, int sync, int* outputused)
|
||||||
{
|
{
|
||||||
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
||||||
raspiLight->commit();
|
// raspiLight->commit();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,52 @@
|
|||||||
|
|
||||||
|
# Find the BCM-package (VC control)
|
||||||
|
find_package(BCM REQUIRED)
|
||||||
|
include_directories(${BCM_INCLUDE_DIRS})
|
||||||
|
|
||||||
# Define the current source locations
|
# Define the current source locations
|
||||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion)
|
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion)
|
||||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion)
|
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion)
|
||||||
|
|
||||||
add_library(hyperion
|
SET(Hyperion_HEADERS
|
||||||
${CURRENT_HEADER_DIR}/Hyperion.h
|
${CURRENT_HEADER_DIR}/Hyperion.h
|
||||||
${CURRENT_HEADER_DIR}/LedDevice.h
|
${CURRENT_HEADER_DIR}/LedDevice.h
|
||||||
${CURRENT_HEADER_DIR}/LedString.h
|
${CURRENT_HEADER_DIR}/LedString.h
|
||||||
${CURRENT_HEADER_DIR}/ImageToLedsMap.h
|
${CURRENT_HEADER_DIR}/ImageProcessor.h
|
||||||
|
${CURRENT_HEADER_DIR}/ImageProcessorFactory.h
|
||||||
|
${CURRENT_HEADER_DIR}/PriorityMuxer.h
|
||||||
|
${CURRENT_HEADER_DIR}/DispmanxWrapper.h
|
||||||
|
|
||||||
|
${CURRENT_SOURCE_DIR}/DispmanxFrameGrabber.h
|
||||||
|
|
||||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
|
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
|
||||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
|
${CURRENT_SOURCE_DIR}/ImageToLedsMap.h
|
||||||
|
${CURRENT_SOURCE_DIR}/ColorTransform.h
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(Hyperion_SOURCES
|
||||||
${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}/ImageProcessor.cpp
|
||||||
${CURRENT_SOURCE_DIR}/ColorTransform.h
|
${CURRENT_SOURCE_DIR}/ImageProcessorFactory.cpp
|
||||||
${CURRENT_SOURCE_DIR}/ColorTransform.cpp
|
${CURRENT_SOURCE_DIR}/PriorityMuxer.cpp
|
||||||
|
|
||||||
|
${CURRENT_SOURCE_DIR}/DispmanxWrapper.cpp
|
||||||
|
${CURRENT_SOURCE_DIR}/DispmanxFrameGrabber.cpp
|
||||||
|
|
||||||
|
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
|
||||||
|
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
|
||||||
|
${CURRENT_SOURCE_DIR}/ColorTransform.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_HEADERS})
|
||||||
|
|
||||||
|
add_library(hyperion
|
||||||
|
${Hyperion_HEADERS}
|
||||||
|
${Hyperion_HEADERS_MOC}
|
||||||
|
${Hyperion_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(hyperion
|
target_link_libraries(hyperion
|
||||||
hyperion-utils)
|
hyperion-utils
|
||||||
|
${QT_LIBRARIES}
|
||||||
|
${BCM_LIBRARIES})
|
||||||
|
@ -1,23 +1,26 @@
|
|||||||
|
// STL includes
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include "ColorTransform.h"
|
#include "ColorTransform.h"
|
||||||
|
|
||||||
|
using namespace hyperion;
|
||||||
|
|
||||||
ColorTransform::ColorTransform() :
|
ColorTransform::ColorTransform() :
|
||||||
_threshold(0),
|
_threshold(0),
|
||||||
_gamma(1.0),
|
_gamma(1.0),
|
||||||
_blacklevel(0.0),
|
_blacklevel(0.0),
|
||||||
_whitelevel(1.0)
|
_whitelevel(1.0)
|
||||||
{
|
{
|
||||||
initializeMapping();
|
initializeMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorTransform::ColorTransform(double threshold, double gamma, double blacklevel, double whitelevel) :
|
ColorTransform::ColorTransform(double threshold, double gamma, double blacklevel, double whitelevel) :
|
||||||
_threshold(threshold),
|
_threshold(threshold),
|
||||||
_gamma(gamma),
|
_gamma(gamma),
|
||||||
_blacklevel(blacklevel),
|
_blacklevel(blacklevel),
|
||||||
_whitelevel(whitelevel)
|
_whitelevel(whitelevel)
|
||||||
{
|
{
|
||||||
initializeMapping();
|
initializeMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorTransform::~ColorTransform()
|
ColorTransform::~ColorTransform()
|
||||||
@ -26,77 +29,77 @@ ColorTransform::~ColorTransform()
|
|||||||
|
|
||||||
double ColorTransform::getThreshold() const
|
double ColorTransform::getThreshold() const
|
||||||
{
|
{
|
||||||
return _threshold;
|
return _threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorTransform::setThreshold(double threshold)
|
void ColorTransform::setThreshold(double threshold)
|
||||||
{
|
{
|
||||||
_threshold = threshold;
|
_threshold = threshold;
|
||||||
initializeMapping();
|
initializeMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
double ColorTransform::getGamma() const
|
double ColorTransform::getGamma() const
|
||||||
{
|
{
|
||||||
return _gamma;
|
return _gamma;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorTransform::setGamma(double gamma)
|
void ColorTransform::setGamma(double gamma)
|
||||||
{
|
{
|
||||||
_gamma = gamma;
|
_gamma = gamma;
|
||||||
initializeMapping();
|
initializeMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
double ColorTransform::getBlacklevel() const
|
double ColorTransform::getBlacklevel() const
|
||||||
{
|
{
|
||||||
return _blacklevel;
|
return _blacklevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorTransform::setBlacklevel(double blacklevel)
|
void ColorTransform::setBlacklevel(double blacklevel)
|
||||||
{
|
{
|
||||||
_blacklevel = blacklevel;
|
_blacklevel = blacklevel;
|
||||||
initializeMapping();
|
initializeMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
double ColorTransform::getWhitelevel() const
|
double ColorTransform::getWhitelevel() const
|
||||||
{
|
{
|
||||||
return _whitelevel;
|
return _whitelevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorTransform::setWhitelevel(double whitelevel)
|
void ColorTransform::setWhitelevel(double whitelevel)
|
||||||
{
|
{
|
||||||
_whitelevel = whitelevel;
|
_whitelevel = whitelevel;
|
||||||
initializeMapping();
|
initializeMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorTransform::initializeMapping()
|
void ColorTransform::initializeMapping()
|
||||||
{
|
{
|
||||||
// initialize the mapping as a linear array
|
// initialize the mapping as a linear array
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
double output = i / 255.0;
|
double output = i / 255.0;
|
||||||
|
|
||||||
// apply linear transform
|
// apply linear transform
|
||||||
if (output < _threshold)
|
if (output < _threshold)
|
||||||
{
|
{
|
||||||
output = 0.0;
|
output = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply gamma correction
|
// apply gamma correction
|
||||||
output = std::pow(output, _gamma);
|
output = std::pow(output, _gamma);
|
||||||
|
|
||||||
// apply blacklevel and whitelevel
|
// apply blacklevel and whitelevel
|
||||||
output = _blacklevel + (_whitelevel - _blacklevel) * output;
|
output = _blacklevel + (_whitelevel - _blacklevel) * output;
|
||||||
|
|
||||||
// calc mapping
|
// calc mapping
|
||||||
int mappingValue = output * 255;
|
int mappingValue = output * 255;
|
||||||
if (mappingValue < 0)
|
if (mappingValue < 0)
|
||||||
{
|
{
|
||||||
mappingValue = 0;
|
mappingValue = 0;
|
||||||
}
|
}
|
||||||
else if (mappingValue > 255)
|
else if (mappingValue > 255)
|
||||||
{
|
{
|
||||||
mappingValue = 255;
|
mappingValue = 255;
|
||||||
}
|
}
|
||||||
_mapping[i] = mappingValue;
|
_mapping[i] = mappingValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "stdint.h"
|
// STL includes
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace hyperion
|
||||||
|
{
|
||||||
|
|
||||||
/// Transform for a single color byte value
|
/// Transform for a single color byte value
|
||||||
///
|
///
|
||||||
@ -14,36 +18,38 @@
|
|||||||
class ColorTransform
|
class ColorTransform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ColorTransform();
|
ColorTransform();
|
||||||
ColorTransform(double threshold, double gamma, double whitelevel, double blacklevel);
|
ColorTransform(double threshold, double gamma, double blacklevel, double whitelevel);
|
||||||
~ColorTransform();
|
~ColorTransform();
|
||||||
|
|
||||||
double getThreshold() const;
|
double getThreshold() const;
|
||||||
void setThreshold(double threshold);
|
void setThreshold(double threshold);
|
||||||
|
|
||||||
double getGamma() const;
|
double getGamma() const;
|
||||||
void setGamma(double gamma);
|
void setGamma(double gamma);
|
||||||
|
|
||||||
double getBlacklevel() const;
|
double getBlacklevel() const;
|
||||||
void setBlacklevel(double blacklevel);
|
void setBlacklevel(double blacklevel);
|
||||||
|
|
||||||
double getWhitelevel() const;
|
double getWhitelevel() const;
|
||||||
void setWhitelevel(double whitelevel);
|
void setWhitelevel(double whitelevel);
|
||||||
|
|
||||||
/// get the transformed value for the given byte value
|
/// get the transformed value for the given byte value
|
||||||
uint8_t transform(uint8_t input) const
|
uint8_t transform(uint8_t input) const
|
||||||
{
|
{
|
||||||
return _mapping[input];
|
return _mapping[input];
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initializeMapping();
|
void initializeMapping();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double _threshold;
|
double _threshold;
|
||||||
double _gamma;
|
double _gamma;
|
||||||
double _blacklevel;
|
double _blacklevel;
|
||||||
double _whitelevel;
|
double _whitelevel;
|
||||||
|
|
||||||
uint8_t _mapping[256];
|
uint8_t _mapping[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // end namespace hyperion
|
||||||
|
54
libsrc/hyperion/DispmanxFrameGrabber.cpp
Normal file
54
libsrc/hyperion/DispmanxFrameGrabber.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
#include "DispmanxFrameGrabber.h"
|
||||||
|
|
||||||
|
DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned height) :
|
||||||
|
_display(0),
|
||||||
|
_resource(0),
|
||||||
|
_width(width),
|
||||||
|
_height(height)
|
||||||
|
{
|
||||||
|
// Initiase BCM
|
||||||
|
bcm_host_init();
|
||||||
|
|
||||||
|
// Open the connection to the displaydisplay
|
||||||
|
_display = vc_dispmanx_display_open(0);
|
||||||
|
int ret = vc_dispmanx_display_get_info(_display, &_info);
|
||||||
|
assert(ret == 0);
|
||||||
|
|
||||||
|
// Create the resources for capturing image
|
||||||
|
_resource = vc_dispmanx_resource_create(
|
||||||
|
VC_IMAGE_RGB888,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
&_vc_image_ptr);
|
||||||
|
assert(_resource);
|
||||||
|
|
||||||
|
// Define the capture rectangle with the same size
|
||||||
|
vc_dispmanx_rect_set(&_rectangle, 0, 0, width, height);
|
||||||
|
_pitch = width * 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
DispmanxFrameGrabber::~DispmanxFrameGrabber()
|
||||||
|
{
|
||||||
|
// Clean up resources
|
||||||
|
vc_dispmanx_resource_delete(_resource);
|
||||||
|
|
||||||
|
// Close the displaye
|
||||||
|
vc_dispmanx_display_close(_display);
|
||||||
|
|
||||||
|
// De-init BCM
|
||||||
|
bcm_host_deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispmanxFrameGrabber::grabFrame(RgbImage& image)
|
||||||
|
{
|
||||||
|
// Sanity check of the given image size
|
||||||
|
assert(image.width() == _width && image.height() == _height);
|
||||||
|
|
||||||
|
void* image_ptr = image.memptr();
|
||||||
|
|
||||||
|
// Create the snapshot
|
||||||
|
vc_dispmanx_snapshot(_display, _resource, VC_IMAGE_ROT0);
|
||||||
|
// Read the snapshot into the memory (incl down-scaling)
|
||||||
|
vc_dispmanx_resource_read_data(_resource, &_rectangle, image_ptr, _pitch);
|
||||||
|
}
|
35
libsrc/hyperion/DispmanxFrameGrabber.h
Normal file
35
libsrc/hyperion/DispmanxFrameGrabber.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// BCM includes
|
||||||
|
#include <bcm_host.h>
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// Utils includes
|
||||||
|
#include <utils/RgbImage.h>
|
||||||
|
|
||||||
|
///
|
||||||
|
/// The DispmanxFrameGrabber grabs
|
||||||
|
///
|
||||||
|
class DispmanxFrameGrabber
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DispmanxFrameGrabber(const unsigned width, const unsigned height);
|
||||||
|
~DispmanxFrameGrabber();
|
||||||
|
|
||||||
|
void grabFrame(RgbImage& image);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DISPMANX_DISPLAY_HANDLE_T _display;
|
||||||
|
DISPMANX_MODEINFO_T _info;
|
||||||
|
|
||||||
|
DISPMANX_RESOURCE_HANDLE_T _resource;
|
||||||
|
|
||||||
|
uint32_t _vc_image_ptr;
|
||||||
|
|
||||||
|
VC_RECT_T _rectangle;
|
||||||
|
unsigned _width;
|
||||||
|
unsigned _height;
|
||||||
|
uint32_t _pitch;
|
||||||
|
};
|
46
libsrc/hyperion/DispmanxWrapper.cpp
Normal file
46
libsrc/hyperion/DispmanxWrapper.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// QT includes
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
// Hyperion includes
|
||||||
|
#include <hyperion/DispmanxWrapper.h>
|
||||||
|
#include <hyperion/ImageProcessorFactory.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Local-Hyperion includes
|
||||||
|
#include "DispmanxFrameGrabber.h"
|
||||||
|
|
||||||
|
DispmanxWrapper::DispmanxWrapper() :
|
||||||
|
_timer(),
|
||||||
|
_processor(ImageProcessorFactory::getInstance().newImageProcessor()),
|
||||||
|
_frameGrabber(new DispmanxFrameGrabber(64, 64))
|
||||||
|
{
|
||||||
|
_timer.setInterval(100);
|
||||||
|
_timer.setSingleShot(false);
|
||||||
|
|
||||||
|
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(action()));
|
||||||
|
}
|
||||||
|
|
||||||
|
DispmanxWrapper::~DispmanxWrapper()
|
||||||
|
{
|
||||||
|
delete _frameGrabber;
|
||||||
|
delete _processor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispmanxWrapper::start()
|
||||||
|
{
|
||||||
|
_timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispmanxWrapper::action()
|
||||||
|
{
|
||||||
|
qDebug() << "[" << QDateTime::currentDateTimeUtc() << "] Grabbing frame";
|
||||||
|
RgbImage image(64, 64);
|
||||||
|
_frameGrabber->grabFrame(image);
|
||||||
|
|
||||||
|
//_processor->
|
||||||
|
}
|
||||||
|
void DispmanxWrapper::stop()
|
||||||
|
{
|
||||||
|
_timer.stop();
|
||||||
|
}
|
@ -10,6 +10,9 @@
|
|||||||
#include <hyperion/LedDevice.h>
|
#include <hyperion/LedDevice.h>
|
||||||
|
|
||||||
#include "LedDeviceWs2801.h"
|
#include "LedDeviceWs2801.h"
|
||||||
|
#include "ColorTransform.h"
|
||||||
|
|
||||||
|
using namespace hyperion;
|
||||||
|
|
||||||
LedDevice* constructDevice(const Json::Value& deviceConfig)
|
LedDevice* constructDevice(const Json::Value& deviceConfig)
|
||||||
{
|
{
|
||||||
@ -34,9 +37,41 @@ LedDevice* constructDevice(const Json::Value& deviceConfig)
|
|||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColorTransform* createColorTransform(const Json::Value& colorConfig)
|
||||||
|
{
|
||||||
|
const double threshold = colorConfig["threshold"].asDouble();
|
||||||
|
const double gamma = colorConfig["gamma"].asDouble();
|
||||||
|
const double blacklevel = colorConfig["blacklevel"].asDouble();
|
||||||
|
const double whitelevel = colorConfig["whitelevel"].asDouble();
|
||||||
|
|
||||||
|
ColorTransform* transform = new ColorTransform(threshold, gamma, blacklevel, whitelevel);
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
LedString createLedString(const Json::Value& ledsConfig)
|
||||||
|
{
|
||||||
|
LedString ledString;
|
||||||
|
|
||||||
|
for (const Json::Value& ledConfig : ledsConfig)
|
||||||
|
{
|
||||||
|
Led led;
|
||||||
|
led.index = ledConfig["index"].asInt();
|
||||||
|
const Json::Value& hscanConfig = ledConfig["hscan"];
|
||||||
|
const Json::Value& vscanConfig = ledConfig["vscan"];
|
||||||
|
led.minX_frac = std::max(0.0, std::min(100.0, hscanConfig["minimum"].asDouble()))/100.0;
|
||||||
|
led.maxX_frac = std::max(0.0, std::min(100.0, hscanConfig["maximum"].asDouble()))/100.0;
|
||||||
|
led.minY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["maximum"].asDouble()))/100.0;
|
||||||
|
led.maxY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["minimum"].asDouble()))/100.0;
|
||||||
|
|
||||||
|
ledString.leds().push_back(led);
|
||||||
|
}
|
||||||
|
return ledString;
|
||||||
|
}
|
||||||
|
|
||||||
Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
||||||
mLedString(LedString::construct(jsonConfig["leds"], jsonConfig["color"])),
|
mLedString(createLedString(jsonConfig["leds"])),
|
||||||
mImage(nullptr),
|
mRedTransform( createColorTransform(jsonConfig["color"]["red"])),
|
||||||
|
mGreenTransform(createColorTransform(jsonConfig["color"]["green"])),
|
||||||
|
mBlueTransform( createColorTransform(jsonConfig["color"]["blue"])),
|
||||||
mDevice(constructDevice(jsonConfig["device"]))
|
mDevice(constructDevice(jsonConfig["device"]))
|
||||||
{
|
{
|
||||||
// empty
|
// empty
|
||||||
@ -45,58 +80,29 @@ Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
|||||||
|
|
||||||
Hyperion::~Hyperion()
|
Hyperion::~Hyperion()
|
||||||
{
|
{
|
||||||
// Delete the existing image (or delete nullptr)
|
|
||||||
delete mImage;
|
|
||||||
|
|
||||||
// Delete the Led-String
|
// Delete the Led-String
|
||||||
delete mDevice;
|
delete mDevice;
|
||||||
|
|
||||||
|
// Delete the color-transform
|
||||||
|
delete mBlueTransform;
|
||||||
|
delete mGreenTransform;
|
||||||
|
delete mRedTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hyperion::setInputSize(const unsigned width, const unsigned height)
|
void Hyperion::setValue(int priority, std::vector<RgbColor>& ledColors)
|
||||||
{
|
{
|
||||||
// Delete the existing image (or delete nullptr)
|
// Apply the transform to each led and color-channel
|
||||||
delete mImage;
|
for (RgbColor& color : ledColors)
|
||||||
|
|
||||||
// Create the new image with the mapping to the leds
|
|
||||||
mImage = new RgbImage(width, height);
|
|
||||||
mLedsMap.createMapping(*mImage, mLedString.leds());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hyperion::commit()
|
|
||||||
{
|
|
||||||
// Derive the color per led
|
|
||||||
std::vector<RgbColor> ledColors = mLedsMap.getMeanLedColor();
|
|
||||||
// const std::vector<RgbColor> ledColors = mLedsMap.getMedianLedColor();
|
|
||||||
|
|
||||||
// Write the Led colors to the led-string
|
|
||||||
mDevice->write(ledColors);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hyperion::operator() (const RgbImage& inputImage)
|
|
||||||
{
|
|
||||||
// Copy the input-image into the buffer
|
|
||||||
mImage->copy(inputImage);
|
|
||||||
|
|
||||||
// Derive the color per led
|
|
||||||
std::vector<RgbColor> ledColors = mLedsMap.getMeanLedColor();
|
|
||||||
// std::vector<RgbColor> ledColors = mLedsMap.getMedianLedColor();
|
|
||||||
applyTransform(ledColors);
|
|
||||||
|
|
||||||
// Write the Led colors to the led-string
|
|
||||||
mDevice->write(ledColors);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hyperion::setColor(const RgbColor& color)
|
|
||||||
{
|
|
||||||
mDevice->write(std::vector<RgbColor>(mLedString.leds().size(), color));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hyperion::applyTransform(std::vector<RgbColor>& colors) const
|
|
||||||
{
|
|
||||||
for (RgbColor& color : colors)
|
|
||||||
{
|
{
|
||||||
color.red = (color.red < mLedString.red.blacklevel)? 0 : mLedString.red.adjust + mLedString.red.gamma * color.red;
|
color.red = mRedTransform->transform(color.red);
|
||||||
color.green = (color.green < mLedString.green.blacklevel)? 0 : mLedString.green.adjust + mLedString.green.gamma * color.green;
|
color.green = mGreenTransform->transform(color.green);
|
||||||
color.blue = (color.blue < mLedString.blue.blacklevel)? 0 : mLedString.blue.adjust + mLedString.blue.gamma * color.blue;
|
color.blue = mBlueTransform->transform(color.blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
mMuxer.setInput(priority, ledColors);
|
||||||
|
|
||||||
|
if (priority == mMuxer.getCurrentPriority())
|
||||||
|
{
|
||||||
|
mDevice->write(ledColors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
65
libsrc/hyperion/ImageProcessor.cpp
Normal file
65
libsrc/hyperion/ImageProcessor.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include <hyperion/ImageProcessor.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "ImageToLedsMap.h"
|
||||||
|
#include "ColorTransform.h"
|
||||||
|
|
||||||
|
using namespace hyperion;
|
||||||
|
|
||||||
|
ImageProcessor::ImageProcessor(const LedString& ledString) :
|
||||||
|
mLedString(ledString),
|
||||||
|
mBuffer(nullptr),
|
||||||
|
mImageToLeds(nullptr)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageProcessor::~ImageProcessor()
|
||||||
|
{
|
||||||
|
delete mImageToLeds;
|
||||||
|
delete mBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RgbColor> ImageProcessor::process(const RgbImage& image)
|
||||||
|
{
|
||||||
|
// Ensure that the buffer-image is the proper size
|
||||||
|
setSize(image.width(), image.height());
|
||||||
|
|
||||||
|
// Copy the data of the given image into the mapped-image
|
||||||
|
mBuffer->copy(image);
|
||||||
|
|
||||||
|
// Create a result vector and call the 'in place' functionl
|
||||||
|
std::vector<RgbColor> colors(mLedString.leds().size(), RgbColor::BLACK);
|
||||||
|
inplace_process(colors);
|
||||||
|
|
||||||
|
// return the computed colors
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageProcessor::setSize(const unsigned width, const unsigned height)
|
||||||
|
{
|
||||||
|
// Check if the existing buffer-image is already the correct dimensions
|
||||||
|
if (mBuffer && mBuffer->width() == width && mBuffer->height() == height)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up the old buffer and mapping
|
||||||
|
delete mImageToLeds;
|
||||||
|
delete mBuffer;
|
||||||
|
|
||||||
|
// Construct a new buffer and mapping
|
||||||
|
mBuffer = new RgbImage(width, height);
|
||||||
|
mImageToLeds = new ImageToLedsMap(*mBuffer, mLedString.leds());
|
||||||
|
}
|
||||||
|
|
||||||
|
RgbImage& ImageProcessor::image()
|
||||||
|
{
|
||||||
|
return *mBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageProcessor::inplace_process(std::vector<RgbColor>& ledColors)
|
||||||
|
{
|
||||||
|
// Determine the mean-colors of each led (using the existing mapping)
|
||||||
|
mImageToLeds->getMeanLedColor(ledColors);
|
||||||
|
}
|
21
libsrc/hyperion/ImageProcessorFactory.cpp
Normal file
21
libsrc/hyperion/ImageProcessorFactory.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
// Hyperion includes
|
||||||
|
#include <hyperion/ImageProcessorFactory.h>
|
||||||
|
#include <hyperion/ImageProcessor.h>
|
||||||
|
|
||||||
|
ImageProcessorFactory& ImageProcessorFactory::getInstance()
|
||||||
|
{
|
||||||
|
static ImageProcessorFactory instance;
|
||||||
|
// Return the singleton instance
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageProcessorFactory::init(const LedString& ledString)
|
||||||
|
{
|
||||||
|
_ledString = ledString;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageProcessor* ImageProcessorFactory::newImageProcessor() const
|
||||||
|
{
|
||||||
|
return new ImageProcessor(_ledString);
|
||||||
|
}
|
@ -3,14 +3,11 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
// hyperion includes
|
// hyperion includes
|
||||||
#include <hyperion/ImageToLedsMap.h>
|
#include "ImageToLedsMap.h"
|
||||||
|
|
||||||
ImageToLedsMap::ImageToLedsMap()
|
using namespace hyperion;
|
||||||
{
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageToLedsMap::createMapping(const RgbImage& image, const std::vector<Led>& leds)
|
ImageToLedsMap::ImageToLedsMap(const RgbImage& image, const std::vector<Led>& leds)
|
||||||
{
|
{
|
||||||
mColorsMap.resize(leds.size(), std::vector<const RgbColor*>());
|
mColorsMap.resize(leds.size(), std::vector<const RgbColor*>());
|
||||||
|
|
||||||
@ -46,6 +43,19 @@ std::vector<RgbColor> ImageToLedsMap::getMeanLedColor()
|
|||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageToLedsMap::getMeanLedColor(std::vector<RgbColor>& ledColors)
|
||||||
|
{
|
||||||
|
// Sanity check for the number of leds
|
||||||
|
assert(mColorsMap.size() == ledColors.size());
|
||||||
|
|
||||||
|
auto led = ledColors.begin();
|
||||||
|
for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors, ++led)
|
||||||
|
{
|
||||||
|
const RgbColor color = findMeanColor(*ledColors);
|
||||||
|
*led = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RgbColor ImageToLedsMap::findMeanColor(const std::vector<const RgbColor*>& colors)
|
RgbColor ImageToLedsMap::findMeanColor(const std::vector<const RgbColor*>& colors)
|
||||||
{
|
{
|
||||||
uint_fast16_t cummRed = 0;
|
uint_fast16_t cummRed = 0;
|
||||||
@ -64,27 +74,3 @@ RgbColor ImageToLedsMap::findMeanColor(const std::vector<const RgbColor*>& color
|
|||||||
|
|
||||||
return {avgRed, avgGreen, avgBlue};
|
return {avgRed, avgGreen, avgBlue};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<RgbColor> ImageToLedsMap::getMedianLedColor()
|
|
||||||
{
|
|
||||||
std::vector<RgbColor> ledColors;
|
|
||||||
for (std::vector<const RgbColor*>& colors : mColorsMap)
|
|
||||||
{
|
|
||||||
const RgbColor color = findMedianColor(colors);
|
|
||||||
ledColors.push_back(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ledColors;
|
|
||||||
}
|
|
||||||
|
|
||||||
RgbColor ImageToLedsMap::findMedianColor(std::vector<const RgbColor*>& colors)
|
|
||||||
{
|
|
||||||
std::sort(colors.begin(), colors.end(), [](const RgbColor* lhs, const RgbColor* rhs){ return lhs->red < rhs->red; });
|
|
||||||
const uint8_t red = colors.at(colors.size()/2)->red;
|
|
||||||
std::sort(colors.begin(), colors.end(), [](const RgbColor* lhs, const RgbColor* rhs){ return lhs->green < rhs->green; });
|
|
||||||
const uint8_t green = colors.at(colors.size()/2)->green;
|
|
||||||
std::sort(colors.begin(), colors.end(), [](const RgbColor* lhs, const RgbColor* rhs){ return lhs->blue < rhs->blue; });
|
|
||||||
const uint8_t blue = colors.at(colors.size()/2)->blue;
|
|
||||||
|
|
||||||
return {red, green, blue};
|
|
||||||
}
|
|
||||||
|
57
libsrc/hyperion/ImageToLedsMap.h
Normal file
57
libsrc/hyperion/ImageToLedsMap.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// hyperion-utils includes
|
||||||
|
#include <utils/RgbImage.h>
|
||||||
|
|
||||||
|
// hyperion includes
|
||||||
|
#include <hyperion/LedString.h>
|
||||||
|
|
||||||
|
namespace hyperion
|
||||||
|
{
|
||||||
|
|
||||||
|
class ImageToLedsMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an mapping from the colors in the image to each led based on the border
|
||||||
|
* definition given in the list of leds. The map holds pointers to the given image and its
|
||||||
|
* lifetime should never exceed that of the given image
|
||||||
|
*
|
||||||
|
* @param[in] image The RGB image
|
||||||
|
* @param[in] leds The list with led specifications
|
||||||
|
*/
|
||||||
|
ImageToLedsMap(const RgbImage& image, const std::vector<Led>& leds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the mean-color for each led using the mapping the image given
|
||||||
|
* at construction.
|
||||||
|
*
|
||||||
|
* @return ledColors The vector containing the output
|
||||||
|
*/
|
||||||
|
std::vector<RgbColor> getMeanLedColor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the mean-color for each led using the mapping the image given
|
||||||
|
* at construction.
|
||||||
|
*
|
||||||
|
* @param[out] ledColors The vector containing the output
|
||||||
|
*/
|
||||||
|
void getMeanLedColor(std::vector<RgbColor>& ledColors);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::vector<const RgbColor*> > mColorsMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the 'mean color' of the given list. This is the mean over each color-channel (red,
|
||||||
|
* green, blue)
|
||||||
|
*
|
||||||
|
* @param colors The list with colors
|
||||||
|
*
|
||||||
|
* @return The mean of the given list of colors (or black when empty)
|
||||||
|
*/
|
||||||
|
RgbColor findMeanColor(const std::vector<const RgbColor*>& colors);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace hyperion
|
@ -9,41 +9,6 @@
|
|||||||
// hyperion includes
|
// hyperion includes
|
||||||
#include <hyperion/LedString.h>
|
#include <hyperion/LedString.h>
|
||||||
|
|
||||||
LedString LedString::construct(const Json::Value& ledsConfig, const Json::Value& colorConfig)
|
|
||||||
{
|
|
||||||
LedString ledString;
|
|
||||||
|
|
||||||
const Json::Value& redConfig = colorConfig["red"];
|
|
||||||
const Json::Value& greenConfig = colorConfig["greem"];
|
|
||||||
const Json::Value& blueConfig = colorConfig["blue"];
|
|
||||||
|
|
||||||
ledString.red.gamma = redConfig["gamma"].asDouble();
|
|
||||||
ledString.red.adjust = redConfig["adjust"].asDouble();
|
|
||||||
ledString.red.blacklevel = redConfig["blacklevel"].asDouble();
|
|
||||||
|
|
||||||
ledString.green.gamma = greenConfig["gamma"].asDouble();
|
|
||||||
ledString.green.adjust = colorConfig["adjust"].asDouble();
|
|
||||||
ledString.green.blacklevel = colorConfig["blacklevel"].asDouble();
|
|
||||||
|
|
||||||
ledString.blue.gamma = blueConfig["gamma"].asDouble();
|
|
||||||
ledString.blue.adjust = blueConfig["adjust"].asDouble();
|
|
||||||
ledString.blue.blacklevel = blueConfig["blacklevel"].asDouble();
|
|
||||||
|
|
||||||
for (const Json::Value& ledConfig : ledsConfig)
|
|
||||||
{
|
|
||||||
Led led;
|
|
||||||
led.index = ledConfig["index"].asInt();
|
|
||||||
const Json::Value& hscanConfig = ledConfig["hscan"];
|
|
||||||
const Json::Value& vscanConfig = ledConfig["vscan"];
|
|
||||||
led.minX_frac = std::max(0.0, std::min(100.0, hscanConfig["minimum"].asDouble()))/100.0;
|
|
||||||
led.maxX_frac = std::max(0.0, std::min(100.0, hscanConfig["maximum"].asDouble()))/100.0;
|
|
||||||
led.minY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["maximum"].asDouble()))/100.0;
|
|
||||||
led.maxY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["minimum"].asDouble()))/100.0;
|
|
||||||
|
|
||||||
ledString.mLeds.push_back(led);
|
|
||||||
}
|
|
||||||
return ledString;
|
|
||||||
}
|
|
||||||
|
|
||||||
LedString::LedString()
|
LedString::LedString()
|
||||||
{
|
{
|
||||||
@ -54,6 +19,11 @@ LedString::~LedString()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Led>& LedString::leds()
|
||||||
|
{
|
||||||
|
return mLeds;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<Led>& LedString::leds() const
|
const std::vector<Led>& LedString::leds() const
|
||||||
{
|
{
|
||||||
return mLeds;
|
return mLeds;
|
||||||
|
94
libsrc/hyperion/PriorityMuxer.cpp
Normal file
94
libsrc/hyperion/PriorityMuxer.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
|
||||||
|
// STL includes
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
// Hyperion includes
|
||||||
|
#include <hyperion/PriorityMuxer.h>
|
||||||
|
|
||||||
|
PriorityMuxer::PriorityMuxer() :
|
||||||
|
mCurrentPriority(MAX_PRIORITY)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
PriorityMuxer::~PriorityMuxer()
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
int PriorityMuxer::getCurrentPriority() const
|
||||||
|
{
|
||||||
|
return mCurrentPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<int> PriorityMuxer::getPriorities() const
|
||||||
|
{
|
||||||
|
return mActiveInputs.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PriorityMuxer::hasPriority(const int priority) const
|
||||||
|
{
|
||||||
|
return mActiveInputs.contains(priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority) const
|
||||||
|
{
|
||||||
|
auto elemIt = mActiveInputs.find(priority);
|
||||||
|
if (elemIt == mActiveInputs.end())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("no such priority");
|
||||||
|
}
|
||||||
|
return elemIt.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriorityMuxer::setInput(const int priority, const std::vector<RgbColor>& ledColors, const int64_t timeoutTime_ms)
|
||||||
|
{
|
||||||
|
InputInfo& input = mActiveInputs[priority];
|
||||||
|
input.priority = priority;
|
||||||
|
input.timeoutTime_ms = timeoutTime_ms;
|
||||||
|
input.ledColors = ledColors;
|
||||||
|
|
||||||
|
mCurrentPriority = std::min(mCurrentPriority, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriorityMuxer::clearInput(const int priority)
|
||||||
|
{
|
||||||
|
mActiveInputs.remove(priority);
|
||||||
|
if (mCurrentPriority == priority)
|
||||||
|
{
|
||||||
|
if (mActiveInputs.empty())
|
||||||
|
{
|
||||||
|
mCurrentPriority = MAX_PRIORITY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QList<int> keys = mActiveInputs.keys();
|
||||||
|
mCurrentPriority = *std::min_element(keys.begin(), keys.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriorityMuxer::clearAll()
|
||||||
|
{
|
||||||
|
mActiveInputs.clear();
|
||||||
|
mCurrentPriority = MAX_PRIORITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriorityMuxer::setCurrentTime(const int64_t& now)
|
||||||
|
{
|
||||||
|
mCurrentPriority = MAX_PRIORITY;
|
||||||
|
|
||||||
|
for (auto infoIt = mActiveInputs.begin(); infoIt != mActiveInputs.end();)
|
||||||
|
{
|
||||||
|
if (infoIt->timeoutTime_ms != -1 && infoIt->timeoutTime_ms <= now)
|
||||||
|
{
|
||||||
|
infoIt = mActiveInputs.erase(infoIt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mCurrentPriority = std::min(mCurrentPriority, infoIt->priority);
|
||||||
|
++infoIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,12 @@
|
|||||||
add_executable(WriteConfig
|
add_executable(WriteConfig
|
||||||
WriteConfig.cpp)
|
WriteConfig.cpp)
|
||||||
|
|
||||||
|
add_executable(HyperionDispmanx
|
||||||
|
HyperionMain.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(HyperionDispmanx
|
||||||
|
hyperion)
|
||||||
|
|
||||||
add_executable(boblight-dispmanx
|
add_executable(boblight-dispmanx
|
||||||
boblight-dispmanx.cpp
|
boblight-dispmanx.cpp
|
||||||
flagmanager.h
|
flagmanager.h
|
||||||
@ -27,12 +33,12 @@ target_link_libraries(boblight-dispmanx
|
|||||||
bob2hyperion
|
bob2hyperion
|
||||||
${BCM_LIBRARIES})
|
${BCM_LIBRARIES})
|
||||||
|
|
||||||
add_executable(HyperionDispmanX
|
#add_executable(HyperionDispmanX
|
||||||
HyperionDispmanX.cpp)
|
# HyperionDispmanX.cpp)
|
||||||
|
|
||||||
target_link_libraries(HyperionDispmanX
|
#target_link_libraries(HyperionDispmanX
|
||||||
hyperion
|
# hyperion
|
||||||
${BCM_LIBRARIES})
|
# ${BCM_LIBRARIES})
|
||||||
|
|
||||||
|
|
||||||
# Find the libPNG
|
# Find the libPNG
|
||||||
|
@ -43,7 +43,7 @@ int main(int /*argc*/, char** /*argv*/)
|
|||||||
}
|
}
|
||||||
Hyperion hyperion(raspiConfig);
|
Hyperion hyperion(raspiConfig);
|
||||||
|
|
||||||
dispmanx_process(hyperion, sRunning);
|
// dispmanx_process(hyperion, sRunning);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
17
src/HyperionMain.cpp
Normal file
17
src/HyperionMain.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
// QT includes
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
// Hyperion includes
|
||||||
|
#include <hyperion/DispmanxWrapper.h>
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
QCoreApplication app(argc, argv);
|
||||||
|
|
||||||
|
|
||||||
|
DispmanxWrapper dispmanx;
|
||||||
|
dispmanx.start();
|
||||||
|
|
||||||
|
app.exec();
|
||||||
|
}
|
@ -144,10 +144,10 @@ int main(int argc, char** argv)
|
|||||||
FbWriter fbWriter;
|
FbWriter fbWriter;
|
||||||
|
|
||||||
Hyperion raspiLight(raspiConfig);
|
Hyperion raspiLight(raspiConfig);
|
||||||
raspiLight.setInputSize(image->width(), image->height());
|
// raspiLight.setInputSize(image->width(), image->height());
|
||||||
|
|
||||||
fbWriter.writeImage(*image);
|
fbWriter.writeImage(*image);
|
||||||
raspiLight(*image);
|
// raspiLight(*image);
|
||||||
|
|
||||||
sleep(5);
|
sleep(5);
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* boblight
|
* boblight
|
||||||
* Copyright (C) Bob 2009
|
* Copyright (C) Bob 2009
|
||||||
*
|
*
|
||||||
* boblight is free software: you can redistribute it and/or modify it
|
* boblight is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the
|
* under the terms of the GNU General Public License as published by the
|
||||||
* Free Software Foundation, either version 3 of the License, or
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* boblight is distributed in the hope that it will be useful, but
|
* boblight is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* See the GNU General Public License for more details.
|
* See the GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along
|
* You should have received a copy of the GNU General Public License along
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
@ -35,16 +35,16 @@ CArguments::CArguments(int argc, char** argv)
|
|||||||
|
|
||||||
if (m_argc == 0)
|
if (m_argc == 0)
|
||||||
{
|
{
|
||||||
m_argv = NULL;
|
m_argv = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_argv = new char*[m_argc];
|
m_argv = new char*[m_argc];
|
||||||
for (int i = 0; i < m_argc; i++)
|
for (int i = 0; i < m_argc; i++)
|
||||||
{
|
{
|
||||||
m_argv[i] = new char[strlen(argv[i]) + 1];
|
m_argv[i] = new char[strlen(argv[i]) + 1];
|
||||||
strcpy(m_argv[i], argv[i]);
|
strcpy(m_argv[i], argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,11 +53,11 @@ CArguments::~CArguments()
|
|||||||
{
|
{
|
||||||
if (m_argv)
|
if (m_argv)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_argc; i++)
|
for (int i = 0; i < m_argc; i++)
|
||||||
{
|
{
|
||||||
delete[] m_argv[i];
|
delete[] m_argv[i];
|
||||||
}
|
}
|
||||||
delete[] m_argv;
|
delete[] m_argv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,75 +87,75 @@ void CFlagManager::ParseFlags(int tempargc, char** tempargv)
|
|||||||
int c;
|
int c;
|
||||||
|
|
||||||
opterr = 0; //we don't want to print error messages
|
opterr = 0; //we don't want to print error messages
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, m_flags.c_str())) != -1)
|
while ((c = getopt(argc, argv, m_flags.c_str())) != -1)
|
||||||
{
|
{
|
||||||
if (c == 'p') //priority
|
if (c == 'p') //priority
|
||||||
{
|
{
|
||||||
option = optarg;
|
option = optarg;
|
||||||
if (!StrToInt(option, m_priority) || m_priority < 0 || m_priority > 255)
|
if (!StrToInt(option, m_priority) || m_priority < 0 || m_priority > 255)
|
||||||
{
|
{
|
||||||
throw string("Wrong option " + string(optarg) + " for argument -p");
|
throw string("Wrong option " + string(optarg) + " for argument -p");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (c == 's') //address[:port]
|
else if (c == 's') //address[:port]
|
||||||
{
|
{
|
||||||
option = optarg;
|
option = optarg;
|
||||||
//store address in string and set the char* to it
|
//store address in string and set the char* to it
|
||||||
m_straddress = option.substr(0, option.find(':'));
|
m_straddress = option.substr(0, option.find(':'));
|
||||||
m_address = m_straddress.c_str();
|
m_address = m_straddress.c_str();
|
||||||
|
|
||||||
if (option.find(':') != string::npos) //check if we have a port
|
if (option.find(':') != string::npos) //check if we have a port
|
||||||
{
|
{
|
||||||
option = option.substr(option.find(':') + 1);
|
option = option.substr(option.find(':') + 1);
|
||||||
string word;
|
string word;
|
||||||
if (!StrToInt(option, m_port) || m_port < 0 || m_port > 65535)
|
if (!StrToInt(option, m_port) || m_port < 0 || m_port > 65535)
|
||||||
{
|
{
|
||||||
throw string("Wrong option " + string(optarg) + " for argument -s");
|
throw string("Wrong option " + string(optarg) + " for argument -s");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (c == 'o') //option for libboblight
|
else if (c == 'o') //option for libboblight
|
||||||
{
|
{
|
||||||
m_options.push_back(optarg);
|
m_options.push_back(optarg);
|
||||||
}
|
}
|
||||||
else if (c == 'l') //list libboblight options
|
else if (c == 'l') //list libboblight options
|
||||||
{
|
{
|
||||||
m_printboblightoptions = true;
|
m_printboblightoptions = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (c == 'h') //print help message
|
else if (c == 'h') //print help message
|
||||||
{
|
{
|
||||||
m_printhelp = true;
|
m_printhelp = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (c == 'f')
|
else if (c == 'f')
|
||||||
{
|
{
|
||||||
m_fork = true;
|
m_fork = true;
|
||||||
}
|
}
|
||||||
else if (c == 'y')
|
else if (c == 'y')
|
||||||
{
|
{
|
||||||
if (!StrToBool(optarg, m_sync))
|
if (!StrToBool(optarg, m_sync))
|
||||||
{
|
{
|
||||||
throw string("Wrong value " + string(optarg) + " for sync mode");
|
throw string("Wrong value " + string(optarg) + " for sync mode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (c == '?') //unknown option
|
else if (c == '?') //unknown option
|
||||||
{
|
{
|
||||||
//check if we know this option, but expected an argument
|
//check if we know this option, but expected an argument
|
||||||
if (m_flags.find(ToString((char)optopt) + ":") != string::npos)
|
if (m_flags.find(ToString((char)optopt) + ":") != string::npos)
|
||||||
{
|
{
|
||||||
throw string("Option " + ToString((char)optopt) + "requires an argument");
|
throw string("Option " + ToString((char)optopt) + "requires an argument");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw string("Unkown option " + ToString((char)optopt));
|
throw string("Unkown option " + ToString((char)optopt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ParseFlagsExtended(argc, argv, c, optarg); //pass our argument to a derived class
|
ParseFlagsExtended(argc, argv, c, optarg); //pass our argument to a derived class
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PostGetopt(optind, argc, argv); //some postprocessing
|
PostGetopt(optind, argc, argv); //some postprocessing
|
||||||
@ -169,7 +169,7 @@ void CFlagManager::PrintBoblightOptions()
|
|||||||
|
|
||||||
for (int i = 0; i < nroptions; i++)
|
for (int i = 0; i < nroptions; i++)
|
||||||
{
|
{
|
||||||
cout << boblight_getoptiondescript(boblight, i) << "\n";
|
cout << boblight_getoptiondescript(boblight, i) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
boblight_destroy(boblight);
|
boblight_destroy(boblight);
|
||||||
@ -178,74 +178,74 @@ void CFlagManager::PrintBoblightOptions()
|
|||||||
void CFlagManager::ParseBoblightOptions(void* boblight)
|
void CFlagManager::ParseBoblightOptions(void* boblight)
|
||||||
{
|
{
|
||||||
int nrlights = boblight_getnrlights(boblight);
|
int nrlights = boblight_getnrlights(boblight);
|
||||||
|
|
||||||
for (int i = 0; i < m_options.size(); i++)
|
for (size_t i = 0; i < m_options.size(); i++)
|
||||||
{
|
{
|
||||||
string option = m_options[i];
|
string option = m_options[i];
|
||||||
string lightname;
|
string lightname;
|
||||||
string optionname;
|
string optionname;
|
||||||
string optionvalue;
|
string optionvalue;
|
||||||
int lightnr = -1;
|
int lightnr = -1;
|
||||||
|
|
||||||
//check if we have a lightname, otherwise we use all lights
|
//check if we have a lightname, otherwise we use all lights
|
||||||
if (option.find(':') != string::npos)
|
if (option.find(':') != string::npos)
|
||||||
{
|
{
|
||||||
lightname = option.substr(0, option.find(':'));
|
lightname = option.substr(0, option.find(':'));
|
||||||
if (option.find(':') == option.size() - 1) //check if : isn't the last char in the string
|
if (option.find(':') == option.size() - 1) //check if : isn't the last char in the string
|
||||||
{
|
{
|
||||||
throw string("wrong option \"" + option + "\", syntax is [light:]option=value");
|
throw string("wrong option \"" + option + "\", syntax is [light:]option=value");
|
||||||
}
|
}
|
||||||
option = option.substr(option.find(':') + 1); //shave off the lightname
|
option = option.substr(option.find(':') + 1); //shave off the lightname
|
||||||
|
|
||||||
//check which light this is
|
//check which light this is
|
||||||
bool lightfound = false;
|
bool lightfound = false;
|
||||||
for (int j = 0; j < nrlights; j++)
|
for (int j = 0; j < nrlights; j++)
|
||||||
{
|
{
|
||||||
if (lightname == boblight_getlightname(boblight, j))
|
if (lightname == boblight_getlightname(boblight, j))
|
||||||
{
|
{
|
||||||
lightfound = true;
|
lightfound = true;
|
||||||
lightnr = j;
|
lightnr = j;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!lightfound)
|
if (!lightfound)
|
||||||
{
|
{
|
||||||
throw string("light \"" + lightname + "\" used in option \"" + m_options[i] + "\" doesn't exist");
|
throw string("light \"" + lightname + "\" used in option \"" + m_options[i] + "\" doesn't exist");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if '=' exists and it's not at the end of the string
|
//check if '=' exists and it's not at the end of the string
|
||||||
if (option.find('=') == string::npos || option.find('=') == option.size() - 1)
|
if (option.find('=') == string::npos || option.find('=') == option.size() - 1)
|
||||||
{
|
{
|
||||||
throw string("wrong option \"" + option + "\", syntax is [light:]option=value");
|
throw string("wrong option \"" + option + "\", syntax is [light:]option=value");
|
||||||
}
|
}
|
||||||
|
|
||||||
optionname = option.substr(0, option.find('=')); //option name is everything before = (already shaved off the lightname here)
|
optionname = option.substr(0, option.find('=')); //option name is everything before = (already shaved off the lightname here)
|
||||||
optionvalue = option.substr(option.find('=') + 1); //value is everything after =
|
optionvalue = option.substr(option.find('=') + 1); //value is everything after =
|
||||||
|
|
||||||
option = optionname + " " + optionvalue; //libboblight wants syntax without =
|
option = optionname + " " + optionvalue; //libboblight wants syntax without =
|
||||||
|
|
||||||
//bitch if we can't set this option
|
//bitch if we can't set this option
|
||||||
if (!boblight_setoption(boblight, lightnr, option.c_str()))
|
if (!boblight_setoption(boblight, lightnr, option.c_str()))
|
||||||
{
|
{
|
||||||
throw string(boblight_geterror(boblight));
|
throw string(boblight_geterror(boblight));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFlagManager::SetVideoGamma()
|
bool CFlagManager::SetVideoGamma()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_options.size(); i++)
|
for (size_t i = 0; i < m_options.size(); i++)
|
||||||
{
|
{
|
||||||
string option = m_options[i];
|
string option = m_options[i];
|
||||||
if (option.find(':') != string::npos)
|
if (option.find(':') != string::npos)
|
||||||
option = option.substr(option.find(':') + 1); //shave off the lightname
|
option = option.substr(option.find(':') + 1); //shave off the lightname
|
||||||
|
|
||||||
if (option.find('=') != string::npos)
|
if (option.find('=') != string::npos)
|
||||||
{
|
{
|
||||||
if (option.substr(0, option.find('=')) == "gamma")
|
if (option.substr(0, option.find('=')) == "gamma")
|
||||||
return false; //gamma set by user, don't override
|
return false; //gamma set by user, don't override
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_options.push_back("gamma=" + ToString(VIDEOGAMMA));
|
m_options.push_back("gamma=" + ToString(VIDEOGAMMA));
|
||||||
|
42
src/misc.h
42
src/misc.h
@ -1,17 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* boblight
|
* boblight
|
||||||
* Copyright (C) Bob 2009
|
* Copyright (C) Bob 2009
|
||||||
*
|
*
|
||||||
* boblight is free software: you can redistribute it and/or modify it
|
* boblight is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the
|
* under the terms of the GNU General Public License as published by the
|
||||||
* Free Software Foundation, either version 3 of the License, or
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* boblight is distributed in the hope that it will be useful, but
|
* boblight is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* See the GNU General Public License for more details.
|
* See the GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along
|
* You should have received a copy of the GNU General Public License along
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
@ -96,15 +96,15 @@ inline A Round(B value)
|
|||||||
{
|
{
|
||||||
if (value == 0.0)
|
if (value == 0.0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (value > 0.0)
|
else if (value > 0.0)
|
||||||
{
|
{
|
||||||
return (A)(value + 0.5);
|
return (A)(value + 0.5);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return (A)(value - 0.5);
|
return (A)(value - 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ inline bool StrToInt(const std::string& data, int& value)
|
|||||||
|
|
||||||
inline bool StrToInt(const std::string& data, int64_t& value)
|
inline bool StrToInt(const std::string& data, int64_t& value)
|
||||||
{
|
{
|
||||||
return sscanf(data.c_str(), "%ld", &value) == 1;
|
return sscanf(data.c_str(), "%lld", &value) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool HexStrToInt(const std::string& data, int& value)
|
inline bool HexStrToInt(const std::string& data, int& value)
|
||||||
@ -145,7 +145,7 @@ inline bool HexStrToInt(const std::string& data, int& value)
|
|||||||
|
|
||||||
inline bool HexStrToInt(const std::string& data, int64_t& value)
|
inline bool HexStrToInt(const std::string& data, int64_t& value)
|
||||||
{
|
{
|
||||||
return sscanf(data.c_str(), "%x", &value) == 1;
|
return sscanf(data.c_str(), "%llx", &value) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool StrToFloat(const std::string& data, float& value)
|
inline bool StrToFloat(const std::string& data, float& value)
|
||||||
@ -163,26 +163,26 @@ inline bool StrToBool(const std::string& data, bool& value)
|
|||||||
std::string data2 = data;
|
std::string data2 = data;
|
||||||
std::string word;
|
std::string word;
|
||||||
if (!GetWord(data2, word))
|
if (!GetWord(data2, word))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (word == "1" || word == "true" || word == "on" || word == "yes")
|
if (word == "1" || word == "true" || word == "on" || word == "yes")
|
||||||
{
|
{
|
||||||
value = true;
|
value = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (word == "0" || word == "false" || word == "off" || word == "no")
|
else if (word == "0" || word == "false" || word == "off" || word == "no")
|
||||||
{
|
{
|
||||||
value = false;
|
value = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int ivalue;
|
int ivalue;
|
||||||
if (StrToInt(word, ivalue))
|
if (StrToInt(word, ivalue))
|
||||||
{
|
{
|
||||||
value = ivalue != 0;
|
value = ivalue != 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,93 +1,96 @@
|
|||||||
|
// STL includes
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include <hyperion/ColorTransform.h>
|
#include <../../libsrc/hyperion/ColorTransform.h>
|
||||||
|
|
||||||
|
using namespace hyperion;
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::cout << "Testing linear transform" << std::endl;
|
std::cout << "Testing linear transform" << std::endl;
|
||||||
ColorTransform t;
|
ColorTransform t;
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
uint8_t input = i;
|
uint8_t input = i;
|
||||||
uint8_t output = t.transform(input);
|
uint8_t output = t.transform(input);
|
||||||
uint8_t expected = input;
|
uint8_t expected = input;
|
||||||
|
|
||||||
if (output != expected)
|
if (output != expected)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
|
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
|
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::cout << "Testing threshold" << std::endl;
|
std::cout << "Testing threshold" << std::endl;
|
||||||
ColorTransform t(.10, 1.0, 0.0, 1.0);
|
ColorTransform t(.10, 1.0, 0.0, 1.0);
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
uint8_t input = i;
|
uint8_t input = i;
|
||||||
uint8_t output = t.transform(input);
|
uint8_t output = t.transform(input);
|
||||||
uint8_t expected = ((i/255.0) < t.getThreshold() ? 0 : output);
|
uint8_t expected = ((i/255.0) < t.getThreshold() ? 0 : output);
|
||||||
|
|
||||||
if (output != expected)
|
if (output != expected)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
|
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
|
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::cout << "Testing blacklevel and whitelevel" << std::endl;
|
std::cout << "Testing blacklevel and whitelevel" << std::endl;
|
||||||
ColorTransform t(0, 1.0, 0.2, 0.8);
|
ColorTransform t(0, 1.0, 0.2, 0.8);
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
uint8_t input = i;
|
uint8_t input = i;
|
||||||
uint8_t output = t.transform(input);
|
uint8_t output = t.transform(input);
|
||||||
uint8_t expected = (uint8_t)(input * (t.getWhitelevel()-t.getBlacklevel()) + 255 * t.getBlacklevel());
|
uint8_t expected = (uint8_t)(input * (t.getWhitelevel()-t.getBlacklevel()) + 255 * t.getBlacklevel());
|
||||||
|
|
||||||
if (output != expected)
|
if (output != expected)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
|
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
|
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::cout << "Testing gamma" << std::endl;
|
std::cout << "Testing gamma" << std::endl;
|
||||||
ColorTransform t(0, 2.0, 0.0, 1.0);
|
ColorTransform t(0, 2.0, 0.0, 1.0);
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
uint8_t input = i;
|
uint8_t input = i;
|
||||||
uint8_t output = t.transform(input);
|
uint8_t output = t.transform(input);
|
||||||
uint8_t expected = (uint8_t)(255 * std::pow(i / 255.0, 2));
|
uint8_t expected = (uint8_t)(255 * std::pow(i / 255.0, 2));
|
||||||
|
|
||||||
if (output != expected)
|
if (output != expected)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
|
std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
|
std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ int main()
|
|||||||
double redGamma = redConfig["gamma"].asDouble();
|
double redGamma = redConfig["gamma"].asDouble();
|
||||||
std::cout << "RED GAMMA = " << redGamma << std::endl;
|
std::cout << "RED GAMMA = " << redGamma << std::endl;
|
||||||
std::cout << "RED GAMMA = " << colorConfig["red.gamma"].asDouble() << std::endl;
|
std::cout << "RED GAMMA = " << colorConfig["red.gamma"].asDouble() << std::endl;
|
||||||
LedString ledString = LedString::construct(ledConfig, colorConfig);
|
// LedString ledString = LedString::construct(ledConfig, colorConfig);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user