From b457c444f62bd39aa57eee42f49e4a7fd01d5a93 Mon Sep 17 00:00:00 2001 From: "T. van der Zwan" Date: Wed, 14 Aug 2013 15:02:09 +0000 Subject: [PATCH] Changed the image-to-leds map by using offset-pointing. Moved the image-buffer from processor to dispmanx-wrapper. Added timeout handling to Hyperion. --- include/hyperion/DispmanxWrapper.h | 2 + include/hyperion/Hyperion.h | 12 +++++- include/hyperion/ImageProcessor.h | 25 ++++-------- include/hyperion/LedString.h | 4 +- include/utils/RgbImage.h | 4 ++ libsrc/hyperion/CMakeLists.txt | 2 +- libsrc/hyperion/DispmanxWrapper.cpp | 8 ++-- libsrc/hyperion/Hyperion.cpp | 45 +++++++++++++++++++-- libsrc/hyperion/ImageProcessor.cpp | 49 +++++++++------------- libsrc/hyperion/ImageToLedsMap.cpp | 63 ++++++++++++++++------------- libsrc/hyperion/ImageToLedsMap.h | 16 +++++--- 11 files changed, 136 insertions(+), 94 deletions(-) diff --git a/include/hyperion/DispmanxWrapper.h b/include/hyperion/DispmanxWrapper.h index 75f2bf1f..18b6370b 100644 --- a/include/hyperion/DispmanxWrapper.h +++ b/include/hyperion/DispmanxWrapper.h @@ -6,6 +6,7 @@ // Utils includes #include +#include // Forward class declaration class DispmanxFrameGrabber; @@ -42,6 +43,7 @@ private: QTimer _timer; + RgbImage _image; DispmanxFrameGrabber * _frameGrabber; ImageProcessor * _processor; diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 2455d5d0..2ec33f15 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -1,6 +1,10 @@ #pragma once +// QT includes +#include +#include + // hyperion-utils includes #include @@ -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 &ledColors, const int timeout_ms); +private slots: + void update(); + private: void applyTransform(std::vector& colors) const; @@ -36,4 +44,6 @@ private: hyperion::ColorTransform* mBlueTransform; LedDevice* mDevice; + + QTimer _timer; }; diff --git a/include/hyperion/ImageProcessor.h b/include/hyperion/ImageProcessor.h index 7ee06006..46e13864 100644 --- a/include/hyperion/ImageProcessor.h +++ b/include/hyperion/ImageProcessor.h @@ -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 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 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& ledColors); + void process(const RgbImage& image, std::vector& ledColors); private: friend class ImageProcessorFactory; @@ -66,7 +56,6 @@ private: private: const LedString mLedString; - RgbImage *mBuffer; hyperion::ImageToLedsMap* mImageToLeds; }; diff --git a/include/hyperion/LedString.h b/include/hyperion/LedString.h index cc4962ff..030dd11f 100644 --- a/include/hyperion/LedString.h +++ b/include/hyperion/LedString.h @@ -18,9 +18,9 @@ namespace Json { class Value; } *
  * |--------------------image--|
  * | minX  maxX                |
- * |  |-----|maxY              |
- * |  |     |                  |
  * |  |-----|minY              |
+ * |  |     |                  |
+ * |  |-----|maxY              |
  * |                           |
  * |                           |
  * |                           |
diff --git a/include/utils/RgbImage.h b/include/utils/RgbImage.h
index 7c5cea2d..5ee8e5d2 100644
--- a/include/utils/RgbImage.h
+++ b/include/utils/RgbImage.h
@@ -45,6 +45,10 @@ public:
 		return mColors;
 	}
 
+	const RgbColor* memptr() const
+	{
+		return mColors;
+	}
 private:
 
 	inline unsigned toIndex(const unsigned x, const unsigned y) const
diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt
index e684e617..74e72502 100644
--- a/libsrc/hyperion/CMakeLists.txt
+++ b/libsrc/hyperion/CMakeLists.txt
@@ -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
diff --git a/libsrc/hyperion/DispmanxWrapper.cpp b/libsrc/hyperion/DispmanxWrapper.cpp
index 75af522b..7f14a7f6 100644
--- a/libsrc/hyperion/DispmanxWrapper.cpp
+++ b/libsrc/hyperion/DispmanxWrapper.cpp
@@ -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);
diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp
index 09363ecb..47165c03 100644
--- a/libsrc/hyperion/Hyperion.cpp
+++ b/libsrc/hyperion/Hyperion.cpp
@@ -2,6 +2,8 @@
 // Syslog include
 #include 
 
+#include 
+
 // JsonSchema include
 #include 
 
@@ -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& 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);
 	}
 }
diff --git a/libsrc/hyperion/ImageProcessor.cpp b/libsrc/hyperion/ImageProcessor.cpp
index df508212..3fc7b2d8 100644
--- a/libsrc/hyperion/ImageProcessor.cpp
+++ b/libsrc/hyperion/ImageProcessor.cpp
@@ -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 ImageProcessor::process(const RgbImage& image)
@@ -25,41 +38,15 @@ std::vector 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 colors(mLedString.leds().size(), RgbColor::BLACK);
-	inplace_process(colors);
+	std::vector 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& ledColors)
+void ImageProcessor::process(const RgbImage& image, std::vector& ledColors)
 {
 	// Determine the mean-colors of each led (using the existing mapping)
-	mImageToLeds->getMeanLedColor(ledColors);
+	mImageToLeds->getMeanLedColor(image, ledColors);
 }
diff --git a/libsrc/hyperion/ImageToLedsMap.cpp b/libsrc/hyperion/ImageToLedsMap.cpp
index 98e25425..e41cd1df 100644
--- a/libsrc/hyperion/ImageToLedsMap.cpp
+++ b/libsrc/hyperion/ImageToLedsMap.cpp
@@ -7,43 +7,51 @@
 
 using namespace hyperion;
 
-ImageToLedsMap::ImageToLedsMap(const RgbImage& image, const std::vector& leds)
+ImageToLedsMap::ImageToLedsMap(const unsigned width, const unsigned height, const std::vector& leds) :
+	_width(width),
+	_height(height),
+	mColorsMap()
 {
-	mColorsMap.resize(leds.size(), std::vector());
+	// 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 ledColors;
+		for (unsigned y = minY_idx; y<=maxY_idx && ypush_back(&image(x,y));
+				ledColors.push_back(y*width + x);
 			}
 		}
+		mColorsMap.push_back(ledColors);
 	}
 }
 
-std::vector ImageToLedsMap::getMeanLedColor()
+unsigned ImageToLedsMap::width() const
 {
-	std::vector 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 ImageToLedsMap::getMeanLedColor(const RgbImage & image) const
+{
+	std::vector colors(mColorsMap.size(), RgbColor::BLACK);
+	getMeanLedColor(image, colors);
 	return colors;
 }
 
-void ImageToLedsMap::getMeanLedColor(std::vector& ledColors)
+void ImageToLedsMap::getMeanLedColor(const RgbImage & image, std::vector & ledColors) const
 {
 	// Sanity check for the number of leds
 	assert(mColorsMap.size() == ledColors.size());
@@ -51,21 +59,22 @@ void ImageToLedsMap::getMeanLedColor(std::vector& 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& colors)
+RgbColor ImageToLedsMap::calcMeanColor(const RgbImage & image, const std::vector & 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());
diff --git a/libsrc/hyperion/ImageToLedsMap.h b/libsrc/hyperion/ImageToLedsMap.h
index 5e4a4e9c..e7acf6f4 100644
--- a/libsrc/hyperion/ImageToLedsMap.h
+++ b/libsrc/hyperion/ImageToLedsMap.h
@@ -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& leds);
+	ImageToLedsMap(const unsigned width, const unsigned height, const std::vector & 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 getMeanLedColor();
+	std::vector 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& ledColors);
+	void getMeanLedColor(const RgbImage & image, std::vector & ledColors) const;
 
 private:
-	std::vector > mColorsMap;
+	const unsigned _width;
+	const unsigned _height;
+	std::vector > 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& colors);
+	RgbColor calcMeanColor(const RgbImage & image, const std::vector & colors) const;
 };
 
 } // end namespace hyperion