Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpHistogram.h
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Gray level histogram manipulation.
32 */
33
40
41#ifndef VP_HISTOGRAM_H
42#define VP_HISTOGRAM_H
43
44#include <sstream>
45
46#include <visp3/core/vpConfig.h>
47#include <visp3/core/vpColor.h>
48#include <visp3/core/vpHistogramPeak.h>
49#include <visp3/core/vpHistogramValey.h>
50#include <visp3/core/vpImage.h>
51
52#include <list>
53#if defined(VISP_HAVE_THREADS)
54#include <thread>
55#endif
56
108class VISP_EXPORT vpHistogram
109{
110public:
111 vpHistogram(const unsigned int &size = 256);
112 vpHistogram(const vpHistogram &h);
113 VP_EXPLICIT vpHistogram(const vpImage<unsigned char> &I);
114 VP_EXPLICIT vpHistogram(const vpImage<unsigned char> &I, const vpImage<bool> *p_mask);
115 virtual ~vpHistogram();
116
118
139 inline unsigned operator[](const unsigned char level) const
140 {
141 if (level < m_size) {
142 return m_histogram[level];
143 }
144
145 std::stringstream ss;
146 ss << "Level is > to size (" << m_size << ") !";
147 throw vpException(vpException::dimensionError, ss.str().c_str());
148 }
149
169 inline unsigned operator()(const unsigned char level) const
170 {
171 if (level < m_size) {
172 return m_histogram[level];
173 }
174
175 std::stringstream ss;
176 ss << "Level is > to size (" << m_size << ") !";
177 throw vpException(vpException::dimensionError, ss.str().c_str());
178 }
179
199 inline unsigned get(const unsigned char level) const
200 {
201 if (level < m_size) {
202 return m_histogram[level];
203 }
204
205 std::stringstream ss;
206 ss << "Level is > to size (" << m_size << ") !";
207 throw vpException(vpException::dimensionError, ss.str().c_str());
208 }
209
227 inline void set(const unsigned char level, unsigned int value)
228 {
229 if (level < m_size) {
230 m_histogram[level] = value;
231 }
232 else {
233 std::stringstream ss;
234 ss << "Level is > to size (" << m_size << ") !";
235 throw vpException(vpException::dimensionError, ss.str().c_str());
236 }
237 }
238
249 inline void setMask(const vpImage<bool> *p_mask)
250 {
251 mp_mask = p_mask;
252 }
253
254 void calculate(const vpImage<unsigned char> &I, unsigned int nbins = 256, unsigned int nbThreads = 1);
255
256#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
257 template <typename ArithmeticType>
258 typename std::enable_if<std::is_floating_point<ArithmeticType>::value, void>::type calculate(const vpImage<ArithmeticType> &I, const ArithmeticType &minVal, const ArithmeticType &maxVal, ArithmeticType &widthBin, unsigned int nbins = 256, unsigned int nbThreads = 1)
259 {
260 widthBin = (maxVal - minVal)/static_cast<ArithmeticType>(nbins);
261 if (m_size < nbins) {
262 init(nbins);
263 }
264
265 memset(m_histogram, 0, m_size * sizeof(unsigned int));
266
267 bool use_single_thread;
268#if !defined(VISP_HAVE_THREADS)
269 use_single_thread = true;
270#else
271 use_single_thread = (nbThreads == 0 || nbThreads == 1);
272#endif
273
274 if ((!use_single_thread) && (I.getSize() <= nbThreads)) {
275 use_single_thread = true;
276 }
277
278 if (use_single_thread) {
279 // Single thread
280 const bool alwaysTrue = true;
281 const bool *ptrMaskCurrent = &alwaysTrue;
282 if (mp_mask) {
283 ptrMaskCurrent = static_cast<const bool *>(mp_mask->bitmap);
284 }
285
286 unsigned int size_ = I.getWidth() * I.getHeight();
287 unsigned int idCurrent = 0;
288
289 m_total = 0;
290 while (idCurrent < size_) {
291 if (*ptrMaskCurrent) {
292 unsigned int id = static_cast<unsigned int>(std::floor((I.bitmap[idCurrent] - minVal)/widthBin));
293 ++m_histogram[id];
294 ++m_total;
295 }
296 ++idCurrent;
297 if (mp_mask) {
298 ++ptrMaskCurrent;
299 }
300 }
301 }
302 else {
303#if defined(VISP_HAVE_THREADS)
304 // Multi-threads
305 std::vector<std::thread *> threadpool;
306 std::vector<vpHistogramFloatingPoints_Param_t<ArithmeticType> *> histogramParams;
307
308 unsigned int image_size = I.getSize();
309 unsigned int step = image_size / nbThreads;
310 unsigned int last_step = image_size - step * (nbThreads - 1);
311
312 for (unsigned int index = 0; index < nbThreads; ++index) {
313 unsigned int start_index = index * step;
314 unsigned int end_index = (index + 1) * step;
315
316 if (index == nbThreads - 1) {
317 end_index = start_index + last_step;
318 }
319
320 vpHistogramFloatingPoints_Param_t<ArithmeticType> *histogram_param = new vpHistogramFloatingPoints_Param_t<ArithmeticType>(start_index, end_index, minVal, widthBin, &I, mp_mask);
321 histogram_param->m_histogram = new unsigned int[m_size];
322 histogram_param->m_mask = mp_mask;
323 memset(histogram_param->m_histogram, 0, m_size * sizeof(unsigned int));
324
325 histogramParams.push_back(histogram_param);
326
327 // Start the threads
328 std::thread *histogram_thread = new std::thread(&computeHistogramFloatingPointThread<ArithmeticType>, histogram_param);
329 threadpool.push_back(histogram_thread);
330 }
331
332 for (size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
333 // Wait until thread ends up
334 threadpool[cpt]->join();
335 }
336
337 m_total = 0;
338 for (unsigned int cpt1 = 0; cpt1 < m_size; ++cpt1) {
339 unsigned int sum = 0;
340
341 for (size_t cpt2 = 0; cpt2 < histogramParams.size(); ++cpt2) {
342 sum += histogramParams[cpt2]->m_histogram[cpt1];
343 }
344
345 m_histogram[cpt1] = sum;
346 m_total += sum;
347 }
348
349 // Delete
350 for (size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
351 delete threadpool[cpt];
352 }
353
354 for (size_t cpt = 0; cpt < histogramParams.size(); ++cpt) {
355 delete histogramParams[cpt];
356 }
357#endif
358 }
359 }
360#endif
361
362 void equalize(const vpImage<unsigned char> &I, vpImage<unsigned char> &Iout);
363
364 void display(const vpImage<unsigned char> &I, const vpColor &color = vpColor::white, unsigned int thickness = 2,
365 unsigned int maxValue_ = 0);
366
367 void smooth(unsigned int fsize = 3);
368 unsigned getPeaks(std::list<vpHistogramPeak> &peaks);
369 unsigned getPeaks(unsigned char dist, vpHistogramPeak &peak1, vpHistogramPeak &peak2);
370 bool getPeaks(unsigned char dist, vpHistogramPeak &peakl, vpHistogramPeak &peakr, vpHistogramValey &valey);
371 unsigned getValey(std::list<vpHistogramValey> &valey);
372 bool getValey(const vpHistogramPeak &peak1, const vpHistogramPeak &peak2, vpHistogramValey &valey);
373 unsigned getValey(unsigned char dist, const vpHistogramPeak &peak, vpHistogramValey &valeyl,
374 vpHistogramValey &valeyr);
375 unsigned sort(std::list<vpHistogramPeak> &peaks);
376
377 bool write(const std::string &filename);
378 bool write(const char *filename);
379
388 inline unsigned getSize() const { return m_size; }
389
411 inline unsigned *getValues() { return m_histogram; }
412
418 inline unsigned int getTotal() { return m_total; }
419
420private:
421#if defined(VISP_HAVE_THREADS) && (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
422
423#ifndef DOXYGEN_SHOULD_SKIP_THIS
424 template <typename ArithmeticType>
425 struct vpHistogramFloatingPoints_Param_t
426 {
427 unsigned int m_start_index;
428 unsigned int m_end_index;
429
430 unsigned int *m_histogram;
431 const ArithmeticType m_minVal;
432 const ArithmeticType m_step;
433 const vpImage<ArithmeticType> *m_I;
434 const vpImage<bool> *m_mask;
435
436 vpHistogramFloatingPoints_Param_t() : m_start_index(0), m_end_index(0), m_histogram(nullptr), m_minVal(0.), m_step(1.), m_I(nullptr), m_mask(nullptr) { }
437
438 vpHistogramFloatingPoints_Param_t(unsigned int start_index, unsigned int end_index, const ArithmeticType &minVal, const ArithmeticType &step, const vpImage<ArithmeticType> *const I, const vpImage<bool> *const mask)
439 : m_start_index(start_index), m_end_index(end_index), m_histogram(nullptr), m_minVal(minVal), m_step(step), m_I(I), m_mask(mask)
440 { }
441
442 ~vpHistogramFloatingPoints_Param_t()
443 {
444 if (m_histogram != nullptr) {
445 delete[] m_histogram;
446 }
447 }
448 };
449
450 template <typename ArithmeticType>
451 static typename std::enable_if<std::is_floating_point<ArithmeticType>::value, void>::type computeHistogramFloatingPointThread(vpHistogramFloatingPoints_Param_t<ArithmeticType> *histogram_param)
452 {
453 unsigned int start_index = histogram_param->m_start_index;
454 unsigned int end_index = histogram_param->m_end_index;
455 unsigned int stopUnroll = end_index - 8;
456 unsigned int current_index = start_index;
457
458 const vpImage<ArithmeticType> *I = histogram_param->m_I;
459
460 // Compute the index of a floating point value according to the min and step
461 const ArithmeticType &minVal = histogram_param->m_minVal;
462 const ArithmeticType &step = histogram_param->m_step;
463
464 auto computeIndex = [&minVal, &step](const ArithmeticType &val) {
465 return static_cast<unsigned int> (std::floor((val - minVal)/step));
466 };
467
468 const bool alwaysTrue = true;
469 const bool *ptrMaskCurrent = &alwaysTrue;
470 if (histogram_param->m_mask) {
471 ptrMaskCurrent = (const bool *)histogram_param->m_mask->bitmap + start_index;
472 }
473
474 if (end_index >= 8 + start_index) {
475 // Unroll loop version
476 while (current_index <= stopUnroll) {
477 if (*ptrMaskCurrent) {
478 unsigned int id = computeIndex(I->bitmap[current_index]);
479 histogram_param->m_histogram[id]++;
480 }
481 ++current_index;
482 if (histogram_param->m_mask != nullptr) {
483 ++ptrMaskCurrent;
484 }
485
486 if (*ptrMaskCurrent) {
487 unsigned int id = computeIndex(I->bitmap[current_index]);
488 histogram_param->m_histogram[id]++;
489 }
490 ++current_index;
491 if (histogram_param->m_mask != nullptr) {
492 ++ptrMaskCurrent;
493 }
494
495 if (*ptrMaskCurrent) {
496 unsigned int id = computeIndex(I->bitmap[current_index]);
497 histogram_param->m_histogram[id]++;
498 }
499 ++current_index;
500 if (histogram_param->m_mask != nullptr) {
501 ++ptrMaskCurrent;
502 }
503
504 if (*ptrMaskCurrent) {
505 unsigned int id = computeIndex(I->bitmap[current_index]);
506 histogram_param->m_histogram[id]++;
507 }
508 ++current_index;
509 if (histogram_param->m_mask != nullptr) {
510 ++ptrMaskCurrent;
511 }
512
513 if (*ptrMaskCurrent) {
514 unsigned int id = computeIndex(I->bitmap[current_index]);
515 histogram_param->m_histogram[id]++;
516 }
517 ++current_index;
518 if (histogram_param->m_mask != nullptr) {
519 ++ptrMaskCurrent;
520 }
521
522 if (*ptrMaskCurrent) {
523 unsigned int id = computeIndex(I->bitmap[current_index]);
524 histogram_param->m_histogram[id]++;
525 }
526 ++current_index;
527 if (histogram_param->m_mask != nullptr) {
528 ++ptrMaskCurrent;
529 }
530
531 if (*ptrMaskCurrent) {
532 unsigned int id = computeIndex(I->bitmap[current_index]);
533 histogram_param->m_histogram[id]++;
534 }
535 ++current_index;
536 if (histogram_param->m_mask != nullptr) {
537 ++ptrMaskCurrent;
538 }
539
540 if (*ptrMaskCurrent) {
541 unsigned int id = computeIndex(I->bitmap[current_index]);
542 histogram_param->m_histogram[id]++;
543 }
544 ++current_index;
545 if (histogram_param->m_mask != nullptr) {
546 ++ptrMaskCurrent;
547 }
548 }
549 }
550
551 while (current_index < end_index) {
552 if (*ptrMaskCurrent) {
553 unsigned int id = computeIndex(I->bitmap[current_index]);
554 histogram_param->m_histogram[id]++;
555 }
556 if (histogram_param->m_mask != nullptr) {
557 ++ptrMaskCurrent;
558 }
559 ++current_index;
560 }
561 }
562#endif // DOXYGEN_SHOULD_SKIP_THIS
563#endif
564
565 void init(unsigned size = 256);
566
567 unsigned int *m_histogram;
568 unsigned m_size;
569 const vpImage<bool> *mp_mask;
570 unsigned int m_total;
571 static const unsigned int constr_val_256;
572};
573END_VISP_NAMESPACE
574#endif
Class to define RGB colors available for display functionalities.
Definition vpColor.h:157
static const vpColor white
Definition vpColor.h:193
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ dimensionError
Bad dimension.
Definition vpException.h:71
Declaration of the peak (maximum value) in a gray level image histogram.
Declaration of the valey (minimum value) in a gray level image histogram.
unsigned * getValues()
unsigned int getTotal()
Get the total number of pixels in the input image.
vpHistogram & operator=(const vpHistogram &h)
unsigned operator()(const unsigned char level) const
unsigned getSize() const
unsigned operator[](const unsigned char level) const
void set(const unsigned char level, unsigned int value)
std::enable_if< std::is_floating_point< ArithmeticType >::value, void >::type calculate(const vpImage< ArithmeticType > &I, const ArithmeticType &minVal, const ArithmeticType &maxVal, ArithmeticType &widthBin, unsigned int nbins=256, unsigned int nbThreads=1)
void setMask(const vpImage< bool > *p_mask)
Set a mask to ignore pixels for which the mask is false.
vpHistogram(const unsigned int &size=256)
unsigned get(const unsigned char level) const
Definition of the vpImage class member functions.
Definition vpImage.h:131
Type * bitmap
points toward the bitmap
Definition vpImage.h:135