PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusOpenIGTLinkVideoSource.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 // Plus includes
8 #include "PlusConfigure.h"
9 #include "vtkPlusChannel.h"
10 #include "vtkPlusDataSource.h"
13 
14 // OpenIGTLink includes
15 #include <igtlImageMessage.h>
16 
17 // VTK includes
18 #include <vtkImageData.h>
19 #include <vtkObjectFactory.h>
20 
22 
23 //----------------------------------------------------------------------------
25 {
27 }
28 
29 //----------------------------------------------------------------------------
31 {
32 }
33 
34 //----------------------------------------------------------------------------
35 void vtkPlusOpenIGTLinkVideoSource::PrintSelf(ostream& os, vtkIndent indent)
36 {
37  this->Superclass::PrintSelf(os, indent);
38 }
39 
40 //----------------------------------------------------------------------------
42 {
43  LOG_TRACE("vtkPlusOpenIGTLinkVideoSource::InternalUpdate");
44  if (!this->IsRecording() || !this->GetConnected())
45  {
46  // drop the frame, we are not recording data now
47  return PLUS_SUCCESS;
48  }
49 
50  igtl::MessageHeader::Pointer headerMsg;
51  if (ReceiveMessageHeader(headerMsg) == PLUS_FAIL)
52  {
53  if (!this->IsRecording() || !this->GetConnected())
54  {
55  // Disconnect while waiting for message, exit gracefully
56  return PLUS_SUCCESS;
57  }
59  return PLUS_FAIL;
60  }
61 
62  if (headerMsg == nullptr)
63  {
64  // Not a problem, just no messages received this timeout period
65  return PLUS_SUCCESS;
66  }
67 
68  // We've received valid header data
69  headerMsg->Unpack(this->IgtlMessageCrcCheckEnabled);
70 
71  // Set unfiltered and filtered timestamp by converting UTC to system timestamp
72  double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
73 
74  igsioTrackedFrame trackedFrame;
75  igtl::MessageBase::Pointer bodyMsg = this->MessageFactory->CreateReceiveMessage(headerMsg);
76 
77  if (typeid(*bodyMsg) == typeid(igtl::ImageMessage))
78  {
80  {
81  LOG_ERROR("Couldn't get image from OpenIGTLink server!");
82  return PLUS_FAIL;
83  }
84  }
85  else if (typeid(*bodyMsg) == typeid(igtl::PlusTrackedFrameMessage))
86  {
88  {
89  LOG_ERROR("Couldn't get tracked frame from OpenIGTLink server!");
90  return PLUS_FAIL;
91  }
92  double unfilteredTimestampUtc = trackedFrame.GetTimestamp();
93  if (this->UseReceivedTimestamps)
94  {
95  // Use the timestamp in the OpenIGTLink message
96  // The received timestamp is in UTC and timestamps in the buffer are in system time, so conversion is needed
97  unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTimeFromUniversalTime(unfilteredTimestampUtc);
98  }
99  }
100  else
101  {
102  // if the data type is unknown, skip reading.
103  igsioLockGuard<vtkIGSIORecursiveCriticalSection> socketGuard(this->SocketMutex);
104  this->ClientSocket->Skip(headerMsg->GetBodySizeToRead(), 0);
105  return PLUS_SUCCESS;
106  }
107 
108  // No need to filter already filtered timestamped items received over OpenIGTLink
109  // If the original timestamps are not used it's still safer not to use filtering, as filtering assumes uniform frame rate, which is not guaranteed
110  double filteredTimestamp = unfilteredTimestamp;
111 
112  // The timestamps are already defined, so we don't need to filter them,
113  // for simplicity, we increase frame number always by 1.
114  this->FrameNumber++;
115 
116  vtkPlusDataSource* aSource = NULL;
117  if (this->GetFirstActiveOutputVideoSource(aSource) != PLUS_SUCCESS)
118  {
119  LOG_ERROR("Unable to retrieve the video source in the OpenIGTLinkVideo device.");
120  return PLUS_FAIL;
121  }
122 
123  // If the buffer is empty, set the pixel type and frame size to the first received properties
124  if (aSource->GetNumberOfItems() == 0)
125  {
126  igsioVideoFrame* videoFrame = trackedFrame.GetImageData();
127  if (videoFrame == NULL)
128  {
129  LOG_ERROR("Invalid video frame received, cannot use it to initialize the video buffer");
130  return PLUS_FAIL;
131  }
132  aSource->SetPixelType(videoFrame->GetVTKScalarPixelType());
133  unsigned int numberOfScalarComponents(1);
134  if (videoFrame->GetNumberOfScalarComponents(numberOfScalarComponents) != PLUS_SUCCESS)
135  {
136  LOG_ERROR("Unable to retrieve number of scalar components.");
137  return PLUS_FAIL;
138  }
139  aSource->SetNumberOfScalarComponents(numberOfScalarComponents);
140  aSource->SetImageType(videoFrame->GetImageType());
141  aSource->SetInputFrameSize(trackedFrame.GetFrameSize());
142  }
143  igsioFieldMapType customFields = trackedFrame.GetCustomFields();
144  PlusStatus status = aSource->AddItem(trackedFrame.GetImageData(), this->FrameNumber, unfilteredTimestamp, filteredTimestamp, &customFields);
145  this->Modified();
146 
147  return status;
148 }
149 
150 //-----------------------------------------------------------------------------
152 {
153  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
154  XML_READ_STRING_ATTRIBUTE_OPTIONAL(ImageMessageEmbeddedTransformName, deviceConfig);
155  return PLUS_SUCCESS;
156 }
157 
158 //----------------------------------------------------------------------------
160 {
161  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
162  deviceConfig->SetAttribute("ImageMessageEmbeddedTransformName", this->ImageMessageEmbeddedTransformName.GetTransformName().c_str());
163  return PLUS_SUCCESS;
164 }
165 
166 //----------------------------------------------------------------------------
168 {
169  if (this->OutputChannels.size() > 1)
170  {
171  LOG_WARNING("vtkPlusOpenIGTLinkVideoSource is expecting one output channel and there are " << this->OutputChannels.size() << " channels. First output channel will be used.");
172  return PLUS_FAIL;
173  }
174 
175  if (this->OutputChannels.empty())
176  {
177  LOG_ERROR("No output channels defined for vtkPlusOpenIGTLinkVideoSource. Cannot proceed.");
178  this->SetCorrectlyConfigured(false);
179  return PLUS_FAIL;
180  }
181 
182  return PLUS_SUCCESS;
183 }
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
vtkSmartPointer< vtkPlusIgtlMessageFactory > MessageFactory
PlusStatus SetInputFrameSize(unsigned int x, unsigned int y, unsigned int z)
virtual PlusStatus AddItem(vtkImageData *frame, US_IMAGE_ORIENTATION usImageOrientation, US_IMAGE_TYPE imageType, long frameNumber, double unfilteredTimestamp=UNDEFINED_TIMESTAMP, double filteredTimestamp=UNDEFINED_TIMESTAMP, const igsioFieldMapType *customFields=NULL)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
vtkSmartPointer< vtkIGSIORecursiveCriticalSection > SocketMutex
bool RequireImageOrientationInConfiguration
PlusStatus SetImageType(US_IMAGE_TYPE imageType)
igsioTransformName ImageMessageEmbeddedTransformName
#define PLUS_FAIL
Definition: PlusCommon.h:43
IGTL message helper class for tracked frame messages.
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
static PlusStatus UnpackTrackedFrameMessage(igtl::MessageHeader::Pointer headerMsg, igtl::Socket *socket, igsioTrackedFrame &trackedFrame, const igsioTransformName &embeddedTransformName, int crccheck)
PlusStatus GetFirstActiveOutputVideoSource(vtkPlusDataSource *&aVideoSource)
virtual void SetCorrectlyConfigured(bool)
unsigned long FrameNumber
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
virtual void PrintSelf(ostream &os, vtkIndent indent)
virtual PlusStatus ReceiveMessageHeader(igtl::MessageHeader::Pointer &headerMsg)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
static PlusStatus UnpackImageMessage(igtl::MessageHeader::Pointer headerMsg, igtl::Socket *socket, igsioTrackedFrame &trackedFrame, const igsioTransformName &embeddedTransformName, int crccheck)
virtual bool IsRecording() const
igtl::ClientSocket::Pointer ClientSocket
VTK interface for video input from OpenIGTLink image message.
virtual int GetConnected() const
ChannelContainer OutputChannels
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
vtkStandardNewMacro(vtkPlusOpenIGTLinkVideoSource)
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
virtual int GetNumberOfItems()
Interface to a 3D positioning tool, video source, or generalized data stream.