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 CLITKEXTRACTLYMPHSTATIONSFILTER_TXX
20 #define CLITKEXTRACTLYMPHSTATIONSFILTER_TXX
23 #include "clitkCommon.h"
24 #include "clitkExtractLymphStationsFilter.h"
25 #include "clitkAddRelativePositionConstraintToLabelImageFilter.h"
26 #include "clitkSegmentationUtils.h"
27 #include "clitkAutoCropFilter.h"
28 #include "clitkSegmentationUtils.h"
29 #include "clitkSliceBySliceRelativePositionFilter.h"
32 #include <itkStatisticsLabelMapFilter.h>
33 #include <itkLabelImageToStatisticsLabelMapFilter.h>
34 #include <itkRegionOfInterestImageFilter.h>
35 #include <itkBinaryThresholdImageFilter.h>
36 #include <itkImageSliceConstIteratorWithIndex.h>
37 #include <itkImageSliceIteratorWithIndex.h>
38 #include <itkBinaryThinningImageFilter.h>
41 #include "RelativePositionPropImageFilter.h"
43 //--------------------------------------------------------------------
44 template <class TImageType>
45 clitk::ExtractLymphStationsFilter<TImageType>::
46 ExtractLymphStationsFilter():
48 clitk::FilterWithAnatomicalFeatureDatabaseManagement(),
49 itk::ImageToImageFilter<TImageType, MaskImageType>()
51 this->SetNumberOfRequiredInputs(1);
52 SetBackgroundValue(0);
53 SetForegroundValue(1);
56 ExtractStation_8_SetDefaultValues();
57 ExtractStation_3P_SetDefaultValues();
58 ExtractStation_2RL_SetDefaultValues();
59 ExtractStation_3A_SetDefaultValues();
60 ExtractStation_7_SetDefaultValues();
62 //--------------------------------------------------------------------
65 //--------------------------------------------------------------------
66 template <class TImageType>
68 clitk::ExtractLymphStationsFilter<TImageType>::
69 GenerateOutputInformation() {
72 m_Input = dynamic_cast<const ImageType*>(itk::ProcessObject::GetInput(0));
73 m_Mediastinum = GetAFDB()->template GetImage <MaskImageType>("Mediastinum");
75 // Global supports for stations
76 StartNewStep("Supports for stations");
78 ExtractStationSupports();
82 StartNewStep("Station 8");
88 StartNewStep("Station 3P");
95 StartNewStep("Station 2RL");
102 StartNewStep("Station 3A");
108 StartNewStep("Station 7");
113 if (0) { // temporary suppress
114 // Extract Station4RL
115 StartNewStep("Station 4RL");
117 //ExtractStation_4RL();
121 //--------------------------------------------------------------------
124 //--------------------------------------------------------------------
125 template <class TImageType>
127 clitk::ExtractLymphStationsFilter<TImageType>::
128 GenerateInputRequestedRegion() {
129 //DD("GenerateInputRequestedRegion (nothing?)");
131 //--------------------------------------------------------------------
134 //--------------------------------------------------------------------
135 template <class TImageType>
137 clitk::ExtractLymphStationsFilter<TImageType>::
139 // Final Step -> graft output (if SetNthOutput => redo)
140 this->GraftOutput(m_ListOfStations["8"]);
142 //--------------------------------------------------------------------
145 //--------------------------------------------------------------------
146 template <class TImageType>
148 clitk::ExtractLymphStationsFilter<TImageType>::
149 CheckForStation(std::string station)
151 // Compute Station name
152 std::string s = "Station"+station;
155 // Check if station already exist in DB
157 if (GetAFDB()->TagExist(s)) {
158 m_ListOfStations[station] = GetAFDB()->template GetImage<MaskImageType>(s);
162 // Define the starting support
163 if (found && GetComputeStation(station)) {
164 std::cout << "Station " << station << " already exists, but re-computation forced." << std::endl;
166 if (!found || GetComputeStation(station)) {
167 m_Working_Support = m_Mediastinum = GetAFDB()->template GetImage<MaskImageType>("Mediastinum", true);
171 std::cout << "Station " << station << " found. I used it" << std::endl;
175 //--------------------------------------------------------------------
178 //--------------------------------------------------------------------
179 template <class TImageType>
181 clitk::ExtractLymphStationsFilter<TImageType>::
182 GetComputeStation(std::string station)
184 return (m_ComputeStationMap.find(station) != m_ComputeStationMap.end());
186 //--------------------------------------------------------------------
189 //--------------------------------------------------------------------
190 template <class TImageType>
192 clitk::ExtractLymphStationsFilter<TImageType>::
193 AddComputeStation(std::string station)
195 m_ComputeStationMap[station] = true;
197 //--------------------------------------------------------------------
200 //--------------------------------------------------------------------
201 template <class TImageType>
203 clitk::ExtractLymphStationsFilter<TImageType>::
206 if (CheckForStation("3P")) {
207 ExtractStation_3P_SI_Limits();
208 ExtractStation_3P_Ant_Limits();
209 ExtractStation_3P_Post_Limits();
210 ExtractStation_3P_LR_sup_Limits();
211 // ExtractStation_3P_LR_sup_Limits_2();
212 ExtractStation_3P_LR_inf_Limits();
213 ExtractStation_8_Single_CCL_Limits(); // YES 8 !
214 ExtractStation_3P_Remove_Structures(); // after CCL
215 // Store image filenames into AFDB
216 writeImage<MaskImageType>(m_ListOfStations["3P"], "seg/Station3P.mhd");
217 GetAFDB()->SetImageFilename("Station3P", "seg/Station3P.mhd");
221 //--------------------------------------------------------------------
224 //--------------------------------------------------------------------
225 template <class TImageType>
227 clitk::ExtractLymphStationsFilter<TImageType>::
230 if (CheckForStation("3A")) {
231 ExtractStation_3A_SI_Limits();
232 ExtractStation_3A_Ant_Limits();
233 ExtractStation_3A_Post_Limits();
234 // Store image filenames into AFDB
235 writeImage<MaskImageType>(m_ListOfStations["3A"], "seg/Station3A.mhd");
236 GetAFDB()->SetImageFilename("Station3A", "seg/Station3A.mhd");
240 //--------------------------------------------------------------------
243 //--------------------------------------------------------------------
244 template <class TImageType>
246 clitk::ExtractLymphStationsFilter<TImageType>::
249 if (CheckForStation("2RL")) {
250 ExtractStation_2RL_SI_Limits();
251 ExtractStation_2RL_Post_Limits();
252 ExtractStation_2RL_Ant_Limits2();
253 ExtractStation_2RL_Ant_Limits();
254 ExtractStation_2RL_LR_Limits();
255 ExtractStation_2RL_Remove_Structures();
256 ExtractStation_2RL_SeparateRL();
258 // Store image filenames into AFDB
259 writeImage<MaskImageType>(m_ListOfStations["2R"], "seg/Station2R.mhd");
260 writeImage<MaskImageType>(m_ListOfStations["2L"], "seg/Station2L.mhd");
261 GetAFDB()->SetImageFilename("Station2R", "seg/Station2R.mhd");
262 GetAFDB()->SetImageFilename("Station2L", "seg/Station2L.mhd");
266 //--------------------------------------------------------------------
269 //--------------------------------------------------------------------
270 template <class TImageType>
272 clitk::ExtractLymphStationsFilter<TImageType>::
273 ExtractStation_4RL() {
277 WARNING ONLY 4R FIRST !!! (not same inf limits)
279 ExtractStation_4RL_SI_Limits();
280 ExtractStation_4RL_LR_Limits();
281 ExtractStation_4RL_AP_Limits();
283 //--------------------------------------------------------------------
286 //--------------------------------------------------------------------
287 template <class ImageType>
289 clitk::ExtractLymphStationsFilter<ImageType>::
290 Remove_Structures(std::string station, std::string s)
293 StartNewStep("[Station"+station+"] Remove "+s);
294 MaskImagePointer Structure = GetAFDB()->template GetImage<MaskImageType>(s);
295 clitk::AndNot<MaskImageType>(m_Working_Support, Structure, GetBackgroundValue());
297 catch(clitk::ExceptionObject e) {
298 std::cout << s << " not found, skip." << std::endl;
301 //--------------------------------------------------------------------
304 //--------------------------------------------------------------------
305 template <class TImageType>
307 clitk::ExtractLymphStationsFilter<TImageType>::
308 SetFuzzyThreshold(std::string station, std::string tag, double value)
310 m_FuzzyThreshold[station][tag] = value;
312 //--------------------------------------------------------------------
315 //--------------------------------------------------------------------
316 template <class TImageType>
318 clitk::ExtractLymphStationsFilter<TImageType>::
319 GetFuzzyThreshold(std::string station, std::string tag)
321 if (m_FuzzyThreshold.find(station) == m_FuzzyThreshold.end()) {
322 clitkExceptionMacro("Could not find options for station "+station+" in the list (while searching for tag "+tag+").");
326 if (m_FuzzyThreshold[station].find(tag) == m_FuzzyThreshold[station].end()) {
327 clitkExceptionMacro("Could not find options "+tag+" in the list of FuzzyThreshold for station "+station+".");
331 return m_FuzzyThreshold[station][tag];
333 //--------------------------------------------------------------------
336 //--------------------------------------------------------------------
337 template <class TImageType>
339 clitk::ExtractLymphStationsFilter<TImageType>::
340 FindLineForS7S8Separation(MaskImagePointType & A, MaskImagePointType & B)
342 // Create line from A to B with
343 // A = upper border of LLL at left
344 // B = lower border of bronchus intermedius (BI) or RightMiddleLobeBronchus
347 GetAFDB()->GetPoint3D("LineForS7S8Separation_Begin", A);
348 GetAFDB()->GetPoint3D("LineForS7S8Separation_End", B);
350 catch(clitk::ExceptionObject & o) {
352 DD("FindLineForS7S8Separation");
353 // Load LeftLowerLobeBronchus and get centroid point
354 MaskImagePointer LeftLowerLobeBronchus =
355 GetAFDB()->template GetImage <MaskImageType>("LeftLowerLobeBronchus");
356 std::vector<MaskImagePointType> c;
357 clitk::ComputeCentroids<MaskImageType>(LeftLowerLobeBronchus, GetBackgroundValue(), c);
360 // Load RightMiddleLobeBronchus and get superior point (not centroid here)
361 MaskImagePointer RightMiddleLobeBronchus =
362 GetAFDB()->template GetImage <MaskImageType>("RightMiddleLobeBronchus");
363 bool b = FindExtremaPointInAGivenDirection<MaskImageType>(RightMiddleLobeBronchus,
364 GetBackgroundValue(),
367 clitkExceptionMacro("Error while searching most superior point in RightMiddleLobeBronchus. Abort");
370 // Insert into the DB
371 GetAFDB()->SetPoint3D("LineForS7S8Separation_Begin", A);
372 GetAFDB()->SetPoint3D("LineForS7S8Separation_End", B);
375 //--------------------------------------------------------------------
378 //--------------------------------------------------------------------
379 template <class TImageType>
381 clitk::ExtractLymphStationsFilter<TImageType>::
382 FindCarinaSlicePosition()
386 z = GetAFDB()->GetDouble("CarinaZ");
388 catch(clitk::ExceptionObject e) {
389 DD("FindCarinaSlicePosition");
391 MaskImagePointer Carina = GetAFDB()->template GetImage<MaskImageType>("Carina");
393 // Get Centroid and Z value
394 std::vector<MaskImagePointType> centroids;
395 clitk::ComputeCentroids<MaskImageType>(Carina, GetBackgroundValue(), centroids);
397 // We dont need Carina structure from now
400 // Put inside the AFDB
401 GetAFDB()->SetPoint3D("CarinaPoint", centroids[1]);
402 GetAFDB()->SetDouble("CarinaZ", centroids[1][2]);
408 //--------------------------------------------------------------------
411 //--------------------------------------------------------------------
412 template <class TImageType>
414 clitk::ExtractLymphStationsFilter<TImageType>::
415 FindLeftAndRightBronchi()
418 m_RightBronchus = GetAFDB()->template GetImage <MaskImageType>("RightBronchus");
419 m_LeftBronchus = GetAFDB()->template GetImage <MaskImageType>("LeftBronchus");
421 catch(clitk::ExceptionObject & o) {
423 DD("FindLeftAndRightBronchi");
424 // The goal is to separate the trachea inferiorly to the carina into
425 // a Left and Right bronchus.
428 MaskImagePointer Trachea = GetAFDB()->template GetImage<MaskImageType>("Trachea");
430 // Get the Carina position
431 m_CarinaZ = FindCarinaSlicePosition();
433 // Consider only inferiorly to the Carina
434 MaskImagePointer m_Working_Trachea =
435 clitk::CropImageRemoveGreaterThan<MaskImageType>(Trachea, 2, m_CarinaZ, true, // AutoCrop
436 GetBackgroundValue());
438 // Labelize the trachea
439 m_Working_Trachea = Labelize<MaskImageType>(m_Working_Trachea, 0, true, 1);
441 // Carina position must at the first slice that separate the two
442 // main bronchus (not superiorly). We thus first check that the
443 // upper slice is composed of at least two labels
444 MaskImagePointer RightBronchus;
445 MaskImagePointer LeftBronchus;
446 typedef itk::ImageSliceIteratorWithIndex<MaskImageType> SliceIteratorType;
447 SliceIteratorType iter(m_Working_Trachea, m_Working_Trachea->GetLargestPossibleRegion());
448 iter.SetFirstDirection(0);
449 iter.SetSecondDirection(1);
450 iter.GoToReverseBegin(); // Start from the end (because image is IS not SI)
452 while (!iter.IsAtReverseEndOfSlice()) {
453 while (!iter.IsAtReverseEndOfLine()) {
454 if (iter.Get() > maxLabel) maxLabel = iter.Get();
460 clitkExceptionMacro("First slice from Carina does not seems to seperate the two main bronchus. Abort");
463 // Compute 3D centroids of both parts to identify the left from the
465 std::vector<ImagePointType> c;
466 clitk::ComputeCentroids<MaskImageType>(m_Working_Trachea, GetBackgroundValue(), c);
467 ImagePointType C1 = c[1];
468 ImagePointType C2 = c[2];
470 ImagePixelType rightLabel;
471 ImagePixelType leftLabel;
472 if (C1[0] < C2[0]) { rightLabel = 1; leftLabel = 2; }
473 else { rightLabel = 2; leftLabel = 1; }
475 // Select LeftLabel (set one label to Backgroundvalue)
477 clitk::Binarize<MaskImageType>(m_Working_Trachea, rightLabel, rightLabel,
478 GetBackgroundValue(), GetForegroundValue());
480 SetBackground<MaskImageType, MaskImageType>(m_Working_Trachea, m_Working_Trachea,
481 leftLabel, GetBackgroundValue(), false);
483 LeftBronchus = clitk::Binarize<MaskImageType>(m_Working_Trachea, leftLabel, leftLabel,
484 GetBackgroundValue(), GetForegroundValue());
486 SetBackground<MaskImageType, MaskImageType>(m_Working_Trachea, m_Working_Trachea,
487 rightLabel, GetBackgroundValue(), false);
491 RightBronchus = clitk::AutoCrop<MaskImageType>(RightBronchus, GetBackgroundValue());
492 LeftBronchus = clitk::AutoCrop<MaskImageType>(LeftBronchus, GetBackgroundValue());
494 // Insert int AFDB if need after
495 GetAFDB()->template SetImage <MaskImageType>("RightBronchus", "seg/rightBronchus.mhd",
496 RightBronchus, true);
497 GetAFDB()->template SetImage <MaskImageType>("LeftBronchus", "seg/leftBronchus.mhd",
501 //--------------------------------------------------------------------
503 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX