-
Notifications
You must be signed in to change notification settings - Fork 105
/
Copy pathvtkPlusOpenIGTLinkVideoSource.cxx
203 lines (176 loc) · 7.79 KB
/
vtkPlusOpenIGTLinkVideoSource.cxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*=Plus=header=begin======================================================
Program: Plus
Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
See License.txt for details.
=========================================================Plus=header=end*/
// Plus includes
#include "PlusConfigure.h"
#include "vtkPlusChannel.h"
#include "vtkPlusDataSource.h"
#include "vtkPlusIgtlMessageCommon.h"
#include "vtkPlusOpenIGTLinkVideoSource.h"
// OpenIGTLink includes
#include <igtlImageMessage.h>
// VTK includes
#include <vtkImageData.h>
#include <vtkObjectFactory.h>
vtkStandardNewMacro(vtkPlusOpenIGTLinkVideoSource);
//----------------------------------------------------------------------------
vtkPlusOpenIGTLinkVideoSource::vtkPlusOpenIGTLinkVideoSource()
{
this->RequireImageOrientationInConfiguration = true;
}
//----------------------------------------------------------------------------
vtkPlusOpenIGTLinkVideoSource::~vtkPlusOpenIGTLinkVideoSource()
{
}
//----------------------------------------------------------------------------
void vtkPlusOpenIGTLinkVideoSource::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
//----------------------------------------------------------------------------
PlusStatus vtkPlusOpenIGTLinkVideoSource::InternalUpdate()
{
LOG_TRACE("vtkPlusOpenIGTLinkVideoSource::InternalUpdate");
if (!this->IsRecording() || !this->GetConnected())
{
// drop the frame, we are not recording data now
return PLUS_SUCCESS;
}
igtl::MessageHeader::Pointer headerMsg;
if (ReceiveMessageHeader(headerMsg) == PLUS_FAIL)
{
if (!this->IsRecording() || !this->GetConnected())
{
// Disconnect while waiting for message, exit gracefully
return PLUS_SUCCESS;
}
OnReceiveTimeout();
return PLUS_FAIL;
}
if (headerMsg == nullptr)
{
// Not a problem, just no messages received this timeout period
return PLUS_SUCCESS;
}
// We've received valid header data
headerMsg->Unpack(this->IgtlMessageCrcCheckEnabled);
// Set unfiltered and filtered timestamp by converting UTC to system timestamp
double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
igsioTrackedFrame trackedFrame;
igtl::MessageBase::Pointer bodyMsg = this->MessageFactory->CreateReceiveMessage(headerMsg);
igsioTransformName embeddedTransformName = this->ImageMessageEmbeddedTransformName;
if (this->ImageMessageEmbeddedTransformName.From() == this->ImageMessageEmbeddedTransformName.To())
{
// If the From and To coordinate frames are the same, then don't unpack the transform.
// Unpacking the transform would cause errors such as "Setting a transform to itself is not allowed" in vtkIGSIOTransformRepository.
embeddedTransformName = igsioTransformName();
}
if (typeid(*bodyMsg) == typeid(igtl::ImageMessage))
{
if (vtkPlusIgtlMessageCommon::UnpackImageMessage(bodyMsg, this->ClientSocket, trackedFrame, embeddedTransformName, this->IgtlMessageCrcCheckEnabled) != PLUS_SUCCESS)
{
LOG_ERROR("Couldn't get image from OpenIGTLink server!");
return PLUS_FAIL;
}
}
else if (typeid(*bodyMsg) == typeid(igtl::PlusTrackedFrameMessage))
{
if (vtkPlusIgtlMessageCommon::UnpackTrackedFrameMessage(bodyMsg, this->ClientSocket, trackedFrame, embeddedTransformName, this->IgtlMessageCrcCheckEnabled) != PLUS_SUCCESS)
{
LOG_ERROR("Couldn't get tracked frame from OpenIGTLink server!");
return PLUS_FAIL;
}
double unfilteredTimestampUtc = trackedFrame.GetTimestamp();
if (this->UseReceivedTimestamps)
{
// Use the timestamp in the OpenIGTLink message
// The received timestamp is in UTC and timestamps in the buffer are in system time, so conversion is needed
unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTimeFromUniversalTime(unfilteredTimestampUtc);
}
}
else
{
// if the data type is unknown, skip reading.
igsioLockGuard<vtkIGSIORecursiveCriticalSection> socketGuard(this->SocketMutex);
this->ClientSocket->Skip(headerMsg->GetBodySizeToRead(), 0);
return PLUS_SUCCESS;
}
// No need to filter already filtered timestamped items received over OpenIGTLink
// 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
double filteredTimestamp = unfilteredTimestamp;
// The timestamps are already defined, so we don't need to filter them,
// for simplicity, we increase frame number always by 1.
this->FrameNumber++;
vtkPlusDataSource* aSource = NULL;
if (this->GetFirstActiveOutputVideoSource(aSource) != PLUS_SUCCESS)
{
LOG_ERROR("Unable to retrieve the video source in the OpenIGTLinkVideo device.");
return PLUS_FAIL;
}
// If the buffer is empty, set the pixel type and frame size to the first received properties
if (aSource->GetNumberOfItems() == 0)
{
igsioVideoFrame* videoFrame = trackedFrame.GetImageData();
if (videoFrame == NULL)
{
LOG_ERROR("Invalid video frame received, cannot use it to initialize the video buffer");
return PLUS_FAIL;
}
aSource->SetPixelType(videoFrame->GetVTKScalarPixelType());
unsigned int numberOfScalarComponents(1);
if (videoFrame->GetNumberOfScalarComponents(numberOfScalarComponents) != PLUS_SUCCESS)
{
LOG_ERROR("Unable to retrieve number of scalar components.");
return PLUS_FAIL;
}
aSource->SetNumberOfScalarComponents(numberOfScalarComponents);
aSource->SetImageType(videoFrame->GetImageType());
aSource->SetInputFrameSize(trackedFrame.GetFrameSize());
}
if (embeddedTransformName.IsValid())
{
std::string transformStatusField = embeddedTransformName.GetTransformName() + igsioTrackedFrame::TransformStatusPostfix;
std::string strStatus = trackedFrame.GetFrameField(transformStatusField);
if (strStatus.empty())
{
// Transform status has not been set on the frame, and is assumed to be OK.
trackedFrame.SetFrameTransformStatus(embeddedTransformName, TOOL_OK);
}
}
igsioFieldMapType customFields = trackedFrame.GetCustomFields();
PlusStatus status = aSource->AddItem(trackedFrame.GetImageData(), this->FrameNumber, unfilteredTimestamp, filteredTimestamp, &customFields);
this->Modified();
return status;
}
//-----------------------------------------------------------------------------
PlusStatus vtkPlusOpenIGTLinkVideoSource::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
{
XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
XML_READ_STRING_ATTRIBUTE_OPTIONAL(ImageMessageEmbeddedTransformName, deviceConfig);
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
PlusStatus vtkPlusOpenIGTLinkVideoSource::WriteConfiguration(vtkXMLDataElement* rootConfigElement)
{
XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
deviceConfig->SetAttribute("ImageMessageEmbeddedTransformName", this->ImageMessageEmbeddedTransformName.GetTransformName().c_str());
return PLUS_SUCCESS;
}
//----------------------------------------------------------------------------
PlusStatus vtkPlusOpenIGTLinkVideoSource::NotifyConfigured()
{
if (this->OutputChannels.size() > 1)
{
LOG_WARNING("vtkPlusOpenIGTLinkVideoSource is expecting one output channel and there are " << this->OutputChannels.size() << " channels. First output channel will be used.");
return PLUS_FAIL;
}
if (this->OutputChannels.empty())
{
LOG_ERROR("No output channels defined for vtkPlusOpenIGTLinkVideoSource. Cannot proceed.");
this->SetCorrectlyConfigured(false);
return PLUS_FAIL;
}
return PLUS_SUCCESS;
}