2013-11-11 10:00:37 +01:00
# include <hyperion/ImageToLedsMap.h>
2013-07-26 22:38:34 +02:00
2013-08-13 11:10:45 +02:00
using namespace hyperion ;
2013-07-26 22:38:34 +02:00
2013-08-21 17:24:42 +02:00
ImageToLedsMap : : ImageToLedsMap (
2023-02-17 16:02:51 +01:00
Logger * log ,
int width ,
int height ,
int horizontalBorder ,
int verticalBorder ,
const std : : vector < Led > & leds ,
int reducedPixelSetFactor ,
int accuracyLevel )
: _log ( log )
, _width ( width )
2016-09-08 16:32:42 +02:00
, _height ( height )
, _horizontalBorder ( horizontalBorder )
, _verticalBorder ( verticalBorder )
2023-02-17 16:02:51 +01:00
, _nextPixelCount ( reducedPixelSetFactor )
, _clusterCount ( )
2016-12-19 23:59:50 +01:00
, _colorsMap ( )
2013-07-26 22:38:34 +02:00
{
2023-02-17 16:02:51 +01:00
_nextPixelCount = reducedPixelSetFactor + 1 ;
setAccuracyLevel ( accuracyLevel ) ;
2013-08-21 17:24:42 +02:00
// Sanity check of the size of the borders (and width and height)
2017-08-04 12:01:45 +02:00
Q_ASSERT ( _width > 2 * _verticalBorder ) ;
Q_ASSERT ( _height > 2 * _horizontalBorder ) ;
2017-08-12 07:55:32 +02:00
Q_ASSERT ( _width < 10000 ) ;
Q_ASSERT ( _height < 10000 ) ;
2013-08-21 17:24:42 +02:00
2013-08-14 17:02:09 +02:00
// Reserve enough space in the map for the leds
2016-12-19 23:59:50 +01:00
_colorsMap . reserve ( leds . size ( ) ) ;
2013-07-26 22:38:34 +02:00
2023-02-17 16:02:51 +01:00
const int xOffset = _verticalBorder ;
const int actualWidth = _width - 2 * _verticalBorder ;
const int yOffset = _horizontalBorder ;
const int actualHeight = _height - 2 * _horizontalBorder ;
size_t totalCount = 0 ;
size_t totalCapacity = 0 ;
int ledCounter = 0 ;
2013-08-21 17:24:42 +02:00
2013-08-14 17:02:09 +02:00
for ( const Led & led : leds )
2013-07-26 22:38:34 +02:00
{
2014-03-26 16:26:11 +01:00
// skip leds without area
if ( ( led . maxX_frac - led . minX_frac ) < 1e-6 | | ( led . maxY_frac - led . minY_frac ) < 1e-6 )
{
2016-12-19 23:59:50 +01:00
_colorsMap . emplace_back ( ) ;
2014-03-26 16:26:11 +01:00
continue ;
}
2014-05-06 22:02:40 +02:00
2013-08-21 17:24:42 +02:00
// Compute the index boundaries for this led
2023-02-17 16:02:51 +01:00
int minX_idx = xOffset + int32_t ( qRound ( actualWidth * led . minX_frac ) ) ;
int maxX_idx = xOffset + int32_t ( qRound ( actualWidth * led . maxX_frac ) ) ;
int minY_idx = yOffset + int32_t ( qRound ( actualHeight * led . minY_frac ) ) ;
int maxY_idx = yOffset + int32_t ( qRound ( actualHeight * led . maxY_frac ) ) ;
2014-05-06 22:02:40 +02:00
2014-03-26 16:26:11 +01:00
// make sure that the area is at least a single led large
2017-08-04 12:01:45 +02:00
minX_idx = qMin ( minX_idx , xOffset + actualWidth - 1 ) ;
2014-03-26 16:26:11 +01:00
if ( minX_idx = = maxX_idx )
{
2019-01-06 19:49:56 +01:00
maxX_idx + + ;
2014-03-26 16:26:11 +01:00
}
2017-08-04 12:01:45 +02:00
minY_idx = qMin ( minY_idx , yOffset + actualHeight - 1 ) ;
2014-03-26 16:26:11 +01:00
if ( minY_idx = = maxY_idx )
{
2019-01-06 19:49:56 +01:00
maxY_idx + + ;
2014-03-26 16:26:11 +01:00
}
2013-07-26 22:38:34 +02:00
2013-08-21 17:24:42 +02:00
// Add all the indices in the above defined rectangle to the indices for this led
2023-02-17 16:02:51 +01:00
const int maxYLedCount = qMin ( maxY_idx , yOffset + actualHeight ) ;
const int maxXLedCount = qMin ( maxX_idx , xOffset + actualWidth ) ;
const int realYLedCount = qAbs ( maxYLedCount - minY_idx ) ;
const int realXLedCount = qAbs ( maxXLedCount - minX_idx ) ;
bool skipPixelProcessing { false } ;
if ( _nextPixelCount > 1 )
{
skipPixelProcessing = true ;
}
size_t totalSize = static_cast < size_t > ( 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 ) ;
}
2019-01-06 19:49:56 +01:00
2023-02-17 16:02:51 +01:00
std : : vector < int > ledColors ;
ledColors . reserve ( totalSize ) ;
2019-01-06 19:49:56 +01:00
2023-02-17 16:02:51 +01:00
for ( int y = minY_idx ; y < maxYLedCount ; y + = _nextPixelCount )
2013-07-26 22:38:34 +02:00
{
2023-02-17 16:02:51 +01:00
for ( int x = minX_idx ; x < maxXLedCount ; x + = _nextPixelCount )
2013-07-26 22:38:34 +02:00
{
2023-02-17 16:02:51 +01:00
ledColors . push_back ( y * width + x ) ;
2013-07-26 22:38:34 +02:00
}
}
2013-08-21 17:24:42 +02:00
// Add the constructed vector to the map
2016-12-19 23:59:50 +01:00
_colorsMap . push_back ( ledColors ) ;
2023-02-17 16:02:51 +01:00
totalCount + = ledColors . size ( ) ;
totalCapacity + = ledColors . capacity ( ) ;
ledCounter + + ;
2013-07-26 22:38:34 +02:00
}
2023-02-17 16:02:51 +01:00
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 ( ) ) ;
2013-07-26 22:38:34 +02:00
}
2023-02-17 16:02:51 +01:00
int ImageToLedsMap : : width ( ) const
2013-07-26 22:38:34 +02:00
{
2013-08-14 17:02:09 +02:00
return _width ;
}
2013-07-26 22:38:34 +02:00
2023-02-17 16:02:51 +01:00
int ImageToLedsMap : : height ( ) const
2013-08-14 17:02:09 +02:00
{
return _height ;
}
2023-02-17 16:02:51 +01:00
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 ;
}