PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkAzureKinectTest.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 
6  Developed by MACBIOIDI & IACTEC group
7 =========================================================Plus=header=end*/
8 
9 #include "PlusConfigure.h"
10 #include "vtkCallbackCommand.h"
11 #include "vtkCommand.h"
12 #include "vtkPlusDataSource.h"
13 #include "vtkSmartPointer.h"
14 #include "vtkPlusAzureKinect.h"
15 #include "vtksys/CommandLineArguments.hxx"
16 #include "vtksys/SystemTools.hxx"
17 #include "vtkImageData.h"
18 #include "vtkImageViewer.h"
19 #include "vtkInformation.h"
20 #include "vtkInformationVector.h"
21 #include "vtkRenderWindow.h"
22 #include "vtkRenderWindowInteractor.h"
23 #include "vtkRenderer.h"
24 #include "vtkRendererCollection.h"
25 #include "vtkPolyDataMapper.h"
26 #include "vtkPolyData.h"
27 #include "vtkPoints.h"
28 #include "vtkVertexGlyphFilter.h"
29 #include "vtkPointData.h"
30 #include "vtkActor.h"
31 #include "vtkUnsignedCharArray.h"
32 #include "igtlOSUtil.h"
33 
34 
35 void PrintLogsCallback(vtkObject* obj, unsigned long eid, void* clientdata, void* calldata);
36 
37 namespace
38 {
39  class vtkMyImageViewerCallback : public vtkCommand
40  {
41  public:
42  static vtkMyImageViewerCallback* New()
43  {
44  return new vtkMyImageViewerCallback;
45  }
46 
47  virtual void Execute(vtkObject* caller, unsigned long, void*)
48  {
49  if (m_Channel->GetVideoDataAvailable())
50  {
51  m_Viewer->SetInputData(m_Channel->GetBrightnessOutput());
52  }
53 
54  //update the timer so it will trigger again
55  m_Viewer->Render();
56  m_Interactor->CreateTimer(VTKI_TIMER_UPDATE);
57  }
58 
59  vtkRenderWindowInteractor* m_Interactor{nullptr};
60  vtkImageViewer* m_Viewer{nullptr};
61  vtkPlusChannel* m_Channel{nullptr};
62  };
63 
64  class vtkMyMeshViewerCallback : public vtkCommand
65  {
66  public:
67  static vtkMyMeshViewerCallback* New()
68  {
69  return new vtkMyMeshViewerCallback;
70  }
71 
72  virtual void Execute(vtkObject* caller, unsigned long, void*)
73  {
74  static bool firstDisplay{true};
75  vtkImageData* texture{nullptr};
76 
77  if (m_Texture && m_Texture->GetVideoDataAvailable())
78  {
79  texture = m_Texture->GetBrightnessOutput();
80  }
81 
82  if (m_Channel->GetVideoDataAvailable())
83  {
84  m_Mapper->SetInputData(ConvertToPCL(m_Channel->GetBrightnessOutput(), texture));
85  m_Mapper->Modified();
86 
87  if (firstDisplay)
88  {
89  m_Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->ResetCamera();
90  firstDisplay = false;
91  }
92  }
93 
94  m_Interactor->Render();
95  }
96 
97  vtkRenderWindowInteractor* m_Interactor{nullptr};
98  vtkPlusChannel* m_Channel{nullptr};
99  vtkPolyDataMapper* m_Mapper{nullptr};
100  vtkPlusChannel* m_Texture{nullptr};
101 
102  private:
103  vtkSmartPointer<vtkPolyData> ConvertToPCL(vtkImageData* imageData, vtkImageData* texture)
104  {
105  if (imageData->GetNumberOfScalarComponents() != 3)
106  {
107  return nullptr;
108  }
109 
110  int* dims = imageData->GetDimensions();
111  vtkNew<vtkPoints> points;
112  vtkNew<vtkUnsignedCharArray> colors;
113  colors->SetNumberOfComponents(3);
114  colors->SetName("Colors");
115 
116  for (int x = 0; x < dims[0]; x++)
117  {
118  for (int y = 0; y < dims[1]; y++)
119  {
120  for (int z = 0; z < dims[2]; z++)
121  {
122  auto* coords =
123  static_cast<int16_t*>(imageData->GetScalarPointer(x, y, z));
124 
125  if (coords[2] == 0)
126  {
127  continue;
128  }
129 
130  points->InsertNextPoint(coords[0], coords[1], coords[2]);
131 
132  if (texture)
133  {
134  auto* color =
135  static_cast<uint8_t*>(texture->GetScalarPointer(x, y, z));
136  colors->InsertNextTypedTuple(color);
137  }
138  else
139  {
140  uint8_t color[3] = {255, 255, 255};
141  colors->InsertNextTypedTuple(color);
142  }
143  }
144  }
145  }
146 
147  vtkNew<vtkPolyData> poly;
148  poly->SetPoints(points);
149  poly->GetPointData()->SetScalars(colors);
150 
151  vtkNew<vtkVertexGlyphFilter> vertexGenerator;
152  vertexGenerator->SetInputData(poly);
153  vertexGenerator->Update();
154 
155  return vertexGenerator->GetOutput();
156  }
157  };
158 }
159 
160 int main(int argc, char** argv)
161 {
162  bool printHelp(false);
163  std::string inputConfigFileName = "Testing/PlusDeviceSet_DataCollectionOnly_AzureKinect.xml";
164 
165  vtksys::CommandLineArguments args;
166  args.Initialize(argc, argv);
167 
168  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
169  bool renderingOff(false);
170 
171  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
172  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
173  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFileName, "Config file containing the device configuration.");
174  args.AddArgument("--rendering-off", vtksys::CommandLineArguments::NO_ARGUMENT, &renderingOff, "Run test without rendering.");
175 
176  if (!args.Parse())
177  {
178  std::cerr << "Problem parsing arguments" << std::endl;
179  std::cout << "\n\nHelp:" << args.GetHelp() << std::endl;
180  exit(EXIT_FAILURE);
181  }
182 
183  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
184 
185  if (printHelp)
186  {
187  std::cout << "\n\nHelp:" << args.GetHelp() << std::endl;
188  exit(EXIT_SUCCESS);
189  }
190 
191  vtkNew<vtkPlusAzureKinect> azureKinectDevice;
192  azureKinectDevice->SetDeviceId("VideoDevice");
193 
194  if (!vtksys::SystemTools::FileExists(inputConfigFileName))
195  {
196  LOG_ERROR("Bad configuration file: " << inputConfigFileName);
197  exit(EXIT_FAILURE);
198  }
199 
200  LOG_DEBUG("Reading config file: " << inputConfigFileName);
201  auto* configRead = vtkXMLUtilities::ReadElementFromFile(inputConfigFileName.c_str());
202 
203  if (!configRead)
204  {
205  LOG_ERROR("Failed to read configuration file");
206  exit(EXIT_FAILURE);
207  }
208 
209  LOG_TRACE("Config file: " << *configRead);
210  if (azureKinectDevice->ReadConfiguration(configRead) != PLUS_SUCCESS)
211  {
212  LOG_ERROR("Failed to read configuration");
213  exit(EXIT_FAILURE);
214  }
215 
216  if (azureKinectDevice->NotifyConfigured() != PLUS_SUCCESS)
217  {
218  LOG_ERROR("Invalid configuration");
219  exit(EXIT_FAILURE);
220  }
221 
222  vtkPlusChannel* rgbChannel{nullptr};
223  azureKinectDevice->GetOutputChannelByName(rgbChannel, "VideoStreamRGB");
224 
225  vtkPlusChannel* depthChannel{nullptr};
226  azureKinectDevice->GetOutputChannelByName(depthChannel, "VideoStreamDEPTH");
227 
228 
229  vtkPlusChannel* pclChannel{nullptr};
230  azureKinectDevice->GetOutputChannelByName(pclChannel, "VideoStreamPCL");
231 
232  vtkIndent indent;
233  azureKinectDevice->PrintSelf(std::cout, indent);
234 
235  // Add an observer to warning and error events for redirecting it to the stdout
236  vtkNew<vtkCallbackCommand> callbackCommand;
237  callbackCommand->SetCallback(PrintLogsCallback);
238  azureKinectDevice->AddObserver("WarningEvent", callbackCommand);
239  azureKinectDevice->AddObserver("ErrorEvent", callbackCommand);
240 
241  if (azureKinectDevice->Connect() != PLUS_SUCCESS)
242  {
243  LOG_ERROR("Failed to connect");
244  exit(EXIT_FAILURE);
245  }
246 
247  if (azureKinectDevice->StartRecording() != PLUS_SUCCESS)
248  {
249  LOG_INFO("Failed to start recording");
250  exit(EXIT_FAILURE);
251  }
252 
253  if (!renderingOff)
254  {
255  vtkNew<vtkImageViewer> imageViewer;
256  imageViewer->SetColorWindow(255);
257  imageViewer->SetColorLevel(127.5);
258  imageViewer->SetZSlice(0);
259 
260  // Create the interactor that handles the event loop
261  vtkNew<vtkRenderWindowInteractor> imageInteractor;
262  imageInteractor->SetRenderWindow(imageViewer->GetRenderWindow());
263  imageViewer->SetupInteractor(imageInteractor);
264 
265  imageViewer->Render(); //must be called after iren and viewer are linked or there will be problems
266 
267  // Establish timer event and create timer to update the live image
268  vtkNew<vtkMyImageViewerCallback> call;
269  call->m_Interactor = imageInteractor;
270  call->m_Viewer = imageViewer;
271  imageInteractor->AddObserver(vtkCommand::TimerEvent, call);
272  imageInteractor->CreateTimer(VTKI_TIMER_FIRST);
273 
274  // Display rgb image
275  if (rgbChannel)
276  {
277  call->m_Channel = rgbChannel;
278  imageInteractor->Initialize();
279  imageInteractor->Start();
280  }
281 
282  // Display depth image
283  if (depthChannel)
284  {
285  call->m_Channel = depthChannel;
286  imageInteractor->Start();
287  }
288 
289  imageInteractor->GetRenderWindow()->Finalize();
290 
291  // Display points cloud
292  if (pclChannel)
293  {
294  vtkNew<vtkRenderer> pclRenderer;
295  vtkNew<vtkRenderWindow> pclRenderWindow;
296  pclRenderWindow->SetSize(640, 480);
297  pclRenderWindow->AddRenderer(pclRenderer);
298  vtkNew<vtkRenderWindowInteractor> pclInteractor;
299  pclInteractor->SetRenderWindow(pclRenderWindow);
300 
301  vtkNew<vtkPolyDataMapper> mapper;
302  mapper->SetInputData(vtkSmartPointer<vtkPolyData>::New());
303  vtkNew<vtkActor> actor;
304  actor->SetMapper(mapper);
305  pclRenderer->SetBackground(0., 0., 0.);
306  pclRenderer->AddActor(actor);
307 
308  pclRenderWindow->Render();
309  pclInteractor->Initialize();
310 
311  vtkNew<vtkMyMeshViewerCallback> call2;
312  call2->m_Interactor = pclInteractor;
313  call2->m_Mapper = mapper;
314  call2->m_Channel = pclChannel;
315 
316  if (rgbChannel)
317  {
318  call2->m_Texture = rgbChannel;
319  }
320 
321  pclInteractor->AddObserver(vtkCommand::TimerEvent, call2);
322  pclInteractor->CreateRepeatingTimer(100);
323 
324  pclInteractor->Start();
325  pclInteractor->GetRenderWindow()->Finalize();
326  }
327  }
328  else
329  {
330  igtl::Sleep(2000);
331  }
332 
333  if (azureKinectDevice->StopRecording() != PLUS_SUCCESS)
334  {
335  LOG_INFO("Failed to stop recording");
336  exit(EXIT_FAILURE);
337  }
338 
339  if (azureKinectDevice->Disconnect() != PLUS_SUCCESS)
340  {
341  LOG_ERROR("Failed to disconnect");
342  exit(EXIT_FAILURE);
343  }
344 
345  LOG_INFO("Exit successfully");
346  exit(EXIT_SUCCESS);
347 }
348 
349 
350 // Callback function for error and warning redirects
351 void PrintLogsCallback(vtkObject* obj, unsigned long eid, void* clientdata, void* calldata)
352 {
353  if (eid == vtkCommand::GetEventIdFromString("WarningEvent"))
354  {
355  LOG_WARNING((const char*)calldata);
356  }
357  else if (eid == vtkCommand::GetEventIdFromString("ErrorEvent"))
358  {
359  LOG_ERROR((const char*)calldata);
360  }
361 }
int main(int argc, char **argv)
vtkImageData * GetBrightnessOutput()
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
int x
Definition: phidget22.h:4265
static vtkIGSIOLogger * Instance()
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
Direction vectors of rods y
Definition: algo3.m:15
void PrintLogsCallback(vtkObject *obj, unsigned long eid, void *clientdata, void *calldata)