Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Bilateral.cpp
1 /* This file is part of the BIAS library (Basic ImageAlgorithmS).
2 
3  Copyright (C) 2003-2009 (see file CONTACT for details)
4  Multimediale Systeme der Informationsverarbeitung
5  Institut fuer Informatik
6  Christian-Albrechts-Universitaet Kiel
7 
8  BIAS is free software; you can redistribute it and/or modify
9  it under the terms of the GNU Lesser General Public License as published by
10  the Free Software Foundation; either version 2.1 of the License, or
11  (at your option) any later version.
12 
13  BIAS is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License
19  along with BIAS; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/
21 
22 
23 #include "bias_config.h"
24 #include "Bilateral.hh"
25 
26 #include <Base/Image/ImageIO.hh>
27 #include <Base/Image/ImageConvert.hh>
28 
29 #include <Base/Math/Vector2.hh>
30 #include <algorithm>
31 
32 using namespace BIAS;
33 using namespace std;
34 
35 template <class InputStorageType, class OutputStorageType>
37  : FilterNToN<InputStorageType,OutputStorageType>()
38 {
40  _lastSecondSize=-1;
41  _secondSize=0;
44  _ignoreValue = (InputStorageType)0.0;
45  SetSize(2,2);
46 }
47 
48 
49 template <class InputStorageType, class OutputStorageType>
52  : FilterNToN<InputStorageType, OutputStorageType>(other)
53 {
54 
56  _secondSize = other._secondSize;
60 
62 }
63 
64 
65 template <class InputStorageType, class OutputStorageType>
68 {}
69 
70 template <class InputStorageType, class OutputStorageType>
72 SetSize(int newsize, int secondsize)
73 {
74  if(newsize != _lastBilateralSize || secondsize!=_lastSecondSize){
75  _BilateralSize = newsize;
76  _lastBilateralSize =_BilateralSize;
77  if(secondsize != -1){
78  _secondSize = secondsize;
79  _lastSecondSize = _secondSize;
80  }
81  else{
82  _secondSize = _BilateralSize;
83  _lastSecondSize = _secondSize;
84  }
85  }
86  _CalculateKernels(_GaussSigma);
87 }
88 
89 template <class InputStorageType, class OutputStorageType>
91 _CalculateKernels(double gaussSigma)
92 {
93  _GaussSigma = gaussSigma;
94  //double fac= 1.0/(2.0*gaussSigma*gaussSigma);
95 
96  register double g=0.0;
97  _gaussFilterMask.Init(_BilateralSize*2+1,_secondSize*2+1,1);
98  float **fmida = _gaussFilterMask.GetImageDataArray();
99  //create 2D gauss mask
100  Vector2<double> zero(0,0);
101  for(int xh=-_BilateralSize;xh<=_BilateralSize;xh++){
102  for(int yh=-_secondSize;yh<=_secondSize;yh++){
103  Vector2<double> p(xh,yh);
104  double dist = zero.Dist(p)*zero.Dist(p);
105  g = exp(double(-0.5*(double)(dist/gaussSigma*gaussSigma))); //(xh*xh)+(yh*yh))));
106  fmida[yh+_secondSize][xh+_BilateralSize] = float(g);
107  }
108  }
109  //BIAS::ImageIO::Save("filtermask.mip",_gaussFilterMask);
110 }
111 
112 ////////////////////////////////////////////////////////////////
113 template <class InputStorageType, class OutputStorageType>
116 {
117  if (src.GetChannelCount()!=1) {
118  return FilterColorImg(src,dst);
119  }
120 
122  OutputStorageType **dstida = dst.GetImageDataArray();
123  const InputStorageType **srcida = src.GetImageDataArray();
124  bool identimg = false;
125 
126  if ((void*)src.GetImageData() != (void*)dst.GetImageData()) {
127  if (!src.SamePixelAndChannelCount(dst)) {
128  if (!dst.IsEmpty())
129  dst.Release();
130  dst.Init(src.GetWidth(), src.GetHeight(), 1);
131  dstida = dst.GetImageDataArray();
132  }
133  } else {
134  identimg = true;
135  tmp.Init(src.GetWidth(), src.GetHeight(), 1);
136  dstida = tmp.GetImageDataArray();
137  }
138 
139  register double g=0.0,gb=0.0;
140  // double facB= 1.0/(2.0*_BilateralSigma*_BilateralSigma);
141  float ** fmida = _gaussFilterMask.GetImageDataArray();
142  int y=0,x=0,xh=0,yh=0;
143  int width = (int)src.GetWidth();
144  int height = (int)src.GetHeight();
145  double sumGB=0.0,sumGBMulI=0.0;
146  double scrSq=0.0;
147  double bilSigSq = _BilateralSigma*_BilateralSigma;
148 
149  // BIAS::Image<float> bilFilter(width*(_BilateralSize*2+1),height*(_secondSize*2+1),1) ;
150  // float ** bilida = bilFilter.GetImageDataArray();
151 
152 #ifdef BIAS_HAVE_OPENMP
153 #pragma omp parallel for private(y,x,xh,yh,g,gb,scrSq,sumGB,sumGBMulI)
154 #endif
155  for ( y=0; y < height; y++) {
156  for ( x=0; x < width; x++) {
157  if(srcida[y][x] != 0.0){
158  sumGB =sumGBMulI = 0.0;
159  unsigned count=0;
160  for(yh = -_secondSize; yh <= _secondSize; yh++){
161  for(xh = -_BilateralSize; xh <= _BilateralSize; xh++){
162  if((y+yh >= 0) && (y+yh < height) &&
163  (x+xh >= 0) && (x+xh < width) &&
164  srcida[y][x] != _ignoreValue && srcida[y+yh][x+xh] != _ignoreValue)
165  {
166  //standard gauss
167  g = (double)fmida[_secondSize+yh][_BilateralSize+xh];
168 
169  //bilateral term;
170  scrSq = (double)(srcida[y][x]-srcida[y+yh][x+xh]);
171  scrSq *=scrSq;
172  gb = exp(double(-0.5*(scrSq/bilSigSq)) );
173 
174  //bilida[y*(_secondSize*2+1)+yh][x*(_BilateralSize*2+1)+xh] = gb;
175 
176  sumGB+= g*gb;
177  sumGBMulI += g*gb*(double)srcida[y+yh][x+xh];
178  count++;
179  }
180  }
181  }
182 
183  if(sumGB != 0.0 && count != 0 && !BIAS_ISNAN(sumGB) && !BIAS_ISINF(sumGB)){
184  //this is a data dependent normalization,
185  //better divide by count.
186  dstida[y][x] = (OutputStorageType)(sumGBMulI / sumGB);
187  //dstida[y][x] = (OutputStorageType)(sumGBMulI / count);
188  }
189  else{
190  dstida[y][x] = (OutputStorageType) srcida[y][x];
191  }
192  }
193  }
194  }
195  // BIAS::ImageIO::Save("bilateralmask.mip",bilFilter);
196  if (identimg) dst.StealImage(tmp);
197  return 0;
198 }
199 
200 ////////////////////////////////////////////////////////////////
201 template <class InputStorageType, class OutputStorageType>
204  const Image<InputStorageType>& support,
206 {
207  if (!src.SamePixelAndChannelCount(support)) {
208  BIASERR("Source and support image do not have same pixel and channel count!");
209  return -1;
210  }
211 
212  if (src.GetChannelCount()!=1) {
213  return FilterColorImg(src,support,dst);
214  }
215 
217  OutputStorageType **dstida = dst.GetImageDataArray();
218  const InputStorageType **srcida = src.GetImageDataArray();
219  const InputStorageType **suppida= support.GetImageDataArray();
220  bool identimg = false;
221 
222  if ((void*)src.GetImageData() != (void*)dst.GetImageData()) {
223  if (!src.SamePixelAndChannelCount(dst)) {
224  if (!dst.IsEmpty())
225  dst.Release();
226  dst.Init(src.GetWidth(), src.GetHeight(), 1);
227  dstida = dst.GetImageDataArray();
228  }
229  } else {
230  identimg = true;
231  tmp.Init(src.GetWidth(), src.GetHeight(), 1);
232  dstida = tmp.GetImageDataArray();
233  }
234 
235  register double g=0.0,gb=0.0;
236  float ** fmida = _gaussFilterMask.GetImageDataArray();
237  int y=0,x=0,xh=0,yh=0;
238 
239  int width = (int)src.GetWidth();
240  int height = (int)src.GetHeight();
241  double sumGB=0.0,sumGBMulI=0.0;
242  double scrSq=0.0;
243  double bilSigSq = _BilateralSigma*_BilateralSigma;
244 
245 #ifdef BIAS_HAVE_OPENMP
246 #pragma omp parallel for private(y,x,xh,yh,g,gb,scrSq,sumGB,sumGBMulI)
247 #endif
248  for ( y=0; y < height; y++) {
249  for ( x=0; x < width; x++) {
250  if(srcida[y][x] != 0.0){
251  sumGB =sumGBMulI = 0.0;
252 
253  for(xh=-_BilateralSize;xh<=_BilateralSize;xh++){
254  for(yh=-_secondSize;yh<=_secondSize;yh++){
255  if(y+yh >= 0 && y+yh < height &&
256  x+xh >= 0 && x+xh < width &&
257  srcida[y][x] != _ignoreValue && srcida[y+yh][x+xh] != _ignoreValue)
258  {
259  //standard gauss
260  g = (double)fmida[_secondSize+yh][_BilateralSize+xh];
261 
262  //bilateral term;
263  scrSq = (double)(suppida[y][x]-suppida[y+yh][x+xh]);
264  scrSq *=scrSq;
265  gb = exp(double(-0.5*(scrSq/bilSigSq)) );
266 
267  //add up
268  sumGB+= g*gb;
269  sumGBMulI += g*gb*srcida[y+yh][x+xh];
270  }
271  }
272  }
273 
274  if(sumGB != 0.0 && !BIAS_ISNAN(sumGB) && !BIAS_ISINF(sumGB)){
275  dstida[y][x] = (OutputStorageType)(sumGBMulI / sumGB);
276  }
277  else{
278  dstida[y][x] = (OutputStorageType) srcida[y][x];
279  }
280  }
281  }
282  }
283 
284  if (identimg) dst.StealImage(tmp);
285  return 0;
286 }
287 
288 template <class InputStorageType, class OutputStorageType>
291 {
292  BIASERR("FilterInt makes no sense here, using general Filter interface.");
293  return Filter(src, dst);
294 }
295 
296 
297 
298 template <class InputStorageType, class OutputStorageType>
301 {
302  BIASERR("FilterFloat makes no sense here, using general Filter interface.");
303  return Filter(src, dst);
304 }
305 
306 
307 template <class InputStorageType, class OutputStorageType>
309 GetBordersValid_(int &border_x, int &border_y) const
310 {
311  if (_secondSize > _BilateralSize) {
312  border_x = border_y = _secondSize;
313  } else {
314  border_x = border_y = _BilateralSize;
315  }
316 }
317 
318 template <class InputStorageType, class OutputStorageType>
322 {
323  Image<InputStorageType> srcCopy, temp;
324 
325  int width = src.GetWidth();
326  int height = src.GetHeight();
327  dst = Image<OutputStorageType>(width, height, 3, true);
328 
329  Image<InputStorageType> red(width, height, 1);
330  Image<OutputStorageType> redG(width, height, 1);
331  Image<InputStorageType> green(width, height, 1);
332  Image<OutputStorageType> greenG(width, height, 1);
333  Image<InputStorageType> blue(width, height, 1);
334  Image<OutputStorageType> blueG(width, height, 1);
335 
336  /// use planar image in order to apply median filter seperately to each channel for now
337  if (!((src.GetColorModel() == ImageBase::CM_RGB) && src.IsPlanar())) {
338  temp = src;
339  ImageConvert::Convert(temp, srcCopy, ImageBase::CM_RGB, true);
340  red.GetChannel(srcCopy, 0);
341  green.GetChannel(srcCopy, 1);
342  blue.GetChannel(srcCopy, 2);
343  }else{
344  red.GetChannel(src, 0);
345  green.GetChannel(src, 1);
346  blue.GetChannel(src, 2);
347  }
348 
349  Filter(red, redG);
350  Filter(green, greenG);
351  Filter(blue, blueG);
352 
356 
357 
358  return 0 ;
359 }
360 
361 template <class InputStorageType, class OutputStorageType>
364  const Image<InputStorageType>& support,
366 {
367  Image<InputStorageType> srcCopy,supportCopy;
368  int width = src.GetWidth();
369  int height = src.GetHeight();
370  dst = Image<OutputStorageType>(width, height, 3, true);
371 
372  Image<InputStorageType> red(width, height, 1);
373  Image<InputStorageType> redSupp(width, height, 1);
374  Image<OutputStorageType> redG(width, height, 1);
375  Image<InputStorageType> green(width, height, 1);
376  Image<InputStorageType> greenSupp(width, height, 1);
377  Image<OutputStorageType> greenG(width, height, 1);
378  Image<InputStorageType> blue(width, height, 1);
379  Image<InputStorageType> blueSupp(width, height, 1);
380  Image<OutputStorageType> blueG(width, height, 1);
381 
382  /// use planar image in order to apply median filter seperately to each channel for now
383  if (!((src.GetColorModel() == ImageBase::CM_RGB) && src.IsPlanar())) {
384  Image<InputStorageType> temp = src;
385  ImageConvert::Convert(temp, srcCopy, ImageBase::CM_RGB, true);
386  red.GetChannel(srcCopy, 0);
387  green.GetChannel(srcCopy, 1);
388  blue.GetChannel(srcCopy, 2);
389  }else{
390  red.GetChannel(src, 0);
391  green.GetChannel(src, 1);
392  blue.GetChannel(src, 2);
393  }
394 
395  if (!((support.GetColorModel() == ImageBase::CM_RGB) && support.IsPlanar())) {
396  Image<InputStorageType> temp = support;
397  ImageConvert::Convert(temp, supportCopy, ImageBase::CM_RGB, true);
398  redSupp.GetChannel(supportCopy, 0);
399  greenSupp.GetChannel(supportCopy, 1);
400  blueSupp.GetChannel(supportCopy, 2);
401  }else{
402  redSupp.GetChannel(support, 0);
403  greenSupp.GetChannel(support, 1);
404  blueSupp.GetChannel(support, 2);
405  }
406 
407 
408  Filter(red, redSupp,redG);
409  Filter(green, greenSupp, greenG);
410  Filter(blue, blueSupp, blueG);
411 
412 
416 
417  return 0 ;
418 }
419 //////////////////////////////////////////////////////////////////////////
420 // instantiation
421 //////////////////////////////////////////////////////////////////////////
422 
423 namespace BIAS{
424 #define FILTER_INSTANTIATION_CLASS Bilateral
425 #include "Filterinst.hh"
426 }
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
virtual void GetBordersValid_(int &border_x, int &border_y) const
Definition: Bilateral.cpp:309
static void SetChannel(const ImageBase &im, const unsigned int channelId, const inputType *channelIn)
Copy channel, determines the internal ImageBase type and casts the input type to the type foreseen in...
Definition: ImageBase.hh:340
void SetSize(int newsize, int secondsize=-1)
Definition: Bilateral.cpp:72
int _lastBilateralSize
Definition: Bilateral.hh:97
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
double _GaussSigma
sigma of gaussian kernel
Definition: Bilateral.hh:95
int _secondSize
Use this variable for non-quadratic filter sizes e.g. 3x1.
Definition: Bilateral.hh:99
virtual int FilterFloat(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
Definition: Bilateral.cpp:300
bool IsPlanar() const
Definition: ImageBase.hh:484
virtual ~Bilateral()
Definition: Bilateral.cpp:67
unsigned int GetWidth() const
Definition: ImageBase.hh:312
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
Bilateral filtering with given filter size (5x5 as standard)
Definition: Bilateral.cpp:115
int FilterColorImg(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
Filter a color image by calling Filter(...) for every channel.
Definition: Bilateral.cpp:320
InputStorageType _ignoreValue
Definition: Bilateral.hh:103
int GetChannel(const ImageBase &source, const unsigned int channel)
copies one specific channel from source to Image can only be called from an planar image...
Definition: ImageBase.cpp:428
int _BilateralSize
half win size of filter, 1 means 3x3
Definition: Bilateral.hh:97
int StealImage(ImageBase &source)
steals the image data array from source, after releasing the actual image data and sets source image ...
Definition: ImageBase.cpp:395
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)
Definition: Bilateral.cpp:290
color values, 3 channels, order: red,green,blue
Definition: ImageBase.hh:131
base class for simple n-&gt;n filter implementations
Definition: FilterNToN.hh:43
unsigned int GetHeight() const
Definition: ImageBase.hh:319
2D bilateral filter
Definition: Bilateral.hh:35
bool SamePixelAndChannelCount(const ImageBase &Image) const
checks if data area has same &quot;size&quot; as Image of other type
Definition: ImageBase.hh:73
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
enum EColorModel GetColorModel() const
Definition: ImageBase.hh:407
static int Convert(BIAS::ImageBase &source, BIAS::ImageBase &dest, enum BIAS::ImageBase::EColorModel targetColorModel, bool bPlanar=false)
main general conversion function, calls desired specialized functions, always initializes the destIma...
double _BilateralSigma
Definition: Bilateral.hh:95
void _CalculateKernels(double gaussSigma)
Definition: Bilateral.cpp:91
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153