1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ======================================================================-====*/
19 #ifndef CLITKEXTRACTPATIENTFILTER_TXX
20 #define CLITKEXTRACTPATIENTFILTER_TXX
23 #include "clitkImageCommon.h"
24 #include "clitkSetBackgroundImageFilter.h"
25 #include "clitkDecomposeAndReconstructImageFilter.h"
26 #include "clitkAutoCropFilter.h"
27 #include "clitkMemoryUsage.h"
30 #include "itkBinaryThresholdImageFilter.h"
31 #include "itkConnectedComponentImageFilter.h"
32 #include "itkRelabelComponentImageFilter.h"
33 #include "itkBinaryMorphologicalClosingImageFilter.h"
34 #include "itkBinaryMorphologicalOpeningImageFilter.h"
35 #include "itkBinaryBallStructuringElement.h"
36 #include "itkCastImageFilter.h"
38 //--------------------------------------------------------------------
39 template <class TInputImageType>
40 clitk::ExtractPatientFilter<TInputImageType>::
41 ExtractPatientFilter():
43 clitk::FilterWithAnatomicalFeatureDatabaseManagement(),
44 itk::ImageToImageFilter<TInputImageType, MaskImageType>()
46 this->SetNumberOfRequiredInputs(1);
47 SetBackgroundValue(0); // Must be zero
48 SetForegroundValue(1);
50 // Step 1: Threshold + CC + sort (Find low density areas)
51 SetUpperThreshold(-300);
52 SetLowerThreshold(-1000);
53 UseLowerThresholdOff();
55 // Step 2: DecomposeAndReconstructImageFilter (optional)
56 DecomposeAndReconstructDuringFirstStepOff();
57 InternalImageSizeType r;
60 SetMaximumNumberOfLabels1(2);
61 SetNumberOfNewLabels1(1);
63 // Step 3: Remove the air (largest area).
65 // Step 4: 2nd DecomposeAndReconstructImageFilter
66 DecomposeAndReconstructDuringSecondStepOff();
68 SetMaximumNumberOfLabels2(2);
69 SetNumberOfNewLabels2(1);
71 // Step 5: Only keep label corresponding (Keep patient's labels)
75 // Step 4: OpenClose (option)
79 //--------------------------------------------------------------------
82 //--------------------------------------------------------------------
83 template <class TInputImageType>
85 clitk::ExtractPatientFilter<TInputImageType>::
86 SetInput(const TInputImageType * image)
88 this->SetNthInput(0, const_cast<TInputImageType *>(image));
90 //--------------------------------------------------------------------
93 //--------------------------------------------------------------------
94 template <class TInputImageType>
96 clitk::ExtractPatientFilter<TInputImageType>::
97 GenerateOutputInformation() {
99 clitk::PrintMemory(GetVerboseMemoryFlag(), "Initial memory"); // OK
101 Superclass::GenerateOutputInformation();
102 input = dynamic_cast<const TInputImageType*>(itk::ProcessObject::GetInput(0));
104 // MaskImagePointer outputImage = this->GetOutput(0);
105 // outputImage->SetRegions(input->GetLargestPossibleRegion());
107 // Get input pointers
108 static const unsigned int Dim = InputImageType::ImageDimension;
109 //input = dynamic_cast<const TInputImageType*>(itk::ProcessObject::GetInput(0));
111 //--------------------------------------------------------------------
112 //--------------------------------------------------------------------
114 StartNewStep("Find low densities areas");
115 typedef itk::BinaryThresholdImageFilter<InputImageType, InternalImageType> BinarizeFilterType;
116 typename BinarizeFilterType::Pointer binarizeFilter=BinarizeFilterType::New();
117 binarizeFilter->SetInput(input);
118 if (m_UseLowerThreshold) binarizeFilter->SetLowerThreshold(GetLowerThreshold());
119 binarizeFilter->SetUpperThreshold(GetUpperThreshold());
120 binarizeFilter ->SetInsideValue(this->GetForegroundValue());
121 binarizeFilter ->SetOutsideValue(this->GetBackgroundValue());
123 // Connected component labeling
124 typedef itk::ConnectedComponentImageFilter<InternalImageType, InternalImageType> ConnectFilterType;
125 typename ConnectFilterType::Pointer connectFilter=ConnectFilterType::New();
126 connectFilter->SetInput(binarizeFilter->GetOutput());
127 connectFilter->SetBackgroundValue(this->GetBackgroundValue());
128 connectFilter->SetFullyConnected(false);
130 // Sort labels according to size
131 typedef itk::RelabelComponentImageFilter<InternalImageType, InternalImageType> RelabelFilterType;
132 typename RelabelFilterType::Pointer relabelFilter=RelabelFilterType::New();
133 relabelFilter->InPlaceOn();
134 relabelFilter->SetInput(connectFilter->GetOutput());
135 relabelFilter->Update();
136 working_image = relabelFilter->GetOutput();
139 StopCurrentStep<InternalImageType>(working_image);
141 //--------------------------------------------------------------------
142 //--------------------------------------------------------------------
144 if (GetDecomposeAndReconstructDuringFirstStep()) {
145 StartNewStep("First Decompose & Reconstruct step");
146 typedef clitk::DecomposeAndReconstructImageFilter<InternalImageType,InternalImageType> FilterType;
147 typename FilterType::Pointer f = FilterType::New();
148 f->SetInput(working_image);
149 // f->SetVerbose(m_Verbose);
150 f->SetRadius(GetRadius1());
151 f->SetMaximumNumberOfLabels(GetMaximumNumberOfLabels1());
152 f->SetBackgroundValue(this->GetBackgroundValue());
153 f->SetForegroundValue(this->GetForegroundValue());
154 f->SetFullyConnected(true);
155 f->SetNumberOfNewLabels(GetNumberOfNewLabels1());
157 working_image = f->GetOutput();
158 StopCurrentStep<InternalImageType>(working_image);
161 //--------------------------------------------------------------------
162 //--------------------------------------------------------------------
163 StartNewStep("Remove the air (largest area)");
164 typedef itk::BinaryThresholdImageFilter<InternalImageType, InternalImageType> iBinarizeFilterType;
165 typename iBinarizeFilterType::Pointer binarizeFilter2 = iBinarizeFilterType::New();
166 binarizeFilter2->SetInput(working_image);
167 binarizeFilter2->SetLowerThreshold(GetFirstKeep());
168 binarizeFilter2->SetUpperThreshold(GetLastKeep());
169 binarizeFilter2 ->SetInsideValue(0);
170 binarizeFilter2 ->SetOutsideValue(1);
171 // binarizeFilter2 ->Update(); // NEEDED ?
173 typename ConnectFilterType::Pointer connectFilter2 = ConnectFilterType::New();
174 connectFilter2->SetInput(binarizeFilter2->GetOutput());
175 connectFilter2->SetBackgroundValue(this->GetBackgroundValue());
176 connectFilter2->SetFullyConnected(false);
178 typename RelabelFilterType::Pointer relabelFilter2 = RelabelFilterType::New();
179 relabelFilter2->SetInput(connectFilter2->GetOutput());
180 relabelFilter2->Update();
181 working_image = relabelFilter2->GetOutput();
184 working_image = KeepLabels<InternalImageType>
185 (working_image, GetBackgroundValue(), GetForegroundValue(), 1, 1, true);
186 StopCurrentStep<InternalImageType>(working_image);
188 //--------------------------------------------------------------------
189 //--------------------------------------------------------------------
191 if (GetDecomposeAndReconstructDuringSecondStep()) {
192 StartNewStep("Second Decompose & Reconstruct step");
193 typedef clitk::DecomposeAndReconstructImageFilter<InternalImageType,InternalImageType> FilterType;
194 typename FilterType::Pointer f = FilterType::New();
195 f->SetInput(working_image);
196 // f->SetVerbose(m_Verbose);
197 f->SetRadius(GetRadius2());
198 f->SetMaximumNumberOfLabels(GetMaximumNumberOfLabels2());
199 f->SetBackgroundValue(this->GetBackgroundValue());
200 f->SetForegroundValue(this->GetForegroundValue());
201 f->SetFullyConnected(true);
202 f->SetNumberOfNewLabels(GetNumberOfNewLabels2());
204 working_image = f->GetOutput();
205 StopCurrentStep<InternalImageType>(working_image);
208 //--------------------------------------------------------------------
209 //--------------------------------------------------------------------
211 if (GetFinalOpenClose()) {
212 StartNewStep("Final OpenClose");
214 typedef itk::BinaryBallStructuringElement<InternalPixelType,Dim> KernelType;
215 KernelType structuringElement;
216 structuringElement.SetRadius(1);
217 structuringElement.CreateStructuringElement();
218 typedef itk::BinaryMorphologicalOpeningImageFilter<InternalImageType, InternalImageType , KernelType> OpenFilterType;
219 typename OpenFilterType::Pointer openFilter = OpenFilterType::New();
220 openFilter->SetInput(working_image);
221 openFilter->SetBackgroundValue(this->GetBackgroundValue());
222 openFilter->SetForegroundValue(this->GetForegroundValue());
223 openFilter->SetKernel(structuringElement);
225 typedef itk::BinaryMorphologicalClosingImageFilter<InternalImageType, InternalImageType , KernelType> CloseFilterType;
226 typename CloseFilterType::Pointer closeFilter = CloseFilterType::New();
227 closeFilter->SetInput(openFilter->GetOutput());
228 closeFilter->SetSafeBorder(true);
229 closeFilter->SetForegroundValue(this->GetForegroundValue());
230 // closeFilter->SetBackgroundValue(SetBackgroundValue());
231 closeFilter->SetKernel(structuringElement);
232 closeFilter->Update();
233 working_image = closeFilter->GetOutput();
234 StopCurrentStep<InternalImageType>(working_image);
237 //--------------------------------------------------------------------
238 //--------------------------------------------------------------------
240 typedef itk::CastImageFilter<InternalImageType, MaskImageType> CastImageFilterType;
241 typename CastImageFilterType::Pointer caster= CastImageFilterType::New();
242 caster->SetInput(working_image);
244 output = caster->GetOutput();
246 //--------------------------------------------------------------------
247 //--------------------------------------------------------------------
250 StartNewStep("AutoCrop");
251 typedef clitk::AutoCropFilter<MaskImageType> CropFilterType;
252 typename CropFilterType::Pointer cropFilter = CropFilterType::New();
253 cropFilter->SetInput(output);
254 cropFilter->SetBackgroundValue(GetBackgroundValue());
255 cropFilter->Update();
256 output = cropFilter->GetOutput();
257 StopCurrentStep<MaskImageType>(output);
260 //--------------------------------------------------------------------
263 //--------------------------------------------------------------------
264 template <class TInputImageType>
266 clitk::ExtractPatientFilter<TInputImageType>::
269 this->GraftOutput(output);
270 // Store image filename into AFDB
271 GetAFDB()->SetImageFilename("Patient", this->GetOutputPatientFilename());
274 //--------------------------------------------------------------------
277 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX