mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Changed the image-to-leds map by using offset-pointing.
Moved the image-buffer from processor to dispmanx-wrapper. Added timeout handling to Hyperion.
This commit is contained in:
parent
e8b97dcb01
commit
b457c444f6
@ -6,6 +6,7 @@
|
||||
|
||||
// Utils includes
|
||||
#include <utils/RgbColor.h>
|
||||
#include <utils/RgbImage.h>
|
||||
|
||||
// Forward class declaration
|
||||
class DispmanxFrameGrabber;
|
||||
@ -42,6 +43,7 @@ private:
|
||||
|
||||
QTimer _timer;
|
||||
|
||||
RgbImage _image;
|
||||
DispmanxFrameGrabber * _frameGrabber;
|
||||
ImageProcessor * _processor;
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// QT includes
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
// hyperion-utils includes
|
||||
#include <utils/RgbImage.h>
|
||||
|
||||
@ -13,8 +17,9 @@
|
||||
namespace hyperion { class ColorTransform; }
|
||||
|
||||
|
||||
class Hyperion
|
||||
class Hyperion : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Hyperion(const Json::Value& jsonConfig);
|
||||
|
||||
@ -24,6 +29,9 @@ public:
|
||||
|
||||
void setValue(int priority, std::vector<RgbColor> &ledColors, const int timeout_ms);
|
||||
|
||||
private slots:
|
||||
void update();
|
||||
|
||||
private:
|
||||
void applyTransform(std::vector<RgbColor>& colors) const;
|
||||
|
||||
@ -36,4 +44,6 @@ private:
|
||||
hyperion::ColorTransform* mBlueTransform;
|
||||
|
||||
LedDevice* mDevice;
|
||||
|
||||
QTimer _timer;
|
||||
};
|
||||
|
@ -21,18 +21,6 @@ class ImageProcessor
|
||||
public:
|
||||
~ImageProcessor();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -44,19 +32,21 @@ public:
|
||||
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.
|
||||
* 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.
|
||||
*
|
||||
* @return The reference of the underlying image-buffer.
|
||||
* @param[in] image The image to translate to led values
|
||||
*
|
||||
* @return The color value per led
|
||||
*/
|
||||
RgbImage& image();
|
||||
std::vector<RgbColor> process(const 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);
|
||||
void process(const RgbImage& image, std::vector<RgbColor>& ledColors);
|
||||
|
||||
private:
|
||||
friend class ImageProcessorFactory;
|
||||
@ -66,7 +56,6 @@ private:
|
||||
private:
|
||||
const LedString mLedString;
|
||||
|
||||
RgbImage *mBuffer;
|
||||
hyperion::ImageToLedsMap* mImageToLeds;
|
||||
};
|
||||
|
||||
|
@ -18,9 +18,9 @@ namespace Json { class Value; }
|
||||
* <pre>
|
||||
* |--------------------image--|
|
||||
* | minX maxX |
|
||||
* | |-----|maxY |
|
||||
* | | | |
|
||||
* | |-----|minY |
|
||||
* | | | |
|
||||
* | |-----|maxY |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
|
@ -45,6 +45,10 @@ public:
|
||||
return mColors;
|
||||
}
|
||||
|
||||
const RgbColor* memptr() const
|
||||
{
|
||||
return mColors;
|
||||
}
|
||||
private:
|
||||
|
||||
inline unsigned toIndex(const unsigned x, const unsigned y) const
|
||||
|
@ -9,12 +9,12 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion)
|
||||
|
||||
# Group the headers that go through the MOC compiler
|
||||
SET(Hyperion_QT_HEADERS
|
||||
${CURRENT_HEADER_DIR}/Hyperion.h
|
||||
${CURRENT_HEADER_DIR}/DispmanxWrapper.h
|
||||
)
|
||||
|
||||
SET(Hyperion_HEADERS
|
||||
${CURRENT_HEADER_DIR}/LedString.h
|
||||
${CURRENT_HEADER_DIR}/Hyperion.h
|
||||
${CURRENT_HEADER_DIR}/LedDevice.h
|
||||
${CURRENT_HEADER_DIR}/ImageProcessor.h
|
||||
${CURRENT_HEADER_DIR}/ImageProcessorFactory.h
|
||||
|
@ -16,6 +16,7 @@ DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHe
|
||||
_updateInterval_ms(1000/updateRate_Hz),
|
||||
_timeout_ms(2 * _updateInterval_ms),
|
||||
_timer(),
|
||||
_image(grabWidth, grabHeight),
|
||||
_frameGrabber(new DispmanxFrameGrabber(grabWidth, grabHeight)),
|
||||
_processor(ImageProcessorFactory::getInstance().newImageProcessor()),
|
||||
_ledColors(hyperion->getLedCount(), RgbColor::BLACK),
|
||||
@ -46,13 +47,10 @@ void DispmanxWrapper::start()
|
||||
|
||||
void DispmanxWrapper::action()
|
||||
{
|
||||
// Obtain reference of the buffer-image used by the processor
|
||||
RgbImage & image = _processor->image();
|
||||
|
||||
// Grab frame into the allocated image
|
||||
_frameGrabber->grabFrame(image);
|
||||
_frameGrabber->grabFrame(_image);
|
||||
|
||||
_processor->inplace_process(_ledColors);
|
||||
_processor->process(_image, _ledColors);
|
||||
|
||||
const int _priority = 100;
|
||||
_hyperion->setValue(_priority, _ledColors, _timeout_ms);
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Syslog include
|
||||
#include <syslog.h>
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
// JsonSchema include
|
||||
#include <utils/jsonschema/JsonFactory.h>
|
||||
|
||||
@ -72,9 +74,12 @@ Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
||||
mRedTransform( createColorTransform(jsonConfig["color"]["red"])),
|
||||
mGreenTransform(createColorTransform(jsonConfig["color"]["green"])),
|
||||
mBlueTransform( createColorTransform(jsonConfig["color"]["blue"])),
|
||||
mDevice(constructDevice(jsonConfig["device"]))
|
||||
mDevice(constructDevice(jsonConfig["device"])),
|
||||
_timer()
|
||||
{
|
||||
// empty
|
||||
_timer.setSingleShot(true);
|
||||
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -104,10 +109,42 @@ void Hyperion::setValue(int priority, std::vector<RgbColor>& ledColors, const in
|
||||
color.blue = mBlueTransform->transform(color.blue);
|
||||
}
|
||||
|
||||
mMuxer.setInput(priority, ledColors);
|
||||
if (timeout_ms > 0)
|
||||
{
|
||||
const uint64_t timeoutTime = QDateTime::currentMSecsSinceEpoch() + timeout_ms;
|
||||
mMuxer.setInput(priority, ledColors, timeoutTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
mMuxer.setInput(priority, ledColors);
|
||||
}
|
||||
|
||||
if (priority == mMuxer.getCurrentPriority())
|
||||
{
|
||||
mDevice->write(ledColors);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void Hyperion::update()
|
||||
{
|
||||
// Update the muxer, cleaning obsolete priorities
|
||||
mMuxer.setCurrentTime(QDateTime::currentMSecsSinceEpoch());
|
||||
|
||||
// Obtain the current priority channel
|
||||
int priority = mMuxer.getCurrentPriority();
|
||||
const PriorityMuxer::InputInfo & priorityInfo = mMuxer.getInputInfo(priority);
|
||||
|
||||
// Write the data to the device
|
||||
mDevice->write(priorityInfo.ledColors);
|
||||
|
||||
// Start the timeout-timer
|
||||
if (priorityInfo.timeoutTime_ms == -1)
|
||||
{
|
||||
_timer.stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
int timeout_ms = std::max(0, int(priorityInfo.timeoutTime_ms - QDateTime::currentMSecsSinceEpoch()));
|
||||
_timer.start(timeout_ms);
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ using namespace hyperion;
|
||||
|
||||
ImageProcessor::ImageProcessor(const LedString& ledString) :
|
||||
mLedString(ledString),
|
||||
mBuffer(nullptr),
|
||||
mImageToLeds(nullptr)
|
||||
{
|
||||
// empty
|
||||
@ -17,7 +16,21 @@ ImageProcessor::ImageProcessor(const LedString& ledString) :
|
||||
ImageProcessor::~ImageProcessor()
|
||||
{
|
||||
delete mImageToLeds;
|
||||
delete mBuffer;
|
||||
}
|
||||
|
||||
void ImageProcessor::setSize(const unsigned width, const unsigned height)
|
||||
{
|
||||
// Check if the existing buffer-image is already the correct dimensions
|
||||
if (mImageToLeds && mImageToLeds->width() == width && mImageToLeds->height() == height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up the old buffer and mapping
|
||||
delete mImageToLeds;
|
||||
|
||||
// Construct a new buffer and mapping
|
||||
mImageToLeds = new ImageToLedsMap(width, height, mLedString.leds());
|
||||
}
|
||||
|
||||
std::vector<RgbColor> ImageProcessor::process(const RgbImage& image)
|
||||
@ -25,41 +38,15 @@ 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);
|
||||
std::vector<RgbColor> colors = mImageToLeds->getMeanLedColor(image);
|
||||
|
||||
// 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)
|
||||
void ImageProcessor::process(const RgbImage& image, std::vector<RgbColor>& ledColors)
|
||||
{
|
||||
// Determine the mean-colors of each led (using the existing mapping)
|
||||
mImageToLeds->getMeanLedColor(ledColors);
|
||||
mImageToLeds->getMeanLedColor(image, ledColors);
|
||||
}
|
||||
|
@ -7,43 +7,51 @@
|
||||
|
||||
using namespace hyperion;
|
||||
|
||||
ImageToLedsMap::ImageToLedsMap(const RgbImage& image, const std::vector<Led>& leds)
|
||||
ImageToLedsMap::ImageToLedsMap(const unsigned width, const unsigned height, const std::vector<Led>& leds) :
|
||||
_width(width),
|
||||
_height(height),
|
||||
mColorsMap()
|
||||
{
|
||||
mColorsMap.resize(leds.size(), std::vector<const RgbColor*>());
|
||||
// Reserve enough space in the map for the leds
|
||||
mColorsMap.reserve(leds.size());
|
||||
|
||||
auto ledColors = mColorsMap.begin();
|
||||
for (auto led = leds.begin(); ledColors != mColorsMap.end() && led != leds.end(); ++ledColors, ++led)
|
||||
for (const Led& led : leds)
|
||||
{
|
||||
ledColors->clear();
|
||||
const unsigned minX_idx = unsigned(width * led.minX_frac);
|
||||
const unsigned maxX_idx = unsigned(width * led.maxX_frac);
|
||||
const unsigned minY_idx = unsigned(height * led.minY_frac);
|
||||
const unsigned maxY_idx = unsigned(height * led.maxY_frac);
|
||||
|
||||
const unsigned minX_idx = unsigned(image.width() * led->minX_frac);
|
||||
const unsigned maxX_idx = unsigned(image.width() * led->maxX_frac);
|
||||
const unsigned minY_idx = unsigned(image.height() * led->minY_frac);
|
||||
const unsigned maxY_idx = unsigned(image.height() * led->maxY_frac);
|
||||
|
||||
for (unsigned y = minY_idx; y<=maxY_idx && y<image.height(); ++y)
|
||||
std::vector<unsigned> ledColors;
|
||||
for (unsigned y = minY_idx; y<=maxY_idx && y<height; ++y)
|
||||
{
|
||||
for (unsigned x = minX_idx; x<=maxX_idx && x<image.width(); ++x)
|
||||
for (unsigned x = minX_idx; x<=maxX_idx && x<width; ++x)
|
||||
{
|
||||
ledColors->push_back(&image(x,y));
|
||||
ledColors.push_back(y*width + x);
|
||||
}
|
||||
}
|
||||
mColorsMap.push_back(ledColors);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<RgbColor> ImageToLedsMap::getMeanLedColor()
|
||||
unsigned ImageToLedsMap::width() const
|
||||
{
|
||||
std::vector<RgbColor> colors;
|
||||
for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors)
|
||||
{
|
||||
const RgbColor color = findMeanColor(*ledColors);
|
||||
colors.push_back(color);
|
||||
}
|
||||
return _width;
|
||||
}
|
||||
|
||||
unsigned ImageToLedsMap::height() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
std::vector<RgbColor> ImageToLedsMap::getMeanLedColor(const RgbImage & image) const
|
||||
{
|
||||
std::vector<RgbColor> colors(mColorsMap.size(), RgbColor::BLACK);
|
||||
getMeanLedColor(image, colors);
|
||||
return colors;
|
||||
}
|
||||
|
||||
void ImageToLedsMap::getMeanLedColor(std::vector<RgbColor>& ledColors)
|
||||
void ImageToLedsMap::getMeanLedColor(const RgbImage & image, std::vector<RgbColor> & ledColors) const
|
||||
{
|
||||
// Sanity check for the number of leds
|
||||
assert(mColorsMap.size() == ledColors.size());
|
||||
@ -51,21 +59,22 @@ void ImageToLedsMap::getMeanLedColor(std::vector<RgbColor>& ledColors)
|
||||
auto led = ledColors.begin();
|
||||
for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors, ++led)
|
||||
{
|
||||
const RgbColor color = findMeanColor(*ledColors);
|
||||
const RgbColor color = calcMeanColor(image, *ledColors);
|
||||
*led = color;
|
||||
}
|
||||
}
|
||||
|
||||
RgbColor ImageToLedsMap::findMeanColor(const std::vector<const RgbColor*>& colors)
|
||||
RgbColor ImageToLedsMap::calcMeanColor(const RgbImage & image, const std::vector<unsigned> & colors) const
|
||||
{
|
||||
uint_fast16_t cummRed = 0;
|
||||
uint_fast16_t cummGreen = 0;
|
||||
uint_fast16_t cummBlue = 0;
|
||||
for (const RgbColor* color : colors)
|
||||
for (const unsigned colorOffset : colors)
|
||||
{
|
||||
cummRed += color->red;
|
||||
cummGreen += color->green;
|
||||
cummBlue += color->blue;
|
||||
const RgbColor& color = image.memptr()[colorOffset];
|
||||
cummRed += color.red;
|
||||
cummGreen += color.green;
|
||||
cummBlue += color.blue;
|
||||
}
|
||||
|
||||
const uint8_t avgRed = uint8_t(cummRed/colors.size());
|
||||
|
@ -22,7 +22,11 @@ public:
|
||||
* @param[in] image The RGB image
|
||||
* @param[in] leds The list with led specifications
|
||||
*/
|
||||
ImageToLedsMap(const RgbImage& image, const std::vector<Led>& leds);
|
||||
ImageToLedsMap(const unsigned width, const unsigned height, const std::vector<Led> & leds);
|
||||
|
||||
unsigned width() const;
|
||||
|
||||
unsigned height() const;
|
||||
|
||||
/**
|
||||
* Determines the mean-color for each led using the mapping the image given
|
||||
@ -30,7 +34,7 @@ public:
|
||||
*
|
||||
* @return ledColors The vector containing the output
|
||||
*/
|
||||
std::vector<RgbColor> getMeanLedColor();
|
||||
std::vector<RgbColor> getMeanLedColor(const RgbImage & image) const;
|
||||
|
||||
/**
|
||||
* Determines the mean-color for each led using the mapping the image given
|
||||
@ -38,10 +42,12 @@ public:
|
||||
*
|
||||
* @param[out] ledColors The vector containing the output
|
||||
*/
|
||||
void getMeanLedColor(std::vector<RgbColor>& ledColors);
|
||||
void getMeanLedColor(const RgbImage & image, std::vector<RgbColor> & ledColors) const;
|
||||
|
||||
private:
|
||||
std::vector<std::vector<const RgbColor*> > mColorsMap;
|
||||
const unsigned _width;
|
||||
const unsigned _height;
|
||||
std::vector<std::vector<unsigned> > mColorsMap;
|
||||
|
||||
/**
|
||||
* Finds the 'mean color' of the given list. This is the mean over each color-channel (red,
|
||||
@ -51,7 +57,7 @@ private:
|
||||
*
|
||||
* @return The mean of the given list of colors (or black when empty)
|
||||
*/
|
||||
RgbColor findMeanColor(const std::vector<const RgbColor*>& colors);
|
||||
RgbColor calcMeanColor(const RgbImage & image, const std::vector<unsigned> & colors) const;
|
||||
};
|
||||
|
||||
} // end namespace hyperion
|
||||
|
Loading…
Reference in New Issue
Block a user