direcs  2012-09-30
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
QKinect.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * This file is part of the OpenKinect Project. http://www.openkinect.org *
3  * *
4  * Copyright (c) 2010 individual OpenKinect contributors. *
5  * See the CONTRIB file for details. *
6  * *
7  * This file is part of direcs. *
8  * www.direcs.de *
9  * *
10  * direcs is free software: you can redistribute it and/or modify it *
11  * under the terms of the GNU General Public License as published *
12  * by the Free Software Foundation, version 3 of the License. *
13  * *
14  * direcs is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with direcs. If not, see <http://www.gnu.org/licenses/>. *
21  * *
22  ***************************************************************************/
23 
24 //----------------------------------------------------------------------------------------------------------------------
28 //----------------------------------------------------------------------------------------------------------------------
29 
30 #include <QKinect.h>
31 #include <QDebug>
32 #include <cstdlib>
33 #include <cmath>
34 #include <cassert>
35 
36 
37 //----------------------------------------------------------------------------------------------------------------------
38 QKinect *QKinect::s_instance = 0;// initialize pointer
39 //----------------------------------------------------------------------------------------------------------------------
40 
41 
43 {
44  // loop while we are active and process the kinect event queue
45  while(m_active)
46  {
47  //qDebug()<<"process thread\n";
48  if (freenect_process_events(m_ctx) < 0)
49  {
50  throw std::runtime_error("Cannot process freenect events");
51  }
52  }
53 }
54 
55 
57 {
58  // dtor is not called directly
59  if (s_instance)
60  {
61  delete s_instance;
62  }
63 }
64 
65 
67 {
68  // this is the main singleton code first check to see if we exist
69  if (s_instance==0 )
70  {
71  // we do so create an instance (this will validate the pointer so other
72  // methods called in the init function will have a valid pointer to use)
73  s_instance = new QKinect;
74  // now setup the actual class (with a valid pointer)
76  s_instance->init();
77  }
78 
79  // otherwise return the existing pointer
80  return s_instance;
81 }
82 
83 
84 QKinect::QKinect() : QObject(0)
85 {
86  kinectDetected = false;
87 
88  // nothing to see here we just need a valid object pointer the init
89  // method does all the hard work
90  //qDebug()<<"ctor called \n";
91 }
92 
93 
95 {
96  // first see if we can init the kinect
97  if (freenect_init(&m_ctx, NULL) < 0)
98  {
99  emit message("freenect_init() failed");
100 
101  kinectDetected = false;
102 
103  return;
104  }
105 
107  freenect_set_log_level(m_ctx, FREENECT_LOG_DEBUG);
108 
110  int nr_devices = freenect_num_devices (m_ctx);
111 
112  emit message(QString("%1 Kinects found.").arg(nr_devices));
113 
115  m_userDeviceNumber = 0;
116  m_bufferDepth.resize(FREENECT_VIDEO_RGB_SIZE);
117  m_bufferVideo.resize(FREENECT_VIDEO_RGB_SIZE);
118  m_bufferDepthRaw.resize(FREENECT_FRAME_PIX);
119  m_bufferDepthRaw16.resize(FREENECT_FRAME_PIX);
120  m_gamma.resize(2048);
121 
125  if (freenect_open_device(m_ctx, &m_dev, m_userDeviceNumber) < 0)
126  {
127  emit message("ERROR opening Kinect device.");
128 
129  kinectDetected = false;
130 
131  return;
132  }
133 
136  for (int i=0; i<2048; ++i)
137  {
138  float v = i/2048.0;
139  v = std::pow(v, 3)* 6;
140  m_gamma[i] = v*6*256;
141  }
142 
144  m_newRgbFrame=false;
145  m_newDepthFrame=false;
146  m_deviceActive=true;
147 
148  // set our video formats to RGB by default
150  freenect_set_video_format(m_dev, FREENECT_VIDEO_RGB);
151  freenect_set_depth_format(m_dev, FREENECT_DEPTH_11BIT);
152 
154  freenect_set_depth_callback(m_dev, depthCallback);
155  freenect_set_video_callback(m_dev, videoCallback);
156 
157  // start the video and depth sub systems
158  startVideo();
159  startDepth();
160 
161  // set the thread to be active and start
163  m_process->setActive();
164  m_process->start();
165  setGreenLed();
166 
167  kinectDetected = true;
168 }
169 
170 
172 {
176  freenect_stop_depth(m_dev);
177  freenect_stop_video(m_dev);
178  // close down our devices
179  freenect_close_device(m_dev);
180  freenect_shutdown(m_ctx);
181 
182 }
183 
184 
186 {
187  freenect_set_led(m_dev,LED_OFF);
188 }
189 
190 
192 {
193  freenect_set_led(m_dev,LED_RED);
194 }
195 
196 
198 {
199  freenect_set_led(m_dev,LED_GREEN);
200 }
201 
202 
204 {
205  freenect_set_led(m_dev,LED_YELLOW);
206 }
207 
208 
210 {
211  freenect_set_led(m_dev,LED_BLINK_RED_YELLOW);
212 }
213 
214 
216 {
217  freenect_set_led(m_dev,LED_BLINK_GREEN);
218 }
219 
220 
222 {
223  freenect_set_led(m_dev,LED_BLINK_RED_YELLOW);
224 }
225 
226 
227 void QKinect::setVideoMode(int _mode)
228 {
229  freenect_video_format vm=FREENECT_VIDEO_RGB;
230 
231  switch(_mode)
232  {
233  case 0 : { vm=FREENECT_VIDEO_RGB; break;}
234  case 1 : { vm=FREENECT_VIDEO_YUV_RGB; break;}
235  case 2 : { vm=FREENECT_VIDEO_IR_8BIT; break;}
236  /*
238  case 1 : { vm=FREENECT_VIDEO_BAYER; break;}
239  case 2 : { vm=FREENECT_VIDEO_IR_8BIT; break;}
240  case 3 : { vm=FREENECT_VIDEO_IR_10BIT; break;}
241  case 4 : { vm=FREENECT_VIDEO_IR_10BIT_PACKED; break;}
242  case 5 : { vm=FREENECT_VIDEO_YUV_RGB; break;}
243  case 6 : { vm=FREENECT_VIDEO_YUV_RAW; break;}
244  */
245  default :
246  {
247  emit message("Kinect: index out of bounds for video mode");
248  vm = FREENECT_VIDEO_RGB;
249  }
250  break;
251  }
252 
254  freenect_stop_video(m_dev);
255  freenect_set_video_format(m_dev, vm);
256  freenect_start_video(m_dev);
257 }
258 
259 
261 {
262  freenect_set_tilt_degs(m_dev,0);
263 }
264 
265 
266 void QKinect::setAngle(double _angle)
267 {
268  // constrain the angle from -30 - +30
269  if(_angle > 30)
270  {
271  _angle = 30;
272  }
273  else if(_angle <-30)
274  {
275  _angle=-30;
276  }
277 
278  freenect_set_tilt_degs(m_dev,_angle);
279 }
280 
281 
282 bool QKinect::getRGB(std::vector<uint8_t> &o_buffer)
283 {
286  QMutexLocker locker( &m_mutex );
287 
288  // do we have a new frame?
289  if(m_newRgbFrame)
290  {
291  // if so swap out and fill
292  o_buffer.swap(m_bufferVideo);
293  m_newRgbFrame = false;
294  return true;
295  }
296  else
297  {
298  return false;
299  }
300 }
301 
302 
303 bool QKinect::getDepth(std::vector<uint8_t> &o_buffer)
304 {
305  // this fills the depth buffer, first lock our mutex
306  QMutexLocker locker( &m_mutex );
307 
308  if(m_newDepthFrame)
309  {
310  // swap data
311  o_buffer.swap(m_bufferDepth);
312  m_newDepthFrame = false;
313  return true;
314  }
315  else
316  {
317  return false;
318  }
319 }
320 
321 
322 bool QKinect::getDepth16Bit(std::vector<uint16_t> &o_buffer)
323 {
325  QMutexLocker locker( &m_mutex );
326 
327  if(m_newDepthFrame)
328  {
329  // fill our buffer if avaliable
330  o_buffer.swap( m_bufferDepthRaw16 );
331  m_newDepthFrame = false;
332  return true;
333  }
334  else
335  {
336  return false;
337  }
338 }
339 
340 
341 bool QKinect::getDepthRaw(std::vector<uint8_t> &o_buffer)
342 {
343  //qDebug()<< "getDepth callback\n";
344  QMutexLocker locker( &m_mutex );
345 
346  if(m_newDepthFrame)
347  {
348  o_buffer.swap(m_bufferDepthRaw);
349  m_newDepthFrame = false;
350  return true;
351  }
352  else
353  {
354  return false;
355  }
356 }
357 
358 
359 void QKinect::grabDepth(void *_depth, uint32_t _timestamp)
360 {
361  // this method fills all the different depth buffers at once
362  // modifed from the sample code glview and cppview.cpp
364  QMutexLocker locker( &m_mutex );
365 
366  // cast the void pointer to the unint16_t the data is actually in
367  uint16_t* depth = static_cast<uint16_t*>(_depth);
368 
369  // now loop and fill data buffers
370  for (unsigned int i = 0; i < FREENECT_FRAME_PIX; ++i)
371  {
372  // first our two raw buffers the first will lose precision and may well
373  // be removed in the next iterations
374  m_bufferDepthRaw[i]=depth[i];
375  m_bufferDepthRaw16[i]=depth[i];
376 
377  // now get the index into the gamma table
378  int pval = m_gamma[depth[i]];
379 
380  // get the lower bit
381  int lb = pval & 0xff;
382 
383  // shift right by 8 and determine which colour value to fill the
384  // array with based on the position
385  switch (pval>>8)
386  {
387  case 0:
388  m_bufferDepth[3*i+0] = 255;
389  m_bufferDepth[3*i+1] = 255-lb;
390  m_bufferDepth[3*i+2] = 255-lb;
391  break;
392  case 1:
393  m_bufferDepth[3*i+0] = 255;
394  m_bufferDepth[3*i+1] = lb;
395  m_bufferDepth[3*i+2] = 0;
396  break;
397  case 2:
398  m_bufferDepth[3*i+0] = 255-lb;
399  m_bufferDepth[3*i+1] = 255;
400  m_bufferDepth[3*i+2] = 0;
401  break;
402  case 3:
403  m_bufferDepth[3*i+0] = 0;
404  m_bufferDepth[3*i+1] = 255;
405  m_bufferDepth[3*i+2] = lb;
406  break;
407  case 4:
408  m_bufferDepth[3*i+0] = 0;
409  m_bufferDepth[3*i+1] = 255-lb;
410  m_bufferDepth[3*i+2] = 255;
411  break;
412  case 5:
413  m_bufferDepth[3*i+0] = 0;
414  m_bufferDepth[3*i+1] = 0;
415  m_bufferDepth[3*i+2] = 255-lb;
416  break;
417  default:
418  m_bufferDepth[3*i+0] = 0;
419  m_bufferDepth[3*i+1] = 0;
420  m_bufferDepth[3*i+2] = 0;
421  break;
422  }
423  }
424 
425  // flag we have a new frame
426  m_newDepthFrame = true;
427 
428  Q_UNUSED(_timestamp);
429 }
430 
431 
432 void QKinect::grabVideo(void *_video, uint32_t _timestamp)
433 {
434  // lock our mutex and copy the data from the video buffer
435  QMutexLocker locker( &m_mutex );
436 
437  uint8_t* rgb = static_cast<uint8_t*>(_video);
438  std::copy(rgb, rgb+FREENECT_VIDEO_RGB_SIZE, m_bufferVideo.begin());
439  m_newRgbFrame = true;
440 
441  Q_UNUSED(_timestamp);
442 }
443 
444 
446 {
447  if(freenect_start_video(m_dev) < 0)
448  {
449  throw std::runtime_error("Cannot start RGB callback");
450  }
451 }
452 
453 
455 {
456  if(freenect_stop_video(m_dev) < 0)
457  {
458  throw std::runtime_error("Cannot stop RGB callback");
459  }
460 }
461 
462 
464 {
465  if(freenect_start_depth(m_dev) < 0)
466  {
467  throw std::runtime_error("Cannot start depth callback");
468  }
469 }
470 
471 
473 {
474  if(freenect_stop_depth(m_dev) < 0)
475  {
476  throw std::runtime_error("Cannot stop depth callback");
477  }
478 }
479 
480 
482 {
483  if(_mode ==true)
484  {
485  startVideo();
486  }
487  else
488  {
489  stopVideo();
490  }
491 }
492 
493 
495 {
496  if(_mode == true)
497  {
498  startDepth();
499  }
500  else
501  {
502  stopDepth();
503  }
504 }