ANIMA  4.0
animaFibersFilterer.cxx
Go to the documentation of this file.
1 #include <tclap/CmdLine.h>
2 
4 #include <animaShapesWriter.h>
5 
6 #include <animaShapesReader.h>
7 #include <vtkSmartPointer.h>
8 #include <vtkPoints.h>
9 #include <vtkPointData.h>
10 #include <vtkPolyData.h>
11 #include <vtkCleanPolyData.h>
12 #include <vtkGenericCell.h>
13 
14 #include <itkNearestNeighborInterpolateImageFunction.h>
15 #include <itkPoolMultiThreader.h>
16 
17 void FilterTracks(vtkPolyData *tracks, unsigned int startIndex, unsigned int endIndex,
18  itk::NearestNeighborInterpolateImageFunction < itk::Image <unsigned short, 3> > * interpolator,
19  const std::vector <unsigned int> &touchLabels, const std::vector <unsigned int> &endingsLabels,
20  const std::vector <unsigned int> &forbiddenLabels)
21 {
22  std::vector <unsigned int> seenLabels;
23  std::vector <unsigned int> seenEndingsLabels;
24  double pointPositionVTK[3];
25  itk::ContinuousIndex<double, 3> currentIndex;
26  typedef itk::Image <unsigned short, 3>::PointType PointType;
27  PointType pointPosition;
28 
29  vtkSmartPointer <vtkGenericCell> cell = vtkGenericCell::New();
30  for (unsigned int i = startIndex;i < endIndex;++i)
31  {
32  // Inspect i-th cell
33  tracks->GetCell(i,cell);
34  vtkPoints *cellPts = cell->GetPoints();
35  vtkIdType numCellPts = cellPts->GetNumberOfPoints();
36  seenLabels.clear();
37  bool lineOk = true;
38 
39  // First test endings, if not right, useless to continue
40  seenEndingsLabels.clear();
41  for (unsigned int j = 0;j < numCellPts;j += numCellPts - 1)
42  {
43  cellPts->GetPoint(j, pointPositionVTK);
44  for (unsigned int k = 0; k < 3; ++k)
45  pointPosition[k] = pointPositionVTK[k];
46  interpolator->GetInputImage()->TransformPhysicalPointToContinuousIndex(pointPosition,currentIndex);
47  if (interpolator->IsInsideBuffer(currentIndex))
48  {
49  unsigned int value = static_cast <unsigned int> (std::round(interpolator->EvaluateAtContinuousIndex(currentIndex)));
50  for (unsigned int k = 0;k < endingsLabels.size();++k)
51  {
52  if (value == endingsLabels[k])
53  {
54  bool alreadyIn = false;
55  for (unsigned int l = 0;l < seenEndingsLabels.size();++l)
56  {
57  if (seenEndingsLabels[l] == value)
58  {
59  alreadyIn = true;
60  break;
61  }
62  }
63 
64  if (!alreadyIn)
65  seenEndingsLabels.push_back(value);
66 
67  break;
68  }
69  }
70  }
71  }
72 
73  if (seenEndingsLabels.size() != endingsLabels.size())
74  lineOk = false;
75 
76  // Then test forbidden and touched labels
77  if (lineOk)
78  {
79  for (unsigned int j = 0;j < numCellPts;++j)
80  {
81  cellPts->GetPoint(j, pointPositionVTK);
82  for (unsigned int k = 0; k < 3; ++k)
83  pointPosition[k] = pointPositionVTK[k];
84 
85  interpolator->GetInputImage()->TransformPhysicalPointToContinuousIndex(pointPosition,currentIndex);
86 
87  if (!interpolator->IsInsideBuffer(currentIndex))
88  continue;
89 
90  unsigned int value = static_cast <unsigned int> (std::round(interpolator->EvaluateAtContinuousIndex(currentIndex)));
91 
92  for (unsigned int k = 0;k < forbiddenLabels.size();++k)
93  {
94  if (value == forbiddenLabels[k])
95  {
96  lineOk = false;
97  break;
98  }
99  }
100 
101  if (!lineOk)
102  break;
103 
104  for (unsigned int k = 0;k < touchLabels.size();++k)
105  {
106  if (value == touchLabels[k])
107  {
108  bool alreadyIn = false;
109  for (unsigned int l = 0;l < seenLabels.size();++l)
110  {
111  if (seenLabels[l] == value)
112  {
113  alreadyIn = true;
114  break;
115  }
116  }
117 
118  if (!alreadyIn)
119  seenLabels.push_back(value);
120 
121  break;
122  }
123  }
124  }
125  }
126 
127  if (!lineOk || (seenLabels.size() != touchLabels.size()))
128  tracks->DeleteCell(i);
129  }
130 }
131 
132 typedef struct
133 {
134  vtkPolyData *tracks;
135  itk::NearestNeighborInterpolateImageFunction < itk::Image <unsigned short, 3> > *interpolator;
136  std::vector <unsigned int> touchLabels;
137  std::vector <unsigned int> endingsLabels;
138  std::vector <unsigned int> forbiddenLabels;
140 
141 ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION ThreadFilterer(void *arg)
142 {
143  itk::MultiThreaderBase::WorkUnitInfo *threadArgs = (itk::MultiThreaderBase::WorkUnitInfo *)arg;
144  unsigned int nbThread = threadArgs->WorkUnitID;
145  unsigned int numTotalThread = threadArgs->NumberOfWorkUnits;
146 
147  ThreaderArguments *tmpArg = (ThreaderArguments *)threadArgs->UserData;
148  unsigned int nbTotalCells = tmpArg->tracks->GetNumberOfCells();
149 
150  unsigned int step = nbTotalCells / numTotalThread;
151  unsigned int startIndex = nbThread * step;
152  unsigned int endIndex = (nbThread + 1) * step;
153 
154  if (nbThread == numTotalThread - 1)
155  endIndex = nbTotalCells;
156 
157  FilterTracks(tmpArg->tracks, startIndex, endIndex, tmpArg->interpolator, tmpArg->touchLabels, tmpArg->endingsLabels, tmpArg->forbiddenLabels);
158 
159  return ITK_THREAD_RETURN_DEFAULT_VALUE;
160 }
161 
162 int main(int argc, char **argv)
163 {
164  TCLAP::CmdLine cmd("Filters fibers from a vtp file using a label image and specifying with several -t and -f which labels should be touched or are forbidden for each fiber. INRIA / IRISA - VisAGeS/Empenn Team", ' ',ANIMA_VERSION);
165 
166  TCLAP::ValueArg<std::string> inArg("i","input","input tracks file",true,"","input tracks",cmd);
167  TCLAP::ValueArg<std::string> roiArg("r","roi","input ROI label image",true,"","ROI image",cmd);
168  TCLAP::ValueArg<std::string> outArg("o","output","output tracks name",true,"","output tracks",cmd);
169 
170  TCLAP::MultiArg<unsigned int> touchArg("t", "touch", "Labels that have to be touched",false,"touched labels",cmd);
171  TCLAP::MultiArg<unsigned int> endingsArg("e", "endings", "Labels that have to be touched by the endings of the fibers",false,"endings labels",cmd);
172  TCLAP::MultiArg<unsigned int> forbiddenArg("f", "forbid", "Labels that must not to be touched",false,"forbidden labels",cmd);
173 
174  TCLAP::ValueArg<unsigned int> nbThreadsArg("T","nb-threads","Number of threads to run on (default: all available)",false,itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads(),"number of threads",cmd);
175  try
176  {
177  cmd.parse(argc,argv);
178  }
179  catch (TCLAP::ArgException& e)
180  {
181  std::cerr << "Error: " << e.error() << "for argument " << e.argId() << std::endl;
182  return EXIT_FAILURE;
183  }
184 
185  typedef itk::Image <unsigned short, 3> ROIImageType;
186  ROIImageType::Pointer roiImage = anima::readImage <ROIImageType> (roiArg.getValue());
187 
188  typedef itk::NearestNeighborInterpolateImageFunction <ROIImageType> InterpolatorType;
189  InterpolatorType::Pointer interpolator = InterpolatorType::New();
190  interpolator->SetInputImage(roiImage);
191 
192  anima::ShapesReader trackReader;
193  trackReader.SetFileName(inArg.getValue());
194  trackReader.Update();
195 
196  vtkSmartPointer <vtkPolyData> tracks = trackReader.GetOutput();
197 
198  // Get dummy cell so that it's thread safe
199  vtkSmartPointer <vtkGenericCell> dummyCell = vtkGenericCell::New();
200  tracks->GetCell(0,dummyCell);
201 
202  std::vector <unsigned int> touchLabels = touchArg.getValue();
203  std::vector <unsigned int> endingsLabels = endingsArg.getValue();
204  std::vector <unsigned int> forbiddenLabels = forbiddenArg.getValue();
205 
206  if (endingsLabels.size() > 2)
207  std::cerr << "Endings consider only the two ending points of each fiber. Having more than two labels will lead to empty bundles" << std::endl;
208 
209  ThreaderArguments tmpStr;
210  tmpStr.interpolator = interpolator;
211  tmpStr.tracks = tracks;
212  tmpStr.touchLabels = touchLabels;
213  tmpStr.endingsLabels = endingsLabels;
214  tmpStr.forbiddenLabels = forbiddenLabels;
215 
216  itk::PoolMultiThreader::Pointer mThreader = itk::PoolMultiThreader::New();
217  mThreader->SetNumberOfWorkUnits(nbThreadsArg.getValue());
218  mThreader->SetSingleMethod(ThreadFilterer,&tmpStr);
219  mThreader->SingleMethodExecute();
220 
221  // Final pruning of removed cells
222  tracks->RemoveDeletedCells();
223 
224  // Out of security, but apparently does not do much
225  vtkSmartPointer <vtkCleanPolyData> vtkCleaner = vtkSmartPointer <vtkCleanPolyData>::New();
226  vtkCleaner->SetInputData(tracks);
227  vtkCleaner->Update();
228  tracks->ShallowCopy(vtkCleaner->GetOutput());
229 
230  std::cout << "Kept " << tracks->GetNumberOfCells() << " after filtering" << std::endl;
231 
232  anima::ShapesWriter writer;
233  writer.SetInputData(tracks);
234  writer.SetFileName(outArg.getValue());
235  std::cout << "Writing tracks: " << outArg.getValue() << std::endl;
236  writer.Update();
237 
238  return EXIT_SUCCESS;
239 }
std::vector< unsigned int > endingsLabels
void SetInputData(vtkPolyData *data)
void FilterTracks(vtkPolyData *tracks, unsigned int startIndex, unsigned int endIndex, itk::NearestNeighborInterpolateImageFunction< itk::Image< unsigned short, 3 > > *interpolator, const std::vector< unsigned int > &touchLabels, const std::vector< unsigned int > &endingsLabels, const std::vector< unsigned int > &forbiddenLabels)
int main(int argc, char **argv)
std::vector< unsigned int > touchLabels
void SetFileName(std::string &name)
ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION ThreadFilterer(void *arg)
itk::NearestNeighborInterpolateImageFunction< itk::Image< unsigned short, 3 > > * interpolator
vtkPolyData * GetOutput()
std::vector< unsigned int > forbiddenLabels
void SetFileName(std::string &name)