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:
T. van der Zwan 2013-08-14 15:02:09 +00:00
parent e8b97dcb01
commit b457c444f6
11 changed files with 136 additions and 94 deletions

View File

@ -6,6 +6,7 @@
// Utils includes // Utils includes
#include <utils/RgbColor.h> #include <utils/RgbColor.h>
#include <utils/RgbImage.h>
// Forward class declaration // Forward class declaration
class DispmanxFrameGrabber; class DispmanxFrameGrabber;
@ -42,6 +43,7 @@ private:
QTimer _timer; QTimer _timer;
RgbImage _image;
DispmanxFrameGrabber * _frameGrabber; DispmanxFrameGrabber * _frameGrabber;
ImageProcessor * _processor; ImageProcessor * _processor;

View File

@ -1,6 +1,10 @@
#pragma once #pragma once
// QT includes
#include <QObject>
#include <QTimer>
// hyperion-utils includes // hyperion-utils includes
#include <utils/RgbImage.h> #include <utils/RgbImage.h>
@ -13,8 +17,9 @@
namespace hyperion { class ColorTransform; } namespace hyperion { class ColorTransform; }
class Hyperion class Hyperion : public QObject
{ {
Q_OBJECT
public: public:
Hyperion(const Json::Value& jsonConfig); Hyperion(const Json::Value& jsonConfig);
@ -24,6 +29,9 @@ public:
void setValue(int priority, std::vector<RgbColor> &ledColors, const int timeout_ms); void setValue(int priority, std::vector<RgbColor> &ledColors, const int timeout_ms);
private slots:
void update();
private: private:
void applyTransform(std::vector<RgbColor>& colors) const; void applyTransform(std::vector<RgbColor>& colors) const;
@ -36,4 +44,6 @@ private:
hyperion::ColorTransform* mBlueTransform; hyperion::ColorTransform* mBlueTransform;
LedDevice* mDevice; LedDevice* mDevice;
QTimer _timer;
}; };

View File

@ -21,18 +21,6 @@ class ImageProcessor
public: public:
~ImageProcessor(); ~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 * Specifies the width and height of 'incomming' images. This will resize the buffer-image to
* match the given size. * match the given size.
@ -44,19 +32,21 @@ public:
void setSize(const unsigned width, const unsigned height); void setSize(const unsigned width, const unsigned height);
/** /**
* Returns a reference of the underlying image-buffer. This can be used to write data directly * Processes the image to a list of led colors. This will update the size of the buffer-image
* into the buffer, avoiding a copy inside the process method. * 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. * Determines the led colors of the image in the buffer.
* *
* @param[out] ledColors The color value per led * @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: private:
friend class ImageProcessorFactory; friend class ImageProcessorFactory;
@ -66,7 +56,6 @@ private:
private: private:
const LedString mLedString; const LedString mLedString;
RgbImage *mBuffer;
hyperion::ImageToLedsMap* mImageToLeds; hyperion::ImageToLedsMap* mImageToLeds;
}; };

View File

@ -18,9 +18,9 @@ namespace Json { class Value; }
* <pre> * <pre>
* |--------------------image--| * |--------------------image--|
* | minX maxX | * | minX maxX |
* | |-----|maxY |
* | | | |
* | |-----|minY | * | |-----|minY |
* | | | |
* | |-----|maxY |
* | | * | |
* | | * | |
* | | * | |

View File

@ -45,6 +45,10 @@ public:
return mColors; return mColors;
} }
const RgbColor* memptr() const
{
return mColors;
}
private: private:
inline unsigned toIndex(const unsigned x, const unsigned y) const inline unsigned toIndex(const unsigned x, const unsigned y) const

View File

@ -9,12 +9,12 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion)
# Group the headers that go through the MOC compiler # Group the headers that go through the MOC compiler
SET(Hyperion_QT_HEADERS SET(Hyperion_QT_HEADERS
${CURRENT_HEADER_DIR}/Hyperion.h
${CURRENT_HEADER_DIR}/DispmanxWrapper.h ${CURRENT_HEADER_DIR}/DispmanxWrapper.h
) )
SET(Hyperion_HEADERS SET(Hyperion_HEADERS
${CURRENT_HEADER_DIR}/LedString.h ${CURRENT_HEADER_DIR}/LedString.h
${CURRENT_HEADER_DIR}/Hyperion.h
${CURRENT_HEADER_DIR}/LedDevice.h ${CURRENT_HEADER_DIR}/LedDevice.h
${CURRENT_HEADER_DIR}/ImageProcessor.h ${CURRENT_HEADER_DIR}/ImageProcessor.h
${CURRENT_HEADER_DIR}/ImageProcessorFactory.h ${CURRENT_HEADER_DIR}/ImageProcessorFactory.h

View File

@ -16,6 +16,7 @@ DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHe
_updateInterval_ms(1000/updateRate_Hz), _updateInterval_ms(1000/updateRate_Hz),
_timeout_ms(2 * _updateInterval_ms), _timeout_ms(2 * _updateInterval_ms),
_timer(), _timer(),
_image(grabWidth, grabHeight),
_frameGrabber(new DispmanxFrameGrabber(grabWidth, grabHeight)), _frameGrabber(new DispmanxFrameGrabber(grabWidth, grabHeight)),
_processor(ImageProcessorFactory::getInstance().newImageProcessor()), _processor(ImageProcessorFactory::getInstance().newImageProcessor()),
_ledColors(hyperion->getLedCount(), RgbColor::BLACK), _ledColors(hyperion->getLedCount(), RgbColor::BLACK),
@ -46,13 +47,10 @@ void DispmanxWrapper::start()
void DispmanxWrapper::action() void DispmanxWrapper::action()
{ {
// Obtain reference of the buffer-image used by the processor
RgbImage & image = _processor->image();
// Grab frame into the allocated 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; const int _priority = 100;
_hyperion->setValue(_priority, _ledColors, _timeout_ms); _hyperion->setValue(_priority, _ledColors, _timeout_ms);

View File

@ -2,6 +2,8 @@
// Syslog include // Syslog include
#include <syslog.h> #include <syslog.h>
#include <QDateTime>
// JsonSchema include // JsonSchema include
#include <utils/jsonschema/JsonFactory.h> #include <utils/jsonschema/JsonFactory.h>
@ -72,9 +74,12 @@ Hyperion::Hyperion(const Json::Value &jsonConfig) :
mRedTransform( createColorTransform(jsonConfig["color"]["red"])), mRedTransform( createColorTransform(jsonConfig["color"]["red"])),
mGreenTransform(createColorTransform(jsonConfig["color"]["green"])), mGreenTransform(createColorTransform(jsonConfig["color"]["green"])),
mBlueTransform( createColorTransform(jsonConfig["color"]["blue"])), 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); 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()) 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);
} }
} }

View File

@ -8,7 +8,6 @@ using namespace hyperion;
ImageProcessor::ImageProcessor(const LedString& ledString) : ImageProcessor::ImageProcessor(const LedString& ledString) :
mLedString(ledString), mLedString(ledString),
mBuffer(nullptr),
mImageToLeds(nullptr) mImageToLeds(nullptr)
{ {
// empty // empty
@ -17,7 +16,21 @@ ImageProcessor::ImageProcessor(const LedString& ledString) :
ImageProcessor::~ImageProcessor() ImageProcessor::~ImageProcessor()
{ {
delete mImageToLeds; 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) 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 // Ensure that the buffer-image is the proper size
setSize(image.width(), image.height()); 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 // Create a result vector and call the 'in place' functionl
std::vector<RgbColor> colors(mLedString.leds().size(), RgbColor::BLACK); std::vector<RgbColor> colors = mImageToLeds->getMeanLedColor(image);
inplace_process(colors);
// return the computed colors // return the computed colors
return colors; return colors;
} }
void ImageProcessor::setSize(const unsigned width, const unsigned height) void ImageProcessor::process(const RgbImage& image, std::vector<RgbColor>& ledColors)
{
// 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) // Determine the mean-colors of each led (using the existing mapping)
mImageToLeds->getMeanLedColor(ledColors); mImageToLeds->getMeanLedColor(image, ledColors);
} }

View File

@ -7,43 +7,51 @@
using namespace hyperion; 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 (const Led& led : leds)
for (auto led = leds.begin(); ledColors != mColorsMap.end() && led != leds.end(); ++ledColors, ++led)
{ {
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); std::vector<unsigned> ledColors;
const unsigned maxX_idx = unsigned(image.width() * led->maxX_frac); for (unsigned y = minY_idx; y<=maxY_idx && y<height; ++y)
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)
{ {
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; return _width;
for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors) }
{
const RgbColor color = findMeanColor(*ledColors);
colors.push_back(color);
}
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; 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 // Sanity check for the number of leds
assert(mColorsMap.size() == ledColors.size()); assert(mColorsMap.size() == ledColors.size());
@ -51,21 +59,22 @@ void ImageToLedsMap::getMeanLedColor(std::vector<RgbColor>& ledColors)
auto led = ledColors.begin(); auto led = ledColors.begin();
for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors, ++led) for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors, ++led)
{ {
const RgbColor color = findMeanColor(*ledColors); const RgbColor color = calcMeanColor(image, *ledColors);
*led = color; *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 cummRed = 0;
uint_fast16_t cummGreen = 0; uint_fast16_t cummGreen = 0;
uint_fast16_t cummBlue = 0; uint_fast16_t cummBlue = 0;
for (const RgbColor* color : colors) for (const unsigned colorOffset : colors)
{ {
cummRed += color->red; const RgbColor& color = image.memptr()[colorOffset];
cummGreen += color->green; cummRed += color.red;
cummBlue += color->blue; cummGreen += color.green;
cummBlue += color.blue;
} }
const uint8_t avgRed = uint8_t(cummRed/colors.size()); const uint8_t avgRed = uint8_t(cummRed/colors.size());

View File

@ -22,7 +22,11 @@ public:
* @param[in] image The RGB image * @param[in] image The RGB image
* @param[in] leds The list with led specifications * @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 * 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 * @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 * 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 * @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: 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, * 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) * @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 } // end namespace hyperion