PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkDataCollectorTest1.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 // Local includes
13 #include "PlusConfigure.h"
14 #include "vtkPlusChannel.h"
15 #include "vtkPlusDataCollector.h"
16 #include "vtkPlusDataSource.h"
17 #include "vtkPlusDevice.h"
18 #include "vtkPlusRfProcessor.h"
19 #include "vtkPlusSavedDataSource.h"
20 #ifdef PLUS_USE_ULTRASONIX_VIDEO
21  #include "vtkPlusSonixVideoSource.h"
22 #endif
23 
24 // VTK includes
25 #include <vtkCallbackCommand.h>
26 #include <vtkCommand.h>
27 #include <vtkImageData.h>
28 #ifdef PLUS_RENDERING_ENABLED
29 #include <vtkImageViewer.h>
30 #endif
31 #include <vtkMatrix4x4.h>
32 #include <vtkRenderWindowInteractor.h>
33 #include <vtkRenderer.h>
34 #include <vtkSmartPointer.h>
35 #include <vtkTextActor.h>
36 #include <vtkTextProperty.h>
37 #include <vtkXMLUtilities.h>
38 #include <vtksys/CommandLineArguments.hxx>
39 
40 class vtkMyCallback : public vtkCommand
41 {
42 public:
43  static vtkMyCallback* New()
44  {
45  return new vtkMyCallback;
46  }
47 
48  virtual void Execute(vtkObject* caller, unsigned long, void*)
49  {
50  vtkSmartPointer<vtkMatrix4x4> tFrame2Tracker = vtkSmartPointer<vtkMatrix4x4>::New();
51 
52  igsioTrackedFrame trackedFrame;
53  if (this->BroadcastChannel->GetTrackedFrame(trackedFrame) != PLUS_SUCCESS)
54  {
55  LOG_WARNING("Unable to get tracked frame!");
56  return;
57  }
58 
59  if (trackedFrame.GetImageData()->IsImageValid())
60  {
61  // Display image if it's valid
62  if (trackedFrame.GetImageData()->GetImageType() == US_IMG_BRIGHTNESS || trackedFrame.GetImageData()->GetImageType() == US_IMG_RGB_COLOR)
63  {
64  // B mode
65  this->ImageData->DeepCopy(trackedFrame.GetImageData()->GetImage());
66  }
67  else
68  {
69  // RF mode
70  RfProcessor->SetRfFrame(trackedFrame.GetImageData()->GetImage(), trackedFrame.GetImageData()->GetImageType());
71  this->ImageData->ShallowCopy(RfProcessor->GetBrightnessScanConvertedImage());
72  }
73 #ifdef PLUS_RENDERING_ENABLED
74  this->Viewer->SetInputData(this->ImageData);
75  this->Viewer->Modified();
76 #endif
77  }
78 
79  if (TransformName.IsValid())
80  {
81  std::ostringstream ss;
82  ss.precision(2);
83  ToolStatus status(TOOL_INVALID);
84  if (trackedFrame.GetFrameTransformStatus(TransformName, status) == PLUS_SUCCESS && status == TOOL_OK)
85  {
86  trackedFrame.GetFrameTransform(TransformName, tFrame2Tracker);
87  ss << std::fixed
88  << tFrame2Tracker->GetElement(0, 0) << " " << tFrame2Tracker->GetElement(0, 1) << " " << tFrame2Tracker->GetElement(0, 2) << " " << tFrame2Tracker->GetElement(0, 3) << "\n"
89  << tFrame2Tracker->GetElement(1, 0) << " " << tFrame2Tracker->GetElement(1, 1) << " " << tFrame2Tracker->GetElement(1, 2) << " " << tFrame2Tracker->GetElement(1, 3) << "\n"
90  << tFrame2Tracker->GetElement(2, 0) << " " << tFrame2Tracker->GetElement(2, 1) << " " << tFrame2Tracker->GetElement(2, 2) << " " << tFrame2Tracker->GetElement(2, 3) << "\n"
91  << tFrame2Tracker->GetElement(3, 0) << " " << tFrame2Tracker->GetElement(3, 1) << " " << tFrame2Tracker->GetElement(3, 2) << " " << tFrame2Tracker->GetElement(3, 3) << "\n";
92  }
93  else
94  {
95  std::string strTransformName;
96  TransformName.GetTransformName(strTransformName);
97  ss << "Transform '" << strTransformName << "' is invalid ...";
98  }
99  this->StepperTextActor->SetInput(ss.str().c_str());
100  this->StepperTextActor->Modified();
101  }
102 
103 #ifdef PLUS_RENDERING_ENABLED
104  this->Viewer->Render();
105 
106  //update the timer so it will trigger again
107  this->RenderWindowInteractor->CreateTimer(VTKI_TIMER_UPDATE);
108 #endif
109  }
110 
111  vtkPlusDataCollector* DataCollector;
112  vtkPlusChannel* BroadcastChannel;
113 #ifdef PLUS_RENDERING_ENABLED
114  vtkImageViewer* Viewer;
115 #endif
116  vtkRenderWindowInteractor* RenderWindowInteractor;
117  vtkTextActor* StepperTextActor;
118  igsioTransformName TransformName;
119  vtkImageData* ImageData;
120  vtkPlusRfProcessor* RfProcessor;
121 };
122 
123 int main(int argc, char** argv)
124 {
125  std::string inputConfigFileName;
126  bool renderingOff(false);
127  std::string inputVideoBufferMetafile;
128  std::string inputTrackerBufferMetafile;
129  std::string inputTransformName;
130  bool inputRepeat(false);
131  std::string inputSonixIp;
132 
133  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
134 
135  vtksys::CommandLineArguments args;
136  args.Initialize(argc, argv);
137 
138  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFileName, "Name of the input configuration file.");
139 #ifdef PLUS_USE_ULTRASONIX_VIDEO
140  args.AddArgument("--sonix-ip", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputSonixIp, "IP address of the Ultrasonix scanner (overrides the IP address parameter defined in the config file; only applicable if VideoDevice is SonixVideo).");
141 #endif
142  args.AddArgument("--video-buffer-seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputVideoBufferMetafile, "Video buffer sequence metafile.");
143  args.AddArgument("--tracker-buffer-seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputTrackerBufferMetafile, "Tracker buffer sequence metafile.");
144  args.AddArgument("--transform", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputTransformName, "Name of the transform displayed.");
145 
146  args.AddArgument("--rendering-off", vtksys::CommandLineArguments::NO_ARGUMENT, &renderingOff, "Run test without rendering.");
147  args.AddArgument("--repeat", vtksys::CommandLineArguments::NO_ARGUMENT, &inputRepeat, "Repeat tracked frames after reached the latest one.");
148  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
149 
150  if (!args.Parse())
151  {
152  std::cerr << "Problem parsing arguments" << std::endl;
153  std::cout << "Help: " << args.GetHelp() << std::endl;
154  exit(EXIT_FAILURE);
155  }
156 
157  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
158 
159  if (inputConfigFileName.empty())
160  {
161  std::cerr << "input-config-file-name is required" << std::endl;
162  exit(EXIT_FAILURE);
163  }
164 
166 
167  vtkSmartPointer<vtkXMLDataElement> configRootElement = vtkSmartPointer<vtkXMLDataElement>::New();
168  if (PlusXmlUtils::ReadDeviceSetConfigurationFromFile(configRootElement, inputConfigFileName.c_str()) == PLUS_FAIL)
169  {
170  LOG_ERROR("Unable to read configuration from file " << inputConfigFileName.c_str());
171  return EXIT_FAILURE;
172  }
173 
175 
176  vtkSmartPointer<vtkPlusDataCollector> dataCollector = vtkSmartPointer<vtkPlusDataCollector>::New();
177 
178  if (dataCollector->ReadConfiguration(configRootElement) != PLUS_SUCCESS)
179  {
180  LOG_ERROR("Configuration incorrect for vtkPlusDataCollectorTest1.");
181  exit(EXIT_FAILURE);
182  }
183  vtkPlusDevice* videoDevice = NULL;
184  vtkPlusDevice* trackerDevice = NULL;
185 
186  if (! inputVideoBufferMetafile.empty())
187  {
188  if (dataCollector->GetDevice(videoDevice, "VideoDevice") != PLUS_SUCCESS)
189  {
190  LOG_ERROR("Unable to locate the device with Id=\"VideoDevice\". Check config file.");
191  exit(EXIT_FAILURE);
192  }
193  vtkPlusSavedDataSource* videoSource = dynamic_cast<vtkPlusSavedDataSource*>(videoDevice);
194  if (videoSource == NULL)
195  {
196  LOG_ERROR("Unable to cast video source to vtkPlusSavedDataSource.");
197  exit(EXIT_FAILURE);
198  }
199  videoSource->SetSequenceFile(inputVideoBufferMetafile.c_str());
200  videoSource->SetRepeatEnabled(inputRepeat);
201  }
202 #ifdef PLUS_USE_ULTRASONIX_VIDEO
203  else if (!inputSonixIp.empty())
204  {
205  if (dataCollector->GetDevice(videoDevice, "VideoDevice") != PLUS_SUCCESS)
206  {
207  LOG_ERROR("Unable to locate the device with Id=\"VideoDevice\". Check config file.");
208  exit(EXIT_FAILURE);
209  }
210  vtkPlusSonixVideoSource* videoSource = dynamic_cast<vtkPlusSonixVideoSource*>(videoDevice);
211  if (videoSource == NULL)
212  {
213  LOG_ERROR("Video source is not SonixVideo. Cannot set IP address.");
214  exit(EXIT_FAILURE);
215  }
216  videoSource->SetSonixIP(inputSonixIp.c_str());
217  }
218 #endif
219 
220  if (! inputTrackerBufferMetafile.empty())
221  {
222  if (dataCollector->GetDevice(trackerDevice, "TrackerDevice") != PLUS_SUCCESS)
223  {
224  LOG_ERROR("Unable to locate the device with Id=\"TrackerDevice\". Check config file.");
225  exit(EXIT_FAILURE);
226  }
227  vtkPlusSavedDataSource* tracker = dynamic_cast<vtkPlusSavedDataSource*>(trackerDevice);
228  if (tracker == NULL)
229  {
230  LOG_ERROR("Unable to cast tracker to vtkPlusSavedDataSource");
231  exit(EXIT_FAILURE);
232  }
233  tracker->SetSequenceFile(inputTrackerBufferMetafile.c_str());
234  tracker->SetRepeatEnabled(inputRepeat);
235  }
236 
237  if (dataCollector->Connect() != PLUS_SUCCESS)
238  {
239  LOG_ERROR("Failed to connect to devices!");
240  exit(EXIT_FAILURE);
241  }
242 
243  if (dataCollector->Start() != PLUS_SUCCESS)
244  {
245  LOG_ERROR("Failed to start data collection!");
246  exit(EXIT_FAILURE);
247  }
248 
249  if (renderingOff)
250  {
251  LOG_DEBUG("Rendering is disabled");
252  }
253  else
254  {
255 #ifdef PLUS_RENDERING_ENABLED
256  if (dataCollector->GetDevice(videoDevice, "TrackedVideoDevice") != PLUS_SUCCESS)
257  {
258  LOG_ERROR("Unable to locate the device with Id=\"TrackedVideoDevice\". Check config file.");
259  exit(EXIT_FAILURE);
260  }
261  vtkPlusChannel* aChannel(NULL);
262  if (videoDevice->GetOutputChannelByName(aChannel, "TrackedVideoStream") != PLUS_SUCCESS)
263  {
264  LOG_ERROR("Unable to locate the channel with Id=\"TrackedVideoStream\". Check config file.");
265  exit(EXIT_FAILURE);
266  }
267 
268  vtkSmartPointer<vtkImageViewer> viewer = vtkSmartPointer<vtkImageViewer>::New();
269  viewer->SetColorWindow(255);
270  viewer->SetColorLevel(127.5);
271  viewer->SetZSlice(0);
272  viewer->SetSize(800, 600);
273 
274  // Create a text actor for tracking information
275  vtkSmartPointer<vtkTextActor> stepperTextActor = vtkSmartPointer<vtkTextActor>::New();
276  vtkSmartPointer<vtkTextProperty> textprop = stepperTextActor->GetTextProperty();
277  textprop->SetColor(1, 0, 0);
278  textprop->SetFontFamilyToArial();
279  textprop->SetFontSize(15);
280  textprop->SetJustificationToLeft();
281  textprop->SetVerticalJustificationToTop();
282  stepperTextActor->VisibilityOn();
283  stepperTextActor->SetDisplayPosition(20, 65);
284  viewer->GetRenderer()->AddActor(stepperTextActor);
285 
286  //Create the interactor that handles the event loop
287  vtkSmartPointer<vtkRenderWindowInteractor> iren = vtkSmartPointer<vtkRenderWindowInteractor>::New();
288  iren->SetRenderWindow(viewer->GetRenderWindow());
289  viewer->SetupInteractor(iren);
290 
291  viewer->Render(); //must be called after iren and viewer are linked
292  //or there will be problems
293 
294  vtkSmartPointer<vtkImageData> imageData = vtkSmartPointer<vtkImageData>::New();
295 
296  vtkSmartPointer<vtkPlusRfProcessor> rfProc = vtkSmartPointer<vtkPlusRfProcessor>::New();
297  rfProc->ReadConfiguration(configRootElement);
298 
299  //establish timer event and create timer
300  vtkSmartPointer<vtkMyCallback> call = vtkSmartPointer<vtkMyCallback>::New();
301  call->DataCollector = dataCollector;
302  call->BroadcastChannel = aChannel;
303  call->Viewer = viewer;
304  call->RenderWindowInteractor = iren;
305  call->StepperTextActor = stepperTextActor;
306  call->ImageData = imageData;
307  call->RfProcessor = rfProc;
308 
309  if (!inputTransformName.empty())
310  {
311  if (call->TransformName.SetTransformName(inputTransformName.c_str()) != PLUS_SUCCESS)
312  {
313  LOG_ERROR("Transform name '" << inputTransformName << "' is invalid!");
314  return EXIT_FAILURE;
315  }
316  }
317 
318  iren->AddObserver(vtkCommand::TimerEvent, call);
319  iren->CreateTimer(VTKI_TIMER_FIRST); //VTKI_TIMER_FIRST = 0
320 
321  //iren must be initialized so that it can handle events
322  iren->Initialize();
323  iren->Start();
324 #else
325  LOG_WARNING("Cannot perform rendering when VTK_RENDERING_BACKEND is None!");
326 #endif
327  }
328 
329  dataCollector->Disconnect();
330 
331  std::cout << "vtkPlusDataCollectorTest1 completed successfully!" << std::endl;
332  return EXIT_SUCCESS;
333 
334 }
Abstract interface for tracker and video devices.
Definition: vtkPlusDevice.h:60
vtkRenderWindowInteractor * iren
#define PLUS_FAIL
Definition: PlusCommon.h:43
static vtkPlusConfig * GetInstance()
PlusStatus GetOutputChannelByName(vtkPlusChannel *&aChannel, const char *aChannelId)
int main(int argc, char **argv)
Manages devices that record image or positional data.
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
vtkImageViewer * viewer
virtual void SetRepeatEnabled(bool)
VTK interface for video input from Ultrasonix machine.
virtual void SetSequenceFile(const char *)
Convenience class to combine multiple algorithms to compute a displayable B-mode frame from RF data.
Class for providing VTK video input interface from sequence fileAttributes:
static vtkIGSIOLogger * Instance()
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
virtual void SetSonixIP(const char *)
void SetDeviceSetConfigurationData(vtkXMLDataElement *deviceSetConfigurationData)
static PlusStatus ReadDeviceSetConfigurationFromFile(vtkXMLDataElement *config, const char *filename)
Definition: PlusXmlUtils.h:23