Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
VideoSource_OpenNI.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_OpenNI.hh"
26 #include <iostream>
27 #include <Base/Image/ImageIO.hh>
28 
29 using namespace std;
30 
31 namespace BIAS {
32 
33  int VideoSource_OpenNI::numInstances_ = 0;
34  int VideoSource_OpenNI::numDevices_ = 0;
35  xn::Context VideoSource_OpenNI::context_;
36  std::vector<VideoSource_OpenNI::ONIDeviceNode> VideoSource_OpenNI::devices_;
37 
38  xn::NodeInfoList VideoSource_OpenNI::device_nodes_;
39  xn::NodeInfoList VideoSource_OpenNI::depth_nodes_;
40  xn::NodeInfoList VideoSource_OpenNI::image_nodes_;
41  xn::NodeInfoList VideoSource_OpenNI::ir_nodes_;
42 
43  pthread_mutex_t *VideoSource_OpenNI::exclusive_mutex = NULL;
44 
45  VideoSource_OpenNI::VideoSource_OpenNI() {
46  Active_ = false;
47  Width_ = 640;
48  Height_ = 480;
49  depthLookupTable_ = NULL;
50 
51  CreateLookupTable_();
52 
53  if (numDevices_ == 0) {
54  ScanBus();
55  }
56  if (numInstances_ == 0) {
57  exclusive_mutex = new pthread_mutex_t;
58  pthread_mutex_init(exclusive_mutex, NULL);
59  }
60  numInstances_ ++;
61  capMode_ = DepthRay;
62  colorMode_ = false;
63  contextInited_ = false;
64  switchModeEveryFrame_ = false;
65  }
66 
67  bool VideoSource_OpenNI::CheckError_(XnStatus rc, std::string what) {
68  if (rc != XN_STATUS_OK)
69  {
70  BIASERR("OpenNI Fail: " << what << " : " << xnGetStatusString(rc));
71  return true;
72  }
73  return false;
74  }
75 
76 
77  VideoSource_OpenNI::~VideoSource_OpenNI() {
78  numInstances_ --;
79  if (numInstances_ == 0) {
80  DeleteLookupTable_();
81  }
82  if (numInstances_ == 0) {
83  context_.Shutdown();
84  numDevices_ = 0;
85  devices_.clear();
86  }
87  }
88 
89  int VideoSource_OpenNI::OpenDevice() {
90  return OpenDevice(0);
91  }
92 
93  int VideoSource_OpenNI::OpenDevice(int device) {
94  deviceId_ = device;
95  int ret = SetVideoModeColor();
96  if (ret == 0) {
97  return StartDepthStream();
98  } else {
99  return 1;
100  }
101  }
102 
103  int VideoSource_OpenNI::CloseDevice() {
104  Active_ = false;
105  return 0;
106  }
107 
108  int VideoSource_OpenNI::PreGrab() {
109  cout << "OpenNI: pregrab device" << endl;
110  Active_ = true;
111  return 0;
112  }
113  int VideoSource_OpenNI::PostGrab() {
114  cout << "OpenNI: postgrab device " << endl;
115  XnStatus rc;
116  if (colorMode_ == false) {
117  rc = irGenerator_.StopGenerating();
118  if (CheckError_(rc, "stop generating IR")) return 1;
119  } else {
120  rc = colorGenerator_.StopGenerating();
121  if (CheckError_(rc, "stop generating color")) return 1;
122  }
123  if (depthGenerator_.IsValid()) {
124  rc = depthGenerator_.StopGenerating();
125  if (CheckError_(rc, "stop generating depth")) return 1;
126  }
127  Active_ = false;
128  return 0;
129  }
130 
131  int VideoSource_OpenNI::InitImage(BIAS::ImageBase &Image) {
132  if (!Image.IsEmpty()) {
133  BIASWARN("OpenNI Error: image already inited");
134  return 1;
135  }
136  Image.Init(640,480,1);
137  Image.SetColorModel(ImageBase::CM_Bayer_GRBG);
138  return 0;
139  }
140 
141  int VideoSource_OpenNI::InitDepthImage(BIAS::ImageBase &Image) {
142  if (!Image.IsEmpty()) {
143  BIASWARN("OpenNI Error: image already inited");
144  return 1;
145  }
146  Image.Init(640,480,1,ImageBase::ST_float);
147  Image.SetColorModel(ImageBase::CM_Depth);
148 
149  return 0;
150  }
151 
152  int VideoSource_OpenNI::GrabSingle(BIAS::Camera <unsigned char> &image) {
153  if (deviceId_ == 0) {
154  pthread_mutex_lock(exclusive_mutex);
155  context_.WaitAndUpdateAll();
156  pthread_mutex_unlock(exclusive_mutex);
157  }
158 // context_.WaitOneUpdateAll(depthGenerator_);
159 // if (colorMode_) {
160 // context_.WaitOneUpdateAll(colorGenerator_);
161 // } else {
162 // context_.WaitOneUpdateAll(irGenerator_);
163 // }
164  if (depthGenerator_.IsValid())
165  depthGenerator_.GetMetaData(depthMD_);
166  if (colorMode_) {
167  colorGenerator_.GetMetaData(colorMD_);
168  image.CopyIn_NoInit( (void*)colorMD_.Data() );
169  } else {
170  irGenerator_.GetMetaData(irMD_);
171  unsigned char *ida = image.GetImageData();
172  const XnIRPixel *pix = irMD_.Data();
173  for (int x=0;x<Width_*Height_;x++) {
174  ida[x] = (unsigned char) (pix[x] / 2);
175  }
176  }
177  if (switchModeEveryFrame_) {
178  if (colorMode_ == true) {
179  SetVideoModeColor();
180  } else {
181  SetVideoModeIR();
182  }
183  }
184  return 0;
185  }
186  int VideoSource_OpenNI::GrabSingleDepth(BIAS::Camera <float> &image) {
187  if (!depthGenerator_.IsValid()) {
188  return 0;
189  }
190  const XnDepthPixel *data = depthMD_.Data();
191  float *ida = image.GetImageData();
192 
193  switch (capMode_) {
194  case DepthRay: {
195  const float *lut = depthLookupTable_->GetImageData();
196  memset(ida,0,3*sizeof(float));
197  int size = Width_*Height_-3;
198  for (int x=0;x<size;x++) {
199  ida[x+3] = data[x] * lut[x];
200  }
201  break;
202  }
203  case DepthEuclidean: {
204  memset(ida,0,3*sizeof(float));
205  int size = Width_*Height_-3;
206  for (int x=0;x<size;x++) {
207  ida[x+3] = data[x];
208  }
209 
210  break;
211  }
212  default:
213  BIASERR("OpenNI capture mode not supported");
214  break;
215  }
216  return 0;
217  }
218 
219  int VideoSource_OpenNI::CreateDepthLookupTable(double px, double py, double fx, double fy) {
220  pthread_mutex_lock(exclusive_mutex);
221  CreateLookupTable_(px,py,fx,fy);
222  pthread_mutex_unlock(exclusive_mutex);
223  return 0;
224  }
225 
226  int VideoSource_OpenNI::StartDepthStream() {
227  pthread_mutex_lock(exclusive_mutex);
228  if (depthGenerator_.IsValid()) {
229  pthread_mutex_unlock(exclusive_mutex);
230  return 1;
231  }
232  XnStatus rc;
233  // create the production nodes
234  rc = context_.CreateProductionTree (devices_[deviceId_].depthInfo);
235  CheckError_(rc, "create depth generator");
236 
237  rc = devices_[deviceId_].depthInfo.GetInstance(depthGenerator_);
238  CheckError_(rc, "create depth generator instance");
239 
240  XnMapOutputMode depth_mode;
241 
242  depth_mode.nXRes = XN_VGA_X_RES;
243  depth_mode.nYRes = XN_VGA_Y_RES;
244  depth_mode.nFPS = 30;
245 
246  rc = depthGenerator_.SetMapOutputMode(depth_mode);
247  if (CheckError_(rc, "set depth mode")) return 1;
248 
249  rc = depthGenerator_.StartGenerating();
250  if (CheckError_(rc, "starting depth cam")) return 1;
251 
252  pthread_mutex_unlock(exclusive_mutex);
253  return 0;
254  }
255 
256  int VideoSource_OpenNI::StopDepthStream() {
257  pthread_mutex_lock(exclusive_mutex);
258  if (depthGenerator_.IsValid() && depthGenerator_.IsGenerating()) {
259  depthGenerator_.StopGenerating();
260  depthGenerator_.Release();
261  }
262  pthread_mutex_unlock(exclusive_mutex);
263  return 0;
264  }
265 
266  int VideoSource_OpenNI::ToggleDepthStream() {
267  if (depthGenerator_.IsValid()) {
268  return StopDepthStream();
269  } else {
270  return StartDepthStream();
271  }
272  }
273 
274  int VideoSource_OpenNI::SetVideoModeColor() {
275  pthread_mutex_lock(exclusive_mutex);
276  if (colorMode_ == false) {
277  if (irGenerator_.IsValid() && irGenerator_.IsGenerating()) {
278  irGenerator_.StopGenerating();
279  irGenerator_.Release();
280  }
281  } else {
282  pthread_mutex_unlock(exclusive_mutex);
283  return 0;
284  }
285  XnStatus rc;
286  rc = context_.CreateProductionTree (devices_[deviceId_].imageInfo);
287  CheckError_(rc, "create image generator");
288 
289  rc = devices_[deviceId_].imageInfo.GetInstance(colorGenerator_);
290  CheckError_(rc, "create image generator instance");
291 
292  XnMapOutputMode frame_mode;
293 
294  // Set it to VGA maps at 30 FPS
295  frame_mode.nXRes = XN_VGA_X_RES;
296  frame_mode.nYRes = XN_VGA_Y_RES;
297  frame_mode.nFPS = 30;
298 
299  rc = colorGenerator_.SetMapOutputMode(frame_mode);
300  if (CheckError_(rc, "set color mode")) return 1;
301 
302  rc = colorGenerator_.SetIntProperty("InputFormat", 6);
303  if (CheckError_(rc, "set bayer uncompressed")) return 1;
304  rc = colorGenerator_.SetPixelFormat(XN_PIXEL_FORMAT_GRAYSCALE_8_BIT);
305  if (CheckError_(rc, "disable internal debayer")) return 1;
306 
307  colorMode_ = true;
308  rc = colorGenerator_.StartGenerating();
309  if (CheckError_(rc, "starting color cam")) return 1;
310  pthread_mutex_unlock(exclusive_mutex);
311  return 0;
312  }
313 
314  int VideoSource_OpenNI::SetVideoModeIR() {
315  pthread_mutex_lock(exclusive_mutex);
316  if (colorMode_ == true) {
317  if (colorGenerator_.IsValid() && colorGenerator_.IsGenerating()) {
318  colorGenerator_.StopGenerating();
319  colorGenerator_.Release();
320  }
321  } else {
322  pthread_mutex_unlock(exclusive_mutex);
323  return 0;
324  }
325 
326  XnStatus rc;
327  rc = context_.CreateProductionTree (devices_[deviceId_].irInfo);
328  CheckError_(rc, "create ir generator");
329 
330  rc = devices_[deviceId_].irInfo.GetInstance(irGenerator_);
331  CheckError_(rc, "create IR generator instance");
332 
333  XnMapOutputMode frame_mode;
334 
335  // Set it to VGA maps at 30 FPS
336  frame_mode.nXRes = XN_VGA_X_RES;
337  frame_mode.nYRes = XN_VGA_Y_RES;
338  frame_mode.nFPS = 30;
339 
340  rc = irGenerator_.SetMapOutputMode(frame_mode);
341  if (CheckError_(rc, "set ir mode")) return 1;
342 
343  colorMode_ = false;
344 
345  rc = irGenerator_.StartGenerating();
346  if (CheckError_(rc, "starting ir cam")) return 1;
347  pthread_mutex_unlock(exclusive_mutex);
348  return 0;
349  }
350 
351  int VideoSource_OpenNI::SetDepthCaptureMode(CaptureMode mode) {
352  capMode_ = mode;
353  return 0;
354  }
355 
356  int VideoSource_OpenNI::SetSwitchVideoModeAfterGrab() {
357  switchModeEveryFrame_ = !switchModeEveryFrame_;
358  return 1;
359  }
360 
361  int VideoSource_OpenNI::SetTilt(double degrees) {
362  BIASERR("not yet implemented");
363  return 1;
364  }
365 
366  int VideoSource_OpenNI::SetLed(int mode) {
367  BIASERR("not yet implemented");
368  return 1;
369  }
370 
371  int VideoSource_OpenNI::GetAccelerometer(double &tilt, double &x, double &y, double &z) {
372  BIASERR("not yet implemented");
373  return 1;
374  }
375 
376 
377  int VideoSource_OpenNI::GetCapabilities(VideoSourceCapabilities &caps)
378  {
379  return 0;
380  }
381 
382  int VideoSource_OpenNI::GetCapabilities(const char *device, VideoSourceCapabilities &caps)
383  {
384  return 0;
385  }
386 
387  void VideoSource_OpenNI::CreateLookupTable_(double px, double py, double fx, double fy) {
388  if (depthLookupTable_ == NULL) {
389  depthLookupTable_ = new Image<float>(640,480,1);
390  }
391 
392  float **ida = depthLookupTable_->GetImageDataArray();
393 
394  for(unsigned y=0;y<480;y++){
395  for(unsigned x=0;x<640;x++){
396  float alpha = atan(float((x-px)/fx));
397  float beta = atan(float((py-y)/ sqrt( pow((x-px)*(fy/fx),2) + pow(fy,2))));
398  ida[y][x] = 1.0f / (cos(beta) * cos(alpha));
399  }
400  }
401  }
402 
403  void VideoSource_OpenNI::DeleteLookupTable_() {
404  if (depthLookupTable_ != NULL) {
405  delete depthLookupTable_;
406  depthLookupTable_ = NULL;
407  }
408  }
409 
410  void VideoSource_OpenNI::ScanBus() {
411  XnStatus rc;
412  rc = context_.Init();
413  CheckError_(rc, "init context");
414 
415  // enumerate all devices
416  rc = context_.EnumerateProductionTrees (XN_NODE_TYPE_DEVICE, NULL, device_nodes_);
417  CheckError_(rc, "enumerate devices");
418 
419  vector<xn::NodeInfo> device_info;
420  for (xn::NodeInfoList::Iterator nodeIt = device_nodes_.Begin (); nodeIt != device_nodes_.End (); ++nodeIt)
421  {
422  device_info.push_back (*nodeIt);
423  }
424 
425  // enumerate depth nodes
426  rc = context_.EnumerateProductionTrees (XN_NODE_TYPE_DEPTH, NULL, depth_nodes_, NULL);
427  CheckError_(rc, "enumerate depth generators");
428 
429  vector<xn::NodeInfo> depth_info;
430  for (xn::NodeInfoList::Iterator nodeIt = depth_nodes_.Begin (); nodeIt != depth_nodes_.End (); ++nodeIt)
431  {
432  depth_info.push_back (*nodeIt);
433  }
434 
435  // enumerate image nodes
436  rc = context_.EnumerateProductionTrees (XN_NODE_TYPE_IMAGE, NULL, image_nodes_, NULL);
437  CheckError_(rc, "enumerate image generators");
438 
439  vector<xn::NodeInfo> image_info;
440  for (xn::NodeInfoList::Iterator nodeIt = image_nodes_.Begin (); nodeIt != image_nodes_.End (); ++nodeIt)
441  {
442  image_info.push_back (*nodeIt);
443  }
444 
445  // enumerate ir nodes
446  rc = context_.EnumerateProductionTrees (XN_NODE_TYPE_IR, NULL, ir_nodes_, NULL);
447  CheckError_(rc, "enumerate ir generators");
448 
449  vector<xn::NodeInfo> ir_info;
450  for (xn::NodeInfoList::Iterator nodeIt = ir_nodes_.Begin (); nodeIt != ir_nodes_.End (); ++nodeIt)
451  {
452  ir_info.push_back (*nodeIt);
453  }
454 
455  for (unsigned int i=0;i<device_info.size();i++) {
456  devices_.push_back( ONIDeviceNode( depth_info[i], image_info[i], ir_info[i], depth_info[i]));
457  }
458 
459  numDevices_ = devices_.size();
460  cout << "OpenNI: There are " << numDevices_ << " devices connected. " << endl;
461 
462  }
463 
464 }
int BIASVideoSource_EXPORT ScanBus(std::stringstream &ofs)
support function to get the number of cameras and IDs of all cameras on one bus
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
BIAS::Image< float > * depthLookupTable_
void SetColorModel(EColorModel Model)
Definition: ImageBase.hh:561
The image template class for specific storage types.
Definition: Image.hh:78
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.
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