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

View File

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

View File

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

View File

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

View File

@ -45,6 +45,10 @@ public:
return mColors;
}
const RgbColor* memptr() const
{
return mColors;
}
private:
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
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

View File

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

View File

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

View File

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

View File

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

View File

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