ANIMA  4.0
animaRecursiveLineYvvGaussianImageFilter.hxx
Go to the documentation of this file.
1 #pragma once
2 
4 #include <itkObjectFactory.h>
5 #include <itkImageLinearIteratorWithIndex.h>
6 #include <itkImageLinearConstIteratorWithIndex.h>
7 #include <itkProgressReporter.h>
8 #include <new>
9 
10 
11 namespace anima
12 {
13 
14 template <typename TInputImage, typename TOutputImage>
17 {
18  m_Direction = 0;
19  this->SetNumberOfRequiredOutputs( 1 );
20  this->SetNumberOfRequiredInputs( 1 );
21 
22  this->InPlaceOff();
23 }
24 
28 template <typename TInputImage, typename TOutputImage>
29 void
31 ::SetInputImage( const TInputImage * input )
32 {
33  // ProcessObject is not const_correct so this const_cast is required
34  itk::ProcessObject::SetNthInput(0, const_cast< TInputImage * >(input) );
35 }
36 
37 
41 template <typename TInputImage, typename TOutputImage>
42 const TInputImage *
45 {
46  return dynamic_cast<const TInputImage *>((itk::ProcessObject::GetInput(0)));
47 }
48 
52 template <typename TInputImage, typename TOutputImage>
53 void
56 {
57  const ScalarRealType sigmad = m_Sigma/spacing;
58 
59  // Compute q according to 16 in Young et al on Gabor filering
60  ScalarRealType q = 0;
61  if (sigmad >= 3.556)
62  q = 0.9804 * (sigmad - 3.556) + 2.5091;
63  else
64  {
65  if (sigmad < 0.5)
66  std::cerr << "Too low sigma value (< 0.5), computation will not be precise." << std::endl;
67 
68  q = 0.0561 * sigmad * sigmad + 0.5784 * sigmad - 0.2568;
69  }
70 
71  // Compute B and B1 to B3 according to Young et al 2003
72  ScalarRealType m0 = 1.16680;
73  ScalarRealType m1 = 1.10783;
74  ScalarRealType m2 = 1.40586;
75  ScalarRealType scale = (m0 + q) * (m1 * m1 + m2 * m2 + 2 * m1 * q + q * q);
76 
77  m_B1 = q * (2 * m0 * m1 + m1 * m1 + m2 * m2 + (2 * m0 + 4 * m1) * q + 3 * q * q) / scale;
78 
79  m_B2 = - q * q * (m0 + 2 * m1 + 3 * q) / scale;
80 
81  m_B3 = q * q * q / scale;
82 
83  ScalarRealType baseB = (m0 * (m1 * m1 + m2 * m2)) / scale;
84  m_B = baseB * baseB;
85 
86  // M Matrix for initialization on backward pass, from Triggs and Sdika, IEEE TSP
87  m_MMatrix = vnl_matrix <ScalarRealType> (3,3);
88 
89  m_MMatrix(0,0) = - m_B3 * m_B1 + 1 - m_B3 * m_B3 - m_B2;
90  m_MMatrix(0,1) = (m_B3 + m_B1) * (m_B2 + m_B3 * m_B1);
91  m_MMatrix(0,2) = m_B3 * (m_B1 + m_B3 * m_B2);
92 
93  m_MMatrix(1,0) = m_B1 + m_B3 * m_B2;
94  m_MMatrix(1,1) = (1 - m_B2) * (m_B2 + m_B3 * m_B1);
95  m_MMatrix(1,2) = - m_B3 * (m_B3 * m_B1 + m_B3 * m_B3 + m_B2 - 1);
96 
97  m_MMatrix(2,0) = m_B3 * m_B1 + m_B2 + m_B1 * m_B1 - m_B2 * m_B2;
98  m_MMatrix(2,1) = m_B1 * m_B2 + m_B3 * m_B2 * m_B2 - m_B1 * m_B3 * m_B3 - m_B3 * m_B3 * m_B3 - m_B3 * m_B2 + m_B3;
99  m_MMatrix(2,2) = m_B3 * (m_B1 + m_B3 * m_B2);
100 
101  m_MMatrix /= (1 + m_B1 - m_B2 + m_B3) * (1 - m_B1 - m_B2 - m_B3) * (1 + m_B2 + (m_B1 - m_B3) * m_B3);
102 }
103 
107 template <typename TInputImage, typename TOutputImage>
108 void
110 ::FilterDataArray(RealType *outs,const RealType *data, unsigned int ln,
111  RealType &sV0, RealType &sV1, RealType &sV2)
112 {
117  // this value is assumed to exist from the border to infinity.
118  this->ComputeCausalBase(data[0],sV0,sV1,sV2);
119 
123  for( unsigned int i=0; i<ln; i++ )
124  this->ComputeCausalPart(outs[i],data[i],sV0,sV1,sV2);
125 
129  this->ComputeAntiCausalBase(data[ln-1],outs,sV0,sV1,sV2,ln);
130 
131  outs[ln-1] = sV0;
135  for (int i=ln-2; i >= 0; i--)
136  this->ComputeAntiCausalPart(outs[i],outs[i],sV0,sV1,sV2);
137 }
138 
139 
140 //
141 // we need all of the image in just the "Direction" we are separated into
142 //
143 template <typename TInputImage, typename TOutputImage>
144 void
146 ::EnlargeOutputRequestedRegion(itk::DataObject *output)
147 {
148  TOutputImage *out = dynamic_cast<TOutputImage*>(output);
149 
150  if (out)
151  {
152  OutputImageRegionType outputRegion = out->GetRequestedRegion();
153  const OutputImageRegionType &largestOutputRegion = out->GetLargestPossibleRegion();
154 
155  // verify sane parameter
156  if ( this->m_Direction >= outputRegion.GetImageDimension() )
157  {
158  itkExceptionMacro("Direction selected for filtering is greater than ImageDimension")
159  }
160 
161  // expand output region to match largest in the "Direction" dimension
162  outputRegion.SetIndex( m_Direction, largestOutputRegion.GetIndex(m_Direction) );
163  outputRegion.SetSize( m_Direction, largestOutputRegion.GetSize(m_Direction) );
164 
165  out->SetRequestedRegion( outputRegion );
166  }
167 }
168 
169 template <typename TInputImage, typename TOutputImage>
170 void
173 {
174  typedef itk::ImageRegion< TInputImage::ImageDimension > RegionType;
175 
176  typename TInputImage::ConstPointer inputImage( this->GetInputImage () );
177  typename TOutputImage::Pointer outputImage( this->GetOutput() );
178 
179  const unsigned int imageDimension = inputImage->GetImageDimension();
180 
181  if( this->m_Direction >= imageDimension )
182  {
183  itkExceptionMacro("Direction selected for filtering is greater than ImageDimension");
184  }
185 
186  const typename InputImageType::SpacingType & pixelSize = inputImage->GetSpacing();
187  this->SetUp(pixelSize[m_Direction]);
188 
189  RegionType region = outputImage->GetRequestedRegion();
190 
191  const unsigned int ln = region.GetSize()[ this->m_Direction ];
192 
193  if( ln < 4 )
194  {
195  itkExceptionMacro("The number of pixels along direction " << this->m_Direction << " is less than 4. This filter requires a minimum of four pixels along the dimension to be processed.");
196  }
197 }
198 
199 template <typename TInputImage, typename TOutputImage>
200 void
203 {
204  this->AllocateOutputs();
205  this->BeforeThreadedGenerateData();
206 
207  using RegionType = itk::ImageRegion <TInputImage::ImageDimension>;
208  typename TOutputImage::Pointer outputImage(this->GetOutput());
209  const RegionType region = outputImage->GetRequestedRegion();
210 
211  this->GetMultiThreader()->SetNumberOfWorkUnits(this->GetNumberOfWorkUnits());
212  this->GetMultiThreader()->template ParallelizeImageRegionRestrictDirection<TOutputImage::ImageDimension>(
213  this->m_Direction, region, [this](const RegionType & lambdaRegion) { this->DynamicThreadedGenerateData(lambdaRegion); }, this);
214 }
215 
220 template <typename TInputImage, typename TOutputImage>
221 void
224 {
225  typedef typename TOutputImage::PixelType OutputPixelType;
226 
227  typedef itk::ImageLinearConstIteratorWithIndex< TInputImage > InputConstIteratorType;
228  typedef itk::ImageLinearIteratorWithIndex< TOutputImage > OutputIteratorType;
229 
230  typedef itk::ImageRegion< TInputImage::ImageDimension > RegionType;
231 
232  typename TInputImage::ConstPointer inputImage( this->GetInputImage () );
233  typename TOutputImage::Pointer outputImage( this->GetOutput() );
234 
235  RegionType region = outputRegionForThread;
236 
237  InputConstIteratorType inputIterator( inputImage, region );
238  OutputIteratorType outputIterator( outputImage, region );
239 
240  inputIterator.SetDirection( this->m_Direction );
241  outputIterator.SetDirection( this->m_Direction );
242 
243 
244  const unsigned int ln = region.GetSize()[ this->m_Direction ];
245 
246  RealType *inps = 0;
247  RealType *outs = 0;
248  RealType workData0, workData1, workData2;
249 
250  try // this try is intended to catch an eventual AbortException.
251  {
252  inps = new RealType[ln];
253  outs = new RealType[ln];
254 
255  inputIterator.GoToBegin();
256  outputIterator.GoToBegin();
257 
258  while( !inputIterator.IsAtEnd() && !outputIterator.IsAtEnd() )
259  {
260  unsigned int i=0;
261  while( !inputIterator.IsAtEndOfLine() )
262  {
263  inps[i++] = inputIterator.Get();
264  ++inputIterator;
265  }
266 
267  this->FilterDataArray( outs, inps, ln, workData0, workData1, workData2 );
268 
269  unsigned int j=0;
270  while( !outputIterator.IsAtEndOfLine() )
271  {
272  outputIterator.Set( static_cast<OutputPixelType>( outs[j++] ) );
273  ++outputIterator;
274  }
275 
276  inputIterator.NextLine();
277  outputIterator.NextLine();
278  }
279  }
280  catch( itk::ProcessAborted & )
281  {
282  // Consider cases where memory allocation may fail or the process
283  // is aborted.
284 
285  // release locally allocated memory, if memory allocation fails
286  // then we will delete a NULL pointer, which is a valid operation
287  delete [] outs;
288  delete [] inps;
289 
290  // rethrow same exception
291  throw;
292  }
293 
294  delete [] outs;
295  delete [] inps;
296 }
297 
298 
299 template <typename TInputImage, typename TOutputImage>
300 void
302 ::PrintSelf(std::ostream& os, itk::Indent indent) const
303 {
304  Superclass::PrintSelf(os,indent);
305 
306  os << indent << "Direction: " << m_Direction << std::endl;
307 }
308 
309 } // end of namespace anima
void EnlargeOutputRequestedRegion(itk::DataObject *output) ITK_OVERRIDE
itk::NumericTraits< InputPixelType >::ScalarRealType ScalarRealType
itk::NumericTraits< InputPixelType >::RealType RealType
void FilterDataArray(RealType *outs, const RealType *data, unsigned int ln, RealType &sV0, RealType &sV1, RealType &sV2)
void PrintSelf(std::ostream &os, itk::Indent indent) const ITK_OVERRIDE
void DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread) ITK_OVERRIDE