Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkOptitrackTrackingDevice.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
14 
15 #ifdef MITK_USE_OPTITRACK_TRACKER
16 
17 
18 
22 #include <NPTrackingTools.h>
23 
24 //=======================================================
25 // Static method: IsDeviceInstalled
26 //=======================================================
28 {
29  return true;
30 }
31 
32 //=======================================================
33 // Constructor
34 //=======================================================
36  : mitk::TrackingDevice(),
37  m_initialized(false)
38 {
39  // Set the MultiThread and Mutex
40  this->m_MultiThreader = itk::MultiThreader::New();
41  this->m_ToolsMutex = itk::FastMutexLock::New();
42 
43  //Set the mitk device information
44  SetData(mitk::DeviceDataNPOptitrack);
45 
46  //Clear List of tools
47  this->m_AllTools.clear();
48 }
49 
50 //=======================================================
51 // Destructor
52 //=======================================================
54 {
55  MITK_DEBUG << "Deleting OptitrackTrackingDevice";
56  int result;
57 
58  // If device is in Tracking mode, stop the Tracking firts
59  if (this->GetState() == mitk::TrackingDevice::Tracking)
60  {
61  MITK_DEBUG << "OptitrackTrackingDevice in Tracking State -> Stopping Tracking";
62  result = this->StopTracking();
63 
64  if(result == NPRESULT_SUCCESS){
65  MITK_INFO << "OptitrackTrackingDevice Stopped";
66  }
67  else
68  {
69  MITK_INFO << "Error during Stopping";
71  }
72  }
73 
74  // If device is Ready, Close the connection to device and release the memory
75  if (this->GetState() == mitk::TrackingDevice::Ready)
76  {
77  MITK_DEBUG << "OptitrackTrackingDevice in Ready State -> Closing the Connection";
78  result = this->CloseConnection();
79 
80  if(result)
81  {
82  MITK_INFO << "OptitrackTrackingDevice Connection closed";
83  }
84  else
85  {
86  MITK_DEBUG << "Error during Closing Connection";
88  }
89  }
90 
91  // Set the device off
92  m_initialized = false;
93  // Change State to Setup
94  this->SetState(mitk::TrackingDevice::Setup);
95  MITK_DEBUG <<"OptitrackTrackingDevice deleted successfully";
96 }
97 
98 //=======================================================
99 // OpenConnection
100 //=======================================================
102 {
103  // Not initialize the system twice.
104  if(!m_initialized)
105  {
106  MITK_DEBUG << "Initialize Optitrack Tracking System";
107 
108  if( this->InitializeCameras() )
109  {
110  m_initialized = true; // Set the initialized variable to true
111  this->SetState(mitk::TrackingDevice::Ready);
112  if(this->m_calibrationPath.empty()){
113  MITK_INFO << "Numer of connected cameras = " << TT_CameraCount();
114  MITK_WARN << "Attention: No calibration File defined !!";
115  return m_initialized;
116  }
117  else
118  {
119  this->LoadCalibration();
120  }
121  }
122  else
123  {
124  m_initialized = false; // Set the initialized variable to false
125  this->SetState(mitk::TrackingDevice::Setup); // Set the State to Setup
126  MITK_INFO << "Device initialization failed. Device is still in setup state";
127  mitkThrowException(mitk::IGTException) << "Device initialization failed. Device is still in setup state";
128  }
129  }
130  //this->LoadCalibration();
131  return m_initialized;
132 }
133 
134 //=======================================================
135 // InitializeCameras
136 //=======================================================
138 {
139  MITK_DEBUG << "Initialize Optitrack";
140  int result;
141 
142  result = TT_Initialize(); // Initialize the cameras
143 
144  if(result == NPRESULT_SUCCESS)
145  {
146  MITK_DEBUG << "Optitrack Initialization Succeed";
147  return true;
148  }
149  else
150  {
152  // If not succeed after OPTITRACK_ATTEMPTS times launch exception
153  MITK_INFO << "Optitrack Tracking System cannot be initialized \n" << mitk::OptitrackErrorMessages::GetOptitrackErrorMessage(result);
154  mitkThrowException(mitk::IGTException) << "Optitrack Tracking System cannot be initialized \n" << mitk::OptitrackErrorMessages::GetOptitrackErrorMessage(result);
155  return false;
156  }
157 }
158 
159 //=======================================================
160 // LoadCalibration
161 //=======================================================
163 {
164  MITK_DEBUG << "Loading System Calibration";
165  int resultLoadCalibration;
166 
167  // Check the file path
168  if(this->m_calibrationPath.empty()){
169  MITK_INFO << "Calibration Path is empty";
170  mitkThrowException(mitk::IGTException) << "Calibration Path is empty";
171  return false;
172  }
173 
174  // Once the system is ready and Initialized , a calibration file is loaded.
175  if(this->m_initialized)
176  {
177 
178  for( int i=OPTITRACK_ATTEMPTS; i>0; i--)
179  {
180  resultLoadCalibration = TT_LoadCalibration(this->m_calibrationPath.c_str());
181 
182  if(resultLoadCalibration != NPRESULT_SUCCESS)
183  {
185  MITK_DEBUG << "Trying again...";
186  }
187  else
188  {
189  MITK_DEBUG << "Calibration file has been loaded successfully";
190  return true;
191  }
192 
193  }
194 
195  MITK_INFO << "System cannot load a calibration file";
196  mitkThrowException(mitk::IGTException) << "System cannot load a calibration file";
197 
198  }
199  else
200  {
201  MITK_INFO << "System is not ready for load a calibration file because it has not been initialized yet";
202  mitkThrowException(mitk::IGTException) << "System is not ready for load a calibration file because it has not been initialized yet";
203  return false;
204  }
205 
206  // Never reach this point
207  return false;
208 }
209 
210 //=======================================================
211 // SetCalibrationPath
212 //=======================================================
213 void mitk::OptitrackTrackingDevice::SetCalibrationPath(std::string calibrationPath){
214 
215  MITK_DEBUG << "SetcalibrationPath";
216  MITK_DEBUG << calibrationPath;
217 
218  // Check the file path
219  if(calibrationPath.empty())
220  {
221  MITK_INFO << "Calibration Path is empty";
222  //mitkThrowException(mitk::IGTException) << "Calibration Path is empty";
223  return;
224  }
225 
226  this->m_calibrationPath = calibrationPath;
227  MITK_INFO << "Calibration Path has been updated to: " << this->m_calibrationPath;
228  return;
229 }
230 
231 //=======================================================
232 // CloseConnection
233 //=======================================================
235 {
236  MITK_DEBUG << "CloseConnection";
237  int resultStop, resultShutdown;
238 
239  if(m_initialized) // Close connection if the System was initialized first
240  {
241  if(this->GetState() == mitk::TrackingDevice::Tracking)
242  {
243  MITK_DEBUG << "Device state: Tracking -> Stoping the Tracking";
244  resultStop = this->StopTracking(); //Stop tracking on close
245  }
246 
247  this->SetState(mitk::OptitrackTrackingDevice::Setup);
248 
249  for( int i=OPTITRACK_ATTEMPTS; i>0; i--)
250  {
251 
252  TT_ClearTrackableList();
253  resultShutdown = TT_Shutdown();
254 
255  if(resultShutdown == NPRESULT_SUCCESS)
256  {
257  MITK_DEBUG << "System has been Shutdown Correctly";
258  Sleep(2000);
259  return true;
260  }
261  else
262  {
263  MITK_DEBUG << "System cannot ShutDown now. Trying again...";
264  }
265  }
266 
267  MITK_INFO << "System cannot ShutDown now";
269  return false;
270  }
271  else
272  {
273  MITK_INFO << "System has not been initialized. Close connection cannot be done";
274  mitkThrowException(mitk::IGTException) << "System has not been initialized. Close connection cannot be done";
275  return false;
276  }
277 
278  return false;
279 }
280 
281 //=======================================================
282 // StartTracking
283 //=======================================================
285 {
286  MITK_DEBUG << "StartTracking";
287  bool resultIsTrackableTracked;
288 
289  if (this->GetState() != mitk::TrackingDevice::Ready)
290  {
291  MITK_INFO << "System is not in State Ready -> Cannot StartTracking";
292  mitkThrowException(mitk::IGTException) << "System is not in State Ready -> Cannot StartTracking";
293  return false;
294  }
295 
296  this->SetState(mitk::TrackingDevice::Tracking);
297 
298  // Change the m_StopTracking Variable to false
299  this->m_StopTrackingMutex->Lock();
300  this->m_StopTracking = false;
301  this->m_StopTrackingMutex->Unlock();
302 
303  /******************************************************************************
304  ###############################################################################
305  TODO: check the timestamp from the Optitrack API
306  ###############################################################################
307  ******************************************************************************/
309 
310  // Launch multiThreader using the Function ThreadStartTracking that executes the TrackTools() method
311  m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartTracking, this); // start a new thread that executes the TrackTools() method
312 
313  // Information for the user
314  if(GetToolCount() == 0) MITK_INFO << "No tools are defined";
315 
316  for ( int i = 0; i < GetToolCount(); ++i) // use mutexed methods to access tool container
317  {
318  resultIsTrackableTracked = TT_IsTrackableTracked(i);
319  if(resultIsTrackableTracked)
320  {
321  MITK_DEBUG << "Trackable " << i << " is inside the Tracking Volume and it is Tracked";
322  }
323  else
324  {
325  MITK_DEBUG << "Trackable " << i << " is not been tracked. Check if it is inside the Tracking volume";
326  }
327 
328  }
329 
330  return true;
331 }
332 
333 //=======================================================
334 // StopTracking
335 //=======================================================
337 {
338  MITK_DEBUG << "StopTracking";
339 
340  if (this->GetState() == mitk::TrackingDevice::Tracking) // Only if the object is in the correct state
341  {
342  //Change the StopTracking value
343  m_StopTrackingMutex->Lock(); // m_StopTracking is used by two threads, so we have to ensure correct thread handling
344  m_StopTrackingMutex->Unlock();
345  this->SetState(mitk::TrackingDevice::Ready);
346  }
347  else
348  {
349  m_TrackingFinishedMutex->Unlock();
350  MITK_INFO << "System is not in State Tracking -> Cannot StopTracking";
351  mitkThrowException(mitk::IGTException) << "System is not in State Tracking -> Cannot StopTracking";
352  return false;
353  }
354 
355  /******************************************************************************
356  ###############################################################################
357  TODO: check the timestamp from the Optitrack API
358  ###############################################################################
359  ******************************************************************************/
361 
362  m_TrackingFinishedMutex->Unlock();
363  return true;
364 }
365 
366 //=======================================================
367 // ThreadStartTracking
368 //=======================================================
369 ITK_THREAD_RETURN_TYPE mitk::OptitrackTrackingDevice::ThreadStartTracking(void* pInfoStruct)
370 {
371  MITK_DEBUG << "ThreadStartTracking";
372 
373  /* extract this pointer from Thread Info structure */
374  struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
375 
376  if (pInfo == nullptr)
377  {
378  return ITK_THREAD_RETURN_VALUE;
379  }
380 
381  if (pInfo->UserData == nullptr)
382  {
383  return ITK_THREAD_RETURN_VALUE;
384  }
385 
386  OptitrackTrackingDevice *trackingDevice = static_cast<OptitrackTrackingDevice*>(pInfo->UserData);
387 
388  if (trackingDevice != nullptr)
389  {
390  // Call the TrackTools function in this thread
391  trackingDevice->TrackTools();
392  }
393  else
394  {
395  mitkThrowException(mitk::IGTException) << "In ThreadStartTracking(): trackingDevice is nullptr";
396  }
397 
398  trackingDevice->m_ThreadID = -1; // reset thread ID because we end the thread here
399  return ITK_THREAD_RETURN_VALUE;
400 }
401 
402 //=======================================================
403 // GetOptitrackTool
404 //=======================================================
406 {
407  MITK_DEBUG << "ThreadStartTracking";
408  OptitrackTrackingTool* t = nullptr;
409 
410  MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex
411  if(toolNumber < m_AllTools.size())
412  {
413  t = m_AllTools.at(toolNumber);
414  }
415  else
416  {
417  MITK_INFO << "The tool numbered " << toolNumber << " does not exist";
418  mitkThrowException(mitk::IGTException) << "The tool numbered " << toolNumber << " does not exist";
419  }
420  return t;
421 }
422 
423 //=======================================================
424 // GetToolCount
425 //=======================================================
427 {
428  MITK_DEBUG << "GetToolCount";
429  MutexLockHolder lock(*m_ToolsMutex); // lock and unlock the mutex
430  return ( int)(this->m_AllTools.size());
431 }
432 
433 //=======================================================
434 // TrackTools
435 //=======================================================
437 {
438  MITK_DEBUG << "TrackTools";
439 
440  Point3D position;
441  ScalarType t = 0.0;
442 
443  try
444  {
445  bool localStopTracking; // Because m_StopTracking is used by two threads, access has to be guarded by a mutex. To minimize thread locking, a local copy is used here
446  this->m_StopTrackingMutex->Lock(); // update the local copy of m_StopTracking
447  localStopTracking = this->m_StopTracking;
448 
449  /* lock the TrackingFinishedMutex to signal that the execution rights are now transfered to the tracking thread */
450  if (!localStopTracking)
451  {
452  m_TrackingFinishedMutex->Lock();
453  }
454 
455  this->m_StopTrackingMutex->Unlock();
456  while ((this->GetState() == mitk::TrackingDevice::Tracking) && (localStopTracking == false))
457  {
458  // For each Tracked Tool update the position and orientation
459  for ( int i = 0; i < GetToolCount(); ++i) // use mutexed methods to access tool container
460  {
461  OptitrackTrackingTool* currentTool = this->GetOptitrackTool(i);
462  if(currentTool != nullptr)
463  {
464  currentTool->updateTool();
465  MITK_DEBUG << "Tool number " << i << " updated position";
466  }
467  else
468  {
469  MITK_DEBUG << "Get data from tool number " << i << " failed";
470  mitkThrowException(mitk::IGTException) << "Get data from tool number " << i << " failed";
471  }
472  }
473 
474  /* Update the local copy of m_StopTracking */
475  this->m_StopTrackingMutex->Lock();
476  localStopTracking = m_StopTracking;
477  this->m_StopTrackingMutex->Unlock();
478  Sleep(OPTITRACK_FRAME_RATE);
479  } // tracking ends if we pass this line
480 
481  m_TrackingFinishedMutex->Unlock(); // transfer control back to main thread
482  }
483  catch(...)
484  {
485  m_TrackingFinishedMutex->Unlock();
486  this->StopTracking();
487  mitkThrowException(mitk::IGTException) << "Error while trying to track tools. Thread stopped.";
488  }
489 }
490 
491 //=======================================================
492 // SetCameraParams
493 //=======================================================
494 bool mitk::OptitrackTrackingDevice::SetCameraParams(int exposure, int threshold , int intensity, int videoType )
495 {
496  MITK_DEBUG << "SetCameraParams";
497 
498  if(this->m_initialized)
499  {
500  int num_cams = 0;
501  int resultUpdate;
502  bool resultSetCameraSettings;
503 
504  for( int i=OPTITRACK_ATTEMPTS; i>0; i--)
505  {
506  resultUpdate = TT_Update(); // Get Update for the Optitrack API
507  if(resultUpdate == NPRESULT_SUCCESS)
508  {
509  MITK_DEBUG << "Update Succeed";
510  num_cams = TT_CameraCount();
511  i = 0;
512  }
513  else
514  {
516  MITK_DEBUG << "Trying again...";
517  Sleep(30);
518  }
519  }
520 
521  // If no cameras are connected
522  if(num_cams == 0)
523  {
524  MITK_DEBUG << "No cameras are connected to the device";
525  return false;
526  mitkThrowException(mitk::IGTException) << "No cameras are connected to the device";
527  }
528 
529  for(int cam = 0; cam < num_cams; cam++) // for all connected cameras
530  {
531  for( int i=OPTITRACK_ATTEMPTS; i>0; i--)
532  {
533  resultUpdate = TT_Update(); // Get Update for the Optitrack API
534 
535  if(resultUpdate == NPRESULT_SUCCESS)
536  {
537  MITK_DEBUG << "Update Succeed for camera number " << cam;
538  resultSetCameraSettings = TT_SetCameraSettings(cam,videoType,exposure,threshold,intensity);
539 
540  if(resultSetCameraSettings)
541  {
542  MITK_INFO << "Camera # "<<cam<< " params are set";
543  i = 0; // End attempts for camera #cam
544  }
545  else
546  {
548  if(i == 1)
549  mitkThrowException(mitk::IGTException) << "Camera number " << cam << " failed during setting the params. Error: " << mitk::OptitrackErrorMessages::GetOptitrackErrorMessage(resultSetCameraSettings);
550  }
551  }
552  else
553  {
555  MITK_DEBUG << "Update: Trying again...";
556  }
557  }
558  }
559  }
560  else
561  {
562  MITK_INFO << "System is not Initialized -> System is not ready to perform the Camera Parameters Setting";
563  mitkThrowException(mitk::IGTException) << "System is not Initialized -> System is not ready to perform the Camera Parameters Setting";
564  return false;
565  }
566  return true;
567 }
568 
569 //=======================================================
570 // GetTool
571 //=======================================================
572 mitk::TrackingTool* mitk::OptitrackTrackingDevice::GetTool(unsigned int toolNumber) const
573 {
574  return static_cast<mitk::TrackingTool*>(GetOptitrackTool(toolNumber));
575 }
576 
577 //=======================================================
578 // AddToolByFileName
579 //=======================================================
581 {
582  bool resultSetToolByFileName;
583  if(m_initialized)
584  {
585  OptitrackTrackingTool::Pointer t = OptitrackTrackingTool::New();
586  resultSetToolByFileName= t->SetToolByFileName(fileName);
587 
588  if(resultSetToolByFileName)
589  {
590  this->m_AllTools.push_back(t);
591  MITK_INFO << "Added tool "<<t->GetToolName()<< ". Tool vector size is now: "<<m_AllTools.size();
592  return true;
593  }
594  else
595  {
596  MITK_INFO << "Tool could not be added";
597  mitkThrowException(mitk::IGTException) << "Tool could not be added";
598  return false;
599  }
600  }
601  else
602  {
603  MITK_INFO << "System is not Initialized -> Cannot Add tools";
604  mitkThrowException(mitk::IGTException) << "System is not Initialized -> Cannot Add tools";
605  return false;
606  }
607 }
608 
609 
610 //=======================================================
611 // IF Optitrack is not installed set functions to warnings
612 //=======================================================
613 
614 #else
615 
616 //=======================================================
617 // Static method: IsDeviceInstalled
618 //=======================================================
620 {
621  return false;
622 }
623 
624 //=======================================================
625 // Constructor
626 //=======================================================
628  : mitk::TrackingDevice(),
629  m_initialized(false)
630 {
632 }
633 
634 //=======================================================
635 // Destructor
636 //=======================================================
638 {
640 }
641 
642 //=======================================================
643 // OpenConnection
644 //=======================================================
646 {
648  return false;
649 }
650 
651 //=======================================================
652 // InitializeCameras
653 //=======================================================
655 {
657  return false;
658 }
659 
660 //=======================================================
661 // LoadCalibration
662 //=======================================================
664 {
666  return false;
667 }
668 
669 //=======================================================
670 // SetcalibrationPath
671 //=======================================================
672 void mitk::OptitrackTrackingDevice::SetCalibrationPath(std::string /*calibrationPath*/)
673 {
675 }
676 
677 //=======================================================
678 // CloseConnection
679 //=======================================================
681 {
683  return false;
684 }
685 
686 //=======================================================
687 // StartTracking
688 //=======================================================
690 {
692  return false;
693 }
694 
695 //=======================================================
696 // StopTracking
697 //=======================================================
699 {
701  return false;
702 }
703 
704 //=======================================================
705 // ThreadStartTracking
706 //=======================================================
708 {
710  return 0;
711 }
712 
713 //=======================================================
714 // GetOptitrackTool
715 //=======================================================
717 {
719  return nullptr;
720 }
721 
722 //=======================================================
723 // GetToolCount
724 //=======================================================
726 {
728  return 0;
729 }
730 
731 //=======================================================
732 // TrackTools
733 //=======================================================
735 {
737 }
738 
739 //=======================================================
740 // SetCameraParams
741 //=======================================================
743 {
745  return false;
746 }
747 
748 //=======================================================
749 // GetTool
750 //=======================================================
752 {
754  return nullptr;
755 }
756 
757 //=======================================================
758 // AddToolByFileName
759 //=======================================================
761 {
763  return false;
764 }
765 
766 #endif
#define OPTITRACK_FRAME_RATE
Time to refresh the tools location (ms)
bool CloseConnection() override
Close the Connection with the Tracker. Also CleanUp the Optitrack variables using the API: TT_CleanUp...
Interface for all Tracking Tools.
#define MITK_INFO
Definition: mitkLogMacros.h:18
double ScalarType
bool StopTracking() override
Stop the Tracking Thread and tools will not longer be updated.
An object of this class represents an exception of the MITK-IGT module.
OptitrackTrackingTool * GetOptitrackTool(unsigned int toolNumber) const
Return the tool pointer of the tool number toolNumber.
#define MITK_DEBUG
Definition: mitkLogMacros.h:22
DataCollection - Class to facilitate loading/accessing structured data.
bool LoadCalibration()
Load the Calibration file to the Optitrack System and set the cameras in calibrated locations...
static std::string GetOptitrackErrorMessage(int result)
Helper function to get the error messages from Optitrack API.
static ITK_THREAD_RETURN_TYPE ThreadStartTracking(void *data)
Start the Tracking Thread for the tools.
void SetCalibrationPath(std::string calibrationPath)
Sets the file where the calibration of the OptitrackTracker can be found.
#define OPTITRACK_ATTEMPTS
Maximum number of attempts for Initialization, Shutdown and CleanUp.
bool StartTracking() override
Start to Track the tools already defined. If no tools are defined for this tracker, it returns an error. Tools can be added using either AddToolByDescriptionFile or AddToolsByConfigurationFiles.
bool SetCameraParams(int exposure, int threshold, int intensity, int videoType=4)
Set the Cameras Exposure, Threshold and Intensity of IR LEDs. By Default it set the Video type to 4: ...
bool OpenConnection() override
Open the Connection with the Tracker. Calls LoadCalibration function and set the system up with the c...
#define MITK_WARN
Definition: mitkLogMacros.h:19
OptitrackTrackingDevice()
This function load a file with Tools definitions provided for the software.
An object of this class represents the a Tool tracked by Optitrack System. You can define the tool by...
Interface for all Tracking Devices.
static IGTTimeStamp * GetInstance()
returns a pointer to the current instance of mitkTimeStamp
TrackingTool * GetTool(unsigned int toolNumber) const override
Return the tool pointer of the tool number toolNumber.
void Start(itk::Object::Pointer device)
starts the time-acquisition
bool AddToolByDefinitionFile(std::string fileName)
Add a new tool using a text file which described the tool. The file must to have the next structure T...
Point< ScalarType, 3 > Point3D
Definition: mitkPoint.h:95
unsigned int GetToolCount() const override
Returns the number of defined tools.
#define mitkThrowException(classname)
void TrackTools()
Update each tool location in the list m_AllTools.
void Stop(itk::Object::Pointer device)
stops the time-acqusition
bool InitializeCameras()
Initialize the Optitrack System.