Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.