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"
29 #include "itkBinaryThresholdImageFilter.h"
30 #include "itkConnectedComponentImageFilter.h"
31 #include "itkRelabelComponentImageFilter.h"
32 #include "itkBinaryMorphologicalClosingImageFilter.h"
33 #include "itkBinaryMorphologicalOpeningImageFilter.h"
34 #include "itkBinaryBallStructuringElement.h"
35 #include "itkCastImageFilter.h"
37 //--------------------------------------------------------------------
38 template <class TInputImageType, class TOutputImageType>
39 clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
40 ExtractPatientFilter():
42 itk::ImageToImageFilter<TInputImageType, TOutputImageType>()
44 this->SetNumberOfRequiredInputs(1);
45 SetBackgroundValue(0); // Must be zero
46 SetForegroundValue(1);
48 // Step 1: Threshold + CC + sort (Find low density areas)
49 SetUpperThreshold(-300);
50 SetLowerThreshold(-1000);
51 UseLowerThresholdOff();
53 // Step 2: DecomposeAndReconstructImageFilter (optional)
54 DecomposeAndReconstructDuringFirstStepOff();
55 InternalImageSizeType r;
58 SetMaximumNumberOfLabels1(2);
59 SetNumberOfNewLabels1(1);
61 // Step 3: Remove the air (largest area).
63 // Step 4: 2nd DecomposeAndReconstructImageFilter
64 DecomposeAndReconstructDuringSecondStepOff();
66 SetMaximumNumberOfLabels2(2);
67 SetNumberOfNewLabels2(1);
69 // Step 5: Only keep label corresponding (Keep patient's labels)
73 // Step 4: OpenClose (option)
77 //--------------------------------------------------------------------
80 //--------------------------------------------------------------------
81 template <class TInputImageType, class TOutputImageType>
83 clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
84 SetInput(const TInputImageType * image)
86 this->SetNthInput(0, const_cast<TInputImageType *>(image));
88 //--------------------------------------------------------------------
91 //--------------------------------------------------------------------
92 template <class TInputImageType, class TOutputImageType>
93 template<class ArgsInfoType>
95 clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
96 SetArgsInfo(ArgsInfoType arg)
98 SetVerboseOption_GGO(arg);
99 SetVerboseStep_GGO(arg);
100 SetWriteStep_GGO(arg);
101 SetVerboseWarningOff_GGO(arg);
103 SetUpperThreshold_GGO(arg);
104 SetLowerThreshold_GGO(arg);
106 SetDecomposeAndReconstructDuringFirstStep_GGO(arg);
108 SetMaximumNumberOfLabels1_GGO(arg);
109 SetNumberOfNewLabels1_GGO(arg);
111 SetDecomposeAndReconstructDuringSecondStep_GGO(arg);
113 SetMaximumNumberOfLabels2_GGO(arg);
114 SetNumberOfNewLabels2_GGO(arg);
116 SetFirstKeep_GGO(arg);
117 SetLastKeep_GGO(arg);
119 SetFinalOpenClose_GGO(arg);
120 SetAutoCrop_GGO(arg);
122 //--------------------------------------------------------------------
125 //--------------------------------------------------------------------
126 template <class TInputImageType, class TOutputImageType>
128 clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
129 GenerateOutputInformation() {
131 Superclass::GenerateOutputInformation();
132 input = dynamic_cast<const TInputImageType*>(itk::ProcessObject::GetInput(0));
134 // OutputImagePointer outputImage = this->GetOutput(0);
135 // outputImage->SetRegions(input->GetLargestPossibleRegion());
137 // Get input pointers
138 static const unsigned int Dim = InputImageType::ImageDimension;
139 //input = dynamic_cast<const TInputImageType*>(itk::ProcessObject::GetInput(0));
141 //--------------------------------------------------------------------
142 //--------------------------------------------------------------------
144 StartNewStep("Find low densities areas");
145 typedef itk::BinaryThresholdImageFilter<InputImageType, InternalImageType> BinarizeFilterType;
146 typename BinarizeFilterType::Pointer binarizeFilter=BinarizeFilterType::New();
147 binarizeFilter->SetInput(input);
148 if (m_UseLowerThreshold) binarizeFilter->SetLowerThreshold(GetLowerThreshold());
149 binarizeFilter->SetUpperThreshold(GetUpperThreshold());
150 binarizeFilter ->SetInsideValue(this->GetForegroundValue());
151 binarizeFilter ->SetOutsideValue(this->GetBackgroundValue());
153 // Connected component labeling
154 typedef itk::ConnectedComponentImageFilter<InternalImageType, InternalImageType> ConnectFilterType;
155 typename ConnectFilterType::Pointer connectFilter=ConnectFilterType::New();
156 connectFilter->SetInput(binarizeFilter->GetOutput());
157 connectFilter->SetBackgroundValue(this->GetBackgroundValue());
158 connectFilter->SetFullyConnected(false);
160 // Sort labels according to size
161 typedef itk::RelabelComponentImageFilter<InternalImageType, InternalImageType> RelabelFilterType;
162 typename RelabelFilterType::Pointer relabelFilter=RelabelFilterType::New();
163 relabelFilter->InPlaceOn();
164 relabelFilter->SetInput(connectFilter->GetOutput());
165 relabelFilter->Update();
166 working_image = relabelFilter->GetOutput();
169 StopCurrentStep<InternalImageType>(working_image);
171 //--------------------------------------------------------------------
172 //--------------------------------------------------------------------
174 if (GetDecomposeAndReconstructDuringFirstStep()) {
175 StartNewStep("First Decompose & Reconstruct step");
176 typedef clitk::DecomposeAndReconstructImageFilter<InternalImageType,InternalImageType> FilterType;
177 typename FilterType::Pointer f = FilterType::New();
178 f->SetInput(working_image);
179 // f->SetVerbose(m_Verbose);
180 f->SetRadius(GetRadius1());
181 f->SetMaximumNumberOfLabels(GetMaximumNumberOfLabels1());
182 f->SetBackgroundValue(this->GetBackgroundValue());
183 f->SetForegroundValue(this->GetForegroundValue());
184 f->SetFullyConnected(true);
185 f->SetNumberOfNewLabels(GetNumberOfNewLabels1());
187 working_image = f->GetOutput();
188 StopCurrentStep<InternalImageType>(working_image);
191 //--------------------------------------------------------------------
192 //--------------------------------------------------------------------
193 StartNewStep("Remove the air (largest area)");
194 typedef itk::BinaryThresholdImageFilter<InternalImageType, InternalImageType> iBinarizeFilterType;
195 typename iBinarizeFilterType::Pointer binarizeFilter2 = iBinarizeFilterType::New();
196 binarizeFilter2->SetInput(working_image);
197 binarizeFilter2->SetLowerThreshold(GetFirstKeep());
198 binarizeFilter2->SetUpperThreshold(GetLastKeep());
199 binarizeFilter2 ->SetInsideValue(0);
200 binarizeFilter2 ->SetOutsideValue(1);
201 // binarizeFilter2 ->Update(); // NEEDED ?
203 typename ConnectFilterType::Pointer connectFilter2 = ConnectFilterType::New();
204 connectFilter2->SetInput(binarizeFilter2->GetOutput());
205 connectFilter2->SetBackgroundValue(this->GetBackgroundValue());
206 connectFilter2->SetFullyConnected(false);
208 typename RelabelFilterType::Pointer relabelFilter2 = RelabelFilterType::New();
209 relabelFilter2->SetInput(connectFilter2->GetOutput());
210 relabelFilter2->Update();
211 working_image = relabelFilter2->GetOutput();
212 StopCurrentStep<InternalImageType>(working_image);
214 //--------------------------------------------------------------------
215 //--------------------------------------------------------------------
217 if (GetDecomposeAndReconstructDuringSecondStep()) {
218 StartNewStep("Second Decompose & Reconstruct step");
219 typedef clitk::DecomposeAndReconstructImageFilter<InternalImageType,InternalImageType> FilterType;
220 typename FilterType::Pointer f = FilterType::New();
221 f->SetInput(working_image);
222 // f->SetVerbose(m_Verbose);
223 f->SetRadius(GetRadius2());
224 f->SetMaximumNumberOfLabels(GetMaximumNumberOfLabels2());
225 f->SetBackgroundValue(this->GetBackgroundValue());
226 f->SetForegroundValue(this->GetForegroundValue());
227 f->SetFullyConnected(true);
228 f->SetNumberOfNewLabels(GetNumberOfNewLabels2());
230 working_image = f->GetOutput();
231 StopCurrentStep<InternalImageType>(working_image);
234 //--------------------------------------------------------------------
235 //--------------------------------------------------------------------
237 if (GetFinalOpenClose()) {
238 StartNewStep("Final OpenClose");
240 typedef itk::BinaryBallStructuringElement<InternalPixelType,Dim> KernelType;
241 KernelType structuringElement;
242 structuringElement.SetRadius(1);
243 structuringElement.CreateStructuringElement();
244 typedef itk::BinaryMorphologicalOpeningImageFilter<InternalImageType, InternalImageType , KernelType> OpenFilterType;
245 typename OpenFilterType::Pointer openFilter = OpenFilterType::New();
246 openFilter->SetInput(working_image);
247 openFilter->SetBackgroundValue(this->GetBackgroundValue());
248 openFilter->SetForegroundValue(this->GetForegroundValue());
249 openFilter->SetKernel(structuringElement);
251 typedef itk::BinaryMorphologicalClosingImageFilter<InternalImageType, InternalImageType , KernelType> CloseFilterType;
252 typename CloseFilterType::Pointer closeFilter = CloseFilterType::New();
253 closeFilter->SetInput(openFilter->GetOutput());
254 closeFilter->SetSafeBorder(true);
255 closeFilter->SetForegroundValue(this->GetForegroundValue());
256 // closeFilter->SetBackgroundValue(SetBackgroundValue());
257 closeFilter->SetKernel(structuringElement);
258 closeFilter->Update();
259 working_image = closeFilter->GetOutput();
260 StopCurrentStep<InternalImageType>(working_image);
263 //--------------------------------------------------------------------
264 //--------------------------------------------------------------------
266 typedef itk::CastImageFilter<InternalImageType, OutputImageType> CastImageFilterType;
267 typename CastImageFilterType::Pointer caster= CastImageFilterType::New();
268 caster->SetInput(working_image);
270 output = caster->GetOutput();
272 //--------------------------------------------------------------------
273 //--------------------------------------------------------------------
276 StartNewStep("AutoCrop");
277 typedef clitk::AutoCropFilter<OutputImageType> CropFilterType;
278 typename CropFilterType::Pointer cropFilter = CropFilterType::New();
279 cropFilter->SetInput(output);
280 cropFilter->SetBackgroundValue(GetBackgroundValue());
281 cropFilter->Update();
282 output = cropFilter->GetOutput();
283 StopCurrentStep<OutputImageType>(output);
286 //--------------------------------------------------------------------
289 //--------------------------------------------------------------------
290 template <class TInputImageType, class TOutputImageType>
292 clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
294 //this->SetNthOutput(0, output); // -> no because redo filter otherwise
295 this->GraftOutput(output);
297 //--------------------------------------------------------------------
300 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX