Medical Imaging Interaction Toolkit  2016.11.0
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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 #include "mitkKinectV2Device.h"
17 
18 
19 #include <mitkRealTimeClock.h>
21 #include <mitkSurface.h>
22 
23 #include <itkMultiThreader.h>
24 #include <itksys/SystemTools.hxx>
25 
26 
27 namespace mitk
28 {
29 
31  m_DistanceDataBuffer(NULL),
32  m_AmplitudeDataBuffer(NULL),
33  m_RGBDataBuffer(NULL),
34  m_DepthBufferSize(sizeof(float)*512*424),
35  m_RGBBufferSize(3*1920*1080)
36  {
39  }
40 
42  {
43  }
44 
45  std::string GetDeviceName()
46  {
47  return "Microsoft Kinect 2 Device ";
48  }
49 
51  {
52  bool ok = false;
53  if (m_Controller)
54  {
55  ok = m_Controller->OpenCameraConnection();
56  if (ok)
57  {
58  this->m_CaptureWidth = m_Controller->GetDepthCaptureWidth();
59  this->m_CaptureHeight = m_Controller->GetDepthCaptureHeight();
60  this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight;
61 
62  this->m_RGBImageWidth = m_Controller->GetRGBCaptureWidth();
63  this->m_RGBImageHeight = m_Controller->GetRGBCaptureHeight();
65 
66  // allocate buffer
67  this->m_DistanceArray = new float[this->m_PixelNumber];
68  for(int i=0; i<this->m_PixelNumber; i++) {this->m_DistanceArray[i]=0.0;}
69  this->m_AmplitudeArray = new float[this->m_PixelNumber];
70  for(int i=0; i<this->m_PixelNumber; i++) {this->m_AmplitudeArray[i]=0.0;}
71 
72  this->m_DistanceDataBuffer = new float*[this->m_MaxBufferSize];
73  for(int i=0; i<this->m_MaxBufferSize; i++)
74  {
75  this->m_DistanceDataBuffer[i] = new float[this->m_PixelNumber];
76  }
77  this->m_AmplitudeDataBuffer = new float*[this->m_MaxBufferSize];
78  for(int i=0; i<this->m_MaxBufferSize; i++)
79  {
80  this->m_AmplitudeDataBuffer[i] = new float[this->m_PixelNumber];
81  }
82  this->m_RGBDataBuffer = new unsigned char*[this->m_MaxBufferSize];
83  for (int i=0; i<this->m_MaxBufferSize; i++)
84  {
85  this->m_RGBDataBuffer[i] = new unsigned char[this->m_RGBPixelNumber*3];
86  }
87 
88  m_CameraConnected = true;
89  }
90  }
91  return ok;
92  }
93 
95  {
96  bool ok = false;
97  if (m_Controller)
98  {
99  ok = m_Controller->CloseCameraConnection();
100 
101  // clean-up only if camera was connected
102  if (m_CameraConnected)
103  {
104  delete [] m_DistanceArray;
105  delete [] m_AmplitudeArray;
106 
107  for(int i=0; i<this->m_MaxBufferSize; i++)
108  {
109  delete[] this->m_DistanceDataBuffer[i];
110  delete[] this->m_AmplitudeDataBuffer[i];
111  delete[] this->m_RGBDataBuffer[i];
112  }
113  delete[] this->m_DistanceDataBuffer;
114  delete[] this->m_AmplitudeDataBuffer;
115  delete[] this->m_RGBDataBuffer;
116 
117  m_CameraConnected = false;
118  }
119  }
120  return ok;
121  }
122 
124  {
125  if (m_CameraConnected)
126  {
127  // get the first image
128  this->m_Controller->UpdateCamera();
129  this->m_ImageMutex->Lock();
130  this->m_Controller->GetAllData(this->m_DistanceDataBuffer[this->m_FreePos],this->m_AmplitudeDataBuffer[this->m_FreePos],this->m_RGBDataBuffer[this->m_FreePos]);
131  this->m_FreePos = (this->m_FreePos+1) % this->m_BufferSize;
132  this->m_CurrentPos = (this->m_CurrentPos+1) % this->m_BufferSize;
133  this->m_ImageSequence++;
134  this->m_ImageMutex->Unlock();
135 
136  this->m_CameraActiveMutex->Lock();
137  this->m_CameraActive = true;
138  this->m_CameraActiveMutex->Unlock();
139  this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this);
140  // wait a little to make sure that the thread is started
141  itksys::SystemTools::Delay(10);
142  }
143  else
144  {
145  MITK_WARN << "Camera not connected";
146  }
147  }
148 
150  {
151  m_CameraActiveMutex->Lock();
152  m_CameraActive = false;
153  m_CameraActiveMutex->Unlock();
154  itksys::SystemTools::Delay(100);
155  if (m_MultiThreader.IsNotNull())
156  {
157  m_MultiThreader->TerminateThread(m_ThreadID);
158  }
159  // wait a little to make sure that the thread is terminated
160  itksys::SystemTools::Delay(10);
161  }
162 
164  {
165  m_CameraActiveMutex->Lock();
166  bool ok = m_CameraActive;
167  m_CameraActiveMutex->Unlock();
168  return ok;
169  }
170 
172  {
173  if (m_Controller)
174  {
175  m_Controller->UpdateCamera();
176  }
177  }
178 
179  ITK_THREAD_RETURN_TYPE KinectV2Device::Acquire(void* pInfoStruct)
180  {
181  /* extract this pointer from Thread Info structure */
182  struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
183  if (pInfo == NULL)
184  {
185  return ITK_THREAD_RETURN_VALUE;
186  }
187  if (pInfo->UserData == NULL)
188  {
189  return ITK_THREAD_RETURN_VALUE;
190  }
191  KinectV2Device* toFCameraDevice = (KinectV2Device*)pInfo->UserData;
192  if (toFCameraDevice!=NULL)
193  {
194  mitk::RealTimeClock::Pointer realTimeClock;
195  realTimeClock = mitk::RealTimeClock::New();
196  double t1, t2;
197  t1 = realTimeClock->GetCurrentStamp();
198  int n = 100;
199  bool overflow = false;
200  bool printStatus = false;
201  while (toFCameraDevice->IsCameraActive())
202  {
203  // update the ToF camera
204  toFCameraDevice->UpdateCamera();
205  // get the image data from the camera and write it at the next free position in the buffer
206  toFCameraDevice->m_ImageMutex->Lock();
207  toFCameraDevice->m_Controller->GetAllData(toFCameraDevice->m_DistanceDataBuffer[toFCameraDevice->m_FreePos],toFCameraDevice->m_AmplitudeDataBuffer[toFCameraDevice->m_FreePos],toFCameraDevice->m_RGBDataBuffer[toFCameraDevice->m_FreePos]);
208  //Here we get also the PolyData, because the kinect V2 SDK offers an excellent
209  //default calibration and generates very nice, textured surfaces. The method
210  //GetAllData of MITK-ToF does not allow for passing the surface.
211  toFCameraDevice->m_PolyData = toFCameraDevice->m_Controller->GetVtkPolyData();
212  toFCameraDevice->m_ImageMutex->Unlock();
213 
214  // call modified to indicate that cameraDevice was modified
215  toFCameraDevice->Modified();
216 
217  bool generateTriangularMesh = false;
218  toFCameraDevice->GetBoolProperty("GenerateTriangularMesh", generateTriangularMesh);
219  toFCameraDevice->m_Controller->SetGenerateTriangularMesh(generateTriangularMesh);
220 
221  float triangulationThreshold = static_cast<mitk::FloatProperty*>(toFCameraDevice->GetProperty("TriangulationThreshold"))->GetValue();
222  toFCameraDevice->m_Controller->SetTriangulationThreshold(triangulationThreshold);
223 
224  toFCameraDevice->m_FreePos = (toFCameraDevice->m_FreePos+1) % toFCameraDevice->m_BufferSize;
225  toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize;
226  toFCameraDevice->m_ImageSequence++;
227  if (toFCameraDevice->m_FreePos == toFCameraDevice->m_CurrentPos)
228  {
229  overflow = true;
230  }
231  if (toFCameraDevice->m_ImageSequence % n == 0)
232  {
233  printStatus = true;
234  }
235  if (overflow)
236  {
237  overflow = false;
238  }
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  } // end of while loop
249  }
250  return ITK_THREAD_RETURN_VALUE;
251  }
252 
253  void KinectV2Device::GetAmplitudes(float* amplitudeArray, int& imageSequence)
254  {
255  m_ImageMutex->Lock();
256  if (m_CameraActive)
257  {
258  memcpy(amplitudeArray, this->m_AmplitudeDataBuffer[this->m_CurrentPos], this->m_DepthBufferSize);
259  imageSequence = this->m_ImageSequence;
260  }
261  else
262  {
263  MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active.";
264  }
265  m_ImageMutex->Unlock();
266  }
267 
269  {
270  }
271 
272  void KinectV2Device::GetDistances(float* distanceArray, int& imageSequence)
273  {
274  m_ImageMutex->Lock();
275  if (m_CameraActive)
276  {
277  memcpy(distanceArray, this->m_DistanceDataBuffer[this->m_CurrentPos], this->m_DepthBufferSize);
278  imageSequence = this->m_ImageSequence;
279  }
280  else
281  {
282  MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active.";
283  }
284  m_ImageMutex->Unlock();
285  }
286 
287  void KinectV2Device::GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* sourceDataArray,
288  int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray)
289  {
290  if (m_CameraActive)
291  {
292  // check for empty buffer
293  if (this->m_ImageSequence < 0)
294  {
295  // buffer empty
296  MITK_WARN << "Buffer empty!! ";
297  capturedImageSequence = this->m_ImageSequence;
298  return;
299  }
300  // determine position of image in buffer
301  int pos = 0;
302  if ((requiredImageSequence < 0) || (requiredImageSequence > this->m_ImageSequence))
303  {
304  capturedImageSequence = this->m_ImageSequence;
305  pos = this->m_CurrentPos;
306  }
307  else if (requiredImageSequence <= this->m_ImageSequence - this->m_BufferSize)
308  {
309  capturedImageSequence = (this->m_ImageSequence - this->m_BufferSize) + 1;
310  pos = (this->m_CurrentPos + 1) % this->m_BufferSize;
311  }
312  else // (requiredImageSequence > this->m_ImageSequence - this->m_BufferSize) && (requiredImageSequence <= this->m_ImageSequence)
313  {
314  capturedImageSequence = requiredImageSequence;
315  pos = (this->m_CurrentPos + (10-(this->m_ImageSequence - requiredImageSequence))) % this->m_BufferSize;
316  }
317  // write image data to arrays
318  m_ImageMutex->Lock();
319  memcpy(distanceArray, this->m_DistanceDataBuffer[pos], this->m_DepthBufferSize);
320  memcpy(amplitudeArray, this->m_AmplitudeDataBuffer[pos], this->m_DepthBufferSize);
321  memcpy(rgbDataArray, this->m_RGBDataBuffer[pos], this->m_RGBBufferSize);
322  vtkSmartPointer<vtkPolyData> deepCopyOfPoly = vtkSmartPointer<vtkPolyData>::New();
323  deepCopyOfPoly->DeepCopy(this->m_PolyData);
324  m_ImageMutex->Unlock();
325 
326  //Since the standard method GetAllImages does not allow transfering a surface,
327  //we use a property to pass the surface to the workbench.
329  surface->SetVtkPolyData( deepCopyOfPoly );
330  this->SetProperty("ToFSurface", mitk::SmartPointerProperty::New( surface ));
331 
332  this->Modified();
333  }
334  else
335  {
336  MITK_WARN("ToF") << "Warning: Data can only be acquired if camera is active.";
337  }
338  }
339 
341  {
342  return this->m_Controller;
343  }
344 
346  {
347  return this->m_RGBImageWidth;
348  }
349 
351  {
352  return this->m_RGBImageHeight;
353  }
354 }
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
itk::SmartPointer< Self > Pointer
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:22
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)
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
virtual void GetAllImages(float *distanceArray, float *amplitudeArray, float *intensityArray, char *sourceDataArray, int requiredImageSequence, int &capturedImageSequence, unsigned char *rgbDataArray=NULL)
gets the 3 images (distance, amplitude, intensity) from the ToF camera. Caution! The user is responsi...
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:23
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.
virtual bool OnConnectCamera()
opens a connection to the ToF camera
std::string GetDeviceName()
int m_CaptureWidth
width of the range image (x dimension)
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
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.