1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
41 #include "precomp.hpp"
42 #include "opencv2/core.hpp"
43 #include "opencv2/imgproc.hpp"
62 #define CV_STREAM_TIMEOUT 2000
64 #define CV_DEPTH_STREAM 0
65 #define CV_COLOR_STREAM 1
66 #define CV_IR_STREAM 2
67 #define CV_MAX_NUM_STREAMS 3
72 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
74 static cv::Mutex initOpenNI2Mutex;
76 struct OpenNI2Initializer
81 cv::AutoLock al(initOpenNI2Mutex);
82 static OpenNI2Initializer initializer;
88 // Initialize and configure the context.
89 openni::Status status = openni::OpenNI::initialize();
90 if (status != openni::STATUS_OK)
92 CV_Error(CV_StsError, std::string("Failed to initialize:") + openni::OpenNI::getExtendedError());
98 openni::OpenNI::shutdown();
102 class CvCapture_OpenNI2 : public CvCapture
105 enum { DEVICE_DEFAULT=0, DEVICE_MS_KINECT=0, DEVICE_ASUS_XTION=1, DEVICE_MAX=1 };
107 static const int INVALID_PIXEL_VAL = 0;
108 static const int INVALID_COORDINATE_VAL = 0;
110 static const int DEFAULT_MAX_BUFFER_SIZE = 2;
111 static const int DEFAULT_IS_CIRCLE_BUFFER = 0;
112 static const int DEFAULT_MAX_TIME_DURATION = 20;
114 CvCapture_OpenNI2(int index = 0);
115 CvCapture_OpenNI2(const char * filename);
116 virtual ~CvCapture_OpenNI2();
118 virtual double getProperty(int propIdx) const CV_OVERRIDE;
119 virtual bool setProperty(int probIdx, double propVal) CV_OVERRIDE;
120 virtual bool grabFrame() CV_OVERRIDE;
121 virtual IplImage* retrieveFrame(int outputType) CV_OVERRIDE;
123 bool isOpened() const;
130 IplImage* getIplImagePtr();
135 static const int outputMapsTypesCount = 8;
137 static openni::VideoMode defaultStreamOutputMode(int stream);
139 CvCapture_OpenNI2(int index, const char * filename);
141 IplImage* retrieveDepthMap();
142 IplImage* retrievePointCloudMap();
143 IplImage* retrieveDisparityMap();
144 IplImage* retrieveDisparityMap_32F();
145 IplImage* retrieveValidDepthMask();
146 IplImage* retrieveBGRImage();
147 IplImage* retrieveGrayImage();
148 IplImage* retrieveIrImage();
150 void toggleStream(int stream, bool toggle);
151 void readCamerasParams();
153 double getDepthGeneratorProperty(int propIdx) const;
154 bool setDepthGeneratorProperty(int propIdx, double propVal);
155 double getImageGeneratorProperty(int propIdx) const;
156 bool setImageGeneratorProperty(int propIdx, double propVal);
157 double getIrGeneratorProperty(int propIdx) const;
158 bool setIrGeneratorProperty(int propIdx, double propVal);
159 double getCommonProperty(int propIdx) const;
160 bool setCommonProperty(int propIdx, double propVal);
163 openni::Device device;
164 bool isContextOpened;
166 // Data generators with its metadata
167 std::vector<openni::VideoStream> streams;
168 std::vector<openni::VideoFrameRef> streamFrames;
169 std::vector<cv::Mat> streamImages;
171 int maxBufferSize, maxTimeDuration; // for approx sync
173 //cv::Ptr<ApproximateSyncGrabber> approxSyncGrabber;
176 // TODO find in OpenNI function to convert z->disparity and remove fields "baseline" and depthFocalLength_VGA
177 // Distance between IR projector and IR camera (in meters)
179 // Focal length for the IR camera in VGA resolution (in pixels)
180 int depthFocalLength_VGA;
182 // The value for shadow (occluded pixels)
184 // The value for pixels without a valid disparity measurement
187 std::vector<OutputMap> outputMaps;
190 IplImage* CvCapture_OpenNI2::OutputMap::getIplImagePtr()
195 iplHeader = IplImage(mat);
199 bool CvCapture_OpenNI2::isOpened() const
201 return isContextOpened;
204 openni::VideoMode CvCapture_OpenNI2::defaultStreamOutputMode(int stream)
206 openni::VideoMode mode;
207 mode.setResolution(640, 480);
211 case CV_DEPTH_STREAM:
212 mode.setPixelFormat(openni::PIXEL_FORMAT_DEPTH_1_MM);
214 case CV_COLOR_STREAM:
215 mode.setPixelFormat(openni::PIXEL_FORMAT_RGB888);
218 mode.setPixelFormat(openni::PIXEL_FORMAT_GRAY16);
225 CvCapture_OpenNI2::CvCapture_OpenNI2(int index) :
226 CvCapture_OpenNI2(index, nullptr)
229 CvCapture_OpenNI2::CvCapture_OpenNI2(const char * filename) :
230 CvCapture_OpenNI2(-1, filename)
233 CvCapture_OpenNI2::CvCapture_OpenNI2(int index, const char * filename) :
235 isContextOpened(false),
236 streams(CV_MAX_NUM_STREAMS),
237 streamFrames(CV_MAX_NUM_STREAMS),
238 streamImages(CV_MAX_NUM_STREAMS),
239 maxBufferSize(DEFAULT_MAX_BUFFER_SIZE),
240 maxTimeDuration(DEFAULT_MAX_TIME_DURATION),
241 isCircleBuffer(DEFAULT_IS_CIRCLE_BUFFER),
243 depthFocalLength_VGA(0),
246 outputMaps(outputMapsTypesCount)
248 // Initialize and configure the context.
249 OpenNI2Initializer::init();
251 const char* deviceURI = openni::ANY_DEVICE;
252 bool needColor = true;
256 int deviceType = DEVICE_DEFAULT;
259 deviceType = index / 10;
262 // Asus XTION and Occipital Structure Sensor do not have an image generator
263 needColor = (deviceType != DEVICE_ASUS_XTION);
265 // find appropriate device URI
266 openni::Array<openni::DeviceInfo> ldevs;
269 openni::OpenNI::enumerateDevices(&ldevs);
270 if (index < ldevs.getSize())
271 deviceURI = ldevs[index].getUri();
274 CV_Error(CV_StsError, "OpenCVKinect2: Device index exceeds the number of available OpenNI devices");
280 deviceURI = filename;
283 openni::Status status;
284 status = device.open(deviceURI);
285 if (status != openni::STATUS_OK)
287 CV_Error(CV_StsError, std::string("OpenCVKinect2: Failed to open device: ") + openni::OpenNI::getExtendedError());
290 toggleStream(CV_DEPTH_STREAM, true);
292 toggleStream(CV_COLOR_STREAM, true);
294 toggleStream(CV_IR_STREAM, true);
296 setProperty(CV_CAP_PROP_OPENNI_REGISTRATION, 1.0);
298 // default for Kinect2 camera
299 setProperty(CV_CAP_PROP_OPENNI2_MIRROR, 0.0);
301 isContextOpened = true;
304 CvCapture_OpenNI2::~CvCapture_OpenNI2()
306 for (size_t i = 0; i < streams.size(); ++i)
308 streamFrames[i].release();
310 streams[i].destroy();
315 void CvCapture_OpenNI2::toggleStream(int stream, bool toggle)
317 openni::Status status;
320 static const std::string stream_names[CV_MAX_NUM_STREAMS] = {
326 static const openni::SensorType stream_sensor_types[CV_MAX_NUM_STREAMS] = {
327 openni::SENSOR_DEPTH,
328 openni::SENSOR_COLOR,
332 if (toggle) // want to open stream
335 if (streams[stream].isValid())
339 status = streams[stream].create(device, stream_sensor_types[stream]);
340 if (status == openni::STATUS_OK)
342 // try to set up default stream mode (if available)
343 const openni::Array<openni::VideoMode>& vm = streams[stream].getSensorInfo().getSupportedVideoModes();
344 openni::VideoMode dm = defaultStreamOutputMode(stream);
345 for (int i = 0; i < vm.getSize(); i++)
347 if (vm[i].getPixelFormat() == dm.getPixelFormat() &&
348 vm[i].getResolutionX() == dm.getResolutionX() &&
349 vm[i].getResolutionY() == dm.getResolutionY() &&
350 vm[i].getFps() == dm.getFps())
352 status = streams[stream].setVideoMode(defaultStreamOutputMode(stream));
353 if (status != openni::STATUS_OK)
355 streams[stream].destroy();
356 CV_Error(CV_StsError, std::string("OpenCVKinect2 : Couldn't set ") +
357 stream_names[stream] + std::string(" stream output mode: ") +
358 std::string(openni::OpenNI::getExtendedError()));
364 status = streams[stream].start();
365 if (status != openni::STATUS_OK)
367 streams[stream].destroy();
368 CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start ") +
369 stream_names[stream] + std::string(" stream: ") +
370 std::string(openni::OpenNI::getExtendedError()));
375 CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find ") +
376 stream_names[stream] + " stream: " +
377 std::string(openni::OpenNI::getExtendedError()));
380 else if (streams[stream].isValid()) // want to close stream
382 //FIX for libfreenect2
383 //which stops the whole device when stopping only one stream
385 //streams[stream].stop();
386 //streams[stream].destroy();
391 void CvCapture_OpenNI2::readCamerasParams()
393 double pixelSize = 0;
394 if (streams[CV_DEPTH_STREAM].getProperty<double>(XN_STREAM_PROPERTY_ZERO_PLANE_PIXEL_SIZE, &pixelSize) != openni::STATUS_OK)
396 CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read pixel size!" +
397 std::string(openni::OpenNI::getExtendedError()));
400 // pixel size @ VGA = pixel size @ SXGA x 2
401 pixelSize *= 2.0; // in mm
403 // focal length of IR camera in pixels for VGA resolution
404 unsigned long long zeroPlaneDistance; // in mm
405 if (streams[CV_DEPTH_STREAM].getProperty(XN_STREAM_PROPERTY_ZERO_PLANE_DISTANCE, &zeroPlaneDistance) != openni::STATUS_OK)
407 CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read virtual plane distance!" +
408 std::string(openni::OpenNI::getExtendedError()));
411 if (streams[CV_DEPTH_STREAM].getProperty<double>(XN_STREAM_PROPERTY_EMITTER_DCMOS_DISTANCE, &baseline) != openni::STATUS_OK)
413 CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read base line!" +
414 std::string(openni::OpenNI::getExtendedError()));
417 // baseline from cm -> mm
420 // focal length from mm -> pixels (valid for 640x480)
421 depthFocalLength_VGA = (int)((double)zeroPlaneDistance / (double)pixelSize);
424 double CvCapture_OpenNI2::getProperty( int propIdx ) const
426 double propValue = 0;
430 int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK;
432 if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR )
434 propValue = getImageGeneratorProperty( purePropIdx );
436 else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR )
438 propValue = getDepthGeneratorProperty( purePropIdx );
440 else if ((propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IR_GENERATOR)
442 propValue = getIrGeneratorProperty(purePropIdx);
446 propValue = getCommonProperty( purePropIdx );
453 bool CvCapture_OpenNI2::setProperty( int propIdx, double propValue )
458 int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK;
460 if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR )
462 isSet = setImageGeneratorProperty( purePropIdx, propValue );
464 else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR )
466 isSet = setDepthGeneratorProperty( purePropIdx, propValue );
468 else if ((propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IR_GENERATOR)
470 isSet = setIrGeneratorProperty(purePropIdx, propValue);
474 isSet = setCommonProperty( purePropIdx, propValue );
481 double CvCapture_OpenNI2::getCommonProperty( int propIdx ) const
483 double propValue = 0;
487 case CV_CAP_PROP_FRAME_WIDTH :
488 case CV_CAP_PROP_FRAME_HEIGHT :
489 case CV_CAP_PROP_FPS :
490 case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH :
491 case CV_CAP_PROP_OPENNI_BASELINE :
492 case CV_CAP_PROP_OPENNI_FOCAL_LENGTH :
493 case CV_CAP_PROP_OPENNI_REGISTRATION :
494 propValue = getDepthGeneratorProperty( propIdx );
496 case CV_CAP_PROP_OPENNI2_SYNC :
497 propValue = const_cast<CvCapture_OpenNI2 *>(this)->device.getDepthColorSyncEnabled();
499 case CV_CAP_PROP_OPENNI2_MIRROR:
501 bool isMirroring = false;
502 for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)
503 isMirroring |= streams[i].getMirroringEnabled();
504 propValue = isMirroring ? 1.0 : 0.0;
508 CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for getting.", propIdx) );
514 bool CvCapture_OpenNI2::setCommonProperty( int propIdx, double propValue )
520 case CV_CAP_PROP_OPENNI2_MIRROR:
522 bool mirror = propValue > 0.0 ? true : false;
523 for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)
525 if (streams[i].isValid())
526 isSet |= streams[i].setMirroringEnabled(mirror) == openni::STATUS_OK;
530 // There is a set of properties that correspond to depth generator by default
531 // (is they are pass without particular generator flag).
532 case CV_CAP_PROP_OPENNI_REGISTRATION:
533 isSet = setDepthGeneratorProperty(propIdx, propValue);
535 case CV_CAP_PROP_OPENNI2_SYNC:
536 isSet = device.setDepthColorSyncEnabled(propValue > 0.0) == openni::STATUS_OK;
539 case CV_CAP_PROP_FRAME_WIDTH:
540 case CV_CAP_PROP_FRAME_HEIGHT:
541 case CV_CAP_PROP_AUTOFOCUS:
546 CV_Error(CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for setting.", propIdx));
552 double CvCapture_OpenNI2::getDepthGeneratorProperty( int propIdx ) const
554 double propValue = 0;
555 if( !streams[CV_DEPTH_STREAM].isValid() )
558 openni::VideoMode mode;
562 case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
563 propValue = streams[CV_DEPTH_STREAM].isValid();
565 case CV_CAP_PROP_FRAME_WIDTH :
566 propValue = streams[CV_DEPTH_STREAM].getVideoMode().getResolutionX();
568 case CV_CAP_PROP_FRAME_HEIGHT :
569 propValue = streams[CV_DEPTH_STREAM].getVideoMode().getResolutionY();
571 case CV_CAP_PROP_FPS :
572 mode = streams[CV_DEPTH_STREAM].getVideoMode();
573 propValue = mode.getFps();
575 case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH :
576 propValue = streams[CV_DEPTH_STREAM].getMaxPixelValue();
578 case CV_CAP_PROP_OPENNI_BASELINE :
580 const_cast<CvCapture_OpenNI2*>(this)->readCamerasParams();
581 propValue = baseline;
583 case CV_CAP_PROP_OPENNI_FOCAL_LENGTH :
584 if(depthFocalLength_VGA <= 0)
585 const_cast<CvCapture_OpenNI2*>(this)->readCamerasParams();
586 propValue = (double)depthFocalLength_VGA;
588 case CV_CAP_PROP_OPENNI_REGISTRATION :
589 propValue = device.getImageRegistrationMode();
591 case CV_CAP_PROP_POS_MSEC :
592 propValue = (double)streamFrames[CV_DEPTH_STREAM].getTimestamp();
594 case CV_CAP_PROP_POS_FRAMES :
595 propValue = streamFrames[CV_DEPTH_STREAM].getFrameIndex();
598 CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for getting.", propIdx) );
604 bool CvCapture_OpenNI2::setDepthGeneratorProperty( int propIdx, double propValue )
610 case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
613 toggleStream(CV_DEPTH_STREAM, propValue > 0.0);
617 case CV_CAP_PROP_OPENNI_REGISTRATION:
619 CV_Assert(streams[CV_DEPTH_STREAM].isValid());
620 if( propValue != 0.0 ) // "on"
622 // if there isn't image generator (i.e. ASUS XtionPro doesn't have it)
623 // then the property isn't available
624 if ( streams[CV_COLOR_STREAM].isValid() )
626 openni::ImageRegistrationMode mode = propValue != 0.0 ? openni::IMAGE_REGISTRATION_DEPTH_TO_COLOR : openni::IMAGE_REGISTRATION_OFF;
627 if( device.getImageRegistrationMode() != mode )
629 if (device.isImageRegistrationModeSupported(mode))
631 openni::Status status = device.setImageRegistrationMode(mode);
632 if( status != openni::STATUS_OK )
633 CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setDepthGeneratorProperty: ") +
634 std::string(openni::OpenNI::getExtendedError()));
639 CV_Error(CV_StsError, "CvCapture_OpenNI2::setDepthGeneratorProperty: Unsupported viewpoint.");
647 openni::Status status = device.setImageRegistrationMode(openni::IMAGE_REGISTRATION_OFF);
648 if( status != openni::STATUS_OK )
649 CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setDepthGeneratorProperty: ") +
650 std::string(openni::OpenNI::getExtendedError()));
657 CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for setting.", propIdx) );
663 double CvCapture_OpenNI2::getImageGeneratorProperty( int propIdx ) const
665 double propValue = 0.;
666 if( !streams[CV_COLOR_STREAM].isValid() )
669 openni::VideoMode mode;
672 case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
673 propValue = streams[CV_COLOR_STREAM].isValid();
675 case CV_CAP_PROP_FRAME_WIDTH :
676 propValue = streams[CV_COLOR_STREAM].getVideoMode().getResolutionX();
678 case CV_CAP_PROP_FRAME_HEIGHT :
679 propValue = streams[CV_COLOR_STREAM].getVideoMode().getResolutionY();
681 case CV_CAP_PROP_FPS :
682 propValue = streams[CV_COLOR_STREAM].getVideoMode().getFps();
684 case CV_CAP_PROP_POS_MSEC :
685 propValue = (double)streamFrames[CV_COLOR_STREAM].getTimestamp();
687 case CV_CAP_PROP_POS_FRAMES :
688 propValue = (double)streamFrames[CV_COLOR_STREAM].getFrameIndex();
691 CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.", propIdx) );
697 bool CvCapture_OpenNI2::setImageGeneratorProperty(int propIdx, double propValue)
703 case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
706 toggleStream(CV_COLOR_STREAM, propValue > 0.0);
710 case CV_CAP_PROP_OPENNI_OUTPUT_MODE :
712 if (!streams[CV_COLOR_STREAM].isValid())
714 openni::VideoMode mode = streams[CV_COLOR_STREAM].getVideoMode();
716 switch( cvRound(propValue) )
718 case CV_CAP_OPENNI_VGA_30HZ :
719 mode.setResolution(640,480);
722 case CV_CAP_OPENNI_SXGA_15HZ :
723 mode.setResolution(1280, 960);
726 case CV_CAP_OPENNI_SXGA_30HZ :
727 mode.setResolution(1280, 960);
730 case CV_CAP_OPENNI_QVGA_30HZ :
731 mode.setResolution(320, 240);
734 case CV_CAP_OPENNI_QVGA_60HZ :
735 mode.setResolution(320, 240);
739 CV_Error( CV_StsBadArg, "Unsupported image generator output mode.");
742 openni::Status status = streams[CV_COLOR_STREAM].setVideoMode( mode );
743 if( status != openni::STATUS_OK )
744 CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setImageGeneratorProperty: ") +
745 std::string(openni::OpenNI::getExtendedError()));
751 CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.", propIdx) );
757 double CvCapture_OpenNI2::getIrGeneratorProperty(int propIdx) const
759 double propValue = 0.;
760 if (!streams[CV_IR_STREAM].isValid())
763 openni::VideoMode mode;
766 case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
767 propValue = streams[CV_IR_STREAM].isValid();
769 case CV_CAP_PROP_FRAME_WIDTH:
770 propValue = streams[CV_IR_STREAM].getVideoMode().getResolutionX();
772 case CV_CAP_PROP_FRAME_HEIGHT:
773 propValue = streams[CV_IR_STREAM].getVideoMode().getResolutionY();
775 case CV_CAP_PROP_FPS:
776 propValue = streams[CV_IR_STREAM].getVideoMode().getFps();
778 case CV_CAP_PROP_POS_MSEC:
779 propValue = (double)streamFrames[CV_IR_STREAM].getTimestamp();
781 case CV_CAP_PROP_POS_FRAMES:
782 propValue = (double)streamFrames[CV_IR_STREAM].getFrameIndex();
785 CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.", propIdx));
791 bool CvCapture_OpenNI2::setIrGeneratorProperty(int propIdx, double propValue)
797 case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
800 toggleStream(CV_IR_STREAM, propValue > 0.0);
804 case CV_CAP_PROP_OPENNI_OUTPUT_MODE:
806 if (!streams[CV_IR_STREAM].isValid())
808 openni::VideoMode mode = streams[CV_IR_STREAM].getVideoMode();
810 switch (cvRound(propValue))
812 case CV_CAP_OPENNI_VGA_30HZ:
813 mode.setResolution(640, 480);
816 case CV_CAP_OPENNI_SXGA_15HZ:
817 mode.setResolution(1280, 960);
820 case CV_CAP_OPENNI_SXGA_30HZ:
821 mode.setResolution(1280, 960);
824 case CV_CAP_OPENNI_QVGA_30HZ:
825 mode.setResolution(320, 240);
828 case CV_CAP_OPENNI_QVGA_60HZ:
829 mode.setResolution(320, 240);
833 CV_Error(CV_StsBadArg, "Unsupported image generator output mode.");
836 openni::Status status = streams[CV_IR_STREAM].setVideoMode(mode);
837 if (status != openni::STATUS_OK)
838 CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setImageGeneratorProperty: ") +
839 std::string(openni::OpenNI::getExtendedError()));
845 CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.", propIdx));
851 bool CvCapture_OpenNI2::grabFrame()
856 bool isGrabbed = false;
858 int numActiveStreams = 0;
859 openni::VideoStream* streamPtrs[CV_MAX_NUM_STREAMS];
860 for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i) {
861 streamPtrs[numActiveStreams++] = &streams[i];
865 openni::Status status = openni::OpenNI::waitForAnyStream(streamPtrs, numActiveStreams, ¤tStream, CV_STREAM_TIMEOUT);
866 if( status != openni::STATUS_OK )
869 for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)
871 if (streams[i].isValid())
872 streams[i].readFrame(&streamFrames[i]);
879 inline void getDepthMapFromMetaData(const openni::VideoFrameRef& depthMetaData, cv::Mat& depthMap, int noSampleValue, int shadowValue)
881 depthMap.create(depthMetaData.getHeight(), depthMetaData.getWidth(), CV_16UC1);
882 depthMap.data = (uchar*)depthMetaData.getData();
884 cv::Mat badMask = (depthMap == (double)noSampleValue) | (depthMap == (double)shadowValue) | (depthMap == 0);
886 // mask the pixels with invalid depth
887 depthMap.setTo( cv::Scalar::all( CvCapture_OpenNI2::INVALID_PIXEL_VAL ), badMask );
890 IplImage* CvCapture_OpenNI2::retrieveDepthMap()
892 if( !streamFrames[CV_DEPTH_STREAM].isValid() )
895 getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue );
897 return outputMaps[CV_CAP_OPENNI_DEPTH_MAP].getIplImagePtr();
900 IplImage* CvCapture_OpenNI2::retrievePointCloudMap()
902 if( !streamFrames[CV_DEPTH_STREAM].isValid() )
906 getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], depthImg, noSampleValue, shadowValue);
908 const int badPoint = INVALID_PIXEL_VAL;
909 const float badCoord = INVALID_COORDINATE_VAL;
910 int cols = streamFrames[CV_DEPTH_STREAM].getWidth(), rows = streamFrames[CV_DEPTH_STREAM].getHeight();
911 cv::Mat pointCloud_XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) );
913 float worldX, worldY, worldZ;
914 for( int y = 0; y < rows; y++ )
916 for (int x = 0; x < cols; x++)
918 openni::CoordinateConverter::convertDepthToWorld(streams[CV_DEPTH_STREAM], x, y, depthImg.at<unsigned short>(y, x), &worldX, &worldY, &worldZ);
920 if (depthImg.at<unsigned short>(y, x) == badPoint) // not valid
921 pointCloud_XYZ.at<cv::Point3f>(y, x) = cv::Point3f(badCoord, badCoord, badCoord);
924 pointCloud_XYZ.at<cv::Point3f>(y, x) = cv::Point3f(worldX*0.001f, worldY*0.001f, worldZ*0.001f); // from mm to meters
929 outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].mat = pointCloud_XYZ;
931 return outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].getIplImagePtr();
934 static void computeDisparity_32F( const openni::VideoFrameRef& depthMetaData, cv::Mat& disp, double baseline, int F, int noSampleValue, int shadowValue)
937 getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue );
938 CV_Assert( depth.type() == CV_16UC1 );
940 // disparity = baseline * F / z;
942 float mult = (float)(baseline /*mm*/ * F /*pixels*/);
944 disp.create( depth.size(), CV_32FC1);
945 disp = cv::Scalar::all( CvCapture_OpenNI2::INVALID_PIXEL_VAL );
946 for( int y = 0; y < disp.rows; y++ )
948 for( int x = 0; x < disp.cols; x++ )
950 unsigned short curDepth = depth.at<unsigned short>(y,x);
951 if( curDepth != CvCapture_OpenNI2::INVALID_PIXEL_VAL )
952 disp.at<float>(y,x) = mult / curDepth;
957 IplImage* CvCapture_OpenNI2::retrieveDisparityMap()
959 if (!streamFrames[CV_DEPTH_STREAM].isValid())
965 computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);
967 disp32.convertTo(outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1);
969 return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].getIplImagePtr();
972 IplImage* CvCapture_OpenNI2::retrieveDisparityMap_32F()
974 if (!streamFrames[CV_DEPTH_STREAM].isValid())
979 computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);
981 return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].getIplImagePtr();
984 IplImage* CvCapture_OpenNI2::retrieveValidDepthMask()
986 if (!streamFrames[CV_DEPTH_STREAM].isValid())
990 getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], d, noSampleValue, shadowValue);
992 outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].mat = d != CvCapture_OpenNI2::INVALID_PIXEL_VAL;
994 return outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].getIplImagePtr();
997 inline void getBGRImageFromMetaData( const openni::VideoFrameRef& imageMetaData, cv::Mat& bgrImage )
1000 if( imageMetaData.getVideoMode().getPixelFormat() != openni::PIXEL_FORMAT_RGB888 )
1001 CV_Error( CV_StsUnsupportedFormat, "Unsupported format of grabbed image." );
1003 bgrImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3);
1004 bufferImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3);
1005 bufferImage.data = (uchar*)imageMetaData.getData();
1007 cv::cvtColor(bufferImage, bgrImage, cv::COLOR_RGB2BGR);
1010 inline void getGrayImageFromMetaData(const openni::VideoFrameRef& imageMetaData, cv::Mat& grayImage)
1012 if (imageMetaData.getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_GRAY8)
1014 grayImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC1);
1015 grayImage.data = (uchar*)imageMetaData.getData();
1017 else if (imageMetaData.getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_GRAY16)
1019 grayImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_16UC1);
1020 grayImage.data = (uchar*)imageMetaData.getData();
1024 CV_Error(CV_StsUnsupportedFormat, "Unsupported format of grabbed image.");
1028 IplImage* CvCapture_OpenNI2::retrieveBGRImage()
1030 if( !streamFrames[CV_COLOR_STREAM].isValid() )
1033 getBGRImageFromMetaData(streamFrames[CV_COLOR_STREAM], outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat );
1035 return outputMaps[CV_CAP_OPENNI_BGR_IMAGE].getIplImagePtr();
1038 IplImage* CvCapture_OpenNI2::retrieveGrayImage()
1040 if (!streamFrames[CV_COLOR_STREAM].isValid())
1043 CV_Assert(streamFrames[CV_COLOR_STREAM].getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_RGB888); // RGB
1046 getBGRImageFromMetaData(streamFrames[CV_COLOR_STREAM], rgbImage);
1047 cv::cvtColor( rgbImage, outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].mat, CV_BGR2GRAY );
1049 return outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].getIplImagePtr();
1052 IplImage* CvCapture_OpenNI2::retrieveIrImage()
1054 if (!streamFrames[CV_IR_STREAM].isValid())
1057 getGrayImageFromMetaData(streamFrames[CV_IR_STREAM], outputMaps[CV_CAP_OPENNI_IR_IMAGE].mat);
1059 return outputMaps[CV_CAP_OPENNI_IR_IMAGE].getIplImagePtr();
1062 IplImage* CvCapture_OpenNI2::retrieveFrame( int outputType )
1064 IplImage* image = 0;
1065 CV_Assert( outputType < outputMapsTypesCount && outputType >= 0);
1067 if( outputType == CV_CAP_OPENNI_DEPTH_MAP )
1069 image = retrieveDepthMap();
1071 else if( outputType == CV_CAP_OPENNI_POINT_CLOUD_MAP )
1073 image = retrievePointCloudMap();
1075 else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP )
1077 image = retrieveDisparityMap();
1079 else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP_32F )
1081 image = retrieveDisparityMap_32F();
1083 else if( outputType == CV_CAP_OPENNI_VALID_DEPTH_MASK )
1085 image = retrieveValidDepthMask();
1087 else if( outputType == CV_CAP_OPENNI_BGR_IMAGE )
1089 image = retrieveBGRImage();
1091 else if( outputType == CV_CAP_OPENNI_GRAY_IMAGE )
1093 image = retrieveGrayImage();
1095 else if( outputType == CV_CAP_OPENNI_IR_IMAGE )
1097 image = retrieveIrImage();
1103 CvCapture* cvCreateCameraCapture_OpenNI2( int index )
1105 CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( index );
1107 if( capture->isOpened() )
1114 CvCapture* cvCreateFileCapture_OpenNI2( const char* filename )
1116 CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( filename );
1118 if( capture->isOpened() )