ImageToLedsMap.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. #ifndef IMAGETOLEDSMAP_H
  2. #define IMAGETOLEDSMAP_H
  3. // STL includes
  4. #include <cassert>
  5. #include <memory>
  6. #include <sstream>
  7. #include <cmath>
  8. // hyperion-utils includes
  9. #include <utils/Image.h>
  10. #include <utils/Logger.h>
  11. #include <utils/ColorRgbScalar.h>
  12. #include <utils/ColorSys.h>
  13. // hyperion includes
  14. #include <hyperion/LedString.h>
  15. namespace hyperion
  16. {
  17. ///
  18. /// The ImageToLedsMap holds a mapping of indices into an image to LEDs. It can be used to
  19. /// calculate the average (aka mean) or dominant color per LED for a given region.
  20. ///
  21. class ImageToLedsMap : public QObject
  22. {
  23. Q_OBJECT
  24. public:
  25. ///
  26. /// Constructs an mapping from the absolute indices in an image to each LED based on the border
  27. /// definition given in the list of LEDs. The map holds absolute indices to any given image,
  28. /// provided that it is row-oriented.
  29. /// The mapping is created purely on size (width and height). The given borders are excluded
  30. /// from indexing.
  31. ///
  32. /// @param[in] log Logger
  33. /// @param[in] width The width of the indexed image
  34. /// @param[in] height The width of the indexed image
  35. /// @param[in] horizontalBorder The size of the horizontal border (0=no border)
  36. /// @param[in] verticalBorder The size of the vertical border (0=no border)
  37. /// @param[in] leds The list with led specifications
  38. /// @param[in] reducedProcessingFactor Factor to reduce the number of pixels evaluated during processing
  39. /// @param[in] accuraryLevel The accuracy used during processing (only for selected types)
  40. ///
  41. ImageToLedsMap(
  42. Logger* log,
  43. int width,
  44. int height,
  45. int horizontalBorder,
  46. int verticalBorder,
  47. const std::vector<Led> & leds,
  48. int reducedProcessingFactor = 0,
  49. int accuraryLevel = 0);
  50. ///
  51. /// Returns the width of the indexed image
  52. ///
  53. /// @return The width of the indexed image [pixels]
  54. ///
  55. int width() const;
  56. ///
  57. /// Returns the height of the indexed image
  58. ///
  59. /// @return The height of the indexed image [pixels]
  60. ///
  61. int height() const;
  62. int horizontalBorder() const { return _horizontalBorder; }
  63. int verticalBorder() const { return _verticalBorder; }
  64. ///
  65. /// Set the accuracy used during processing
  66. /// (only for selected types)
  67. ///
  68. /// @param[in] level The accuracy level (0-4)
  69. void setAccuracyLevel (int level);
  70. ///
  71. /// Determines the mean color for each LED using the LED area mapping given
  72. /// at construction.
  73. ///
  74. /// @param[in] image The image from which to extract the led colors
  75. ///
  76. /// @return The vector containing the output
  77. ///
  78. template <typename Pixel_T>
  79. std::vector<ColorRgb> getMeanLedColor(const Image<Pixel_T> & image) const
  80. {
  81. std::vector<ColorRgb> colors(_colorsMap.size(), ColorRgb{0,0,0});
  82. getMeanLedColor(image, colors);
  83. return colors;
  84. }
  85. ///
  86. /// Determines the mean color for each LED using the LED area mapping given
  87. /// at construction.
  88. ///
  89. /// @param[in] image The image from which to extract the LED colors
  90. /// @param[out] ledColors The vector containing the output
  91. ///
  92. template <typename Pixel_T>
  93. void getMeanLedColor(const Image<Pixel_T> & image, std::vector<ColorRgb> & ledColors) const
  94. {
  95. if(_colorsMap.size() != ledColors.size())
  96. {
  97. Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size());
  98. return;
  99. }
  100. // Iterate each led and compute the mean
  101. auto led = ledColors.begin();
  102. for (auto colors = _colorsMap.begin(); colors != _colorsMap.end(); ++colors, ++led)
  103. {
  104. const ColorRgb color = calcMeanColor(image, *colors);
  105. *led = color;
  106. }
  107. }
  108. ///
  109. /// Determines the mean color squared for each LED using the LED area mapping given
  110. /// at construction.
  111. ///
  112. /// @param[in] image The image from which to extract the led colors
  113. ///
  114. /// @return The vector containing the output
  115. ///
  116. template <typename Pixel_T>
  117. std::vector<ColorRgb> getMeanLedColorSqrt(const Image<Pixel_T> & image) const
  118. {
  119. std::vector<ColorRgb> colors(_colorsMap.size(), ColorRgb{0,0,0});
  120. getMeanLedColorSqrt(image, colors);
  121. return colors;
  122. }
  123. ///
  124. /// Determines the mean color squared for each LED using the LED area mapping given
  125. /// at construction.
  126. ///
  127. /// @param[in] image The image from which to extract the LED colors
  128. /// @param[out] ledColors The vector containing the output
  129. ///
  130. template <typename Pixel_T>
  131. void getMeanLedColorSqrt(const Image<Pixel_T> & image, std::vector<ColorRgb> & ledColors) const
  132. {
  133. if(_colorsMap.size() != ledColors.size())
  134. {
  135. Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size());
  136. return;
  137. }
  138. // Iterate each led and compute the mean
  139. auto led = ledColors.begin();
  140. for (auto colors = _colorsMap.begin(); colors != _colorsMap.end(); ++colors, ++led)
  141. {
  142. const ColorRgb color = calcMeanColorSqrt(image, *colors);
  143. *led = color;
  144. }
  145. }
  146. ///
  147. /// Determines the mean color of the image and assigns it to all LEDs
  148. ///
  149. /// @param[in] image The image from which to extract the led color
  150. ///
  151. /// @return The vector containing the output
  152. ///
  153. template <typename Pixel_T>
  154. std::vector<ColorRgb> getUniLedColor(const Image<Pixel_T> & image) const
  155. {
  156. std::vector<ColorRgb> colors(_colorsMap.size(), ColorRgb{0,0,0});
  157. getUniLedColor(image, colors);
  158. return colors;
  159. }
  160. ///
  161. /// Determines the mean color of the image and assigns it to all LEDs
  162. ///
  163. /// @param[in] image The image from which to extract the LED colors
  164. /// @param[out] ledColors The vector containing the output
  165. ///
  166. template <typename Pixel_T>
  167. void getUniLedColor(const Image<Pixel_T> & image, std::vector<ColorRgb> & ledColors) const
  168. {
  169. if(_colorsMap.size() != ledColors.size())
  170. {
  171. Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size());
  172. return;
  173. }
  174. // calculate uni color
  175. const ColorRgb color = calcMeanColor(image);
  176. //Update all LEDs with same color
  177. std::fill(ledColors.begin(),ledColors.end(), color);
  178. }
  179. ///
  180. /// Determines the dominant color for each LED using the LED area mapping given
  181. /// at construction.
  182. ///
  183. /// @param[in] image The image from which to extract the LED color
  184. ///
  185. /// @return The vector containing the output
  186. ///
  187. template <typename Pixel_T>
  188. std::vector<ColorRgb> getDominantLedColor(const Image<Pixel_T> & image) const
  189. {
  190. std::vector<ColorRgb> colors(_colorsMap.size(), ColorRgb{0,0,0});
  191. getDominantLedColor(image, colors);
  192. return colors;
  193. }
  194. ///
  195. /// Determines the dominant color for each LED using the LED area mapping given
  196. /// at construction.
  197. ///
  198. /// @param[in] image The image from which to extract the LED colors
  199. /// @param[out] ledColors The vector containing the output
  200. ///
  201. template <typename Pixel_T>
  202. void getDominantLedColor(const Image<Pixel_T> & image, std::vector<ColorRgb> & ledColors) const
  203. {
  204. // Sanity check for the number of LEDs
  205. if(_colorsMap.size() != ledColors.size())
  206. {
  207. Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size());
  208. return;
  209. }
  210. // Iterate each led and compute the dominant color
  211. auto led = ledColors.begin();
  212. for (auto colors = _colorsMap.begin(); colors != _colorsMap.end(); ++colors, ++led)
  213. {
  214. const ColorRgb color = calculateDominantColor(image, *colors);
  215. *led = color;
  216. }
  217. }
  218. ///
  219. /// Determines the dominant color using a k-means algorithm for each LED using the LED area mapping given
  220. /// at construction.
  221. ///
  222. /// @param[in] image The image from which to extract the LED color
  223. ///
  224. /// @return The vector containing the output
  225. ///
  226. template <typename Pixel_T>
  227. std::vector<ColorRgb> getDominantLedColorAdv(const Image<Pixel_T> & image) const
  228. {
  229. std::vector<ColorRgb> colors(_colorsMap.size(), ColorRgb{0,0,0});
  230. getDominantLedColorAdv(image, colors);
  231. return colors;
  232. }
  233. ///
  234. /// Determines the dominant color using a k-means algorithm for each LED using the LED area mapping given
  235. /// at construction.
  236. ///
  237. /// @param[in] image The image from which to extract the LED colors
  238. /// @param[out] ledColors The vector containing the output
  239. ///
  240. template <typename Pixel_T>
  241. void getDominantLedColorAdv(const Image<Pixel_T> & image, std::vector<ColorRgb> & ledColors) const
  242. {
  243. // Sanity check for the number of LEDs
  244. if(_colorsMap.size() != ledColors.size())
  245. {
  246. Debug(_log, "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size());
  247. return;
  248. }
  249. // Iterate each led and compute the dominant color
  250. auto led = ledColors.begin();
  251. for (auto colors = _colorsMap.begin(); colors != _colorsMap.end(); ++colors, ++led)
  252. {
  253. const ColorRgb color = calculateDominantColorAdv(image, *colors);
  254. *led = color;
  255. }
  256. }
  257. private:
  258. Logger* _log;
  259. /// The width of the indexed image
  260. const int _width;
  261. /// The height of the indexed image
  262. const int _height;
  263. const int _horizontalBorder;
  264. const int _verticalBorder;
  265. /// Evaluate every "count" pixel
  266. int _nextPixelCount;
  267. /// Number of clusters used during dominant color advanced processing (k-means)
  268. int _clusterCount;
  269. /// The absolute indices into the image for each led
  270. std::vector<std::vector<int>> _colorsMap;
  271. ///
  272. /// Calculates the 'mean color' over the given image. This is the mean over each color-channel
  273. /// (red, green, blue)
  274. ///
  275. /// @param[in] image The image a section from which an average color must be computed
  276. /// @param[in] pixels The list of pixel indices for the given image to be evaluated///
  277. ///
  278. /// @return The mean of the given list of colors (or black when empty)
  279. ///
  280. template <typename Pixel_T>
  281. ColorRgb calcMeanColor(const Image<Pixel_T> & image, const std::vector<int32_t> & pixels) const
  282. {
  283. const auto pixelNum = pixels.size();
  284. if (pixelNum == 0)
  285. {
  286. return ColorRgb::BLACK;
  287. }
  288. // Accumulate the sum of each separate color channel
  289. uint_fast32_t cummRed = 0;
  290. uint_fast32_t cummGreen = 0;
  291. uint_fast32_t cummBlue = 0;
  292. const auto& imgData = image.memptr();
  293. for (const int pixelOffset : pixels)
  294. {
  295. const auto& pixel = imgData[pixelOffset];
  296. cummRed += pixel.red;
  297. cummGreen += pixel.green;
  298. cummBlue += pixel.blue;
  299. }
  300. // Compute the average of each color channel
  301. const uint8_t avgRed = uint8_t(cummRed/pixelNum);
  302. const uint8_t avgGreen = uint8_t(cummGreen/pixelNum);
  303. const uint8_t avgBlue = uint8_t(cummBlue/pixelNum);
  304. // Return the computed color
  305. return {avgRed, avgGreen, avgBlue};
  306. }
  307. ///
  308. /// Calculates the 'mean color' over the given image. This is the mean over each color-channel
  309. /// (red, green, blue)
  310. ///
  311. /// @param[in] image The image a section from which an average color must be computed
  312. ///
  313. /// @return The mean of the given list of colors (or black when empty)
  314. ///
  315. template <typename Pixel_T>
  316. ColorRgb calcMeanColor(const Image<Pixel_T> & image) const
  317. {
  318. // Accumulate the sum of each separate color channel
  319. uint_fast32_t cummRed = 0;
  320. uint_fast32_t cummGreen = 0;
  321. uint_fast32_t cummBlue = 0;
  322. const unsigned pixelNum = image.width() * image.height();
  323. const auto& imgData = image.memptr();
  324. for (unsigned idx=0; idx<pixelNum; idx++)
  325. {
  326. const auto& pixel = imgData[idx];
  327. cummRed += pixel.red;
  328. cummGreen += pixel.green;
  329. cummBlue += pixel.blue;
  330. }
  331. // Compute the average of each color channel
  332. const uint8_t avgRed = uint8_t(cummRed/pixelNum);
  333. const uint8_t avgGreen = uint8_t(cummGreen/pixelNum);
  334. const uint8_t avgBlue = uint8_t(cummBlue/pixelNum);
  335. // Return the computed color
  336. return {avgRed, avgGreen, avgBlue};
  337. }
  338. ///
  339. /// Calculates the 'mean color' squared over the given image. This is the mean over each color-channel
  340. /// (red, green, blue)
  341. ///
  342. /// @param[in] image The image a section from which an average color must be computed
  343. /// @param[in] pixels The list of pixel indices for the given image to be evaluated
  344. ///
  345. /// @return The mean of the given list of colors (or black when empty)
  346. ///
  347. template <typename Pixel_T>
  348. ColorRgb calcMeanColorSqrt(const Image<Pixel_T> & image, const std::vector<int32_t> & pixels) const
  349. {
  350. const auto pixelNum = pixels.size();
  351. if (pixelNum == 0)
  352. {
  353. return ColorRgb::BLACK;
  354. }
  355. // Accumulate the squared sum of each separate color channel
  356. uint_fast32_t cummRed = 0;
  357. uint_fast32_t cummGreen = 0;
  358. uint_fast32_t cummBlue = 0;
  359. const auto& imgData = image.memptr();
  360. for (const int colorOffset : pixels)
  361. {
  362. const auto& pixel = imgData[colorOffset];
  363. cummRed += pixel.red * pixel.red;
  364. cummGreen += pixel.green * pixel.green;
  365. cummBlue += pixel.blue * pixel.blue;
  366. }
  367. // Compute the average of each color channel
  368. #ifdef WIN32
  369. #undef min
  370. #endif
  371. const uint8_t avgRed = static_cast<uint8_t>(std::min(std::lround(std::sqrt(static_cast<double>(cummRed / pixelNum))), 255L));
  372. const uint8_t avgGreen = static_cast<uint8_t>(std::min(std::lround(sqrt(static_cast<double>(cummGreen / pixelNum))), 255L));
  373. const uint8_t avgBlue = static_cast<uint8_t>(std::min(std::lround(sqrt(static_cast<double>(cummBlue / pixelNum))), 255L));
  374. // Return the computed color
  375. return {avgRed, avgGreen, avgBlue};
  376. }
  377. ///
  378. /// Calculates the 'mean color' squared over the given image. This is the mean over each color-channel
  379. /// (red, green, blue)
  380. ///
  381. /// @param[in] image The image a section from which an average color must be computed
  382. ///
  383. /// @return The mean of the given list of colors (or black when empty)
  384. ///
  385. template <typename Pixel_T>
  386. ColorRgb calcMeanColorSqrt(const Image<Pixel_T> & image) const
  387. {
  388. // Accumulate the squared sum of each separate color channel
  389. uint_fast32_t cummRed = 0;
  390. uint_fast32_t cummGreen = 0;
  391. uint_fast32_t cummBlue = 0;
  392. const unsigned pixelNum = image.width() * image.height();
  393. const auto& imgData = image.memptr();
  394. for (int idx=0; idx<pixelNum; ++idx)
  395. {
  396. const auto& pixel = imgData[idx];
  397. cummRed += pixel.red * pixel.red;
  398. cummGreen += pixel.green * pixel.green;
  399. cummBlue += pixel.blue * pixel.blue;
  400. }
  401. // Compute the average of each color channel
  402. const uint8_t avgRed = uint8_t(std::lround(sqrt(static_cast<double>(cummRed/pixelNum))));
  403. const uint8_t avgGreen = uint8_t(std::lround(sqrt(static_cast<double>(cummGreen/pixelNum))));
  404. const uint8_t avgBlue = uint8_t(std::lround(sqrt(static_cast<double>(cummBlue/pixelNum))));
  405. // Return the computed color
  406. return {avgRed, avgGreen, avgBlue};
  407. }
  408. ///
  409. /// Calculates the 'dominant color' of an image area defined by a list of pixel indices
  410. ///
  411. /// @param[in] image The image for which a dominant color is to be computed
  412. /// @param[in] pixels The list of pixel indices for the given image to be evaluated
  413. ///
  414. /// @return The image area's dominant color or black, if no pixel indices provided
  415. ///
  416. template <typename Pixel_T>
  417. ColorRgb calculateDominantColor(const Image<Pixel_T> & image, const std::vector<int> & pixels) const
  418. {
  419. ColorRgb dominantColor {ColorRgb::BLACK};
  420. const auto pixelNum = pixels.size();
  421. if (pixelNum > 0)
  422. {
  423. const auto& imgData = image.memptr();
  424. QMap<QRgb,int> colorDistributionMap;
  425. int count = 0;
  426. for (const int pixelOffset : pixels)
  427. {
  428. QRgb color = imgData[pixelOffset].rgb();
  429. if (colorDistributionMap.contains(color)) {
  430. colorDistributionMap[color] = colorDistributionMap[color] + 1;
  431. }
  432. else {
  433. colorDistributionMap[color] = 1;
  434. }
  435. int colorsFound = colorDistributionMap[color];
  436. if (colorsFound > count) {
  437. dominantColor.setRgb(color);
  438. count = colorsFound;
  439. }
  440. }
  441. }
  442. return dominantColor;
  443. }
  444. ///
  445. /// Calculates the 'dominant color' of an image
  446. ///
  447. /// @param[in] image The image for which a dominant color is to be computed
  448. ///
  449. /// @return The image's dominant color
  450. ///
  451. template <typename Pixel_T>
  452. ColorRgb calculateDominantColor(const Image<Pixel_T> & image) const
  453. {
  454. const unsigned pixelNum = image.width() * image.height();
  455. std::vector<int> pixels(pixelNum);
  456. std::iota(pixels.begin(), pixels.end(), 0);
  457. return calculateDominantColor(image, pixels);
  458. }
  459. template <typename Pixel_T>
  460. struct ColorCluster {
  461. ColorCluster():count(0) {}
  462. ColorCluster(Pixel_T color):count(0),color(color) {}
  463. Pixel_T color;
  464. Pixel_T newColor;
  465. int count;
  466. };
  467. const ColorRgb DEFAULT_CLUSTER_COLORS[5] {
  468. {ColorRgb::BLACK},
  469. {ColorRgb::GREEN},
  470. {ColorRgb::WHITE},
  471. {ColorRgb::RED},
  472. {ColorRgb::YELLOW}
  473. };
  474. ///
  475. /// Calculates the 'dominant color' of an image area defined by a list of pixel indices
  476. /// using a k-means algorithm (https://robocraft.ru/computervision/1063)
  477. ///
  478. /// @param[in] image The image for which a dominant color is to be computed
  479. /// @param[in] pixels The list of pixel indices for the given image to be evaluated
  480. ///
  481. /// @return The image area's dominant color or black, if no pixel indices provided
  482. ///
  483. template <typename Pixel_T>
  484. ColorRgb calculateDominantColorAdv(const Image<Pixel_T> & image, const std::vector<int> & pixels) const
  485. {
  486. ColorRgb dominantColor {ColorRgb::BLACK};
  487. const auto pixelNum = pixels.size();
  488. if (pixelNum > 0)
  489. {
  490. // initial cluster with different colors
  491. auto clusters = std::unique_ptr< ColorCluster<ColorRgbScalar> >(new ColorCluster<ColorRgbScalar>[_clusterCount]);
  492. for(int k = 0; k < _clusterCount; ++k)
  493. {
  494. clusters.get()[k].newColor = DEFAULT_CLUSTER_COLORS[k];
  495. }
  496. // k-means
  497. double min_rgb_euclidean {0};
  498. double old_rgb_euclidean {0};
  499. while(1)
  500. {
  501. for(int k = 0; k < _clusterCount; ++k)
  502. {
  503. clusters.get()[k].count = 0;
  504. clusters.get()[k].color = clusters.get()[k].newColor;
  505. clusters.get()[k].newColor.setRgb(ColorRgb::BLACK);
  506. }
  507. const auto& imgData = image.memptr();
  508. for (const int pixelOffset : pixels)
  509. {
  510. const auto& pixel = imgData[pixelOffset];
  511. min_rgb_euclidean = 255 * 255 * 255;
  512. int clusterIndex = -1;
  513. for(int k = 0; k < _clusterCount; ++k)
  514. {
  515. double euclid = ColorSys::rgb_euclidean(ColorRgbScalar(pixel), clusters.get()[k].color);
  516. if( euclid < min_rgb_euclidean ) {
  517. min_rgb_euclidean = euclid;
  518. clusterIndex = k;
  519. }
  520. }
  521. clusters.get()[clusterIndex].count++;
  522. clusters.get()[clusterIndex].newColor += ColorRgbScalar(pixel);
  523. }
  524. min_rgb_euclidean = 0;
  525. for(int k = 0; k < _clusterCount; ++k)
  526. {
  527. if (clusters.get()[k].count > 0)
  528. {
  529. // new color
  530. clusters.get()[k].newColor /= clusters.get()[k].count;
  531. double ecli = ColorSys::rgb_euclidean(clusters.get()[k].newColor, clusters.get()[k].color);
  532. if(ecli > min_rgb_euclidean)
  533. {
  534. min_rgb_euclidean = ecli;
  535. }
  536. }
  537. }
  538. if( fabs(min_rgb_euclidean - old_rgb_euclidean) < 1)
  539. {
  540. break;
  541. }
  542. old_rgb_euclidean = min_rgb_euclidean;
  543. }
  544. int colorsFoundMax = 0;
  545. int dominantClusterIdx {0};
  546. for(int clusterIdx=0; clusterIdx < _clusterCount; ++clusterIdx){
  547. int colorsFoundinCluster = clusters.get()[clusterIdx].count;
  548. if (colorsFoundinCluster > colorsFoundMax) {
  549. colorsFoundMax = colorsFoundinCluster;
  550. dominantClusterIdx = clusterIdx;
  551. }
  552. }
  553. dominantColor.red = static_cast<uint8_t>(clusters.get()[dominantClusterIdx].newColor.red);
  554. dominantColor.green = static_cast<uint8_t>(clusters.get()[dominantClusterIdx].newColor.green);
  555. dominantColor.blue = static_cast<uint8_t>(clusters.get()[dominantClusterIdx].newColor.blue);
  556. }
  557. return dominantColor;
  558. }
  559. ///
  560. /// Calculates the 'dominant color' of an image area defined by a list of pixel indices
  561. /// using a k-means algorithm (https://robocraft.ru/computervision/1063)
  562. ///
  563. /// @param[in] image The image for which a dominant color is to be computed
  564. ///
  565. /// @return The image's dominant color
  566. ///
  567. template <typename Pixel_T>
  568. ColorRgb calculateDominantColorAdv(const Image<Pixel_T> & image) const
  569. {
  570. const unsigned pixelNum = image.width() * image.height();
  571. std::vector<int> pixels(pixelNum);
  572. std::iota(pixels.begin(), pixels.end(), 0);
  573. return calculateDominantColorAdv(image, pixels);
  574. }
  575. };
  576. } // end namespace hyperion
  577. #endif // IMAGETOLEDSMAP_H