Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
HistogramEqualization.cpp
1 #include "HistogramEqualization.hh"
2 #include <Image/HistogramImage.hh>
3 #include <Base/Image/ImageIO.hh>
4 #include <limits>
5 
6 using namespace BIAS;
7 using namespace std;
8 
9 template <class InputStorageType, class OutputStorageType>
12 
13  if(src.GetChannelCount()!=1){
14  BIASERR("HistogramEqualization: not for multiple channel images");
15  return -1;
16  }
17  if (!dst.SamePixelAndChannelCount(src)){
18  dst.Release();
19  dst.Init(src.GetWidth(), src.GetHeight(), src.GetChannelCount());
20  }
21 
22  //1. compute histogram
23  HistogramImage hsrc;
24  hsrc.AboveThresholdToValue(minCutOff_, minCutOff_);
25  hsrc.BelowThresholdToValue(maxCutOff_, maxCutOff_);
26  hsrc.Init(256,256,1);//we don't really need the drawing functions but we heave to initialize the class...
27  unsigned bincount =(unsigned) (1.0 + std::numeric_limits<InputStorageType>::max() +
28  fabs((double) std::numeric_limits<InputStorageType>::min()));
29  hsrc.InitHist(bincount);
30  hsrc.AddHist<InputStorageType>(src);
31 
32  unsigned binnum = hsrc.GetBinCount();
33  BIASASSERT(binnum>0);
34  unsigned pixnum = 0;
35  map<unsigned,unsigned> filledbins;
36  //we allow only integer values. thus for every possible grey value a bin exists.
37  for(unsigned b=0; b<binnum; b++){
38  unsigned val = (unsigned) hsrc.GetBin(b);
39  if(val>0){
40  filledbins[b]=val;
41  pixnum += val;
42  }
43  }
44 
45  map<unsigned,unsigned>::iterator it;
46  //unsigned numoffilledbins = 0; numoffilledbins = filledbins.size();
47  map<InputStorageType,InputStorageType> NewGreyVal;
48  double sum = 0.0;
49 
50  double maxval = (double)std::numeric_limits<InputStorageType>::max();
51  double minval = (double)std::numeric_limits<InputStorageType>::min();
52  double valrange = (maxval-minval);
53  for(it=filledbins.begin(); it != filledbins.end(); it++){
54  sum+= (double) it->second;
55  InputStorageType oldgreyvalue = (InputStorageType)
56  (it->first - fabs((double) std::numeric_limits<InputStorageType>::min()));
57  NewGreyVal[oldgreyvalue] = (InputStorageType)
58  (((sum/(double)pixnum)*valrange)+minval);
59  }
60 
61  const InputStorageType** pDat = src.GetImageDataArray();
62  OutputStorageType** pDstDat = dst.GetImageDataArray();
63  const ROI *roi = src.GetROI();
64 
65  unsigned wid = src.GetWidth();
66  unsigned hei = src.GetHeight();
67  for(unsigned y=0; y<hei; y++)
68  for(unsigned x=0; x<wid; x++){
69  if (roi->IsInROI(x,y)){
70  InputStorageType oldgreyval = pDat[y][x];
71  //get new value:
72  pDstDat[y][x]= (OutputStorageType) NewGreyVal[oldgreyval];
73  }
74  }
75 
76  return 0;
77 }
78 
79 
80 template <class InputStorageType, class OutputStorageType>
83  unsigned int numRows, unsigned int numCols){
84 
85  if(src.GetChannelCount()!=1){
86  BIASERR("HistogramEqualization: not for multiple channel images");
87  return -1;
88  }
89  if (!dst.SamePixelAndChannelCount(src)){
90  dst.Release();
91  dst.Init(src.GetWidth(), src.GetHeight(), src.GetChannelCount());
92  }
93 
94  // init counts
95  unsigned int imWidth = src.GetWidth();
96  unsigned int imHeight = src.GetHeight();
97  unsigned int numPxCellx = imWidth/numRows;
98  unsigned int numPxCelly = imHeight/numCols;
99 
100  if(src.GetBitDepth() == 0){
101  BIASERR("bit depth not set in image ");
102  BIASABORT;
103  }
104 
105  unsigned int histoSize = 1;
106  for (unsigned int i = 0; i < src.GetBitDepth(); i++){
107  histoSize *= 2;
108  }
109 
110  // init histograms
111  vector<vector<unsigned int> > histograms(numRows*numCols, vector<unsigned int>(histoSize, 0));
112  vector<vector<unsigned int> > newGreyVals(numRows*numCols, vector<unsigned int>(histoSize, 0));
113  vector<unsigned int> histoPixNum(numRows*numCols, 0);
114  vector<Vector2<unsigned int> > cellCenters(numRows*numCols);
115 
116  const InputStorageType** srcPtr = src.GetImageDataArray();
117 
118  unsigned int startInCellX=0, startInCellY=0;
119  unsigned int endInCellX=0, endInCellY=0;
120  unsigned int histoCount=0;
121  InputStorageType val=0;
122  for(unsigned int cx=0; cx < numRows; cx++){
123  for(unsigned int cy=0; cy < numCols; cy++){
124  startInCellX = cx*numPxCellx;
125  startInCellY = cy*numPxCelly;
126  endInCellX = (cx+1)*numPxCellx;
127  endInCellY = (cy+1)*numPxCelly;
128  histoCount = numRows*cy+cx;
129 
130  cellCenters[histoCount] = Vector2<unsigned int>((endInCellX-numPxCellx/2),
131  (endInCellY-numPxCelly/2));
132 
133  for(unsigned int x=startInCellX; x < endInCellX; x++){
134  for(unsigned int y=startInCellY; y < endInCellY; y++){
135  val = srcPtr[y][x];
136  if(val < minCutOff_) val = minCutOff_;
137  if(val > maxCutOff_) val = maxCutOff_;
138  histograms[histoCount][val]++;
139  } // end celly
140  } // end cellx
141 
142  // get pixel count in each cell - might not be equal to pixels in orig image due to
143  // thresholding
144  for(unsigned int hs=0; hs < histoSize; hs++){
145  histoPixNum[histoCount] += histograms[histoCount][hs];
146  }
147 
148  // compute new grey values
149  double sum = 0.0;
150  double maxval = (double)std::numeric_limits<InputStorageType>::max();
151  double minval = (double)std::numeric_limits<InputStorageType>::min();
152  double valrange = (maxval-minval);
153  for(unsigned int hs=0; hs < histoSize; hs++){
154  sum+= (double) histograms[histoCount][hs];
155  InputStorageType oldgreyvalue = (InputStorageType)
156  (hs - fabs((double) std::numeric_limits<InputStorageType>::min()));
157  newGreyVals[histoCount][oldgreyvalue] = (InputStorageType)
158  (((sum/(double)histoPixNum[histoCount])*valrange)+minval);
159  } // end for each histogram entry, compute new grey value
160 
161  } // end for all cell cols
162  }// end for all cell rows
163 
164  // compute new grey values in output image
165  OutputStorageType** pDstDat = dst.GetImageDataArray();
166  const ROI *roi = src.GetROI();
167 
168 
169  double w00=0, w01=0;
170  double w10=0, w11=0;
171  unsigned int cx1 = 0;
172  unsigned int cx2 = 0;
173  unsigned int cy1 = 0;
174  unsigned int cy2 = 0;
175  double distx1=0, distx2=0;
176  double disty1=0, disty2=0;
177  int xm1=0, xm2=0, ym1=0, ym2=0;
178  for(unsigned y=0; y<imHeight; y++){
179  for(unsigned x=0; x<imWidth; x++){
180  // determine nearby cells
181  xm1 = ((int)x-numPxCellx/2);
182  xm2 = ((int)x+numPxCellx/2);
183  ym1 = ((int)y-numPxCelly/2);
184  ym2 = ((int)y+numPxCelly/2);
185 
186 
187 
188  if(xm1 < 0) xm1=0;
189  if(xm2 >= (int)imWidth) xm2 = imWidth-1;
190  if(ym1 < 0) ym1=0;
191  if(ym2 >= (int)imHeight) ym2 = imHeight-1;
192 
193  cx1 = xm1 / numPxCellx;
194  cx2 = xm2 / numPxCellx;
195  cy1 = ym1 / numPxCelly;
196  cy2 = ym2 / numPxCelly;
197 
198  if(cx2 >= numRows) cx2 = numRows-1;
199  if(cy2 >= numCols) cy2 = numCols-1;
200 
201  distx1 = fabs((double)x-(double)cellCenters[cy1*numRows+cx1][0]);
202  distx2 = fabs((double)cellCenters[cy1*numRows+cx2][0]-(double)x);
203  disty1 = fabs((double)y-(double)cellCenters[cy1*numRows+cx1][1]);
204  disty2 = fabs((double)cellCenters[cy2*numRows+cx2][1]-(double)y);
205 
206 
207  distx1 /= numPxCellx;
208  distx2 /= numPxCellx;
209  disty1 /= numPxCelly;
210  disty2 /= numPxCelly;
211 
212  if(cx1==cx2){
213  distx2 = 1.0 - distx1;
214  }
215  if(cy1==cy2){
216  disty2 = 1.0 - disty1;
217  }
218 
219  w00 = distx2*disty2;
220  w01 = distx1*disty2;
221  w10 = distx2*disty1;
222  w11 = distx1*disty1;
223 
224 
225  if (roi->IsInROI(x,y)){
226  InputStorageType oldgreyval = srcPtr[y][x];
227  unsigned int oldIndex = (unsigned int)oldgreyval;
228  //get new value:
229 // cout << "dst acces " << dst.GetWidth() << " " << dst.GetHeight() << " " << x << " " << y << endl;
230 // cout << "newgreyvals " << newGreyVals.size() << " " << cy1*numRows+cx1
231 // << " " << cy1*numRows+cx2 << " " << cy2*numRows+cx1 << " " << cy2*numRows+cx2
232 // << " " << newGreyVals[cy1*numRows+cx1].size() << " " << newGreyVals[cy1*numRows+cx2].size()
233 // << " " << newGreyVals[cy2*numRows+cx1].size() << " " << newGreyVals[cy2*numRows+cx2].size()
234 // << " old index " << oldIndex << endl;
235 // cout << " num rows " << numRows << " cy2 " << cy2 << " cx1 " << cx1 << " cx2 " << cx2 << endl;
236  pDstDat[y][x]= (OutputStorageType) (w00*newGreyVals[cy1*numRows+cx1][oldIndex] +
237  w01*newGreyVals[cy1*numRows+cx2][oldIndex] +
238  w10*newGreyVals[cy2*numRows+cx1][oldIndex] +
239  w11*newGreyVals[cy2*numRows+cx2][oldIndex]);
240  }
241  }
242  }
243 
244  return 0;
245 }
246 
247 
248 #define INST(intype,outtype) \
249 template class BIASImage_EXPORT HistogramEqualization<intype,outtype>;
250 namespace BIAS{
251 INST(char,char)
252 INST(unsigned char, unsigned char)
253 }
254 //won't work for float and double instances.
255 //even int and unsigned int aren't so good ideas.
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
int AboveThresholdToValue(StorageType Threshold, StorageType Value)
sets alls pixels with values above Threshold to Value
Definition: Image.cpp:1028
class for handling different region of interest (ROI) representations...
Definition: ROI.hh:118
int InitHist(unsigned int bincount=256, unsigned int histcount=1)
reserves the internal data structures for histcount histograms with bincount bins in each in one imag...
int BelowThresholdToValue(StorageType Threshold, StorageType Value)
sets alls pixels with values below Threshold to Value
Definition: Image.cpp:1013
int AdaptiveHistogramEqualization(const Image< InputStorageType > &src, Image< OutputStorageType > &dst, unsigned int numRows=8, unsigned int numCols=8)
unsigned int GetWidth() const
Definition: ImageBase.hh:312
unsigned int GetBitDepth() const
returns the bits per channel Is not necessairily 8*sizeof(StorageType), could be fewer bits...
Definition: ImageBase.hh:344
double GetBin(unsigned int bin, unsigned int hist=0)
Get the counted number of bin from hist, -1 for invalid bin/hist.
int AddHist(const Image< StorageType > &Image, unsigned int hist=0)
calculates the histogram of image and adds them to the internal data structures
ROI * GetROI()
Returns a pointer to the roi object.
Definition: ImageBase.hh:615
bool IsInROI(const double &x, const double &y) const
ROI check if pixel position is inside the ROI.
Definition: ROI.hh:463
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
unsigned int GetHeight() const
Definition: ImageBase.hh:319
INST(unsigned char)
bool SamePixelAndChannelCount(const ImageBase &Image) const
checks if data area has same &quot;size&quot; as Image of other type
Definition: ImageBase.hh:73
Class for easy histogram image generation.
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
prototyp for filter computation function
unsigned int GetBinCount()
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153