1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
8 //
9 //
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
21 //
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
25 //
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 #include "precomp.hpp"
42 #include "opencv2/core.hpp"
43 #include "opencv2/imgproc.hpp"
44
45 #ifdef HAVE_OPENNI
46
47 #if defined TBB_INTERFACE_VERSION && TBB_INTERFACE_VERSION < 5000
48 # undef HAVE_TBB
49 #endif
50
51 #include <queue>
52
53 #ifndef i386
54 # define i386 0
55 #endif
56 #ifndef __arm__
57 # define __arm__ 0
58 #endif
59 #ifndef _ARC
60 # define _ARC 0
61 #endif
62 #ifndef __APPLE__
63 # define __APPLE__ 0
64 #endif
65
66 #include "XnCppWrapper.h"
67
68 const cv::String XMLConfig =
69 "<OpenNI>"
70 "<Licenses>"
71 "<License vendor=\"PrimeSense\" key=\"0KOIk2JeIBYClPWVnMoRKn5cdY4=\"/>"
72 "</Licenses>"
73 "<Log writeToConsole=\"false\" writeToFile=\"false\">"
74 "<LogLevel value=\"3\"/>"
75 "<Masks>"
76 "<Mask name=\"ALL\" on=\"true\"/>"
77 "</Masks>"
78 "<Dumps>"
79 "</Dumps>"
80 "</Log>"
81 "<ProductionNodes>"
82 "<Node type=\"Image\" name=\"Image1\" stopOnError=\"false\">"
83 "<Configuration>"
84 "<MapOutputMode xRes=\"640\" yRes=\"480\" FPS=\"30\"/>"
85 "<Mirror on=\"false\"/>"
86 "</Configuration>"
87 "</Node> "
88 "<Node type=\"Depth\" name=\"Depth1\">"
89 "<Configuration>"
90 "<MapOutputMode xRes=\"640\" yRes=\"480\" FPS=\"30\"/>"
91 "<Mirror on=\"false\"/>"
92 "</Configuration>"
93 "</Node>"
94 "</ProductionNodes>"
95 "</OpenNI>\n";
96
97 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
98 class ApproximateSyncGrabber
99 {
100 public:
ApproximateSyncGrabber(xn::Context & _context,xn::DepthGenerator & _depthGenerator,xn::ImageGenerator & _imageGenerator,int _maxBufferSize,bool _isCircleBuffer,int _maxTimeDuration)101 ApproximateSyncGrabber( xn::Context &_context,
102 xn::DepthGenerator &_depthGenerator,
103 xn::ImageGenerator &_imageGenerator,
104 int _maxBufferSize, bool _isCircleBuffer, int _maxTimeDuration ) :
105 context(_context), depthGenerator(_depthGenerator), imageGenerator(_imageGenerator),
106 maxBufferSize(_maxBufferSize), isCircleBuffer(_isCircleBuffer), maxTimeDuration(_maxTimeDuration)
107 {
108 #ifdef HAVE_TBB
109 task = 0;
110 #endif
111
112 CV_Assert( depthGenerator.IsValid() );
113 CV_Assert( imageGenerator.IsValid() );
114 }
115
setMaxBufferSize(int _maxBufferSize)116 void setMaxBufferSize( int _maxBufferSize )
117 {
118 maxBufferSize = _maxBufferSize;
119 #ifdef HAVE_TBB
120 task->setMaxBufferSize();
121 #endif
122 }
getMaxBufferSize() const123 inline int getMaxBufferSize() const { return maxBufferSize; }
124
setIsCircleBuffer(bool _isCircleBuffer)125 void setIsCircleBuffer( bool _isCircleBuffer ) { isCircleBuffer = _isCircleBuffer; }
getIsCircleBuffer() const126 bool getIsCircleBuffer() const { return isCircleBuffer; }
127
setMaxTimeDuration(int _maxTimeDuration)128 void setMaxTimeDuration( int _maxTimeDuration ) { maxTimeDuration = _maxTimeDuration; }
getMaxTimeDuration() const129 int getMaxTimeDuration() const { return maxTimeDuration; }
130
grab(xn::DepthMetaData & depthMetaData,xn::ImageMetaData & imageMetaData)131 bool grab( xn::DepthMetaData& depthMetaData,
132 xn::ImageMetaData& imageMetaData )
133 {
134 CV_Assert( task );
135
136
137 while( task->grab(depthMetaData, imageMetaData) == false )
138 {
139 #ifndef HAVE_TBB
140 task->spin();
141 #endif
142 }
143 return true;
144
145 }
146
start()147 void start()
148 {
149 CV_Assert( depthGenerator.IsValid() );
150 CV_Assert( imageGenerator.IsValid() );
151 #ifdef HAVE_TBB
152 task = new( tbb::task::allocate_root() ) TBBApproximateSynchronizerTask( *this );
153 tbb::task::enqueue(*task);
154 #else
155 task.reset( new ApproximateSynchronizer( *this ) );
156 #endif
157 }
158
finish()159 void finish()
160 {
161 #ifdef HAVE_TBB
162 if( task )
163 tbb::task::destroy( *task );
164 #else
165 task.release();
166 #endif
167 }
168
isRun() const169 bool isRun() const { return task != 0; }
170
171 xn::Context &context;
172 xn::DepthGenerator &depthGenerator;
173 xn::ImageGenerator &imageGenerator;
174
175 private:
176 ApproximateSyncGrabber(const ApproximateSyncGrabber&);
177 ApproximateSyncGrabber& operator=(const ApproximateSyncGrabber&);
178
179 int maxBufferSize;
180 bool isCircleBuffer;
181 int maxTimeDuration;
182
183 class ApproximateSynchronizerBase
184 {
185 public:
ApproximateSynchronizerBase(ApproximateSyncGrabber & _approxSyncGrabber)186 ApproximateSynchronizerBase( ApproximateSyncGrabber& _approxSyncGrabber ) :
187 approxSyncGrabber(_approxSyncGrabber), isDepthFilled(false), isImageFilled(false)
188 {}
189
~ApproximateSynchronizerBase()190 virtual ~ApproximateSynchronizerBase() {}
191
192 virtual bool isSpinContinue() const = 0;
193 virtual void pushDepthMetaData( xn::DepthMetaData& depthMetaData ) = 0;
194 virtual void pushImageMetaData( xn::ImageMetaData& imageMetaData ) = 0;
195 virtual bool popDepthMetaData( xn::DepthMetaData& depthMetaData ) = 0;
196 virtual bool popImageMetaData( xn::ImageMetaData& imageMetaData ) = 0;
197
spin()198 void spin()
199 {
200 while(isSpinContinue() == true)
201 {
202 XnStatus status = approxSyncGrabber.context.WaitAnyUpdateAll();
203 if( status != XN_STATUS_OK )
204 continue;
205
206 //xn::DepthMetaData depth;
207 //xn::ImageMetaData image;
208 approxSyncGrabber.depthGenerator.GetMetaData(depth);
209 approxSyncGrabber.imageGenerator.GetMetaData(image);
210
211 if( depth.Data() && depth.IsDataNew() )
212 pushDepthMetaData( depth );
213
214 if( image.Data() && image.IsDataNew() )
215 pushImageMetaData( image );
216 }
217 }
218
grab(xn::DepthMetaData & depthMetaData,xn::ImageMetaData & imageMetaData)219 virtual bool grab( xn::DepthMetaData& depthMetaData,
220 xn::ImageMetaData& imageMetaData )
221 {
222 for(;;)
223 {
224 if( !isDepthFilled )
225 isDepthFilled = popDepthMetaData(depth);
226 if( !isImageFilled )
227 isImageFilled = popImageMetaData(image);
228
229 if( !isDepthFilled || !isImageFilled )
230 break;
231
232 double timeDiff = 1e-3 * std::abs(static_cast<double>(depth.Timestamp()) - static_cast<double>(image.Timestamp()));
233
234 if( timeDiff <= approxSyncGrabber.maxTimeDuration )
235 {
236 depthMetaData.InitFrom(depth);
237 imageMetaData.InitFrom(image);
238 isDepthFilled = isImageFilled = false;
239 return true;
240 }
241 else
242 {
243 if( depth.Timestamp() < image.Timestamp() )
244 isDepthFilled = false;
245 else
246 isImageFilled = false;
247 }
248 }
249
250 return false;
251 }
252
253 protected:
254 ApproximateSyncGrabber& approxSyncGrabber;
255 xn::DepthMetaData depth;
256 xn::ImageMetaData image;
257 bool isDepthFilled;
258 bool isImageFilled;
259 };
260
261 // If there isn't TBB the synchronization will be executed in the main thread.
262 class ApproximateSynchronizer: public ApproximateSynchronizerBase
263 {
264 public:
ApproximateSynchronizer(ApproximateSyncGrabber & _approxSyncGrabber)265 ApproximateSynchronizer( ApproximateSyncGrabber& _approxSyncGrabber ) :
266 ApproximateSynchronizerBase(_approxSyncGrabber)
267 {}
268
isSpinContinue() const269 virtual bool isSpinContinue() const
270 {
271 int maxBufferSize = approxSyncGrabber.getMaxBufferSize();
272 return (maxBufferSize <= 0) || (static_cast<int>(depthQueue.size()) < maxBufferSize &&
273 static_cast<int>(imageQueue.size()) < maxBufferSize); // "<" to may push
274 }
275
pushDepthMetaData(xn::DepthMetaData & depthMetaData)276 virtual inline void pushDepthMetaData( xn::DepthMetaData& depthMetaData )
277 {
278 cv::Ptr<xn::DepthMetaData> depthPtr = cv::makePtr<xn::DepthMetaData>();
279 depthPtr->CopyFrom(depthMetaData);
280 depthQueue.push(depthPtr);
281 }
pushImageMetaData(xn::ImageMetaData & imageMetaData)282 virtual inline void pushImageMetaData( xn::ImageMetaData& imageMetaData )
283 {
284 cv::Ptr<xn::ImageMetaData> imagePtr = cv::makePtr<xn::ImageMetaData>();
285 imagePtr->CopyFrom(imageMetaData);
286 imageQueue.push(imagePtr);
287 }
popDepthMetaData(xn::DepthMetaData & depthMetaData)288 virtual inline bool popDepthMetaData( xn::DepthMetaData& depthMetaData )
289 {
290 if( depthQueue.empty() )
291 return false;
292
293 depthMetaData.CopyFrom(*depthQueue.front());
294 depthQueue.pop();
295 return true;
296 }
popImageMetaData(xn::ImageMetaData & imageMetaData)297 virtual inline bool popImageMetaData( xn::ImageMetaData& imageMetaData )
298 {
299 if( imageQueue.empty() )
300 return false;
301
302 imageMetaData.CopyFrom(*imageQueue.front());
303 imageQueue.pop();
304 return true;
305 }
306
307 private:
308 std::queue<cv::Ptr<xn::DepthMetaData> > depthQueue;
309 std::queue<cv::Ptr<xn::ImageMetaData> > imageQueue;
310 };
311
312 #ifdef HAVE_TBB
313 // If there is TBB the synchronization will be executed in own thread.
314 class TBBApproximateSynchronizer: public ApproximateSynchronizerBase
315 {
316 public:
TBBApproximateSynchronizer(ApproximateSyncGrabber & _approxSyncGrabber)317 TBBApproximateSynchronizer( ApproximateSyncGrabber& _approxSyncGrabber ) :
318 ApproximateSynchronizerBase(_approxSyncGrabber)
319 {
320 setMaxBufferSize();
321 }
322
setMaxBufferSize()323 void setMaxBufferSize()
324 {
325 int maxBufferSize = approxSyncGrabber.getMaxBufferSize();
326 if( maxBufferSize >= 0 )
327 {
328 depthQueue.set_capacity( maxBufferSize );
329 imageQueue.set_capacity( maxBufferSize );
330 }
331 }
332
isSpinContinue() const333 virtual inline bool isSpinContinue() const { return true; }
334
pushDepthMetaData(xn::DepthMetaData & depthMetaData)335 virtual inline void pushDepthMetaData( xn::DepthMetaData& depthMetaData )
336 {
337 cv::Ptr<xn::DepthMetaData> depthPtr = cv::makePtr<xn::DepthMetaData>(), tmp;
338 depthPtr->CopyFrom(depthMetaData);
339
340 tbb::mutex mtx;
341 mtx.lock();
342 if( depthQueue.try_push(depthPtr) == false )
343 {
344 if( approxSyncGrabber.getIsCircleBuffer() )
345 {
346 CV_Assert( depthQueue.try_pop(tmp) );
347 CV_Assert( depthQueue.try_push(depthPtr) );
348 }
349 }
350 mtx.unlock();
351 }
352
pushImageMetaData(xn::ImageMetaData & imageMetaData)353 virtual inline void pushImageMetaData( xn::ImageMetaData& imageMetaData )
354 {
355 cv::Ptr<xn::ImageMetaData> imagePtr = cv::makePtr<xn::ImageMetaData>(), tmp;
356 imagePtr->CopyFrom(imageMetaData);
357
358 tbb::mutex mtx;
359 mtx.lock();
360 if( imageQueue.try_push(imagePtr) == false )
361 {
362 if( approxSyncGrabber.getIsCircleBuffer() )
363 {
364 CV_Assert( imageQueue.try_pop(tmp) );
365 CV_Assert( imageQueue.try_push(imagePtr) );
366 }
367 }
368 mtx.unlock();
369 }
370
popDepthMetaData(xn::DepthMetaData & depthMetaData)371 virtual inline bool popDepthMetaData( xn::DepthMetaData& depthMetaData )
372 {
373 cv::Ptr<xn::DepthMetaData> depthPtr;
374 bool isPop = depthQueue.try_pop(depthPtr);
375 if( isPop )
376 depthMetaData.CopyFrom(*depthPtr);
377 return isPop;
378 }
popImageMetaData(xn::ImageMetaData & imageMetaData)379 virtual inline bool popImageMetaData( xn::ImageMetaData& imageMetaData )
380 {
381 cv::Ptr<xn::ImageMetaData> imagePtr;
382 bool isPop = imageQueue.try_pop(imagePtr);
383 if( isPop )
384 imageMetaData.CopyFrom(*imagePtr);
385 return isPop;
386 }
387
388 private:
389 tbb::concurrent_bounded_queue<cv::Ptr<xn::DepthMetaData> > depthQueue;
390 tbb::concurrent_bounded_queue<cv::Ptr<xn::ImageMetaData> > imageQueue;
391 };
392
393 class TBBApproximateSynchronizerTask: public tbb::task
394 {
395 public:
TBBApproximateSynchronizerTask(ApproximateSyncGrabber & approxSyncGrabber)396 TBBApproximateSynchronizerTask( ApproximateSyncGrabber& approxSyncGrabber ) :
397 synchronizer(approxSyncGrabber)
398 {}
399
setMaxBufferSize()400 void setMaxBufferSize()
401 {
402 synchronizer.setMaxBufferSize();
403 }
404
grab(xn::DepthMetaData & depthMetaData,xn::ImageMetaData & imageMetaData)405 bool grab( xn::DepthMetaData& depthMetaData,
406 xn::ImageMetaData& imageMetaData )
407 {
408 return synchronizer.grab( depthMetaData, imageMetaData );
409 }
410
411 private:
execute()412 tbb::task* execute()
413 {
414 synchronizer.spin();
415 return 0;
416 }
417 TBBApproximateSynchronizer synchronizer;
418 };
419 #endif // HAVE_TBB
420
421 #ifdef HAVE_TBB
422 TBBApproximateSynchronizerTask* task;
423 #else
424 cv::Ptr<ApproximateSynchronizer> task;
425 #endif
426 };
427
428 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
429 class CvCapture_OpenNI : public CvCapture
430 {
431 public:
432 enum { DEVICE_DEFAULT=0, DEVICE_MS_KINECT=0, DEVICE_ASUS_XTION=1, DEVICE_MAX=1 };
433
434 static const int INVALID_PIXEL_VAL = 0;
435 static const int INVALID_COORDINATE_VAL = 0;
436
437 #ifdef HAVE_TBB
438 static const int DEFAULT_MAX_BUFFER_SIZE = 8;
439 #else
440 static const int DEFAULT_MAX_BUFFER_SIZE = 2;
441 #endif
442 static const int DEFAULT_IS_CIRCLE_BUFFER = 0;
443 static const int DEFAULT_MAX_TIME_DURATION = 20;
444
445 CvCapture_OpenNI(int index=0);
446 CvCapture_OpenNI(const char * filename);
447 virtual ~CvCapture_OpenNI();
448
449 virtual double getProperty(int propIdx) const;
450 virtual bool setProperty(int probIdx, double propVal);
451 virtual bool grabFrame();
452 virtual IplImage* retrieveFrame(int outputType);
453
454 bool isOpened() const;
455
456 protected:
457 struct OutputMap
458 {
459 public:
460 cv::Mat mat;
461 IplImage* getIplImagePtr();
462 private:
463 IplImage iplHeader;
464 };
465
466 static const int outputMapsTypesCount = 7;
467
468 static XnMapOutputMode defaultMapOutputMode();
469
470 IplImage* retrieveDepthMap();
471 IplImage* retrievePointCloudMap();
472 IplImage* retrieveDisparityMap();
473 IplImage* retrieveDisparityMap_32F();
474 IplImage* retrieveValidDepthMask();
475 IplImage* retrieveBGRImage();
476 IplImage* retrieveGrayImage();
477
478 bool readCamerasParams();
479
480 double getDepthGeneratorProperty(int propIdx) const;
481 bool setDepthGeneratorProperty(int propIdx, double propVal);
482 double getImageGeneratorProperty(int propIdx) const;
483 bool setImageGeneratorProperty(int propIdx, double propVal);
484 double getCommonProperty(int propIdx) const;
485 bool setCommonProperty(int propIdx, double propVal);
486
487 // OpenNI context
488 xn::Context context;
489 bool isContextOpened;
490
491 xn::ProductionNode productionNode;
492
493 // Data generators with its metadata
494 xn::DepthGenerator depthGenerator;
495 xn::DepthMetaData depthMetaData;
496
497 xn::ImageGenerator imageGenerator;
498 xn::ImageMetaData imageMetaData;
499
500 int maxBufferSize, maxTimeDuration; // for approx sync
501 bool isCircleBuffer;
502 cv::Ptr<ApproximateSyncGrabber> approxSyncGrabber;
503
504 // Cameras settings:
505 // TODO find in OpenNI function to convert z->disparity and remove fields "baseline" and depthFocalLength_VGA
506 // Distance between IR projector and IR camera (in meters)
507 XnDouble baseline;
508 // Focal length for the IR camera in VGA resolution (in pixels)
509 XnUInt64 depthFocalLength_VGA;
510
511 // The value for shadow (occluded pixels)
512 XnUInt64 shadowValue;
513 // The value for pixels without a valid disparity measurement
514 XnUInt64 noSampleValue;
515
516 std::vector<OutputMap> outputMaps;
517 };
518
getIplImagePtr()519 IplImage* CvCapture_OpenNI::OutputMap::getIplImagePtr()
520 {
521 if( mat.empty() )
522 return 0;
523
524 iplHeader = IplImage(mat);
525 return &iplHeader;
526 }
527
isOpened() const528 bool CvCapture_OpenNI::isOpened() const
529 {
530 return isContextOpened;
531 }
532
defaultMapOutputMode()533 XnMapOutputMode CvCapture_OpenNI::defaultMapOutputMode()
534 {
535 XnMapOutputMode mode;
536 mode.nXRes = XN_VGA_X_RES;
537 mode.nYRes = XN_VGA_Y_RES;
538 mode.nFPS = 30;
539 return mode;
540 }
541
CvCapture_OpenNI(int index)542 CvCapture_OpenNI::CvCapture_OpenNI( int index )
543 {
544 int deviceType = DEVICE_DEFAULT;
545 XnStatus status;
546
547 isContextOpened = false;
548 maxBufferSize = DEFAULT_MAX_BUFFER_SIZE;
549 isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER;
550 maxTimeDuration = DEFAULT_MAX_TIME_DURATION;
551
552 if( index >= 10 )
553 {
554 deviceType = index / 10;
555 index %= 10;
556 }
557
558 if( deviceType > DEVICE_MAX )
559 return;
560
561 // Initialize and configure the context.
562 status = context.Init();
563 if( status != XN_STATUS_OK )
564 {
565 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to initialize the context: %s\n", xnGetStatusString(status));
566 return;
567 }
568
569 // Find devices
570 xn::NodeInfoList devicesList;
571 status = context.EnumerateProductionTrees( XN_NODE_TYPE_DEVICE, NULL, devicesList, 0 );
572 if( status != XN_STATUS_OK )
573 {
574 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to enumerate production trees: %s\n", xnGetStatusString(status));
575 return;
576 }
577
578 // Chose device according to index
579 xn::NodeInfoList::Iterator it = devicesList.Begin();
580 for( int i = 0; i < index && it!=devicesList.End(); ++i ) it++;
581 if ( it == devicesList.End() )
582 {
583 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed device with index %d\n", index);
584 return;
585 }
586
587 xn::NodeInfo deviceNode = *it;
588 status = context.CreateProductionTree( deviceNode, productionNode );
589 if( status != XN_STATUS_OK )
590 {
591 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to create production tree: %s\n", xnGetStatusString(status));
592 return;
593 }
594
595 xn::ScriptNode scriptNode;
596 status = context.RunXmlScript( XMLConfig.c_str(), scriptNode );
597 if( status != XN_STATUS_OK )
598 {
599 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to run xml script: %s\n", xnGetStatusString(status));
600 return;
601 }
602
603 // Associate generators with context.
604 // enumerate the nodes to find if depth generator is present
605 xn::NodeInfoList depthList;
606 status = context.EnumerateExistingNodes( depthList, XN_NODE_TYPE_DEPTH );
607 if( status != XN_STATUS_OK )
608 {
609 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to enumerate depth generators: %s\n", xnGetStatusString(status));
610 return;
611 }
612 if( depthList.IsEmpty() )
613 {
614 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : The device doesn't have depth generator. Such devices aren't supported now.\n");
615 return;
616 }
617 status = depthGenerator.Create( context );
618 if( status != XN_STATUS_OK )
619 {
620 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to create depth generator: %s\n", xnGetStatusString(status));
621 return;
622 }
623
624 // enumerate the nodes to find if image generator is present
625 xn::NodeInfoList imageList;
626 status = context.EnumerateExistingNodes( imageList, XN_NODE_TYPE_IMAGE );
627 if( status != XN_STATUS_OK )
628 {
629 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to enumerate image generators: %s\n", xnGetStatusString(status));
630 return;
631 }
632
633 if( !imageList.IsEmpty() )
634 {
635 status = imageGenerator.Create( context );
636 if( status != XN_STATUS_OK )
637 {
638 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to create image generator: %s\n", xnGetStatusString(status));
639 return;
640 }
641 }
642
643 // Set map output mode.
644 if( depthGenerator.IsValid() )
645 {
646 CV_DbgAssert( depthGenerator.SetMapOutputMode(defaultMapOutputMode()) == XN_STATUS_OK ); // xn::DepthGenerator supports VGA only! (Jan 2011)
647 }
648 if( imageGenerator.IsValid() )
649 {
650 CV_DbgAssert( imageGenerator.SetMapOutputMode(defaultMapOutputMode()) == XN_STATUS_OK );
651 }
652
653 if( deviceType == DEVICE_ASUS_XTION )
654 {
655 //ps/asus specific
656 imageGenerator.SetIntProperty("InputFormat", 1 /*XN_IO_IMAGE_FORMAT_YUV422*/);
657 imageGenerator.SetPixelFormat(XN_PIXEL_FORMAT_RGB24);
658 depthGenerator.SetIntProperty("RegistrationType", 1 /*XN_PROCESSING_HARDWARE*/);
659 }
660
661 // Start generating data.
662 status = context.StartGeneratingAll();
663 if( status != XN_STATUS_OK )
664 {
665 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to start generating OpenNI data: %s\n", xnGetStatusString(status));
666 return;
667 }
668
669 if( !readCamerasParams() )
670 {
671 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Could not read cameras parameters\n");
672 return;
673 }
674
675 outputMaps.resize( outputMapsTypesCount );
676
677 isContextOpened = true;
678
679 setProperty(CV_CAP_PROP_OPENNI_REGISTRATION, 1.0);
680 }
681
CvCapture_OpenNI(const char * filename)682 CvCapture_OpenNI::CvCapture_OpenNI(const char * filename)
683 {
684 XnStatus status;
685
686 isContextOpened = false;
687 maxBufferSize = DEFAULT_MAX_BUFFER_SIZE;
688 isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER;
689 maxTimeDuration = DEFAULT_MAX_TIME_DURATION;
690
691 // Initialize and configure the context.
692 status = context.Init();
693 if( status != XN_STATUS_OK )
694 {
695 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to initialize the context: %s\n", xnGetStatusString(status));
696 return;
697 }
698
699 // Open file
700 status = context.OpenFileRecording( filename, productionNode );
701 if( status != XN_STATUS_OK )
702 {
703 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Failed to open input file (%s): %s\n", filename, xnGetStatusString(status));
704 return;
705 }
706
707 context.FindExistingNode( XN_NODE_TYPE_DEPTH, depthGenerator );
708 context.FindExistingNode( XN_NODE_TYPE_IMAGE, imageGenerator );
709
710 if( !readCamerasParams() )
711 {
712 fprintf(stderr, "CvCapture_OpenNI::CvCapture_OpenNI : Could not read cameras parameters\n");
713 return;
714 }
715
716 outputMaps.resize( outputMapsTypesCount );
717
718 isContextOpened = true;
719 }
720
~CvCapture_OpenNI()721 CvCapture_OpenNI::~CvCapture_OpenNI()
722 {
723 context.StopGeneratingAll();
724 context.Release();
725 }
726
readCamerasParams()727 bool CvCapture_OpenNI::readCamerasParams()
728 {
729 XnDouble pixelSize = 0;
730 if( depthGenerator.GetRealProperty( "ZPPS", pixelSize ) != XN_STATUS_OK )
731 {
732 fprintf(stderr, "CvCapture_OpenNI::readCamerasParams : Could not read pixel size!\n");
733 return false;
734 }
735
736 // pixel size @ VGA = pixel size @ SXGA x 2
737 pixelSize *= 2.0; // in mm
738
739 // focal length of IR camera in pixels for VGA resolution
740 XnUInt64 zeroPlanDistance; // in mm
741 if( depthGenerator.GetIntProperty( "ZPD", zeroPlanDistance ) != XN_STATUS_OK )
742 {
743 fprintf(stderr, "CvCapture_OpenNI::readCamerasParams : Could not read virtual plane distance!\n");
744 return false;
745 }
746
747 if( depthGenerator.GetRealProperty( "LDDIS", baseline ) != XN_STATUS_OK )
748 {
749 fprintf(stderr, "CvCapture_OpenNI::readCamerasParams : Could not read base line!\n");
750 return false;
751 }
752
753 // baseline from cm -> mm
754 baseline *= 10;
755
756 // focal length from mm -> pixels (valid for 640x480)
757 depthFocalLength_VGA = (XnUInt64)((double)zeroPlanDistance / (double)pixelSize);
758
759 if( depthGenerator.GetIntProperty( "ShadowValue", shadowValue ) != XN_STATUS_OK )
760 {
761 fprintf(stderr, "CvCapture_OpenNI::readCamerasParams : Could not read property \"ShadowValue\"!\n");
762 return false;
763 }
764
765 if( depthGenerator.GetIntProperty("NoSampleValue", noSampleValue ) != XN_STATUS_OK )
766 {
767 fprintf(stderr, "CvCapture_OpenNI::readCamerasParams : Could not read property \"NoSampleValue\"!\n");
768 return false;
769 }
770
771 return true;
772 }
773
getProperty(int propIdx) const774 double CvCapture_OpenNI::getProperty( int propIdx ) const
775 {
776 double propValue = 0;
777
778 if( isOpened() )
779 {
780 int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK;
781
782 if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR )
783 {
784 propValue = getImageGeneratorProperty( purePropIdx );
785 }
786 else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR )
787 {
788 propValue = getDepthGeneratorProperty( purePropIdx );
789 }
790 else
791 {
792 propValue = getCommonProperty( purePropIdx );
793 }
794 }
795
796 return propValue;
797 }
798
setProperty(int propIdx,double propValue)799 bool CvCapture_OpenNI::setProperty( int propIdx, double propValue )
800 {
801 bool isSet = false;
802 if( isOpened() )
803 {
804 int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK;
805
806 if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR )
807 {
808 isSet = setImageGeneratorProperty( purePropIdx, propValue );
809 }
810 else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR )
811 {
812 isSet = setDepthGeneratorProperty( purePropIdx, propValue );
813 }
814 else
815 {
816 isSet = setCommonProperty( purePropIdx, propValue );
817 }
818 }
819
820 return isSet;
821 }
822
getCommonProperty(int propIdx) const823 double CvCapture_OpenNI::getCommonProperty( int propIdx ) const
824 {
825 double propValue = 0;
826
827 switch( propIdx )
828 {
829 // There is a set of properties that correspond to depth generator by default
830 // (is they are pass without particular generator flag). Two reasons of this:
831 // 1) We can assume that depth generator is the main one for depth sensor.
832 // 2) In the initial vertions of OpenNI integration to OpenCV the value of
833 // flag CV_CAP_OPENNI_DEPTH_GENERATOR was 0 (it isn't zero now).
834 case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT :
835 case CV_CAP_PROP_FRAME_WIDTH :
836 case CV_CAP_PROP_FRAME_HEIGHT :
837 case CV_CAP_PROP_FPS :
838 case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH :
839 case CV_CAP_PROP_OPENNI_BASELINE :
840 case CV_CAP_PROP_OPENNI_FOCAL_LENGTH :
841 case CV_CAP_PROP_OPENNI_REGISTRATION :
842 propValue = getDepthGeneratorProperty( propIdx );
843 break;
844 case CV_CAP_PROP_OPENNI_APPROX_FRAME_SYNC :
845 propValue = !approxSyncGrabber.empty() && approxSyncGrabber->isRun() ? 1. : 0.;
846 break;
847 case CV_CAP_PROP_OPENNI_MAX_BUFFER_SIZE :
848 propValue = maxBufferSize;
849 break;
850 case CV_CAP_PROP_OPENNI_CIRCLE_BUFFER :
851 propValue = isCircleBuffer ? 1. : 0.;
852 break;
853 case CV_CAP_PROP_OPENNI_MAX_TIME_DURATION :
854 propValue = maxTimeDuration;
855 break;
856 default :
857 CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for getting.\n", propIdx) );
858 }
859
860 return propValue;
861 }
862
setCommonProperty(int propIdx,double propValue)863 bool CvCapture_OpenNI::setCommonProperty( int propIdx, double propValue )
864 {
865 bool isSet = false;
866
867 switch( propIdx )
868 {
869 // There is a set of properties that correspond to depth generator by default
870 // (is they are pass without particular generator flag).
871 case CV_CAP_PROP_OPENNI_REGISTRATION:
872 isSet = setDepthGeneratorProperty( propIdx, propValue );
873 break;
874 case CV_CAP_PROP_OPENNI_APPROX_FRAME_SYNC :
875 if( propValue && depthGenerator.IsValid() && imageGenerator.IsValid() )
876 {
877 // start synchronization
878 if( approxSyncGrabber.empty() )
879 {
880 approxSyncGrabber.reset(new ApproximateSyncGrabber( context, depthGenerator, imageGenerator, maxBufferSize, isCircleBuffer, maxTimeDuration ));
881 }
882 else
883 {
884 approxSyncGrabber->finish();
885
886 // update params
887 approxSyncGrabber->setMaxBufferSize(maxBufferSize);
888 approxSyncGrabber->setIsCircleBuffer(isCircleBuffer);
889 approxSyncGrabber->setMaxTimeDuration(maxTimeDuration);
890 }
891 approxSyncGrabber->start();
892 }
893 else if( !propValue && !approxSyncGrabber.empty() )
894 {
895 // finish synchronization
896 approxSyncGrabber->finish();
897 }
898 break;
899 case CV_CAP_PROP_OPENNI_MAX_BUFFER_SIZE :
900 maxBufferSize = cvRound(propValue);
901 if( !approxSyncGrabber.empty() )
902 approxSyncGrabber->setMaxBufferSize(maxBufferSize);
903 break;
904 case CV_CAP_PROP_OPENNI_CIRCLE_BUFFER :
905 if( !approxSyncGrabber.empty() )
906 approxSyncGrabber->setIsCircleBuffer(isCircleBuffer);
907 break;
908 case CV_CAP_PROP_OPENNI_MAX_TIME_DURATION :
909 maxTimeDuration = cvRound(propValue);
910 if( !approxSyncGrabber.empty() )
911 approxSyncGrabber->setMaxTimeDuration(maxTimeDuration);
912 break;
913 default:
914 CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for setting.\n", propIdx) );
915 }
916
917 return isSet;
918 }
919
getDepthGeneratorProperty(int propIdx) const920 double CvCapture_OpenNI::getDepthGeneratorProperty( int propIdx ) const
921 {
922 double propValue = 0;
923 if( !depthGenerator.IsValid() )
924 return propValue;
925
926 XnMapOutputMode mode;
927
928 switch( propIdx )
929 {
930 case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT :
931 CV_DbgAssert( depthGenerator.IsValid() );
932 propValue = 1.;
933 break;
934 case CV_CAP_PROP_FRAME_WIDTH :
935 if( depthGenerator.GetMapOutputMode(mode) == XN_STATUS_OK )
936 propValue = mode.nXRes;
937 break;
938 case CV_CAP_PROP_FRAME_HEIGHT :
939 if( depthGenerator.GetMapOutputMode(mode) == XN_STATUS_OK )
940 propValue = mode.nYRes;
941 break;
942 case CV_CAP_PROP_FPS :
943 if( depthGenerator.GetMapOutputMode(mode) == XN_STATUS_OK )
944 propValue = mode.nFPS;
945 break;
946 case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH :
947 propValue = depthGenerator.GetDeviceMaxDepth();
948 break;
949 case CV_CAP_PROP_OPENNI_BASELINE :
950 propValue = baseline;
951 break;
952 case CV_CAP_PROP_OPENNI_FOCAL_LENGTH :
953 propValue = (double)depthFocalLength_VGA;
954 break;
955 case CV_CAP_PROP_OPENNI_REGISTRATION :
956 propValue = depthGenerator.GetAlternativeViewPointCap().IsViewPointAs(const_cast<CvCapture_OpenNI *>(this)->imageGenerator) ? 1.0 : 0.0;
957 break;
958 case CV_CAP_PROP_POS_MSEC :
959 propValue = (double)depthGenerator.GetTimestamp();
960 break;
961 case CV_CAP_PROP_POS_FRAMES :
962 propValue = depthGenerator.GetFrameID();
963 break;
964 default :
965 CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for getting.\n", propIdx) );
966 }
967
968 return propValue;
969 }
970
setDepthGeneratorProperty(int propIdx,double propValue)971 bool CvCapture_OpenNI::setDepthGeneratorProperty( int propIdx, double propValue )
972 {
973 bool isSet = false;
974
975 CV_Assert( depthGenerator.IsValid() );
976
977 switch( propIdx )
978 {
979 case CV_CAP_PROP_OPENNI_REGISTRATION:
980 {
981 if( propValue != 0.0 ) // "on"
982 {
983 // if there isn't image generator (i.e. ASUS XtionPro doesn't have it)
984 // then the property isn't avaliable
985 if( imageGenerator.IsValid() )
986 {
987 if( !depthGenerator.GetAlternativeViewPointCap().IsViewPointAs(imageGenerator) )
988 {
989 if( depthGenerator.GetAlternativeViewPointCap().IsViewPointSupported(imageGenerator) )
990 {
991 XnStatus status = depthGenerator.GetAlternativeViewPointCap().SetViewPoint(imageGenerator);
992 if( status != XN_STATUS_OK )
993 fprintf(stderr, "CvCapture_OpenNI::setDepthGeneratorProperty : %s\n", xnGetStatusString(status));
994 else
995 isSet = true;
996 }
997 else
998 fprintf(stderr, "CvCapture_OpenNI::setDepthGeneratorProperty : Unsupported viewpoint.\n");
999 }
1000 else
1001 isSet = true;
1002 }
1003 }
1004 else // "off"
1005 {
1006 XnStatus status = depthGenerator.GetAlternativeViewPointCap().ResetViewPoint();
1007 if( status != XN_STATUS_OK )
1008 fprintf(stderr, "CvCapture_OpenNI::setDepthGeneratorProperty : %s\n", xnGetStatusString(status));
1009 else
1010 isSet = true;
1011 }
1012 }
1013 break;
1014 default:
1015 CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for setting.\n", propIdx) );
1016 }
1017
1018 return isSet;
1019 }
1020
getImageGeneratorProperty(int propIdx) const1021 double CvCapture_OpenNI::getImageGeneratorProperty( int propIdx ) const
1022 {
1023 double propValue = 0.;
1024 if( !imageGenerator.IsValid() )
1025 return propValue;
1026
1027 XnMapOutputMode mode;
1028 switch( propIdx )
1029 {
1030 case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT :
1031 CV_DbgAssert( imageGenerator.IsValid() );
1032 propValue = 1.;
1033 break;
1034 case CV_CAP_PROP_FRAME_WIDTH :
1035 if( imageGenerator.GetMapOutputMode(mode) == XN_STATUS_OK )
1036 propValue = mode.nXRes;
1037 break;
1038 case CV_CAP_PROP_FRAME_HEIGHT :
1039 if( imageGenerator.GetMapOutputMode(mode) == XN_STATUS_OK )
1040 propValue = mode.nYRes;
1041 break;
1042 case CV_CAP_PROP_FPS :
1043 if( imageGenerator.GetMapOutputMode(mode) == XN_STATUS_OK )
1044 propValue = mode.nFPS;
1045 break;
1046 case CV_CAP_PROP_POS_MSEC :
1047 propValue = (double)imageGenerator.GetTimestamp();
1048 break;
1049 case CV_CAP_PROP_POS_FRAMES :
1050 propValue = (double)imageGenerator.GetFrameID();
1051 break;
1052 default :
1053 CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.\n", propIdx) );
1054 }
1055
1056 return propValue;
1057 }
1058
setImageGeneratorProperty(int propIdx,double propValue)1059 bool CvCapture_OpenNI::setImageGeneratorProperty( int propIdx, double propValue )
1060 {
1061 bool isSet = false;
1062 if( !imageGenerator.IsValid() )
1063 return isSet;
1064
1065 switch( propIdx )
1066 {
1067 case CV_CAP_PROP_OPENNI_OUTPUT_MODE :
1068 {
1069 XnMapOutputMode mode;
1070
1071 switch( cvRound(propValue) )
1072 {
1073 case CV_CAP_OPENNI_VGA_30HZ :
1074 mode.nXRes = XN_VGA_X_RES;
1075 mode.nYRes = XN_VGA_Y_RES;
1076 mode.nFPS = 30;
1077 break;
1078 case CV_CAP_OPENNI_SXGA_15HZ :
1079 mode.nXRes = XN_SXGA_X_RES;
1080 mode.nYRes = XN_SXGA_Y_RES;
1081 mode.nFPS = 15;
1082 break;
1083 case CV_CAP_OPENNI_SXGA_30HZ :
1084 mode.nXRes = XN_SXGA_X_RES;
1085 mode.nYRes = XN_SXGA_Y_RES;
1086 mode.nFPS = 30;
1087 break;
1088 case CV_CAP_OPENNI_QVGA_30HZ :
1089 mode.nXRes = XN_QVGA_X_RES;
1090 mode.nYRes = XN_QVGA_Y_RES;
1091 mode.nFPS = 30;
1092 break;
1093 case CV_CAP_OPENNI_QVGA_60HZ :
1094 mode.nXRes = XN_QVGA_X_RES;
1095 mode.nYRes = XN_QVGA_Y_RES;
1096 mode.nFPS = 60;
1097 break;
1098 default :
1099 CV_Error( CV_StsBadArg, "Unsupported image generator output mode.\n");
1100 }
1101
1102 XnStatus status = imageGenerator.SetMapOutputMode( mode );
1103 if( status != XN_STATUS_OK )
1104 fprintf(stderr, "CvCapture_OpenNI::setImageGeneratorProperty : %s\n", xnGetStatusString(status));
1105 else
1106 isSet = true;
1107 break;
1108 }
1109 default:
1110 CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.\n", propIdx) );
1111 }
1112
1113 return isSet;
1114 }
1115
grabFrame()1116 bool CvCapture_OpenNI::grabFrame()
1117 {
1118 if( !isOpened() )
1119 return false;
1120
1121 bool isGrabbed = false;
1122 if( !approxSyncGrabber.empty() && approxSyncGrabber->isRun() )
1123 {
1124 isGrabbed = approxSyncGrabber->grab( depthMetaData, imageMetaData );
1125 }
1126 else
1127 {
1128 XnStatus status = context.WaitAndUpdateAll();
1129 if( status != XN_STATUS_OK )
1130 return false;
1131
1132 if( depthGenerator.IsValid() )
1133 depthGenerator.GetMetaData( depthMetaData );
1134 if( imageGenerator.IsValid() )
1135 imageGenerator.GetMetaData( imageMetaData );
1136 isGrabbed = true;
1137 }
1138
1139 return isGrabbed;
1140 }
1141
getDepthMapFromMetaData(const xn::DepthMetaData & depthMetaData,cv::Mat & depthMap,XnUInt64 noSampleValue,XnUInt64 shadowValue)1142 inline void getDepthMapFromMetaData( const xn::DepthMetaData& depthMetaData, cv::Mat& depthMap, XnUInt64 noSampleValue, XnUInt64 shadowValue )
1143 {
1144 int cols = depthMetaData.XRes();
1145 int rows = depthMetaData.YRes();
1146
1147 depthMap.create( rows, cols, CV_16UC1 );
1148
1149 const XnDepthPixel* pDepthMap = depthMetaData.Data();
1150
1151 // CV_Assert( sizeof(unsigned short) == sizeof(XnDepthPixel) );
1152 memcpy( depthMap.data, pDepthMap, cols*rows*sizeof(XnDepthPixel) );
1153
1154 cv::Mat badMask = (depthMap == (double)noSampleValue) | (depthMap == (double)shadowValue) | (depthMap == 0);
1155
1156 // mask the pixels with invalid depth
1157 depthMap.setTo( cv::Scalar::all( CvCapture_OpenNI::INVALID_PIXEL_VAL ), badMask );
1158 }
1159
retrieveDepthMap()1160 IplImage* CvCapture_OpenNI::retrieveDepthMap()
1161 {
1162 if( !depthMetaData.Data() )
1163 return 0;
1164
1165 getDepthMapFromMetaData( depthMetaData, outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue );
1166
1167 return outputMaps[CV_CAP_OPENNI_DEPTH_MAP].getIplImagePtr();
1168 }
1169
retrievePointCloudMap()1170 IplImage* CvCapture_OpenNI::retrievePointCloudMap()
1171 {
1172 if( !depthMetaData.Data() )
1173 return 0;
1174
1175 cv::Mat depth;
1176 getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue );
1177
1178 const int badPoint = INVALID_PIXEL_VAL;
1179 const float badCoord = INVALID_COORDINATE_VAL;
1180 int cols = depthMetaData.XRes(), rows = depthMetaData.YRes();
1181 cv::Mat pointCloud_XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) );
1182
1183 std::vector<XnPoint3D> proj(cols*rows);
1184 std::vector<XnPoint3D> real(cols*rows);
1185 for( int y = 0; y < rows; y++ )
1186 {
1187 for( int x = 0; x < cols; x++ )
1188 {
1189 int ind = y*cols+x;
1190 proj[ind].X = (float)x;
1191 proj[ind].Y = (float)y;
1192 proj[ind].Z = depth.at<unsigned short>(y, x);
1193 }
1194 }
1195 depthGenerator.ConvertProjectiveToRealWorld(cols*rows, &proj.front(), &real.front());
1196
1197 for( int y = 0; y < rows; y++ )
1198 {
1199 for( int x = 0; x < cols; x++ )
1200 {
1201 // Check for invalid measurements
1202 if( depth.at<unsigned short>(y, x) == badPoint ) // not valid
1203 pointCloud_XYZ.at<cv::Point3f>(y,x) = cv::Point3f( badCoord, badCoord, badCoord );
1204 else
1205 {
1206 int ind = y*cols+x;
1207 pointCloud_XYZ.at<cv::Point3f>(y,x) = cv::Point3f( real[ind].X*0.001f, real[ind].Y*0.001f, real[ind].Z*0.001f); // from mm to meters
1208 }
1209 }
1210 }
1211
1212 outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].mat = pointCloud_XYZ;
1213
1214 return outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].getIplImagePtr();
1215 }
1216
computeDisparity_32F(const xn::DepthMetaData & depthMetaData,cv::Mat & disp,XnDouble baseline,XnUInt64 F,XnUInt64 noSampleValue,XnUInt64 shadowValue)1217 static void computeDisparity_32F( const xn::DepthMetaData& depthMetaData, cv::Mat& disp, XnDouble baseline, XnUInt64 F,
1218 XnUInt64 noSampleValue, XnUInt64 shadowValue )
1219 {
1220 cv::Mat depth;
1221 getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue );
1222 CV_Assert( depth.type() == CV_16UC1 );
1223
1224
1225 // disparity = baseline * F / z;
1226
1227 float mult = (float)(baseline /*mm*/ * F /*pixels*/);
1228
1229 disp.create( depth.size(), CV_32FC1);
1230 disp = cv::Scalar::all( CvCapture_OpenNI::INVALID_PIXEL_VAL );
1231 for( int y = 0; y < disp.rows; y++ )
1232 {
1233 for( int x = 0; x < disp.cols; x++ )
1234 {
1235 unsigned short curDepth = depth.at<unsigned short>(y,x);
1236 if( curDepth != CvCapture_OpenNI::INVALID_PIXEL_VAL )
1237 disp.at<float>(y,x) = mult / curDepth;
1238 }
1239 }
1240 }
1241
retrieveDisparityMap()1242 IplImage* CvCapture_OpenNI::retrieveDisparityMap()
1243 {
1244 if( !depthMetaData.Data() )
1245 return 0;
1246
1247 cv::Mat disp32;
1248 computeDisparity_32F( depthMetaData, disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue );
1249
1250 disp32.convertTo( outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1 );
1251
1252 return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].getIplImagePtr();
1253 }
1254
retrieveDisparityMap_32F()1255 IplImage* CvCapture_OpenNI::retrieveDisparityMap_32F()
1256 {
1257 if( !depthMetaData.Data() )
1258 return 0;
1259
1260 computeDisparity_32F( depthMetaData, outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue );
1261
1262 return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].getIplImagePtr();
1263 }
1264
retrieveValidDepthMask()1265 IplImage* CvCapture_OpenNI::retrieveValidDepthMask()
1266 {
1267 if( !depthMetaData.Data() )
1268 return 0;
1269
1270 cv::Mat depth;
1271 getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue );
1272
1273 outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].mat = depth != CvCapture_OpenNI::INVALID_PIXEL_VAL;
1274
1275 return outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].getIplImagePtr();
1276 }
1277
getBGRImageFromMetaData(const xn::ImageMetaData & imageMetaData,cv::Mat & bgrImage)1278 inline void getBGRImageFromMetaData( const xn::ImageMetaData& imageMetaData, cv::Mat& bgrImage )
1279 {
1280 if( imageMetaData.PixelFormat() != XN_PIXEL_FORMAT_RGB24 )
1281 CV_Error( CV_StsUnsupportedFormat, "Unsupported format of grabbed image\n" );
1282
1283 cv::Mat rgbImage( imageMetaData.YRes(), imageMetaData.XRes(), CV_8UC3 );
1284 const XnRGB24Pixel* pRgbImage = imageMetaData.RGB24Data();
1285
1286 // CV_Assert( 3*sizeof(uchar) == sizeof(XnRGB24Pixel) );
1287 memcpy( rgbImage.data, pRgbImage, rgbImage.total()*sizeof(XnRGB24Pixel) );
1288 cv::cvtColor( rgbImage, bgrImage, CV_RGB2BGR );
1289 }
1290
retrieveBGRImage()1291 IplImage* CvCapture_OpenNI::retrieveBGRImage()
1292 {
1293 if( !imageMetaData.Data() )
1294 return 0;
1295
1296 getBGRImageFromMetaData( imageMetaData, outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat );
1297
1298 return outputMaps[CV_CAP_OPENNI_BGR_IMAGE].getIplImagePtr();
1299 }
1300
retrieveGrayImage()1301 IplImage* CvCapture_OpenNI::retrieveGrayImage()
1302 {
1303 if( !imageMetaData.Data() )
1304 return 0;
1305
1306 CV_Assert( imageMetaData.BytesPerPixel() == 3 ); // RGB
1307
1308 cv::Mat rgbImage;
1309 getBGRImageFromMetaData( imageMetaData, rgbImage );
1310 cv::cvtColor( rgbImage, outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].mat, CV_BGR2GRAY );
1311
1312 return outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].getIplImagePtr();
1313 }
1314
retrieveFrame(int outputType)1315 IplImage* CvCapture_OpenNI::retrieveFrame( int outputType )
1316 {
1317 IplImage* image = 0;
1318 CV_Assert( outputType < outputMapsTypesCount && outputType >= 0);
1319
1320 if( outputType == CV_CAP_OPENNI_DEPTH_MAP )
1321 {
1322 image = retrieveDepthMap();
1323 }
1324 else if( outputType == CV_CAP_OPENNI_POINT_CLOUD_MAP )
1325 {
1326 image = retrievePointCloudMap();
1327 }
1328 else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP )
1329 {
1330 image = retrieveDisparityMap();
1331 }
1332 else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP_32F )
1333 {
1334 image = retrieveDisparityMap_32F();
1335 }
1336 else if( outputType == CV_CAP_OPENNI_VALID_DEPTH_MASK )
1337 {
1338 image = retrieveValidDepthMask();
1339 }
1340 else if( outputType == CV_CAP_OPENNI_BGR_IMAGE )
1341 {
1342 image = retrieveBGRImage();
1343 }
1344 else if( outputType == CV_CAP_OPENNI_GRAY_IMAGE )
1345 {
1346 image = retrieveGrayImage();
1347 }
1348
1349 return image;
1350 }
1351
1352
cvCreateCameraCapture_OpenNI(int index)1353 CvCapture* cvCreateCameraCapture_OpenNI( int index )
1354 {
1355 CvCapture_OpenNI* capture = new CvCapture_OpenNI( index );
1356
1357 if( capture->isOpened() )
1358 return capture;
1359
1360 delete capture;
1361 return 0;
1362 }
1363
cvCreateFileCapture_OpenNI(const char * filename)1364 CvCapture* cvCreateFileCapture_OpenNI( const char* filename )
1365 {
1366 CvCapture_OpenNI* capture = new CvCapture_OpenNI( filename );
1367
1368 if( capture->isOpened() )
1369 return capture;
1370
1371 delete capture;
1372 return 0;
1373 }
1374
1375 #endif
1376