Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkKinectV2Device.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 #include "mitkKinectV2Device.h"
13 
14 
15 #include <mitkRealTimeClock.h>
17 #include <mitkSurface.h>
18 
19 #include <itkMultiThreader.h>
20 #include <itksys/SystemTools.hxx>
21 
22 
23 namespace mitk
24 {
26 
28  m_DistanceDataBuffer(nullptr),
29  m_AmplitudeDataBuffer(nullptr),
30  m_RGBDataBuffer(nullptr),
31  m_DepthBufferSize(sizeof(float)*512*424),
32  m_RGBBufferSize(3*1920*1080)
33  {
35  m_PolyData = vtkSmartPointer<vtkPolyData>::New();
36  }
37 
39  {
40  }
41 
42  std::string GetDeviceName()
43  {
44  return "Microsoft Kinect 2 Device ";
45  }
46 
48  {
49  bool ok = false;
50  if (m_Controller)
51  {
52  ok = m_Controller->OpenCameraConnection();
53  if (ok)
54  {
55  this->m_CaptureWidth = m_Controller->GetDepthCaptureWidth();
56  this->m_CaptureHeight = m_Controller->GetDepthCaptureHeight();
57  this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight;
58 
59  this->m_RGBImageWidth = m_Controller->GetRGBCaptureWidth();
60  this->m_RGBImageHeight = m_Controller->GetRGBCaptureHeight();
62 
63  // allocate buffer
64  this->m_DistanceArray = new float[this->m_PixelNumber];
65  for(int i=0; i<this->m_PixelNumber; i++) {this->m_DistanceArray[i]=0.0;}
66  this->m_AmplitudeArray = new float[this->m_PixelNumber];
67  for(int i=0; i<this->m_PixelNumber; i++) {this->m_AmplitudeArray[i]=0.0;}
68 
69  this->m_DistanceDataBuffer = new float*[this->m_MaxBufferSize];
70  for(int i=0; i<this->m_MaxBufferSize; i++)
71  {
72  this->m_DistanceDataBuffer[i] = new float[this->m_PixelNumber];
73  }
74  this->m_AmplitudeDataBuffer = new float*[this->m_MaxBufferSize];
75  for(int i=0; i<this->m_MaxBufferSize; i++)
76  {
77  this->m_AmplitudeDataBuffer[i] = new float[this->m_PixelNumber];
78  }
79  this->m_RGBDataBuffer = new unsigned char*[this->m_MaxBufferSize];
80  for (int i=0; i<this->m_MaxBufferSize; i++)
81  {
82  this->m_RGBDataBuffer[i] = new unsigned char[this->m_RGBPixelNumber*3];
83  }
84 
85  m_CameraConnected = true;
86  }
87  }
88  return ok;
89  }
90 
92  {
93  bool ok = false;
94  if (m_Controller)
95  {
96  ok = m_Controller->CloseCameraConnection();
97 
98  // clean-up only if camera was connected
100  {
101  delete [] m_DistanceArray;
102  delete [] m_AmplitudeArray;
103 
104  for(int i=0; i<this->m_MaxBufferSize; i++)
105  {
106  delete[] this->m_DistanceDataBuffer[i];
107  delete[] this->m_AmplitudeDataBuffer[i];
108  delete[] this->m_RGBDataBuffer[i];
109  }
110  delete[] this->m_DistanceDataBuffer;
111  delete[] this->m_AmplitudeDataBuffer;
112  delete[] this->m_RGBDataBuffer;
113 
114  m_CameraConnected = false;
115  }
116  }
117  return ok;
118  }
119 
121  {
122  if (m_CameraConnected)
123  {
124  // get the first image
125  this->m_Controller->UpdateCamera();
126  this->m_ImageMutex->Lock();
127  this->m_Controller->GetAllData(this->m_DistanceDataBuffer[this->m_FreePos],this->m_AmplitudeDataBuffer[this->m_FreePos],this->m_RGBDataBuffer[this->m_FreePos]);
128  this->m_FreePos = (this->m_FreePos+1) % this->m_BufferSize;
129  this->m_CurrentPos = (this->m_CurrentPos+1) % this->m_BufferSize;
130  this->m_ImageSequence++;
131  this->m_ImageMutex->Unlock();
132 
133  this->m_CameraActiveMutex->Lock();
134  this->m_CameraActive = true;
135  this->m_CameraActiveMutex->Unlock();
136  this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this);
137  // wait a little to make sure that the thread is started
138  itksys::SystemTools::Delay(10);
139  }
140  else
141  {
142  MITK_WARN << "Camera not connected";
143  }
144  }
145 
147  {
148  m_CameraActiveMutex->Lock();
149  m_CameraActive = false;
150  m_CameraActiveMutex->Unlock();
151  itksys::SystemTools::Delay(100);
152  if (m_MultiThreader.IsNotNull())
153  {
154  m_MultiThreader->TerminateThread(m_ThreadID);
155  }
156  // wait a little to make sure that the thread is terminated
157  itksys::SystemTools::Delay(10);
158  }
159 
161  {
162  m_CameraActiveMutex->Lock();
163  bool ok = m_CameraActive;
164  m_CameraActiveMutex->Unlock();
165  return ok;
166  }
167 
169  {
170  if (m_Controller)
171  {
172  m_Controller->UpdateCamera();
173  }
174  }
175 
176  ITK_THREAD_RETURN_TYPE KinectV2Device::Acquire(void* pInfoStruct)
177  {
178  /* extract this pointer from Thread Info structure */
179  struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
180  if (pInfo == nullptr)
181  {
182  return ITK_THREAD_RETURN_VALUE;
183  }
184  if (pInfo->UserData == nullptr)
185  {
186  return ITK_THREAD_RETURN_VALUE;
187  }
188  KinectV2Device* toFCameraDevice = (KinectV2Device*)pInfo->UserData;
189  if (toFCameraDevice!=nullptr)
190  {
191  mitk::RealTimeClock::Pointer realTimeClock;
192  realTimeClock = mitk::RealTimeClock::New();
193  double t1, t2;
194  t1 = realTimeClock->GetCurrentStamp();
195  int n = 100;
196  bool overflow = false;
197  bool printStatus = false;
198  while (toFCameraDevice->IsCameraActive())
199  {
200  // update the ToF camera
201  toFCameraDevice->UpdateCamera();
202  // get the image data from the camera and write it at the next free position in the buffer
203  toFCameraDevice->m_ImageMutex->Lock();
204  toFCameraDevice->m_Controller->GetAllData(toFCameraDevice->m_DistanceDataBuffer[toFCameraDevice->m_FreePos],toFCameraDevice->m_AmplitudeDataBuffer[toFCameraDevice->m_FreePos],toFCameraDevice->m_RGBDataBuffer[toFCameraDevice->m_FreePos]);
205  //Here we get also the PolyData, because the kinect V2 SDK offers an excellent
206  //default calibration and generates very nice, textured surfaces. The method
207  //GetAllData of MITK-ToF does not allow for passing the surface.
208  toFCameraDevice->m_PolyData = toFCameraDevice->m_Controller->GetVtkPolyData();
209  toFCameraDevice->m_ImageMutex->Unlock();
210 
211  // call modified to indicate that cameraDevice was modified
212  toFCameraDevice->Modified();
213 
214  bool generateTriangularMesh = false;
215  toFCameraDevice->GetBoolProperty("GenerateTriangularMesh", generateTriangularMesh);
216  toFCameraDevice->m_Controller->SetGenerateTriangularMesh(generateTriangularMesh);
217 
218  float triangulationThreshold = static_cast<mitk::FloatProperty*>(toFCameraDevice->GetProperty("TriangulationThreshold"))->GetValue();
219  toFCameraDevice->m_Controller->SetTriangulationThreshold(triangulationThreshold);
220 
221  toFCameraDevice->m_FreePos = (toFCameraDevice->m_FreePos+1) % toFCameraDevice->m_BufferSize;
222  toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize;
223  toFCameraDevice->m_ImageSequence++;
224  if (toFCameraDevice->m_FreePos == toFCameraDevice->m_CurrentPos)
225  {
226  overflow = true;
227  }
228 
229  if (overflow)
230  {
231  overflow = false;
232  }
233 
234  if(m_PrintFrameRate)
235  {
236  if (toFCameraDevice->m_ImageSequence % n == 0)
237  {
238  printStatus = true;
239  }
240  // print current framerate
241  if (printStatus)
242  {
243  t2 = realTimeClock->GetCurrentStamp() - t1;
244  MITK_INFO << " Framerate (fps): " << n / (t2/1000) << " Sequence: " << toFCameraDevice->m_ImageSequence;
245  t1 = realTimeClock->GetCurrentStamp();
246  printStatus = false;
247  }
248  }
249  } // end of while loop
250  }
251  return ITK_THREAD_RETURN_VALUE;
252  }
253 
254  void KinectV2Device::GetAmplitudes(float* amplitudeArray, int& imageSequence)
255  {
256  m_ImageMutex->Lock();
257  if (m_CameraActive)
258  {
259  memcpy(amplitudeArray, this->m_AmplitudeDataBuffer[this->m_CurrentPos], this->m_DepthBufferSize);
260  imageSequence = this->m_ImageSequence;
261  }
262  else
263  {
264  MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active.";
265  }
266  m_ImageMutex->Unlock();
267  }
268 
270  {
271  }
272 
273  void KinectV2Device::GetDistances(float* distanceArray, int& imageSequence)
274  {
275  m_ImageMutex->Lock();
276  if (m_CameraActive)
277  {
278  memcpy(distanceArray, this->m_DistanceDataBuffer[this->m_CurrentPos], this->m_DepthBufferSize);
279  imageSequence = this->m_ImageSequence;
280  }
281  else
282  {
283  MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active.";
284  }
285  m_ImageMutex->Unlock();
286  }
287 
288  void KinectV2Device::GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray,
289  int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray)
290  {
291  if (m_CameraActive)
292  {
293  // check for empty buffer
294  if (this->m_ImageSequence < 0)
295  {
296  // buffer empty
297  MITK_WARN << "Buffer empty!! ";
298  capturedImageSequence = this->m_ImageSequence;
299  return;
300  }
301  // determine position of image in buffer
302  int pos = 0;
303  if ((requiredImageSequence < 0) || (requiredImageSequence > this->m_ImageSequence))
304  {
305  capturedImageSequence = this->m_ImageSequence;
306  pos = this->m_CurrentPos;
307  }
308  else if (requiredImageSequence <= this->m_ImageSequence - this->m_BufferSize)
309  {
310  capturedImageSequence = (this->m_ImageSequence - this->m_BufferSize) + 1;
311  pos = (this->m_CurrentPos + 1) % this->m_BufferSize;
312  }
313  else // (requiredImageSequence > this->m_ImageSequence - this->m_BufferSize) && (requiredImageSequence <= this->m_ImageSequence)
314  {
315  capturedImageSequence = requiredImageSequence;
316  pos = (this->m_CurrentPos + (10-(this->m_ImageSequence - requiredImageSequence))) % this->m_BufferSize;
317  }
318  // write image data to arrays
319  m_ImageMutex->Lock();
320  memcpy(distanceArray, this->m_DistanceDataBuffer[pos], this->m_DepthBufferSize);
321  memcpy(amplitudeArray, this->m_AmplitudeDataBuffer[pos], this->m_DepthBufferSize);
322  memcpy(rgbDataArray, this->m_RGBDataBuffer[pos], this->m_RGBBufferSize);
323  m_ImageMutex->Unlock();
324 
325  //Since the standard method GetAllImages does not allow transfering a surface,
326  //we use a property to pass the surface to the workbench.
328  surface->SetVtkPolyData(this->m_PolyData);
329  this->SetProperty("ToFSurface", mitk::SmartPointerProperty::New( surface ));
330 
331  this->Modified();
332  }
333  else
334  {
335  MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active.";
336  }
337  }
338 
339  KinectV2Controller::Pointer KinectV2Device::GetController()
340  {
341  return this->m_Controller;
342  }
343 
345  {
346  return this->m_RGBImageWidth;
347  }
348 
350  {
351  return this->m_RGBImageHeight;
352  }
353 }
virtual void StartCamera()
starts the continuous updating of the camera. A separate thread updates the source data...
virtual BaseProperty * GetProperty(const char *propertyKey)
get a BaseProperty from the property list
int GetRGBCaptureHeight()
returns the height of the RGB image
virtual bool DisconnectCamera()
closes the connection to the camera
float ** m_DistanceDataBuffer
buffer holding the last distance images
KinectV2Controller::Pointer GetController()
returns the corresponding camera controller
#define MITK_INFO
Definition: mitkLogMacros.h:18
virtual void UpdateCamera()
updates the camera for image acquisition
bool GetBoolProperty(const char *propertyKey, bool &boolValue)
get a bool from the property list
int m_RGBPixelNumber
number of pixels in the range image (m_RGBImageWidth*m_RGBImageHeight)
virtual void StopCamera()
stops the continuous updating of the camera
int m_PixelNumber
number of pixels in the range image (m_CaptureWidth*m_CaptureHeight)
DataCollection - Class to facilitate loading/accessing structured data.
vcl_size_t m_RGBBufferSize
Size of RGB buffer (i.e. memory size of RGB image)
static bool m_PrintFrameRate
prints the framerate to the console every 100 frames, deactivated by default
vcl_size_t m_DepthBufferSize
Size of depth buffer (i.e. memory size of depth and infrared image)
float * m_DistanceArray
float array holding the distance image
int m_ThreadID
ID of the started thread.
static Pointer New()
KinectV2Controller::Pointer m_Controller
corresponding CameraController
int GetRGBCaptureWidth()
returns the width of the RGB image
itk::FastMutexLock::Pointer m_CameraActiveMutex
mutex for the cameraActive flag
itk::MultiThreader::Pointer m_MultiThreader
itk::MultiThreader used for thread handling
unsigned char ** m_RGBDataBuffer
buffer holding the last RGB image
int m_FreePos
current position in the buffer which will be filled with data acquired from the hardware ...
virtual void SetProperty(const char *propertyKey, BaseProperty *propertyValue)
set a BaseProperty property in the property list
int m_RGBImageHeight
height of the RGB image (y dimension)
#define MITK_WARN
Definition: mitkLogMacros.h:19
bool m_CameraActive
flag indicating if the camera is currently active or not. Caution: thread safe access only! ...
int m_CurrentPos
current position in the buffer which will be retrieved by the Get methods
bool m_CameraConnected
flag indicating if the camera is successfully connected or not. Caution: thread safe access only! ...
static ITK_THREAD_RETURN_TYPE Acquire(void *pInfoStruct)
Thread method continuously acquiring images from the ToF hardware.
bool t2(false)
virtual bool OnConnectCamera()
opens a connection to the ToF camera
std::string GetDeviceName()
int m_CaptureWidth
width of the range image (x dimension)
virtual void GetAllImages(float *distanceArray, float *amplitudeArray, float *intensityArray, char *sourceDataArray, int requiredImageSequence, int &capturedImageSequence, unsigned char *rgbDataArray=nullptr)
gets the 3 images (distance, amplitude, intensity) from the ToF camera. Caution! The user is responsi...
itk::FastMutexLock::Pointer m_ImageMutex
mutex for images provided by the range camera
virtual void GetIntensities(float *intensityArray, int &imageSequence)
Does nothing for Kinect V2 as there is no intensity data provided by the device.
int m_BufferSize
buffer size of the image buffer needed for loss-less acquisition of range data
virtual void GetDistances(float *distanceArray, int &imageSequence)
gets the distance data from the ToF camera measuring the distance between the camera and the differen...
virtual bool IsCameraActive()
returns whether the camera is currently active or not
int m_MaxBufferSize
maximal buffer size needed for initialization of data arrays. Default value is 100.
virtual void GetAmplitudes(float *amplitudeArray, int &imageSequence)
gets the amplitude data from the ToF camera as the strength of the active illumination of every pixel...
int m_CaptureHeight
height of the range image (y dimension)
Interface for all representations of Microsoft Kinect V2 devices. Kinect2Device internally holds an i...
float * m_AmplitudeArray
float array holding the amplitude image
static Pointer New(void)
instanciates a new, operating-system dependant, instance of mitk::RealTimeClock.
int m_RGBImageWidth
width of the RGB image (x dimension)
vtkSmartPointer< vtkPolyData > m_PolyData
Surface generated via the Kinect V2 SDK with default/unknown calibration.
static Pointer New()
int m_ImageSequence
counter for acquired images
float ** m_AmplitudeDataBuffer
buffer holding the last amplitude images