Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
VideoSource_Kinect.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 
29 using namespace std;
30 
31 namespace BIAS {
32 
33  /////////////////////////////////////////////////////////////////////////
34  ///////////////////////VideoSource_Kinect////////////////////////////////
35  /////////////////////////////////////////////////////////////////////////
36 
37  Freenect::Freenect *VideoSource_Kinect::kinectManager_ = NULL;
38  int VideoSource_Kinect::deviceCount_ = 0;
39  int VideoSource_Kinect::openDevices_ = 0;
40 
41 
42  VideoSource_Kinect::VideoSource_Kinect() {
43  kinectDevice_ = NULL;
44  Active_ = false;
45  Width_ = 640;
46  Height_ = 480;
47  }
48 
49 
50  VideoSource_Kinect::~VideoSource_Kinect() {
51 
52  if (openDevices_ != 0) {
53  CloseDevice();
54  }
55  if (openDevices_ == 0) {
56  // todo this does not always return
57  //if (kinectManager_ != NULL) delete kinectManager_;
58  kinectManager_ = NULL;
59  }
60  }
61 
62  int VideoSource_Kinect::
63  OpenDevice()
64  {
65  return OpenDevice(0);
66  }
67 
68  int VideoSource_Kinect::
69  OpenDevice(int device)
70  {
71  if (openDevices_ > 0 && device==0) {
72  BIASWARN("Kinect: I guess you try to open the next device (device=0 given)");
73  device = openDevices_;
74  BIASWARN("Kinect: Trying to open device " << device << " instead");
75  }
76  if (kinectManager_ == NULL) {
77  try {
78  kinectManager_ = new Freenect::Freenect();
79  deviceCount_ = kinectManager_->deviceCount();
80  } catch (std::runtime_error e) {
81  BIASERR("Kinect Error: " << e.what());
82  return -1;
83  }
84  }
85  try {
86  kinectDevice_ = &kinectManager_->createDevice<VideoSource_Kinect_Callback>(device);
87  } catch (std::runtime_error e) {
88  BIASERR("Kinect Error: " << e.what());
89  return -2;
90  }
91  if (kinectDevice_ == NULL) {
92  BIASERR("Kinect Error: Device can not be opened");
93  return -3;
94  }
95  CreateDepthLookupTable();
96  deviceId_ = device;
97  openDevices_++;
98  return 0;
99  }
100 
101  int VideoSource_Kinect::CloseDevice() {
102  kinectManager_->deleteDevice(deviceId_);
103  openDevices_--;
104  kinectDevice_ = NULL;
105  Active_ = false;
106  return 0;
107  }
108 
109  int VideoSource_Kinect::PreGrab() {
110  cout << "pregrab device " << deviceId_ << endl;
111  BIASASSERT(kinectDevice_ != NULL)
112  try {
113  kinectDevice_->setDepthFormat(FREENECT_DEPTH_11BIT);
114  kinectDevice_->setVideoFormat(FREENECT_VIDEO_BAYER);
115  } catch (std::runtime_error e) {
116  BIASERR("Kinect Error: " << e.what());
117  return 1;
118  }
119  try {
120  kinectDevice_->startDepth();
121  } catch (std::runtime_error e) {
122  BIASERR("Kinect Error: " << e.what());
123  return 1;
124  }
125  try {
126  kinectDevice_->startVideo(); // todo this causes error as setVideoFormat already starts video, ignore for now
127  } catch (std::runtime_error e) {
128  BIASERR("Kinect Error: " << e.what());
129  Active_ = true;
130  return 0;
131  }
132  Active_ = true;
133  return 0;
134  }
135  int VideoSource_Kinect::PostGrab() {
136  BIASASSERT(kinectDevice_ != NULL)
137  try {
138  kinectDevice_->stopVideo();
139  kinectDevice_->stopDepth();
140  } catch (std::runtime_error e) {
141  BIASERR("Kinect Error: " << e.what());
142  return 1;
143  }
144  return 0;
145  }
146 
147  int VideoSource_Kinect::
148  InitImage(BIAS::ImageBase &Image)
149  {
150  if (!Image.IsEmpty()) {
151  BIASWARN("Kinect Error: image already inited");
152  return 1;
153  }
154  Image.Init(640,480,1);
155  Image.SetColorModel(ImageBase::CM_Bayer_GRBG);
156  return 0;
157  }
158 
159  int VideoSource_Kinect::
160  InitDepthImage(BIAS::ImageBase &Image)
161  {
162  if (!Image.IsEmpty()) {
163  BIASWARN("Kinect Error: image already inited");
164  return 1;
165  }
166  Image.Init(640,480,1,ImageBase::ST_float);
167  Image.SetColorModel(ImageBase::CM_Depth);
168 
169  return 0;
170  }
171 
172  int VideoSource_Kinect::GrabSingle(BIAS::Camera <unsigned char> &image) {
173  BIASASSERT(kinectDevice_ != NULL)
174  return kinectDevice_->GetLatestColor(image);
175  }
176 
177  int VideoSource_Kinect::CreateDepthLookupTable(double px, double py, double fx, double fy) {
178  BIASASSERT(kinectDevice_ != NULL)
179  kinectDevice_->CreateLookupTable(px,py,fx,fy);
180  return 0;
181  }
182 
183  int VideoSource_Kinect::GrabSingleDepth(BIAS::Camera <float> &image) {
184  BIASASSERT(kinectDevice_ != NULL)
185  return kinectDevice_->GetLatestDepth(image);
186  }
187 
188  int VideoSource_Kinect::SetVideoModeColor() {
189  BIASASSERT(kinectDevice_ != NULL)
190  kinectDevice_->SetSwitchVideoModeAfterGrab(false);
191  return kinectDevice_->SetVideoMode(FREENECT_VIDEO_BAYER);
192  }
193 
194  int VideoSource_Kinect::SetVideoModeIR() {
195  BIASASSERT(kinectDevice_ != NULL)
196  kinectDevice_->SetSwitchVideoModeAfterGrab(false);
197  return kinectDevice_->SetVideoMode(FREENECT_VIDEO_IR_8BIT);
198  }
199 
200  int VideoSource_Kinect::SetDepthCaptureMode(CaptureMode mode) {
201  BIASASSERT(kinectDevice_ != NULL)
202  kinectDevice_->SetDepthMode(mode);
203  return 0;
204  }
205 
206  int VideoSource_Kinect::SetSwitchVideoModeAfterGrab() {
207  return kinectDevice_->SetSwitchVideoModeAfterGrab(true);
208  }
209 
210  int VideoSource_Kinect::SetTilt(double degrees) {
211  BIASASSERT(kinectDevice_ != NULL)
212  try {
213  if (degrees<-30.0) {
214  BIASWARN("Kinect: clipping angle to -30");
215  degrees = -30;
216  }
217  if (degrees>30.0) {
218  BIASWARN("Kinect: clipping angle to 30");
219  degrees = 30;
220  }
221  kinectDevice_->setTiltDegrees(degrees);
222  } catch (std::runtime_error e) {
223  BIASERR("Kinect Error: " << e.what());
224  return 1;
225  }
226  return 0;
227  }
228 
229  int VideoSource_Kinect::SetLed(int mode) {
230  BIASASSERT(kinectDevice_ != NULL)
231  try {
232  kinectDevice_->setLed((freenect_led_options)mode);
233  } catch (std::runtime_error e) {
234  BIASERR("Kinect Error: " << e.what());
235  return 1;
236  }
237  return 0;
238  }
239 
240  int VideoSource_Kinect::GetAccelerometer(double &tilt, double &x, double &y, double &z) {
241  BIASASSERT(kinectDevice_ != NULL)
242  try {
243  kinectDevice_->updateState();
244  Freenect::FreenectTiltState state = kinectDevice_->getState();
245  tilt = state.getTiltDegs();
246  state.getAccelerometers(&x, &y, &z);
247  } catch (std::runtime_error e) {
248  BIASERR("Kinect Error: " << e.what());
249  return 1;
250  }
251  return 0;
252  }
253 
254  int VideoSource_Kinect::GetCapabilities(VideoSourceCapabilities &caps)
255  {
256  return 0;
257  }
258 
259  int VideoSource_Kinect::GetCapabilities(const char *device, VideoSourceCapabilities &caps)
260  {
261  return 0;
262  }
263 
264  int VideoSource_Kinect::ToggleDepthStream() {
265  BIASERR("ToggleDepthStream not implemented for libfreenect");
266  return 0;
267  }
268 
269  ////////////////////////////////////////////////////////////////////////////////
270  //////////////////VideoSource_Kinect_Callback //////////////////////////////////
271  ////////////////////////////////////////////////////////////////////////////////
272 
273  VideoSource_Kinect_Callback::
274  VideoSource_Kinect_Callback(freenect_context *_ctx, int _index)
275  : Freenect::FreenectDevice(_ctx, _index)
276  {
277  colorbuffer_.resize(2);
278  colorbuffer_[0].Init(640,480,1);
279  colorbuffer_[1].Init(640,480,1);
280  depthbuffer_.resize(2);
281  depthbuffer_[0].Init(640,480,1);
282  depthbuffer_[1].Init(640,480,1);
283  colorbuffer_[0].SetColorModel(ImageBase::CM_Bayer_GRBG);
284  colorbuffer_[1].SetColorModel(ImageBase::CM_Bayer_GRBG);
285  writingToC_ = 0;
286  writingToD_ = 0;
287  color_mutex = new pthread_mutex_t;
288  depth_mutex = new pthread_mutex_t;
289  coloravail_mutex = new pthread_mutex_t;
290  depthavail_mutex = new pthread_mutex_t;
291  newColorAvail_ = new pthread_cond_t;
292  newDepthAvail_ = new pthread_cond_t;
293  pthread_mutex_init(color_mutex, NULL);
294  pthread_mutex_init(depth_mutex, NULL);
295  pthread_mutex_init(coloravail_mutex, NULL);
296  pthread_mutex_init(depthavail_mutex, NULL);
297  pthread_cond_init(newColorAvail_, NULL);
298  pthread_cond_init(newDepthAvail_, NULL);
299  for (int i=0; i<2048; i++) {
300  const float k1 = 1.1863f;
301  const float k2 = 2842.5f;
302  const float k3 = 0.1236f;
303  const float depth = k3 * tanf(i/k2 + k1);
304  lookup_[i] = depth * 1000.0f;
305  }
306  lookup_[2047] = 0.0f;
307  switch_ = false;
309  }
310 
312  VideoCallback(void *video, uint32_t timestamp)
313  {
314  //cout << "color writing to buffer " << writingToC_ << endl;
315  colorbuffer_[writingToC_].CopyIn_NoInit(video);
316  //colorbuffer_[writingToC_].SetTime(timestamp, 0); // todo
317  //cout << timestamp << endl;
318  pthread_mutex_lock(color_mutex);
319  writingToC_ = (writingToC_ + 1)%2;
320  pthread_mutex_unlock(color_mutex);
321  pthread_cond_signal(newColorAvail_);
322  }
323 
325  DepthCallback(void *depth, uint32_t timestamp)
326  {
327  //cout << "depth writing to buffer " << writingToD_ << endl;
328  //depth is 16-bit/ pixel, contains 11-bit data
329 #ifdef WIN32
330  //unsigned short *pDepth = (unsigned short*)depth;
331  uint16_t *pDepth = (uint16_t*)depth;
332 #else
333  u_int16_t *pDepth = (u_int16_t*)depth;
334 #endif
335  float *buf = depthbuffer_[writingToD_].GetImageData();
336  float *lut = depthLookupTable_.GetImageData();
337  switch (capMode_) {
339  for (unsigned int x=0;x<640*480;x++) {
340  buf[x] = lookup_[ pDepth[x] ] * lut[x];
341  }
342  break;
343  }
345  for (unsigned int x=0;x<640*480;x++) {
346  buf[x] = lookup_[ pDepth[x] ];
347  }
348  break;
349  }
351  for (unsigned int x=0;x<640*480;x++) {
352  buf[x] = pDepth[x];
353  }
354  break;
355  }
356  default: {
357  BIASERR("unknown mode")
358  break;
359  }
360  }
361  //depthbuffer_[writingToD_].SetTime(timestamp, 0); // todo
362  pthread_mutex_lock(depth_mutex);
363  writingToD_ = (writingToD_ + 1)%2;
364  pthread_mutex_unlock(depth_mutex);
365  pthread_cond_signal(newDepthAvail_);
366  }
367 
370  {
371  pthread_cond_wait(newColorAvail_, coloravail_mutex);
372  pthread_mutex_lock(color_mutex);
373  int idx = (writingToC_ + 1)%2;
374  if (switch_) {
375  if (format_ == FREENECT_VIDEO_BAYER) {
376  SetVideoMode(FREENECT_VIDEO_IR_8BIT);
377  } else {
378  SetVideoMode(FREENECT_VIDEO_BAYER);
379  }
380  }
381  pthread_mutex_unlock(color_mutex);
382  // cout << "grabbing " << idx << endl;
383  image.CopyIn_NoInit(colorbuffer_[idx].GetImageData());
384  return 0;
385  }
386 
389  {
390  pthread_cond_wait(newDepthAvail_, depthavail_mutex);
391  pthread_mutex_lock(depth_mutex);
392  int idx = (writingToD_ + 1)%2;
393  pthread_mutex_unlock(depth_mutex);
394 
395  // Copy and compensate for the +3 pixel offset in the depth image
396  float* idaDst = image.GetImageData();
397  memset(idaDst,0,3*sizeof(float));
398  memcpy(idaDst+3, depthbuffer_[idx].GetImageData(), (480*640-3)*sizeof(float));
399 
400 
401  //image.CopyIn_NoInit(depthbuffer_[idx].GetImageData());
402  return 0;
403  }
404 
406  SetVideoMode(freenect_video_format format)
407  {
408  try {
409  setVideoFormat(format);
410  format_ = format;
411  } catch (std::runtime_error e) {
412  BIASERR("Kinect Error: " << e.what());
413  return 1;
414  }
415  // todo already started by setformat??
416  // try {
417  // startVideo();
418  // } catch (std::runtime_error e) {
419  // BIASERR("Kinect Error: " << e.what());
420  // return 1;
421  // }
422  return 0;
423  }
424 
427  {
428  switch_ = switchMode;
429  return 0;
430  }
431 
433  SetDepthMode(int mode)
434  {
435  capMode_ = mode;
436  }
437 
438 
440  CreateLookupTable(double px, double py, double fx, double fy)
441  {
442  if (depthLookupTable_.IsEmpty()) {
443  depthLookupTable_.Init(640,480,1);
444  }
445  float **ida = depthLookupTable_.GetImageDataArray();
446 
447  for(unsigned y=0;y<480;y++){
448  for(unsigned x=0;x<640;x++){
449  float alpha = atan(float((x-px)/fx));
450  float beta = atan(float((py-y)/ sqrt( pow((x-px)*(fy/fx),2) + pow(fy,2))));
451  ida[y][x] = 1.0f / (cos(beta) * cos(alpha));
452  }
453  }
454  }
455 
456 }//end namespace BIAS
Bayer_GRBG, 1 channel RGB image Bayer tile.
Definition: ImageBase.hh:145
virtual int SetVideoMode(freenect_video_format format)
std::vector< Camera< float > > depthbuffer_
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
Implementing FreenectDevice Interface, this class is used internally by VideoSource_Kinect - do not u...
virtual void VideoCallback(void *video, uint32_t timestamp)
libfreenect thread calls this when new color data is available
void SetColorModel(EColorModel Model)
Definition: ImageBase.hh:561
virtual void DepthCallback(void *depth, uint32_t timestamp)
libfreenect thread calls this when new depth data is available
std::vector< Camera< unsigned char > > colorbuffer_
virtual int GetLatestDepth(Camera< float > &image)
Callbacks store image data in double buffer, get latest Note that the depth image is shifted by 3 pix...
virtual int GetLatestColor(Camera< unsigned char > &image)
Callbacks store image data in double buffer, get latest.
The image template class for specific storage types.
Definition: Image.hh:78
void CreateLookupTable(double px, double py, double fx, double fy)
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
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
Checks for VideoSource capabilities.
virtual int SetSwitchVideoModeAfterGrab(bool switchMode)
This is the base class for images in BIAS.
Definition: ImageBase.hh:102
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153