PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusOvrvisionProVideoSource.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"
10 #include "vtkPlusChannel.h"
11 #include "vtkPlusDataSource.h"
12 
13 // VTK includes
14 #include <vtkImageData.h>
15 #include <vtkObjectFactory.h>
16 #include <vtksys/SystemTools.hxx>
17 
18 // OpenCV includes
19 #include <opencv2/imgproc.hpp>
20 #include <opencv2/core/mat.hpp>
21 #if defined(PLUS_USE_OPENCL)
22  #include <opencv2/core/ocl.hpp>
23 
24  // OpenCL includes
25  #include <CL/cl.h>
26 #endif
27 
28 //----------------------------------------------------------------------------
29 
31 
32 //----------------------------------------------------------------------------
34  : RequestedFormat(OVR::OV_CAM20VR_VGA)
35  , ProcessingMode(OVR::OV_CAMQT_NONE)
36  , CameraSync(false)
37  , Framerate(-1)
38  , Exposure(7808)
39  , LeftEyeDataSource(NULL)
40  , RightEyeDataSource(NULL)
41  , IsCapturingRGB(false)
42 {
44 
45  // Poll-based device
46  this->StartThreadForInternalUpdates = true;
47 }
48 
49 //----------------------------------------------------------------------------
51 {
52  if (!this->Connected)
53  {
54  this->Disconnect();
55  }
56 }
57 
58 //----------------------------------------------------------------------------
59 void vtkPlusOvrvisionProVideoSource::PrintSelf(ostream& os, vtkIndent indent)
60 {
61  this->Superclass::PrintSelf(os, indent);
62 
63  os << indent << "Resolution: " << Resolution[0] << ", " << Resolution[1] << std::endl;
64  os << indent << "Framerate: " << Framerate << std::endl;
65  os << indent << "CameraSync: " << CameraSync << std::endl;
66  os << indent << "ProcessingMode: " << ProcessingModeName << std::endl;
67  os << indent << "LeftEyeDataSourceName: " << LeftEyeDataSourceName << std::endl;
68  os << indent << "RightEyeDataSourceName: " << RightEyeDataSourceName << std::endl;
69  os << indent << "Vendor: " << Vendor << std::endl;
70 }
71 
72 //----------------------------------------------------------------------------
74 {
75  LOG_TRACE("vtkPlusOvrvisionProVideoSource::InternalConnect");
76 
77 #if defined(PLUS_USE_OPENCL)
78  cv::ocl::setUseOpenCL(true);
79 #endif
80 
81  if (!OvrvisionProHandle.Open(0, RequestedFormat, Vendor.c_str())) // We don't need to share it with OpenGL/D3D, but in the future we could access the images in GPU memory
82  {
83  LOG_ERROR("Unable to connect to OvrvisionPro device.");
84  return PLUS_FAIL;
85  }
86 
87  this->Resolution[0] = OvrvisionProHandle.GetCamWidth();
88  this->Resolution[1] = OvrvisionProHandle.GetCamHeight();
89  this->Framerate = OvrvisionProHandle.GetCamFramerate();
90 
91  this->SetAcquisitionRate(this->Framerate);
92 
93  this->RegionOfInterest.offsetX = 0;
94  this->RegionOfInterest.offsetY = 0;
95  this->RegionOfInterest.width = this->Resolution[0];
96  this->RegionOfInterest.height = this->Resolution[1];
97 
98  FrameSizeType frameSize = { Resolution[0], Resolution[1], 1 };
99  this->LeftEyeDataSource->SetInputFrameSize(frameSize);
100  this->RightEyeDataSource->SetInputFrameSize(frameSize);
101 
102  if (this->IsCapturingRGB)
103  {
106  }
107  else
108  {
111  }
112 
113  this->OvrvisionProHandle.SetCameraSyncMode(CameraSync);
114  this->OvrvisionProHandle.SetCameraExposure(Exposure);
115 
116 #if defined(PLUS_USE_OPENCL)
117  cl_platform_id id = this->OvrvisionProHandle.GetPlatformId();
118  cv::ocl::PlatformInfo info(&id);
119 
120  cv::ocl::attachContext(info.name(), this->OvrvisionProHandle.GetPlatformId(), this->OvrvisionProHandle.GetContext(), this->OvrvisionProHandle.GetDeviceId());
121 #endif
122 
123  this->LeftImage = cv::Mat(OvrvisionProHandle.GetCamHeight(), OvrvisionProHandle.GetCamWidth(), CV_8UC4);
124  this->RightImage = cv::Mat(OvrvisionProHandle.GetCamHeight(), OvrvisionProHandle.GetCamWidth(), CV_8UC4);
125 
126  if (!this->IsCapturingRGB)
127  {
128  this->LeftImage.data = OvrvisionProHandle.GetCamImageBGRA(OVR::OV_CAMEYE_LEFT);
129  this->RightImage.data = OvrvisionProHandle.GetCamImageBGRA(OVR::OV_CAMEYE_RIGHT);
130  }
131 
132  return PLUS_SUCCESS;
133 }
134 
135 //----------------------------------------------------------------------------
137 {
138  LOG_DEBUG("vtkPlusOvrvisionProVideoSource::InternalDisconnect");
139 
140  if (OvrvisionProHandle.isOpen())
141  {
142  OvrvisionProHandle.Close();
143  }
144 
145  return PLUS_SUCCESS;
146 }
147 
148 //----------------------------------------------------------------------------
150 {
151  int numErrors(0);
152 
153  // Query the SDK for the latest frames
154  if (this->IsCapturingRGB)
155  {
156 #if defined(PLUS_USE_OPENCL)
157  OvrvisionProHandle.Capture(this->ProcessingMode); // Capture does not copy it to CPU
158 
159  cv::ocl::convertFromImage(OvrvisionProHandle.GetLeftCLImage(), this->LeftImageCL);
160  cv::ocl::convertFromImage(OvrvisionProHandle.GetRightCLImage(), this->RightImageCL);
161 
162  cv::cvtColor(this->LeftImageCL, this->LeftImageCL, cv::COLOR_BGRA2RGB);
163  cv::cvtColor(this->RightImageCL, this->RightImageCL, cv::COLOR_BGRA2RGB);
164 
165  this->LeftImageCL.copyTo(this->LeftImageColorConverted);
166  this->RightImageCL.copyTo(this->RightImageColorConverted);
167 #else
168  OvrvisionProHandle.PreStoreCamData(this->ProcessingMode);
169 
170  cv::cvtColor(this->LeftImage, this->RightImageColorConverted, cv::COLOR_BGRA2RGB);
171  cv::cvtColor(this->RightImage, this->RightImageColorConverted, cv::COLOR_BGRA2RGB);
172 #endif
173  }
174  else
175  {
176  // Cannot use OpenCL, because it doesn't touch gray scale data (just splits the 16 bit to two 8 bit)
177  OvrvisionProHandle.PreStoreCamData(OVR::OV_CAMQT_NONE);
178  cv::cvtColor(this->LeftImage, this->LeftImageColorConverted, cv::COLOR_BGRA2GRAY);
179  cv::cvtColor(this->RightImage, this->RightImageColorConverted, cv::COLOR_BGRA2GRAY);
180  }
181 
182  // Add them to our local buffers
183  if (this->LeftEyeDataSource->AddItem(this->LeftImageColorConverted.data,
184  this->LeftEyeDataSource->GetInputImageOrientation(),
186  VTK_UNSIGNED_CHAR,
187  this->LeftImageColorConverted.channels(),
188  this->IsCapturingRGB ? US_IMG_RGB_COLOR : US_IMG_BRIGHTNESS,
189  0,
190  this->FrameNumber) != PLUS_SUCCESS)
191  {
192  LOG_ERROR("Unable to add left eye image to data source.");
193  numErrors++;
194  }
195 
196  if (this->RightEyeDataSource->AddItem(this->RightImageColorConverted.data,
197  this->RightEyeDataSource->GetInputImageOrientation(),
199  VTK_UNSIGNED_CHAR,
200  this->RightImageColorConverted.channels(),
201  this->IsCapturingRGB ? US_IMG_RGB_COLOR : US_IMG_BRIGHTNESS,
202  0,
203  this->FrameNumber) != PLUS_SUCCESS)
204  {
205  LOG_ERROR("Unable to add right eye image to data source.");
206  numErrors++;
207  }
208 
209  this->FrameNumber++;
210 
211  return numErrors == 0 ? PLUS_SUCCESS : PLUS_FAIL;
212 }
213 
214 //----------------------------------------------------------------------------
216 {
217  this->ProcessingMode = OVR::OV_CAMQT_NONE;
218  if (igsioCommon::IsEqualInsensitive(this->ProcessingModeName, "OV_CAMQT_DMSRMP"))
219  {
220  this->ProcessingMode = OVR::OV_CAMQT_DMSRMP;
221  }
222  else if (igsioCommon::IsEqualInsensitive(this->ProcessingModeName, "OV_CAMQT_DMS"))
223  {
224  this->ProcessingMode = OVR::OV_CAMQT_DMS;
225  }
226  else
227  {
228  LOG_WARNING("Unrecognized processing mode detected. Defaulting to OVR::OV_CAMQT_NONE.");
229  }
230 }
231 
232 //----------------------------------------------------------------------------
233 std::string vtkPlusOvrvisionProVideoSource::CamPropToString(OVR::Camprop format)
234 {
235  switch (format)
236  {
237  case OVR::OV_CAM5MP_FULL:
238  return "OV_CAM5MP_FULL";
239  case OVR::OV_CAM5MP_FHD:
240  return "OV_CAM5MP_FHD";
241  case OVR::OV_CAMHD_FULL:
242  return "OV_CAMHD_FULL";
243  case OVR::OV_CAMVR_FULL:
244  return "OV_CAMVR_FULL";
245  case OVR::OV_CAMVR_WIDE:
246  return "OV_CAMVR_WIDE";
247  case OVR::OV_CAMVR_VGA:
248  return "OV_CAMVR_VGA";
249  case OVR::OV_CAMVR_QVGA:
250  return "OV_CAMVR_QVGA";
251  case OVR::OV_CAM20HD_FULL:
252  return "OV_CAM20HD_FULL";
253  case OVR::OV_CAM20VR_VGA:
254  default:
255  return "OV_CAM20VR_VGA";
256  }
257 }
258 
259 //----------------------------------------------------------------------------
260 OVR::Camprop vtkPlusOvrvisionProVideoSource::StringToCamProp(const std::string& format)
261 {
262  // Handle strings without OV_ in front
263  std::string nonConstFormat = format;
264  if (nonConstFormat.find("OV_") == std::string::npos)
265  {
266  nonConstFormat.insert(0, "OV_");
267  }
268 
269  if (igsioCommon::IsEqualInsensitive(nonConstFormat, "OV_CAM5MP_FULL"))
270  {
271  return OVR::OV_CAM5MP_FULL;
272  }
273  else if (igsioCommon::IsEqualInsensitive(nonConstFormat, "OV_CAM5MP_FHD"))
274  {
275  return OVR::OV_CAM5MP_FHD;
276  }
277  else if (igsioCommon::IsEqualInsensitive(nonConstFormat, "OV_CAMHD_FULL"))
278  {
279  return OVR::OV_CAMHD_FULL;
280  }
281  else if (igsioCommon::IsEqualInsensitive(nonConstFormat, "OV_CAMVR_FULL"))
282  {
283  return OVR::OV_CAMVR_FULL;
284  }
285  else if (igsioCommon::IsEqualInsensitive(nonConstFormat, "OV_CAMVR_WIDE"))
286  {
287  return OVR::OV_CAMVR_WIDE;
288  }
289  else if (igsioCommon::IsEqualInsensitive(nonConstFormat, "OV_CAMVR_VGA"))
290  {
291  return OVR::OV_CAMVR_VGA;
292  }
293  else if (igsioCommon::IsEqualInsensitive(nonConstFormat, "OV_CAMVR_QVGA"))
294  {
295  return OVR::OV_CAMVR_QVGA;
296  }
297  else if (igsioCommon::IsEqualInsensitive(nonConstFormat, "OV_CAM20HD_FULL"))
298  {
299  return OVR::OV_CAM20HD_FULL;
300  }
301  else
302  {
303  return OVR::OV_CAM20VR_VGA;
304  }
305 }
306 
307 //-----------------------------------------------------------------------------
309 {
310  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
311 
312  auto attr = deviceConfig->GetAttribute("RequestedFormat");
313  if (attr == nullptr)
314  {
315  LOG_INFO("No requested format defined. Falling back to OV_CAM20VR_VGA (640x480@30fps).");
316  RequestedFormat = OVR::OV_CAM20VR_VGA;
317  }
318  else
319  {
321  }
322  XML_READ_STRING_ATTRIBUTE_REQUIRED(LeftEyeDataSourceName, deviceConfig);
323  XML_READ_STRING_ATTRIBUTE_REQUIRED(RightEyeDataSourceName, deviceConfig);
324  XML_READ_STRING_ATTRIBUTE_OPTIONAL(Vendor, deviceConfig);
325  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(int, Exposure, deviceConfig);
326  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(CameraSync, deviceConfig);
327  XML_READ_STRING_ATTRIBUTE_OPTIONAL(ProcessingModeName, deviceConfig);
328 
329  this->SetAcquisitionRate(this->Framerate);
330 
331  if (!this->ProcessingModeName.empty())
332  {
333  this->ConfigureProcessingMode();
334  }
335 
336  return PLUS_SUCCESS;
337 }
338 
339 //-----------------------------------------------------------------------------
341 {
342  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
343 
344  std::string requestedFormat = vtkPlusOvrvisionProVideoSource::CamPropToString(this->RequestedFormat);
345  rootConfigElement->SetAttribute("RequestedFormat", requestedFormat.c_str());
346 
347  if (this->CameraSync)
348  {
349  deviceConfig->SetAttribute("CameraSync", "TRUE");
350  }
351 
352  if (this->ProcessingMode != OVR::OV_CAMQT_NONE)
353  {
354  switch (this->ProcessingMode)
355  {
356  case OVR::OV_CAMQT_DMS:
357  deviceConfig->SetAttribute("ProcessingModeName", "OV_CAMQT_DMS");
358  break;
359  case OVR::OV_CAMQT_DMSRMP:
360  deviceConfig->SetAttribute("ProcessingModeName", "OV_CAMQT_DMSRMP");
361  break;
362  }
363  }
364 
365  XML_WRITE_STRING_ATTRIBUTE_IF_NOT_EMPTY(Vendor, deviceConfig);
366 
367  return PLUS_SUCCESS;
368 }
369 
370 //-----------------------------------------------------------------------------
372 {
373  // OvrvisionSDK requires two data sources, left eye and right eye
375  {
376  LOG_ERROR("Unable to locate data source for left eye labelled: " << this->LeftEyeDataSourceName);
377  return PLUS_FAIL;
378  }
379 
381  {
382  LOG_ERROR("Unable to locate data source for right eye labelled: " << this->RightEyeDataSourceName);
383  return PLUS_FAIL;
384  }
385 
387  {
388  LOG_ERROR("Mistmatch between left and right eye data source image types.");
389  return PLUS_FAIL;
390  }
391 
392  if (this->LeftEyeDataSource->GetImageType() == US_IMG_RGB_COLOR)
393  {
394  this->IsCapturingRGB = true;
395  }
396  else
397  {
398  this->IsCapturingRGB = false;
399  }
400 
401  if (this->OutputChannels.size() != 2)
402  {
403  LOG_ERROR("OvrvisionPro device requires exactly 2 output channels. One for each eye.");
404  return PLUS_FAIL;
405  }
406 
407  return PLUS_SUCCESS;
408 }
409 
410 //----------------------------------------------------------------------------
411 std::array<unsigned int, 2> vtkPlusOvrvisionProVideoSource::GetResolution() const
412 {
413  return this->Resolution;
414 }
PlusStatus GetDataSource(const char *aSourceId, vtkPlusDataSource *&aSource)
std::array< unsigned int, 2 > Resolution
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
virtual PlusStatus NotifyConfigured()
Perform any completion tasks once configured.
US_IMAGE_TYPE GetImageType()
vtkStandardNewMacro(vtkPlusOvrvisionProVideoSource)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
Write configuration to xml data.
static std::string CamPropToString(OVR::Camprop format)
virtual PlusStatus InternalDisconnect()
Device-specific disconnect.
igsioStatus PlusStatus
Definition: PlusCommon.h:40
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)
std::array< unsigned int, 2 > GetResolution() const
bool RequireImageOrientationInConfiguration
PlusStatus SetAcquisitionRate(double aRate)
#define PLUS_FAIL
Definition: PlusCommon.h:43
virtual PlusStatus InternalUpdate()
Device-specific on-update function.
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
Read configuration from xml data.
virtual PlusStatus Disconnect()
unsigned long FrameNumber
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
static OVR::Camprop StringToCamProp(const std::string &format)
bool StartThreadForInternalUpdates
void PrintSelf(ostream &os, vtkIndent indent)
virtual PlusStatus InternalConnect()
Device-specific connect.
ChannelContainer OutputChannels
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
FrameSizeType GetInputFrameSize() const