PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusSavedDataSource.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 #include "vtkImageData.h"
9 #include "vtkMatrix4x4.h"
10 #include "vtkIGSIOSequenceIO.h"
11 #include "vtkObjectFactory.h"
12 #include "vtkPlusBuffer.h"
13 #include "vtkPlusChannel.h"
14 #include "vtkPlusDataSource.h"
15 #include "vtkPlusSavedDataSource.h"
16 #include "vtkIGSIOTrackedFrameList.h"
17 #include "vtksys/SystemTools.hxx"
18 
20 
21 //----------------------------------------------------------------------------
23  : FrameBufferRowAlignment(1)
24  , SequenceFile(NULL)
25  , RepeatEnabled(false)
26  , LoopStartTime_Local(0.0)
27  , LoopStopTime_Local(0.0)
28  , LocalVideoBuffer(NULL)
29  , UseAllFrameFields(false)
30  , UseOriginalTimestamps(false)
31  , LastAddedFrameUid(0)
32  , LastAddedLoopIndex(0)
33  , SimulatedStream(VIDEO_STREAM)
34 {
35  // No callback function provided by the device, so the data capture thread will be used to poll the hardware and add new items to the buffer
36  this->StartThreadForInternalUpdates = true;
37  this->AcquisitionRate = 10;
38 }
39 
40 //----------------------------------------------------------------------------
42 {
43  if (this->Connected)
44  {
45  this->Disconnect();
46  }
48  this->SetSequenceFile(nullptr);
49 }
50 
51 //----------------------------------------------------------------------------
52 void vtkPlusSavedDataSource::PrintSelf(ostream& os, vtkIndent indent)
53 {
54  this->Superclass::PrintSelf(os, indent);
55 }
56 
57 //----------------------------------------------------------------------------
59 {
60  //LOG_TRACE("vtkPlusSavedDataSource::InternalUpdate");
61  const int numberOfFramesInTheLoop = this->LoopLastFrameUid - this->LoopFirstFrameUid + 1;
62 
63  // Determine the UID and loop index of the next frame that will be added
64  BufferItemUidType frameToBeAddedUid = this->LastAddedFrameUid + 1;
65  int frameToBeAddedLoopIndex = this->LastAddedLoopIndex;
66  if (frameToBeAddedUid > this->LoopLastFrameUid)
67  {
68  frameToBeAddedLoopIndex++;
69  frameToBeAddedUid -= numberOfFramesInTheLoop;
70  }
71 
72  PlusStatus status = PLUS_FAIL;
73  if (this->UseOriginalTimestamps)
74  {
75  status = InternalUpdateOriginalTimestamp(frameToBeAddedUid, frameToBeAddedLoopIndex);
76  }
77  else
78  {
79  status = InternalUpdateCurrentTimestamp(frameToBeAddedUid, frameToBeAddedLoopIndex);
80  }
81 
82  return status;
83 }
84 
85 //----------------------------------------------------------------------------
87 {
88  // Compute elapsed time since we started the acquisition
89  double elapsedTime = vtkIGSIOAccurateTimer::GetSystemTime() - this->GetOutputDataSource()->GetStartTime();
90  double loopTime = this->LoopStopTime_Local - this->LoopStartTime_Local;
91 
92  const int numberOfFramesInTheLoop = this->LoopLastFrameUid - this->LoopFirstFrameUid + 1;
93  int currentLoopIndex = 0; // how many loops have we completed so far?
94  BufferItemUidType currentFrameUid = 0; // uid of the frame that has been acquired most recently (uid of the last frame that has to be added in this update)
95  {
96  double currentFrameTime_Local = 0; // current time in the Local buffer time reference
97  if (!this->RepeatEnabled || loopTime == 0)
98  {
99  if (elapsedTime >= loopTime)
100  {
101  // reached the end of the loop, nothing to add
102  return PLUS_SUCCESS;
103  }
104  currentLoopIndex = 0;
105  currentFrameTime_Local = this->LoopStartTime_Local + elapsedTime;
106  }
107  else
108  {
109  currentLoopIndex = floor(elapsedTime / loopTime);
110  currentFrameTime_Local = this->LoopStartTime_Local + elapsedTime - loopTime * currentLoopIndex;
111  double latestTimestamp_Local = 0;
112  GetLocalBuffer()->GetLatestTimeStamp(latestTimestamp_Local);
113  if (currentFrameTime_Local > latestTimestamp_Local)
114  {
115  // hold the last frame after the end of the buffer
116  // (one frame period was added at the end of the buffer for displaying the last frame)
117  currentFrameTime_Local = latestTimestamp_Local;
118  }
119  }
120 
121  // Get the uid of the frame that has been most recently acquired
122  BufferItemUidType closestFrameUid = 0;
123  GetLocalBuffer()->GetItemUidFromTime(currentFrameTime_Local, closestFrameUid);
124  double closestFrameTime_Local = 0;
125  GetLocalBuffer()->GetTimeStamp(closestFrameUid, closestFrameTime_Local);
126  if (closestFrameTime_Local > currentFrameTime_Local)
127  {
128  // the closest frame is newer than the current time, so don't use this item but the one before
129  currentFrameUid = closestFrameUid - 1;
130  }
131  else
132  {
133  currentFrameUid = closestFrameUid;
134  }
135  if (currentFrameUid < this->LoopFirstFrameUid)
136  {
137  currentLoopIndex--;
138  currentFrameUid += numberOfFramesInTheLoop;
139  }
140  if (currentFrameUid > this->LoopLastFrameUid)
141  {
142  currentLoopIndex++;
143  currentFrameUid -= numberOfFramesInTheLoop;
144  }
145  }
146 
147  int numberOfFramesToBeAdded = (currentFrameUid - this->LastAddedFrameUid) +
148  (currentLoopIndex - this->LastAddedLoopIndex) * numberOfFramesInTheLoop;
149 
150  PlusStatus status(PLUS_SUCCESS);
151  for (int addedFrames = 0; addedFrames < numberOfFramesToBeAdded; addedFrames++)
152  {
153 
154  // The sampling rate is constant, so to have a constant frame rate we have to increase the FrameNumber by a constant.
155  // For simplicity, we increase it always by 1.
156  // TODO: use the UID difference as increment
157  this->FrameNumber++;
158 
159  StreamBufferItem dataBufferItemToBeAdded;
160  if (GetLocalBuffer()->GetStreamBufferItem(frameToBeAddedUid, &dataBufferItemToBeAdded) != ITEM_OK)
161  {
162  LOG_ERROR("vtkPlusSavedDataSource: Failed to retrieve item from the buffer, UID=" << frameToBeAddedUid);
163  status = PLUS_FAIL;
164  continue;
165  }
166 
167  // Compute the system time corresponding to this frame
168  // Get the filtered timestamp from the buffer without any local time offset. Offset will be applied when it is copied to the output stream's buffer.
169  double filteredTimestamp = dataBufferItemToBeAdded.GetFilteredTimestamp(0.0) + frameToBeAddedLoopIndex * loopTime -
170  this->LoopStartTime_Local + this->GetOutputDataSource()->GetStartTime();
171  double unfilteredTimestamp = filteredTimestamp; // we ignore unfiltered timestamps
172 
173  switch (this->SimulatedStream)
174  {
175  case VIDEO_STREAM:
176  {
177  igsioFieldMapType fieldMap;
178  if (this->UseAllFrameFields)
179  {
180  fieldMap = dataBufferItemToBeAdded.GetFrameFieldMap();
181  }
182  if (this->AddVideoItemToVideoSources(this->GetVideoSources(), dataBufferItemToBeAdded.GetFrame(), this->FrameNumber, unfilteredTimestamp, filteredTimestamp, &fieldMap) != PLUS_SUCCESS)
183  {
184  status = PLUS_FAIL;
185  }
186  break;
187  }
188  case TRACKER_STREAM:
189  {
190  // retrieve timestamp from the first active tool and add all the tool matrices corresponding to that timestamp
191  double nextFrameTimestamp = dataBufferItemToBeAdded.GetFilteredTimestamp(0.0);
192 
193  for (DataSourceContainerConstIterator it = this->GetToolIteratorBegin(); it != this->GetToolIteratorEnd(); ++it)
194  {
195  vtkPlusDataSource* tool = it->second;
196  StreamBufferItem bufferItem;
197  ItemStatus itemStatus = this->LocalTrackerBuffers[tool->GetId()]->GetStreamBufferItemFromTime(nextFrameTimestamp, &bufferItem, vtkPlusBuffer::INTERPOLATED);
198  if (itemStatus != ITEM_OK)
199  {
200  if (itemStatus == ITEM_NOT_AVAILABLE_YET)
201  {
202  LOG_ERROR("vtkPlusSavedDataSource: Unable to get next item from local buffer from time for tool " << tool->GetId() << " - frame not available yet!");
203  }
204  else if (itemStatus == ITEM_NOT_AVAILABLE_ANYMORE)
205  {
206  LOG_ERROR("vtkPlusSavedDataSource: Unable to get next item from local buffer from time for tool " << tool->GetId() << " - frame not available anymore!");
207  }
208  else
209  {
210  LOG_ERROR("vtkPlusSavedDataSource: Unable to get next item from local buffer from time for tool " << tool->GetId() << "!");
211  }
212  status = PLUS_FAIL;
213  continue;
214  }
215  // Get default transform
216  vtkSmartPointer<vtkMatrix4x4> toolTransMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
217  if (bufferItem.GetMatrix(toolTransMatrix) != PLUS_SUCCESS)
218  {
219  LOG_ERROR("Failed to get toolTransMatrix for tool " << tool->GetId());
220  status = PLUS_FAIL;
221  continue;
222  }
223  // Get flags
224  ToolStatus toolStatus = bufferItem.GetStatus();
225  // This device has no frame numbering, just auto increment tool frame number if new frame received
226  // send the transformation matrix and flags to the tool
227  if (this->ToolTimeStampedUpdateWithoutFiltering(tool->GetId(), toolTransMatrix, toolStatus, unfilteredTimestamp, filteredTimestamp) != PLUS_SUCCESS)
228  {
229  status = PLUS_FAIL;
230  }
231  }
232  }
233  break;
234  default:
235  LOG_ERROR("Unknown stream type: " << this->SimulatedStream);
236  return PLUS_FAIL;
237  }
238 
239  this->LastAddedFrameUid = frameToBeAddedUid;
240  this->LastAddedLoopIndex = frameToBeAddedLoopIndex;
241 
242  frameToBeAddedUid++;
243  if (frameToBeAddedUid > this->LoopLastFrameUid)
244  {
245  frameToBeAddedLoopIndex++;
246  frameToBeAddedUid -= numberOfFramesInTheLoop;
247  }
248  }
249 
250  this->Modified();
251  return status;
252 }
253 
254 //----------------------------------------------------------------------------
256 {
257  // Don't use the original timestamps, just replay with one frame at each update
258 
259  if (!this->RepeatEnabled && frameToBeAddedLoopIndex > 0)
260  {
261  // there is no repeat and we already played the loop once, so don't add any more frames
262  return PLUS_SUCCESS;
263  }
264 
265  this->FrameNumber++;
266  StreamBufferItem dataBufferItemToBeAdded;
267  if (GetLocalBuffer()->GetStreamBufferItem(frameToBeAddedUid, &dataBufferItemToBeAdded) != ITEM_OK)
268  {
269  LOG_ERROR("vtkPlusSavedDataSource: Failed to retrieve item from the buffer, UID=" << frameToBeAddedUid);
270  return PLUS_FAIL;
271  }
272 
273  PlusStatus status = PLUS_SUCCESS;
274  switch (this->SimulatedStream)
275  {
276  case VIDEO_STREAM:
277  {
278  igsioFieldMapType fieldMap;
279  if (this->UseAllFrameFields)
280  {
281  fieldMap = dataBufferItemToBeAdded.GetFrameFieldMap();
282  }
283  if (this->AddVideoItemToVideoSources(this->GetVideoSources(), dataBufferItemToBeAdded.GetFrame(), this->FrameNumber, UNDEFINED_TIMESTAMP, UNDEFINED_TIMESTAMP, &fieldMap) != PLUS_SUCCESS)
284  {
285  // UNDEFINED_TIMESTAMP => use current timestamp
286  status = PLUS_FAIL;
287  }
288  break;
289  }
290  case TRACKER_STREAM:
291  {
292  // retrieve timestamp from the first active tool and add all the tool matrices corresponding to that timestamp
293  double nextFrameTimestamp = dataBufferItemToBeAdded.GetTimestamp(0);
294 
295  for (DataSourceContainerConstIterator it = this->GetToolIteratorBegin(); it != this->GetToolIteratorEnd(); ++it)
296  {
297  vtkPlusDataSource* tool(it->second);
298  StreamBufferItem bufferItem;
299  vtkPlusBuffer* localTrackerBuffer = this->LocalTrackerBuffers[tool->GetId()];
300  ItemStatus itemStatus = ITEM_UNKNOWN_ERROR;
301  if (localTrackerBuffer)
302  {
303  itemStatus = localTrackerBuffer->GetStreamBufferItemFromTime(nextFrameTimestamp, &bufferItem, vtkPlusBuffer::INTERPOLATED);
304  }
305  if (itemStatus != ITEM_OK)
306  {
307  if (itemStatus == ITEM_NOT_AVAILABLE_YET)
308  {
309  LOG_ERROR("vtkPlusSavedDataSource: Unable to get next item from local buffer from time for tool " << tool->GetId() << " - frame not available yet!");
310  }
311  else if (itemStatus == ITEM_NOT_AVAILABLE_ANYMORE)
312  {
313  LOG_ERROR("vtkPlusSavedDataSource: Unable to get next item from local buffer from time for tool " << tool->GetId() << " - frame not available anymore!");
314  }
315  else
316  {
317  LOG_ERROR("vtkPlusSavedDataSource: Unable to get next item from local buffer from time for tool " << tool->GetId() << "!");
318  }
319  status = PLUS_FAIL;
320  continue;
321  }
322  // Get default transform
323  vtkSmartPointer<vtkMatrix4x4> toolTransMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
324  if (bufferItem.GetMatrix(toolTransMatrix) != PLUS_SUCCESS)
325  {
326  LOG_ERROR("Failed to get toolTransMatrix for tool " << tool->GetId());
327  status = PLUS_FAIL;
328  continue;
329  }
330  // Get flags
331  ToolStatus toolStatus = bufferItem.GetStatus();
332  // This device has no frame numbering, just auto increment tool frame number if new frame received
333  unsigned long frameNumber = tool->GetFrameNumber() + 1 ;
334  // send the transformation matrix and flags to the tool
335  if (this->ToolTimeStampedUpdate(tool->GetId(), toolTransMatrix, toolStatus, frameNumber, UNDEFINED_TIMESTAMP) != PLUS_SUCCESS)
336  {
337  status = PLUS_FAIL;
338  }
339  }
340  }
341  break;
342  default:
343  LOG_ERROR("Unknown stream type: " << this->SimulatedStream);
344  return PLUS_FAIL;
345  }
346 
347  this->LastAddedFrameUid = frameToBeAddedUid;
348  this->LastAddedLoopIndex = frameToBeAddedLoopIndex;
349 
350  return status;
351 }
352 
353 //----------------------------------------------------------------------------
355 {
356  LOG_TRACE("vtkPlusSavedDataSource::Probe");
357  if (!vtksys::SystemTools::FileExists(this->GetSequenceFile(), true))
358  {
359  LOG_ERROR("vtkPlusSavedDataSource Probe failed: Unable to find sequence file!");
360  return PLUS_FAIL;
361  }
362  return PLUS_SUCCESS;
363 }
364 
365 //----------------------------------------------------------------------------
367 {
368  LOG_TRACE("vtkPlusSavedDataSource::InternalConnect");
369 
370  if (this->SequenceFile == NULL)
371  {
372  LOG_ERROR("Unable to connect to saved data video source: Unable to read sequence metafile. No filename is specified.");
373  return PLUS_FAIL;
374  }
375  std::string foundAbsoluteImagePath;
376  vtkPlusConfig::GetInstance()->FindImagePath(this->SequenceFile, foundAbsoluteImagePath);
377  if (!vtksys::SystemTools::FileExists(foundAbsoluteImagePath, true))
378  {
379  LOG_ERROR("Unable to connect to saved data video source: Unable to read sequence metafile: " << this->SequenceFile);
380  return PLUS_FAIL;
381  }
382 
383  vtkSmartPointer<vtkIGSIOTrackedFrameList> savedDataBuffer = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
384 
385  // Read sequence file into tracked frame list
386  vtkIGSIOSequenceIO::Read(foundAbsoluteImagePath, savedDataBuffer);
387 
388  if (savedDataBuffer->GetNumberOfTrackedFrames() < 1)
389  {
390  LOG_ERROR("Failed to connect to saved dataset - there is no frame in the sequence metafile!");
391  return PLUS_FAIL;
392  }
393 
394  PlusStatus status = PLUS_FAIL;
395  switch (this->SimulatedStream)
396  {
397  case VIDEO_STREAM:
398  status = InternalConnectVideo(savedDataBuffer);
399  break;
400  case TRACKER_STREAM:
401  status = InternalConnectTracker(savedDataBuffer);
402  break;
403  default:
404  LOG_ERROR("Unknown stream type: " << this->SimulatedStream);
405  }
406 
407  if (status != PLUS_SUCCESS)
408  {
409  return PLUS_FAIL;
410  }
411 
412  if (GetLocalBuffer() == NULL)
413  {
414  LOG_ERROR("Local buffer is invalid");
415  return PLUS_FAIL;
416  }
417 
418  double oldestTimestamp_Local = 0;
419  GetLocalBuffer()->GetOldestTimeStamp(oldestTimestamp_Local);
420  double latestTimestamp_Local = 0;
421  GetLocalBuffer()->GetLatestTimeStamp(latestTimestamp_Local);
422 
423  // Set the default loop start time and length to match the video buffer start time and length
424 
427 
428  this->LoopStartTime_Local = oldestTimestamp_Local;
429 
430  // When we reach the last frame we have to wait one frame period before
431  // playing the first frame, so we have to add one frame period to the loop length (loopTime)
432  double framePeriodSec = 0;
433  double frameRate = GetLocalBuffer()->GetFrameRate();
434  if (frameRate != 0.0)
435  {
436  framePeriodSec = 1.0 / frameRate;
437  }
438  else
439  {
440  // There is probably only one frame in the buffer, so use the AcquisitionRate
441  // (instead of trying to find out the frame period from the frame rate in the file)
442  if (this->AcquisitionRate != 0.0)
443  {
444  framePeriodSec = 1.0 / this->AcquisitionRate;
445  }
446  else
447  {
448  LOG_ERROR("Invalid AcquisitionRate: " << this->AcquisitionRate);
449  framePeriodSec = 1.0;
450  }
451  }
452  this->LoopStopTime_Local = latestTimestamp_Local + framePeriodSec;
453 
454  this->LastAddedFrameUid = this->LoopFirstFrameUid - 1;
455  this->LastAddedLoopIndex = 0;
456 
457  return PLUS_SUCCESS;
458 }
459 
460 //----------------------------------------------------------------------------
461 PlusStatus vtkPlusSavedDataSource::InternalConnectVideo(vtkIGSIOTrackedFrameList* savedDataBuffer)
462 {
463  // Set buffer parameters based on the input tracked frame list
464  vtkPlusDataSource* outputDataSource = this->GetOutputDataSource();
465  if (outputDataSource == NULL)
466  {
467  return PLUS_FAIL;
468  }
469  if (outputDataSource->SetImageType(savedDataBuffer->GetImageType()) != PLUS_SUCCESS)
470  {
471  LOG_ERROR("Failed to set video buffer image type");
472  return PLUS_FAIL;
473  }
474 
475  // Saved data buffer contains data read directly from file, set up a new local buffer
478  this->LocalVideoBuffer->SetImageOrientation(savedDataBuffer->GetImageOrientation());
479  this->LocalVideoBuffer->SetImageType(savedDataBuffer->GetImageType());
480  FrameSizeType frameSize;
481  if (savedDataBuffer->GetFrameSize(frameSize) != PLUS_SUCCESS)
482  {
483  LOG_ERROR("Unable to retrieve frame size.");
484  return PLUS_FAIL;
485  }
486  if (!savedDataBuffer->GetTrackedFrame(0)->GetImageData()->IsFrameEncoded())
487  {
488  this->LocalVideoBuffer->SetFrameSize(frameSize);
489  }
490  unsigned int numberOfScalarComponents;
491  if (savedDataBuffer->GetTrackedFrame(0)->GetNumberOfScalarComponents(numberOfScalarComponents) != PLUS_SUCCESS)
492  {
493  LOG_ERROR("Unable to retrieve number of scalar components.");
494  return PLUS_FAIL;
495  }
496  this->LocalVideoBuffer->SetNumberOfScalarComponents(numberOfScalarComponents);
497  if (!savedDataBuffer->GetTrackedFrame(0)->GetImageData()->IsFrameEncoded())
498  {
499  this->LocalVideoBuffer->SetPixelType(savedDataBuffer->GetTrackedFrame(0)->GetImageData()->GetVTKScalarPixelType());
500  }
501  this->LocalVideoBuffer->SetBufferSize(savedDataBuffer->GetNumberOfTrackedFrames());
502  this->LocalVideoBuffer->SetLocalTimeOffsetSec(0.0); // the time offset is copied from the output, so reset it to 0
504  savedDataBuffer->Clear();
505 
506  PlusStatus result(PLUS_SUCCESS);
507  for (DataSourceContainerIterator it = this->VideoSources.begin(); it != this->VideoSources.end(); ++it)
508  {
509  vtkPlusDataSource* source(it->second);
510 
511  if (source->SetInputImageOrientation(this->LocalVideoBuffer->GetImageOrientation()) != PLUS_SUCCESS)
512  {
513  LOG_ERROR(source->GetId() << ": Failed to set video image orientation");
514  result = PLUS_FAIL;
515  continue;
516  }
517 
518  if (source->SetInputFrameSize(this->LocalVideoBuffer->GetFrameSize()) != PLUS_SUCCESS)
519  {
520  LOG_ERROR(source->GetId() << ": Failed to set video image orientation");
521  result = PLUS_FAIL;
522  continue;
523  }
524 
525  if (source->SetNumberOfScalarComponents(this->LocalVideoBuffer->GetNumberOfScalarComponents()) != PLUS_SUCCESS)
526  {
527  LOG_ERROR(source->GetId() << ": Failed to set video image orientation");
528  result = PLUS_FAIL;
529  continue;
530  }
531 
532  source->Clear();
533 
534  if (source->SetInputFrameSize(this->LocalVideoBuffer->GetFrameSize()) != PLUS_SUCCESS)
535  {
536  LOG_ERROR(source->GetId() << ": Failed to set video image orientation");
537  result = PLUS_FAIL;
538  continue;
539  }
540 
541  if (source->SetPixelType(this->LocalVideoBuffer->GetPixelType()) != PLUS_SUCCESS)
542  {
543  LOG_ERROR(source->GetId() << ": Failed to set video image orientation");
544  result = PLUS_FAIL;
545  continue;
546  }
547  }
548 
549  return result;
550 }
551 
552 //----------------------------------------------------------------------------
553 PlusStatus vtkPlusSavedDataSource::InternalConnectTracker(vtkIGSIOTrackedFrameList* savedDataBuffer)
554 {
555  igsioTrackedFrame* frame = savedDataBuffer->GetTrackedFrame(0);
556  if (frame == NULL)
557  {
558  LOG_ERROR("The tracked frame buffer doesn't seem to contain any frames");
559  return PLUS_FAIL;
560  }
561 
562  // Clear local buffers before connect
563  this->DeleteLocalBuffers();
564 
565  // Enable tools that have a matching transform name in the savedDataBuffer
566  double transformMatrix[16] = {0};
567  for (DataSourceContainerConstIterator it = this->GetToolIteratorBegin(); it != this->GetToolIteratorEnd(); ++it)
568  {
569  vtkPlusDataSource* tool = it->second;
570  if (tool->GetId().empty())
571  {
572  // no tool name is available, don't connect it to any transform in the savedDataBuffer
573  continue;
574  }
575 
576  igsioTransformName toolTransformName(tool->GetId());
577  if (!frame->IsFrameTransformNameDefined(toolTransformName))
578  {
579  std::string strTransformName;
580  toolTransformName.GetTransformName(strTransformName);
581  LOG_WARNING("Tool '" << tool->GetId() << "' has no matching transform in the file with name: " << strTransformName);
582  continue;
583  }
584 
585  if (frame->GetFrameTransform(toolTransformName, transformMatrix) != PLUS_SUCCESS)
586  {
587  LOG_WARNING("Cannot convert the frame field ( for tool " << tool->GetId() << ") to a transform");
588  continue;
589  }
590  // a transform with the same name as the tool name has been found in the savedDataBuffer
591  tool->SetBufferSize(savedDataBuffer->GetNumberOfTrackedFrames());
592 
593  vtkSmartPointer<vtkPlusBuffer> buffer = vtkSmartPointer<vtkPlusBuffer>::New();
594  tool->DeepCopyBufferTo(*buffer);
595  // Copy all the settings from the default tool buffer
596  buffer->SetLocalTimeOffsetSec(0.0); // the time offset is copied from the output, so reset it to 0
597  if (buffer->CopyTransformFromTrackedFrameList(savedDataBuffer, vtkPlusBuffer::READ_FILTERED_IGNORE_UNFILTERED_TIMESTAMPS, toolTransformName) != PLUS_SUCCESS)
598  {
599  LOG_ERROR("Failed to retrieve tracking data from tracked frame list for tool " << tool->GetId());
600  return PLUS_FAIL;
601  }
602 
603  buffer->Register(this);
604  this->LocalTrackerBuffers[tool->GetId()] = buffer;
605  }
606 
607  savedDataBuffer->Clear();
608 
609  ClearAllBuffers();
610 
611  return PLUS_SUCCESS;
612 }
613 
614 //----------------------------------------------------------------------------
616 {
618  return PLUS_SUCCESS;
619 }
620 
621 //-----------------------------------------------------------------------------
622 PlusStatus vtkPlusSavedDataSource::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
623 {
624  LOG_TRACE("vtkPlusSavedDataSource::ReadConfiguration");
625  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
626 
627  // SequenceMetafile attribute is deprecated and kept for backward compatibility only.
628  // SequenceFile attribute should be used instead.
629  if (deviceConfig->GetAttribute("SequenceMetafile"))
630  {
631  if (deviceConfig->GetAttribute("SequenceFile"))
632  {
633  LOG_WARNING("SavedDataSource SequenceMetafile and SequenceFile attributes are specified. Please remove the deprecated SequenceMetaFile attribute.");
634  XML_READ_CSTRING_ATTRIBUTE_REQUIRED(SequenceFile, deviceConfig);
635  }
636  else
637  {
638  LOG_WARNING("Deprecated SequenceMetafile attribute is defined for SavedDataSource device. Please rename the SequenceMetafile attribute to SequenceFile.");
639  SetSequenceFile(deviceConfig->GetAttribute("SequenceMetafile"));
640  }
641  }
642  else
643  {
644  // Nominal case. The other branch should be removed if support for SequenceMetafile attribute is completely removed.
645  XML_READ_CSTRING_ATTRIBUTE_REQUIRED(SequenceFile, deviceConfig);
646  }
647 
648  if (this->SequenceFile == NULL)
649  {
650  LOG_ERROR("Sequence file attribute not read correctly. Check log.");
651  return PLUS_FAIL;
652  }
653 
654  std::string foundAbsoluteImagePath;
655  if (vtkPlusConfig::GetInstance()->FindImagePath(this->SequenceFile, foundAbsoluteImagePath) == PLUS_FAIL)
656  {
657  std::string sequenceFileStr(this->SequenceFile);
658  std::string seqFileTrim = igsioCommon::Trim(sequenceFileStr);
659  std::string foundAbsoluteImagePath;
660  if (vtkPlusConfig::GetInstance()->FindImagePath(seqFileTrim, foundAbsoluteImagePath) == PLUS_SUCCESS)
661  {
662  this->SetSequenceFile(seqFileTrim.c_str());
663  LOG_WARNING("Filename contains unexpected characters at beginning or end of string. Please correct. Filename: " << this->SequenceFile);
664  }
665  else
666  {
667  LOG_ERROR("Unable to locate file: " << this->SequenceFile << ". Please verify location on disk.");
668  return PLUS_FAIL;
669  }
670  }
671 
672  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(RepeatEnabled, deviceConfig);
673  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(UseOriginalTimestamps, deviceConfig);
674 
675  const char* useData = deviceConfig->GetAttribute("UseData");
676  if (useData != NULL)
677  {
678  if (STRCASECMP("IMAGE", useData) == 0)
679  {
680  this->UseAllFrameFields = false;
682  }
683  else if (STRCASECMP("IMAGE_AND_TRANSFORM", useData) == 0)
684  {
685  this->UseAllFrameFields = true;
687  }
688  else if (STRCASECMP("TRANSFORM", useData) == 0)
689  {
690  this->UseAllFrameFields = true;
692  }
693  else
694  {
695  LOG_WARNING("Unable to recognize UseData attribute: " << useData << " - changed to IMAGE by default!");
696  this->UseAllFrameFields = false;
697  }
698  }
699 
700  return PLUS_SUCCESS;
701 }
702 
703 //-----------------------------------------------------------------------------
705 {
706  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(imageAcquisitionConfig, rootConfig);
707 
708  XML_WRITE_CSTRING_ATTRIBUTE_IF_NOT_NULL(SequenceFile, imageAcquisitionConfig);
709  XML_WRITE_BOOL_ATTRIBUTE(RepeatEnabled, imageAcquisitionConfig);
710  XML_WRITE_BOOL_ATTRIBUTE(UseOriginalTimestamps, imageAcquisitionConfig);
711 
712  if (this->UseAllFrameFields)
713  {
714  if (this->SimulatedStream == VIDEO_STREAM)
715  {
716  imageAcquisitionConfig->SetAttribute("UseData", "IMAGE_AND_TRANSFORM");
717  }
718  else if (this->SimulatedStream == TRACKER_STREAM)
719  {
720  imageAcquisitionConfig->SetAttribute("UseData", "TRANSFORM");
721  }
722  }
723  else
724  {
725  imageAcquisitionConfig->SetAttribute("UseData", "IMAGE");
726  }
727 
728  return PLUS_SUCCESS;
729 }
730 
731 //-----------------------------------------------------------------------------
733 {
734  if (this->OutputChannels.empty())
735  {
736  LOG_ERROR("No output channels defined for vtkPlusSavedDataSource. Cannot proceed.");
737  this->SetCorrectlyConfigured(false);
738  return PLUS_FAIL;
739  }
740 
741  switch (this->SimulatedStream)
742  {
743  case VIDEO_STREAM:
744  if (this->GetOutputDataSource() == NULL)
745  {
746  LOG_ERROR("Buffer not created for vtkPlusSavedDataSource but it is required. Check configuration.");
747  this->SetCorrectlyConfigured(false);
748  return PLUS_FAIL;
749  }
750  break;
751  case TRACKER_STREAM:
752  // nothing to check for
753  break;
754  default:
755  LOG_ERROR("Unknown stream type: " << this->SimulatedStream);
756  this->SetCorrectlyConfigured(false);
757  return PLUS_FAIL;
758  }
759  return PLUS_SUCCESS;
760 }
761 
762 //-----------------------------------------------------------------------------
763 void vtkPlusSavedDataSource::GetLoopTimeRange(double& loopStartTime, double& loopStopTime)
764 {
765  loopStartTime = this->LoopStartTime_Local;
766  loopStopTime = this->LoopStopTime_Local;
767 }
768 
769 //-----------------------------------------------------------------------------
770 void vtkPlusSavedDataSource::SetLoopTimeRange(double loopStartTime, double loopStopTime)
771 {
772  if (!this->GetLocalBuffer())
773  {
774  LOG_ERROR("vtkPlusSavedDataSource::SetLoopTimeRange: Invalid local buffer");
775  return;
776  }
777 
778  this->LoopStartTime_Local = loopStartTime;
779  this->LoopStopTime_Local = loopStopTime;
780 
783 
784  this->LastAddedFrameUid = this->LoopFirstFrameUid - 1;
785  this->LastAddedLoopIndex = 0;
786 }
787 
788 //----------------------------------------------------------------------------
789 BufferItemUidType vtkPlusSavedDataSource::GetClosestFrameUidWithinTimeRange(double time_Local, double startTime_Local, double stopTime_Local)
790 {
791  if (!this->GetLocalBuffer())
792  {
793  LOG_ERROR("vtkPlusSavedDataSource::GetClosestFrameUidWithinTimeRange: Invalid local buffer");
794  return 0;
795  }
796 
797  // time_Local should be within the specified interval
798  if (time_Local < startTime_Local)
799  {
800  time_Local = startTime_Local;
801  }
802  else if (time_Local > stopTime_Local)
803  {
804  time_Local = stopTime_Local;
805  }
806  // time_Local should be also within the local buffer time range
807  double oldestTimestamp_Local = 0;
808  this->GetLocalBuffer()->GetOldestTimeStamp(oldestTimestamp_Local);
809  double latestTimestamp_Local = 0;
810  this->GetLocalBuffer()->GetLatestTimeStamp(latestTimestamp_Local);
811 
812  // if the asked time is outside of the loop range then return the closest element in the range
813  if (time_Local < oldestTimestamp_Local)
814  {
815  time_Local = oldestTimestamp_Local;
816  }
817  else if (time_Local > latestTimestamp_Local)
818  {
819  time_Local = latestTimestamp_Local;
820  }
821 
822  // Get the uid of the frame that has been most recently acquired
823  BufferItemUidType closestFrameUid = 0;
824  this->GetLocalBuffer()->GetItemUidFromTime(time_Local, closestFrameUid);
825  double closestFrameTime_Local = 0;
826  this->GetLocalBuffer()->GetTimeStamp(closestFrameUid, closestFrameTime_Local);
827 
828  // The closest frame is at the boundary, but it may be just outside the range:
829  // use the next/previous frame if the closest frame is on the wrong side of the boundary
830  if (closestFrameTime_Local < startTime_Local)
831  {
832  return closestFrameUid + 1;
833  }
834  else if (closestFrameTime_Local > stopTime_Local)
835  {
836  return closestFrameUid - 1;
837  }
838  else
839  {
840  // the found closest frame is already within the specified range
841  return closestFrameUid;
842  }
843 }
844 
845 //----------------------------------------------------------------------------
847 {
848  // Get the first tool - the first active tool determines the timestamp
849  vtkPlusDataSource* firstActiveTool = NULL;
850  if (this->GetFirstActiveTool(firstActiveTool) != PLUS_SUCCESS)
851  {
852  LOG_ERROR("Failed to get local tracker buffer - there is no active tool!");
853  return NULL;
854  }
855  return this->LocalTrackerBuffers[firstActiveTool->GetId()];
856 }
857 
858 //----------------------------------------------------------------------------
860 {
861  if (this->LocalVideoBuffer != NULL)
862  {
863  this->LocalVideoBuffer->Delete();
864  this->LocalVideoBuffer = NULL;
865  }
866 
867  for (std::map<std::string, vtkPlusBuffer*>::iterator it = this->LocalTrackerBuffers.begin(); it != this->LocalTrackerBuffers.end(); ++it)
868  {
869  if ((*it).second != NULL)
870  {
871  (*it).second->Delete();
872  (*it).second = NULL;
873  }
874  }
875 
876  this->LocalTrackerBuffers.clear();
877 }
878 
879 //----------------------------------------------------------------------------
881 {
882  vtkPlusBuffer* buff = NULL;
883  switch (this->SimulatedStream)
884  {
885  case VIDEO_STREAM:
886  buff = LocalVideoBuffer;
887  break;
888  case TRACKER_STREAM:
889  buff = GetLocalTrackerBuffer();
890  break;
891  default:
892  LOG_ERROR("Unknown stream type: " << this->SimulatedStream);
893  }
894  if (buff == NULL)
895  {
896  LOG_WARNING("vtkPlusSavedDataSource LocalBuffer is invalid");
897  }
898  return buff;
899 }
900 
901 //----------------------------------------------------------------------------
903 {
904  vtkPlusDataSource* aSource(NULL);
905 
906  if (this->OutputChannels.empty())
907  {
908  LOG_ERROR("No output channels defined");
909  return NULL;
910  }
911  vtkPlusChannel* outputChannel = this->OutputChannels[0];
912 
913  switch (this->SimulatedStream)
914  {
915  case VIDEO_STREAM:
916  {
917  if (outputChannel->GetVideoSource(aSource) != PLUS_SUCCESS)
918  {
919  LOG_ERROR("Unable to retrieve the video source in the SavedDataSource device.");
920  return NULL;
921  }
922  break;
923  }
924  case TRACKER_STREAM:
925  {
926  if (this->GetFirstActiveTool(aSource) != PLUS_SUCCESS)
927  {
928  LOG_ERROR("Failed to get local tracker buffer - there is no active tool!");
929  return NULL;
930  }
931  }
932  break;
933  default:
934  LOG_ERROR("Unknown stream type: " << this->SimulatedStream);
935  }
936  if (aSource == NULL)
937  {
938  LOG_WARNING("vtkPlusSavedDataSource OutputBuffer is invalid");
939  }
940  return aSource;
941 }
942 
943 //----------------------------------------------------------------------------
945 {
946  if (this->Tools.size() > 0)
947  {
948  return true;
949  }
950 
951  for (DataSourceContainerConstIterator it = this->VideoSources.begin(); it != this->VideoSources.end(); ++it)
952  {
953  vtkPlusDataSource* aSource = it->second;
954  StreamBufferItem item;
955  if (aSource->GetNumberOfItems() > 0 && aSource->GetOldestStreamBufferItem(&item) == ITEM_OK)
956  {
957  if (item.HasValidTransformData())
958  {
959  return true;
960  }
961  }
962  }
963 
964  return false;
965 }
DataSourceContainer::const_iterator DataSourceContainerConstIterator
virtual PlusStatus SetBufferSize(int n)
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
ToolStatus GetStatus() const
virtual PlusStatus InternalConnectTracker(vtkIGSIOTrackedFrameList *savedDataBuffer)
PlusStatus SetImageType(US_IMAGE_TYPE imageType)
PlusStatus InternalUpdateCurrentTimestamp(BufferItemUidType frameToBeAddedUid, int frameToBeAddedLoopIndex)
std::string GetTransformName() const
const char * source
Definition: phidget22.h:2461
virtual PlusStatus NotifyConfigured()
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
virtual PlusStatus ToolTimeStampedUpdateWithoutFiltering(const std::string &aToolSourceId, vtkMatrix4x4 *matrix, ToolStatus status, double unfilteredtimestamp, double filteredtimestamp, const igsioFieldMapType *customFields=NULL)
virtual PlusStatus InternalConnect()
static vtkPlusBuffer * New()
igsioStatus PlusStatus
Definition: PlusCommon.h:40
virtual PlusStatus ToolTimeStampedUpdate(const std::string &aToolSourceId, vtkMatrix4x4 *matrix, ToolStatus status, unsigned long frameNumber, double unfilteredtimestamp, const igsioFieldMapType *customFields=NULL)
std::vector< vtkPlusDataSource * > GetVideoSources() const
PlusStatus InternalUpdateOriginalTimestamp(BufferItemUidType frameToBeAddedUid, int frameToBeAddedLoopIndex)
PlusStatus SetImageOrientation(US_IMAGE_ORIENTATION imageOrientation)
void SetLoopTimeRange(double loopStartTime, double loopStopTime)
DataSourceContainer VideoSources
PlusStatus SetImageType(US_IMAGE_TYPE imageType)
double AcquisitionRate
virtual ItemStatus GetItemUidFromTime(double time, BufferItemUidType &uid)
#define PLUS_FAIL
Definition: PlusCommon.h:43
BufferItemUidType LoopLastFrameUid
DataSourceContainer Tools
static vtkPlusConfig * GetInstance()
virtual PlusStatus SetBufferSize(int n)
igsioFieldMapType GetFrameFieldMap()
virtual BufferItemUidType GetLatestItemUidInBuffer()
double GetFilteredTimestamp(double localTimeOffsetSec)
virtual double GetStartTime()
virtual ItemStatus GetOldestTimeStamp(double &oldestTimestamp)
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
BufferItemUidType LoopFirstFrameUid
virtual PlusStatus Disconnect()
virtual void SetCorrectlyConfigured(bool)
PlusStatus GetFirstActiveTool(vtkPlusDataSource *&aTool) const
unsigned long FrameNumber
PlusStatus FindImagePath(const std::string &aImagePath, std::string &aFoundAbsolutePath)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
virtual bool IsTracker() const
virtual void SetLocalTimeOffsetSec(double offsetSec)
vtkPlusBuffer * GetLocalTrackerBuffer()
std::map< std::string, vtkPlusBuffer * > LocalTrackerBuffers
virtual PlusStatus DeepCopyBufferTo(vtkPlusBuffer &bufferToFill)
void GetLoopTimeRange(double &loopStartTime, double &loopStopTime)
virtual double GetFrameRate(bool ideal=false, double *framePeriodStdevSecPtr=NULL)
virtual ItemStatus GetOldestStreamBufferItem(StreamBufferItem *bufferItem)
virtual ItemStatus GetStreamBufferItemFromTime(double time, StreamBufferItem *bufferItem, DataItemTemporalInterpolationType interpolation)
PlusStatus GetMatrix(vtkMatrix4x4 *outputMatrix)
PlusStatus SetFrameSize(unsigned int x, unsigned int y, unsigned int z, bool allocateFrames=true)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
void PrintSelf(ostream &os, vtkIndent indent)
DataSourceContainer::iterator DataSourceContainerIterator
igsioVideoFrame & GetFrame()
virtual ItemStatus GetTimeStamp(BufferItemUidType uid, double &timestamp)
SimulatedStreamType SimulatedStream
virtual void SetSequenceFile(const char *)
bool StartThreadForInternalUpdates
Class for providing VTK video input interface from sequence fileAttributes:
DataSourceContainerConstIterator GetToolIteratorBegin() const
BufferItemUidType LastAddedFrameUid
vtkPlusDataSource * GetOutputDataSource()
virtual PlusStatus InternalDisconnect()
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
ChannelContainer OutputChannels
virtual PlusStatus AddVideoItemToVideoSources(const std::vector< vtkPlusDataSource * > &videoSources, const igsioVideoFrame &frame, long frameNumber, double unfilteredTimestamp=UNDEFINED_TIMESTAMP, double filteredTimestamp=UNDEFINED_TIMESTAMP, const igsioFieldMapType *customFields=NULL)
virtual ItemStatus GetLatestTimeStamp(double &latestTimestamp)
PlusStatus CopyImagesFromTrackedFrameList(vtkIGSIOTrackedFrameList *sourceTrackedFrameList, TIMESTAMP_FILTERING_OPTION timestampFiltering, bool copyFrameFields)
virtual BufferItemUidType GetOldestItemUidInBuffer()
PlusStatus GetVideoSource(vtkPlusDataSource *&aVideoSource) const
vtkStandardNewMacro(vtkPlusSavedDataSource)
unsigned long long BufferItemUidType
virtual PlusStatus InternalConnectVideo(vtkIGSIOTrackedFrameList *savedDataBuffer)
DataSourceContainerConstIterator GetToolIteratorEnd() const
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
virtual char * GetSequenceFile()
bool HasValidTransformData() const
virtual int GetNumberOfItems()
double GetTimestamp(double localTimeOffsetSec)
BufferItemUidType GetClosestFrameUidWithinTimeRange(double time_Local, double startTime_Local, double stopTime_Local)
Interface to a 3D positioning tool, video source, or generalized data stream.