diff --git a/config/hyperion.config.json.commented b/config/hyperion.config.json.commented index f70adf19..c8677afe 100644 --- a/config/hyperion.config.json.commented +++ b/config/hyperion.config.json.commented @@ -30,6 +30,8 @@ /// Color manipulation configuration used to tune the output colors to specific surroundings. /// The configuration contains a list of color-transforms. Each transform contains the /// following fields: + /// * 'imageToLedMappingType' : multicolor_mean - every led has it's own calculatedmean color + /// unicolor_mean - every led has same color, color is the mean of whole image /// * 'channelAdjustment_enable' : true/false enables/disables this channelAdjustment section /// * 'channelAdjustment_v4l_only' : if enabled and set to true, then channelAdjustment is only for v4l devices /// * 'channelAdjustment' @@ -56,6 +58,7 @@ /// - 'gamma' The gamma-curve correction factor "color" : { + "imageToLedMappingType" : "multicolor_mean", "channelAdjustment_enable" : true, "channelAdjustment_v4l_only" : true, "channelAdjustment" : diff --git a/config/hyperion.config.json.default b/config/hyperion.config.json.default index 13718051..db590d59 100644 --- a/config/hyperion.config.json.default +++ b/config/hyperion.config.json.default @@ -16,6 +16,7 @@ "color" : { + "imageToLedMappingType" : "multicolor_mean", "channelAdjustment_enable" : true, "channelAdjustment_v4l_only" : true, "channelAdjustment" : diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 8c331728..75eae380 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -93,7 +93,7 @@ public: /// unsigned getLedCount() const; - QSize getLedGridSize() const { return _ledGridSize; } + QSize getLedGridSize() const { return _ledGridSize; }; /// /// Returns the current priority @@ -273,6 +273,9 @@ public slots: /// @param timeout The timeout of the effect (after the timout, the effect will be cleared) int setEffect(const QString & effectName, const QJsonObject & args, int priority, int timeout = -1, QString pythonScript = ""); + /// sets the methode how image is maped to leds + void setLedMappingType(int mappingType); + public: static Hyperion *_hyperion; @@ -312,6 +315,7 @@ signals: void componentStateChanged(const hyperion::Components component, bool enabled); + void imageToLedsMappingChanged(int mappingType); void emitImage(int priority, const Image & image, const int timeout_ms); private slots: diff --git a/include/hyperion/ImageProcessor.h b/include/hyperion/ImageProcessor.h index 193eb6e7..15a9fbc7 100644 --- a/include/hyperion/ImageProcessor.h +++ b/include/hyperion/ImageProcessor.h @@ -1,6 +1,7 @@ - #pragma once +#include + // Utils includes #include @@ -18,9 +19,12 @@ /// 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 +class ImageProcessor : public QObject { + Q_OBJECT + public: + ~ImageProcessor(); /// @@ -38,12 +42,23 @@ public: /// void setSize(const unsigned width, const unsigned height); - /// Enable or disable the black border detector - void enableBlackBorderDetector(bool enable); /// Returns starte of black border detector bool blackBorderDetectorEnabled(); + /// Returns starte of black border detector + int ledMappingType(); + + static int mappingTypeToInt(QString mappingType); + +public slots: + /// Enable or disable the black border detector + void enableBlackBorderDetector(bool enable); + + /// Enable or disable the black border detector + void setLedMappingType(int mapType); + +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. @@ -62,7 +77,12 @@ public: verifyBorder(image); // Create a result vector and call the 'in place' functionl - std::vector colors = _imageToLeds->getMeanLedColor(image); + std::vector colors; + switch (_mappingType) + { + case 1: colors = _imageToLeds->getUniLedColor(image); break; + default: colors = _imageToLeds->getMeanLedColor(image); + } // return the computed colors return colors; @@ -84,7 +104,12 @@ public: verifyBorder(image); // Determine the mean-colors of each led (using the existing mapping) - _imageToLeds->getMeanLedColor(image, ledColors); + switch (_mappingType) + { + case 1: _imageToLeds->getUniLedColor(image, ledColors); break; + default: _imageToLeds->getMeanLedColor(image, ledColors); + } + } /// @@ -153,6 +178,7 @@ private: } private: + Logger * _log; /// The Led-string specification const LedString _ledString; @@ -161,4 +187,7 @@ private: /// The mapping of image-pixels to leds hyperion::ImageToLedsMap* _imageToLeds; + + /// Type of image 2 led mapping + int _mappingType; }; diff --git a/include/hyperion/ImageProcessorFactory.h b/include/hyperion/ImageProcessorFactory.h index 5957d4f8..e7381ad0 100644 --- a/include/hyperion/ImageProcessorFactory.h +++ b/include/hyperion/ImageProcessorFactory.h @@ -32,7 +32,7 @@ public: /// @param[in] ledString The led configuration /// @param[in] blackborderConfig Contains the blackborder configuration /// - void init(const LedString& ledString, const QJsonObject &blackborderConfig); + void init(const LedString& ledString, const QJsonObject &blackborderConfig, int mappingType); /// /// Creates a new ImageProcessor. The onwership of the processor is transferred to the caller. @@ -45,6 +45,9 @@ private: /// The Led-string specification LedString _ledString; - // Reference to the blackborder json configuration values + /// Reference to the blackborder json configuration values QJsonObject _blackborderConfig; + + // image 2 led mapping type + int _mappingType; }; diff --git a/include/hyperion/ImageToLedsMap.h b/include/hyperion/ImageToLedsMap.h index 47a39305..116d4760 100644 --- a/include/hyperion/ImageToLedsMap.h +++ b/include/hyperion/ImageToLedsMap.h @@ -70,7 +70,7 @@ namespace hyperion template std::vector getMeanLedColor(const Image & image) const { - std::vector colors(mColorsMap.size(), ColorRgb{0,0,0}); + std::vector colors(_colorsMap.size(), ColorRgb{0,0,0}); getMeanLedColor(image, colors); return colors; } @@ -86,16 +86,50 @@ namespace hyperion void getMeanLedColor(const Image & image, std::vector & ledColors) const { // Sanity check for the number of leds - assert(mColorsMap.size() == ledColors.size()); + assert(_colorsMap.size() == ledColors.size()); // Iterate each led and compute the mean auto led = ledColors.begin(); - for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors, ++led) + for (auto ledColors = _colorsMap.begin(); ledColors != _colorsMap.end(); ++ledColors, ++led) { const ColorRgb color = calcMeanColor(image, *ledColors); *led = color; } } + + /// + /// Determines the mean-color for each led using the mapping the image given + /// at construction. + /// + /// @param[in] image The image from which to extract the led colors + /// + /// @return ledColors The vector containing the output + /// + template + std::vector getUniLedColor(const Image & image) const + { + std::vector colors(_colorsMap.size(), ColorRgb{0,0,0}); + getUniLedColor(image, colors); + return colors; + } + + /// + /// Determines the mean color for each led using the mapping the image given + /// at construction. + /// + /// @param[in] image The image from which to extract the led colors + /// @param[out] ledColors The vector containing the output + /// + template + void getUniLedColor(const Image & image, std::vector & ledColors) const + { + // Sanity check for the number of leds + assert(_colorsMap.size() == ledColors.size()); + + // calculate uni color + const ColorRgb color = calcMeanColor(image); + std::fill(ledColors.begin(),ledColors.end(), color); + } private: /// The width of the indexed image @@ -108,7 +142,7 @@ namespace hyperion const unsigned _verticalBorder; /// The absolute indices into the image for each led - std::vector> mColorsMap; + std::vector> _colorsMap; /// /// Calculates the 'mean color' of the given list. This is the mean over each color-channel @@ -147,6 +181,40 @@ namespace hyperion // Return the computed color return {avgRed, avgGreen, avgBlue}; } + + /// + /// Calculates the 'mean color' over the given image. This is the mean over each color-channel + /// (red, green, blue) + /// + /// @param[in] image The image a section from which an average color must be computed + /// + /// @return The mean of the given list of colors (or black when empty) + /// + template + ColorRgb calcMeanColor(const Image & image) const + { + // Accumulate the sum of each seperate color channel + uint_fast16_t cummRed = 0; + uint_fast16_t cummGreen = 0; + uint_fast16_t cummBlue = 0; + const unsigned imageSize = image.width() * image.height(); + + for (unsigned idx=0; idxgetComponentRegister().componentStateChanged(hyperion::COMP_BLACKBORDER, _processor->blackBorderDetectorEnabled()); qRegisterMetaType("hyperion::Components"); + connect(_hyperion, SIGNAL(imageToLedsMappingChanged(int)), _processor, SLOT(setLedMappingType(int))); connect(_hyperion, SIGNAL(componentStateChanged(hyperion::Components,bool)), this, SLOT(componentStateChanged(hyperion::Components,bool))); connect(&_timer, SIGNAL(timeout()), this, SLOT(action())); } @@ -120,4 +121,3 @@ void GrabberWrapper::setColors(const std::vector &ledColors, const int { _hyperion->setColors(_priority, ledColors, timeout_ms, true, _grabberComponentId); } - diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 9294ee6d..6788f9f1 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -17,6 +17,7 @@ // hyperion include #include #include +#include #include #include @@ -561,7 +562,8 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile) // initialize the image processor factory ImageProcessorFactory::getInstance().init( _ledString, - qjsonConfig["blackborderdetector"].toObject() + qjsonConfig["blackborderdetector"].toObject(), + ImageProcessor::mappingTypeToInt(color["imageToLedMappingType"].toString()) ); getComponentRegister().componentStateChanged(hyperion::COMP_FORWARDER, _messageForwarder->forwardingEnabled()); @@ -852,6 +854,11 @@ int Hyperion::setEffect(const QString &effectName, const QJsonObject &args, int return _effectEngine->runEffect(effectName, args, priority, timeout, pythonScript); } +void Hyperion::setLedMappingType(int mappingType) +{ + emit imageToLedsMappingChanged(mappingType); +} + void Hyperion::update() { // Update the muxer, cleaning obsolete priorities diff --git a/libsrc/hyperion/ImageProcessor.cpp b/libsrc/hyperion/ImageProcessor.cpp index 2083e938..e8508fc4 100644 --- a/libsrc/hyperion/ImageProcessor.cpp +++ b/libsrc/hyperion/ImageProcessor.cpp @@ -1,5 +1,6 @@ // Hyperion includes +#include #include #include @@ -8,13 +9,16 @@ using namespace hyperion; -//ImageProcessor::ImageProcessor(const LedString& ledString, bool enableBlackBorderDetector, uint8_t blackborderThreshold) : -ImageProcessor::ImageProcessor(const LedString& ledString, const QJsonObject & blackborderConfig) : - _ledString(ledString), - _borderProcessor(new BlackBorderProcessor(blackborderConfig) ), - _imageToLeds(nullptr) +ImageProcessor::ImageProcessor(const LedString& ledString, const QJsonObject & blackborderConfig) + : QObject() + , _log(Logger::getInstance("BLACKBORDER")) + , _ledString(ledString) + , _borderProcessor(new BlackBorderProcessor(blackborderConfig) ) + , _imageToLeds(nullptr) + , _mappingType(0) { - // empty +// this is when we want to change the mapping for all input sources +// connect(Hyperion::getInstance(), SIGNAL(imageToLedsMappingChanged(int)), this, SLOT(setLedMappingType(int))); } ImageProcessor::~ImageProcessor() @@ -53,6 +57,25 @@ bool ImageProcessor::blackBorderDetectorEnabled() return _borderProcessor->enabled(); } +void ImageProcessor::setLedMappingType(int mapType) +{ + Debug(_log, "set led mapping to type %d", mapType); + _mappingType = mapType; +} + +int ImageProcessor::ledMappingType() +{ + return _mappingType; +} + +int ImageProcessor::mappingTypeToInt(QString mappingType) +{ + if (mappingType == "unicolor_mean" ) + return 1; + + return 0; +} + bool ImageProcessor::getScanParameters(size_t led, double &hscanBegin, double &hscanEnd, double &vscanBegin, double &vscanEnd) const { if (led < _ledString.leds().size()) diff --git a/libsrc/hyperion/ImageProcessorFactory.cpp b/libsrc/hyperion/ImageProcessorFactory.cpp index cf0d51b6..7b7cfbbe 100644 --- a/libsrc/hyperion/ImageProcessorFactory.cpp +++ b/libsrc/hyperion/ImageProcessorFactory.cpp @@ -9,13 +9,17 @@ ImageProcessorFactory& ImageProcessorFactory::getInstance() return instance; } -void ImageProcessorFactory::init(const LedString& ledString, const QJsonObject & blackborderConfig) +void ImageProcessorFactory::init(const LedString& ledString, const QJsonObject & blackborderConfig, int mappingType) { _ledString = ledString; _blackborderConfig = blackborderConfig; + _mappingType = mappingType; } ImageProcessor* ImageProcessorFactory::newImageProcessor() const { - return new ImageProcessor(_ledString, _blackborderConfig); + ImageProcessor* ip = new ImageProcessor(_ledString, _blackborderConfig); + ip->setLedMappingType(_mappingType); + + return ip; } diff --git a/libsrc/hyperion/ImageToLedsMap.cpp b/libsrc/hyperion/ImageToLedsMap.cpp index 43b0ec8b..38cacc69 100644 --- a/libsrc/hyperion/ImageToLedsMap.cpp +++ b/libsrc/hyperion/ImageToLedsMap.cpp @@ -18,26 +18,26 @@ ImageToLedsMap::ImageToLedsMap( , _height(height) , _horizontalBorder(horizontalBorder) , _verticalBorder(verticalBorder) - , mColorsMap() + , _colorsMap() { // Sanity check of the size of the borders (and width and height) - assert(width > 2*verticalBorder); - assert(height > 2*horizontalBorder); + assert(_width > 2*_verticalBorder); + assert(_height > 2*_horizontalBorder); // Reserve enough space in the map for the leds - mColorsMap.reserve(leds.size()); + _colorsMap.reserve(leds.size()); - const unsigned xOffset = verticalBorder; - const unsigned actualWidth = width - 2 * verticalBorder; - const unsigned yOffset = horizontalBorder; - const unsigned actualHeight = height - 2 * horizontalBorder; + const unsigned xOffset = _verticalBorder; + const unsigned actualWidth = _width - 2 * _verticalBorder; + const unsigned yOffset = _horizontalBorder; + const unsigned actualHeight = _height - 2 * _horizontalBorder; for (const Led& led : leds) { // skip leds without area if ((led.maxX_frac-led.minX_frac) < 1e-6 || (led.maxY_frac-led.minY_frac) < 1e-6) { - mColorsMap.emplace_back(); + _colorsMap.emplace_back(); continue; } @@ -70,7 +70,7 @@ ImageToLedsMap::ImageToLedsMap( } // Add the constructed vector to the map - mColorsMap.push_back(ledColors); + _colorsMap.push_back(ledColors); } } diff --git a/libsrc/hyperion/hyperion.schema.json b/libsrc/hyperion/hyperion.schema.json index 34832001..4b93fddf 100644 --- a/libsrc/hyperion/hyperion.schema.json +++ b/libsrc/hyperion/hyperion.schema.json @@ -51,6 +51,7 @@ "type" : "string", "title" : "edt_dev_general_colorOrder_title", "enum" : ["rgb", "bgr", "rbg", "brg", "gbr", "grb"], + "default" : "rgb", "propertyOrder" : 3 }, "rewriteTime": { @@ -70,26 +71,33 @@ "type":"object", "title" : "edt_conf_color_heading_title", "required" : true, - "defaultProperties": ["channelAdjustment_enable","channelAdjustment","transform_enable","transform"], + "defaultProperties": ["imageToLedMappingType","channelAdjustment_enable","channelAdjustment","transform_enable","transform"], "properties": { + "imageToLedMappingType" : + { + "type" : "string", + "enum" : ["multicolor_mean", "unicolor_mean"], + "default" : "multicolor_mean", + "propertyOrder" : 1 + }, "channelAdjustment_enable" : { "type" : "boolean", "default" : true, - "propertyOrder" : 1 + "propertyOrder" : 2 }, "channelAdjustment_v4l_only" : { "type" : "boolean", "default" : false, - "propertyOrder" : 2 + "propertyOrder" : 3 }, "channelAdjustment" : { "type" : "array", "required" : true, - "propertyOrder" : 3, + "propertyOrder" : 4, "items" : { "type" : "object", @@ -204,19 +212,19 @@ { "type" : "boolean", "default" : true, - "propertyOrder" : 4 + "propertyOrder" : 5 }, "transform_v4l_only" : { "type" : "boolean", "default" : false, - "propertyOrder" : 5 + "propertyOrder" : 6 }, "transform" : { "type" : "array", "required" : true, - "propertyOrder" : 6, + "propertyOrder" : 7, "items" : { "type" : "object", diff --git a/libsrc/jsonserver/JsonClientConnection.cpp b/libsrc/jsonserver/JsonClientConnection.cpp index 58751386..1d1a252f 100644 --- a/libsrc/jsonserver/JsonClientConnection.cpp +++ b/libsrc/jsonserver/JsonClientConnection.cpp @@ -319,6 +319,8 @@ void JsonClientConnection::handleMessage(const QString& messageString) handleLedColorsCommand(message, command, tan); else if (command == "logging") handleLoggingCommand(message, command, tan); + else if (command == "processing") + handleProcessingCommand(message, command, tan); else handleNotImplemented(); } @@ -1272,6 +1274,13 @@ void JsonClientConnection::handleLoggingCommand(const QJsonObject& message, cons sendSuccessReply(command+"-"+subcommand,tan); } +void JsonClientConnection::handleProcessingCommand(const QJsonObject& message, const QString &command, const int tan) +{ + _hyperion->setLedMappingType(ImageProcessor::mappingTypeToInt( message["mappingType"].toString("multicolor_mean")) ); + + sendSuccessReply(command, tan); +} + void JsonClientConnection::incommingLogMessage(Logger::T_LOG_MESSAGE msg) { QJsonObject result, message; diff --git a/libsrc/jsonserver/JsonClientConnection.h b/libsrc/jsonserver/JsonClientConnection.h index 8dd85b20..5e378d47 100644 --- a/libsrc/jsonserver/JsonClientConnection.h +++ b/libsrc/jsonserver/JsonClientConnection.h @@ -265,6 +265,12 @@ private: /// void handleLoggingCommand(const QJsonObject & message, const QString &command, const int tan); + /// Handle an incoming JSON Proccessing message + /// + /// @param message the incoming message + /// + void handleProcessingCommand(const QJsonObject & message, const QString &command, const int tan); + /// /// Handle an incoming JSON message of unknown type /// diff --git a/libsrc/jsonserver/JsonSchemas.qrc b/libsrc/jsonserver/JsonSchemas.qrc index c9575da5..6f349da3 100644 --- a/libsrc/jsonserver/JsonSchemas.qrc +++ b/libsrc/jsonserver/JsonSchemas.qrc @@ -16,5 +16,6 @@ schema/schema-componentstate.json schema/schema-ledcolors.json schema/schema-logging.json + schema/schema-processing.json diff --git a/libsrc/jsonserver/schema/schema-processing.json b/libsrc/jsonserver/schema/schema-processing.json new file mode 100644 index 00000000..ddd04da1 --- /dev/null +++ b/libsrc/jsonserver/schema/schema-processing.json @@ -0,0 +1,19 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["processing"] + }, + "tan" : { + "type" : "integer" + }, + "mappingType": { + "type" : "string", + "enum" : ["multicolor_mean", "unicolor_mean"] + } + }, + "additionalProperties": false +} diff --git a/libsrc/jsonserver/schema/schema.json b/libsrc/jsonserver/schema/schema.json index fdeb9f93..53f66323 100644 --- a/libsrc/jsonserver/schema/schema.json +++ b/libsrc/jsonserver/schema/schema.json @@ -5,7 +5,7 @@ "command": { "type" : "string", "required" : true, - "enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "transform", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging"] + "enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "transform", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing"] } } } diff --git a/src/hyperion-remote/JsonConnection.cpp b/src/hyperion-remote/JsonConnection.cpp index fd11f69d..0890a37d 100644 --- a/src/hyperion-remote/JsonConnection.cpp +++ b/src/hyperion-remote/JsonConnection.cpp @@ -545,6 +545,17 @@ void JsonConnection::setAdjustment(const QString &adjustmentId, parseReply(reply); } + +void JsonConnection::setLedMapping(QString mappingType) +{ + QJsonObject command; + command["command"] = QString("processing"); + command["mappingType"] = mappingType; + + QJsonObject reply = sendMessage(command); + parseReply(reply); +} + QJsonObject JsonConnection::sendMessage(const QJsonObject & message) { // serialize message diff --git a/src/hyperion-remote/JsonConnection.h b/src/hyperion-remote/JsonConnection.h index 6d0f65a1..9ccbdc50 100644 --- a/src/hyperion-remote/JsonConnection.h +++ b/src/hyperion-remote/JsonConnection.h @@ -90,7 +90,7 @@ public: /// Clear all priority channels /// void clearAll(); - + /// /// Enable/Disable components during runtime /// @@ -105,12 +105,12 @@ public: /// @param priority The priority /// void setSource(int priority); - + /// /// Enables auto source, if disabled prio by manual selecting input source /// void setSourceAutoSelect(); - + /// /// Print the current loaded Hyperion configuration file /// @@ -167,6 +167,12 @@ public: const QColor & greenAdjustment, const QColor & blueAdjustment); + /// + /// sets the image to leds mapping type + /// + /// @param mappingType led mapping type + void setLedMapping(QString mappingType); + private: /// /// Send a json command message and receive its reply diff --git a/src/hyperion-remote/hyperion-remote.cpp b/src/hyperion-remote/hyperion-remote.cpp index 34f0e787..466838e5 100644 --- a/src/hyperion-remote/hyperion-remote.cpp +++ b/src/hyperion-remote/hyperion-remote.cpp @@ -87,6 +87,7 @@ int main(int argc, char * argv[]) ColorOption & argRAdjust = parser.add ('R', "redAdjustment" , "Set the adjustment of the red color (requires colors in hex format as RRGGBB)"); ColorOption & argGAdjust = parser.add ('G', "greenAdjustment", "Set the adjustment of the green color (requires colors in hex format as RRGGBB)"); ColorOption & argBAdjust = parser.add ('B', "blueAdjustment", "Set the adjustment of the blue color (requires colors in hex format as RRGGBB)"); + Option & argMapping = parser.add