Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Binomial.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 #include "Binomial.hh"
26 
27 #ifdef BIAS_DEBUG
28 #include <Base/Image/ImageIO.hh>
29 #endif
30 
31 #include <Base/Common/BIASpragma.hh>
32 
33 using namespace BIAS;
34 using namespace std;
35 
36 //////////////////////////////////////////////////////////////////////////
37 // implementation
38 //////////////////////////////////////////////////////////////////////////
39 
40 template <class InputStorageType, class OutputStorageType>
43  : Convolution<InputStorageType, OutputStorageType>()
44 {
45  _HalfWinSize = 1;
46  //this->AddDebugLevel(D_BINOMIAL_KERNEL);
47  //this->AddDebugLevel(D_FILTERBASE_CALLSTACK);
48 
50 }
51 
52 template <class InputStorageType, class OutputStorageType>
55  : _HalfWinSize(other._HalfWinSize),
56  _LastHalfWinSize(other._LastHalfWinSize)
57 {
58 }
59 
60 template <class StorageType, class KernelType>
62 {
63 }
64 
65 ////////////////////////////////////////////////////////////////////////////
66 
67 template <class InputStorageType, class OutputStorageType>
70 {
71  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Binomial::Filter\n");
72 
73  int res=0;
74 
75  switch (_HalfWinSize){
76  case 1:
77  res = Filter3x3(src, dst);
78  break;
79  case 2:
80  res = Filter5x5(src, dst);
81  break;
82  default:
83  if ((_HalfWinSize != _LastHalfWinSize))
84  _CalculateKernel(_HalfWinSize);
86  break;
87  }
88 
89  return res;
90 }
91 
92 template <class InputStorageType, class OutputStorageType>
95  BIASERR("Unsupported interface, use Filter");
96  return Filter(src, dst);
97 }
98 
99 template <class InputStorageType, class OutputStorageType>
102  BIASERR("Unsupported interface, use Filter");
103  return Filter(src, dst);
104 }
105 
106 
107 template <class InputStorageType, class OutputStorageType>
110 {
111  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Binomial::Filter3x3\n");
112  int res=0;
113  if (src.GetChannelCount()==1){
114  if (!src.SamePixelAndChannelCount(dst))
115  if (!dst.IsEmpty()) dst.Release();
116  if (dst.IsEmpty()) dst.Init(src.GetWidth(), src.GetHeight(),
117  src.GetChannelCount());
118  if (this->CalculationInFloat()){
119  switch (_FilterBorderHandling){
120  case TBH_valid:
121  res = Filter3x3ValidGreyFloat(src, dst);
122  break;
123  case TBH_same:
124  res = Filter3x3SameGreyFloat(src, dst);
125  break;
126  default:
127  BIASERR("unfinished");
128  res = -1;
129  break;
130  }
131  } else {
132  _HalfWinSize=1;
134  }
135  } else {
136  _HalfWinSize=1;
138  }
139  return res;
140 }
141 
142 template <class InputStorageType, class OutputStorageType>
145 {
146  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Binomial::Filter5x5\n");
147  int res=0;
148  if (src.GetChannelCount()==1){
149  if (!src.SamePixelAndChannelCount(dst))
150  if (!dst.IsEmpty()) dst.Release();
151  if (dst.IsEmpty()) dst.Init(src.GetWidth(), src.GetHeight(),
152  src.GetChannelCount());
153  if (this->CalculationInFloat()){
154  switch (_FilterBorderHandling){
155  case TBH_valid:
156  res = Filter5x5ValidGreyFloat(src, dst);
157  break;
158  default:
159  BIASERR("Binomial::Filter5x5: border handling unfinished, "
160  <<"using valid");
161  res = Filter5x5ValidGreyFloat(src, dst);
162  break;
163  }
164  } else {
165  BIASASSERT("unfinished");
166  _HalfWinSize=2;
168  }
169  } else {
170  _HalfWinSize=2;
172  }
173  return res;
174 }
175 
176 template <class InputStorageType, class OutputStorageType>
180 {
181  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Binomial::Filter3x3ValidGreyFloat\n");
182 #ifdef BIAS_DEBUG
183  BIASASSERT(src.GetChannelCount() == 1);
184  BIASASSERT(dst.SamePixelAndChannelCount(src));
185 #endif
186  // AddDebugLevel(D_BINOMIAL_WRITE_IM);
187  const unsigned width=src.GetWidth();
188  int nwidth = - int(width);
189  const unsigned height=src.GetHeight();
190 
191  unsigned minx, miny, maxx, maxy;
192  src.GetROI()->GetCorners(minx, miny, maxx, maxy);
193  dst.GetROI()->SetCorners(minx+1, miny+1, maxx-1, maxy-1);
194 
195  if (width>_tmpFloat.GetWidth() ||
196  height>_tmpFloat.GetHeight()){
197  if (!_tmpFloat.IsEmpty()) _tmpFloat.Release();
198  _tmpFloat.Init(width, height, src.GetChannelCount());
199  }
200 
201  const InputStorageType *im=src.GetImageData();
202  const InputStorageType *p, *end, *lend;
203  OutputStorageType *pg, *oend, *olend;
204  CONV_FLOAT *ph, tmp;
205  int offset, step;
206 
207  // separated binomial 3x3 mask = 1 2 1
208  offset=(int)minx+(int)miny*(int)width+1;
209  p=im+offset;
210  ph=_tmpFloat.GetImageData()+offset;
211  step=width-(int)maxx+(int)minx+2;
212  end=im+(int)maxx+((int)maxy-1)*(int)width-1;
213  lend=im+(int)maxx+((int)miny*(int)width)-1;
214  // vertical part
215  while (p<end){
216  while (p<lend){
217  *ph++ = (CONV_FLOAT)(p[-1]) +(CONV_FLOAT)(*p) * 2.0f + (CONV_FLOAT)(p[1]);
218  p++;
219  }
220  ph+=step;
221  p+=step;
222  lend+=width;
223  }
224 
225 #ifdef BIAS_DEBUG
226  if (this->DebugLevelIsSet(D_BINOMIAL_WRITE_IM)){
228  //ImageIO::Save("binomial3x3-input.mip", im);
229  //ImageIO::Save("binomial3x3-horiz.mip", _tmpFloat);
230  ImageIO::Save("binomial3x3-input.mip", im);
231  ImageIO::Save("binomial3x3-horiz.mip", _tmpFloat);
232  }
233 #endif
234 
235  offset=(int)minx+((int)miny+1)*(int)width+1;
236  ph=_tmpFloat.GetImageData()+offset;
237  OutputStorageType *s=dst.GetImageData();
238  pg=s+offset;
239  oend=s+(int)maxx+((int)maxy-2)*(int)width-1;
240  olend=s+(int)maxx+((int)miny+1)*(int)width-1;
241  CONV_FLOAT div = 1.0 / 16.0;
242  // horizontal part
243  while (pg<oend){
244  while (pg<olend){
245  tmp = ph[nwidth] + *ph * 2.0f + ph[width];
246  *pg++ = (OutputStorageType)(tmp * div);
247  ph++;
248  }
249  pg+=step;
250  ph+=step;
251  olend+=width;
252  }
253 #ifdef BIAS_DEBUG
254  if (this->DebugLevelIsSet(D_BINOMIAL_WRITE_IM)){
255  //ImageIO::Save("binomial3x3-result.mip", dst);
256  ImageIO::Save("binomial3x3-result.mip", dst);
257  }
258 #endif
259 
260  return 0;
261 }
262 
263 template <class InputStorageType, class OutputStorageType>
267 {
268  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Binomial::Filter3x3SameGreyFloat\n");
269  int res =0;
270 
271  res = Filter3x3ValidGreyFloat(src, dst);
272 
273  // filter mask is
274  // | 1 2 1 |
275  // | 2 4 2 |
276  // | 1 2 1 |
277  int minx, miny, maxx, maxy;
278  src.GetROI()->GetCorners(minx, miny, maxx, maxy);
279  register int x, y, xp, xm, yp, ym;
280 
281  const InputStorageType **srcida=src.GetImageDataArray();
282  OutputStorageType **dstida=dst.GetImageDataArray();
283 
284  // upper left pixel
285  x = minx;
286  y = miny;
287  xp = x+1;
288  yp = y+1;
289  dstida[y][x] =
290  OutputStorageType((4.0*float(srcida[y][x])+
291  2.0*(float(srcida[y][xp])+float(srcida[yp][x]))+
292  float(srcida[yp][xp]))/9.0);
293 
294  // upper right pixel
295  x = maxx-1;
296  //y = miny;
297  xm = x-1;
298  //yp = y+1;
299  dstida[y][x] =
300  OutputStorageType((4.0*float(srcida[y][x])+
301  2.0*(float(srcida[y][xm])+float(srcida[yp][x]))+
302  float(srcida[yp][xm]))/9.0);
303 
304  // lower right pixel
305  //x = maxx-1;
306  y = maxy-1;
307  //xm = x-1;
308  ym = y-1;
309  dstida[y][x] =
310  OutputStorageType((4.0*float(srcida[y][x])+
311  2.0*(float(srcida[y][xm])+float(srcida[ym][x]))+
312  float(srcida[ym][xm]))/9.0);
313 
314  // lower left pixel
315  x = minx;
316  //y = maxy-1;
317  xp = x+1;
318  //ym = y-1;
319  dstida[y][x] =
320  OutputStorageType((4.0*float(srcida[y][x])+
321  2.0*(float(srcida[y][xp])+float(srcida[ym][x]))+
322  float(srcida[ym][xp]))/9.0);
323 
324 
325 
326  // upper row
327  y = miny;
328  yp = y+1;
329  for (x=minx+1; x<maxx-1; x++){
330  xp = x+1;
331  xm = x-1;
332  dstida[y][x] =
333  OutputStorageType((4.0*float(srcida[y][x])+
334  2.0*(float(srcida[y][xm])+float(srcida[y][xp])+
335  float(srcida[yp][x]))+
336  float(srcida[yp][xp])+float(srcida[yp][xm]))/12.0);
337  }
338  // lower row
339  y = maxy-1;
340  ym = y-1;
341  for (x=minx+1; x<maxx-1; x++){
342  xp = x+1;
343  xm = x-1;
344  dstida[y][x] =
345  OutputStorageType((4.0*float(srcida[y][x])+
346  2.0*(float(srcida[y][xm])+float(srcida[y][xp])+
347  float(srcida[ym][x]))+
348  float(srcida[ym][xp])+float(srcida[ym][xm]))/12.0);
349  }
350  // left column
351  x = minx;
352  xp = x+1;
353  for (y=miny+1; y<maxy-1; y++){
354  yp = y+1;
355  ym = y-1;
356  dstida[y][x] =
357  OutputStorageType((4.0*float(srcida[y][x])+
358  2.0*(float(srcida[ym][x])+float(srcida[yp][x])+
359  float(srcida[y][xp]))+
360  float(srcida[ym][xp])+float(srcida[yp][xp]))/12.0);
361  }
362 
363  // right column
364  x = maxx-1;
365  xm = x-1;
366  for (y=miny+1; y<maxy-1; y++){
367  yp = y+1;
368  ym = y-1;
369  dstida[y][x] =
370  OutputStorageType((4.0*float(srcida[y][x])+
371  2.0*(float(srcida[ym][x])+float(srcida[yp][x])+
372  float(srcida[y][xm]))+
373  float(srcida[ym][xm])+float(srcida[yp][xm]))/12.0);
374  }
375 
376  dst.GetROI()->SetCorners(minx, miny, maxx, maxy);
377 
378  return res;
379 }
380 
381 template <class InputStorageType, class OutputStorageType>
385 {
386  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Binomial::Filter5x5ValidGrey\n");
387 #ifdef BIAS_DEBUG
388  BIASASSERT(src.GetChannelCount() == 1);
389  BIASASSERT(dst.SamePixelAndChannelCount(src));
390 #endif
391  //AddDebugLevel(D_BINOMIAL_WRITE_IM);
392  const unsigned width=src.GetWidth();
393  int nwidth = - int(width);
394  const unsigned height=src.GetHeight();
395 
396  unsigned minx, miny, maxx, maxy;
397  src.GetROI()->GetCorners(minx, miny, maxx, maxy);
398  dst.GetROI()->SetCorners(minx+2, miny+2, maxx-2, maxy-2);
399 
400  // init internal memory if necessairy
401  if (width>_tmpFloat.GetWidth() ||
402  height>_tmpFloat.GetHeight()){
403  if (!_tmpFloat.IsEmpty()) _tmpFloat.Release();
404  _tmpFloat.Init(width, height, src.GetChannelCount());
405  }
406 
407  const InputStorageType *im=src.GetImageData();
408  const InputStorageType *p, *end, *lend;
409  OutputStorageType *pg, *oend, *olend;
410  CONV_FLOAT *ph, tmp;
411  int offset, step;
412  // separated binomial 5x5 mask = 1 4 6 4 1
413  offset=(int)minx+(int)miny*(int)width+2;
414  p=im+offset;
415  ph=_tmpFloat.GetImageData()+offset;
416  step=width-(int)maxx+(int)minx+4;
417  end=im+(int)maxx+((int)maxy-1)*(int)width-2;
418  lend=im+(int)maxx+((int)miny*(int)width)-2;
419  // vertical part
420  while (p<end){
421  while (p<lend){
422  *ph++ = (CONV_FLOAT)(p[-2]) + (CONV_FLOAT)(p[-1])*4.0f + (CONV_FLOAT)(*p)
423  * 6.0f + (CONV_FLOAT)(p[+1])*4.0f + (CONV_FLOAT)(p[2]);
424  p++;
425  }
426  ph+=step;
427  p+=step;
428  lend+=width;
429  }
430 
431 #ifdef BIAS_DEBUG
432  if (this->DebugLevelIsSet(D_BINOMIAL_WRITE_IM)){
434  //ImageIO::Save("binomial5x5-input.mip", im);
435  //ImageIO::Save("binomial5x5-horiz.mip", _tmpFloat);
436  ImageIO::Save("binomial5x5-input.mip", im);
437  ImageIO::Save("binomial5x5-horiz.mip", _tmpFloat);
438  }
439 #endif
440 
441  offset=(int)minx+((int)miny+2)*(int)width+2;
442  ph=_tmpFloat.GetImageData()+offset;
443  OutputStorageType *s=dst.GetImageData();
444  pg=s+offset;
445  oend=s+(int)maxx+((int)maxy-3)*(int)width-2;
446  olend=s+(int)maxx+((int)miny+2)*(int)width-2;
447  int dw=width<<1;
448  CONV_FLOAT div = 1.0 / 256.0;
449  // horizontal part
450  while (pg<oend){
451  while (pg<olend){
452  tmp = ph[-dw] + ph[dw] + ph[nwidth]*4.0f + ph[width]*4.0f + (*ph)*6.0f;
453  *pg++ = (OutputStorageType)(tmp * div);
454  ph++;
455  }
456  pg+=step;
457  ph+=step;
458  olend+=width;
459  }
460 
461 #ifdef BIAS_DEBUG
462  if (this->DebugLevelIsSet(D_BINOMIAL_WRITE_IM)){
463  //ImageIO::Save("binomial5x5-result.mip", dst);
464  ImageIO::Save("binomial5x5-result.mip", dst);
465  }
466 #endif
467 
468  return 0;
469 }
470 
471 ////////////////////////////////////////////////////////////////////////////
472 
473 template <class StorageType, class KernelType>
475 _CalculateKernel(int HalfWinSize)
476 {
477  Vector<FM_INT> vec;
478  int shift;
479  const int size=(HalfWinSize<<1)+1;
480  vec.newsize(size);
481  vec[0]=vec[size-1]=1;
482 
483  int numerator=size-1, denominator=1;
484  for (int i=1; i<=HalfWinSize; i++){
485  vec[i]=vec[size-i-1]=(numerator/denominator);
486  BIASCDOUT(D_BINOMIAL_KERNEL, "num "<<numerator<<" denom "<<denominator
487  <<" = "<<vec[i]<<endl);
488  denominator*=(i+1);
489  numerator*=(size-i-1);
490  }
491  shift=(HalfWinSize<<1);
492 
493  BIASCDOUT(D_BINOMIAL_KERNEL, "size "<<size<<" : "<< vec << " shift "
494  <<shift<<endl<< "-------------\n");
495 
496  _fm.Init(vec, vec, 0, shift*shift, true);
497  BIASCDOUT(D_BINOMIAL_KERNEL, "filter mask (int): "<<_fm<<endl);
498  _fm.CreateFloatFilter();
499  BIASCDOUT(D_BINOMIAL_KERNEL, "filter mask (float): "<<_fm<<endl);
500  _LastHalfWinSize = HalfWinSize;
501 }
502 
503 template <class StorageType, class KernelType>
505 GetBordersValid_(int &border_x, int &border_y) const
506 {
507  border_x = border_y = _HalfWinSize;
508 }
509 
510 //////////////////////////////////////////////////////////////////////////
511 // instantiation
512 //////////////////////////////////////////////////////////////////////////
513 
514 namespace BIAS{
515 #define FILTER_INSTANTIATION_CLASS Binomial
516 #include "Filterinst.hh"
517 }
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
generic convolution class.
Definition: Convolution.hh:66
virtual int FilterFloat(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
no implementation, calls Filter
Definition: Binomial.cpp:101
int SetCorners(unsigned UpperLeftX, unsigned UpperLeftY, unsigned LowerRightX, unsigned LowerRightY)
Sets a rectangular region of interest.
Definition: ROI.cpp:287
void GetCorners(unsigned &UpperLeftX, unsigned &UpperLeftY, unsigned &LowerRightX, unsigned &LowerRightY) const
Return the region of interest, by saving the coordinates within the variables defined by the paramete...
Definition: ROI.hh:443
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
int Filter3x3SameGreyFloat(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
specialized function for convolution with 3x3 binomial filter.
Definition: Binomial.cpp:265
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
decides on the image types which FilterFunction should be called
int Filter3x3ValidGreyFloat(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
specialized function for convolution with 3x3 binomial filter.
Definition: Binomial.cpp:178
int Filter5x5(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
Definition: Binomial.cpp:144
unsigned int GetWidth() const
Definition: ImageBase.hh:312
Vector< T > & newsize(Subscript N)
Definition: vec.h:220
ROI * GetROI()
Returns a pointer to the roi object.
Definition: ImageBase.hh:615
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
virtual int FilterInt(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
no implementation, calls Filter
Definition: Binomial.cpp:94
unsigned int GetHeight() const
Definition: ImageBase.hh:319
bool SamePixelAndChannelCount(const ImageBase &Image) const
checks if data area has same &quot;size&quot; as Image of other type
Definition: ImageBase.hh:73
static int Save(const std::string &filename, const ImageBase &img, const enum TFileFormat FileFormat=FF_auto, const bool sync=BIAS_DEFAULT_SYNC, const int c_jpeg_quality=BIAS_DEFAULT_IMAGE_QUALITY, const bool forceNewID=BIAS_DEFAULT_FORCENEWID, const bool &writeMetaData=true)
Export image as file using extrnal libs.
Definition: ImageIO.cpp:725
int Filter3x3(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
Definition: Binomial.cpp:109
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
sets kernel if params changed and calls convolution
Definition: Binomial.cpp:69
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
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
virtual void GetBordersValid_(int &border_x, int &border_y) const
Definition: Binomial.cpp:505
binomial low pass filter class
Definition: Binomial.hh:42
int Filter5x5ValidGreyFloat(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
specialized function for convolution with 5x5 binomial filter.
Definition: Binomial.cpp:383
int _HalfWinSize
the parameter
Definition: Binomial.hh:108
void _CalculateKernel(int HalfWinSize)
calculates the kernel
Definition: Binomial.cpp:475
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153