PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
ConvertXmlToFcsv.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2  Program: Plus
3  Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4  See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 // Local includes
8 #include "PlusConfigure.h"
10 
11 // VTK includes
12 #include <vtkSmartPointer.h>
13 #include <vtkXMLDataElement.h>
14 #include <vtkXMLUtilities.h>
15 #include <vtksys/CommandLineArguments.hxx>
16 
17 // STL includes
18 #include <fstream>
19 #include <iostream>
20 #include <limits>
21 #include <sstream>
22 
23 static const int FIDUCIAL_COUNT_PER_SLICE = 7;
24 static const int MAX_FIDUCIAL_COUNT = 50;
25 
26 struct FiducialInfo
27 {
28  std::string label;
29  double x;
30  double y;
31  double z;
32  int sel;
33  int vis;
34 };
35 
36 int main(int argc, char** argv)
37 {
38  std::string inputXmlFileName;
39  std::string outputFcsvFileName;
40 
41  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
42 
43  vtksys::CommandLineArguments args;
44  args.Initialize(argc, argv);
45 
46  args.AddArgument("--xml-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputXmlFileName, "Input XML file name");
47  args.AddArgument("--output-xml-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &outputFcsvFileName, "Output FCSV file name");
48  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
49 
50  if (!args.Parse())
51  {
52  std::cerr << "Problem parsing arguments" << std::endl;
53  std::cout << "Help: " << args.GetHelp() << std::endl;
54  exit(EXIT_FAILURE);
55  }
56 
57  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
58 
59  if (inputXmlFileName.empty() || outputFcsvFileName.empty())
60  {
61  std::cerr << "input and output file names are required" << std::endl;
62  exit(EXIT_FAILURE);
63  }
64 
66 
67  std::ofstream of;
68  of.open(outputFcsvFileName.c_str());
69 
70  vtkSmartPointer<vtkXMLDataElement> rootElem = vtkSmartPointer<vtkXMLDataElement>::Take(vtkXMLUtilities::ReadElementFromFile(inputXmlFileName.c_str()));
71 
72  // check to make sure we have the right element
73  if (rootElem == NULL)
74  {
75  LOG_ERROR("Reading XML data file failed: " << inputXmlFileName);
76  exit(EXIT_FAILURE);
77  }
78  if (strcmp(rootElem->GetName(), PlusUsFidSegResultFile::TEST_RESULTS_ELEMENT_NAME) != 0)
79  {
80  LOG_ERROR("XML data file is invalid");
81  exit(EXIT_FAILURE);
82  }
83 
84  // Write header
85  of << "# Fiducial List file " << outputFcsvFileName << std::endl;
86  of << "# version = 2" << std::endl;
87  of << "# name = UsFid" << std::endl;
88  of << "# numPoints = 0" << std::endl;
89  of << "# symbolScale = 5" << std::endl;
90  of << "# symbolType = 12" << std::endl;
91  of << "# visibility = 1" << std::endl;
92  of << "# textScale = 4.5" << std::endl;
93  of << "# color = 0.4,1,1" << std::endl;
94  of << "# selectedColor = 1,0.5,0.5" << std::endl;
95  of << "# opacity = 1" << std::endl;
96  of << "# ambient = 0" << std::endl;
97  of << "# diffuse = 1" << std::endl;
98  of << "# specular = 0" << std::endl;
99  of << "# power = 1" << std::endl;
100  of << "# locked = 0" << std::endl;
101  of << "# numberingScheme = 0" << std::endl;
102  of << "# columns = label,x,y,z,sel,vis" << std::endl;
103 
104  // Write fiducial lines
105  for (int nestedElemInd = 0; nestedElemInd < rootElem->GetNumberOfNestedElements(); nestedElemInd++)
106  {
107  vtkXMLDataElement* currentElem = rootElem->GetNestedElement(nestedElemInd);
108  if (currentElem == NULL)
109  {
110  LOG_ERROR("Invalid current data element");
111  exit(EXIT_FAILURE);
112  }
113  if (strcmp(currentElem->GetName(), PlusUsFidSegResultFile::TEST_CASE_ELEMENT_NAME) != 0)
114  {
115  // ignore all non-test-case elements
116  continue;
117  }
118 
119  vtkXMLDataElement* inputElem = currentElem->FindNestedElementWithName("Input");
120  int frameIndex = 0;
121  inputElem->GetScalarAttribute("ImageSeqFrameIndex", frameIndex);
122 
123  vtkXMLDataElement* outputElem = currentElem->FindNestedElementWithName("Output");
124 
125  const int MAX_FIDUCIAL_COORDINATE_COUNT = MAX_FIDUCIAL_COUNT * 2;
126  double fiducialPoints[MAX_FIDUCIAL_COORDINATE_COUNT]; // baseline fiducial Points
127  memset(fiducialPoints, 0, sizeof(fiducialPoints[0] * MAX_FIDUCIAL_COORDINATE_COUNT));
128  int fidPointsRead = outputElem->GetVectorAttribute("SegmentationPoints", MAX_FIDUCIAL_COORDINATE_COUNT, fiducialPoints);
129 
130  if (fidPointsRead % 2 != 0)
131  {
132  LOG_ERROR("Unpaired baseline fiducial coordinates");
133  exit(EXIT_FAILURE);
134  }
135 
136  if (fidPointsRead > MAX_FIDUCIAL_COORDINATE_COUNT)
137  {
138  LOG_WARNING("Too many baseline fiducials");
139  }
140 
141  std::vector<FiducialInfo> fids(FIDUCIAL_COUNT_PER_SLICE);
142  for (int i = 0; i < FIDUCIAL_COUNT_PER_SLICE; i++)
143  {
144  fids[i].label = "test";
145  fids[i].x = 0;
146  fids[i].y = 0;
147  fids[i].z = frameIndex;
148  fids[i].sel = 0;
149  fids[i].vis = 0;
150  }
151 
152  const int FID_COUNT_TAB2_5_POINT = 5;
153  const int FID_COUNT_TAB2_6_POINT = 6;
154  int fidIndices[FID_COUNT_TAB2_5_POINT] = {0,/* skip 1 */ 2, 3, 4, /* skip 5 */ 6};
155 
156  if (fidPointsRead == FID_COUNT_TAB2_5_POINT * 2) // 5 fiducials are found, we assume that the 2nd and the 6th are not found
157  {
158  for (int f = 0; f < FID_COUNT_TAB2_5_POINT; ++f)
159  {
160  // X and Y coordinates should be inverted, because FCSV (Slicer) assumes RAS coordinate system, while
161  // itk images use LPS coordinate system
162  double x = -fiducialPoints[f * 2 + 0];
163  double y = -fiducialPoints[f * 2 + 1];
164  fids[fidIndices[f]].x = x;
165  fids[fidIndices[f]].y = y;
166  fids[fidIndices[f]].sel = 1;
167  fids[fidIndices[f]].vis = 1;
168  }
169  }
170  else // found no fiducials
171  {
172  for (int f = 0; f < FID_COUNT_TAB2_5_POINT; ++f)
173  {
174  // X and Y coordinates should be inverted, because FCSV (Slicer) assumes RAS coordinate system, while
175  // itk images use LPS coordinate system
176  fids[fidIndices[f]].x = 0;
177  fids[fidIndices[f]].y = 0;
178  fids[fidIndices[f]].sel = 1;
179  fids[fidIndices[f]].vis = 0;
180  }
181  }
182 
183  if (fidPointsRead == FID_COUNT_TAB2_6_POINT * 2)
184  {
185  for (int fidIndex = 0; fidIndex < FID_COUNT_TAB2_6_POINT; ++fidIndex)
186  {
187  int fidIndices[FID_COUNT_TAB2_6_POINT] = {0, 1 , 2, 3, 4, 5 };
188  // X and Y coordinates should be inverted, because FCSV (Slicer) assumes RAS coordinate system, while
189  // itk images use LPS coordinate system
190  double x = -fiducialPoints[fidIndex * 2 + 0];
191  double y = -fiducialPoints[fidIndex * 2 + 1];
192  fids[fidIndices[fidIndex]].x = x;
193  fids[fidIndices[fidIndex]].y = y;
194  fids[fidIndices[fidIndex]].vis = 1;
195  }
196  }
197 
198  for (int i = 0; i < FIDUCIAL_COUNT_PER_SLICE; i++)
199  {
200  of << fids[i].label << "," << fids[i].x << "," << fids[i].y << "," << fids[i].z << "," << fids[i].sel << "," << fids[i].vis << std::endl;
201  }
202  }
203 
204  LOG_DEBUG("Done!");
205 
206  return EXIT_SUCCESS;
207 }
for i
static const int MAX_FIDUCIAL_COUNT
static const int FIDUCIAL_COUNT_PER_SLICE
static const char * TEST_CASE_ELEMENT_NAME
int main(int argc, char **argv)
int x
Definition: phidget22.h:4265
static vtkIGSIOLogger * Instance()
static const char * TEST_RESULTS_ELEMENT_NAME
Direction vectors of rods y
Definition: algo3.m:15