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>
39 clitk::ExtractPatientFilter<TInputImageType>::
40 ExtractPatientFilter():
42 clitk::FilterWithAnatomicalFeatureDatabaseManagement(),
43 itk::ImageToImageFilter<TInputImageType, MaskImageType>()
45 this->SetNumberOfRequiredInputs(1);
46 SetBackgroundValue(0); // Must be zero
47 SetForegroundValue(1);
49 // Step 1: Threshold + CC + sort (Find low density areas)
50 SetUpperThreshold(-300);
51 SetLowerThreshold(-1000);
52 UseLowerThresholdOff();
54 // Step 2: DecomposeAndReconstructImageFilter (optional)
55 DecomposeAndReconstructDuringFirstStepOff();
56 InternalImageSizeType r;
59 SetMaximumNumberOfLabels1(2);
60 SetNumberOfNewLabels1(1);
62 // Step 3: Remove the air (largest area).
64 // Step 4: 2nd DecomposeAndReconstructImageFilter
65 DecomposeAndReconstructDuringSecondStepOff();
67 SetMaximumNumberOfLabels2(2);
68 SetNumberOfNewLabels2(1);
70 // Step 5: Only keep label corresponding (Keep patient's labels)
74 // Step 4: OpenClose (option)
78 //--------------------------------------------------------------------
81 //--------------------------------------------------------------------
82 template <class TInputImageType>
84 clitk::ExtractPatientFilter<TInputImageType>::
85 SetInput(const TInputImageType * image)
87 this->SetNthInput(0, const_cast<TInputImageType *>(image));
89 //--------------------------------------------------------------------
92 //--------------------------------------------------------------------
93 template <class TInputImageType>
94 template<class ArgsInfoType>
96 clitk::ExtractPatientFilter<TInputImageType>::
97 SetArgsInfo(ArgsInfoType arg)
99 SetVerboseOption_GGO(arg);
100 SetVerboseStep_GGO(arg);
101 SetWriteStep_GGO(arg);
102 SetVerboseWarningOff_GGO(arg);
104 SetOutputPatientFilename_GGO(arg);
106 SetUpperThreshold_GGO(arg);
107 SetLowerThreshold_GGO(arg);
109 SetDecomposeAndReconstructDuringFirstStep_GGO(arg);
111 SetMaximumNumberOfLabels1_GGO(arg);
112 SetNumberOfNewLabels1_GGO(arg);
114 SetDecomposeAndReconstructDuringSecondStep_GGO(arg);
116 SetMaximumNumberOfLabels2_GGO(arg);
117 SetNumberOfNewLabels2_GGO(arg);
119 SetFirstKeep_GGO(arg);
120 SetLastKeep_GGO(arg);
122 SetFinalOpenClose_GGO(arg);
123 SetAutoCrop_GGO(arg);
125 SetAFDBFilename_GGO(arg);
127 //--------------------------------------------------------------------
130 //--------------------------------------------------------------------
131 template <class TInputImageType>
133 clitk::ExtractPatientFilter<TInputImageType>::
134 GenerateOutputInformation() {
136 Superclass::GenerateOutputInformation();
137 input = dynamic_cast<const TInputImageType*>(itk::ProcessObject::GetInput(0));
139 // MaskImagePointer outputImage = this->GetOutput(0);
140 // outputImage->SetRegions(input->GetLargestPossibleRegion());
142 // Get input pointers
143 static const unsigned int Dim = InputImageType::ImageDimension;
144 //input = dynamic_cast<const TInputImageType*>(itk::ProcessObject::GetInput(0));
146 //--------------------------------------------------------------------
147 //--------------------------------------------------------------------
149 StartNewStep("Find low densities areas");
150 typedef itk::BinaryThresholdImageFilter<InputImageType, InternalImageType> BinarizeFilterType;
151 typename BinarizeFilterType::Pointer binarizeFilter=BinarizeFilterType::New();
152 binarizeFilter->SetInput(input);
153 if (m_UseLowerThreshold) binarizeFilter->SetLowerThreshold(GetLowerThreshold());
154 binarizeFilter->SetUpperThreshold(GetUpperThreshold());
155 binarizeFilter ->SetInsideValue(this->GetForegroundValue());
156 binarizeFilter ->SetOutsideValue(this->GetBackgroundValue());
158 // Connected component labeling
159 typedef itk::ConnectedComponentImageFilter<InternalImageType, InternalImageType> ConnectFilterType;
160 typename ConnectFilterType::Pointer connectFilter=ConnectFilterType::New();
161 connectFilter->SetInput(binarizeFilter->GetOutput());
162 connectFilter->SetBackgroundValue(this->GetBackgroundValue());
163 connectFilter->SetFullyConnected(false);
165 // Sort labels according to size
166 typedef itk::RelabelComponentImageFilter<InternalImageType, InternalImageType> RelabelFilterType;
167 typename RelabelFilterType::Pointer relabelFilter=RelabelFilterType::New();
168 relabelFilter->InPlaceOn();
169 relabelFilter->SetInput(connectFilter->GetOutput());
170 relabelFilter->Update();
171 working_image = relabelFilter->GetOutput();
174 StopCurrentStep<InternalImageType>(working_image);
176 //--------------------------------------------------------------------
177 //--------------------------------------------------------------------
179 if (GetDecomposeAndReconstructDuringFirstStep()) {
180 StartNewStep("First Decompose & Reconstruct step");
181 typedef clitk::DecomposeAndReconstructImageFilter<InternalImageType,InternalImageType> FilterType;
182 typename FilterType::Pointer f = FilterType::New();
183 f->SetInput(working_image);
184 // f->SetVerbose(m_Verbose);
185 f->SetRadius(GetRadius1());
186 f->SetMaximumNumberOfLabels(GetMaximumNumberOfLabels1());
187 f->SetBackgroundValue(this->GetBackgroundValue());
188 f->SetForegroundValue(this->GetForegroundValue());
189 f->SetFullyConnected(true);
190 f->SetNumberOfNewLabels(GetNumberOfNewLabels1());
192 working_image = f->GetOutput();
193 StopCurrentStep<InternalImageType>(working_image);
196 //--------------------------------------------------------------------
197 //--------------------------------------------------------------------
198 StartNewStep("Remove the air (largest area)");
199 typedef itk::BinaryThresholdImageFilter<InternalImageType, InternalImageType> iBinarizeFilterType;
200 typename iBinarizeFilterType::Pointer binarizeFilter2 = iBinarizeFilterType::New();
201 binarizeFilter2->SetInput(working_image);
202 binarizeFilter2->SetLowerThreshold(GetFirstKeep());
203 binarizeFilter2->SetUpperThreshold(GetLastKeep());
204 binarizeFilter2 ->SetInsideValue(0);
205 binarizeFilter2 ->SetOutsideValue(1);
206 // binarizeFilter2 ->Update(); // NEEDED ?
208 typename ConnectFilterType::Pointer connectFilter2 = ConnectFilterType::New();
209 connectFilter2->SetInput(binarizeFilter2->GetOutput());
210 connectFilter2->SetBackgroundValue(this->GetBackgroundValue());
211 connectFilter2->SetFullyConnected(false);
213 typename RelabelFilterType::Pointer relabelFilter2 = RelabelFilterType::New();
214 relabelFilter2->SetInput(connectFilter2->GetOutput());
215 relabelFilter2->Update();
216 working_image = relabelFilter2->GetOutput();
219 working_image = KeepLabels<InternalImageType>
220 (working_image, GetBackgroundValue(), GetForegroundValue(), 1, 1, true);
221 StopCurrentStep<InternalImageType>(working_image);
223 //--------------------------------------------------------------------
224 //--------------------------------------------------------------------
226 if (GetDecomposeAndReconstructDuringSecondStep()) {
227 StartNewStep("Second Decompose & Reconstruct step");
228 typedef clitk::DecomposeAndReconstructImageFilter<InternalImageType,InternalImageType> FilterType;
229 typename FilterType::Pointer f = FilterType::New();
230 f->SetInput(working_image);
231 // f->SetVerbose(m_Verbose);
232 f->SetRadius(GetRadius2());
233 f->SetMaximumNumberOfLabels(GetMaximumNumberOfLabels2());
234 f->SetBackgroundValue(this->GetBackgroundValue());
235 f->SetForegroundValue(this->GetForegroundValue());
236 f->SetFullyConnected(true);
237 f->SetNumberOfNewLabels(GetNumberOfNewLabels2());
239 working_image = f->GetOutput();
240 StopCurrentStep<InternalImageType>(working_image);
243 //--------------------------------------------------------------------
244 //--------------------------------------------------------------------
246 if (GetFinalOpenClose()) {
247 StartNewStep("Final OpenClose");
249 typedef itk::BinaryBallStructuringElement<InternalPixelType,Dim> KernelType;
250 KernelType structuringElement;
251 structuringElement.SetRadius(1);
252 structuringElement.CreateStructuringElement();
253 typedef itk::BinaryMorphologicalOpeningImageFilter<InternalImageType, InternalImageType , KernelType> OpenFilterType;
254 typename OpenFilterType::Pointer openFilter = OpenFilterType::New();
255 openFilter->SetInput(working_image);
256 openFilter->SetBackgroundValue(this->GetBackgroundValue());
257 openFilter->SetForegroundValue(this->GetForegroundValue());
258 openFilter->SetKernel(structuringElement);
260 typedef itk::BinaryMorphologicalClosingImageFilter<InternalImageType, InternalImageType , KernelType> CloseFilterType;
261 typename CloseFilterType::Pointer closeFilter = CloseFilterType::New();
262 closeFilter->SetInput(openFilter->GetOutput());
263 closeFilter->SetSafeBorder(true);
264 closeFilter->SetForegroundValue(this->GetForegroundValue());
265 // closeFilter->SetBackgroundValue(SetBackgroundValue());
266 closeFilter->SetKernel(structuringElement);
267 closeFilter->Update();
268 working_image = closeFilter->GetOutput();
269 StopCurrentStep<InternalImageType>(working_image);
272 //--------------------------------------------------------------------
273 //--------------------------------------------------------------------
275 typedef itk::CastImageFilter<InternalImageType, MaskImageType> CastImageFilterType;
276 typename CastImageFilterType::Pointer caster= CastImageFilterType::New();
277 caster->SetInput(working_image);
279 output = caster->GetOutput();
281 //--------------------------------------------------------------------
282 //--------------------------------------------------------------------
285 StartNewStep("AutoCrop");
286 typedef clitk::AutoCropFilter<MaskImageType> CropFilterType;
287 typename CropFilterType::Pointer cropFilter = CropFilterType::New();
288 cropFilter->SetInput(output);
289 cropFilter->SetBackgroundValue(GetBackgroundValue());
290 cropFilter->Update();
291 output = cropFilter->GetOutput();
292 StopCurrentStep<MaskImageType>(output);
295 //--------------------------------------------------------------------
298 //--------------------------------------------------------------------
299 template <class TInputImageType>
301 clitk::ExtractPatientFilter<TInputImageType>::
304 this->GraftOutput(output);
305 // Store image filename into AFDB
306 GetAFDB()->SetImageFilename("patient", this->GetOutputPatientFilename());
309 //--------------------------------------------------------------------
312 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX