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 CLITKEXTRACTAIRWAYTREEINFOSFILTER_TXX
20 #define CLITKEXTRACTAIRWAYTREEINFOSFILTER_TXX
23 #include "clitkImageCommon.h"
24 #include "clitkSetBackgroundImageFilter.h"
25 #include "clitkSegmentationUtils.h"
26 #include "clitkAutoCropFilter.h"
29 #include "itkBinaryThresholdImageFilter.h"
30 #include "itkConnectedComponentImageFilter.h"
31 #include "itkRelabelComponentImageFilter.h"
32 #include "itkOtsuThresholdImageFilter.h"
33 #include "itkBinaryThinningImageFilter3D.h"
34 #include "itkImageIteratorWithIndex.h"
37 //--------------------------------------------------------------------
38 template <class ImageType>
39 clitk::ExtractAirwayTreeInfoFilter<ImageType>::
40 ExtractAirwayTreeInfoFilter():
42 itk::ImageToImageFilter<ImageType, ImageType>()
44 // Default global options
45 this->SetNumberOfRequiredInputs(1);
46 SetBackgroundValue(0);
47 SetForegroundValue(1);
49 //--------------------------------------------------------------------
52 //--------------------------------------------------------------------
53 template <class ImageType>
55 clitk::ExtractAirwayTreeInfoFilter<ImageType>::
56 SetInput(const ImageType * image)
58 this->SetNthInput(0, const_cast<ImageType *>(image));
60 //--------------------------------------------------------------------
63 //--------------------------------------------------------------------
64 template <class ImageType>
65 template<class ArgsInfoType>
67 clitk::ExtractAirwayTreeInfoFilter<ImageType>::
68 SetArgsInfo(ArgsInfoType mArgsInfo)
70 SetVerboseOption_GGO(mArgsInfo);
71 SetVerboseStep_GGO(mArgsInfo);
72 SetWriteStep_GGO(mArgsInfo);
73 SetVerboseWarningOff_GGO(mArgsInfo);
75 //--------------------------------------------------------------------
78 //--------------------------------------------------------------------
79 template <class ImageType>
81 clitk::ExtractAirwayTreeInfoFilter<ImageType>::
82 GenerateOutputInformation()
84 Superclass::GenerateOutputInformation();
85 //this->GetOutput(0)->SetRequestedRegion(this->GetOutput(0)->GetLargestPossibleRegion());
88 input = dynamic_cast<const ImageType*>(itk::ProcessObject::GetInput(0));
90 StartNewStepOrStop("Find bronchial bifurcations");
91 // Step 1 : extract skeleton
92 // Define the thinning filter
93 typedef itk::BinaryThinningImageFilter3D<ImageType, ImageType> ThinningFilterType;
94 typename ThinningFilterType::Pointer thinningFilter = ThinningFilterType::New();
95 thinningFilter->SetInput(input);
96 thinningFilter->Update();
97 skeleton = thinningFilter->GetOutput();
98 writeImage<ImageType>(skeleton, "skeleton.mhd");
103 // Step 2.1 : find first point for tracking
104 typedef itk::ImageRegionConstIteratorWithIndex<ImageType> IteratorType;
105 IteratorType it(skeleton, skeleton->GetLargestPossibleRegion());
106 it.GoToReverseBegin();
107 while ((!it.IsAtEnd()) && (it.Get() == GetBackgroundValue())) {
111 this->SetLastError("ERROR: first point in the skeleton not found ! Abort");
114 DD(skeleton->GetLargestPossibleRegion().GetIndex());
115 typename ImageType::IndexType index = it.GetIndex();
116 skeleton->TransformIndexToPhysicalPoint(index, m_FirstTracheaPoint);
118 DD(m_FirstTracheaPoint);
120 // Step 2.2 : initialize neighborhooditerator
121 typedef itk::NeighborhoodIterator<ImageType> NeighborhoodIteratorType;
122 typename NeighborhoodIteratorType::SizeType radius;
124 NeighborhoodIteratorType nit(radius, skeleton, skeleton->GetLargestPossibleRegion());
128 // Find first label number (must be different from BG and FG)
129 typename ImageType::PixelType label = GetForegroundValue()+1;
130 while ((label == GetBackgroundValue()) || (label == GetForegroundValue())) { label++; }
133 // Track from the first point
134 std::vector<BifurcationType> listOfBifurcations;
135 TrackFromThisIndex(listOfBifurcations, skeleton, index, label);
137 DD(listOfBifurcations.size());
138 writeImage<ImageType>(skeleton, "skeleton2.mhd");
140 for(unsigned int i=0; i<listOfBifurcations.size(); i++) {
141 typename ImageType::PointType p;
142 skeleton->TransformIndexToPhysicalPoint(listOfBifurcations[i].index, p);
147 //--------------------------------------------------------------------
150 //--------------------------------------------------------------------
151 template <class ImageType>
153 clitk::ExtractAirwayTreeInfoFilter<ImageType>::
156 // Do not put some "startnewstep" here, because the object if
157 // modified and the filter's pipeline it do two times. But it is
158 // required to quit if MustStop was set before.
159 if (GetMustStop()) return;
161 // If everything goes well, set the output
162 this->GraftOutput(skeleton); // not SetNthOutput
164 //--------------------------------------------------------------------
167 //--------------------------------------------------------------------
168 template <class ImageType>
170 clitk::ExtractAirwayTreeInfoFilter<ImageType>::
171 TrackFromThisIndex(std::vector<BifurcationType> & listOfBifurcations,
172 ImagePointer skeleton,
173 ImageIndexType index,
174 ImagePixelType label)
176 DD("TrackFromThisIndex");
179 // Create NeighborhoodIterator
180 typedef itk::NeighborhoodIterator<ImageType> NeighborhoodIteratorType;
181 typename NeighborhoodIteratorType::SizeType radius;
183 NeighborhoodIteratorType nit(radius, skeleton, skeleton->GetLargestPossibleRegion());
186 std::vector<typename NeighborhoodIteratorType::IndexType> listOfTrackedPoint;
189 nit.SetLocation(index);
190 // DD((int)nit.GetCenterPixel());
191 nit.SetCenterPixel(label);
192 listOfTrackedPoint.clear();
193 for(unsigned int i=0; i<nit.Size(); i++) {
194 if (i != nit.GetCenterNeighborhoodIndex ()) { // Do not observe the current point
195 // DD(nit.GetIndex(i));
196 if (nit.GetPixel(i) == GetForegroundValue()) { // if this is foreground, we continue the tracking
197 // DD(nit.GetIndex(i));
198 listOfTrackedPoint.push_back(nit.GetIndex(i));
202 // DD(listOfTrackedPoint.size());
203 if (listOfTrackedPoint.size() == 1) {
204 index = listOfTrackedPoint[0];
207 if (listOfTrackedPoint.size() == 2) {
208 BifurcationType bif(index, label, label+1, label+2);
209 listOfBifurcations.push_back(bif);
210 TrackFromThisIndex(listOfBifurcations, skeleton, listOfTrackedPoint[0], label+1);
211 TrackFromThisIndex(listOfBifurcations, skeleton, listOfTrackedPoint[1], label+2);
214 if (listOfTrackedPoint.size() > 2) {
215 std::cerr << "too much bifurcation points ... ?" << std::endl;
218 // Else this it the end of the tracking
224 //--------------------------------------------------------------------
227 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX