1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkVectorConfidenceConnectedImageFilter_hxx
19 #define itkVectorConfidenceConnectedImageFilter_hxx
20 
21 #include "itkVectorConfidenceConnectedImageFilter.h"
22 #include "itkMacro.h"
23 #include "itkImageRegionIterator.h"
24 #include "itkVectorMeanImageFunction.h"
25 #include "itkCovarianceImageFunction.h"
26 #include "itkBinaryThresholdImageFunction.h"
27 #include "itkFloodFilledImageFunctionConditionalIterator.h"
28 #include "itkNumericTraitsRGBPixel.h"
29 #include "itkProgressReporter.h"
30 
31 namespace itk
32 {
33 /**
34  * Constructor
35  */
36 template< typename TInputImage, typename TOutputImage >
37 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
VectorConfidenceConnectedImageFilter()38 ::VectorConfidenceConnectedImageFilter()
39 {
40   m_Multiplier = 2.5;
41   m_NumberOfIterations = 4;
42   m_Seeds.clear();
43   m_InitialNeighborhoodRadius = 1;
44   m_ReplaceValue = NumericTraits< OutputImagePixelType >::OneValue();
45   m_ThresholdFunction = DistanceThresholdFunctionType::New();
46 }
47 
48 /**
49  * Standard PrintSelf method.
50  */
51 template< typename TInputImage, typename TOutputImage >
52 void
53 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
PrintSelf(std::ostream & os,Indent indent) const54 ::PrintSelf(std::ostream & os, Indent indent) const
55 {
56   this->Superclass::PrintSelf(os, indent);
57   os << indent << "Number of iterations: " << m_NumberOfIterations
58      << std::endl;
59   os << indent << "Multiplier for confidence interval: " << m_Multiplier
60      << std::endl;
61   os << indent << "ReplaceValue: "
62      << static_cast< typename NumericTraits< OutputImagePixelType >::PrintType >( m_ReplaceValue )
63      << std::endl;
64   os << indent << "InitialNeighborhoodRadius: " << m_InitialNeighborhoodRadius
65      << std::endl;
66 }
67 
68 template< typename TInputImage, typename TOutputImage >
69 void
70 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
SetSeed(const IndexType & seed)71 ::SetSeed(const IndexType & seed)
72 {
73   this->ClearSeeds();
74   this->AddSeed(seed);
75 }
76 
77 template< typename TInputImage, typename TOutputImage >
78 void
79 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
AddSeed(const IndexType & seed)80 ::AddSeed(const IndexType & seed)
81 {
82   m_Seeds.push_back(seed);
83   this->Modified();
84 }
85 
86 template< typename TInputImage, typename TOutputImage >
87 void
88 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
ClearSeeds()89 ::ClearSeeds()
90 {
91   if ( !this->m_Seeds.empty() )
92     {
93     this->m_Seeds.clear();
94     this->Modified();
95     }
96 }
97 
98 template< typename TInputImage, typename TOutputImage >
99 void
100 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
GenerateInputRequestedRegion()101 ::GenerateInputRequestedRegion()
102 {
103   Superclass::GenerateInputRequestedRegion();
104   if ( this->GetInput() )
105     {
106     InputImagePointer input =
107       const_cast< TInputImage * >( this->GetInput() );
108     input->SetRequestedRegionToLargestPossibleRegion();
109     }
110 }
111 
112 
113 template< typename TInputImage, typename TOutputImage >
114 void
115 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
EnlargeOutputRequestedRegion(DataObject * output)116 ::EnlargeOutputRequestedRegion(DataObject *output)
117 {
118   Superclass::EnlargeOutputRequestedRegion(output);
119   output->SetRequestedRegionToLargestPossibleRegion();
120 }
121 
122 template< typename TInputImage, typename TOutputImage >
123 void
124 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
GenerateData()125 ::GenerateData()
126 {
127   using InputPixelType = typename InputImageType::PixelType;
128 
129   using SecondFunctionType = BinaryThresholdImageFunction<OutputImageType>;
130   using IteratorType = FloodFilledImageFunctionConditionalIterator< OutputImageType, DistanceThresholdFunctionType >;
131   using SecondIteratorType = FloodFilledImageFunctionConditionalConstIterator< InputImageType,
132                                                             SecondFunctionType >;
133 
134   unsigned int loop;
135 
136   typename Superclass::InputImageConstPointer inputImage  = this->GetInput();
137   typename Superclass::OutputImagePointer outputImage = this->GetOutput();
138 
139   // Zero the output
140   OutputImageRegionType region = outputImage->GetRequestedRegion();
141   outputImage->SetBufferedRegion(region);
142   outputImage->Allocate();
143   outputImage->FillBuffer (NumericTraits< OutputImagePixelType >::ZeroValue());
144 
145   // Compute the statistics of the seed point
146   using VectorMeanImageFunctionType = VectorMeanImageFunction< InputImageType >;
147   typename VectorMeanImageFunctionType::Pointer meanFunction =
148     VectorMeanImageFunctionType::New();
149 
150   meanFunction->SetInputImage(inputImage);
151   meanFunction->SetNeighborhoodRadius(m_InitialNeighborhoodRadius);
152   using CovarianceImageFunctionType = CovarianceImageFunction< InputImageType >;
153   typename CovarianceImageFunctionType::Pointer varianceFunction =
154     CovarianceImageFunctionType::New();
155   varianceFunction->SetInputImage(inputImage);
156   varianceFunction->SetNeighborhoodRadius(m_InitialNeighborhoodRadius);
157 
158   // Set up the image function used for connectivity
159   m_ThresholdFunction->SetInputImage (inputImage);
160 
161   CovarianceMatrixType covariance;
162   MeanVectorType       mean;
163 
164   using ComponentPixelType = typename InputPixelType::ValueType;
165   using ComponentRealType = typename NumericTraits< ComponentPixelType >::RealType;
166 
167   const unsigned int dimension = inputImage->GetNumberOfComponentsPerPixel();
168 
169   covariance = CovarianceMatrixType(dimension, dimension);
170   mean       = MeanVectorType(dimension);
171 
172   covariance.fill(NumericTraits< ComponentRealType >::ZeroValue());
173   mean.fill(NumericTraits< ComponentRealType >::ZeroValue());
174 
175   using MeanFunctionVectorType = typename VectorMeanImageFunctionType::OutputType;
176   using CovarianceFunctionMatrixType = typename CovarianceImageFunctionType::OutputType;
177 
178   typename SeedsContainerType::const_iterator si = m_Seeds.begin();
179   typename SeedsContainerType::const_iterator li = m_Seeds.end();
180   SizeValueType seed_cnt = 0;
181   while ( si != li )
182     {
183     if ( region.IsInside(*si) )
184       {
185       ++seed_cnt;
186       const MeanFunctionVectorType       meanContribution       = meanFunction->EvaluateAtIndex(*si);
187       const CovarianceFunctionMatrixType covarianceContribution = varianceFunction->EvaluateAtIndex(*si);
188       for ( unsigned int ii = 0; ii < dimension; ii++ )
189         {
190         mean[ii] += meanContribution[ii];
191         for ( unsigned int jj = 0; jj < dimension; jj++ )
192           {
193           covariance[ii][jj] += covarianceContribution[ii][jj];
194           }
195         }
196       }
197     si++;
198     }
199 
200   if ( seed_cnt == 0 )
201     {
202       this->UpdateProgress(1.0);
203       // no seeds result in zero image
204       return;
205     }
206 
207   for ( unsigned int ik = 0; ik < dimension; ik++ )
208     {
209     mean[ik] /= seed_cnt;
210     for ( unsigned int jk = 0; jk < dimension; jk++ )
211       {
212       covariance[ik][jk] /= seed_cnt;
213       }
214     }
215 
216   m_ThresholdFunction->SetMean(mean);
217   m_ThresholdFunction->SetCovariance(covariance);
218 
219   m_ThresholdFunction->SetThreshold(m_Multiplier);
220 
221   itkDebugMacro(<< "\nMultiplier originally = " << m_Multiplier);
222 
223   // Make sure that the multiplier is large enough to include the seed points
224   // themselves.
225   // This is a pragmatic fix, but a questionable practice because it means that
226   // the actual
227   // region may be grown using a multiplier different from the one specified by
228   // the user.
229 
230   si = m_Seeds.begin();
231   li = m_Seeds.end();
232   while ( si != li )
233     {
234     if ( region.IsInside(*si) )
235       {
236       const double distance =
237         m_ThresholdFunction->EvaluateDistanceAtIndex(*si);
238       if ( distance >  m_Multiplier )
239         {
240         m_Multiplier = distance;
241         }
242       }
243     si++;
244     }
245 
246   // Finally setup the eventually modified multiplier. That is actually the
247   // threshold itself.
248   m_ThresholdFunction->SetThreshold(m_Multiplier);
249 
250   itkDebugMacro(<< "\nMultiplier after verifying seeds inclusion = " << m_Multiplier);
251 
252   // Segment the image, the iterator walks the output image (so Set()
253   // writes into the output image), starting at the seed point.  As
254   // the iterator walks, if the corresponding pixel in the input image
255   // (accessed via the "m_ThresholdFunction" assigned to the iterator) is within
256   // the [lower, upper] bounds prescribed, the pixel is added to the
257   // output segmentation and its neighbors become candidates for the
258   // iterator to walk.
259   IteratorType it = IteratorType (outputImage, m_ThresholdFunction, m_Seeds);
260   it.GoToBegin();
261   while ( !it.IsAtEnd() )
262     {
263     it.Set(m_ReplaceValue);
264     ++it;
265     }
266 
267   ProgressReporter progress(this, 0, region.GetNumberOfPixels() * m_NumberOfIterations);
268 
269   for ( loop = 0; loop < m_NumberOfIterations; ++loop )
270     {
271     // Now that we have an initial segmentation, let's recalculate the
272     // statistics.  Since we have already labelled the output, we visit
273     // pixels in the input image that have been set in the output image.
274     // Essentially, we flip the iterator around, so we walk the input
275     // image (so Get() will get pixel values from the input) and constrain
276     // iterator such it only visits pixels that were set in the output.
277     typename SecondFunctionType::Pointer secondFunction = SecondFunctionType::New();
278     secondFunction->SetInputImage (outputImage);
279     secondFunction->ThresholdBetween(m_ReplaceValue, m_ReplaceValue);
280 
281     covariance = CovarianceMatrixType(dimension, dimension);
282     mean       = MeanVectorType(dimension);
283 
284     covariance.fill(NumericTraits< ComponentRealType >::ZeroValue());
285     mean.fill(NumericTraits< ComponentRealType >::ZeroValue());
286 
287     SizeValueType num = NumericTraits< SizeValueType >::ZeroValue();
288 
289     SecondIteratorType sit =
290       SecondIteratorType (inputImage, secondFunction, m_Seeds);
291     sit.GoToBegin();
292     while ( !sit.IsAtEnd() )
293       {
294       const InputPixelType pixelValue = sit.Get();
295       for ( unsigned int i = 0; i < dimension; i++ )
296         {
297         const auto pixelValueI = static_cast< ComponentRealType >( pixelValue[i] );
298         covariance[i][i] += pixelValueI * pixelValueI;
299         mean[i] += pixelValueI;
300         for ( unsigned int j = i + 1; j < dimension; j++ )
301           {
302           const auto pixelValueJ = static_cast< ComponentRealType >( pixelValue[j] );
303           const ComponentRealType product = pixelValueI * pixelValueJ;
304           covariance[i][j] += product;
305           covariance[j][i] += product;
306           }
307         }
308       ++num;
309       ++sit;
310       }
311     for ( unsigned int ii = 0; ii < dimension; ii++ )
312       {
313       mean[ii] /= static_cast< double >( num );
314       for ( unsigned int jj = 0; jj < dimension; jj++ )
315         {
316         covariance[ii][jj] /= static_cast< double >( num );
317         }
318       }
319 
320     for ( unsigned int ik = 0; ik < dimension; ik++ )
321       {
322       for ( unsigned int jk = 0; jk < dimension; jk++ )
323         {
324         covariance[ik][jk] -= mean[ik] * mean[jk];
325         }
326       }
327 
328     m_ThresholdFunction->SetMean(mean);
329     m_ThresholdFunction->SetCovariance(covariance);
330 
331     // Rerun the segmentation, the iterator walks the output image,
332     // starting at the seed point.  As the iterator walks, if the
333     // corresponding pixel in the input image (accessed via the
334     // "m_ThresholdFunction" assigned to the iterator) is within the [lower,
335     // upper] bounds prescribed, the pixel is added to the output
336     // segmentation and its neighbors become candidates for the
337     // iterator to walk.
338     outputImage->FillBuffer (NumericTraits< OutputImagePixelType >::ZeroValue());
339     IteratorType thirdIt = IteratorType (outputImage, m_ThresholdFunction, m_Seeds);
340     thirdIt.GoToBegin();
341     try
342       {
343       while ( !thirdIt.IsAtEnd() )
344         {
345         thirdIt.Set(m_ReplaceValue);
346         ++thirdIt;
347         progress.CompletedPixel();  // potential exception thrown here
348         }
349       }
350     catch ( ProcessAborted & )
351       {
352       break; // interrupt the iterations loop
353       }
354     }  // end iteration loop
355 
356   if ( this->GetAbortGenerateData() )
357     {
358     ProcessAborted e(__FILE__, __LINE__);
359     e.SetDescription("Process aborted.");
360     e.SetLocation(ITK_LOCATION);
361     throw e;
362     }
363 }
364 
365 template< typename TInputImage, typename TOutputImage >
366 const typename
367 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >::CovarianceMatrixType &
368 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
GetCovariance() const369 ::GetCovariance() const
370 {
371   return m_ThresholdFunction->GetCovariance();
372 }
373 
374 template< typename TInputImage, typename TOutputImage >
375 const typename
376 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >::MeanVectorType &
377 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
GetMean() const378 ::GetMean() const
379 {
380   return m_ThresholdFunction->GetMean();
381 }
382 
383 template< typename TInputImage, typename TOutputImage >
384 const typename VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >::SeedsContainerType &
385 VectorConfidenceConnectedImageFilter< TInputImage, TOutputImage >
GetSeeds() const386 ::GetSeeds() const
387 {
388   itkDebugMacro("returning Seeds");
389   return this->m_Seeds;
390 }
391 
392 } // end namespace itk
393 
394 #endif
395