From 1063eadec502a2c3cbe759a006e8b3af670a0164 Mon Sep 17 00:00:00 2001 From: LordGrey Date: Mon, 13 Feb 2023 18:12:51 +0100 Subject: [PATCH] ImageToLED - Add reduced pixel processing, make dominant color advanced configurable --- assets/webconfig/i18n/en.json | 8 ++ include/hyperion/ImageProcessor.h | 66 +++++++++----- include/hyperion/ImageToLedsMap.h | 95 +++++++++++--------- libsrc/hyperion/ImageProcessor.cpp | 105 +++++++++++++++++++---- libsrc/hyperion/ImageToLedsMap.cpp | 53 ++++++++++-- libsrc/hyperion/schema/schema-color.json | 26 +++++- 6 files changed, 265 insertions(+), 88 deletions(-) diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json index 14aea881..946f2965 100644 --- a/assets/webconfig/i18n/en.json +++ b/assets/webconfig/i18n/en.json @@ -251,6 +251,8 @@ "edt_conf_bb_unknownFrameCnt_title": "Unknown frames", "edt_conf_bge_heading_title": "Background Effect/Color", "edt_conf_bobls_heading_title": "Boblight Server", + "edt_conf_color_accuracyLevel_expl": "Level how accurate dominat colors are evaluated. A higher level creates more accurate results, but also requries more processing power. Should to be combined with reduced pixel processing.", + "edt_conf_color_accuracyLevel_title": "Accuracy level", "edt_conf_color_backlightColored_expl": "Add some color to your backlight.", "edt_conf_color_backlightColored_title": "Colored backlight", "edt_conf_color_backlightThreshold_expl": "The minimum amount of brightness (backlight). Disabled during effects, colors and in status \"Off\"", @@ -291,6 +293,8 @@ "edt_conf_color_saturationGain_title": "Saturation gain", "edt_conf_color_brightnessGain_expl": "Adjusts the brightness of colors. 1.0 means no change, over 1.0 increases brightness, under 1.0 decreases brightness.", "edt_conf_color_brightnessGain_title": "Brightness gain", + "edt_conf_color_reducedPixelSetFactorFactor_expl": "Evaluate only a set of pixels per LED area defined, Low ~25%, Medium ~10%, High ~6%", + "edt_conf_color_reducedPixelSetFactorFactor_title": "Reduced pixel processing", "edt_conf_color_white_expl": "The calibrated white value.", "edt_conf_color_white_title": "White", "edt_conf_color_yellow_expl": "The calibrated yellow value.", @@ -321,6 +325,7 @@ "edt_conf_enum_custom": "Custom", "edt_conf_enum_decay": "Decay", "edt_conf_enum_delay": "Delay only", + "edt_conf_enum_disabled": "Disabled", "edt_conf_enum_dl_error": "Error", "edt_conf_enum_dl_informational": "Informational", "edt_conf_enum_dl_nodebug": "No Debug output", @@ -334,6 +339,7 @@ "edt_conf_enum_effect": "Effect", "edt_conf_enum_gbr": "GBR", "edt_conf_enum_grb": "GRB", + "edt_conf_enum_high": "High", "edt_conf_enum_hsv": "HSV", "edt_conf_enum_left_right": "Left to right", "edt_conf_enum_linear": "Linear", @@ -341,6 +347,8 @@ "edt_conf_enum_logsilent": "Silent", "edt_conf_enum_logverbose": "Verbose", "edt_conf_enum_logwarn": "Warning", + "edt_conf_enum_low": "Low", + "edt_conf_enum_medium": "Medium", "edt_conf_enum_multicolor_mean": "Mean Color Simple - per LED", "edt_conf_enum_multicolor_mean_squared": "Mean Color Squared - per LED", "edt_conf_enum_please_select": "Please Select", diff --git a/include/hyperion/ImageProcessor.h b/include/hyperion/ImageProcessor.h index 18eac24c..84f4e26c 100644 --- a/include/hyperion/ImageProcessor.h +++ b/include/hyperion/ImageProcessor.h @@ -1,6 +1,7 @@ #pragma once #include +#include // Utils includes #include @@ -46,7 +47,7 @@ public: /// @param[in] width The new width of the buffer-image /// @param[in] height The new height of the buffer-image /// - void setSize(unsigned width, unsigned height); + void setSize(int width, int height); /// /// @brief Update the led string (eg on settings change) @@ -56,6 +57,19 @@ public: /// Returns state of black border detector bool blackBorderDetectorEnabled() const; + /// + /// Factor to reduce the number of pixels evaluated during processing + /// + /// @param[in] count Use every "count" pixel + void setReducedPixelSetFactorFactor(int count); + + /// + /// Set the accuracy used during processing + /// (only for selected types) + /// + /// @param[in] level The accuracy level (0-4) + void setAccuracyLevel(int level); + /// Returns the current _userMappingType, this may not be the current applied type! int getUserLedMappingType() const { return _userMappingType; } @@ -109,11 +123,14 @@ public: std::vector process(const Image& image) { std::vector colors; + if (image.width()>0 && image.height()>0) { // Ensure that the buffer-image is the proper size setSize(image); + assert(!_imageToLedColors.isNull()); + // Check black border detection verifyBorder(image); @@ -121,19 +138,19 @@ public: switch (_mappingType) { case 1: - colors = _imageToLeds->getUniLedColor(image); + colors = _imageToLedColors->getUniLedColor(image); break; case 2: - colors = _imageToLeds->getMeanLedColorSqrt(image); + colors = _imageToLedColors->getMeanLedColorSqrt(image); break; case 3: - colors = _imageToLeds->getDominantLedColor(image); + colors = _imageToLedColors->getDominantLedColor(image); break; case 4: - colors = _imageToLeds->getDominantLedColorAdv(image); + colors = _imageToLedColors->getDominantLedColorAdv(image); break; default: - colors = _imageToLeds->getMeanLedColor(image); + colors = _imageToLedColors->getMeanLedColor(image); } } else @@ -166,19 +183,19 @@ public: switch (_mappingType) { case 1: - _imageToLeds->getUniLedColor(image, ledColors); + _imageToLedColors->getUniLedColor(image, ledColors); break; case 2: - _imageToLeds->getMeanLedColorSqrt(image, ledColors); + _imageToLedColors->getMeanLedColorSqrt(image, ledColors); break; case 3: - _imageToLeds->getDominantLedColor(image, ledColors); + _imageToLedColors->getDominantLedColor(image, ledColors); break; case 4: - _imageToLeds->getDominantLedColorAdv(image, ledColors); + _imageToLedColors->getDominantLedColorAdv(image, ledColors); break; default: - _imageToLeds->getMeanLedColor(image, ledColors); + _imageToLedColors->getMeanLedColor(image, ledColors); } } else @@ -199,6 +216,13 @@ public: bool getScanParameters(size_t led, double & hscanBegin, double & hscanEnd, double & vscanBegin, double & vscanEnd) const; private: + + void registerProcessingUnit( + int width, + int height, + int horizontalBorder, + int verticalBorder); + /// /// Performs black-border detection (if enabled) on the given image /// @@ -207,30 +231,24 @@ private: template void verifyBorder(const Image & image) { - if (!_borderProcessor->enabled() && ( _imageToLeds->horizontalBorder()!=0 || _imageToLeds->verticalBorder()!=0 )) + if (!_borderProcessor->enabled() && ( _imageToLedColors->horizontalBorder()!=0 || _imageToLedColors->verticalBorder()!=0 )) { Debug(_log, "Reset border"); _borderProcessor->process(image); - delete _imageToLeds; - _imageToLeds = new hyperion::ImageToLedsMap(image.width(), image.height(), 0, 0, _ledString.leds()); + registerProcessingUnit(image.width(), image.height(), 0, 0); } if(_borderProcessor->enabled() && _borderProcessor->process(image)) { const hyperion::BlackBorder border = _borderProcessor->getCurrentBorder(); - // Clean up the old mapping - delete _imageToLeds; - if (border.unknown) { - // Construct a new buffer and mapping - _imageToLeds = new hyperion::ImageToLedsMap(image.width(), image.height(), 0, 0, _ledString.leds()); + registerProcessingUnit(image.width(), image.height(), 0, 0); } else { - // Construct a new buffer and mapping - _imageToLeds = new hyperion::ImageToLedsMap(image.width(), image.height(), border.horizontalSize, border.verticalSize, _ledString.leds()); + registerProcessingUnit(image.width(), image.height(), border.horizontalSize, border.verticalSize); } } } @@ -239,6 +257,7 @@ private slots: void handleSettingsUpdate(settings::type type, const QJsonDocument& config); private: + Logger * _log; /// The Led-string specification LedString _ledString; @@ -247,7 +266,7 @@ private: hyperion::BlackBorderProcessor * _borderProcessor; /// The mapping of image-pixels to LEDs - hyperion::ImageToLedsMap* _imageToLeds; + QSharedPointer _imageToLedColors; /// Type of image to LED mapping int _mappingType; @@ -256,6 +275,9 @@ private: /// Type of last requested hard type int _hardMappingType; + int _accuraryLevel; + int _reducedPixelSetFactorFactor; + /// Hyperion instance pointer Hyperion* _hyperion; }; diff --git a/include/hyperion/ImageToLedsMap.h b/include/hyperion/ImageToLedsMap.h index b93edd13..a3aebf82 100644 --- a/include/hyperion/ImageToLedsMap.h +++ b/include/hyperion/ImageToLedsMap.h @@ -17,15 +17,14 @@ namespace hyperion { - /// Number of clusters for k-means calculation - const int CLUSTER_COUNT {5}; - /// /// The ImageToLedsMap holds a mapping of indices into an image to LEDs. It can be used to /// calculate the average (aka mean) or dominant color per LED for a given region. /// - class ImageToLedsMap + class ImageToLedsMap : public QObject { + Q_OBJECT + public: /// @@ -35,17 +34,26 @@ namespace hyperion /// The mapping is created purely on size (width and height). The given borders are excluded /// from indexing. /// + /// @param[in] log Logger + /// @param[in] mappingType Type of the mapping algorithm /// @param[in] width The width of the indexed image /// @param[in] height The width of the indexed image /// @param[in] horizontalBorder The size of the horizontal border (0=no border) /// @param[in] verticalBorder The size of the vertical border (0=no border) /// @param[in] leds The list with led specifications + /// @param[in] reducedProcessingFactor Factor to reduce the number of pixels evaluated during processing + /// @param[in] accuraryLevel The accuracy used during processing (only for selected types) /// - ImageToLedsMap(int width, + ImageToLedsMap( + Logger* log, + int mappingType, + int width, int height, int horizontalBorder, int verticalBorder, - const std::vector & leds); + const std::vector & leds, + int reducedProcessingFactor = 0, + int accuraryLevel = 0); /// /// Returns the width of the indexed image @@ -64,6 +72,13 @@ namespace hyperion int horizontalBorder() const { return _horizontalBorder; } int verticalBorder() const { return _verticalBorder; } + /// + /// Set the accuracy used during processing + /// (only for selected types) + /// + /// @param[in] level The accuracy level (0-4) + void setAccuracyLevel (int level); + /// /// Determines the mean color for each LED using the LED area mapping given /// at construction. @@ -92,7 +107,7 @@ namespace hyperion { if(_colorsMap.size() != ledColors.size()) { - Debug(Logger::getInstance("HYPERION"), "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); + Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); return; } @@ -133,7 +148,7 @@ namespace hyperion { if(_colorsMap.size() != ledColors.size()) { - Debug(Logger::getInstance("HYPERION"), "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); + Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); return; } @@ -172,7 +187,7 @@ namespace hyperion { if(_colorsMap.size() != ledColors.size()) { - Debug(Logger::getInstance("HYPERION"), "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); + Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); return; } @@ -211,7 +226,7 @@ namespace hyperion // Sanity check for the number of LEDs if(_colorsMap.size() != ledColors.size()) { - Debug(Logger::getInstance("HYPERION"), "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); + Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); return; } @@ -253,7 +268,7 @@ namespace hyperion // Sanity check for the number of LEDs if(_colorsMap.size() != ledColors.size()) { - Debug(Logger::getInstance("HYPERION"), "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); + Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size()); return; } @@ -267,6 +282,11 @@ namespace hyperion } private: + + Logger* _log; + + int _mappingType; + /// The width of the indexed image const int _width; /// The height of the indexed image @@ -275,6 +295,12 @@ namespace hyperion const int _horizontalBorder; const int _verticalBorder; + /// Evaluate every "count" pixel + int _nextPixelCount; + + /// Number of clusters used during dominant color advanced processing (k-means) + int _clusterCount; + /// The absolute indices into the image for each led std::vector> _colorsMap; @@ -496,12 +522,21 @@ namespace hyperion struct ColorCluster { ColorCluster():count(0) {} + ColorCluster(Pixel_T color):count(0),color(color) {} Pixel_T color; Pixel_T newColor; int count; }; + const ColorRgb DEFAULT_CLUSTER_COLORS[5] { + {ColorRgb::BLACK}, + {ColorRgb::GREEN}, + {ColorRgb::WHITE}, + {ColorRgb::RED}, + {ColorRgb::YELLOW} + }; + /// /// Calculates the 'dominant color' of an image area defined by a list of pixel indices /// using a k-means algorithm (https://robocraft.ru/computervision/1063) @@ -519,31 +554,11 @@ namespace hyperion const auto pixelNum = pixels.size(); if (pixelNum > 0) { - ColorCluster clusters[CLUSTER_COUNT]; - - // initial cluster colors - switch (CLUSTER_COUNT) { - case 5: - clusters[4].newColor = ColorRgbScalar(ColorRgb::YELLOW); - case 4: - clusters[3].newColor = ColorRgbScalar(ColorRgb::RED); - case 3: - clusters[2].newColor = ColorRgbScalar(ColorRgb::WHITE); - case 2: - clusters[1].newColor = ColorRgbScalar(ColorRgb::GREEN); - case 1: - clusters[0].newColor = ColorRgbScalar(ColorRgb::BLACK); - break; - default: - for(int k = 0; k < CLUSTER_COUNT; ++k) - { - int randomRed = rand() % static_cast(256); - int randomGreen = rand() % static_cast(256); - int randomBlue = rand() % static_cast(256); - - clusters[k].newColor = ColorRgbScalar(randomRed, randomGreen, randomBlue); - } - break; + // initial cluster with different colors + ColorCluster clusters[_clusterCount]; + for(int k = 0; k < _clusterCount; ++k) + { + clusters[k].newColor = DEFAULT_CLUSTER_COLORS[k]; } // k-means @@ -552,7 +567,7 @@ namespace hyperion while(1) { - for(int k = 0; k < CLUSTER_COUNT; ++k) + for(int k = 0; k < _clusterCount; ++k) { clusters[k].count = 0; clusters[k].color = clusters[k].newColor; @@ -566,7 +581,7 @@ namespace hyperion min_rgb_euclidean = 255 * 255 * 255; int clusterIndex = -1; - for(int k = 0; k < CLUSTER_COUNT; ++k) + for(int k = 0; k < _clusterCount; ++k) { double euclid = ColorSys::rgb_euclidean(ColorRgbScalar(pixel), clusters[k].color); @@ -581,7 +596,7 @@ namespace hyperion } min_rgb_euclidean = 0; - for(int k = 0; k < CLUSTER_COUNT; ++k) + for(int k = 0; k < _clusterCount; ++k) { if (clusters[k].count > 0) { @@ -606,7 +621,7 @@ namespace hyperion int colorsFoundMax = 0; int dominantClusterIdx {0}; - for(int clusterIdx=0; clusterIdx < CLUSTER_COUNT; ++clusterIdx){ + for(int clusterIdx=0; clusterIdx < _clusterCount; ++clusterIdx){ int colorsFoundinCluster = clusters[clusterIdx].count; if (colorsFoundinCluster > colorsFoundMax) { colorsFoundMax = colorsFoundinCluster; diff --git a/libsrc/hyperion/ImageProcessor.cpp b/libsrc/hyperion/ImageProcessor.cpp index c9321d16..1984cb05 100644 --- a/libsrc/hyperion/ImageProcessor.cpp +++ b/libsrc/hyperion/ImageProcessor.cpp @@ -4,13 +4,40 @@ #include #include -// Blacborder includes +// Blackborder includes #include +#include #include using namespace hyperion; +void ImageProcessor::registerProcessingUnit( + int width, + int height, + int horizontalBorder, + int verticalBorder) +{ + if (width > 0 && height > 0) + { + _imageToLedColors = QSharedPointer(new ImageToLedsMap( + _log, + _mappingType, + width, + height, + horizontalBorder, + verticalBorder, + _ledString.leds(), + _reducedPixelSetFactorFactor, + _accuraryLevel + )); + } + else + { + _imageToLedColors = QSharedPointer(nullptr); + } +} + // global transform method int ImageProcessor::mappingTypeToInt(const QString& mappingType) { @@ -62,10 +89,12 @@ ImageProcessor::ImageProcessor(const LedString& ledString, Hyperion* hyperion) , _log(nullptr) , _ledString(ledString) , _borderProcessor(new BlackBorderProcessor(hyperion, this)) - , _imageToLeds(nullptr) + , _imageToLedColors(nullptr) , _mappingType(0) , _userMappingType(0) - , _hardMappingType(0) + , _hardMappingType(-1) + , _accuraryLevel(0) + , _reducedPixelSetFactorFactor(1) , _hyperion(hyperion) { QString subComponent = hyperion->property("instance").toString(); @@ -79,7 +108,6 @@ ImageProcessor::ImageProcessor(const LedString& ledString, Hyperion* hyperion) ImageProcessor::~ImageProcessor() { - delete _imageToLeds; } void ImageProcessor::handleSettingsUpdate(settings::type type, const QJsonDocument& config) @@ -92,39 +120,40 @@ void ImageProcessor::handleSettingsUpdate(settings::type type, const QJsonDocume { setLedMappingType(newType); } + + int reducedPixelSetFactorFactor = obj["reducedPixelSetFactorFactor"].toString().toInt(); + setReducedPixelSetFactorFactor(reducedPixelSetFactorFactor); + + int accuracyLevel = obj["accuracyLevel"].toInt(); + setAccuracyLevel(accuracyLevel); } } -void ImageProcessor::setSize(unsigned width, unsigned height) +void ImageProcessor::setSize(int width, int height) { // Check if the existing buffer-image is already the correct dimensions - if (_imageToLeds && _imageToLeds->width() == width && _imageToLeds->height() == height) + if (!_imageToLedColors.isNull() && _imageToLedColors->width() == width && _imageToLedColors->height() == height) { return; } - // Clean up the old buffer and mapping - delete _imageToLeds; - // Construct a new buffer and mapping - _imageToLeds = (width>0 && height>0) ? (new ImageToLedsMap(width, height, 0, 0, _ledString.leds())) : nullptr; + registerProcessingUnit(width, height, 0, 0); } void ImageProcessor::setLedString(const LedString& ledString) { - if ( _imageToLeds != nullptr) + Debug(_log,""); + if ( !_imageToLedColors.isNull() ) { _ledString = ledString; // get current width/height - unsigned width = _imageToLeds->width(); - unsigned height = _imageToLeds->height(); - - // Clean up the old buffer and mapping - delete _imageToLeds; + int width = _imageToLedColors->width(); + int height = _imageToLedColors->height(); // Construct a new buffer and mapping - _imageToLeds = new ImageToLedsMap(width, height, 0, 0, _ledString.leds()); + registerProcessingUnit(width, height, 0, 0); } } @@ -138,15 +167,55 @@ bool ImageProcessor::blackBorderDetectorEnabled() const return _borderProcessor->enabled(); } +void ImageProcessor::setReducedPixelSetFactorFactor(int count) +{ + int currentReducedPixelSetFactor= _reducedPixelSetFactorFactor; + + _reducedPixelSetFactorFactor = count; + Debug(_log, "Set reduced pixel set factor to %d", _reducedPixelSetFactorFactor); + + if (currentReducedPixelSetFactor != _reducedPixelSetFactorFactor && !_imageToLedColors.isNull()) + { + int width = _imageToLedColors->width(); + int height = _imageToLedColors->height(); + + // Construct a new buffer and mapping + registerProcessingUnit(width, height, 0, 0); + } +} + +void ImageProcessor::setAccuracyLevel(int level) +{ + _accuraryLevel = level; + Debug(_log, "Set processing accuracy level to %d", _accuraryLevel); + + if (!_imageToLedColors.isNull()) + { + _imageToLedColors->setAccuracyLevel(_accuraryLevel); + } +} + void ImageProcessor::setLedMappingType(int mapType) { + int currentMappingType = _mappingType; + // if the _hardMappingType is >-1 we aren't allowed to overwrite it _userMappingType = mapType; - Debug(_log, "set user led mapping to %s", QSTRING_CSTR(mappingTypeToStr(mapType))); + + Debug(_log, "Set user LED mapping to %s", QSTRING_CSTR(mappingTypeToStr(mapType))); + if(_hardMappingType == -1) { _mappingType = mapType; } + + if (currentMappingType != _mappingType && !_imageToLedColors.isNull()) + { + int width = _imageToLedColors->width(); + int height = _imageToLedColors->height(); + + registerProcessingUnit(width, height, 0, 0); + } } void ImageProcessor::setHardLedMappingType(int mapType) diff --git a/libsrc/hyperion/ImageToLedsMap.cpp b/libsrc/hyperion/ImageToLedsMap.cpp index a87e7e20..57568aae 100644 --- a/libsrc/hyperion/ImageToLedsMap.cpp +++ b/libsrc/hyperion/ImageToLedsMap.cpp @@ -3,17 +3,28 @@ using namespace hyperion; ImageToLedsMap::ImageToLedsMap( + Logger* log, + int mappingType, int width, int height, int horizontalBorder, int verticalBorder, - const std::vector& leds) - : _width(width) + const std::vector& leds, + int reducedPixelSetFactor, + int accuracyLevel) + : _log(log) + , _mappingType(mappingType) + , _width(width) , _height(height) , _horizontalBorder(horizontalBorder) , _verticalBorder(verticalBorder) + , _nextPixelCount(reducedPixelSetFactor) + , _clusterCount() , _colorsMap() { + _nextPixelCount = reducedPixelSetFactor + 1; + setAccuracyLevel(accuracyLevel); + // Sanity check of the size of the borders (and width and height) Q_ASSERT(_width > 2*_verticalBorder); Q_ASSERT(_height > 2*_horizontalBorder); @@ -30,6 +41,7 @@ ImageToLedsMap::ImageToLedsMap( size_t totalCount = 0; size_t totalCapacity = 0; + int ledCounter = 0; for (const Led& led : leds) { @@ -65,14 +77,27 @@ ImageToLedsMap::ImageToLedsMap( const int realYLedCount = qAbs(maxYLedCount - minY_idx); const int realXLedCount = qAbs(maxXLedCount - minX_idx); - size_t totalSize = realYLedCount* realXLedCount; + bool skipPixelProcessing {false}; + if (_nextPixelCount > 1) + { + skipPixelProcessing = true; + } + + size_t totalSize = static_cast(realYLedCount * realXLedCount); + + if (!skipPixelProcessing && totalSize > 1600) + { + skipPixelProcessing = true; + _nextPixelCount = 2; + Warning(_log, "Mapping LED/light [%d]. The current mapping area contains %d pixels which is huge. Therefore every %d pixels will be skipped. You can enable reduced processing to hide that warning.", ledCounter, totalSize, _nextPixelCount); + } std::vector ledColors; ledColors.reserve(totalSize); - for (int y = minY_idx; y < maxYLedCount; ++y) + for (int y = minY_idx; y < maxYLedCount; y += _nextPixelCount) { - for (int x = minX_idx; x < maxXLedCount; ++x) + for (int x = minX_idx; x < maxXLedCount; x += _nextPixelCount) { ledColors.push_back( y * width + x); } @@ -84,9 +109,10 @@ ImageToLedsMap::ImageToLedsMap( totalCount += ledColors.size(); totalCapacity += ledColors.capacity(); + ledCounter++; } - Debug(Logger::getInstance("HYPERION"), "Total index number is: %d (memory: %d). image size: %d x %d, LED areas: %d", - totalCount, totalCapacity, width, height, leds.size()); + Debug(_log, "Total index number is: %d (memory: %d). Reduced pixel set factor: %d, Accuracy level: %d, Image size: %d x %d, LED areas: %d", + totalCount, totalCapacity, reducedPixelSetFactor, accuracyLevel, width, height, leds.size()); } @@ -99,3 +125,16 @@ int ImageToLedsMap::height() const { return _height; } + +void ImageToLedsMap::setAccuracyLevel (int accuracyLevel) +{ + if (accuracyLevel > 4 ) + { + Warning(_log, "Accuracy level %d is too high, it will be set to 4", accuracyLevel); + accuracyLevel = 4; + } + //Set cluster number for dominant color advanced + _clusterCount = accuracyLevel + 1; + +} + diff --git a/libsrc/hyperion/schema/schema-color.json b/libsrc/hyperion/schema/schema-color.json index ed331d21..a56d3bed 100644 --- a/libsrc/hyperion/schema/schema-color.json +++ b/libsrc/hyperion/schema/schema-color.json @@ -16,13 +16,37 @@ }, "propertyOrder" : 1 }, + "accuracyLevel": { + "type": "integer", + "title": "edt_conf_color_accuracyLevel_title", + "minimum": 1, + "maximum": 4, + "default": 2, + "propertyOrder": 2, + "options": { + "dependencies": { + "imageToLedMappingType": "dominant_color_advanced" + } + } + }, + "reducedPixelSetFactorFactor": { + "type": "string", + "title": "edt_conf_color_reducedPixelSetFactorFactor_title", + "default": 0, + "enum" : ["0", "1", "2", "3"], + "default" : "0", + "options" : { + "enum_titles" : ["edt_conf_enum_disabled", "edt_conf_enum_low", "edt_conf_enum_medium", "edt_conf_enum_high"] + }, + "propertyOrder": 3 + }, "channelAdjustment" : { "type" : "array", "title" : "edt_conf_color_channelAdjustment_header_title", "minItems": 1, "required" : true, - "propertyOrder" : 3, + "propertyOrder" : 4, "items" : { "type" : "object",