]> Creatis software - clitk.git/blob - vv/vvLandmarks.cxx
Add clitkImage2DicomSeries tool to write a Dicom Series from an image without a corre...
[clitk.git] / vv / vvLandmarks.cxx
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://www.centreleonberard.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 #include "vvLandmarks.h"
19
20 #include <ios>
21 #include <fstream>
22 #include <sstream>
23 #include <string>
24 #include <locale.h>
25
26 #include <vtkVersion.h>
27 #include "vtkPolyData.h"
28 #include "vtkPoints.h"
29 #include "vtkFloatArray.h"
30 #include "vtkPointData.h"
31 #include "clitkCommon.h"
32 #include <itksys/SystemTools.hxx>
33
34 //--------------------------------------------------------------------
35 vvLandmarks::vvLandmarks(int size)
36 {
37   mLandmarks.resize(size);
38   mFilenames.resize(0);
39   mTime = 0;
40
41   for (int i = 0; i < size; i++) {
42     mLandmarks[i].resize(0);
43     vtkPoints *points = vtkPoints::New();
44     mPoints.push_back(points);
45     mIds.push_back(vtkFloatArray::New());
46     mLabels.push_back(vtkStringArray::New());
47     mLabels.back()->SetName("labels");
48   }
49   mPolyData = vtkPolyData::New();
50 }
51 //--------------------------------------------------------------------
52
53
54 //--------------------------------------------------------------------
55 vvLandmarks::~vvLandmarks()
56 {
57   for (unsigned int i = 0; i < mPoints.size(); i++) {
58     mPoints[i]->Delete();
59     mIds[i]->Delete();
60     mLabels[i]->Delete();
61   }
62   /*for(unsigned int i = 0; i < mText.size(); i++) {
63     mText[i]->Delete();
64     }*/
65   if (mPolyData)
66     mPolyData->Delete();
67 }
68 //--------------------------------------------------------------------
69
70
71 //--------------------------------------------------------------------
72 void vvLandmarks::AddLandmark(float x,float y,float z,float t,double value)
73 {
74   vvLandmark point;
75   vtkIdType idPoint;
76   point.coordinates[0] = x;
77   point.coordinates[1] = y;
78   point.coordinates[2] = z;
79   point.coordinates[3] = t;
80   point.pixel_value=value;
81   mLandmarks[mTime].push_back(point);
82
83   idPoint = mPoints[int(t)]->InsertNextPoint(x,y,z);
84   std::string str_vtkIdType;        // string which will contain the result
85   std::ostringstream convert;       // stream used for the conversion
86   convert << idPoint;                   // insert the textual representation of 'idPoint' in the characters in the stream
87   str_vtkIdType = convert.str();    // set 'str_vtkIdType' to the contents of the stream
88   mLabels[mTime]->InsertNextValue(str_vtkIdType.c_str());
89
90   std::stringstream numberVal;
91   numberVal << (mLandmarks.size()-1);
92   /*
93   vvLandmarksGlyph *number = vvLandmarksGlyph::New();
94   number->SetText(numberVal.str().c_str());
95   number->BackingOff();
96   DD(numberVal.str().c_str());
97   mText.push_back(number);
98   */
99
100   mIds[mTime]->InsertNextTuple1(0.55);
101   //mIds->InsertTuple1(mLandmarks.size(),mLandmarks.size());
102   SetTime(int(t));
103 }
104 //--------------------------------------------------------------------
105
106
107 //--------------------------------------------------------------------
108 void vvLandmarks::RemoveLastLandmark()
109 {
110   mPoints[mTime]->SetNumberOfPoints(mPoints[mTime]->GetNumberOfPoints()-1);
111   //  mText.pop_back();
112   mLandmarks[mTime].pop_back();
113   mIds[mTime]->RemoveLastTuple();
114   mLabels[mTime]->SetNumberOfValues(mLabels[mTime]->GetNumberOfValues()-1);
115   mLabels[mTime]->Modified();
116   mPolyData->Modified();
117 }
118 //--------------------------------------------------------------------
119
120
121 //--------------------------------------------------------------------
122 void vvLandmarks::RemoveLandmarkWithLabel(vtkStdString label, int time)
123 {
124   if (label != "P1" && label != "P2")
125     return;
126   // erase a vtkPoint by shifiting the array .
127   // not a problem here because there are no 
128   // pologyons linking the points
129   int t = time;//mLandmarks[index].coordinates[3];
130   int npoints = mPoints[t]->GetNumberOfPoints();
131   
132   //search of the index corresponding to the label
133   int index(0);
134   while (mLabels[t]->GetValue(index) != label)
135     ++index;
136   
137   for (int i = index; i < npoints - 1; i++) {
138     mPoints[t]->InsertPoint(i, mPoints[t]->GetPoint(i+1));
139         std::string str_i;                   // string which will contain the result
140         std::ostringstream convert;      // stream used for the conversion
141         convert << i;                        // insert the textual representation of 'i' in the characters in the stream
142         str_i = convert.str();           // set 'str_i' to the contents of the stream
143         mLabels[t]->SetValue(i,mLabels[t]->GetValue(i+1));
144     }
145   mPoints[t]->SetNumberOfPoints(npoints-1);
146   mLabels[t]->SetNumberOfValues(npoints-1);
147   mLabels[t]->Modified();
148   mPolyData->Modified();
149
150   mLandmarks[t].erase(mLandmarks[t].begin() + index);
151   mIds[t]->RemoveLastTuple();
152 }
153 //--------------------------------------------------------------------
154
155
156 //--------------------------------------------------------------------
157 void vvLandmarks::RemoveLandmark(int index)
158 {
159   // erase a vtkPoint by shifiting the array .
160   // not a problem here because there are no 
161   // pologyons linking the points
162   int t = mTime;//mLandmarks[index].coordinates[3];
163   int npoints = mPoints[t]->GetNumberOfPoints();
164   for (int i = index; i < npoints - 1; i++) {
165     mPoints[t]->InsertPoint(i, mPoints[t]->GetPoint(i+1));
166         std::string str_i;                   // string which will contain the result
167         std::ostringstream convert;      // stream used for the conversion
168         convert << i;                        // insert the textual representation of 'i' in the characters in the stream
169         str_i = convert.str();           // set 'str_i' to the contents of the stream
170         mLabels[t]->SetValue(i,str_i.c_str());
171     }
172   mPoints[t]->SetNumberOfPoints(npoints-1);
173   mLabels[t]->SetNumberOfValues(npoints-1);
174   mLabels[t]->Modified();
175   mPolyData->Modified();
176
177   mLandmarks[t].erase(mLandmarks[t].begin() + index);
178   mIds[t]->RemoveLastTuple();
179 }
180 //--------------------------------------------------------------------
181
182 //--------------------------------------------------------------------
183 void vvLandmarks::RemoveAll()
184 {
185   for (unsigned int i = 0; i < mLandmarks.size(); i++) {
186     mLandmarks[i].clear();
187     mPoints[i]->SetNumberOfPoints(0);
188     mLabels[i]->SetNumberOfValues(0);
189     mIds[i]->SetNumberOfValues(0);
190   }
191 }
192 //--------------------------------------------------------------------
193
194 //--------------------------------------------------------------------
195 void vvLandmarks::ChangeComments(int index, std::string comments)
196 {
197   mLandmarks[mTime][index].comments = comments;
198 }
199 //--------------------------------------------------------------------
200
201
202 //--------------------------------------------------------------------
203 double vvLandmarks::GetPixelValue(int index)
204 {
205   return mLandmarks[mTime][index].pixel_value;
206 }
207 //--------------------------------------------------------------------
208
209
210 //--------------------------------------------------------------------
211 float* vvLandmarks::GetCoordinates(int index)
212 {
213   return mLandmarks[mTime][index].coordinates;
214 }
215 //--------------------------------------------------------------------
216
217
218 //--------------------------------------------------------------------
219 std::string vvLandmarks::GetComments(int index)
220 {
221   return mLandmarks[mTime][index].comments;
222 }
223 //--------------------------------------------------------------------
224
225
226 //--------------------------------------------------------------------
227 bool vvLandmarks::LoadFile(std::vector<std::string> filenames)
228 {
229   // all files in the sequence must be of the same type
230   std::string extension = itksys::SystemTools::GetFilenameExtension(filenames[0]);
231   if (extension == ".txt")
232     return LoadTxtFile(filenames);
233   else if (extension == ".pts")
234     return LoadPtsFile(filenames);
235
236   return false;
237 }
238
239 //--------------------------------------------------------------------
240 bool vvLandmarks::LoadTxtFile(std::vector<std::string> filenames)
241 {
242   mFilenames = filenames;
243   for (unsigned int i = 0; i < mPoints.size(); i++) {
244     mLandmarks[i].clear();
245     mPoints[i]->SetNumberOfPoints(0);
246   }
247
248   int err = 0;
249   for (unsigned int f = 0; f < filenames.size(); f++) {
250     std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
251     if (!fp.is_open()) {
252       std::cerr <<"Unable to open file " << filenames[f] << std::endl;
253       err++;
254     }
255     vtkIdType idPoint;
256     char line[255];
257     bool first_line=true;
258     while (fp.getline(line,255)) {
259       //    DD(line);
260       std::string stringline = line;
261       stringline += "\n";
262       
263       if (first_line) {
264         first_line=false;
265         ///New landmark format: first line is "LANDMARKSXX", where XX is the version number
266         if (stringline.size() >= 10 && stringline.compare(0,9,"LANDMARKS")==0) {
267           std::istringstream ss(stringline.c_str()+9);
268           ss >> mFormatVersion;
269           continue; //skip first line
270         } else
271           mFormatVersion=0;
272       }
273       if (stringline.size() > 1) {
274         vvLandmark point;
275         int previousSpace = 0;
276         int space=0;
277         if (mFormatVersion>0) {
278           space = stringline.find(" ", previousSpace+1);
279           if (space < -1 || space > (int)stringline.size()) {
280             ErrorMsg(mLandmarks.size(),"index");
281             continue;
282           }
283           //int index = atoi(stringline.substr(previousSpace,space - previousSpace).c_str());
284           previousSpace = space;
285         }
286         space = stringline.find(" ", previousSpace+1);
287         if (space < -1 || space > (int)stringline.size()) {
288           ErrorMsg(mLandmarks.size(),"x position");
289           continue;
290         }
291         point.coordinates[0] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
292         //      DD(point.coordinates[0]);
293         previousSpace = space;
294         space = stringline.find(" ", previousSpace+1);
295         if (space < -1 || space > (int)stringline.size()) {
296           ErrorMsg(mLandmarks.size(),"y position");
297           continue;
298         }
299         point.coordinates[1] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
300         //      DD(point.coordinates[1]);
301         previousSpace = space;
302         space = stringline.find(" ", previousSpace+1);
303         if (space < -1 || space > (int)stringline.size()) {
304           ErrorMsg(mLandmarks.size(),"z position");
305           continue;
306         }
307         point.coordinates[2] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
308         previousSpace = space;
309         if (mFormatVersion>0) {
310           space = stringline.find(" ", previousSpace+1);
311           if (space < -1 || space > (int)stringline.size()) {
312             ErrorMsg(mLandmarks.size(),"t position");
313             continue;
314           }
315           point.coordinates[3] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
316           previousSpace = space;
317           space = stringline.find(" ", previousSpace+1);
318           if (space < -1 || space > (int)stringline.size()) {
319             ErrorMsg(mLandmarks.size(),"pixel value");
320             continue;
321           }
322           point.pixel_value = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
323           //        DD(point.pixel_value);
324         } else {
325           point.pixel_value=0.; //Not in file
326           point.coordinates[3]=(float)f;
327         }
328         previousSpace = space;
329         //this is the maximum size of comments
330         space = (stringline.find("\n", previousSpace+1) < 254 ? stringline.find("\n", previousSpace+1) : 254);
331         if (previousSpace != -1) {
332           point.comments = stringline.substr(previousSpace,space - (previousSpace)).c_str();
333         }
334         //      DD(point.comments);
335         mLandmarks[int(point.coordinates[3])].push_back(point);
336         mIds[int(point.coordinates[3])]->InsertNextTuple1(0.55);
337         idPoint = mPoints[int(point.coordinates[3])]->InsertNextPoint(
338                                                             point.coordinates[0],point.coordinates[1],point.coordinates[2]);
339         std::string str_vtkIdType;          // string which will contain the result
340         std::ostringstream convert;     // stream used for the conversion
341         convert << idPoint;                 // insert the textual representation of 'idPoint' in the characters in the stream
342         str_vtkIdType = convert.str(); // set 'str_vtkIdType' to the contents of the stream
343         mLabels[int(point.coordinates[3])]->InsertNextValue(str_vtkIdType.c_str());
344       }
345     }
346   }
347
348   if (err > 0 && err == filenames.size())
349     return false;
350   
351   SetTime(0);
352   
353   return true;
354 }
355 //--------------------------------------------------------------------
356
357 //--------------------------------------------------------------------
358 bool vvLandmarks::LoadPtsFile(std::vector<std::string> filenames)
359 {
360   mFilenames = filenames;
361   for (unsigned int i = 0; i < mPoints.size(); i++) {
362     mPoints[i]->SetNumberOfPoints(0);
363     mLandmarks[i].clear();
364   }
365
366   int err = 0;
367   for (unsigned int f = 0; f < filenames.size(); f++) {
368     std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
369     if (!fp.is_open()) {
370       std::cerr <<"Unable to open file " << filenames[f] << std::endl;
371       err++;
372     }
373     vtkIdType idPoint;
374     char line[255];
375     bool first_line=true;
376     while (fp.getline(line,255)) {
377       std::string stringline = line;
378       stringline += "\n";
379       
380       std::string separators = "\t\n\r ";
381       if (stringline.size() > 1) {
382         vvLandmark point;
383         int previousSpace = 0;
384         int space=0;
385
386         if (stringline[0] == '#') // comments
387           continue;
388         
389         space = stringline.find_first_of(separators, previousSpace+1);
390         if (space == std::string::npos) {
391           ErrorMsg(mLandmarks.size(),"x position");
392           continue;
393         }
394         point.coordinates[0] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
395         //      DD(point.coordinates[0]);
396         previousSpace = space;
397         space = stringline.find_first_of(separators, previousSpace+1);
398         if (space == std::string::npos) {
399           ErrorMsg(mLandmarks.size(),"y position");
400           continue;
401         }
402         point.coordinates[1] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
403         //      DD(point.coordinates[1]);
404         previousSpace = space;
405         space = stringline.find_first_of(separators, previousSpace+1);
406         if (space == std::string::npos) {
407           ErrorMsg(mLandmarks.size(),"z position");
408           continue;
409         }
410         point.coordinates[2] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
411         previousSpace = space;
412         point.pixel_value=0.; //Not in file
413         point.coordinates[3]=(float)f;  //Not in file
414         point.comments = "";  //Not in file
415
416         //      DD(point.comments);
417         mLandmarks[int(point.coordinates[3])].push_back(point);
418         mIds[int(point.coordinates[3])]->InsertNextTuple1(0.55);
419         idPoint = mPoints[int(point.coordinates[3])]->InsertNextPoint(
420                                                             point.coordinates[0],point.coordinates[1],point.coordinates[2]);
421         std::string str_vtkIdType;     // string which will contain the result
422         std::ostringstream convert;  // stream used for the conversion
423         convert << idPoint;        // insert the textual representation of 'idPoint' in the characters in the stream
424         str_vtkIdType = convert.str(); // set 'str_vtkIdType' to the contents of the stream
425         mLabels[int(point.coordinates[3])]->InsertNextValue(str_vtkIdType.c_str());
426       }
427     }
428   }
429   
430   SetTime(0);
431   DD("vvLandmarks::LoadPtsFile")
432   if (err > 0 && err == filenames.size())
433     return false;
434
435   
436   return true;
437 }
438 //--------------------------------------------------------------------
439
440 //--------------------------------------------------------------------
441 bool vvLandmarks::ErrorMsg(int num,const char * text)
442 {
443   std::cerr << "error when loading point " << num << " at " << text << std::endl;
444   return false;
445 }
446 //--------------------------------------------------------------------
447
448
449 //--------------------------------------------------------------------
450 void vvLandmarks::SaveFile(std::string filename)
451 {
452   std::string fileContent = "LANDMARKS1\n"; //File format version identification
453   for (unsigned int t = 0; t < mLandmarks.size(); t++) {
454     for (unsigned int i = 0; i < mLandmarks[t].size(); i++) {
455       std::stringstream out;
456       out.imbue(std::locale("C")); //This is to specify that the dot is to be used as the decimal separator
457       out << i << " "
458           << mLandmarks[t][i].coordinates[0] << " "
459           << mLandmarks[t][i].coordinates[1] << " "
460           << mLandmarks[t][i].coordinates[2] << " "
461           << mLandmarks[t][i].coordinates[3] << " "
462           << mLandmarks[t][i].pixel_value << " ";
463       fileContent += out.str();
464       if (mLandmarks[t][i].comments.size() == 0)
465         fileContent += " ";
466       else
467         fileContent += mLandmarks[t][i].comments;
468       fileContent += "\n";
469     }
470   }
471   std::ofstream fp(filename.c_str(), std::ios::trunc);
472   if ( !fp ) {
473     std::cerr << "Unable to open file" << std::endl;
474     return;
475   }
476   fp << fileContent.c_str()<< std::endl;
477   fp.close();
478 }
479 //--------------------------------------------------------------------
480
481
482 //--------------------------------------------------------------------
483 void vvLandmarks::SetTime(int time)
484 {
485   if (time >= 0 && time <= ((int)mPoints.size() -1)) {
486     mPolyData->SetPoints(mPoints[time]);
487     mPolyData->GetPointData()->SetScalars(mIds[time]);
488     mPolyData->GetPointData()->AddArray(mLabels[time]);
489     mPolyData->Modified();
490 #if VTK_MAJOR_VERSION <= 5
491     mPolyData->Update();
492 #else
493     //mPolyData->Update();
494 #endif
495     mTime = time;
496   }
497 }
498 //--------------------------------------------------------------------
499
500
501 //--------------------------------------------------------------------
502 std::string vvLandmarks::replace_dots(std::string input)
503 {
504   ///Replaces the dots used in the file with the decimal separator in use on the platform
505   lconv * conv=localeconv();
506   unsigned int position = input.find( "." );
507   while ( position < input.size() ) {
508     input.replace(position, 1, conv->decimal_point);
509     position = input.find( ".", position + 1 );
510   }
511   return input;
512 }
513 //--------------------------------------------------------------------