PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkThorLabsVideoSourceTest.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 "vtkCallbackCommand.h"
20 #include "vtkChartXY.h"
21 #include "vtkCommand.h"
22 #include "vtkContextScene.h"
23 #ifdef PLUS_RENDERING_ENABLED
24 #include "vtkContextView.h"
25 #endif
26 #include "vtkFloatArray.h"
27 #include "vtkImageData.h"
28 #ifdef PLUS_RENDERING_ENABLED
29 #include "vtkImageViewer.h"
30 #endif
31 #include "vtkInformation.h"
32 #include "vtkInformationVector.h"
33 #include "vtkPlot.h"
34 #include "vtkPlusChannel.h"
35 #include "vtkRenderWindow.h"
36 #include "vtkRenderWindowInteractor.h"
37 #include "vtkRenderer.h"
38 #include "vtkSmartPointer.h"
40 #include "vtkTable.h"
41 #include "vtkTableAlgorithm.h"
43 #include "vtkXMLUtilities.h"
44 #include "vtksys/CommandLineArguments.hxx"
45 #include <stdlib.h>
46 
47 //----------------------------------------------------------------------------
48 
49 //----------------------------------------------------------------------------
50 
51 class vtkExtractImageRow : public vtkTableAlgorithm
52 {
53 public:
54  static vtkExtractImageRow* New();
55  vtkTypeMacro(vtkExtractImageRow,vtkTableAlgorithm);
56  void PrintSelf(ostream& os, vtkIndent indent)
57  {
58  this->Superclass::PrintSelf(os, indent);
59  }
60 
61  // Description:
62  // Specify the first vtkGraph input and the second vtkSelection input.
63  int FillInputPortInformation(int port, vtkInformation* info)
64  {
65  if (port == 0)
66  {
67  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
68  return 1;
69  }
70  return 0;
71  }
72 
73 protected:
74  vtkExtractImageRow()
75  {
76  this->SetNumberOfInputPorts(1);
77  }
78  virtual ~vtkExtractImageRow()
79  {
80  }
81 
82  int RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector)
83  {
84  vtkImageData* inputImage = vtkImageData::GetData(inputVector[0]);
85  vtkInformation* outInfo = outputVector->GetInformationObject(0);
86  vtkTable* outputTable = vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
87 
88  if(!inputImage)
89  {
90  LOG_ERROR("No input image is available");
91  return 0;
92  }
93 
94  // Create the tables if they haven't been created yet
95  if (outputTable->GetColumnByName("wavelength")==NULL)
96  {
97  vtkSmartPointer<vtkFloatArray> arrXnew = vtkSmartPointer<vtkFloatArray>::New();
98  arrXnew->SetName("wavelength");
99  outputTable->AddColumn(arrXnew);
100  }
101  if (outputTable->GetColumnByName("Intensity")==NULL)
102  {
103  vtkSmartPointer<vtkFloatArray> arrRfValNew = vtkSmartPointer<vtkFloatArray>::New();
104  arrRfValNew->SetName("Intensity");
105  outputTable->AddColumn(arrRfValNew);
106  }
107 
108  int rowCount=inputImage->GetDimensions()[1];
109  if (rowCount!=2)
110  {
111  LOG_ERROR("Expected two rows in the input image, found "<<rowCount);
112  return 0;
113  }
114  int numPoints=inputImage->GetDimensions()[0];
115  int wavelengthRow=0;
116  int intensityRow=1;
117 
118  outputTable->SetNumberOfRows(numPoints);
119  if (inputImage->GetScalarType()==VTK_FLOAT)
120  {
121  float* wavelengthBuffer=reinterpret_cast<float*>(inputImage->GetScalarPointer())+wavelengthRow*numPoints;
122  float* intensityBuffer=reinterpret_cast<float*>(inputImage->GetScalarPointer())+intensityRow*numPoints;
123  for (int i = 0; i < numPoints; ++i)
124  {
125  outputTable->SetValue(i, 0, *(wavelengthBuffer++));
126  outputTable->SetValue(i, 1, *(intensityBuffer++));
127  }
128  }
129  else if (inputImage->GetScalarType()==VTK_DOUBLE)
130  {
131  double* wavelengthBuffer=reinterpret_cast<double*>(inputImage->GetScalarPointer())+wavelengthRow*numPoints;
132  double* intensityBuffer=reinterpret_cast<double*>(inputImage->GetScalarPointer())+intensityRow*numPoints;
133  for (int i = 0; i < numPoints; ++i)
134  {
135  outputTable->SetValue(i, 0, *(wavelengthBuffer++));
136  outputTable->SetValue(i, 1, *(intensityBuffer++));
137  }
138  }
139  else
140  {
141  LOG_ERROR("Plotting is only supported for float and double data");
142  return 0;
143  }
144 
145  return 1;
146  }
147 
148 private:
149  vtkExtractImageRow(const vtkExtractImageRow&); // Not implemented
150  void operator=(const vtkExtractImageRow&); // Not implemented
151 };
152 
153 vtkStandardNewMacro(vtkExtractImageRow);
154 
155 #ifdef PLUS_RENDERING_ENABLED
156 //---------------------------------------------------------------------------------
157 class vtkMyPlotCallback : public vtkCommand
158 {
159 public:
160  static vtkMyPlotCallback *New() { return new vtkMyPlotCallback; }
161 
162  virtual void Execute(vtkObject *caller, unsigned long eventId, void* callData)
163  {
164  if (eventId==vtkCommand::KeyPressEvent)
165  {
166  if (m_Interactor->GetKeyCode()=='q')
167  {
168  m_Interactor->ExitCallback();
169  }
170  return;
171  }
172 
173  m_ImageToTableAdaptor->Update();
174  m_Viewer->Render();
175  //update the timer so it will trigger again
176  m_Interactor->CreateTimer(VTKI_TIMER_UPDATE);
177  }
178 
179  vtkRenderWindowInteractor *m_Interactor;
180  vtkContextView *m_Viewer;
181  vtkExtractImageRow *m_ImageToTableAdaptor;
182 
183 private:
184 
185  vtkMyPlotCallback()
186  {
187  m_Interactor=NULL;
188  m_Viewer=NULL;
189  m_ImageToTableAdaptor=NULL;
190  }
191 };
192 
193 //----------------------------------------------------------------------------
194 void TestLinePlot(vtkPlusThorLabsVideoSource *spectrometer)
195 {
196  // Set up a 2D scene, add an XY chart to it
197  vtkSmartPointer<vtkContextView> view = vtkSmartPointer<vtkContextView>::New();
198  view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
199  view->GetRenderWindow()->SetSize(400, 300);
200  vtkSmartPointer<vtkChartXY> chart = vtkSmartPointer<vtkChartXY>::New();
201  view->GetScene()->AddItem(chart);
202 
203  vtkSmartPointer<vtkExtractImageRow> imageToTableAdaptor=vtkSmartPointer<vtkExtractImageRow>::New();
204  imageToTableAdaptor->SetInputConnection(spectrometer->GetOutputPort());
205  imageToTableAdaptor->Update();
206 
207  // Add multiple line plots, setting the colors etc
208  vtkPlot *line = chart->AddPlot(vtkChart::LINE);
209  line->SetInputData(imageToTableAdaptor->GetOutput(), 0, 1);
210  line->SetColor(0, 255, 0, 255);
211  line->SetWidth(1.0);
212 
213  vtkSmartPointer<vtkMyPlotCallback> call = vtkSmartPointer<vtkMyPlotCallback>::New();
214  call->m_Interactor=view->GetInteractor();
215  call->m_Viewer=view;
216  call->m_ImageToTableAdaptor=imageToTableAdaptor;
217 
218  view->GetInteractor()->Initialize();
219 
220  view->GetInteractor()->AddObserver(vtkCommand::TimerEvent, call);
221  view->GetInteractor()->CreateTimer(VTKI_TIMER_FIRST);
222 
223  view->GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, call);
224 
225  view->GetInteractor()->Start();
226 
227 }
228 
229 //---------------------------------------------------------------------------------
230 
231 class vtkMyCallback : public vtkCommand
232 {
233 public:
234  static vtkMyCallback *New() { return new vtkMyCallback; }
235 
236  virtual void Execute(vtkObject *caller, unsigned long, void*)
237  {
238  m_Viewer->Render();
239 
240  //update the timer so it will trigger again
241  m_Interactor->CreateTimer(VTKI_TIMER_UPDATE);
242  }
243 
244  vtkRenderWindowInteractor *m_Interactor;
245  vtkImageViewer *m_Viewer;
246 
247 private:
248 
249  vtkMyCallback()
250  {
251  m_Interactor=NULL;
252  m_Viewer=NULL;
253  }
254 };
255 #endif
256 
257 //-------------------------------------------------------------------------------------------
258 int main(int argc, char* argv[])
259 {
260  bool printHelp(false);
261  bool renderingOff(false);
262  std::string inputInstrumentName;
263 
264  vtksys::CommandLineArguments args;
265  args.Initialize(argc, argv);
266 
267  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
268 
269  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
270  args.AddArgument("--instrument-name", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputInstrumentName, "Name of the instrument to collect data from");
271  args.AddArgument("--rendering-off", vtksys::CommandLineArguments::NO_ARGUMENT, &renderingOff, "Run test without rendering.");
272  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level 1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
273 
274  if ( !args.Parse() )
275  {
276  std::cerr << "Problem parsing arguments" << std::endl;
277  std::cout << "\n\nvtkPlusThorLabsVideoSourceTest help:" << args.GetHelp() << std::endl;
278  exit(EXIT_FAILURE);
279  }
280 
281  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
282 
283  if ( printHelp )
284  {
285  std::cout << "\n\nvtkPlusThorLabsVideoSourceTest help:" << args.GetHelp() << std::endl;
286  exit(EXIT_SUCCESS);
287  }
288 
289  vtkSmartPointer<vtkPlusThorLabsVideoSource> spectrometer = vtkSmartPointer<vtkPlusThorLabsVideoSource>::New();
290  spectrometer->SetDeviceId("VideoDevice");
291 
292  if (!inputInstrumentName.empty())
293  {
294  spectrometer->SetInstrumentName(inputInstrumentName.c_str());
295  }
296 
297  spectrometer->CreateDefaultOutputChannel();
298 
299  if ( spectrometer->Connect()!=PLUS_SUCCESS )
300  {
301  LOG_ERROR( "Unable to connect to spectrometer" );
302  exit(EXIT_FAILURE);
303  }
304 
305  spectrometer->StartRecording(); //start recording frame from the video
306 
307  if (renderingOff)
308  {
309  // just run the recording for a few seconds then exit
310  LOG_DEBUG("Rendering disabled. Wait for just a few seconds to acquire data before exiting");
311  Sleep(5000); // no need to use accurate timer, it's just an approximate delay
312  spectrometer->StopRecording();
313  spectrometer->Disconnect();
314  }
315  else
316  {
317  // Allow some time to acquire the first frames (having a first valid frame is important for auto-scale of the display)
318  Sleep(500);
319 
320  // Print a warning message if there are multiple output channels and rendering is enabled,
321  // because only the first output channel is rendered
322  std::string firstChannelName;
323  std::string allChannelNames;
324  int numberOfVideoOutputChannels=0;
325  for( ChannelContainerIterator it = spectrometer->GetOutputChannelsStart(); it != spectrometer->GetOutputChannelsEnd(); ++it)
326  {
327  if ((*it)->HasVideoSource())
328  {
329  if (numberOfVideoOutputChannels==0)
330  {
331  // first channel containing video output
332  firstChannelName = (*it)->GetChannelId();
333  allChannelNames = (*it)->GetChannelId();
334  }
335  else
336  {
337  allChannelNames += std::string(", ") + (*it)->GetChannelId();
338  }
339  numberOfVideoOutputChannels++;
340  }
341  }
342  if (numberOfVideoOutputChannels>1)
343  {
344  LOG_WARNING("Multiple output channels contain video data: "<<allChannelNames<<". Only the first one ("<<firstChannelName<<") will be displayed");
345  }
346 
347 #ifdef PLUS_RENDERING_ENABLED
348  TestLinePlot(spectrometer);
349 #endif
350  }
351 
352  spectrometer->Disconnect();
353  return EXIT_SUCCESS;
354 }
vtkStandardNewMacro(vtkExtractImageRow)
const char int line
Definition: phidget22.h:2458
for i
void TestLinePlot(vtkPlusClarius *ClariusDevice)
int port
Definition: phidget22.h:2454
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
int main(int argc, char *argv[])
static vtkIGSIOLogger * Instance()
ChannelContainer::iterator ChannelContainerIterator
Definition: vtkPlusDevice.h:36
ThorLabs compact spectrometer.