PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusTelemedVideoSource.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 // Local includes
8 #include "PlusConfigure.h"
9 #include "PixelCodec.h"
10 #include "vtkPlusChannel.h"
11 #include "vtkPlusDataSource.h"
14 
15 // VTK includes
16 #include <vtkImageData.h>
17 #include <vtkImageImport.h>
18 #include <vtkObjectFactory.h>
19 
20 //----------------------------------------------------------------------------
21 
22 vtkStandardNewMacro(vtkPlusTelemedVideoSource); // Corresponds to the implementation of : static vtkPlusTelemedVideoSource *New(); (in .h file)
23 
24 //----------------------------------------------------------------------------
26  : ProbeId(0)
27  , FrequencyMhz(-1)
28  , DepthMm(-1)
29  , GainPercent(-1)
30  , DynRangeDb(-1)
31  , PowerDb(-1)
32  , FocusDepthPercent(-1)
33  , ConnectedToDevice(false)
34 {
35  this->FrameSize[0] = 512;
36  this->FrameSize[1] = 512;
37  this->FrameSize[2] = 1; // just in case if the frame size is passed to a method that expects a 3D frame size
38 
39  this->Device = NULL;
41  this->StartThreadForInternalUpdates = true;
42 }
43 
44 //----------------------------------------------------------------------------
46 {
47  delete this->Device;
48  this->Device = NULL;
49 }
50 
51 //----------------------------------------------------------------------------
52 void vtkPlusTelemedVideoSource::PrintSelf(ostream& os, vtkIndent indent)
53 {
54  this->Superclass::PrintSelf(os, indent);
55 }
56 
57 //-----------------------------------------------------------------------------
58 PlusStatus vtkPlusTelemedVideoSource::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
59 {
60  LOG_TRACE("vtkPlusTelemedVideoSource::ReadConfiguration");
61  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
62  XML_READ_STD_ARRAY_ATTRIBUTE_OPTIONAL(int, 3, FrameSize, deviceConfig);
63 
64  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(int, ProbeId, deviceConfig);
65  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, DepthMm, deviceConfig);
66  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, FrequencyMhz, deviceConfig);
67  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, DynRangeDb, deviceConfig);
68  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, GainPercent, deviceConfig);
69  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, PowerDb, deviceConfig);
70  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, FocusDepthPercent, deviceConfig);
71 
72  return PLUS_SUCCESS;
73 }
74 
75 //-----------------------------------------------------------------------------
76 PlusStatus vtkPlusTelemedVideoSource::WriteConfiguration(vtkXMLDataElement* rootConfigElement)
77 {
78  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
79 
80  int frameSize[3] = { this->FrameSize[0], this->FrameSize[1], this->FrameSize[2] };
81  deviceConfig->SetVectorAttribute("FrameSize", 3, frameSize);
82 
83  deviceConfig->SetIntAttribute("ProbeId", this->ProbeId);
84  deviceConfig->SetDoubleAttribute("DepthMm", this->DepthMm);
85  deviceConfig->SetDoubleAttribute("FrequencyMhz", this->FrequencyMhz);
86  deviceConfig->SetDoubleAttribute("DynRangeDb", this->DynRangeDb);
87  deviceConfig->SetDoubleAttribute("GainPercent", this->GainPercent);
88  deviceConfig->SetDoubleAttribute("PowerDb", this->PowerDb);
89  deviceConfig->SetDoubleAttribute("FocusDepthPercent", this->FocusDepthPercent);
90  return PLUS_SUCCESS;
91 }
92 
93 //----------------------------------------------------------------------------
95 {
96  this->Device->FreezeDevice(freeze);
97  return PLUS_SUCCESS;
98 }
99 
100 //----------------------------------------------------------------------------
102 {
103  if (this->Device == NULL)
104  {
105  this->Device = new TelemedUltrasound();
106  }
107  this->Device->SetMaximumFrameSize(this->FrameSize);
108  if (this->Device->Connect(this->ProbeId) != PLUS_SUCCESS)
109  {
110  LOG_ERROR("vtkPlusTelemedVideoSource device initialization failed");
111  this->ConnectedToDevice = false;
112  return PLUS_FAIL;
113  }
114  this->ConnectedToDevice = true;
115 
116  // Updating imaging parameters from config file.
117  // We should consider removing the parameters from this class, and rely on
118  // vtkPlusUsImagingParameters to read parameters from config file.
119  if (this->FrequencyMhz > 0)
120  {
122  }
123  if (this->DepthMm > 0)
124  {
125  this->ImagingParameters->SetDepthMm(this->DepthMm);
126  }
127  if (this->GainPercent >= 0)
128  {
130  }
131  if (this->DynRangeDb > 0)
132  {
134  }
135  if (this->PowerDb >= 0)
136  {
137  this->ImagingParameters->SetPowerDb(this->PowerDb);
138  }
139  if (this->FocusDepthPercent >= 0 && this->FocusDepthPercent <= 1)
140  {
142  }
143 
144  // For the parameters not set from the config file or in the imaging parameters, we should try to read them from the current device settings
146  {
147  double deviceFrequencyMhz;
148  this->GetFrequencyMhz(deviceFrequencyMhz);
149  this->ImagingParameters->SetFrequencyMhz(deviceFrequencyMhz);
150  }
152  {
153  double deviceDepthMM;
154  this->GetDepthMm(deviceDepthMM);
155  this->ImagingParameters->SetDepthMm(deviceDepthMM);
156  }
158  {
159  double deviceGainPercent;
160  this->GetGainPercent(deviceGainPercent);
161  this->ImagingParameters->SetGainPercent(deviceGainPercent);
162  }
164  {
165  double deviceDynRangeDb;
166  this->GetDynRangeDb(deviceDynRangeDb);
167  this->ImagingParameters->SetDynRangeDb(deviceDynRangeDb);
168  }
170  {
171  double devicePowerDb;
172  this->GetPowerDb(devicePowerDb);
173  this->ImagingParameters->SetPowerDb(devicePowerDb);
174  }
176  {
177  double deviceFocusDepthPercent;
178  this->GetFocusDepthPercent(deviceFocusDepthPercent);
179  this->ImagingParameters->SetFocusDepthPercent(deviceFocusDepthPercent);
180  }
181 
182  // Apply all of the parameters
184 
185  return PLUS_SUCCESS;
186 }
187 
188 //----------------------------------------------------------------------------
190 {
191  LOG_DEBUG("Disconnect from Telemed");
192  this->Device->Disconnect();
193  delete this->Device;
194  this->Device = NULL;
195  this->ConnectedToDevice = false;
196  return PLUS_SUCCESS;
197 }
198 
199 //----------------------------------------------------------------------------
201 {
202  LOG_TRACE("vtkPlusTelemedVideoSource::InternalUpdate");
203  if (!this->Recording)
204  {
205  // drop the frame, we are not recording data now
206  return PLUS_SUCCESS;
207  }
208 
209  // Capture one frame from the Telemed device
210  unsigned char* bufferData = this->Device->CaptureFrame();
211  if (bufferData == NULL)
212  {
213  LOG_ERROR("No frame received by the device");
214  return PLUS_FAIL;
215  }
216 
217  this->FrameNumber++;
218 
219  FrameSizeType frameSizeInPix = { 0, 0, 1 };
220  this->Device->GetFrameSize(frameSizeInPix);
221  int bufferSize = this->Device->GetBufferSize();
222  if (frameSizeInPix[0] * frameSizeInPix[1] == 0)
223  {
224  LOG_ERROR("Failed to retrieve valid frame size (got " << frameSizeInPix[0] << "x" << frameSizeInPix[1]);
225  return PLUS_FAIL;
226  }
227  unsigned int numberOfScalarComponents = bufferSize / (frameSizeInPix[0] * frameSizeInPix[1]);
228 
231  if (numberOfScalarComponents == 3)
232  {
234  componentOrdering = PixelCodec::ComponentOrder_RGB;
235  }
236  else if (numberOfScalarComponents == 4)
237  {
239  componentOrdering = PixelCodec::ComponentOrder_RGBA;
240  }
241  else
242  {
243  LOG_ERROR("Unexpected number of scalar components: " << numberOfScalarComponents);
244  return PLUS_FAIL;
245  }
246 
247  // Retrieve the video source in Telemed device
248  vtkPlusDataSource* aSource = NULL;
249  if (this->GetFirstActiveOutputVideoSource(aSource) != PLUS_SUCCESS)
250  {
251  LOG_ERROR("Unable to retrieve the video source in the Telemed device.");
252  return PLUS_FAIL;
253  }
254 
255  // If the buffer is empty, set the pixel type and frame size to the first received properties
256  if (aSource->GetNumberOfItems() == 0)
257  {
258  LOG_DEBUG("Set up image buffer for Telemed");
259  aSource->SetPixelType(VTK_UNSIGNED_CHAR);
260  aSource->SetImageType(US_IMG_BRIGHTNESS);
261  aSource->SetInputFrameSize(frameSizeInPix);
262  LOG_DEBUG("Frame size: " << frameSizeInPix[0] << "x" << frameSizeInPix[1]
263  << ", pixel type: " << vtkImageScalarTypeNameMacro(aSource->GetPixelType())
264  << ", buffer image orientation: " << igsioCommon::GetStringFromUsImageOrientation(aSource->GetInputImageOrientation()));
265  this->UncompressedVideoFrame.SetImageType(aSource->GetImageType());
266  this->UncompressedVideoFrame.SetImageOrientation(aSource->GetInputImageOrientation());
267  }
268 
269  PlusStatus decodingStatus = PLUS_FAIL;
270  if (aSource->GetImageType() == US_IMG_RGB_COLOR)
271  {
272  this->UncompressedVideoFrame.AllocateFrame(frameSizeInPix, VTK_UNSIGNED_CHAR, 3);
273  decodingStatus = PixelCodec::ConvertToBGR24(componentOrdering, encoding, frameSizeInPix[0], frameSizeInPix[1], bufferData, (unsigned char*)this->UncompressedVideoFrame.GetScalarPointer());
274  }
275  else
276  {
277  this->UncompressedVideoFrame.AllocateFrame(frameSizeInPix, VTK_UNSIGNED_CHAR, 1);
278  decodingStatus = PixelCodec::ConvertToGray(encoding, frameSizeInPix[0], frameSizeInPix[1], bufferData, (unsigned char*)this->UncompressedVideoFrame.GetScalarPointer());
279  }
280  if (decodingStatus != PLUS_SUCCESS)
281  {
282  LOG_ERROR("Error while decoding the grabbed image");
283  return PLUS_FAIL;
284  }
285 
286  // Add the frame to the stream buffer
287  PlusStatus status = aSource->AddItem(&this->UncompressedVideoFrame, this->FrameNumber);
288  this->Modified();
289 
290  return status;
291 }
292 
293 
294 /*********** PARAMETERS *************/
295 
296 #define IMAGING_PARAMETER_SET(parameterName) \
297 PlusStatus vtkPlusTelemedVideoSource::Set##parameterName(double a##parameterName) \
298 { \
299  LOG_INFO("Setting US parameter "<<#parameterName<<"="<<a##parameterName); \
300  if (this->Device==NULL) \
301  { \
302  /* Connection has not been established yet. Parameter value will be set upon connection. */ \
303  this->parameterName=a##parameterName; \
304  return PLUS_SUCCESS; \
305  } \
306  int oldParamValue = this->parameterName; \
307  this->parameterName=a##parameterName; \
308  if (this->Device->Set##parameterName(this->parameterName)!=PLUS_SUCCESS) \
309  { \
310  LOG_ERROR("vtkPlusTelemedVideoSource parameter setting failed: "<<#parameterName<<"="<<a##parameterName); \
311  this->parameterName=oldParamValue; \
312  return PLUS_FAIL; \
313  } \
314  return PLUS_SUCCESS; \
315 }
316 
317 #define IMAGING_PARAMETER_GET(parameterName) \
318 PlusStatus vtkPlusTelemedVideoSource::Get##parameterName(double &a##parameterName) \
319 { \
320  if (this->Device==NULL) \
321  { \
322  /* Connection has not been established yet. Return cached parameter value. */ \
323  a##parameterName=this->parameterName; \
324  return PLUS_SUCCESS; \
325  } \
326  if (this->Device->Get##parameterName(this->parameterName)!=PLUS_SUCCESS) \
327  { \
328  LOG_ERROR("vtkPlusTelemedVideoSource parameter setting failed: "<<parameterName<<"="<<a##parameterName); \
329  return PLUS_FAIL; \
330  } \
331  a##parameterName=this->parameterName; \
332  return PLUS_SUCCESS; \
333 }
334 
335 IMAGING_PARAMETER_GET(FrequencyMhz);
336 IMAGING_PARAMETER_GET(DepthMm);
337 IMAGING_PARAMETER_GET(GainPercent);
338 IMAGING_PARAMETER_GET(DynRangeDb);
339 IMAGING_PARAMETER_GET(PowerDb);
340 IMAGING_PARAMETER_GET(FocusDepthPercent);
341 
342 IMAGING_PARAMETER_SET(FrequencyMhz);
343 IMAGING_PARAMETER_SET(DepthMm);
344 IMAGING_PARAMETER_SET(GainPercent);
345 IMAGING_PARAMETER_SET(DynRangeDb);
346 IMAGING_PARAMETER_SET(PowerDb);
347 IMAGING_PARAMETER_SET(FocusDepthPercent);
348 
349 //----------------------------------------------------------------------------
351 {
352  if (this->OutputChannels.size() > 1)
353  {
354  LOG_WARNING("vtkPlusTelemedVideoSource is expecting one output channel and there are " << this->OutputChannels.size() << " channels. First output channel will be used.");
355  }
356 
357  if (this->OutputChannels.empty())
358  {
359  LOG_ERROR("No output channels defined for vtkPlusTelemedVideoSource. Cannot proceed.");
360  this->CorrectlyConfigured = false;
361  return PLUS_FAIL;
362  }
363 
364  return PLUS_SUCCESS;
365 }
366 
367 //----------------------------------------------------------------------------
369 {
370  std::ostringstream versionString;
371  versionString << "Telemed version unknown" << std::ends;
372  return versionString.str();
373 }
374 
375 //----------------------------------------------------------------------------
377 {
378  this->FrameSize = frameSize;
379  return PLUS_SUCCESS;
380 }
381 
382 //----------------------------------------------------------------------------
384 {
385  PlusStatus status = PLUS_SUCCESS;
386 
387  // FREQUENCY
390  {
392  {
393  LOG_ERROR("Failed to set frequency imaging parameter");
394  status = PLUS_FAIL;
395  }
396  }
397 
398  // DEPTH
401  {
402  if (this->SetDepthMm(this->ImagingParameters->GetDepthMm()) != PLUS_SUCCESS)
403  {
404  LOG_ERROR("Failed to set depth imaging parameter");
405  status = PLUS_FAIL;
406  }
407  }
408 
409  // GAIN
412  {
414  {
415  LOG_ERROR("Failed to set gain imaging parameter");
416  status = PLUS_FAIL;
417  }
418  }
419 
420  // DYNAMIC RANGE
423  {
425  {
426  LOG_ERROR("Failed to set dynamic range imaging parameter");
427  status = PLUS_FAIL;
428  }
429  }
430 
431  // POWER
434  {
435  if (this->SetPowerDb(this->ImagingParameters->GetPowerDb()) != PLUS_SUCCESS)
436  {
437  LOG_ERROR("Failed to set power imaging parameter");
438  status = PLUS_FAIL;
439  }
440  }
441 
442  // FOCUS DEPTH
445  {
447  {
448  LOG_ERROR("Failed to set focus depth percent imaging parameter");
449  status = PLUS_FAIL;
450  }
451  }
452 
453  return status;
454 }
bool IsPending(const std::string &paramName) const
PlusStatus SetGainPercent(double aGainPercent)
US_IMAGE_TYPE GetImageType()
PlusStatus GetFrequencyMhz(double &aFrequencyMhz)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
unsigned char * CaptureFrame()
vtkStandardNewMacro(vtkPlusTelemedVideoSource)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
PlusStatus GetFocusDepthPercent(double &aFocusDepthPercent) const
PlusStatus GetDepthMm(double &aDepthMm) const
PlusStatus SetInputFrameSize(unsigned int x, unsigned int y, unsigned int z)
void FreezeDevice(bool freeze)
void GetFrameSize(FrameSizeType &frameSize)
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)
static PlusStatus ConvertToBGR24(ComponentOrdering outputOrdering, PixelEncoding inputCompression, int width, int height, unsigned char *s, unsigned char *d)
Definition: PixelCodec.h:197
vtkPlusUsImagingParameters * ImagingParameters
Store the current imaging parameters.
bool RequireImageOrientationInConfiguration
PlusStatus SetImageType(US_IMAGE_TYPE imageType)
PlusStatus GetGainPercent(double &aGainPercent)
PlusStatus ReadConfiguration(vtkXMLDataElement *config)
#define PLUS_FAIL
Definition: PlusCommon.h:43
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
PlusStatus GetGainPercent(double aGainPercent) const
virtual igsioCommon::VTKScalarPixelType GetPixelType()
virtual PlusStatus SetFrameSize(const FrameSizeType &frameSize)
PlusStatus GetPowerDb(double &aPower) const
PlusStatus GetFirstActiveOutputVideoSource(vtkPlusDataSource *&aVideoSource)
PlusStatus SetPowerDb(double aPower)
PlusStatus WriteConfiguration(vtkXMLDataElement *config)
unsigned long FrameNumber
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
PlusStatus SetFrequencyMhz(double aFrequencyMhz)
void SetMaximumFrameSize(const FrameSizeType &maxFrameSize)
PlusStatus SetFocusDepthPercent(double aFocusDepthPercent)
PlusStatus GetDynRangeDb(double &aDynRangeDb) const
PlusStatus SetGainPercent(double aGainPercent)
#define IMAGING_PARAMETER_SET(parameterName)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
PlusStatus SetDynRangeDb(double aDynRangeDb)
virtual US_IMAGE_ORIENTATION GetInputImageOrientation()
PlusStatus Connect(int probeId=0)
bool StartThreadForInternalUpdates
PlusStatus GetFocusDepthPercent(double &aFocusDepthPercent)
static PlusStatus ConvertToGray(int inputCompression, int width, int height, unsigned char *s, unsigned char *d)
Definition: PixelCodec.h:146
PlusStatus SetFrequencyMhz(double aFrequencyMhz)
ChannelContainer OutputChannels
#define IMAGING_PARAMETER_GET(parameterName)
PlusStatus GetDepthMm(double &aDepthMm)
PlusStatus SetDynRangeDb(double aDynamicRange)
PlusStatus GetFrequencyMhz(double &aFrequencyMhz) const
PlusStatus SetDepthMm(double aDepthMm)
PlusStatus SetFocusDepthPercent(double aFocusDepthPercent)
PlusStatus GetPowerDb(double &aPowerDb)
virtual PlusStatus InternalApplyImagingParameterChange()
PlusStatus SetPowerDb(double aPowerDb)
unsigned long GetBufferSize()
bool IsSet(const std::string &paramName) const
PlusStatus FreezeDevice(bool freeze)
PlusStatus GetDynRangeDb(double &aDynamicRange)
PlusStatus SetDepthMm(double aDepthMm)
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
virtual int GetNumberOfItems()
Class for interfacing the device manager class, and the PLUS library. The devices are Telemed ultraso...
bool CorrectlyConfigured
Interface to a 3D positioning tool, video source, or generalized data stream.