PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkClariusTest.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 
12 #include "PlusConfigure.h"
13 #include "vtkPlusClarius.h"
14 #include "vtkPlusDataSource.h"
15 #include "vtkCallbackCommand.h"
16 #include "vtkChartXY.h"
17 #include "vtkCommand.h"
18 #include "vtkContextScene.h"
19 #include "vtkContextView.h"
20 #include "vtkFloatArray.h"
21 #include "vtkImageData.h"
22 #include "vtkImageViewer.h"
23 #include "vtkInformation.h"
24 #include "vtkInformationVector.h"
25 #include "vtkPlot.h"
26 #include "vtkRenderWindow.h"
27 #include "vtkRenderWindowInteractor.h"
28 #include "vtkRenderer.h"
29 #include "vtkSmartPointer.h"
30 #include "vtkTable.h"
31 #include "vtkTableAlgorithm.h"
32 #include "vtkXMLUtilities.h"
33 #include "vtksys/CommandLineArguments.hxx"
34 #include <stdlib.h>
35 
36 //----------------------------------------------------------------------------
37 
39 {
42 };
43 
44 //----------------------------------------------------------------------------
45 
46 class vtkExtractImageRow : public vtkTableAlgorithm
47 {
48 public:
49  static vtkExtractImageRow* New();
50  vtkTypeMacro(vtkExtractImageRow, vtkTableAlgorithm);
51  void PrintSelf(ostream& os, vtkIndent indent)
52  {
53  this->Superclass::PrintSelf(os, indent);
54  }
55 
56  // Description:
57  // Specify the first vtkGraph input and the second vtkSelection input.
58  int FillInputPortInformation(int port, vtkInformation* info)
59  {
60  if (port == 0)
61  {
62  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
63  return 1;
64  }
65  return 0;
66  }
67 
68 protected:
69  vtkExtractImageRow()
70  {
71  this->SetNumberOfInputPorts(1);
72  }
73  virtual ~vtkExtractImageRow()
74  {
75  }
76 
77  int RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector)
78  {
79  vtkImageData* inputImage = vtkImageData::GetData(inputVector[0]);
80  vtkInformation* outInfo = outputVector->GetInformationObject(0);
81  vtkTable* outputTable = vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
82 
83  if (!inputImage)
84  {
85  LOG_ERROR("No input image is available");
86  return 0;
87  }
88 
89  // Create the tables if they haven't been created yet
90  if (outputTable->GetColumnByName("time") == NULL)
91  {
92  vtkSmartPointer<vtkFloatArray> arrXnew = vtkSmartPointer<vtkFloatArray>::New();
93  arrXnew->SetName("time");
94  outputTable->AddColumn(arrXnew);
95  }
96  if (outputTable->GetColumnByName("RF value") == NULL)
97  {
98  vtkSmartPointer<vtkFloatArray> arrRfValNew = vtkSmartPointer<vtkFloatArray>::New();
99  arrRfValNew->SetName("RF value");
100  outputTable->AddColumn(arrRfValNew);
101  }
102 
103  if (inputImage->GetScalarType() != VTK_SHORT)
104  {
105  LOG_ERROR("Plotting is only supported for signed short data");
106  return 0;
107  }
108  int rowCount = inputImage->GetDimensions()[1]; // number of transducer crystals
109  int numPoints = inputImage->GetDimensions()[0]; // number of data points (RF data values) recorded for one crystal
110  int selectedRow = rowCount / 2; // plot the center column of the image
111  short* pixelBuffer = reinterpret_cast<short*>(inputImage->GetScalarPointer()) + selectedRow * numPoints;
112 
113  outputTable->SetNumberOfRows(numPoints);
114  int timeIndex = numPoints - 1; // the RF data set starts with the latest time
115  for (int i = 0; i < numPoints; ++i)
116  {
117  outputTable->SetValue(i, 0, timeIndex);
118  short value = *pixelBuffer;
119  outputTable->SetValue(i, 1, value);
120  pixelBuffer++;
121  timeIndex--;
122  }
123 
124  return 1;
125  }
126 
127 private:
128  vtkExtractImageRow(const vtkExtractImageRow&); // Not implemented
129  void operator=(const vtkExtractImageRow&); // Not implemented
130 };
131 
132 vtkStandardNewMacro(vtkExtractImageRow);
133 
134 //---------------------------------------------------------------------------------
135 
136 class vtkMyPlotCallback : public vtkCommand
137 {
138 public:
139  static vtkMyPlotCallback *New() { return new vtkMyPlotCallback; }
140 
141  virtual void Execute(vtkObject *caller, unsigned long eventId, void* callData)
142  {
143  if (eventId == vtkCommand::KeyPressEvent)
144  {
145  if (m_Interactor->GetKeyCode() == 'q')
146  {
147  m_Interactor->ExitCallback();
148  }
149  return;
150  }
151 
152  m_ImageToTableAdaptor->Update();
153  m_Viewer->Render();
154  //update the timer so it will trigger again
155  m_Interactor->CreateTimer(VTKI_TIMER_UPDATE);
156  }
157 
158  vtkRenderWindowInteractor *m_Interactor;
159  vtkContextView *m_Viewer;
160  vtkExtractImageRow *m_ImageToTableAdaptor;
161 
162 private:
163 
164  vtkMyPlotCallback()
165  {
166  m_Interactor = NULL;
167  m_Viewer = NULL;
168  m_ImageToTableAdaptor = NULL;
169  }
170 };
171 
172 //----------------------------------------------------------------------------
173 void TestLinePlot(vtkPlusClarius *ClariusDevice)
174 {
175  // Set up a 2D scene, add an XY chart to it
176  vtkSmartPointer<vtkContextView> view = vtkSmartPointer<vtkContextView>::New();
177  view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
178  view->GetRenderWindow()->SetSize(640, 480);
179  vtkSmartPointer<vtkChartXY> chart = vtkSmartPointer<vtkChartXY>::New();
180  view->GetScene()->AddItem(chart);
181 
182  vtkSmartPointer<vtkExtractImageRow> imageToTableAdaptor = vtkSmartPointer<vtkExtractImageRow>::New();
183  imageToTableAdaptor->SetInputConnection(ClariusDevice->GetOutputPort());
184  imageToTableAdaptor->Update();
185 
186  // Add multiple line plots, setting the colors etc
187  vtkPlot *line = chart->AddPlot(vtkChart::LINE);
188  line->SetInputData(imageToTableAdaptor->GetOutput(), 0, 1);
189  line->SetColor(0, 255, 0, 255);
190  line->SetWidth(1.0);
191 
192  vtkSmartPointer<vtkMyPlotCallback> call = vtkSmartPointer<vtkMyPlotCallback>::New();
193  call->m_Interactor = view->GetInteractor();
194  call->m_Viewer = view;
195  call->m_ImageToTableAdaptor = imageToTableAdaptor;
196 
197  view->GetInteractor()->Initialize();
198 
199  view->GetInteractor()->AddObserver(vtkCommand::TimerEvent, call);
200  view->GetInteractor()->CreateTimer(VTKI_TIMER_FIRST);
201 
202  view->GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, call);
203 
204  view->GetInteractor()->Start();
205 
206 }
207 
208 //---------------------------------------------------------------------------------
209 
210 class vtkMyCallback : public vtkCommand
211 {
212 public:
213  static vtkMyCallback *New() { return new vtkMyCallback; }
214 
215  virtual void Execute(vtkObject *caller, unsigned long, void*)
216  {
217  m_Viewer->Render();
218 
219  //update the timer so it will trigger again
220  m_Interactor->CreateTimer(VTKI_TIMER_UPDATE);
221  }
222 
223  vtkRenderWindowInteractor *m_Interactor;
224  vtkImageViewer *m_Viewer;
225 
226 private:
227 
228  vtkMyCallback()
229  {
230  m_Interactor = NULL;
231  m_Viewer = NULL;
232  }
233 };
234 
235 //-------------------------------------------------------------------------------------------
236 
237 int main(int argc, char* argv[])
238 {
239  bool printHelp(false);
240  // bool renderingOff(false);
241  bool printParams(true);
242  std::string inputConfigFile = "Testing/PlusDeviceSet_DataCollectionOnly_Clarius.xml";
243 
244  std::string acqMode("B");
245 
246  vtksys::CommandLineArguments args;
247  args.Initialize(argc, argv);
248 
249  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
250 
251  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
252  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFile, "Config file containing the device configuration.");
253  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level 1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
254 
255  if (!args.Parse())
256  {
257  std::cerr << "Problem parsing arguments" << std::endl;
258  std::cout << "\n\nvtkPlusSonixVideoSourceTest1 help:" << args.GetHelp() << std::endl;
259  exit(EXIT_FAILURE);
260  }
261 
262  vtkPlusLogger::Instance()->SetLogLevel(5);
263 
264 
265  vtkSmartPointer<vtkPlusClarius> ClariusDevice = vtkSmartPointer<vtkPlusClarius>::New();
266  ClariusDevice->SetDeviceId("VideoDevice");
267 
268  // Read config file
269  if (STRCASECMP(inputConfigFile.c_str(), "") != 0)
270  {
271  LOG_DEBUG("Reading config file...");
272  vtkSmartPointer<vtkXMLDataElement> configRead = vtkSmartPointer<vtkXMLDataElement>::Take(::vtkXMLUtilities::ReadElementFromFile(inputConfigFile.c_str()));
273  LOG_DEBUG("Reading config file finished.");
274  if (configRead != NULL)
275  {
276  ClariusDevice->ReadConfiguration(configRead);
277  }
278  }
279 
280  ClariusDevice->CreateDefaultOutputChannel(NULL, true);
281  vtkPlusDataSource* videoSource = NULL;
282  if (ClariusDevice->GetFirstActiveOutputVideoSource(videoSource) != PLUS_SUCCESS)
283  {
284  LOG_ERROR("Unable to retrieve the video source.");
285  exit(EXIT_FAILURE);
286  }
287  videoSource->SetInputImageOrientation(US_IMG_ORIENT_UN);
288 
289  DisplayMode displayMode = SHOW_IMAGE;
290  //DisplayMode displayMode=SHOW_PLOT;
291 
292  if (STRCASECMP(acqMode.c_str(), "B") == 0)
293  {
294  LOG_DEBUG("Acquisition mode: B");
295  //ClariusDevice->SetImagingMode(BMode);
296  displayMode = SHOW_IMAGE;
297  }
298 
299  else
300  {
301  LOG_ERROR("Unsupported AcquisitionDataType requested: " << acqMode);
302  exit(EXIT_FAILURE);
303  }
304 
305  if (ClariusDevice->Connect() != PLUS_SUCCESS)
306  {
307  LOG_ERROR("Unable to connect to Telemed device");
308  exit(EXIT_FAILURE);
309  }
310 
311  // Show the live ultrasound image in a VTK renderer window
312 
313  vtkSmartPointer<vtkImageViewer> viewer = vtkSmartPointer<vtkImageViewer>::New();
314  viewer->SetInputConnection(ClariusDevice->GetOutputPort()); //set image to the render and window
315  viewer->SetColorWindow(255);
316  viewer->SetColorLevel(127.5);
317  viewer->SetZSlice(0);
318 
319  //Create the interactor that handles the event loop
320  vtkSmartPointer<vtkRenderWindowInteractor> iren = vtkSmartPointer<vtkRenderWindowInteractor>::New();
321  iren->SetRenderWindow(viewer->GetRenderWindow());
322  viewer->SetupInteractor(iren);
323 
324  viewer->Render(); //must be called after iren and viewer are linked or there will be problems
325 
326  // Establish timer event and create timer to update the live image
327  vtkSmartPointer<vtkMyCallback> call = vtkSmartPointer<vtkMyCallback>::New();
328  call->m_Interactor = iren;
329  call->m_Viewer = viewer;
330  iren->AddObserver(vtkCommand::TimerEvent, call);
331  iren->CreateTimer(VTKI_TIMER_FIRST);
332 
333  //iren must be initialized so that it can handle events
334  iren->Initialize();
335  iren->Start();
336 
337 
338 
339  ClariusDevice->Disconnect();
340  return EXIT_SUCCESS;
341 }
342 
const char int line
Definition: phidget22.h:2458
vtkStandardNewMacro(vtkExtractImageRow)
vtkRenderWindowInteractor * iren
for i
void TestLinePlot(vtkPlusClarius *ClariusDevice)
virtual PlusStatus SetInputImageOrientation(US_IMAGE_ORIENTATION imageOrientation)
int port
Definition: phidget22.h:2454
int main(int argc, char *argv[])
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
vtkImageViewer * viewer
const char const char * value
Definition: phidget22.h:5111
static vtkIGSIOLogger * Instance()
Interface to the Clarius ultrasound scans This class talks with a Clarius Scanner over the Clarius AP...
Interface to a 3D positioning tool, video source, or generalized data stream.