Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
VideoSource_Kinect_win32.cpp
1 /*
2  This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4  Copyright (C) 2003, 2004 (see file CONTACTS for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10  BIAS is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation; either version 2.1 of the License, or
13  (at your option) any later version.
14 
15  BIAS is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with BIAS; if not, write to the Free Software
22  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  */
24 
25 #include "VideoSource_Kinect.hh"
26 #include <iostream>
27 #include <Base/Image/ImageIO.hh>
28 #include <pthread.h>
29 
30 using namespace std;
31 
32 namespace BIAS {
33 
34  /////////////////////////////////////////////////////////////////////////
35  ///////////////////////VideoSource_Kinect////////////////////////////////
36  /////////////////////////////////////////////////////////////////////////
37 
38  int VideoSource_Kinect::deviceCount_ = 0;
39  int VideoSource_Kinect::openDevices_ = 0;
40  freenect_device* freenectDevice_ = NULL;
41  freenect_context* freenectContext_ = NULL;
42 
43  pthread_t freenect_thread;
44  volatile int die = 0;
45 
46  // back: owned by libfreenect (implicit for depth)
47  // mid: owned by callbacks, "latest frame ready"
48  // front: owned by class,
50  unsigned char *rgb_back, *rgb_mid, *rgb_front;
51  float lookup_[2048];
52 
53  freenect_video_format requested_format = FREENECT_VIDEO_BAYER;
54  freenect_video_format current_format = FREENECT_VIDEO_BAYER;
55 
56  pthread_mutex_t gl_backbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
57  pthread_cond_t gl_frame_cond = PTHREAD_COND_INITIALIZER;
58 
59  pthread_mutex_t coloravail_mutex = PTHREAD_MUTEX_INITIALIZER;
60  pthread_mutex_t depthavail_mutex = PTHREAD_MUTEX_INITIALIZER;
61  pthread_cond_t newColorAvail_ = PTHREAD_COND_INITIALIZER;
62  pthread_cond_t newDepthAvail_ = PTHREAD_COND_INITIALIZER;
63 
64  int got_rgb = 0;
65  int got_depth = 0;
67 
68  bool switch_;
69  int capMode_;
70 
71  VideoSource_Kinect::VideoSource_Kinect()
72  {
73  Active_ = false;
74  Width_ = 640;
75  Height_ = 480;
76  capMode_ = (int)VideoSource_Kinect::DepthRay;
77  }
78 
79 
80  VideoSource_Kinect::~VideoSource_Kinect()
81  {
82  if (openDevices_ != 0) {
83  CloseDevice();
84  }
85  DeleteDepthLookupTable();
86  }
87 
88  int VideoSource_Kinect::
89  OpenDevice()
90  {
91  return OpenDevice(0);
92  }
93 
94  int VideoSource_Kinect::
95  OpenDevice(int device)
96  {
97  if (openDevices_ > 0 && device==0) {
98  BIASWARN("Kinect: I guess you try to open the next device (device=0 given)");
99  device = openDevices_;
100  BIASWARN("Kinect: Trying to open device " << device << " instead");
101  }
102 
103  if (freenect_init(&freenectContext_, NULL) < 0)
104  {
105  BIASERR("Could not init freenect!");
106  return -1;
107  }
108 
109  deviceCount_ = freenect_num_devices (freenectContext_);
110  cout<<"Number of devices found: "<< deviceCount_;
111 
112  if (deviceCount_ < 1){
113  BIASERR("No devices found, returning");
114  return -2;
115  }
116 
117  if (freenect_open_device(freenectContext_, &freenectDevice_, device) < 0) {
118  BIASERR("Could not open device.");
119  return -3;
120  }
121 
122  CreateDepthLookupTable();
123 
124  deviceId_ = device;
125  openDevices_++;
126  return 0;
127  }
128 
129  int VideoSource_Kinect::CloseDevice() {
130  openDevices_--;
131  Active_ = false;
132  return 0;
133  }
134 
135  /////////////////////////////////////////////////////////////////////////////
136  void DepthCallBack(freenect_device *dev, void *v_depth, uint32_t timestamp)
137  {
138  uint16_t *depth = (uint16_t*)v_depth;
139  float *lut = depthLookupTable_->GetImageData();
140 
141  pthread_mutex_lock(&gl_backbuf_mutex);
142  switch (capMode_) {
143  case VideoSource_Kinect::DepthRay: {
144  for (unsigned int x=0;x<640*480;x++) {
145  depth_mid[x] = lookup_[ depth[x] ] * lut[x];
146  }
147  break;
148  }
149  case VideoSource_Kinect::DepthEuclidean: {
150  for (unsigned int x=0;x<640*480;x++) {
151  depth_mid[x] = lookup_[ depth[x] ];
152  }
153  break;
154  }
155  case VideoSource_Kinect::DepthRaw: {
156  for (unsigned int x=0;x<640*480;x++) {
157  depth_mid[x] = lookup_[x];
158  }
159  break;
160  }
161  default: {
162  BIASERR("unknown mode")
163  break;
164  }
165  }
166  got_depth++;
167  pthread_cond_signal(&gl_frame_cond);
168  pthread_mutex_unlock(&gl_backbuf_mutex);
169  pthread_cond_signal(&newDepthAvail_);
170  }
171  /////////////////////////////////////////////////////////////////////////////
172  void VideoCallback(freenect_device *dev, void *rgb, uint32_t timestamp)
173  {
174  pthread_mutex_lock(&gl_backbuf_mutex);
175 
176  // swap buffers
177  assert (rgb_back == rgb);
178  rgb_back = rgb_mid;
179  freenect_set_video_buffer(dev, rgb_back);
180  rgb_mid = (uint8_t*)rgb;
181 
182  got_rgb++;
183  pthread_cond_signal(&gl_frame_cond);
184  pthread_mutex_unlock(&gl_backbuf_mutex);
185  pthread_cond_signal(&newColorAvail_);
186  }
187 
188  /////////////////////////////////////////////////////////////////////////////
189  void *FreenectThreadFunc_(void *arg)
190  {
191  freenect_set_tilt_degs(freenectDevice_,0);
192  freenect_set_led(freenectDevice_,LED_RED);
193  freenect_set_depth_callback(freenectDevice_, DepthCallBack);
194  freenect_set_video_callback(freenectDevice_, VideoCallback);
195  freenect_set_video_format(freenectDevice_, current_format);
196  freenect_set_depth_format(freenectDevice_, FREENECT_DEPTH_11BIT);
197  freenect_set_video_buffer(freenectDevice_, rgb_back);
198 
199  freenect_start_depth(freenectDevice_);
200  freenect_start_video(freenectDevice_);
201 
202  while (!die && freenect_process_events(freenectContext_) >= 0)
203  {
205  freenect_stop_video(freenectDevice_);
206  freenect_set_video_format(freenectDevice_, requested_format);
207  freenect_start_video(freenectDevice_);
209  }
210  }
211 
212  freenect_stop_depth(freenectDevice_);
213  freenect_stop_video(freenectDevice_);
214 
215  freenect_close_device(freenectDevice_);
216  freenect_shutdown(freenectContext_);
217 
218  return NULL;
219  }
220 ////////////////////////////////////////////////////////////////////////
221 
222  int VideoSource_Kinect::PreGrab() {
223  cout << "Pregrab Device " << deviceId_ << endl;
224  int res = pthread_create(&freenect_thread, NULL, FreenectThreadFunc_, NULL);
225  if (res) {
226  BIASERR("Creating Freenect thread failed");
227  return 1;
228  }
229 
230  depth_mid = new float[640*480*3];
231  depth_front = new float[640*480*3];
232  rgb_back = new unsigned char[640*480*3];
233  rgb_mid = new unsigned char[640*480*3];
234  rgb_front = new unsigned char[640*480*3];
235 
236  for (int i=0; i<2048; i++) {
237  const float k1 = 1.1863f;
238  const float k2 = 2842.5f;
239  const float k3 = 0.1236f;
240  const float depth = k3 * tanf(i/k2 + k1);
241  lookup_[i] = depth * 1000.0f;
242  }
243  lookup_[2047] = 0.0f;
244 
245  Active_ = true;
246  return 0;
247  }
248 
249  int VideoSource_Kinect::PostGrab() {
250  die = 1;
251  pthread_join(freenect_thread, NULL);
252  delete[] depth_mid;
253  delete[] depth_front;
254  delete[] rgb_back;
255  delete[] rgb_mid;
256  delete[] rgb_front;
257  return 0;
258  }
259 
260 
261  int VideoSource_Kinect::
262  InitImage(BIAS::ImageBase &Image)
263  {
264  if (!Image.IsEmpty()) {
265  BIASWARN("Image already inited");
266  return 1;
267  }
268  Image.Init(640,480,1);
269  Image.SetColorModel(ImageBase::CM_Bayer_GRBG);
270  return 0;
271  }
272 
273  int VideoSource_Kinect::
274  InitDepthImage(BIAS::ImageBase &Image)
275  {
276  if (!Image.IsEmpty()) {
277  BIASWARN("Kinect Error: image already inited");
278  return 1;
279  }
280  Image.Init(640,480,1,ImageBase::ST_float);
281  Image.SetColorModel(ImageBase::CM_Depth);
282 
283  return 0;
284  }
285 
286  int VideoSource_Kinect::
287  GrabSingle(BIAS::Camera <unsigned char> &image)
288  {
289  pthread_cond_wait(&newColorAvail_, &coloravail_mutex);
290  unsigned char *tmp;
291  if (got_rgb) {
292  tmp = rgb_front;
293  rgb_front = rgb_mid;
294  rgb_mid = tmp;
295  got_rgb = 0;
296  }
297  image.CopyIn_NoInit(rgb_front);
298  return 0;
299  }
300 
301  int VideoSource_Kinect::GrabSingleDepth(BIAS::Camera <float> &image)
302  {
303  pthread_cond_wait(&newDepthAvail_, &depthavail_mutex);
304  float *tmp;
305 
306  if (got_depth) {
307  tmp = depth_front;
309  depth_mid = tmp;
310  got_depth = 0;
311  }
312  image.CopyIn_NoInit(depth_front);
313  return 0;
314  }
315 
316  int VideoSource_Kinect::SetVideoModeColor() {
317  requested_format = FREENECT_VIDEO_BAYER;
318  return 0;
319  }
320 
321  int VideoSource_Kinect::SetVideoModeIR() {
322  requested_format = FREENECT_VIDEO_IR_8BIT;
323  return 0;
324  }
325 
326  int VideoSource_Kinect::SetDepthCaptureMode(CaptureMode mode) {
327  capMode_ = (int)mode;
328  return 0;
329  }
330 
331  int VideoSource_Kinect::SetSwitchVideoModeAfterGrab() {
332  BIASERR("Not implemented!");
333  return 0;
334  }
335 
336  int VideoSource_Kinect::SetTilt(double degrees) {
337  freenect_set_tilt_degs(freenectDevice_,degrees);
338  return 0;
339  }
340 
341  int VideoSource_Kinect::SetLed(int mode) {
342  freenect_set_led(freenectDevice_,(freenect_led_options)mode);
343  return 0;
344  }
345 
346  int VideoSource_Kinect::GetAccelerometer(double &tilt, double &x, double &y, double &z) {
347  freenect_raw_tilt_state* state=NULL;
348  freenect_update_tilt_state(freenectDevice_);
349  state = freenect_get_tilt_state(freenectDevice_);
350  tilt = freenect_get_tilt_degs(state);
351  freenect_get_mks_accel(state, &x, &y, &z);
352  return 0;
353  }
354 
355  int VideoSource_Kinect::GetCapabilities(VideoSourceCapabilities &caps)
356  {
357  return 0;
358  }
359 
360  int VideoSource_Kinect::GetCapabilities(const char *device, VideoSourceCapabilities &caps)
361  {
362  return 0;
363  }
364 
365  int VideoSource_Kinect::
366  CreateDepthLookupTable(double px, double py, double fx, double fy)
367  {
368  if (depthLookupTable_ == NULL) {
369 
370  depthLookupTable_ = new Image<float>(640,480,1);
371  float **ida = depthLookupTable_->GetImageDataArray();
372 
373  for(unsigned y=0;y<480;y++){
374  for(unsigned x=0;x<640;x++){
375  float alpha = atan(float((x-px)/fx));
376  float beta = atan(float((py-y)/ sqrt( pow((x-px)*(fy/fx),2) + pow(fy,2))));
377  ida[y][x] = 1.0f / (cos(beta) * cos(alpha));
378  }
379  }
380  }
381  return 0;
382  }
383 
384  void VideoSource_Kinect::
385  DeleteDepthLookupTable()
386  {
387  if (depthLookupTable_ != NULL) {
388  delete depthLookupTable_;
389  depthLookupTable_ = NULL;
390  }
391  }
392 
393 
394  int VideoSource_Kinect::
395  ToggleDepthStream(){
396  BIASERR("ToggleDepthStream not implemented for windows and libfreenect.");
397  return -1;
398  }
399 }
pthread_t freenect_thread
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
void CopyIn_NoInit(void *data)
Take some data and fill it into the Image.
Definition: ImageBase.cpp:827
void DepthCallBack(freenect_device *dev, void *v_depth, uint32_t timestamp)
freenect_context * freenectContext_
BIAS::Image< float > * depthLookupTable_
void SetColorModel(EColorModel Model)
Definition: ImageBase.hh:561
pthread_mutex_t coloravail_mutex
freenect_video_format current_format
freenect_device * freenectDevice_
float lookup_[2048]
pthread_cond_t newColorAvail_
pthread_cond_t gl_frame_cond
void VideoCallback(freenect_device *dev, void *rgb, uint32_t timestamp)
pthread_mutex_t depthavail_mutex
pthread_cond_t newDepthAvail_
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
freenect_video_format requested_format
void Init(unsigned int width, unsigned int height, unsigned int nChannels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
Initialize image size and channels.
Definition: ImageBase.cpp:229
pthread_mutex_t gl_backbuf_mutex
unsigned char * rgb_back
unsigned char * rgb_front
unsigned char * rgb_mid
This is the base class for images in BIAS.
Definition: ImageBase.hh:102
volatile int die
void * FreenectThreadFunc_(void *arg)
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153