Orfeo Toolbox  3.16
itkBilateralImageFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkBilateralImageFilter.txx,v $
5  Language: C++
6  Date: $Date: 2009-10-27 16:06:37 $
7  Version: $Revision: 1.33 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 #ifndef __itkBilateralImageFilter_txx
18 #define __itkBilateralImageFilter_txx
19 
21 #include "itkImageRegionIterator.h"
22 #include "itkGaussianImageSource.h"
25 #include "itkProgressReporter.h"
27 
28 
29 namespace itk
30 {
31 template< class TInputImage, class TOutputImage >
32 void
34 ::SetRadius(const unsigned long i)
35 {
36  m_Radius.Fill(i);
37 }
38 
39 template <class TInputImage, class TOutputImage>
40 void
43 {
44  // call the superclass' implementation of this method. this should
45  // copy the output requested region to the input requested region
46  Superclass::GenerateInputRequestedRegion();
47 
48  // get pointers to the input and output
49  typename Superclass::InputImagePointer inputPtr =
50  const_cast< TInputImage *>( this->GetInput() );
51 
52  if ( !inputPtr )
53  {
54  return;
55  }
56 
57  // Pad the image by 2.5*sigma in all directions
58  typename TInputImage::SizeType radius;
59  unsigned int i;
60 
61  if (m_AutomaticKernelSize)
62  {
63  for (i = 0; i < ImageDimension; i++)
64  {
65  radius[i] =
66  (typename TInputImage::SizeType::SizeValueType)
67  vcl_ceil(m_DomainMu*m_DomainSigma[i]/this->GetInput()->GetSpacing()[i]);
68  }
69  }
70  else
71  {
72  for (i = 0; i < ImageDimension; i++)
73  {
74  radius[i] = m_Radius[i];
75  }
76  }
77 
78  // get a copy of the input requested region (should equal the output
79  // requested region)
80  typename TInputImage::RegionType inputRequestedRegion;
81  inputRequestedRegion = inputPtr->GetRequestedRegion();
82 
83  // pad the input requested region by the operator radius
84  inputRequestedRegion.PadByRadius( radius );
85 
86  // crop the input requested region at the input's largest possible region
87  if ( inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()) )
88  {
89  inputPtr->SetRequestedRegion( inputRequestedRegion );
90  return;
91  }
92  else
93  {
94  // Couldn't crop the region (requested region is outside the largest
95  // possible region). Throw an exception.
96 
97  // store what we tried to request (prior to trying to crop)
98  inputPtr->SetRequestedRegion( inputRequestedRegion );
99 
100  // build an exception
101  InvalidRequestedRegionError e(__FILE__, __LINE__);
102  e.SetLocation(ITK_LOCATION);
103  e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
104  e.SetDataObject(inputPtr);
105  throw e;
106  }
107 }
108 
109 template< class TInputImage, class TOutputImage >
110 void
113 {
114  // Build a small image of the N-dimensional Gaussian used for domain filter
115  //
116  // Gaussian image size will be (2*vcl_ceil(2.5*sigma)+1) x (2*vcl_ceil(2.5*sigma)+1)
117  unsigned int i;
118  typename InputImageType::SizeType radius;
119  typename InputImageType::SizeType domainKernelSize;
120 
121  const InputImageType * inputImage = this->GetInput();
122 
123  const typename InputImageType::SpacingType inputSpacing = inputImage->GetSpacing();
124  const typename InputImageType::PointType inputOrigin = inputImage->GetOrigin();
125 
126  if (m_AutomaticKernelSize)
127  {
128  for (i = 0; i < ImageDimension; i++)
129  {
130  radius[i] =
131  (typename TInputImage::SizeType::SizeValueType)
132  vcl_ceil(m_DomainMu * m_DomainSigma[i] / inputSpacing[i] );
133  domainKernelSize[i] = 2 * radius[i] + 1;
134  }
135  }
136  else
137  {
138  for (i = 0; i < ImageDimension; i++)
139  {
140  radius[i] = m_Radius[i];
141  domainKernelSize[i] = 2 * radius[i] + 1;
142  }
143  }
144 
148 
150  gaussianImage->SetSize( domainKernelSize.GetSize() );
151  gaussianImage->SetSpacing( inputSpacing );
152  gaussianImage->SetOrigin( inputOrigin );
153  gaussianImage->SetScale( 1.0 );
154  gaussianImage->SetNormalized( true );
155 
156  for (i=0; i < ImageDimension; i++)
157  {
158  mean[i] = inputSpacing[i] * radius[i] + inputOrigin[i]; // center pixel pos
159  sigma[i] = m_DomainSigma[i];
160  }
161  gaussianImage->SetSigma( sigma );
162  gaussianImage->SetMean( mean );
163 
164  gaussianImage->Update();
165 
166  // copy this small Gaussian image into a neighborhood
167  m_GaussianKernel.SetRadius(radius);
168 
169  KernelIteratorType kernel_it;
171  = ImageRegionIterator<GaussianImageType>(gaussianImage->GetOutput(),
172  gaussianImage->GetOutput()
173  ->GetBufferedRegion() );
174  double norm = 0.0;
175  for (git.GoToBegin(); !git.IsAtEnd(); ++git)
176  {
177  norm += git.Get();
178  }
179  for (git.GoToBegin(), kernel_it = m_GaussianKernel.Begin(); !git.IsAtEnd();
180  ++git, ++kernel_it)
181  {
182  *kernel_it = git.Get() / norm;
183  }
184 
185  // Build a lookup table for the range gaussian
186  //
187  //
188 
189  // First, determine the min and max intensity range
192 
193  statistics->SetInput( inputImage );
194  statistics->GetOutput()
195  ->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() );
196  statistics->Update();
197 
198  // Now create the lookup table whose domain runs from 0.0 to
199  // (max-min) and range is gaussian evaluated at
200  // that point
201  //
202  double rangeVariance = m_RangeSigma * m_RangeSigma;
203 
204  // denominator (normalization factor) for Gaussian used for range
205  double rangeGaussianDenom;
206  rangeGaussianDenom = m_RangeSigma*vcl_sqrt(2.0*vnl_math::pi);
207 
208  // Maximum delta for the dynamic range
209  double tableDelta;
210  double v;
211 
212  m_DynamicRange = (static_cast<double>(statistics->GetMaximum())
213  - static_cast<double>(statistics->GetMinimum()));
214 
215  m_DynamicRangeUsed = m_RangeMu * m_RangeSigma;
216 
217  tableDelta = m_DynamicRangeUsed
218  / static_cast<double>(m_NumberOfRangeGaussianSamples);
219 
220  // Finally, build the table
221  m_RangeGaussianTable.resize( m_NumberOfRangeGaussianSamples );
222  for (i = 0, v = 0.0; i < m_NumberOfRangeGaussianSamples;
223  ++i, v += tableDelta)
224  {
225  m_RangeGaussianTable[i] = vcl_exp(-0.5*v*v/rangeVariance)/rangeGaussianDenom;
226  }
227 }
228 
229 
230 template< class TInputImage, class TOutputImage >
231 void
233 ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
234  int threadId)
235 {
236  typename TInputImage::ConstPointer input = this->GetInput();
237  typename TOutputImage::Pointer output = this->GetOutput();
238  unsigned long i;
239  const double rangeDistanceThreshold = m_DynamicRangeUsed;
240 
241  // Now we are ready to bilateral filter!
242  //
243  //
244  //
245 
246  // Boundary condition
248 
249  // Find the boundary "faces"
252  faceList = fC(this->GetInput(), outputRegionForThread,
253  m_GaussianKernel.GetRadius());
254 
256 
257  OutputPixelRealType centerPixel;
258  OutputPixelRealType val, tableArg, normFactor, rangeGaussian,
259  rangeDistance, pixel, gaussianProduct;
260 
261  const double distanceToTableIndex
262  = static_cast<double>(m_NumberOfRangeGaussianSamples)/m_DynamicRangeUsed;
263 
264 
265  // Process all the faces, the NeighborhoodIterator will deteremine
266  // whether a specified region needs to use the boundary conditions or
267  // not.
271  KernelConstIteratorType kernelEnd = m_GaussianKernel.End();
272 
273  ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
274 
275  for (fit = faceList.begin(); fit != faceList.end(); ++fit)
276  {
277  // walk the boundary face and the corresponding section of the output
278  b_iter = NeighborhoodIteratorType(m_GaussianKernel.GetRadius(),
279  this->GetInput(), *fit);
280  b_iter.OverrideBoundaryCondition(&BC);
281  o_iter = ImageRegionIterator<OutputImageType>(this->GetOutput(), *fit);
282 
283  while ( ! b_iter.IsAtEnd() )
284  {
285  // Setup
286  centerPixel = static_cast<OutputPixelRealType>(b_iter.GetCenterPixel());
287  val = 0.0;
288  normFactor = 0.0;
289 
290  // Walk the neighborhood of the input and the kernel
291  for (i=0, k_it = m_GaussianKernel.Begin(); k_it < kernelEnd;
292  ++k_it, ++i)
293  {
294  // range distance between neighborhood pixel and neighborhood center
295  pixel = static_cast<OutputPixelRealType>(b_iter.GetPixel(i));
296  rangeDistance = pixel - centerPixel;
297  // flip sign if needed
298  if (rangeDistance < 0.0)
299  {
300  rangeDistance *= -1.0;
301  }
302 
303  // if the range distance is close enough, then use the pixel
304  if (rangeDistance < rangeDistanceThreshold)
305  {
306  // look up the range gaussian in a table
307  tableArg = rangeDistance * distanceToTableIndex;
308  rangeGaussian = m_RangeGaussianTable[Math::Floor<size_t>(tableArg)];
309 
310  // normalization factor so filter integrates to one
311  // (product of the domain and the range gaussian)
312  gaussianProduct = (*k_it) * rangeGaussian;
313  normFactor += gaussianProduct;
314 
315  // Input Image * Domain Gaussian * Range Gaussian
316  val += pixel * gaussianProduct;
317  }
318  }
319  // normalize the value
320  val /= normFactor;
321 
322  // store the filtered value
323  o_iter.Set( static_cast<OutputPixelType>(val) );
324 
325  ++b_iter;
326  ++o_iter;
327  progress.CompletedPixel();
328  }
329  }
330 }
331 
332 
333 template< class TInputImage, class TOutputImage >
334 void
336 ::PrintSelf(std::ostream& os, Indent indent) const
337 {
338  Superclass::PrintSelf(os,indent);
339 
340  os << indent << "DomainSigma: " << m_DomainSigma << std::endl;
341  os << indent << "RangeSigma: " << m_RangeSigma << std::endl;
342  os << indent << "FilterDimensionality: " << m_FilterDimensionality << std::endl;
343  os << indent << "NumberOfRangeGaussianSamples: " << m_NumberOfRangeGaussianSamples << std::endl;
344  os << indent << "Input dynamic range: " << m_DynamicRange << std::endl;
345  os << indent << "Amount of dynamic range used: " << m_DynamicRangeUsed << std::endl;
346  os << indent << "AutomaticKernelSize: " << m_AutomaticKernelSize << std::endl;
347  os << indent << "Radius: " << m_Radius << std::endl;
348 }
349 
350 } // end namespace itk
351 
352 #endif

Generated at Sat Feb 2 2013 23:25:34 for Orfeo Toolbox with doxygen 1.8.1.1