PICCANTE  0.4
The hottest HDR imaging library!
histogram.hpp
Go to the documentation of this file.
1 /*
2 
3 PICCANTE
4 The hottest HDR imaging library!
5 http://vcg.isti.cnr.it/piccante
6 
7 Copyright (C) 2014
8 Visual Computing Laboratory - ISTI CNR
9 http://vcg.isti.cnr.it
10 First author: Francesco Banterle
11 
12 This Source Code Form is subject to the terms of the Mozilla Public
13 License, v. 2.0. If a copy of the MPL was not distributed with this
14 file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 
16 */
17 
18 #ifndef PIC_HISTOGRAM_HPP
19 #define PIC_HISTOGRAM_HPP
20 
21 #include "image.hpp"
22 #include "base.hpp"
23 
24 #include "util/bbox.hpp"
25 #include "util/std_util.hpp"
26 #include "util/array.hpp"
27 #include "util/math.hpp"
28 
29 namespace pic {
30 
32 
37 class Histogram
38 {
39 protected:
40  float *bin_c;
41  float *bin_nor;
42  int nBin;
44  float fMin, fMax;
46  float epsilon;
47 
53  inline float projectDomain(float x)
54  {
55  switch(type) {
56  case VS_LOG_2: {
57  return logf(x + epsilon) * C_INV_LOG_NAT_2;
58  }
59  break;
60 
61  case VS_LOG_E: {
62  return logf(x + epsilon);
63  }
64  break;
65 
66  case VS_LOG_10: {
67  return log10f(x + epsilon);
68  }
69  break;
70 
71  default: {
72  return x;
73  } break;
74  }
75 
76  return x;
77  }
78 
84  inline float unprojectDomain(float x)
85  {
86  switch(type) {
87  case VS_LOG_2: {
88  return powf(2.0f, x) - epsilon;
89  }
90  break;
91 
92  case VS_LOG_E: {
93  return expf(x) - epsilon;
94  }
95  break;
96 
97  case VS_LOG_10: {
98  return powf(10.0f, x) - epsilon;
99  }
100  break;
101 
102  default: {
103  return x;
104  }
105  break;
106  }
107 
108  return x;
109  }
110 
115  inline void update(float x)
116  {
117  float val = projectDomain(x);
118 
119  int indx = int(((val - fMin) * nBinf) / deltaMaxMin);
120 
121  #ifdef PIC_DEBUG
122  if((indx >= nBin) || (indx < 0)) {
123  printf("Error in Calculate %d.\n",indx);
124  }
125  #endif
126 
127  bin[CLAMP(indx, nBin)]++;
128  }
129 
130 public:
132 
137  {
138  bin = NULL;
139  bin_nor = NULL;
140  bin_c = NULL;
141  bin_work = NULL;
142 
143  nBin = 0;
144  type = VS_LIN;
145  fMin = -FLT_MAX;
146  fMax = FLT_MAX;
147 
148  epsilon = 1e-6f;
149  }
150 
159  Histogram(Image *imgIn, VALUE_SPACE type, int nBin, int channel = 0)
160  {
161  bin = NULL;
162  bin_nor = NULL;
163  bin_c = NULL;
164  bin_work = NULL;
165 
166  fMin = -FLT_MAX;
167  fMax = FLT_MAX;
168 
169  epsilon = 1e-6f;
170  this->nBin = 0;
171 
172  calculate(imgIn, type, nBin, NULL, channel);
173  }
174 
179  {
180  release();
181 
182  nBin = 0;
183  type = VS_LIN;
184  fMin = -FLT_MAX;
185  fMax = FLT_MAX;
186  }
187 
191  void release()
192  {
193  bin = delete_vec_s(bin);
197  }
198 
213  void calculate(Image *imgIn, VALUE_SPACE type = VS_LIN, int nBin = 256,
214  BBox *box = NULL, int channel = 0)
215  {
216  if((imgIn == NULL) || (channel < 0) ) {
217  uniform(0.0f, 1.0f, 1, type, nBin);
218  return;
219  }
220 
221  if(!imgIn->isValid() || (channel >= imgIn->channels)) {
222  uniform(0.0f, 1.0f, 1, type, nBin);
223  return;
224  }
225 
226  if(nBin < 1 || type == VS_LDR) {
227  nBin = 256;
228  }
229 
230  bool c1 = (nBin != this->nBin) && (bin != NULL);
231  bool c2 = (bin == NULL);
232  if(c1 || c2) {
233  release();
234 
235  bin = new uint[nBin];
236  memset((void *)bin, 0, nBin * sizeof(uint));
237  } else {
238  memset((void *)bin, 0, nBin * sizeof(uint));
239  }
240 
241  this->nBin = nBin;
242  this->type = type;
243 
244  int size = imgIn->width * imgIn->height * imgIn->channels;
245  int channels = imgIn->channels;
246 
247  //compute statistics
248  fMin = FLT_MAX;
249  fMax = -FLT_MAX;
250 
251  if(box == NULL) {
252  for(int i = channel; i < size; i += channels) {
253  float val = imgIn->data[i];
254  fMin = MIN(fMin, val);
255  fMax = MAX(fMax, val);
256  }
257  } else {
258  for(int k = box->z0; k < box->z1; k++) {
259  for(int j = box->y0; j < box->y1; j++) {
260  for(int i = box->x0; i < box->x1; i++) {
261  float *tmp_data = (*imgIn)(i, j, k);
262  fMin = MIN(fMin, tmp_data[channel]);
263  fMax = MAX(fMax, tmp_data[channel]);
264  }
265  }
266  }
267  }
268 
271 
272  deltaMaxMin = (fMax - fMin);
273  nBinf = float(nBin - 1);
274 
275  //compute the histogram
276  if(box == NULL) {
277  for(int i = channel; i < size; i += channels) {
278  update(imgIn->data[i]);
279  }
280  } else {
281  for(int k = box->z0; k < box->z1; k++) {
282  for(int j = box->y0; j < box->y1; j++) {
283  for(int i = box->x0; i < box->x1; i++) {
284  float *tmp_data = (*imgIn)(i, j, k);
285  update(tmp_data[channel]);
286  }
287  }
288  }
289  }
290  }
291 
298  void uniform(float fMin, float fMax, uint value, VALUE_SPACE type, int nBin)
299  {
300  bool c1 = (nBin != this->nBin) && (bin != NULL);
301  bool c2 = (bin == NULL);
302  if(c1 || c2) {
303  release();
304 
305  bin = new uint[nBin];
306  }
307 
308  this->nBin = nBin;
309  this->type = type;
310 
311  memset((void *)bin, value, nBin * sizeof(uint));
312 
313  nBinf = float(nBin - 1);
314 
315  this->fMin = fMin;
316  this->fMax = fMax;
317  deltaMaxMin = (fMax - fMin);
318  }
319 
325  void update(float fMin, float fMax)
326  {
327  this->fMin = projectDomain(fMin);
328  this->fMax = projectDomain(fMax);
329  deltaMaxMin = (fMax - fMin);
330  }
331 
337  int project(float x)
338  {
339  if(deltaMaxMin > 0.0f) {
340  float y = projectDomain(x);
341  return int(((y - fMin) * nBinf) / deltaMaxMin);
342  } else {
343  return 0.5f;
344  }
345  }
346 
352  float unproject(int ind)
353  {
354  float indf = float(ind);
355  float y = ((indf * deltaMaxMin) / nBinf) + fMin;
356  return unprojectDomain(y);
357  }
358 
364  void ceiling(float k)
365  {
366  float tolerance = float(Array<uint>::sum(bin, nBin)) * 0.025f;
367  int trimmings = 0;
368  bool bFlag = true;
369 
370  std::vector<bool> trimmed_vec;
371 
372  while((trimmings <= tolerance) && bFlag) {
373  trimmings = 0;
374  float T = float(Array<uint>::sum(bin, nBin));
375 
376  if(T < tolerance) {
377  bFlag = false;
378  } else {
379  bool bTrimmed = false;
380  uint ceiling = uint(T * k);
381 
382  for(int i = 0; i < nBin; i++) {
383  if(bin[i] > ceiling) {
384  trimmings += (bin[i] - ceiling);
385  bin[i] = ceiling;
386  bTrimmed = true;
387  }
388  }
389 
390  trimmed_vec.push_back(bTrimmed);
391 
392  }
393 
394  int tvSize = int(trimmed_vec.size());
395  if(tvSize >= 2) {
396  bool b0 = !trimmed_vec[tvSize - 1];
397  bool b1 = !trimmed_vec[tvSize - 2];
398  if(b0 && b1) {
399  bFlag = false;
400  }
401  }
402  }
403  }
404 
409  void clip(uint value)
410  {
411  int redistrib = 0;
412  for(int i = 0; i < nBin; i++) {
413  if(bin[i] > value) {
414  redistrib += bin[i] - value + 1;
415  bin[i] = value;
416  }
417  }
418 
419  int nCount = redistrib / nBin;
420 
421  for(int i = 0; i < nCount; i++) {
422  for(int j = 0; j < nBin; j++) {
423  bin[j]++;
424  }
425  }
426 
427  int remainder = redistrib % nBin;
428 
429  for(int i =0; i < remainder; i++) {
430  bin[rand() % nBin]++;
431  }
432  }
433 
440  float *cumulativef(bool bNormalized)
441  {
442  getNormalized();
443 
445 
446  if(bNormalized) {
447  Arrayf::div(bin_c, nBin, bin_c[nBin - 1]);
448  }
449 
450  return bin_c;
451  }
452 
459  float *getCumulativef()
460  {
461  return bin_c;
462  }
463 
468  float getfMin()
469  {
470  return fMin;
471  }
472 
473 
478  float getfMax()
479  {
480  return fMax;
481  }
482 
487  float *getNormalized(bool bNor = true)
488  {
489  if(bin_nor == NULL) {
490  bin_nor = new float[nBin];
491  }
492 
493  int ind;
494  float maxValf;
495  if(bNor) {
496  maxValf = float(Array<uint>::getMax(bin, nBin, ind));
497  } else {
498  maxValf = float(Array<uint>::sum(bin, nBin));
499  }
500 
501  if(maxValf > 0.0f) {
502  for(int i = 0; i < nBin; i++) {
503  bin_nor[i] = float(bin[i]) / maxValf;
504  }
505  } else {
506  Arrayf::assign(0.0f, bin_nor, nBin);
507  }
508 
509  return bin_nor;
510  }
511 
516  float getOtsu()
517  {
518  float *pdf = getNormalized(false);
519 
520  float w0 = 0.0f;
521  float w1 = 1.0f;
522  float mu0 = 0.0f;
523  float mu1 = 0.0f;
524  int index = 0;
525  for(int i = 0; i < nBin; i++) {
526  mu1 += unproject(i) * pdf[i];
527  }
528 
529  float sigma_b_max = 0.0f;
530  for(int i = 1; i < nBin; i++) {
531 
532  w0 += pdf[i];
533  w1 -= pdf[i];
534 
535  float tmp = unproject(i) * pdf[i];
536  mu0 += tmp;
537  mu1 -= tmp;
538 
539  if(w0 > 0.0f && w1 > 0.0f) {
540  float delta = (mu0 / w0) - (mu1 / w1);
541  float sigma_b = w0 * w1 * delta * delta;
542 
543  if(sigma_b > sigma_b_max) {
544  sigma_b_max = sigma_b;
545  index = i;
546  }
547  }
548  }
549 
550  return unproject(index);
551  }
552 
558  void write(std::string name, bool bNor)
559  {
560  Image img(1, nBin, 1, 1);
561 
562  if(bNor) {
563  getNormalized();
564  memcpy(img.data, bin_nor, sizeof(float) * nBin);
565  } else {
566  for(int i = 0; i < nBin; i++) {
567  img.data[i] = float(bin[i]);
568  }
569  }
570 
571  img.Write(name, LT_NONE);
572  }
573 
585  std::vector< float > exposureCovering(int nBits = 8, float overlap = 1.0f)
586  {
587  std::vector< float > ret;
588 
589  if(type != VS_LOG_2) {
590  #ifdef PIC_DEBUG
591  printf("ERROR in ExposureCovering: this histogram has to be in log2!\n");
592  #endif
593 
594  return ret;
595  }
596 
597  float dMM = deltaMaxMin / nBinf;
598 
599  int removingBins = int(float(nBits) /dMM + overlap);
600 
601  if( bin_work == NULL) {
602  bin_work = new uint [nBin];
603  }
604 
605  memcpy(bin_work, bin, sizeof(uint) * nBin);
606 
607  int countIndex = 0;
608  while(Array<uint>::sum(bin_work, nBin) > 0) {
609 
610 
611  int count = -1;
612  int index = 0;
613 
614  for(int i = 0; i < (nBin - removingBins); i++) {
615  int tmpCount = 0;
616 
617  for(int j = i; j < (i + removingBins); j++) {
618  tmpCount += bin_work[j];
619  }
620 
621  if(tmpCount > count) {
622  count = tmpCount;
623  index = i;
624  }
625  }
626 
627  if(index == 0) {
628  countIndex++;
629  }
630 
631  if(countIndex > 2) {
632  break;
633  }
634 
635  for(int j = index; j < (index + removingBins); j++) {
636  bin_work[j] = 0;
637  }
638 
639  float fstop = (float(index + removingBins) * dMM) + fMin;
640 
641 
642  /*
643  int ind;
644  Array<uint>::getMax(bin_work, nBin, ind);
645 
646  int indMin = MAX(ind - removingBins_half, 0);
647  int indMax = MIN(ind + removingBins_half, nBin);
648 
649  for(int i = indMin; i < indMax; i++) {
650  bin_work[i] = 0;
651  }
652 
653  float fstop = -float(ind - removingBins_half) * dMM + fMin;*/
654 
655  printf("%f\n", fstop);
656  ret.push_back(fstop);
657 
658  }
659 
660  return ret;
661  }
662 
669  float getBestExposure(int nBits, float overlap = 0.5f)
670  {
671  if(overlap < 0.0f) {
672  overlap = 0.5f;
673  }
674 
675  float nBits_f = float(nBits);
676  if((type != VS_LOG_2) && (nBits_f > deltaMaxMin) && (nBits < 1)){
677  return 0.0f;
678  }
679 
680  float dMM = deltaMaxMin / nBinf;
681  int range_size_hist = int(float(nBits) /dMM + overlap);
682  range_size_hist = (range_size_hist < 1) ? 2 : range_size_hist;
683 
684  #ifdef PIC_DEBUG
685  printf("Histogram [%f %f] %d\n", fMin, fMax, range_size_hist);
686  #endif
687 
688  int count = -1;
689  int index = 0;
690 
691  for(int i = 0; i < (nBin - range_size_hist); i++) {
692  int tmpCount = 0;
693 
694  for(int j = i; j < (i + range_size_hist); j++) {
695  tmpCount += bin[j];
696  }
697 
698  if(tmpCount > count) {
699  count = tmpCount;
700  index = i;
701  }
702  }
703 
704  float fstop_index = (float(index + range_size_hist) * dMM) + fMin;
705  return -fstop_index;
706  }
707 };
708 
709 
710 } // end namespace pic
711 
712 #endif /* PIC_HISTOGRAM_HPP */
713 
The BBox class manages the creation of bounding boxes for images.
Definition: bbox.hpp:29
unsigned int uint
Definition: base.hpp:23
float * bin_nor
Definition: histogram.hpp:41
float * cumulativef(bool bNormalized)
cumulativef computes the cumulative Histogram.
Definition: histogram.hpp:440
void calculate(Image *imgIn, VALUE_SPACE type=VS_LIN, int nBin=256, BBox *box=NULL, int channel=0)
calculate computes the histogram of an input image. In the case of LDR images, they are ssumed to be ...
Definition: histogram.hpp:213
float * data
data is the main buffer where pixel values are stored.
Definition: image.hpp:91
void write(std::string name, bool bNor)
write saves the Histogram as an Image into a file.
Definition: histogram.hpp:558
int channels
Definition: image.hpp:80
The Histogram class is a class for creating, managing, loading, and saving histogram for an Image...
Definition: histogram.hpp:37
void update(float fMin, float fMax)
update
Definition: histogram.hpp:325
Definition: histogram.hpp:31
float * bin_c
Definition: histogram.hpp:40
T * delete_vec_s(T *data)
delete_vec_s
Definition: std_util.hpp:138
float unprojectDomain(float x)
unprojectDomain removes the histogram domain to x.
Definition: histogram.hpp:84
uint * bin
Definition: histogram.hpp:131
void clip(uint value)
clip clips the histogram to value.
Definition: histogram.hpp:409
float * getCumulativef()
getCumulativef this function returns the cumulative Histogram. Note that cumulativef needs to be comp...
Definition: histogram.hpp:459
VALUE_SPACE
Definition: histogram.hpp:31
float * getNormalized(bool bNor=true)
getNormalized normalizes the Histogram.
Definition: histogram.hpp:487
float getfMin()
getfMin
Definition: histogram.hpp:468
Histogram()
Histogram is the basic constructor setting variables to defaults.
Definition: histogram.hpp:136
VALUE_SPACE type
Definition: histogram.hpp:43
void ceiling(float k)
ceiling limits the maximum value of the histogram using Ward algorithm.
Definition: histogram.hpp:364
float projectDomain(float x)
projectDomain applies the histogram domain to x.
Definition: histogram.hpp:53
Definition: histogram.hpp:31
int project(float x)
project converts an input value in the histogram domain.
Definition: histogram.hpp:337
Definition: histogram.hpp:31
Definition: histogram.hpp:31
float fMax
Definition: histogram.hpp:44
float deltaMaxMin
Definition: histogram.hpp:45
float unproject(int ind)
unproject converts a histogram value back to its original domain.
Definition: histogram.hpp:352
float fMin
Definition: histogram.hpp:44
float getfMax()
getfMax
Definition: histogram.hpp:478
std::vector< float > exposureCovering(int nBits=8, float overlap=1.0f)
exposureCovering computes the exposure values for fully covering the dynamic range of the image...
Definition: histogram.hpp:585
static T * cumsum(T *vec, int size, T *ret)
cumsum
Definition: array.hpp:438
#define MIN(a, b)
Definition: math.hpp:69
Definition: dynamic_range.hpp:29
The Image class stores an image as buffer of float.
Definition: image.hpp:60
float getBestExposure(int nBits, float overlap=0.5f)
getBestExposure computes the best interval center.
Definition: histogram.hpp:669
static void div(T *data, int size, T value)
div
Definition: array.hpp:353
const float C_INV_LOG_NAT_2
Definition: math.hpp:36
float getOtsu()
getOtsu
Definition: histogram.hpp:516
Histogram(Image *imgIn, VALUE_SPACE type, int nBin, int channel=0)
Histogram is an extension of the basic constructor, where calculate is called in order to populate th...
Definition: histogram.hpp:159
int nBin
Definition: histogram.hpp:42
void release()
release
Definition: histogram.hpp:191
The Array class.
Definition: array.hpp:30
Definition: bilateral_separation.hpp:25
bool isValid()
isValid checks if the current image is valid, which means if they have an allocated buffer or not...
#define CLAMP(x, a)
Definition: math.hpp:77
static T * assign(T *data, int size, T *ret)
assign
Definition: array.hpp:464
#define MAX(a, b)
Definition: math.hpp:73
float epsilon
Definition: histogram.hpp:46
float nBinf
Definition: histogram.hpp:45
int width
Definition: image.hpp:80
void uniform(float fMin, float fMax, uint value, VALUE_SPACE type, int nBin)
uniform
Definition: histogram.hpp:298
int height
Definition: image.hpp:80
void update(float x)
update
Definition: histogram.hpp:115
bool Write(std::string nameFile, LDR_type typeWrite, int writerCounter)
Write saves an Image into a file on the disk.
~Histogram()
~Histogram is the basic destructor which frees memory.
Definition: histogram.hpp:178
uint * bin_work
Definition: histogram.hpp:131
Definition: histogram.hpp:31