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 CLITKEXTRACTMEDIASTINUMFILTER_TXX
20 #define CLITKEXTRACTMEDIASTINUMFILTER_TXX
23 #include "clitkCommon.h"
24 #include "clitkExtractMediastinumFilter.h"
25 #include "clitkAddRelativePositionConstraintToLabelImageFilter.h"
26 #include "clitkSegmentationUtils.h"
27 #include "clitkExtractAirwayTreeInfoFilter.h"
31 #include "itkStatisticsLabelMapFilter.h"
32 #include "itkLabelImageToStatisticsLabelMapFilter.h"
33 #include "itkRegionOfInterestImageFilter.h"
34 #include "itkBinaryThresholdImageFilter.h"
37 #include "RelativePositionPropImageFilter.h"
39 //--------------------------------------------------------------------
40 template <class ImageType>
41 clitk::ExtractMediastinumFilter<ImageType>::
42 ExtractMediastinumFilter():
44 itk::ImageToImageFilter<ImageType, ImageType>()
46 this->SetNumberOfRequiredInputs(4);
48 SetBackgroundValuePatient(0);
49 SetBackgroundValueLung(0);
50 SetBackgroundValueBones(0);
51 SetForegroundValueLeftLung(1);
52 SetForegroundValueRightLung(2);
53 SetBackgroundValue(0);
54 SetForegroundValue(1);
56 SetIntermediateSpacing(6);
57 SetFuzzyThreshold1(0.4);
58 SetFuzzyThreshold2(0.6);
59 SetFuzzyThreshold3(0.2);
61 //--------------------------------------------------------------------
64 //--------------------------------------------------------------------
65 template <class ImageType>
67 clitk::ExtractMediastinumFilter<ImageType>::
68 SetInputPatientLabelImage(const ImageType * image, ImagePixelType bg)
70 this->SetNthInput(0, const_cast<ImageType *>(image));
71 m_BackgroundValuePatient = bg;
73 //--------------------------------------------------------------------
76 //--------------------------------------------------------------------
77 template <class ImageType>
79 clitk::ExtractMediastinumFilter<ImageType>::
80 SetInputLungLabelImage(const ImageType * image, ImagePixelType bg,
81 ImagePixelType fgLeft, ImagePixelType fgRight)
83 this->SetNthInput(1, const_cast<ImageType *>(image));
84 m_BackgroundValueLung = bg;
85 m_ForegroundValueLeftLung = fgLeft;
86 m_ForegroundValueRightLung = fgRight;
88 //--------------------------------------------------------------------
91 //--------------------------------------------------------------------
92 template <class ImageType>
94 clitk::ExtractMediastinumFilter<ImageType>::
95 SetInputBonesLabelImage(const ImageType * image, ImagePixelType bg)
97 this->SetNthInput(2, const_cast<ImageType *>(image));
98 m_BackgroundValueBones = bg;
100 //--------------------------------------------------------------------
103 //--------------------------------------------------------------------
104 template <class ImageType>
106 clitk::ExtractMediastinumFilter<ImageType>::
107 SetInputTracheaLabelImage(const ImageType * image, ImagePixelType bg)
109 this->SetNthInput(3, const_cast<ImageType *>(image));
110 m_BackgroundValueTrachea = bg;
112 //--------------------------------------------------------------------
115 //--------------------------------------------------------------------
116 template <class ImageType>
117 template<class ArgsInfoType>
119 clitk::ExtractMediastinumFilter<ImageType>::
120 SetArgsInfo(ArgsInfoType mArgsInfo)
122 SetVerboseOption_GGO(mArgsInfo);
123 SetVerboseStep_GGO(mArgsInfo);
124 SetWriteStep_GGO(mArgsInfo);
125 SetVerboseWarningOff_GGO(mArgsInfo);
127 SetBackgroundValuePatient_GGO(mArgsInfo);
128 SetBackgroundValueLung_GGO(mArgsInfo);
129 SetBackgroundValueTrachea_GGO(mArgsInfo);
131 SetForegroundValueLeftLung_GGO(mArgsInfo);
132 SetForegroundValueRightLung_GGO(mArgsInfo);
134 SetIntermediateSpacing_GGO(mArgsInfo);
135 SetFuzzyThreshold1_GGO(mArgsInfo);
136 SetFuzzyThreshold2_GGO(mArgsInfo);
137 SetFuzzyThreshold3_GGO(mArgsInfo);
139 //--------------------------------------------------------------------
142 //--------------------------------------------------------------------
143 template <class ImageType>
145 clitk::ExtractMediastinumFilter<ImageType>::
146 GenerateOutputInformation() {
147 ImagePointer input = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
148 ImagePointer outputImage = this->GetOutput(0);
149 outputImage->SetRegions(outputImage->GetLargestPossibleRegion());
151 //--------------------------------------------------------------------
154 //--------------------------------------------------------------------
155 template <class ImageType>
157 clitk::ExtractMediastinumFilter<ImageType>::
158 GenerateInputRequestedRegion()
161 Superclass::GenerateInputRequestedRegion();
162 // Get input pointers
163 ImagePointer patient = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
164 ImagePointer lung = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(1));
165 ImagePointer bones = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(2));
166 ImagePointer trachea = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(3));
168 patient->SetRequestedRegion(patient->GetLargestPossibleRegion());
169 lung->SetRequestedRegion(lung->GetLargestPossibleRegion());
170 bones->SetRequestedRegion(bones->GetLargestPossibleRegion());
171 trachea->SetRequestedRegion(trachea->GetLargestPossibleRegion());
173 //--------------------------------------------------------------------
176 //--------------------------------------------------------------------
177 template <class ImageType>
179 clitk::ExtractMediastinumFilter<ImageType>::
182 // Get input pointers
183 ImageConstPointer patient = dynamic_cast<const ImageType*>(itk::ProcessObject::GetInput(0));
184 ImageConstPointer lung = dynamic_cast<const ImageType*>(itk::ProcessObject::GetInput(1));
185 ImageConstPointer bones = dynamic_cast<const ImageType*>(itk::ProcessObject::GetInput(2));
186 ImageConstPointer trachea = dynamic_cast<const ImageType*>(itk::ProcessObject::GetInput(3));
188 // Get output pointer
191 // Step 1: patient minus lungs, minus bones
192 StartNewStep("Patient contours minus lungs and minus bones");
193 typedef clitk::BooleanOperatorLabelImageFilter<ImageType> BoolFilterType;
194 typename BoolFilterType::Pointer boolFilter = BoolFilterType::New();
195 boolFilter->InPlaceOn();
196 boolFilter->SetInput1(patient);
197 boolFilter->SetInput2(lung);
198 boolFilter->SetOperationType(BoolFilterType::AndNot);
199 boolFilter->Update();
200 boolFilter->SetInput1(boolFilter->GetOutput());
201 boolFilter->SetInput2(bones);
202 boolFilter->SetOperationType(BoolFilterType::AndNot);
203 boolFilter->Update();
204 output = boolFilter->GetOutput();
206 // Auto crop to gain support area
207 output = clitk::AutoCrop<ImageType>(output, GetBackgroundValue());
208 this->template StopCurrentStep<ImageType>(output);
210 // Step 2: LR limits from lung (need separate lung ?)
211 StartNewStep("Left/Right limits with lungs");
213 /* // WE DO NOT NEED THE FOLLOWING
214 // Get separate lung images to get only the right and left lung
215 // (label must be '1' because right is greater than left).
216 ImagePointer right_lung = clitk::SetBackground<ImageType, ImageType>(lung, lung, 2, 0);
217 ImagePointer left_lung = clitk::SetBackground<ImageType, ImageType>(lung, lung, 1, 0);
218 writeImage<ImageType>(right_lung, "right.mhd");
219 writeImage<ImageType>(left_lung, "left.mhd");
222 typedef clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType> RelPosFilterType;
223 typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New();
224 relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId());
225 relPosFilter->VerboseStepOff();
226 relPosFilter->WriteStepOff();
227 relPosFilter->SetInput(output);
228 DD(output->GetLargestPossibleRegion().GetIndex());
229 // relPosFilter->SetInputObject(left_lung);
230 relPosFilter->SetInputObject(lung);
231 relPosFilter->SetOrientationType(RelPosFilterType::LeftTo); // warning left lung is at right ;)
232 relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing());
233 relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1());
234 relPosFilter->Update();
235 output = relPosFilter->GetOutput();
236 DD(output->GetLargestPossibleRegion());
238 relPosFilter->SetInput(output);
239 relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId());
240 relPosFilter->VerboseStepOff();
241 relPosFilter->WriteStepOff();
242 // relPosFilter->SetInputObject(right_lung);
243 relPosFilter->SetInputObject(lung);
244 relPosFilter->SetOrientationType(RelPosFilterType::RightTo);
245 relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing());
246 relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1());
247 relPosFilter->Update();
248 output = relPosFilter->GetOutput();
249 DD(output->GetLargestPossibleRegion());
250 this->template StopCurrentStep<ImageType>(output);
252 // Step 3: AP limits from bones
253 StartNewStep("Ant/Post limits with bones");
254 ImageConstPointer bones_ant;
255 ImageConstPointer bones_post;
257 // Find ant-post coordinate of trachea (assume the carena position is a
258 // good estimation of the ant-post position of the trachea)
259 typedef clitk::ExtractAirwayTreeInfoFilter<ImageType> AirwayFilter;
260 typename AirwayFilter::Pointer airwayfilter = AirwayFilter::New();
261 airwayfilter->SetVerboseStep(false);
262 airwayfilter->SetWriteStep(false);
263 airwayfilter->SetInput(trachea);
264 airwayfilter->Update();
265 DD(airwayfilter->GetFirstTracheaPoint());
266 ImagePointType point_trachea = airwayfilter->GetCarinaPoint();
267 ImageIndexType index_trachea;
268 bones->TransformPhysicalPointToIndex(point_trachea, index_trachea);
272 // Split bone image first into two parts (ant and post)
273 typedef itk::RegionOfInterestImageFilter<ImageType, ImageType> CropFilterType;
274 // typedef itk::ExtractImageFilter<ImageType, ImageType> CropFilterType;
275 typename CropFilterType::Pointer cropFilter = CropFilterType::New();
276 ImageRegionType region = bones->GetLargestPossibleRegion();
277 ImageSizeType size = region.GetSize();
279 size[1] = index_trachea[1]; //size[1]/2.0;
281 region.SetSize(size);
282 cropFilter->SetInput(bones);
283 // cropFilter->SetExtractionRegion(region);
284 cropFilter->SetRegionOfInterest(region);
285 cropFilter->ReleaseDataFlagOff();
286 cropFilter->Update();
287 bones_ant = cropFilter->GetOutput();
288 writeImage<ImageType>(bones_ant, "b_ant.mhd");
290 // cropFilter->ResetPipeline();// = CropFilterType::New();
291 cropFilter = CropFilterType::New();
292 ImageIndexType index = region.GetIndex();
293 index[1] = bones->GetLargestPossibleRegion().GetIndex()[1] + size[1]-1;
294 size[1] = bones->GetLargestPossibleRegion().GetSize()[1] - size[1];
296 region.SetIndex(index);
297 region.SetSize(size);
298 cropFilter->SetInput(bones);
299 // cropFilter->SetExtractionRegion(region);
300 cropFilter->SetRegionOfInterest(region);
301 cropFilter->ReleaseDataFlagOff();
302 cropFilter->Update();
303 bones_post = cropFilter->GetOutput();
304 writeImage<ImageType>(bones_post, "b_post.mhd");
307 relPosFilter->SetCurrentStepNumber(0);
308 relPosFilter->ResetPipeline();// = RelPosFilterType::New();
309 relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId());
310 relPosFilter->VerboseStepOff();
311 relPosFilter->WriteStepOff();
312 relPosFilter->SetInput(output);
313 relPosFilter->SetInputObject(bones_post);
314 relPosFilter->SetOrientationType(RelPosFilterType::AntTo);
315 relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing());
316 relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold2());
317 relPosFilter->Update();
318 output = relPosFilter->GetOutput();
319 writeImage<ImageType>(output, "post.mhd");
321 relPosFilter->SetInput(relPosFilter->GetOutput());
322 relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId());
323 relPosFilter->VerboseStepOff();
324 relPosFilter->WriteStepOff();
325 relPosFilter->SetInput(output);
326 relPosFilter->SetInputObject(bones_ant);
327 relPosFilter->SetOrientationType(RelPosFilterType::PostTo);
328 relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing());
329 relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold2());
330 relPosFilter->Update();
331 output = relPosFilter->GetOutput();
332 this->template StopCurrentStep<ImageType>(output);
334 output = clitk::Labelize<ImageType>(output, GetBackgroundValue(), true, 100);
335 // output = RemoveLabels<ImageType>(output, BG, param->GetLabelsToRemove());
336 output = clitk::KeepLabels<ImageType>(output, GetBackgroundValue(),
337 GetForegroundValue(), 1, 1, 0);
340 // Step : Lower limits from lung (need separate lung ?)
341 StartNewStep("Lower limits with lungs");
342 relPosFilter = RelPosFilterType::New();
343 relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId());
344 relPosFilter->VerboseStepOff();
345 relPosFilter->WriteStepOff();
346 relPosFilter->SetInput(output);
347 DD(output->GetLargestPossibleRegion().GetIndex());
348 // relPosFilter->SetInputObject(left_lung);
349 relPosFilter->SetInputObject(lung);
350 relPosFilter->SetOrientationType(RelPosFilterType::SupTo);
351 relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing());
352 relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold3());
353 relPosFilter->Update();
354 output = relPosFilter->GetOutput();
355 DD(output->GetLargestPossibleRegion());
357 output = clitk::AutoCrop<ImageType>(output, GetBackgroundValue());
358 // cropFilter = CropFilterType::New();
359 //cropFilter->SetInput(output);
360 //cropFilter->Update();
361 //output = cropFilter->GetOutput();
363 // Final Step -> set output
364 this->SetNthOutput(0, output);
366 //--------------------------------------------------------------------
369 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX