PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkIntersonArraySDKCxxVideoSourceTest.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 
18 #include "PlusConfigure.h"
19 #include "vtkAxis.h"
20 #include "vtkCallbackCommand.h"
21 #include "vtkChartXY.h"
22 #include "vtkCommand.h"
23 #include "vtkContextScene.h"
24 #include "vtkContextView.h"
25 #include "vtkFloatArray.h"
26 #include "vtkImageData.h"
27 #include "vtkImageViewer.h"
28 #include "vtkInformation.h"
29 #include "vtkInformationVector.h"
30 #include "vtkPlot.h"
31 #include "vtkRenderWindow.h"
32 #include "vtkRenderWindowInteractor.h"
33 #include "vtkRenderer.h"
34 #include "vtkSmartPointer.h"
36 #include "vtkTable.h"
37 #include "vtkTableAlgorithm.h"
38 #include "vtkXMLUtilities.h"
39 #include "vtksys/CommandLineArguments.hxx"
40 #include <stdlib.h>
41 
42 //----------------------------------------------------------------------------
43 
45 {
48 };
49 
50 //----------------------------------------------------------------------------
51 
52 class vtkExtractImageRow : public vtkTableAlgorithm
53 {
54 public:
55  static vtkExtractImageRow* New();
56  vtkTypeMacro(vtkExtractImageRow,vtkTableAlgorithm);
57  void PrintSelf(ostream& os, vtkIndent indent)
58  {
59  this->Superclass::PrintSelf(os, indent);
60  }
61 
62  // Description:
63  // Specify the first vtkGraph input and the second vtkSelection input.
64  int FillInputPortInformation(int port, vtkInformation* info)
65  {
66  if (port == 0)
67  {
68  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
69  return 1;
70  }
71  return 0;
72  }
73 
74 protected:
75  vtkExtractImageRow()
76  {
77  this->SetNumberOfInputPorts(1);
78  }
79  virtual ~vtkExtractImageRow()
80  {
81  }
82 
83  int RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector)
84  {
85  vtkImageData* inputImage = vtkImageData::GetData(inputVector[0]);
86  vtkInformation* outInfo = outputVector->GetInformationObject(0);
87  vtkTable* outputTable = vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
88 
89  if(!inputImage)
90  {
91  LOG_ERROR("No input image is available");
92  return 0;
93  }
94 
95  // Create the tables if they haven't been created yet
96  if (outputTable->GetColumnByName("time")==NULL)
97  {
98  vtkSmartPointer<vtkFloatArray> arrXnew = vtkSmartPointer<vtkFloatArray>::New();
99  arrXnew->SetName("time");
100  outputTable->AddColumn(arrXnew);
101  }
102  if (outputTable->GetColumnByName("RF value")==NULL)
103  {
104  vtkSmartPointer<vtkFloatArray> arrRfValNew = vtkSmartPointer<vtkFloatArray>::New();
105  arrRfValNew->SetName("RF value");
106  outputTable->AddColumn(arrRfValNew);
107  }
108 
109  if (inputImage->GetScalarType() != VTK_SHORT)
110  {
111  LOG_ERROR("Plotting is only supported for signed short data");
112  return 0;
113  }
114  int rowCount=inputImage->GetDimensions()[1]; // number of transducer crystals
115  int numPoints=inputImage->GetDimensions()[0]; // number of data points (RF data values) recorded for one crystal
116  int selectedRow=rowCount/2; // plot the center column of the image
117  short* pixelBuffer=reinterpret_cast<short*>(inputImage->GetScalarPointer())+selectedRow*numPoints;
118 
119  outputTable->SetNumberOfRows(numPoints);
120  int timeIndex=numPoints-1; // the RF data set starts with the latest time
121  for (int i = 0; i < numPoints; ++i)
122  {
123  outputTable->SetValue(i, 0, timeIndex);
124  short value=*pixelBuffer;
125  outputTable->SetValue(i, 1, value);
126  pixelBuffer++;
127  timeIndex--;
128  }
129 
130  return 1;
131  }
132 
133 private:
134  vtkExtractImageRow(const vtkExtractImageRow&); // Not implemented
135  void operator=(const vtkExtractImageRow&); // Not implemented
136 };
137 
138 vtkStandardNewMacro(vtkExtractImageRow);
139 
140 //---------------------------------------------------------------------------------
141 
142 class vtkMyPlotCallback : public vtkCommand
143 {
144 public:
145  static vtkMyPlotCallback *New() { return new vtkMyPlotCallback; }
146 
147  virtual void Execute(vtkObject *caller, unsigned long eventId, void* callData)
148  {
149  if (eventId==vtkCommand::KeyPressEvent)
150  {
151  if (m_Interactor->GetKeyCode()=='q')
152  {
153  m_Interactor->ExitCallback();
154  }
155  return;
156  }
157 
158  m_ImageToTableAdaptor->Update();
159  m_Viewer->Render();
160  //update the timer so it will trigger again
161  m_Interactor->CreateTimer(VTKI_TIMER_UPDATE);
162  }
163 
164  vtkRenderWindowInteractor *m_Interactor;
165  vtkContextView *m_Viewer;
166  vtkExtractImageRow *m_ImageToTableAdaptor;
167 
168 private:
169 
170  vtkMyPlotCallback()
171  {
172  m_Interactor=NULL;
173  m_Viewer=NULL;
174  m_ImageToTableAdaptor=NULL;
175  }
176 };
177 
178 //----------------------------------------------------------------------------
180 {
181  // Set up a 2D scene, add an XY chart to it
182  vtkSmartPointer<vtkContextView> view = vtkSmartPointer<vtkContextView>::New();
183  view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
184  view->GetRenderWindow()->SetSize(1200, 400);
185  vtkSmartPointer<vtkChartXY> chart = vtkSmartPointer<vtkChartXY>::New();
186  view->GetScene()->AddItem(chart);
187 
188  vtkSmartPointer<vtkExtractImageRow> imageToTableAdaptor=vtkSmartPointer<vtkExtractImageRow>::New();
189  imageToTableAdaptor->SetInputConnection(intersonDevice->GetOutputPort());
190  imageToTableAdaptor->Update();
191 
192  // Add multiple line plots, setting the colors etc
193  vtkPlot *line = chart->AddPlot(vtkChart::LINE);
194  line->SetInputData(imageToTableAdaptor->GetOutput(), 0, 1);
195  line->SetColor(0, 255, 0, 255);
196  line->SetWidth(1.0);
197 
198  vtkAxis * yAxis = line->GetYAxis();
199  yAxis->SetBehavior(vtkAxis::FIXED);
200  yAxis->SetMinimumLimit( -32768 );
201  yAxis->SetMaximumLimit( 32767 );
202  yAxis->SetMinimum( -32768 );
203  yAxis->SetMaximum( 32767 );
204 
205  vtkSmartPointer<vtkMyPlotCallback> call = vtkSmartPointer<vtkMyPlotCallback>::New();
206  call->m_Interactor=view->GetInteractor();
207  call->m_Viewer=view;
208  call->m_ImageToTableAdaptor=imageToTableAdaptor;
209 
210  view->GetInteractor()->Initialize();
211 
212  view->GetInteractor()->AddObserver(vtkCommand::TimerEvent, call);
213  view->GetInteractor()->CreateTimer(VTKI_TIMER_FIRST);
214 
215  view->GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, call);
216 
217  view->GetInteractor()->Start();
218 
219 }
220 
221 //---------------------------------------------------------------------------------
222 
223 class vtkMyCallback : public vtkCommand
224 {
225 public:
226  static vtkMyCallback *New() { return new vtkMyCallback; }
227 
228  virtual void Execute(vtkObject *caller, unsigned long, void*)
229  {
230  m_Viewer->Render();
231 
232  //update the timer so it will trigger again
233  m_Interactor->CreateTimer(VTKI_TIMER_UPDATE);
234  }
235 
236  vtkRenderWindowInteractor *m_Interactor;
237  vtkImageViewer *m_Viewer;
238 
239 private:
240 
241  vtkMyCallback()
242  {
243  m_Interactor=NULL;
244  m_Viewer=NULL;
245  }
246 };
247 
248 //-------------------------------------------------------------------------------------------
249 
250 int main(int argc, char* argv[])
251 {
252  bool printHelp(false);
253  bool renderingOff(false);
254  std::string inputConfigFileName;
255  double depthCm = -1;
256  double dynRangeDb = -1;
257  double frequencyMhz = -1;
258 
259  std::string acqMode("B");
260 
261  vtksys::CommandLineArguments args;
262  args.Initialize(argc, argv);
263 
264  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
265 
266  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
267  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFileName, "Config file containing the device configuration.");
268  args.AddArgument("--acq-mode", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &acqMode, "Acquisition mode: B or RF (Default: B).");
269  args.AddArgument("--depth", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &depthCm, "Depth in cm.");
270  args.AddArgument("--frequencyMhz", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &frequencyMhz, "Frequency in MHz");
271  args.AddArgument("--dynRangeDb", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &dynRangeDb, "BMode Dynamic Range. 1 corresponds to the maximum dynamic range.");
272  args.AddArgument("--rendering-off", vtksys::CommandLineArguments::NO_ARGUMENT, &renderingOff, "Run test without rendering.");
273  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level 1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
274 
275  if ( !args.Parse() )
276  {
277  std::cerr << "Problem parsing arguments" << std::endl;
278  std::cout << "\n\nvtkPlusIntersonArraySDKCxxVideoSourceTest help:" << args.GetHelp() << std::endl;
279  exit(EXIT_FAILURE);
280  }
281 
282  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
283 
284  if ( printHelp )
285  {
286  std::cout << "\n\nvtkPlusIntersonArraySDKCxxVideoSourceTest help:" << args.GetHelp() << std::endl;
287  exit(EXIT_SUCCESS);
288  }
289 
290  vtkSmartPointer<vtkPlusIntersonArraySDKCxxVideoSource> intersonDevice =
291  vtkSmartPointer<vtkPlusIntersonArraySDKCxxVideoSource>::New();
292  intersonDevice->SetDeviceId("VideoDevice");
293 
294  // Read config file
295  if( STRCASECMP(inputConfigFileName.c_str(), "") != 0 )
296  {
297  LOG_DEBUG("Reading config file...");
298  vtkSmartPointer<vtkXMLDataElement> configRootElement = vtkSmartPointer<vtkXMLDataElement>::New();
299  if (PlusXmlUtils::ReadDeviceSetConfigurationFromFile(configRootElement, inputConfigFileName.c_str())==PLUS_FAIL)
300  {
301  LOG_ERROR("Unable to read configuration from file " << inputConfigFileName.c_str());
302  return EXIT_FAILURE;
303  }
304  intersonDevice->ReadConfiguration(configRootElement);
305  }
306 
307  DisplayMode displayMode = SHOW_IMAGE;
308 
309  if (STRCASECMP(acqMode.c_str(), "B")==0)
310  {
311  LOG_DEBUG("Acquisition mode: B");
312  displayMode = SHOW_IMAGE;
313  }
314  else if (STRCASECMP(acqMode.c_str(), "RF")==0)
315  {
316  LOG_DEBUG("Acquisition mode: RF");
317  displayMode=SHOW_PLOT;
318  }
319  else
320  {
321  LOG_ERROR("Unsupported Acquisition mode requested: " << acqMode);
322  exit(EXIT_FAILURE);
323  }
324 
325  if ( intersonDevice->Connect() != PLUS_SUCCESS )
326  {
327  LOG_ERROR( "Unable to connect to Interson Probe" );
328  exit(EXIT_FAILURE);
329  }
330 
331  intersonDevice->StartRecording(); // start recording frames for the video
332 
333  if( renderingOff )
334  {
335  // just run the recording for a few seconds then exit
336  LOG_DEBUG("Rendering disabled. Wait for just a few seconds to acquire data before exiting");
337  Sleep(3000); // no need to use accurate timer, it's just an approximate delay
338  }
339  else
340  {
341  if( displayMode == SHOW_PLOT )
342  {
343  TestLinePlot(intersonDevice);
344  }
345  else
346  {
347  // Show the live ultrasound image in a VTK renderer window
348  vtkSmartPointer<vtkImageViewer> viewer = vtkSmartPointer<vtkImageViewer>::New();
349  viewer->SetInputConnection(intersonDevice->GetOutputPort()); //set image to the render and window
350  viewer->SetColorWindow(255);
351  viewer->SetColorLevel(127.5);
352  viewer->SetZSlice(0);
353 
354  //Create the interactor that handles the event loop
355  vtkSmartPointer<vtkRenderWindowInteractor> iren = vtkSmartPointer<vtkRenderWindowInteractor>::New();
356  iren->SetRenderWindow(viewer->GetRenderWindow());
357  viewer->SetupInteractor(iren);
358 
359  viewer->Render(); //must be called after iren and viewer are linked or there will be problems
360 
361  // Establish timer event and create timer to update the live image
362  vtkSmartPointer<vtkMyCallback> call = vtkSmartPointer<vtkMyCallback>::New();
363  call->m_Interactor=iren;
364  call->m_Viewer=viewer;
365  iren->AddObserver(vtkCommand::TimerEvent, call);
366  iren->CreateTimer(VTKI_TIMER_FIRST);
367 
368  //iren must be initialized so that it can handle events
369  iren->Initialize();
370  iren->Start();
371  }
372  }
373 
374  intersonDevice->StopRecording();
375  intersonDevice->Disconnect();
376  return EXIT_SUCCESS;
377 }
378 
const char int line
Definition: phidget22.h:2458
vtkRenderWindowInteractor * iren
Class for acquiring ultrasound images from Interson Array USB ultrasound systems with C++ Wrapped SDK...
for i
#define PLUS_FAIL
Definition: PlusCommon.h:43
int port
Definition: phidget22.h:2454
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
int main(int argc, char *argv[])
vtkImageViewer * viewer
void TestLinePlot(vtkPlusIntersonArraySDKCxxVideoSource *intersonDevice)
const char const char * value
Definition: phidget22.h:5111
static vtkIGSIOLogger * Instance()
vtkStandardNewMacro(vtkExtractImageRow)
static PlusStatus ReadDeviceSetConfigurationFromFile(vtkXMLDataElement *config, const char *filename)
Definition: PlusXmlUtils.h:23