PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusPhantomLinearObjectRegistrationAlgo.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 #include "PlusConfigure.h"
8 
10 #include "vtkIGSIOTransformRepository.h"
11 
12 #include "vtkObjectFactory.h"
13 #include "vtkXMLUtilities.h"
14 #include "vtksys/SystemTools.hxx"
15 #include "vtkMath.h"
16 
17 #include "itkImage.h"
18 #include "itkLandmarkBasedTransformInitializer.h"
19 #include "itkSimilarity3DTransform.h"
20 
21 //-----------------------------------------------------------------------------
22 
24 
25 std::string vtkPlusPhantomLinearObjectRegistrationAlgo::ConfigurationElementName = "vtkPlusPhantomLinearObjectRegistrationAlgo";
26 
27 //-----------------------------------------------------------------------------
28 
30 {
31  this->RegistrationError = -1.0;
32 
34  this->RecordedPoints = NULL;
36  this->PhantomCoordinateFrame = NULL;
37  this->ReferenceCoordinateFrame = NULL;
38  this->StylusTipCoordinateFrame = NULL;
39 
40  vtkSmartPointer<vtkPoints> acquiredPoints = vtkSmartPointer<vtkPoints>::New();
41  this->SetRecordedPoints(acquiredPoints);
42 
43  vtkSmartPointer<vtkDoubleArray> markerToReferenceTransformMatrixArray = vtkSmartPointer<vtkDoubleArray>::New();
44  this->SetMarkerToReferenceTransformMatrixArray(markerToReferenceTransformMatrixArray);
45  this->MarkerToReferenceTransformMatrixArray->SetNumberOfComponents(16);
46 }
47 
48 //-----------------------------------------------------------------------------
49 
51 {
53  this->SetDefinedPlanesFromXML(NULL);
54  this->SetRecordedPlanes(NULL);
55  this->SetRecordedPoints(NULL);
56 }
57 
58 //-----------------------------------------------------------------------------
59 
60 PlusStatus vtkPlusPhantomLinearObjectRegistrationAlgo::LinearObjectRegister(vtkIGSIOTransformRepository* aTransformRepository/* = NULL*/)
61 {
62  LOG_TRACE("vtkPlusPhantomLinearObjectRegistrationAlgo::Register");
63 
64  Planes fixedPlanes;
65  Planes movingPlanes;
66  References fixedReferences;
67  References movingReferences;
68 
69  for (int i=0; i<this->RecordedPoints->GetNumberOfPoints(); i++)
70  {
71  //TODO: Matthew's algorithm for converting points into a plane goes here
72  ;
73 
74  //-----------------------------------------------------------------
75  }
76 
77  fixedPlanes = this->DefinedPlanes;
78  fixedReferences = this->DefinedReferences;
79 
80  // Look at matthew's code to see what his algorithnm wants as input
81  // hint I think it's planes and an xml
82  // Then, call his algorithm!
83 
84  //for each plane recorded by the stylus
85  int i(0);
86  for (std::vector<Plane>::const_iterator it = this->RecordedPlanes.PlanesBegin(); it != this->RecordedPlanes.PlanesEnd(); ++it )
87  {
88  LOG_DEBUG("Phantom plane " << i << ": Defined: " << it->ToXMLString() << " Recorded: " << movingPlanes.GetPlane(i).ToXMLString() );
89  ++i;
90  }
91 
92  // Initialize ITK transform
93  auto transform = itk::VersorRigid3DTransform<double>::New();
94  transform->SetIdentity();
95 
96  //TODO: make itk::PlaneBasedTransfromInitializer
97  /*auto initializer = itk::LandmarkBasedTransformInitializer<itk::VersorRigid3DTransform<double>, itk::Image<short,3>, itk::Image<short,3> >::New();
98  initializer->SetTransform(transform);
99  initializer->SetFixedPlanes(fixedPlanes);
100  initializer->SetMovingPlanes(movingPlanes);
101  initializer->InitializeTransform();*/
102 
103  // Get result (do the registration)
104  vtkSmartPointer<vtkMatrix4x4> phantomToReferenceTransformMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
105  phantomToReferenceTransformMatrix->Identity();
106 
107  //TODO: this is where Matthew's algorithm for linear object registration will go--------------------------------------------------------------------
108  /*itk::Matrix<double,3,3> transformMatrix = transform->GetMatrix();
109  for (int i=0; i<transformMatrix.RowDimensions; ++i)
110  {
111  for (int j=0; j<transformMatrix.ColumnDimensions; ++j)
112  {
113  phantomToReferenceTransformMatrix->SetElement(i, j, transformMatrix[i][j]);
114  }
115  }
116  itk::Vector<double,3> transformOffset = transform->GetOffset();
117  for (int j=0; j<transformOffset.GetNumberOfComponents(); ++j)
118  {
119  phantomToReferenceTransformMatrix->SetElement(j, 3, transformOffset[j]);
120  }
121 
122  std::ostringstream osPhantomToReferenceTransformMatrix;
123  phantomToReferenceTransformMatrix->Print(osPhantomToReferenceTransformMatrix);
124 
125  LOG_DEBUG("PhantomToReferenceTransformMatrix:\n" << osPhantomToReferenceTransformMatrix.str().c_str() );
126 
127  this->SetPhantomToReferenceTransformMatrix(phantomToReferenceTransformMatrix);
128 
129  if (ComputeError() != PLUS_SUCCESS)
130  {
131  LOG_ERROR("Failed to compute registration error!");
132  return PLUS_FAIL;
133  }*/
134 
135  //------------------------------------------------------------------------------------------------------------------------------------------------
136 
137  // Save result
138  if (aTransformRepository)
139  {
140  igsioTransformName phantomToReferenceTransformName(this->PhantomCoordinateFrame, this->ReferenceCoordinateFrame);
141  aTransformRepository->SetTransform(phantomToReferenceTransformName, this->PhantomToReferenceTransformMatrix);
142  aTransformRepository->SetTransformPersistent(phantomToReferenceTransformName, true);
143  aTransformRepository->SetTransformDate(phantomToReferenceTransformName, vtkIGSIOAccurateTimer::GetInstance()->GetDateAndTimeString().c_str());
144  aTransformRepository->SetTransformError(phantomToReferenceTransformName, this->RegistrationError);
145  }
146  else
147  {
148  LOG_INFO("Transform repository object is NULL, cannot save results into it");
149  }
150 
151  return PLUS_SUCCESS;
152 }
153 
154 //-----------------------------------------------------------------------------
155 
157 {
158  LOG_TRACE("vtkPlusPhantomLinearObjectRegistrationAlgo::ReadConfiguration");
159 
160  XML_FIND_NESTED_ELEMENT_REQUIRED(phantomDefinition, aConfig, "PhantomDefinition");
161 
162  this->DefinedPlanes.Reset();
163  this->RecordedPlanes.Reset();
164  this->DefinedPlaneNames.clear();
165 
166  // Load geometry
167  XML_FIND_NESTED_ELEMENT_REQUIRED(geometry, phantomDefinition, "Geometry");
168 
169 // Read references (NWires are not interesting at this point, it is only parsed if segmentation is needed)
170  vtkXMLDataElement* references = geometry->FindNestedElementWithName("References");
171  if (references == NULL)
172  {
173  if(geometry->FindNestedElementWithName("Landmarks") == NULL)
174  {
175  LOG_ERROR("No References or Landmarks found in configuration file found, registration is not possible!");
176  return PLUS_FAIL;
177  }
178  else
179  {
180  LOG_WARNING("No References found in configuration file found, perform Landmark Registration");
181  return PLUS_FAIL;
182  }
183  }
184  else
185  {
186  //find the number of references defined in the config file
187  int numberOfReferences = references->GetNumberOfNestedElements();
188  this->DefinedReferenceNames.resize(numberOfReferences);
189 
190  //for each reference
191  for (int i=0; i<numberOfReferences; ++i)
192  {
193  //define a reference variable
194  vtkXMLDataElement* reference = references->GetNestedElement(i);
195  if ((reference == NULL) || (STRCASECMP("Reference", reference->GetName())))
196  {
197  LOG_WARNING("Invalid reference definition found");
198  continue;
199  }
200 
201  //define a varaible to store the name of the reference
202  const char* referenceName = reference->GetAttribute("Name");
203  if (referenceName==NULL)
204  {
205  LOG_WARNING("Invalid reference name (reference #"<<i+1<<")");
206  continue;
207  }
208 
209  double referencePosition[3];
210  if (! reference->GetVectorAttribute("Position", 3, referencePosition))
211  {
212  LOG_WARNING("Invalid reference position (reference #"<<i+1<<")");
213  continue;
214  }
215 
216  std::vector<double> referencePositionVector;
217  for(int j=0; j<3;j++)
218  {
219  referencePositionVector.push_back(referencePosition[j]);
220  }
221 
222  this->DefinedReferences.InsertReference(Reference(referencePositionVector));
223  this->DefinedReferenceNames[i] = referenceName;
224  }
225  }
226 
227  if (this->DefinedReferences.GetNumberOfReferences() == 0)
228  {
229  LOG_ERROR("No valid references were found!");
230  return PLUS_FAIL;
231  }
232 
233  // Read planes (NWires are not interesting at this point, it is only parsed if segmentation is needed)
234  vtkXMLDataElement* planes = geometry->FindNestedElementWithName("Planes");
235  if (planes == NULL)
236  {
237  if(geometry->FindNestedElementWithName("Landmarks") == NULL)
238  {
239  LOG_ERROR("No Planes or Landmarks found in configuration file found, registration is not possible!");
240  return PLUS_FAIL;
241  }
242  else
243  {
244  LOG_WARNING("No Planes found in configuration file found, perform Landmark Registration");
245  return PLUS_FAIL;
246  }
247  }
248  else
249  {
250  //find the number of planes defined in the config file
251  int numberOfPlanes = planes->GetNumberOfNestedElements();
252  this->DefinedPlaneNames.resize(numberOfPlanes);
253 
254  //for each plane
255  for (int i=0; i<numberOfPlanes; ++i)
256  {
257  //define a plane variable
258  vtkXMLDataElement* plane = planes->GetNestedElement(i);
259 
260  if ((plane == NULL) || (STRCASECMP("Plane", plane->GetName())))
261  {
262  LOG_WARNING("Invalid plane definition found!");
263  continue;
264  }
265 
266  //define a varaible to store the name of the plane
267  const char* planeName = plane->GetAttribute("Name");
268  if (planeName==NULL)
269  {
270  LOG_WARNING("Invalid plane name (plane #"<<i+1<<")");
271  continue;
272  }
273 
274  //define an array of length 3 of 3-tuples (each plane has 3 points that define it each with 3 rectangular coordinates in the phantom coordinate system)
275  std::vector<double> pointsOnPlane[3];
276 
277  double pointOnPlane[3];
278  //test the validity of each point on the plane then add the plane to the DefinedPlanes
279  if (! plane->GetVectorAttribute("BasePoint", 3, pointOnPlane))
280  {
281  LOG_WARNING("Invalid base point position!");
282  continue;
283  }
284  for(int j=0; j<3; j++)
285  {
286  pointsOnPlane[0].push_back(pointOnPlane[j]);
287  }
288 
289  if (! plane->GetVectorAttribute("EndPoint1", 3, pointOnPlane))
290  {
291  LOG_WARNING("Invalid end point 1 position!");
292  continue;
293  }
294  for(int j=0; j<3; j++)
295  {
296  pointsOnPlane[1].push_back(pointOnPlane[j]);
297  }
298 
299  if (! plane->GetVectorAttribute("EndPoint2", 3, pointOnPlane))
300  {
301  LOG_WARNING("Invalid end point 2 position!");
302  continue;
303  }
304  for(int j=0; j<3; j++)
305  {
306  pointsOnPlane[2].push_back(pointOnPlane[j]);
307  }
308 
309  this->DefinedPlanes.InsertPlane(Plane(pointsOnPlane[0], pointsOnPlane[1], pointsOnPlane[2]));
310  this->DefinedPlaneNames[i] = planeName;
311  //---------------------------------------------------------------------------------------------------------------------------------------------
312  }
313  }
314 
315  if (this->DefinedPlanes.GetNumberOfPlanes() == 0)
316  {
317  LOG_ERROR("No valid planes were found!");
318  return PLUS_FAIL;
319  }
320 
321  XML_FIND_NESTED_ELEMENT_REQUIRED(phantomRegistrationElement, aConfig, vtkPlusPhantomLinearObjectRegistrationAlgo::ConfigurationElementName.c_str());
322  XML_READ_CSTRING_ATTRIBUTE_REQUIRED(PhantomCoordinateFrame, phantomRegistrationElement);
323  XML_READ_CSTRING_ATTRIBUTE_REQUIRED(ReferenceCoordinateFrame, phantomRegistrationElement);
324  XML_READ_CSTRING_ATTRIBUTE_REQUIRED(StylusTipCoordinateFrame, phantomRegistrationElement);
325 
326  return PLUS_SUCCESS;
327 }
328 
329 //-----------------------------------------------------------------------------
330 
332 {
333  LOG_TRACE("vtkPlusPhantomLinearObjectRegistrationAlgo::ComputeError");
334 
335  //TODO: Matthew's Algorithm for error calculation-------------------------------------------------------------------------------------------------
336 
337  /*for (int i=0; i<this->RecordedLandmarks->GetNumberOfPoints(); ++i)
338  {
339  // Defined landmarks from xml are in the phantom coordinate system
340  double* landmarkPointArray = this->DefinedLandmarks->GetPoint(i);
341  double landmarkPoint[4] = {landmarkPointArray[0], landmarkPointArray[1], landmarkPointArray[2], 1.0};
342 
343  double* transformedLandmarkPoint = this->PhantomToReferenceTransformMatrix->MultiplyDoublePoint(landmarkPoint);
344 
345  // Recorded landmarks are in the tracker coordinate system
346  double* recordedPointArray = this->RecordedLandmarks->GetPoint(i);
347 
348  sumDistance += sqrt( vtkMath::Distance2BetweenPoints(transformedLandmarkPoint, recordedPointArray) );
349  }
350 
351  this->RegistrationError = sumDistance / this->RecordedLandmarks->GetNumberOfPoints();*/
352 
353  //----------------------------------------------------------------------------------------------------------------------------------------
354 
355  LOG_DEBUG("Registration error = " << this->RegistrationError);
356 
357  return PLUS_SUCCESS;
358 }
359 
360 
361 //-----------------------------------------------------------------------------
362 
364 {
365  this->MarkerToReferenceTransformMatrixArray->InsertNextTuple(*aMarkerToReferenceTransformMatrix->Element);
366 
367  return PLUS_SUCCESS;
368 }
369 //-----------------------------------------------------------------------------
370 
372 {
373  LOG_TRACE("vtkPhantomLinearObjectRegistration::Initialize");
374 
375  this->MarkerToReferenceTransformMatrixArray->SetNumberOfTuples(0);
376 
377  return PLUS_SUCCESS;
378 }
379 //-----------------------------------------------------------------------------
380 
382 {
383  if(planes == NULL)
384  {
385  this->RecordedPlanes.Reset();
386  return;
387  }
388 
389  this->RecordedPlanes = *planes;
390 }
391 //-----------------------------------------------------------------------------
392 
394 {
395  if(planes == NULL)
396  {
397  this->DefinedPlanes.Reset();
398  return;
399  }
400 
401  this->DefinedPlanes = *planes;
402 }
std::vector< Plane >::const_iterator PlanesBegin() const
Definition: Planes.cxx:55
virtual void SetRecordedPoints(vtkPoints *)
PlusStatus LinearObjectRegister(vtkIGSIOTransformRepository *aTransformRepository=NULL)
virtual void SetPhantomToReferenceTransformMatrix(vtkMatrix4x4 *)
const Plane & GetPlane(int index)
Definition: Planes.cxx:43
igsioStatus PlusStatus
Definition: PlusCommon.h:40
void Reset()
Definition: Planes.cxx:22
for i
#define PLUS_FAIL
Definition: PlusCommon.h:43
Definition: Plane.h:18
virtual std::string ToXMLString() const
Definition: Plane.cxx:65
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
Definition: Planes.h:13
Landmark registration to determine the Phantom pose relative to the attached marker (PhantomReference...
int GetNumberOfPlanes()
Definition: Planes.cxx:49
void InsertPlane(const Plane &newPlane)
Definition: Planes.cxx:28
virtual void SetMarkerToReferenceTransformMatrixArray(vtkDoubleArray *)
void InsertReference(const Reference &newReference)
Definition: References.cxx:32
std::vector< Plane >::const_iterator PlanesEnd() const
Definition: Planes.cxx:61
PlusStatus InsertNextCalibrationPoint(vtkMatrix4x4 *aMarkerToReferenceTransformMatrix)
vtkStandardNewMacro(vtkPlusPhantomLinearObjectRegistrationAlgo)
int GetNumberOfReferences()
Definition: References.cxx:56