]> Creatis software - clitk.git/blob - segmentation/clitkRelativePositionList.txx
Merge branch 'master' of git.creatis.insa-lyon.fr:clitk
[clitk.git] / segmentation / clitkRelativePositionList.txx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to: 
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
8
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.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17   ======================================================================-====*/
18
19 #include "clitkLabelImageOverlapMeasureFilter.h"
20
21 //--------------------------------------------------------------------
22 template <class TImageType>
23 clitk::RelativePositionList<TImageType>::
24 RelativePositionList():  
25   clitk::FilterBase(),
26   clitk::FilterWithAnatomicalFeatureDatabaseManagement(),
27   itk::ImageToImageFilter<TImageType, TImageType>()
28 {
29   ComputeOverlapFlagOff();
30 }
31 //--------------------------------------------------------------------
32
33
34 //--------------------------------------------------------------------
35 template <class TImageType>
36 void
37 clitk::RelativePositionList<TImageType>::
38 SetReferenceImageForOverlapMeasure(ImagePointer ref) {
39   m_reference = ref;
40   ComputeOverlapFlagOn();
41 }
42 //--------------------------------------------------------------------
43
44
45 //--------------------------------------------------------------------
46 template <class TImageType>
47 void
48 clitk::RelativePositionList<TImageType>::
49 Read(std::string filename) {
50   /*
51     The goal here is to read a text file that contains options for the
52     RelativePosition filter. The text file contains options in the
53     same form of the config file of the clitkRelativePosition tool. In
54     this text file, each time a "object" option is found, a new set of
55     options is considered.
56    */
57
58   // Open the file
59   std::ifstream is;
60   openFileForReading(is, filename);
61
62   // Read input -> the structure name that will be used as input
63   // (initial support)
64   skipComment(is);
65   std::string s;
66   is >> s;
67   if (s != "input") {
68     FATAL("while reading RelativePositionList file. This file must start with 'input = '");
69     exit(0);
70   }
71   is >> s; 
72   if (s != "=") {
73     FATAL("while reading RelativePositionList file. This file must start with 'input = '");
74     exit(0);
75   }
76   std::string name;
77   is >> name;
78   skipComment(is);
79
80   // Create a temporary filename 
81   char n[] = "tmp_clitkRelativePosition_XXXXXX";
82   mkstemp(n); // tmpnam(n); 
83   std::string tmpfilename(n);
84   
85   // Loop on the file text ; Every time we see a "object" token, we
86   // split the file.
87   while (is) {
88     bool stop=false;
89     std::ostringstream ss;
90     // first part of ss is the last 'object = ' found, stored in s
91     ss << s << std::endl; 
92     while (!stop) {
93       skipComment(is);
94       if (!is) stop = true;
95       else {
96         std::getline(is, s);
97         if (s.find("object") != std::string::npos) stop=true;
98         else ss << s << std::endl;
99         if (!is) stop = true;
100       }
101     }
102     std::string text = ss.str();
103     if (text.size() > 10) { // if too small, it is not a list of option
104       std::ofstream os;
105       openFileForWriting(os, tmpfilename);
106       os << text;
107       os << "input = nothing" << std::endl;
108       os << "output = nothing" << std::endl;
109       os.close();
110
111       // Create a struct to store options. I use two step to allow to
112       // fill the args values with de default and then check
113       // automatically the options.
114       ArgsInfoType args_info;
115       std::vector<char> writable(tmpfilename.size() + 1);
116       std::copy(tmpfilename.begin(), tmpfilename.end(), writable.begin());
117       char ** argv = new char*[1];
118       argv[0] = new char[1];
119       struct cmdline_parser_clitkRelativePosition_params params;
120       params.override = 0;
121       params.initialize = 1;
122       params.check_required = 0;
123       cmdline_parser_clitkRelativePosition_configfile(&writable[0], &args_info, 1, 1, 1);
124       mArgsInfoList.push_back(args_info);
125       
126       // Delete the temporary file
127       std::remove(tmpfilename.c_str());
128     }
129   }
130
131   // Set the main input name
132   SetInputName(name);
133 }
134 //--------------------------------------------------------------------
135
136
137 //--------------------------------------------------------------------
138 template <class TImageType>
139 void 
140 clitk::RelativePositionList<TImageType>::
141 GenerateInputRequestedRegion() 
142 {
143   // Call default
144   itk::ImageToImageFilter<ImageType, ImageType>::GenerateInputRequestedRegion();
145   // Get input pointers and set requested region to common region
146   ImagePointer input1 = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
147   input1->SetRequestedRegion(input1->GetLargestPossibleRegion());
148 }
149 //--------------------------------------------------------------------
150
151
152
153 //--------------------------------------------------------------------
154 template <class TImageType>
155 void
156 clitk::RelativePositionList<TImageType>::
157 GenerateOutputInformation() {
158
159   // Get input
160   m_working_input = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
161   std::string s = GetInputName();
162
163   // Debug
164   if (GetDisplayUsedStructuresOnlyFlag()) {
165     for(uint i=0; i<mArgsInfoList.size(); i++) {
166       // Check if we only want to display structure name
167       AddUsedStructures(s, mArgsInfoList[i].object_arg);
168     }
169     return;
170   }
171
172   // Loop on RelativePositionList of operations
173   for(uint i=0; i<mArgsInfoList.size(); i++) {
174
175     // clitk::PrintMemory(true, "Start"); 
176     // remove _S in station name
177     std::string sname = s;
178     clitk::findAndReplace<std::string>(sname, "_S", " ");
179     std::string text = "["+sname+"] ";
180     if (mArgsInfoList[i].orientation_given) text += std::string(mArgsInfoList[i].orientation_arg[0])+" ";
181     else text = text+"("+toString(mArgsInfoList[i].angle1_arg)+" "+
182            toString(mArgsInfoList[i].angle2_arg)+" "+
183            (mArgsInfoList[i].inverse_flag?"true":"false")+") ";
184     text = text+mArgsInfoList[i].object_arg+" "+toString(mArgsInfoList[i].threshold_arg);
185     if (mArgsInfoList[i].sliceBySlice_flag) {
186       text += " SbS";
187     }
188     else text += " 3D";
189     text += " sp=" + toString(mArgsInfoList[i].spacing_arg)+" ";
190
191     StartNewStep(text, false); // no endl
192     typename RelPosFilterType::Pointer relPosFilter;
193
194     // Is it slice by slice or 3D ?
195     if (mArgsInfoList[i].sliceBySlice_flag) {
196       typename SliceRelPosFilterType::Pointer f = SliceRelPosFilterType::New();
197       relPosFilter = f;
198       SetFilterOptions(relPosFilter, mArgsInfoList[i]);  
199       f->SetDirection(2);
200       // Set SbS specific options
201       f->SetUniqueConnectedComponentBySliceFlag(mArgsInfoList[i].uniqueCCL_flag);
202       f->SetObjectCCLSelectionFlag(mArgsInfoList[i].uniqueObjectCCL_flag);
203       f->IgnoreEmptySliceObjectFlagOn();
204       f->SetVerboseSlicesFlag(mArgsInfoList[i].verboseSlices_flag);
205       //f->SetObjectCCLSelectionDimension(0);
206       //f->SetObjectCCLSelectionDirection(-1);
207       //f->SetAutoCropFlag(false);
208       // Print if needed
209       if (mArgsInfoList[i].verboseOptions_flag) f->PrintOptions();
210     }
211     else {
212       relPosFilter = clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::New();
213       SetFilterOptions(relPosFilter, mArgsInfoList[i]);  
214       // Print if needed
215       if (mArgsInfoList[i].verboseOptions_flag) relPosFilter->PrintOptions();
216     }
217
218     // Set input
219     relPosFilter->SetInput(m_working_input);  
220   
221     // Run the filter
222     relPosFilter->Update();
223     m_working_input = relPosFilter->GetOutput();  
224     StopCurrentStep<ImageType>(m_working_input);
225
226     // Compute overlap with reference if needed
227     if (GetComputeOverlapFlag()) {
228       typedef clitk::LabelImageOverlapMeasureFilter<ImageType> FilterType;
229       typename FilterType::Pointer filter = FilterType::New();
230       filter->SetInput(0, m_working_input);
231       filter->SetInput(1, m_reference);
232       filter->Update();
233     }
234     std::cout << std::endl;    
235   }
236 }
237 //--------------------------------------------------------------------
238
239
240 //--------------------------------------------------------------------
241 template <class TImageType>
242 void
243 clitk::RelativePositionList<TImageType>::
244 GenerateData() 
245 {
246   // Final Step -> set output
247   this->GraftOutput(m_working_input);
248 }
249 //--------------------------------------------------------------------
250
251
252 //--------------------------------------------------------------------
253 template <class TImageType>
254 void
255 clitk::RelativePositionList<TImageType>::
256 SetFilterOptions(typename RelPosFilterType::Pointer filter, ArgsInfoType & options) {
257
258   if (options.orientation_given > 1) {
259     clitkExceptionMacro("Error in the RelPos options. I need a single --orientation (for the moment)."
260                         << " Current options are for obj = '" << options.object_arg
261                         << "', threshold = " << options.threshold_arg << std::endl);
262   }
263
264   ImagePointer object = GetAFDB()->template GetImage<ImageType>(options.object_arg);
265   filter->SetInputObject(object);
266   filter->WriteStepFlagOff();
267   filter->SetRadius(options.radius_arg);
268   if (options.writeStep_flag) filter->WriteStepFlagOn();
269   filter->SetVerboseImageSizeFlag(GetVerboseImageSizeFlag());
270   filter->SetFuzzyThreshold(options.threshold_arg);
271   filter->SetInverseOrientationFlag(options.inverse_flag); // MUST BE BEFORE AddOrientationTypeString
272   filter->SetFastFlag(options.fastFlag_flag);
273
274   if (options.orientation_given == 1)  {
275     for(uint i=0; i<options.orientation_given; i++) 
276       filter->AddOrientationTypeString(options.orientation_arg[i]);
277   }
278   else {
279     if (options.angle1_given && options.angle2_given) {
280       filter->AddAnglesInDeg(options.angle1_arg, options.angle2_arg);
281     }
282     else {
283       clitkExceptionMacro("Error in the RelPos options. I need --orientation or (--angle1 and --angle2)."
284                           << " Current options are for obj = '" << options.object_arg
285                           << "', threshold = " << options.threshold_arg << std::endl);
286     }
287   }
288   filter->SetIntermediateSpacing(options.spacing_arg);
289   if (options.spacing_arg == -1) filter->IntermediateSpacingFlagOff();
290   else filter->IntermediateSpacingFlagOn();
291   filter->SetVerboseStepFlag(options.verboseStep_flag);
292   filter->SetAutoCropFlag(!options.noAutoCrop_flag); 
293 }
294 //--------------------------------------------------------------------
295
296