PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusIntersonArraySDKCxxVideoSource.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 "vtkPlusChannel.h"
10 #include "vtkPlusDataSource.h"
12 #include "vtkPlusRfProcessor.h"
14 #include "vtkPlusUSImagingParameters.h"
16 
17 // VTK includes
18 #include <vtkImageCast.h>
19 #include <vtkImageData.h>
20 #include <vtkImageImport.h>
21 #include <vtkObjectFactory.h>
22 
23 // Interson includes
24 #include <IntersonArrayCxxControlsHWControls.h>
25 #include <IntersonArrayCxxImagingContainer.h>
26 #include <IntersonArrayCxxIntersonClass.h>
27 
28 //----------------------------------------------------------------------------
29 typedef IntersonArrayCxx::Imaging::Container ContainerType;
30 typedef IntersonArrayCxx::Controls::HWControls HWControlsType;
31 typedef IntersonArrayCxx::IntersonClass IntersonClassType;
32 
33 //----------------------------------------------------------------------------
34 
36 
37 //----------------------------------------------------------------------------
38 struct BmodeCallbackClientData
39 {
40  vtkPlusIntersonArraySDKCxxVideoSource* ActiveIntersonArrayDevice;
41 };
42 struct RfCallbackClientData
43 {
44  vtkPlusIntersonArraySDKCxxVideoSource* ActiveIntersonArrayDevice;
45 };
46 
47 //----------------------------------------------------------------------------
48 void vtkPlusIntersonArraySDKCxxVideoSource::NewBmodeImageCallback(BmodePixelType* buffer, void* clientData)
49 {
50  if (buffer == NULL)
51  {
52  LOG_ERROR("No actual frame data received");
53  return;
54  }
55 
56  BmodeCallbackClientData* callbackClientData = static_cast<BmodeCallbackClientData*>(clientData);
57  vtkPlusIntersonArraySDKCxxVideoSource* activeIntersonArrayDevice = callbackClientData->ActiveIntersonArrayDevice;
58 
59  if (activeIntersonArrayDevice != NULL)
60  {
61  activeIntersonArrayDevice->AddBmodeFrameToBuffer(buffer, clientData);
62  }
63  else
64  {
65  LOG_ERROR("vtkPlusIntersonArraySDKCxxVideoSource B-mode callback but the ActiveIntersonArrayDevice is NULL. Disconnect between the device and SDK.");
66  return;
67  }
68 }
69 
70 //----------------------------------------------------------------------------
71 void vtkPlusIntersonArraySDKCxxVideoSource::NewRfImageCallback(RfPixelType* buffer, void* clientData)
72 {
73  if (buffer == NULL)
74  {
75  LOG_ERROR("No actual frame data received");
76  return;
77  }
78 
79  RfCallbackClientData* callbackClientData = static_cast<RfCallbackClientData*>(clientData);
80  vtkPlusIntersonArraySDKCxxVideoSource* activeIntersonArrayDevice = callbackClientData->ActiveIntersonArrayDevice;
81 
82  if (activeIntersonArrayDevice != NULL)
83  {
84  activeIntersonArrayDevice->AddRfFrameToBuffer(buffer, clientData);
85  }
86  else
87  {
88  LOG_ERROR("vtkPlusIntersonArraySDKCxxVideoSource B-mode callback but the ActiveIntersonArrayDevice is NULL. Disconnect between the device and SDK.");
89  return;
90  }
91 }
92 
93 class vtkPlusIntersonArraySDKCxxVideoSource::vtkInternal
94 {
95 public:
97 
98  //----------------------------------------------------------------------------
99  vtkPlusIntersonArraySDKCxxVideoSource::vtkInternal::vtkInternal(vtkPlusIntersonArraySDKCxxVideoSource* external)
100  : External(external)
101  {
102  this->HWControls = new HWControlsType();
103  this->Container = new ContainerType();
104  this->IntersonClass = new IntersonClassType();
105 
106  this->BmodeClientData.ActiveIntersonArrayDevice = this->External;
107  this->RfClientData.ActiveIntersonArrayDevice = this->External;
108 
109  this->BModeBufferToVtkImage = vtkSmartPointer<vtkImageImport>::New();
110  this->BModeBufferToVtkImage->SetDataScalarType(VTK_UNSIGNED_SHORT);
111  this->BModeBufferToVtkImage->SetDataExtent(0, ContainerType::MAX_SAMPLES / 2 - 1, 0, ContainerType::NBOFLINES - 1, 0, 0);
112  this->BModeBufferToVtkImage->SetWholeExtent(0, ContainerType::MAX_SAMPLES / 2 - 1, 0, ContainerType::NBOFLINES - 1, 0, 0);
113 
114  this->BModeImageCast = vtkSmartPointer<vtkImageCast>::New();
115  this->BModeImageCast->SetOutputScalarTypeToUnsignedChar();
116  this->BModeImageCast->SetInputConnection(this->BModeBufferToVtkImage->GetOutputPort());
117 
118  this->RfBufferToVtkImage = vtkSmartPointer<vtkImageImport>::New();
119  this->RfBufferToVtkImage->SetDataScalarType(VTK_UNSIGNED_CHAR);
120  this->RfBufferToVtkImage->SetDataExtent(0, ContainerType::MAX_RFSAMPLES - 1, 0, ContainerType::NBOFLINES - 1, 0, 0);
121  this->RfBufferToVtkImage->SetWholeExtent(0, ContainerType::MAX_RFSAMPLES - 1, 0, ContainerType::NBOFLINES - 1, 0, 0);
122  }
123 
124  //----------------------------------------------------------------------------
125  vtkPlusIntersonArraySDKCxxVideoSource::vtkInternal::~vtkInternal()
126  {
127  this->External = NULL;
128  delete HWControls;
129  delete Container;
130  delete IntersonClass;
131  }
132 
133  std::string GetSdkVersion()
134  {
135  return this->IntersonClass->Version();
136  }
137 
138  HWControlsType* GetHWControls()
139  {
140  return this->HWControls;
141  }
142 
143  ContainerType* GetContainer()
144  {
145  return this->Container;
146  }
147 
148  vtkImageData* ConvertBModeBufferToVtkImage(unsigned char* pixelData)
149  {
150  this->BModeBufferToVtkImage->SetImportVoidPointer(pixelData);
151  this->BModeBufferToVtkImage->Modified();
152  this->BModeImageCast->Update();
153  return this->BModeImageCast->GetOutput();
154  }
155 
156  vtkImageData* ConvertRfBufferToVtkImage(short* pixelData)
157  {
158  this->RfBufferToVtkImage->SetImportVoidPointer(pixelData);
159  this->RfBufferToVtkImage->Update();
160  return this->RfBufferToVtkImage->GetOutput();
161  }
162 
163  void EnableBModeCallback()
164  {
165  this->Container->SetNewImageCallback(&vtkPlusIntersonArraySDKCxxVideoSource::NewBmodeImageCallback,
166  &(this->BmodeClientData));
167  }
168 
169  void DisableBModeCallback()
170  {
171  this->Container->SetNewImageCallback(NULL, NULL);
172  }
173 
174  void EnableRfCallback()
175  {
176  this->Container->SetNewRFImageCallback(&vtkPlusIntersonArraySDKCxxVideoSource::NewRfImageCallback,
177  &(this->RfClientData));
178  }
179 
180  void DisableRfCallback()
181  {
182  this->Container->SetNewRFImageCallback(NULL, NULL);
183  }
184 
185 
186  // Find the channel that outputs the source.
187  vtkPlusChannel* GetSourceChannel(vtkPlusDataSource* source)
188  {
189  vtkPlusChannel* channel = NULL;
190  for (ChannelContainerConstIterator channelIt = this->External->OutputChannels.begin();
191  channelIt != this->External->OutputChannels.end();
192  ++channelIt)
193  {
194  if (!(*channelIt)->HasVideoSource())
195  {
196  LOG_ERROR("Output channel does not have VideoSource");
197  return channel;
198  }
199  vtkPlusDataSource* channelSource = NULL;
200  (*channelIt)->GetVideoSource(channelSource);
201  if (channelSource == source)
202  {
203  channel = *channelIt;
204  break;
205  }
206  }
207  return channel;
208  }
209 
210 private:
211  HWControlsType* HWControls;
212  ContainerType* Container;
213  IntersonClassType* IntersonClass;
214 
215  BmodeCallbackClientData BmodeClientData;
216  RfCallbackClientData RfClientData;
217 
218  vtkSmartPointer<vtkImageImport> BModeBufferToVtkImage;
219  vtkSmartPointer<vtkImageCast> BModeImageCast;
220  vtkSmartPointer<vtkImageImport> RfBufferToVtkImage;
221 };
222 
223 
224 //----------------------------------------------------------------------------
226  PulseVoltage(30)
227 {
228  this->Internal = new vtkInternal(this);
229 
230  this->StartThreadForInternalUpdates = false;
231 
234 
236 }
237 
238 //----------------------------------------------------------------------------
240 {
241  if (!this->Connected)
242  {
243  this->Disconnect();
244  }
245 
246  delete this->Internal;
247  this->Internal = NULL;
248 }
249 
250 //----------------------------------------------------------------------------
251 void vtkPlusIntersonArraySDKCxxVideoSource::PrintSelf(ostream& os, vtkIndent indent)
252 {
253  this->Superclass::PrintSelf(os, indent);
254 
255  os << indent << "Pulse voltage: " << this->PulseVoltage << "\n";
256 }
257 
258 //----------------------------------------------------------------------------
260 {
261  LOG_TRACE("vtkPlusIntersonArraySDKCxxVideoSource::InternalConnect");
262 
263  HWControlsType* hwControls = this->Internal->GetHWControls();
264 
265  typedef HWControlsType::FoundProbesType FoundProbesType;
266  FoundProbesType foundProbes;
267  hwControls->FindAllProbes(foundProbes);
268  if (foundProbes.empty())
269  {
270  LOG_ERROR("Interson SDK Cxx could not find the probe.");
271  return PLUS_FAIL;
272  }
273  if (foundProbes.size() > 1)
274  {
275  LOG_WARNING("Multiple Interson probes are attached, using the first one");
276  }
277  hwControls->FindMyProbe(0);
278  const unsigned int probeId = hwControls->GetProbeID();
279  LOG_DEBUG("Found probe ID: " << probeId);
280  if (probeId == 0)
281  {
282  LOG_ERROR("Interson Array SDK Cxx could not find the probe.");
283  return PLUS_FAIL;
284  }
285 
286  double frequency = -1;
287  this->ImagingParameters->GetFrequencyMhz(frequency);
288  if (this->SetProbeFrequencyMhz(frequency) == PLUS_FAIL)
289  {
290  return PLUS_FAIL;
291  }
292 
293  if (!hwControls->SendHighVoltage(this->PulseVoltage, this->PulseVoltage))
294  {
295  LOG_ERROR("Could not set the pulse voltage.");
296  return PLUS_FAIL;
297  }
298  if (!hwControls->EnableHighVoltage())
299  {
300  LOG_ERROR("Could not enable high voltage.");
301  return PLUS_FAIL;
302  }
303 
304  double dynamicRangeDb = -1;
305  this->ImagingParameters->GetDynRangeDb(dynamicRangeDb);
306  if (this->SetDynRangeDb(dynamicRangeDb) == PLUS_FAIL)
307  {
308  return PLUS_FAIL;
309  }
310 
311  // TODO: use hardware button
312  hwControls->DisableHardButton();
313 
314  ContainerType* container = this->Internal->GetContainer();
315  container->SetHWControls(hwControls);
316 
317  std::vector<vtkPlusDataSource*> rfSources;
318  vtkPlusDataSource* source = NULL;
320 
321  int width_samples;
322  if (!rfSources.empty())
323  {
324  container->SetRFData(true);
325  width_samples = ContainerType::MAX_RFSAMPLES;
326  }
327  else
328  {
329  container->SetRFData(false);
330  width_samples = ContainerType::MAX_SAMPLES / 2;
331  }
332 
333  LOG_DEBUG("Interson Array SDK version " << this->Internal->GetSdkVersion() <<
334  ", USB probe FPGA version " << hwControls->ReadFPGAVersion());
335 
336  // Even if we do not use their SDK scan converter, we have to initialize the
337  // scan converter to get the probe fully initialized.
338  const int depth = 100;
339  const int heightLines = hwControls->GetLinesPerArray();
340  const int steering = 0;
341  const int compoundAngle = 0;
342  const int depthCfm = 0;
343  const bool cfm = 0;
344  const bool doubler = false;
345  const bool compound = false;
346 
347  if (hwControls->ValidDepth(depth) != depth)
348  {
349  LOG_ERROR("Invalid depth requested: " << depth);
350  return PLUS_FAIL;
351  }
352 
353  auto converterErrorIdle = container->IdleInitScanConverter(depth, width_samples, heightLines, probeId,
354  steering, depthCfm, doubler, compound, compoundAngle, cfm);
355  if (converterErrorIdle != ContainerType::SUCCESS)
356  {
357  LOG_ERROR("Idle scan converter initialization error: " << converterErrorIdle);
358  return PLUS_FAIL;
359  }
360 
361  auto converterErrorHard = container->HardInitScanConverter(depth, width_samples, heightLines, steering, depthCfm);
362  if (converterErrorHard != ContainerType::SUCCESS)
363  {
364  LOG_ERROR("Hard scan converter initialization error: " << converterErrorHard);
365  return PLUS_FAIL;
366  }
367 
368  std::vector<vtkPlusDataSource*> bmodeSources;
370 
371  if (!rfSources.empty())
372  {
373  this->Internal->EnableRfCallback();
374  this->Internal->DisableBModeCallback();
375 
376  source = rfSources[0];
377  // Clear buffer on connect because the new frames that we will acquire might have a different size
378  source->Clear();
379 
380  vtkPlusChannel* channel = this->Internal->GetSourceChannel(source);
381  if (channel == NULL)
382  {
383  LOG_ERROR("Could not find channel for source");
384  return PLUS_FAIL;
385  }
386  else
387  {
388  source->SetPixelType(VTK_UNSIGNED_CHAR);
389  source->SetImageType(US_IMG_RF_REAL);
390  source->SetOutputImageOrientation(US_IMG_ORIENT_FM);
391  source->SetInputFrameSize(ContainerType::MAX_RFSAMPLES,
392  hwControls->GetLinesPerArray(),
393  1);
394  LOG_INFO("RF Pixel type: " << vtkImageScalarTypeNameMacro(source->GetPixelType())
395  << ", device image orientation: "
396  << igsioCommon::GetStringFromUsImageOrientation(source->GetInputImageOrientation())
397  << ", buffer image orientation: "
398  << igsioCommon::GetStringFromUsImageOrientation(source->GetOutputImageOrientation()));
399  }
400 
401  if (!bmodeSources.empty())
402  {
403  LOG_INFO("BMode souces are not empty!!");
404  source = bmodeSources[0];
405  channel = this->Internal->GetSourceChannel(source);
406  if (channel == NULL)
407  {
408  LOG_ERROR("Could not find channel for source");
409  return PLUS_FAIL;
410  }
411 
412  // Clear buffer on connect because the new frames that we will acquire might have a different size
413  source->Clear();
414  source->SetPixelType(VTK_UNSIGNED_CHAR);
415  source->SetImageType(US_IMG_BRIGHTNESS);
416  vtkPlusRfProcessor* rfProcessor = channel->GetRfProcessor();
417  if (rfProcessor != NULL)
418  {
419  channel->SetSaveRfProcessingParameters(true); // RF processing parameters were used, make sure they will be saved into the config file
420  source->SetOutputImageOrientation(US_IMG_ORIENT_MF);
421  vtkPlusUsScanConvert* scanConverter = rfProcessor->GetScanConverter();
422  if (scanConverter != NULL)
423  {
424  int outputExtent[6];
425  scanConverter->GetOutputImageExtent(outputExtent);
426  if (outputExtent[1] - outputExtent[0] + 1 < 0 || outputExtent[3] - outputExtent[2] + 1 < 0)
427  {
428  LOG_ERROR("Invalid extents. Cannot set frame size.");
429  return PLUS_FAIL;
430  }
431  source->SetInputFrameSize(static_cast<unsigned int>(outputExtent[1] - outputExtent[0] + 1),
432  static_cast<unsigned int>(outputExtent[3] - outputExtent[2] + 1),
433  1);
434  }
435  }
436  else
437  {
438  source->SetOutputImageOrientation(US_IMG_ORIENT_FM);
439  source->SetInputFrameSize(ContainerType::MAX_RFSAMPLES,
440  hwControls->GetLinesPerArray(),
441  1);
442  }
443  LOG_INFO("Pixel type: " << vtkImageScalarTypeNameMacro(source->GetPixelType())
444  << ", device image orientation: "
445  << igsioCommon::GetStringFromUsImageOrientation(source->GetInputImageOrientation())
446  << ", buffer image orientation: "
447  << igsioCommon::GetStringFromUsImageOrientation(source->GetOutputImageOrientation()));
448  }
449  }
450  else if (!bmodeSources.empty())
451  {
452  this->Internal->EnableBModeCallback();
453  this->Internal->DisableRfCallback();
454 
455  source = bmodeSources[0];
456  // Clear buffer on connect because the new frames that we will acquire might have a different size
457  source->Clear();
458  source->SetPixelType(VTK_UNSIGNED_CHAR);
459  source->SetImageType(US_IMG_BRIGHTNESS);
460 
461  vtkPlusChannel* channel = this->Internal->GetSourceChannel(source);
462  if (channel == NULL)
463  {
464  LOG_ERROR("Could not find channel for source");
465  return PLUS_FAIL;
466  }
467  else
468  {
469  vtkPlusRfProcessor* rfProcessor = channel->GetRfProcessor();
470  if (rfProcessor != NULL)
471  {
472  vtkPlusUsScanConvert* scanConverter = rfProcessor->GetScanConverter();
473  if (scanConverter != NULL)
474  {
475  channel->SetSaveRfProcessingParameters(true); // RF processing parameters were used, make sure they will be saved into the config file
476  source->SetOutputImageOrientation(US_IMG_ORIENT_MF);
477  int outputExtent[6];
478  scanConverter->GetOutputImageExtent(outputExtent);
479  if (outputExtent[1] - outputExtent[0] + 1 < 0 || outputExtent[3] - outputExtent[2] + 1 < 0)
480  {
481  LOG_ERROR("Invalid extents. Cannot set frame size.");
482  return PLUS_FAIL;
483  }
484  source->SetInputFrameSize(outputExtent[1] - outputExtent[0] + 1,
485  outputExtent[3] - outputExtent[2] + 1,
486  1);
487  }
488  else
489  {
490  LOG_ERROR("Did not find expected scan converter parameters.");
491  return PLUS_FAIL;
492  }
493  }
494  else
495  {
496  source->SetOutputImageOrientation(US_IMG_ORIENT_MF);
497  source->SetInputFrameSize(ContainerType::MAX_SAMPLES / 2,
498  hwControls->GetLinesPerArray(),
499  1);
500  }
501  }
502 
503  LOG_INFO("BMode Pixel type: " << vtkImageScalarTypeNameMacro(source->GetPixelType())
504  << ", device image orientation: "
505  << igsioCommon::GetStringFromUsImageOrientation(source->GetInputImageOrientation())
506  << ", buffer image orientation: "
507  << igsioCommon::GetStringFromUsImageOrientation(source->GetOutputImageOrientation()));
508  }
509  else
510  {
511  LOG_ERROR("Expected an RF or BMode port not found");
512  return PLUS_FAIL;
513  }
514 
515  return PLUS_SUCCESS;
516 }
517 
518 
519 //----------------------------------------------------------------------------
521 {
522  LOG_DEBUG("Disconnect from Interson");
523 
524  HWControlsType* hwControls = this->Internal->GetHWControls();
525  hwControls->DisableHighVoltage();
526 
527  this->StopRecording();
528  ContainerType* container = this->Internal->GetContainer();
529 
530  return PLUS_SUCCESS;
531 }
532 
533 //----------------------------------------------------------------------------
535 {
536  ContainerType* container = this->Internal->GetContainer();
537 
538  HWControlsType* hwControls = this->Internal->GetHWControls();
539 
540  std::vector<vtkPlusDataSource*> bmodeSources;
541  std::vector<vtkPlusDataSource*> rfSources;
544 
545  if (!rfSources.empty())
546  {
547  container->StartRFReadScan();
548  }
549  else if (!bmodeSources.empty())
550  {
551  container->StartReadScan();
552  }
553  Sleep(100); // "time to start"
554 
555  if (!rfSources.empty() && !hwControls->StartRFmode())
556  {
557  LOG_ERROR("Could not start RF collection.");
558  return PLUS_FAIL;
559  }
560  else if (!bmodeSources.empty() && !hwControls->StartBmode())
561  {
562  LOG_ERROR("Could not start B-mode collection.");
563  return PLUS_FAIL;
564  }
565  Sleep(750); // "time to start"
566 
567  return PLUS_SUCCESS;
568 }
569 
570 //----------------------------------------------------------------------------
572 {
573  HWControlsType* hwControls = this->Internal->GetHWControls();
574  if (!hwControls->StopAcquisition())
575  {
576  LOG_ERROR("Could not stop acquisition.");
577  return PLUS_FAIL;
578  }
579 
580  ContainerType* container = this->Internal->GetContainer();
581  container->StopReadScan();
582  Sleep(100); // "time to stop"
583 
584  return PLUS_SUCCESS;
585 }
586 
587 //----------------------------------------------------------------------------
589 {
591  {
592  return PLUS_FAIL;
593  }
594 
595  return PLUS_SUCCESS;
596 }
597 
598 //-----------------------------------------------------------------------------
600 {
601  LOG_TRACE("vtkPlusIntersonArraySDKCxxVideoSource::ReadConfiguration");
602  if (config == NULL)
603  {
604  LOG_ERROR("Unable to configure Interson Array video source! (XML data element is NULL)");
605  return PLUS_FAIL;
606  }
607 
609 
610  vtkXMLDataElement* deviceConfig = this->FindThisDeviceElement(config);
611  if (deviceConfig == NULL)
612  {
613  LOG_ERROR("Unable to find ImageAcquisition element in configuration XML structure!");
614  return PLUS_FAIL;
615  }
616 
617  double dynRange = -1.0;
618  if (deviceConfig->GetScalarAttribute("DynRangeDb", dynRange))
619  {
620  this->ImagingParameters->SetDynRangeDb(dynRange);
621  }
622 
623  double frequency = -1.0;
624  if (deviceConfig->GetScalarAttribute("FrequencyMhz", frequency))
625  {
626  this->ImagingParameters->SetFrequencyMhz(frequency);
627  }
628 
629  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(int, PulseVoltage, deviceConfig);
630 
631  return PLUS_SUCCESS;
632 }
633 
634 //-----------------------------------------------------------------------------
636 {
637  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
638  deviceConfig->SetIntAttribute("PulseVoltage", this->GetPulseVoltage());
639 
640  return PLUS_SUCCESS;
641 }
642 
643 //----------------------------------------------------------------------------
645 {
646  if (this->OutputChannels.size() > 2)
647  {
648  LOG_WARNING("vtkPlusIntersonArraySDKCxxVideoSource is expecting at most two output channels and there are " << this->OutputChannels.size() << " channels.");
649  }
650 
651  if (this->OutputChannels.empty())
652  {
653  LOG_ERROR("No output channels defined for vtkPlusIntersonArraySDKCxxVideoSource. Cannot proceed.");
654  this->CorrectlyConfigured = false;
655  return PLUS_FAIL;
656  }
657 
658  return PLUS_SUCCESS;
659 }
660 
661 //----------------------------------------------------------------------------
663 {
664  return this->Internal->GetSdkVersion();
665 }
666 
667 //----------------------------------------------------------------------------
669 {
670  if (voltage != this->PulseVoltage)
671  {
672  this->PulseVoltage = voltage;
673  this->Modified();
674  }
675 
676  return PLUS_SUCCESS;
677 }
678 
679 //----------------------------------------------------------------------------
681 {
682  int frequency = static_cast<int>(freq * 1e6);
683 
684  HWControlsType* hwControls = this->Internal->GetHWControls();
685  HWControlsType::FrequenciesType supportedFrequencies;
686  hwControls->GetFrequency(supportedFrequencies);
687  // Set to the closest frequency value.
688  unsigned int frequencyIndex = 0;
689  if (frequency <= supportedFrequencies[0])
690  {
691  frequencyIndex = 0;
692  }
693  const size_t numSupportedFrequencies = supportedFrequencies.size();
694  if (frequency >= supportedFrequencies[numSupportedFrequencies - 1])
695  {
696  frequencyIndex = numSupportedFrequencies - 1;
697  }
698  for (size_t ii = 1; ii < numSupportedFrequencies - 1; ++ii)
699  {
700  const int lower = supportedFrequencies[ii - 1] +
701  (supportedFrequencies[ii] - supportedFrequencies[ii - 1]) / 2;
702  if (frequency <= lower)
703  {
704  frequencyIndex = ii - 1;
705  break;
706  }
707  const int upper = supportedFrequencies[ii] +
708  (supportedFrequencies[ii + 1] - supportedFrequencies[ii]) / 2;
709  if (frequency < upper)
710  {
711  frequencyIndex = ii;
712  break;
713  }
714  frequencyIndex = ii + 1;
715  }
716  frequency = supportedFrequencies[frequencyIndex];
717  LOG_DEBUG("Current frequency is " << frequency / 1.0e6);
718 
719  const int focusIndex = 0;
720  const int steering = 0;
721  if (!hwControls->SetFrequencyAndFocus(frequencyIndex, focusIndex, steering))
722  {
723  LOG_ERROR("Could not set the frequency.");
724  return PLUS_FAIL;
725  }
726 
727  this->ImagingParameters->SetFrequencyMhz(static_cast<double>(frequency / 1.0e6));
728 
729  return PLUS_SUCCESS;
730 }
731 
732 //----------------------------------------------------------------------------
734 {
735  unsigned char usedGain = 100;
736  if (dynRangeDb > 0.0)
737  {
738  usedGain = static_cast<unsigned char>(255 * dynRangeDb);
739  }
740  HWControlsType* hwControls = this->Internal->GetHWControls();
741  if (!hwControls->SendDynamic(usedGain))
742  {
743  LOG_ERROR("Could not set dynamic gain.");
744  return PLUS_FAIL;
745  }
746  return PLUS_SUCCESS;
747 }
748 
749 //----------------------------------------------------------------------------
750 PlusStatus vtkPlusIntersonArraySDKCxxVideoSource::AddBmodeFrameToBuffer(BmodePixelType* buffer, void* clientData)
751 {
752  if (!this->Recording)
753  {
754  // drop the frame, we are not recording data now
755  return PLUS_SUCCESS;
756  }
757 
758  HWControlsType* hwControls = this->Internal->GetHWControls();
759  if (hwControls->ReadHardButton())
760  {
761  // TODO: add support for sending the button press info through OpenIGTLink
762  }
763 
764  vtkImageData* bufferVtkImageData = NULL;
765  ++this->FrameNumber;
766 
767  std::vector<vtkPlusDataSource*> sources;
768  vtkPlusDataSource* source = NULL;
770  if (!sources.empty())
771  {
772  source = sources[0];
773  }
774  else
775  {
776  LOG_ERROR("Expected Bmode port not found");
777  return PLUS_FAIL;
778  }
779 
780  vtkPlusChannel* channel = this->Internal->GetSourceChannel(source);
781 
782  vtkPlusRfProcessor* rfProcessor = channel->GetRfProcessor();
783  if (rfProcessor != NULL)
784  {
785  vtkPlusUsScanConvert* scanConverter = rfProcessor->GetScanConverter();
786  if (scanConverter != NULL)
787  {
788  scanConverter->SetInputData(this->Internal->ConvertBModeBufferToVtkImage(buffer));
789  scanConverter->Modified();
790  scanConverter->Update();
791  bufferVtkImageData = scanConverter->GetOutput();
792  }
793  }
794  else
795  {
796  bufferVtkImageData = this->Internal->ConvertBModeBufferToVtkImage(buffer);
797  }
798 
799  const PlusStatus status = source->AddItem(bufferVtkImageData,
800  source->GetInputImageOrientation(),
801  US_IMG_BRIGHTNESS,
802  this->FrameNumber);
803 
804  this->Modified();
805 
806  return status;
807 }
808 
809 //----------------------------------------------------------------------------
810 PlusStatus vtkPlusIntersonArraySDKCxxVideoSource::AddRfFrameToBuffer(RfPixelType* buffer, void* clientData)
811 {
812  if (!this->Recording)
813  {
814  // drop the frame, we are not recording data now
815  return PLUS_SUCCESS;
816  }
817 
818  HWControlsType* hwControls = this->Internal->GetHWControls();
819  if (hwControls->ReadHardButton())
820  {
821  // TODO: add support for sending the button press info through OpenIGTLink
822  }
823 
824  ++this->FrameNumber;
825 
826  std::vector<vtkPlusDataSource*> rfSources;
827  vtkPlusDataSource* source = NULL;
829  if (!rfSources.empty())
830  {
831  source = rfSources[0];
832  }
833  else
834  {
835  LOG_ERROR("Expected RF port not found");
836  return PLUS_FAIL;
837  }
838 
839  vtkPlusChannel* channel = this->Internal->GetSourceChannel(source);
840 
841  vtkImageData* rfBufferVtkImageData = this->Internal->ConvertRfBufferToVtkImage(buffer);
842  if (source->AddItem(rfBufferVtkImageData,
843  source->GetInputImageOrientation(),
844  US_IMG_RF_REAL,
845  this->FrameNumber) == PLUS_FAIL)
846  {
847  LOG_ERROR("Failed to add RF frame to buffer");
848  return PLUS_FAIL;
849  }
850 
851  std::vector<vtkPlusDataSource*> bmodeSources;
853  if (!bmodeSources.empty())
854  {
855  source = bmodeSources[0];
856  channel = this->Internal->GetSourceChannel(source);
857  vtkPlusRfProcessor* rfProcessor = channel->GetRfProcessor();
858  if (rfProcessor != NULL)
859  {
860  rfProcessor->SetRfFrame(rfBufferVtkImageData,
861  US_IMG_RF_REAL);
862  rfProcessor->GetRfToBrightnessConverter()->Modified();
863  vtkPlusUsScanConvert* scanConverter = rfProcessor->GetScanConverter();
864  vtkImageData* bmodeBufferVtkImageData = NULL;
865  if (scanConverter != NULL)
866  {
867  bmodeBufferVtkImageData = rfProcessor->GetBrightnessScanConvertedImage();
868  }
869  else
870  {
871  bmodeBufferVtkImageData = rfProcessor->GetBrightnessConvertedImage();
872  }
873  if (source->AddItem(bmodeBufferVtkImageData,
874  source->GetInputImageOrientation(),
875  US_IMG_BRIGHTNESS,
876  this->FrameNumber) == PLUS_FAIL)
877  {
878  LOG_ERROR("Failed to add BMode frame to buffer.");
879  return PLUS_FAIL;
880  }
881  }
882  else
883  {
884  LOG_ERROR("Expected RfProcessor not found.");
885  return PLUS_FAIL;
886  }
887  }
888 
889  this->Modified();
890 
891  return PLUS_SUCCESS;
892 }
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
int * channel
Definition: phidget22.h:1303
static const std::string RFMODE_PORT_NAME
Definition: vtkPlusDevice.h:68
virtual vtkPlusRfToBrightnessConvert * GetRfToBrightnessConverter()
PhidgetRCServo_Voltage voltage
Definition: phidget22.h:3331
const char * source
Definition: phidget22.h:2461
vtkStandardNewMacro(vtkPlusIntersonArraySDKCxxVideoSource)
IntersonArrayCxx::Controls::HWControls HWControlsType
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
static const std::string BMODE_PORT_NAME
Definition: vtkPlusDevice.h:67
virtual vtkPlusUsScanConvert * GetScanConverter()
bool RequirePortNameInDeviceSetConfiguration
bool RequireImageOrientationInConfiguration
Class for acquiring ultrasound images from Interson Array USB ultrasound systems with C++ Wrapped SDK...
virtual vtkImageData * GetBrightnessScanConvertedImage()
#define PLUS_FAIL
Definition: PlusCommon.h:43
PlusStatus GetVideoSourcesByPortName(const char *aPortName, std::vector< vtkPlusDataSource * > &sources)
virtual PlusStatus SetRfFrame(vtkImageData *rfFrame, US_IMAGE_TYPE imageType)
virtual PlusStatus Disconnect()
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *)
unsigned long FrameNumber
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
vtkXMLDataElement * FindThisDeviceElement(vtkXMLDataElement *rootXMLElement)
ChannelContainer::const_iterator ChannelContainerConstIterator
Definition: vtkPlusDevice.h:35
virtual PlusStatus StopRecording()
IntersonArrayCxx::IntersonClass IntersonClassType
PlusStatus GetDynRangeDb(double &aDynRangeDb) const
static vtkPlusUsImagingParameters * New()
PlusStatus SetDynRangeDb(double aDynRangeDb)
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
virtual int * GetOutputImageExtent()
Convenience class to combine multiple algorithms to compute a displayable B-mode frame from RF data.
bool StartThreadForInternalUpdates
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
PlusStatus SetFrequencyMhz(double aFrequencyMhz)
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
virtual unsigned char GetPulseVoltage()
virtual void SetInputData(vtkDataObject *input)
ChannelContainer OutputChannels
PlusStatus GetFrequencyMhz(double &aFrequencyMhz) const
This is a base class for defining a common scan conversion algorithm interface for all kinds of probe...
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
double frequency
Definition: phidget22.h:3246
virtual vtkImageData * GetOutput()=0
virtual PlusStatus InternalUpdate()
IntersonArrayCxx::Imaging::Container ContainerType
virtual vtkImageData * GetBrightnessConvertedImage()
bool CorrectlyConfigured
Interface to a 3D positioning tool, video source, or generalized data stream.