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(this->GetForegroundValue());
198 binarizeFilter2->SetUpperThreshold(this->GetForegroundValue());
199 binarizeFilter2 ->SetInsideValue(this->GetBackgroundValue());
200 binarizeFilter2 ->SetOutsideValue(this->GetForegroundValue());
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 //--------------------------------------------------------------------
236 StartNewStep("Keep patient's labels");
237 typename iBinarizeFilterType::Pointer binarizeFilter3 = iBinarizeFilterType::New();
238 binarizeFilter3->SetInput(working_image);
239 binarizeFilter3->SetLowerThreshold(GetFirstKeep());
240 binarizeFilter3->SetUpperThreshold(GetLastKeep());
241 binarizeFilter3 ->SetInsideValue(this->GetForegroundValue());
242 binarizeFilter3 ->SetOutsideValue(this->GetBackgroundValue());
243 binarizeFilter3->Update();
244 working_image = binarizeFilter3->GetOutput();
245 StopCurrentStep<InternalImageType>(working_image);
247 //--------------------------------------------------------------------
248 //--------------------------------------------------------------------
250 if (GetFinalOpenClose()) {
251 StartNewStep("Final OpenClose");
253 typedef itk::BinaryBallStructuringElement<InternalPixelType,Dim> KernelType;
254 KernelType structuringElement;
255 structuringElement.SetRadius(1);
256 structuringElement.CreateStructuringElement();
257 typedef itk::BinaryMorphologicalOpeningImageFilter<InternalImageType, InternalImageType , KernelType> OpenFilterType;
258 typename OpenFilterType::Pointer openFilter = OpenFilterType::New();
259 openFilter->SetInput(working_image);
260 openFilter->SetBackgroundValue(this->GetBackgroundValue());
261 openFilter->SetForegroundValue(this->GetForegroundValue());
262 openFilter->SetKernel(structuringElement);
264 typedef itk::BinaryMorphologicalClosingImageFilter<InternalImageType, InternalImageType , KernelType> CloseFilterType;
265 typename CloseFilterType::Pointer closeFilter = CloseFilterType::New();
266 closeFilter->SetInput(openFilter->GetOutput());
267 closeFilter->SetSafeBorder(true);
268 closeFilter->SetForegroundValue(this->GetForegroundValue());
269 // closeFilter->SetBackgroundValue(SetBackgroundValue());
270 closeFilter->SetKernel(structuringElement);
271 closeFilter->Update();
272 working_image = closeFilter->GetOutput();
273 StopCurrentStep<InternalImageType>(working_image);
276 //--------------------------------------------------------------------
277 //--------------------------------------------------------------------
279 typedef itk::CastImageFilter<InternalImageType, OutputImageType> CastImageFilterType;
280 typename CastImageFilterType::Pointer caster= CastImageFilterType::New();
281 caster->SetInput(working_image);
283 output = caster->GetOutput();
285 //--------------------------------------------------------------------
286 //--------------------------------------------------------------------
289 StartNewStep("AutoCrop");
290 typedef clitk::AutoCropFilter<OutputImageType> CropFilterType;
291 typename CropFilterType::Pointer cropFilter = CropFilterType::New();
292 cropFilter->SetInput(output);
293 cropFilter->SetBackgroundValue(GetBackgroundValue());
294 cropFilter->Update();
295 output = cropFilter->GetOutput();
296 StopCurrentStep<OutputImageType>(output);
299 //--------------------------------------------------------------------
302 //--------------------------------------------------------------------
303 template <class TInputImageType, class TOutputImageType>
305 clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
307 //this->SetNthOutput(0, output); // -> no because redo filter otherwise
308 this->GraftOutput(output);
310 //--------------------------------------------------------------------
313 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX