Path: blob/master/modules/videoio/src/cap_openni2.cpp
16344 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/40#include "precomp.hpp"41#include "opencv2/core.hpp"42#include "opencv2/imgproc.hpp"4344#ifdef HAVE_OPENNI24546#include <queue>4748#ifndef i38649# define i386 050#endif51#ifndef __arm__52# define __arm__ 053#endif54#ifndef _ARC55# define _ARC 056#endif57#ifndef __APPLE__58# define __APPLE__ 059#endif6061#define CV_STREAM_TIMEOUT 20006263#define CV_DEPTH_STREAM 064#define CV_COLOR_STREAM 165#define CV_IR_STREAM 266#define CV_MAX_NUM_STREAMS 36768#include "OpenNI.h"69#include "PS1080.h"7071///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////7273static cv::Mutex initOpenNI2Mutex;7475struct OpenNI2Initializer76{77public:78static void init()79{80cv::AutoLock al(initOpenNI2Mutex);81static OpenNI2Initializer initializer;82}8384private:85OpenNI2Initializer()86{87// Initialize and configure the context.88openni::Status status = openni::OpenNI::initialize();89if (status != openni::STATUS_OK)90{91CV_Error(CV_StsError, std::string("Failed to initialize:") + openni::OpenNI::getExtendedError());92}93}9495~OpenNI2Initializer()96{97openni::OpenNI::shutdown();98}99};100101class CvCapture_OpenNI2 : public CvCapture102{103public:104enum { DEVICE_DEFAULT=0, DEVICE_MS_KINECT=0, DEVICE_ASUS_XTION=1, DEVICE_MAX=1 };105106static const int INVALID_PIXEL_VAL = 0;107static const int INVALID_COORDINATE_VAL = 0;108109static const int DEFAULT_MAX_BUFFER_SIZE = 2;110static const int DEFAULT_IS_CIRCLE_BUFFER = 0;111static const int DEFAULT_MAX_TIME_DURATION = 20;112113CvCapture_OpenNI2(int index = 0);114CvCapture_OpenNI2(const char * filename);115virtual ~CvCapture_OpenNI2();116117virtual double getProperty(int propIdx) const CV_OVERRIDE;118virtual bool setProperty(int probIdx, double propVal) CV_OVERRIDE;119virtual bool grabFrame() CV_OVERRIDE;120virtual IplImage* retrieveFrame(int outputType) CV_OVERRIDE;121122bool isOpened() const;123124protected:125struct OutputMap126{127public:128cv::Mat mat;129IplImage* getIplImagePtr();130private:131IplImage iplHeader;132};133134static const int outputMapsTypesCount = 8;135136static openni::VideoMode defaultStreamOutputMode(int stream);137138CvCapture_OpenNI2(int index, const char * filename);139140IplImage* retrieveDepthMap();141IplImage* retrievePointCloudMap();142IplImage* retrieveDisparityMap();143IplImage* retrieveDisparityMap_32F();144IplImage* retrieveValidDepthMask();145IplImage* retrieveBGRImage();146IplImage* retrieveGrayImage();147IplImage* retrieveIrImage();148149void toggleStream(int stream, bool toggle);150void readCamerasParams();151152double getDepthGeneratorProperty(int propIdx) const;153bool setDepthGeneratorProperty(int propIdx, double propVal);154double getImageGeneratorProperty(int propIdx) const;155bool setImageGeneratorProperty(int propIdx, double propVal);156double getIrGeneratorProperty(int propIdx) const;157bool setIrGeneratorProperty(int propIdx, double propVal);158double getCommonProperty(int propIdx) const;159bool setCommonProperty(int propIdx, double propVal);160161// OpenNI context162openni::Device device;163bool isContextOpened;164165// Data generators with its metadata166std::vector<openni::VideoStream> streams;167std::vector<openni::VideoFrameRef> streamFrames;168std::vector<cv::Mat> streamImages;169170int maxBufferSize, maxTimeDuration; // for approx sync171bool isCircleBuffer;172//cv::Ptr<ApproximateSyncGrabber> approxSyncGrabber;173174// Cameras settings:175// TODO find in OpenNI function to convert z->disparity and remove fields "baseline" and depthFocalLength_VGA176// Distance between IR projector and IR camera (in meters)177double baseline;178// Focal length for the IR camera in VGA resolution (in pixels)179int depthFocalLength_VGA;180181// The value for shadow (occluded pixels)182int shadowValue;183// The value for pixels without a valid disparity measurement184int noSampleValue;185186std::vector<OutputMap> outputMaps;187};188189IplImage* CvCapture_OpenNI2::OutputMap::getIplImagePtr()190{191if( mat.empty() )192return 0;193194iplHeader = cvIplImage(mat);195return &iplHeader;196}197198bool CvCapture_OpenNI2::isOpened() const199{200return isContextOpened;201}202203openni::VideoMode CvCapture_OpenNI2::defaultStreamOutputMode(int stream)204{205openni::VideoMode mode;206mode.setResolution(640, 480);207mode.setFps(30);208switch (stream)209{210case CV_DEPTH_STREAM:211mode.setPixelFormat(openni::PIXEL_FORMAT_DEPTH_1_MM);212break;213case CV_COLOR_STREAM:214mode.setPixelFormat(openni::PIXEL_FORMAT_RGB888);215break;216case CV_IR_STREAM:217mode.setPixelFormat(openni::PIXEL_FORMAT_GRAY16);218break;219}220return mode;221}222223224CvCapture_OpenNI2::CvCapture_OpenNI2(int index) :225CvCapture_OpenNI2(index, nullptr)226{ }227228CvCapture_OpenNI2::CvCapture_OpenNI2(const char * filename) :229CvCapture_OpenNI2(-1, filename)230{ }231232CvCapture_OpenNI2::CvCapture_OpenNI2(int index, const char * filename) :233device(),234isContextOpened(false),235streams(CV_MAX_NUM_STREAMS),236streamFrames(CV_MAX_NUM_STREAMS),237streamImages(CV_MAX_NUM_STREAMS),238maxBufferSize(DEFAULT_MAX_BUFFER_SIZE),239maxTimeDuration(DEFAULT_MAX_TIME_DURATION),240isCircleBuffer(DEFAULT_IS_CIRCLE_BUFFER),241baseline(0),242depthFocalLength_VGA(0),243shadowValue(0),244noSampleValue(0),245outputMaps(outputMapsTypesCount)246{247// Initialize and configure the context.248OpenNI2Initializer::init();249250const char* deviceURI = openni::ANY_DEVICE;251bool needColor = true;252bool needIR = true;253if (index >= 0)254{255int deviceType = DEVICE_DEFAULT;256if (index >= 10)257{258deviceType = index / 10;259index %= 10;260}261// Asus XTION and Occipital Structure Sensor do not have an image generator262needColor = (deviceType != DEVICE_ASUS_XTION);263264// find appropriate device URI265openni::Array<openni::DeviceInfo> ldevs;266if (index > 0)267{268openni::OpenNI::enumerateDevices(&ldevs);269if (index < ldevs.getSize())270deviceURI = ldevs[index].getUri();271else272{273CV_Error(CV_StsError, "OpenCVKinect2: Device index exceeds the number of available OpenNI devices");274}275}276}277else278{279deviceURI = filename;280}281282openni::Status status;283status = device.open(deviceURI);284if (status != openni::STATUS_OK)285{286CV_Error(CV_StsError, std::string("OpenCVKinect2: Failed to open device: ") + openni::OpenNI::getExtendedError());287}288289toggleStream(CV_DEPTH_STREAM, true);290if (needColor)291toggleStream(CV_COLOR_STREAM, true);292if (needIR)293toggleStream(CV_IR_STREAM, true);294295setProperty(CV_CAP_PROP_OPENNI_REGISTRATION, 1.0);296297// default for Kinect2 camera298setProperty(CV_CAP_PROP_OPENNI2_MIRROR, 0.0);299300isContextOpened = true;301}302303CvCapture_OpenNI2::~CvCapture_OpenNI2()304{305for (size_t i = 0; i < streams.size(); ++i)306{307streamFrames[i].release();308streams[i].stop();309streams[i].destroy();310}311device.close();312}313314void CvCapture_OpenNI2::toggleStream(int stream, bool toggle)315{316openni::Status status;317318// for logging319static const std::string stream_names[CV_MAX_NUM_STREAMS] = {320"depth",321"color",322"IR"323};324325static const openni::SensorType stream_sensor_types[CV_MAX_NUM_STREAMS] = {326openni::SENSOR_DEPTH,327openni::SENSOR_COLOR,328openni::SENSOR_IR329};330331if (toggle) // want to open stream332{333// already opened334if (streams[stream].isValid())335return;336337// open stream338status = streams[stream].create(device, stream_sensor_types[stream]);339if (status == openni::STATUS_OK)340{341// try to set up default stream mode (if available)342const openni::Array<openni::VideoMode>& vm = streams[stream].getSensorInfo().getSupportedVideoModes();343openni::VideoMode dm = defaultStreamOutputMode(stream);344for (int i = 0; i < vm.getSize(); i++)345{346if (vm[i].getPixelFormat() == dm.getPixelFormat() &&347vm[i].getResolutionX() == dm.getResolutionX() &&348vm[i].getResolutionY() == dm.getResolutionY() &&349vm[i].getFps() == dm.getFps())350{351status = streams[stream].setVideoMode(defaultStreamOutputMode(stream));352if (status != openni::STATUS_OK)353{354streams[stream].destroy();355CV_Error(CV_StsError, std::string("OpenCVKinect2 : Couldn't set ") +356stream_names[stream] + std::string(" stream output mode: ") +357std::string(openni::OpenNI::getExtendedError()));358}359}360}361362// start stream363status = streams[stream].start();364if (status != openni::STATUS_OK)365{366streams[stream].destroy();367CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start ") +368stream_names[stream] + std::string(" stream: ") +369std::string(openni::OpenNI::getExtendedError()));370}371}372else373{374CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find ") +375stream_names[stream] + " stream: " +376std::string(openni::OpenNI::getExtendedError()));377}378}379else if (streams[stream].isValid()) // want to close stream380{381//FIX for libfreenect2382//which stops the whole device when stopping only one stream383384//streams[stream].stop();385//streams[stream].destroy();386}387}388389390void CvCapture_OpenNI2::readCamerasParams()391{392double pixelSize = 0;393if (streams[CV_DEPTH_STREAM].getProperty<double>(XN_STREAM_PROPERTY_ZERO_PLANE_PIXEL_SIZE, &pixelSize) != openni::STATUS_OK)394{395CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read pixel size!" +396std::string(openni::OpenNI::getExtendedError()));397}398399// pixel size @ VGA = pixel size @ SXGA x 2400pixelSize *= 2.0; // in mm401402// focal length of IR camera in pixels for VGA resolution403unsigned long long zeroPlaneDistance; // in mm404if (streams[CV_DEPTH_STREAM].getProperty(XN_STREAM_PROPERTY_ZERO_PLANE_DISTANCE, &zeroPlaneDistance) != openni::STATUS_OK)405{406CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read virtual plane distance!" +407std::string(openni::OpenNI::getExtendedError()));408}409410if (streams[CV_DEPTH_STREAM].getProperty<double>(XN_STREAM_PROPERTY_EMITTER_DCMOS_DISTANCE, &baseline) != openni::STATUS_OK)411{412CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read base line!" +413std::string(openni::OpenNI::getExtendedError()));414}415416// baseline from cm -> mm417baseline *= 10;418419// focal length from mm -> pixels (valid for 640x480)420depthFocalLength_VGA = (int)((double)zeroPlaneDistance / (double)pixelSize);421}422423double CvCapture_OpenNI2::getProperty( int propIdx ) const424{425double propValue = 0;426427if( isOpened() )428{429int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK;430431if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR )432{433propValue = getImageGeneratorProperty( purePropIdx );434}435else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR )436{437propValue = getDepthGeneratorProperty( purePropIdx );438}439else if ((propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IR_GENERATOR)440{441propValue = getIrGeneratorProperty(purePropIdx);442}443else444{445propValue = getCommonProperty( purePropIdx );446}447}448449return propValue;450}451452bool CvCapture_OpenNI2::setProperty( int propIdx, double propValue )453{454bool isSet = false;455if( isOpened() )456{457int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK;458459if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR )460{461isSet = setImageGeneratorProperty( purePropIdx, propValue );462}463else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR )464{465isSet = setDepthGeneratorProperty( purePropIdx, propValue );466}467else if ((propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IR_GENERATOR)468{469isSet = setIrGeneratorProperty(purePropIdx, propValue);470}471else472{473isSet = setCommonProperty( purePropIdx, propValue );474}475}476477return isSet;478}479480double CvCapture_OpenNI2::getCommonProperty( int propIdx ) const481{482double propValue = 0;483484switch( propIdx )485{486case CV_CAP_PROP_FRAME_WIDTH :487case CV_CAP_PROP_FRAME_HEIGHT :488case CV_CAP_PROP_FPS :489case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH :490case CV_CAP_PROP_OPENNI_BASELINE :491case CV_CAP_PROP_OPENNI_FOCAL_LENGTH :492case CV_CAP_PROP_OPENNI_REGISTRATION :493propValue = getDepthGeneratorProperty( propIdx );494break;495case CV_CAP_PROP_OPENNI2_SYNC :496propValue = const_cast<CvCapture_OpenNI2 *>(this)->device.getDepthColorSyncEnabled();497break;498case CV_CAP_PROP_OPENNI2_MIRROR:499{500bool isMirroring = false;501for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)502isMirroring |= streams[i].getMirroringEnabled();503propValue = isMirroring ? 1.0 : 0.0;504break;505}506default :507CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for getting.", propIdx) );508}509510return propValue;511}512513bool CvCapture_OpenNI2::setCommonProperty( int propIdx, double propValue )514{515bool isSet = false;516517switch( propIdx )518{519case CV_CAP_PROP_OPENNI2_MIRROR:520{521bool mirror = propValue > 0.0 ? true : false;522for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)523{524if (streams[i].isValid())525isSet |= streams[i].setMirroringEnabled(mirror) == openni::STATUS_OK;526}527}528break;529// There is a set of properties that correspond to depth generator by default530// (is they are pass without particular generator flag).531case CV_CAP_PROP_OPENNI_REGISTRATION:532isSet = setDepthGeneratorProperty(propIdx, propValue);533break;534case CV_CAP_PROP_OPENNI2_SYNC:535isSet = device.setDepthColorSyncEnabled(propValue > 0.0) == openni::STATUS_OK;536break;537538case CV_CAP_PROP_FRAME_WIDTH:539case CV_CAP_PROP_FRAME_HEIGHT:540case CV_CAP_PROP_AUTOFOCUS:541isSet = false;542break;543544default:545CV_Error(CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for setting.", propIdx));546}547548return isSet;549}550551double CvCapture_OpenNI2::getDepthGeneratorProperty( int propIdx ) const552{553double propValue = 0;554if( !streams[CV_DEPTH_STREAM].isValid() )555return propValue;556557openni::VideoMode mode;558559switch( propIdx )560{561case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:562propValue = streams[CV_DEPTH_STREAM].isValid();563break;564case CV_CAP_PROP_FRAME_WIDTH :565propValue = streams[CV_DEPTH_STREAM].getVideoMode().getResolutionX();566break;567case CV_CAP_PROP_FRAME_HEIGHT :568propValue = streams[CV_DEPTH_STREAM].getVideoMode().getResolutionY();569break;570case CV_CAP_PROP_FPS :571mode = streams[CV_DEPTH_STREAM].getVideoMode();572propValue = mode.getFps();573break;574case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH :575propValue = streams[CV_DEPTH_STREAM].getMaxPixelValue();576break;577case CV_CAP_PROP_OPENNI_BASELINE :578if(baseline <= 0)579const_cast<CvCapture_OpenNI2*>(this)->readCamerasParams();580propValue = baseline;581break;582case CV_CAP_PROP_OPENNI_FOCAL_LENGTH :583if(depthFocalLength_VGA <= 0)584const_cast<CvCapture_OpenNI2*>(this)->readCamerasParams();585propValue = (double)depthFocalLength_VGA;586break;587case CV_CAP_PROP_OPENNI_REGISTRATION :588propValue = device.getImageRegistrationMode();589break;590case CV_CAP_PROP_POS_MSEC :591propValue = (double)streamFrames[CV_DEPTH_STREAM].getTimestamp();592break;593case CV_CAP_PROP_POS_FRAMES :594propValue = streamFrames[CV_DEPTH_STREAM].getFrameIndex();595break;596default :597CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for getting.", propIdx) );598}599600return propValue;601}602603bool CvCapture_OpenNI2::setDepthGeneratorProperty( int propIdx, double propValue )604{605bool isSet = false;606607switch( propIdx )608{609case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:610if (isContextOpened)611{612toggleStream(CV_DEPTH_STREAM, propValue > 0.0);613isSet = true;614}615break;616case CV_CAP_PROP_OPENNI_REGISTRATION:617{618CV_Assert(streams[CV_DEPTH_STREAM].isValid());619if( propValue != 0.0 ) // "on"620{621// if there isn't image generator (i.e. ASUS XtionPro doesn't have it)622// then the property isn't available623if ( streams[CV_COLOR_STREAM].isValid() )624{625openni::ImageRegistrationMode mode = propValue != 0.0 ? openni::IMAGE_REGISTRATION_DEPTH_TO_COLOR : openni::IMAGE_REGISTRATION_OFF;626if( device.getImageRegistrationMode() != mode )627{628if (device.isImageRegistrationModeSupported(mode))629{630openni::Status status = device.setImageRegistrationMode(mode);631if( status != openni::STATUS_OK )632CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setDepthGeneratorProperty: ") +633std::string(openni::OpenNI::getExtendedError()));634else635isSet = true;636}637else638CV_Error(CV_StsError, "CvCapture_OpenNI2::setDepthGeneratorProperty: Unsupported viewpoint.");639}640else641isSet = true;642}643}644else // "off"645{646openni::Status status = device.setImageRegistrationMode(openni::IMAGE_REGISTRATION_OFF);647if( status != openni::STATUS_OK )648CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setDepthGeneratorProperty: ") +649std::string(openni::OpenNI::getExtendedError()));650else651isSet = true;652}653}654break;655default:656CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for setting.", propIdx) );657}658659return isSet;660}661662double CvCapture_OpenNI2::getImageGeneratorProperty( int propIdx ) const663{664double propValue = 0.;665if( !streams[CV_COLOR_STREAM].isValid() )666return propValue;667668openni::VideoMode mode;669switch( propIdx )670{671case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:672propValue = streams[CV_COLOR_STREAM].isValid();673break;674case CV_CAP_PROP_FRAME_WIDTH :675propValue = streams[CV_COLOR_STREAM].getVideoMode().getResolutionX();676break;677case CV_CAP_PROP_FRAME_HEIGHT :678propValue = streams[CV_COLOR_STREAM].getVideoMode().getResolutionY();679break;680case CV_CAP_PROP_FPS :681propValue = streams[CV_COLOR_STREAM].getVideoMode().getFps();682break;683case CV_CAP_PROP_POS_MSEC :684propValue = (double)streamFrames[CV_COLOR_STREAM].getTimestamp();685break;686case CV_CAP_PROP_POS_FRAMES :687propValue = (double)streamFrames[CV_COLOR_STREAM].getFrameIndex();688break;689default :690CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.", propIdx) );691}692693return propValue;694}695696bool CvCapture_OpenNI2::setImageGeneratorProperty(int propIdx, double propValue)697{698bool isSet = false;699700switch( propIdx )701{702case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:703if (isContextOpened)704{705toggleStream(CV_COLOR_STREAM, propValue > 0.0);706isSet = true;707}708break;709case CV_CAP_PROP_OPENNI_OUTPUT_MODE :710{711if (!streams[CV_COLOR_STREAM].isValid())712return isSet;713openni::VideoMode mode = streams[CV_COLOR_STREAM].getVideoMode();714715switch( cvRound(propValue) )716{717case CV_CAP_OPENNI_VGA_30HZ :718mode.setResolution(640,480);719mode.setFps(30);720break;721case CV_CAP_OPENNI_SXGA_15HZ :722mode.setResolution(1280, 960);723mode.setFps(15);724break;725case CV_CAP_OPENNI_SXGA_30HZ :726mode.setResolution(1280, 960);727mode.setFps(30);728break;729case CV_CAP_OPENNI_QVGA_30HZ :730mode.setResolution(320, 240);731mode.setFps(30);732break;733case CV_CAP_OPENNI_QVGA_60HZ :734mode.setResolution(320, 240);735mode.setFps(60);736break;737default :738CV_Error( CV_StsBadArg, "Unsupported image generator output mode.");739}740741openni::Status status = streams[CV_COLOR_STREAM].setVideoMode( mode );742if( status != openni::STATUS_OK )743CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setImageGeneratorProperty: ") +744std::string(openni::OpenNI::getExtendedError()));745else746isSet = true;747break;748}749default:750CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.", propIdx) );751}752753return isSet;754}755756double CvCapture_OpenNI2::getIrGeneratorProperty(int propIdx) const757{758double propValue = 0.;759if (!streams[CV_IR_STREAM].isValid())760return propValue;761762openni::VideoMode mode;763switch (propIdx)764{765case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:766propValue = streams[CV_IR_STREAM].isValid();767break;768case CV_CAP_PROP_FRAME_WIDTH:769propValue = streams[CV_IR_STREAM].getVideoMode().getResolutionX();770break;771case CV_CAP_PROP_FRAME_HEIGHT:772propValue = streams[CV_IR_STREAM].getVideoMode().getResolutionY();773break;774case CV_CAP_PROP_FPS:775propValue = streams[CV_IR_STREAM].getVideoMode().getFps();776break;777case CV_CAP_PROP_POS_MSEC:778propValue = (double)streamFrames[CV_IR_STREAM].getTimestamp();779break;780case CV_CAP_PROP_POS_FRAMES:781propValue = (double)streamFrames[CV_IR_STREAM].getFrameIndex();782break;783default:784CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.", propIdx));785}786787return propValue;788}789790bool CvCapture_OpenNI2::setIrGeneratorProperty(int propIdx, double propValue)791{792bool isSet = false;793794switch (propIdx)795{796case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:797if (isContextOpened)798{799toggleStream(CV_IR_STREAM, propValue > 0.0);800isSet = true;801}802break;803case CV_CAP_PROP_OPENNI_OUTPUT_MODE:804{805if (!streams[CV_IR_STREAM].isValid())806return isSet;807openni::VideoMode mode = streams[CV_IR_STREAM].getVideoMode();808809switch (cvRound(propValue))810{811case CV_CAP_OPENNI_VGA_30HZ:812mode.setResolution(640, 480);813mode.setFps(30);814break;815case CV_CAP_OPENNI_SXGA_15HZ:816mode.setResolution(1280, 960);817mode.setFps(15);818break;819case CV_CAP_OPENNI_SXGA_30HZ:820mode.setResolution(1280, 960);821mode.setFps(30);822break;823case CV_CAP_OPENNI_QVGA_30HZ:824mode.setResolution(320, 240);825mode.setFps(30);826break;827case CV_CAP_OPENNI_QVGA_60HZ:828mode.setResolution(320, 240);829mode.setFps(60);830break;831default:832CV_Error(CV_StsBadArg, "Unsupported image generator output mode.");833}834835openni::Status status = streams[CV_IR_STREAM].setVideoMode(mode);836if (status != openni::STATUS_OK)837CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setImageGeneratorProperty: ") +838std::string(openni::OpenNI::getExtendedError()));839else840isSet = true;841break;842}843default:844CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.", propIdx));845}846847return isSet;848}849850bool CvCapture_OpenNI2::grabFrame()851{852if( !isOpened() )853return false;854855bool isGrabbed = false;856857int numActiveStreams = 0;858openni::VideoStream* streamPtrs[CV_MAX_NUM_STREAMS];859for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i) {860streamPtrs[numActiveStreams++] = &streams[i];861}862863int currentStream;864openni::Status status = openni::OpenNI::waitForAnyStream(streamPtrs, numActiveStreams, ¤tStream, CV_STREAM_TIMEOUT);865if( status != openni::STATUS_OK )866return false;867868for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)869{870if (streams[i].isValid())871streams[i].readFrame(&streamFrames[i]);872}873isGrabbed = true;874875return isGrabbed;876}877878inline void getDepthMapFromMetaData(const openni::VideoFrameRef& depthMetaData, cv::Mat& depthMap, int noSampleValue, int shadowValue)879{880depthMap.create(depthMetaData.getHeight(), depthMetaData.getWidth(), CV_16UC1);881depthMap.data = (uchar*)depthMetaData.getData();882883cv::Mat badMask = (depthMap == (double)noSampleValue) | (depthMap == (double)shadowValue) | (depthMap == 0);884885// mask the pixels with invalid depth886depthMap.setTo( cv::Scalar::all( CvCapture_OpenNI2::INVALID_PIXEL_VAL ), badMask );887}888889IplImage* CvCapture_OpenNI2::retrieveDepthMap()890{891if( !streamFrames[CV_DEPTH_STREAM].isValid() )892return 0;893894getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue );895896return outputMaps[CV_CAP_OPENNI_DEPTH_MAP].getIplImagePtr();897}898899IplImage* CvCapture_OpenNI2::retrievePointCloudMap()900{901if( !streamFrames[CV_DEPTH_STREAM].isValid() )902return 0;903904cv::Mat depthImg;905getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], depthImg, noSampleValue, shadowValue);906907const int badPoint = INVALID_PIXEL_VAL;908const float badCoord = INVALID_COORDINATE_VAL;909int cols = streamFrames[CV_DEPTH_STREAM].getWidth(), rows = streamFrames[CV_DEPTH_STREAM].getHeight();910cv::Mat pointCloud_XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) );911912float worldX, worldY, worldZ;913for( int y = 0; y < rows; y++ )914{915for (int x = 0; x < cols; x++)916{917openni::CoordinateConverter::convertDepthToWorld(streams[CV_DEPTH_STREAM], x, y, depthImg.at<unsigned short>(y, x), &worldX, &worldY, &worldZ);918919if (depthImg.at<unsigned short>(y, x) == badPoint) // not valid920pointCloud_XYZ.at<cv::Point3f>(y, x) = cv::Point3f(badCoord, badCoord, badCoord);921else922{923pointCloud_XYZ.at<cv::Point3f>(y, x) = cv::Point3f(worldX*0.001f, worldY*0.001f, worldZ*0.001f); // from mm to meters924}925}926}927928outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].mat = pointCloud_XYZ;929930return outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].getIplImagePtr();931}932933static void computeDisparity_32F( const openni::VideoFrameRef& depthMetaData, cv::Mat& disp, double baseline, int F, int noSampleValue, int shadowValue)934{935cv::Mat depth;936getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue );937CV_Assert( depth.type() == CV_16UC1 );938939// disparity = baseline * F / z;940941float mult = (float)(baseline /*mm*/ * F /*pixels*/);942943disp.create( depth.size(), CV_32FC1);944disp = cv::Scalar::all( CvCapture_OpenNI2::INVALID_PIXEL_VAL );945for( int y = 0; y < disp.rows; y++ )946{947for( int x = 0; x < disp.cols; x++ )948{949unsigned short curDepth = depth.at<unsigned short>(y,x);950if( curDepth != CvCapture_OpenNI2::INVALID_PIXEL_VAL )951disp.at<float>(y,x) = mult / curDepth;952}953}954}955956IplImage* CvCapture_OpenNI2::retrieveDisparityMap()957{958if (!streamFrames[CV_DEPTH_STREAM].isValid())959return 0;960961readCamerasParams();962963cv::Mat disp32;964computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);965966disp32.convertTo(outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1);967968return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].getIplImagePtr();969}970971IplImage* CvCapture_OpenNI2::retrieveDisparityMap_32F()972{973if (!streamFrames[CV_DEPTH_STREAM].isValid())974return 0;975976readCamerasParams();977978computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);979980return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].getIplImagePtr();981}982983IplImage* CvCapture_OpenNI2::retrieveValidDepthMask()984{985if (!streamFrames[CV_DEPTH_STREAM].isValid())986return 0;987988cv::Mat d;989getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], d, noSampleValue, shadowValue);990991outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].mat = d != CvCapture_OpenNI2::INVALID_PIXEL_VAL;992993return outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].getIplImagePtr();994}995996inline void getBGRImageFromMetaData( const openni::VideoFrameRef& imageMetaData, cv::Mat& bgrImage )997{998cv::Mat bufferImage;999if( imageMetaData.getVideoMode().getPixelFormat() != openni::PIXEL_FORMAT_RGB888 )1000CV_Error( CV_StsUnsupportedFormat, "Unsupported format of grabbed image." );10011002bgrImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3);1003bufferImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3);1004bufferImage.data = (uchar*)imageMetaData.getData();10051006cv::cvtColor(bufferImage, bgrImage, cv::COLOR_RGB2BGR);1007}10081009inline void getGrayImageFromMetaData(const openni::VideoFrameRef& imageMetaData, cv::Mat& grayImage)1010{1011if (imageMetaData.getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_GRAY8)1012{1013grayImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC1);1014grayImage.data = (uchar*)imageMetaData.getData();1015}1016else if (imageMetaData.getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_GRAY16)1017{1018grayImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_16UC1);1019grayImage.data = (uchar*)imageMetaData.getData();1020}1021else1022{1023CV_Error(CV_StsUnsupportedFormat, "Unsupported format of grabbed image.");1024}1025}10261027IplImage* CvCapture_OpenNI2::retrieveBGRImage()1028{1029if( !streamFrames[CV_COLOR_STREAM].isValid() )1030return 0;10311032getBGRImageFromMetaData(streamFrames[CV_COLOR_STREAM], outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat );10331034return outputMaps[CV_CAP_OPENNI_BGR_IMAGE].getIplImagePtr();1035}10361037IplImage* CvCapture_OpenNI2::retrieveGrayImage()1038{1039if (!streamFrames[CV_COLOR_STREAM].isValid())1040return 0;10411042CV_Assert(streamFrames[CV_COLOR_STREAM].getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_RGB888); // RGB10431044cv::Mat rgbImage;1045getBGRImageFromMetaData(streamFrames[CV_COLOR_STREAM], rgbImage);1046cv::cvtColor( rgbImage, outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].mat, CV_BGR2GRAY );10471048return outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].getIplImagePtr();1049}10501051IplImage* CvCapture_OpenNI2::retrieveIrImage()1052{1053if (!streamFrames[CV_IR_STREAM].isValid())1054return 0;10551056getGrayImageFromMetaData(streamFrames[CV_IR_STREAM], outputMaps[CV_CAP_OPENNI_IR_IMAGE].mat);10571058return outputMaps[CV_CAP_OPENNI_IR_IMAGE].getIplImagePtr();1059}10601061IplImage* CvCapture_OpenNI2::retrieveFrame( int outputType )1062{1063IplImage* image = 0;1064CV_Assert( outputType < outputMapsTypesCount && outputType >= 0);10651066if( outputType == CV_CAP_OPENNI_DEPTH_MAP )1067{1068image = retrieveDepthMap();1069}1070else if( outputType == CV_CAP_OPENNI_POINT_CLOUD_MAP )1071{1072image = retrievePointCloudMap();1073}1074else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP )1075{1076image = retrieveDisparityMap();1077}1078else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP_32F )1079{1080image = retrieveDisparityMap_32F();1081}1082else if( outputType == CV_CAP_OPENNI_VALID_DEPTH_MASK )1083{1084image = retrieveValidDepthMask();1085}1086else if( outputType == CV_CAP_OPENNI_BGR_IMAGE )1087{1088image = retrieveBGRImage();1089}1090else if( outputType == CV_CAP_OPENNI_GRAY_IMAGE )1091{1092image = retrieveGrayImage();1093}1094else if( outputType == CV_CAP_OPENNI_IR_IMAGE )1095{1096image = retrieveIrImage();1097}10981099return image;1100}11011102CvCapture* cvCreateCameraCapture_OpenNI2( int index )1103{1104CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( index );11051106if( capture->isOpened() )1107return capture;11081109delete capture;1110return 0;1111}11121113CvCapture* cvCreateFileCapture_OpenNI2( const char* filename )1114{1115CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( filename );11161117if( capture->isOpened() )1118return capture;11191120delete capture;1121return 0;1122}11231124#endif112511261127