mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1125 lines
36 KiB
1125 lines
36 KiB
/*M/////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
|
// |
|
// By downloading, copying, installing or using the software you agree to this license. |
|
// If you do not agree to this license, do not download, install, |
|
// copy or use the software. |
|
// |
|
// |
|
// Intel License Agreement |
|
// For Open Source Computer Vision Library |
|
// |
|
// Copyright (C) 2000, Intel Corporation, all rights reserved. |
|
// Third party copyrights are property of their respective owners. |
|
// |
|
// Redistribution and use in source and binary forms, with or without modification, |
|
// are permitted provided that the following conditions are met: |
|
// |
|
// * Redistribution's of source code must retain the above copyright notice, |
|
// this list of conditions and the following disclaimer. |
|
// |
|
// * Redistribution's in binary form must reproduce the above copyright notice, |
|
// this list of conditions and the following disclaimer in the documentation |
|
// and/or other materials provided with the distribution. |
|
// |
|
// * The name of Intel Corporation may not be used to endorse or promote products |
|
// derived from this software without specific prior written permission. |
|
// |
|
// This software is provided by the copyright holders and contributors "as is" and |
|
// any express or implied warranties, including, but not limited to, the implied |
|
// warranties of merchantability and fitness for a particular purpose are disclaimed. |
|
// In no event shall the Intel Corporation or contributors be liable for any direct, |
|
// indirect, incidental, special, exemplary, or consequential damages |
|
// (including, but not limited to, procurement of substitute goods or services; |
|
// loss of use, data, or profits; or business interruption) however caused |
|
// and on any theory of liability, whether in contract, strict liability, |
|
// or tort (including negligence or otherwise) arising in any way out of |
|
// the use of this software, even if advised of the possibility of such damage. |
|
// |
|
//M*/ |
|
#include "precomp.hpp" |
|
#include "opencv2/core.hpp" |
|
#include "opencv2/imgproc.hpp" |
|
|
|
#ifdef HAVE_OPENNI2 |
|
|
|
#include <queue> |
|
|
|
#ifndef i386 |
|
# define i386 0 |
|
#endif |
|
#ifndef __arm__ |
|
# define __arm__ 0 |
|
#endif |
|
#ifndef _ARC |
|
# define _ARC 0 |
|
#endif |
|
#ifndef __APPLE__ |
|
# define __APPLE__ 0 |
|
#endif |
|
|
|
#define CV_STREAM_TIMEOUT 2000 |
|
|
|
#define CV_DEPTH_STREAM 0 |
|
#define CV_COLOR_STREAM 1 |
|
#define CV_IR_STREAM 2 |
|
#define CV_MAX_NUM_STREAMS 3 |
|
|
|
#include "OpenNI.h" |
|
#include "PS1080.h" |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
static cv::Mutex initOpenNI2Mutex; |
|
|
|
struct OpenNI2Initializer |
|
{ |
|
public: |
|
static void init() |
|
{ |
|
cv::AutoLock al(initOpenNI2Mutex); |
|
static OpenNI2Initializer initializer; |
|
} |
|
|
|
private: |
|
OpenNI2Initializer() |
|
{ |
|
// Initialize and configure the context. |
|
openni::Status status = openni::OpenNI::initialize(); |
|
if (status != openni::STATUS_OK) |
|
{ |
|
CV_Error(CV_StsError, std::string("Failed to initialize:") + openni::OpenNI::getExtendedError()); |
|
} |
|
} |
|
|
|
~OpenNI2Initializer() |
|
{ |
|
openni::OpenNI::shutdown(); |
|
} |
|
}; |
|
|
|
class CvCapture_OpenNI2 : public CvCapture |
|
{ |
|
public: |
|
enum { DEVICE_DEFAULT=0, DEVICE_MS_KINECT=0, DEVICE_ASUS_XTION=1, DEVICE_MAX=1 }; |
|
|
|
static const int INVALID_PIXEL_VAL = 0; |
|
static const int INVALID_COORDINATE_VAL = 0; |
|
|
|
static const int DEFAULT_MAX_BUFFER_SIZE = 2; |
|
static const int DEFAULT_IS_CIRCLE_BUFFER = 0; |
|
static const int DEFAULT_MAX_TIME_DURATION = 20; |
|
|
|
CvCapture_OpenNI2(int index = 0); |
|
CvCapture_OpenNI2(const char * filename); |
|
virtual ~CvCapture_OpenNI2(); |
|
|
|
virtual double getProperty(int propIdx) const CV_OVERRIDE; |
|
virtual bool setProperty(int probIdx, double propVal) CV_OVERRIDE; |
|
virtual bool grabFrame() CV_OVERRIDE; |
|
virtual IplImage* retrieveFrame(int outputType) CV_OVERRIDE; |
|
|
|
bool isOpened() const; |
|
|
|
protected: |
|
struct OutputMap |
|
{ |
|
public: |
|
cv::Mat mat; |
|
IplImage* getIplImagePtr(); |
|
private: |
|
IplImage iplHeader; |
|
}; |
|
|
|
static const int outputMapsTypesCount = 8; |
|
|
|
static openni::VideoMode defaultStreamOutputMode(int stream); |
|
|
|
CvCapture_OpenNI2(int index, const char * filename); |
|
|
|
IplImage* retrieveDepthMap(); |
|
IplImage* retrievePointCloudMap(); |
|
IplImage* retrieveDisparityMap(); |
|
IplImage* retrieveDisparityMap_32F(); |
|
IplImage* retrieveValidDepthMask(); |
|
IplImage* retrieveBGRImage(); |
|
IplImage* retrieveGrayImage(); |
|
IplImage* retrieveIrImage(); |
|
|
|
void toggleStream(int stream, bool toggle); |
|
void readCamerasParams(); |
|
|
|
double getDepthGeneratorProperty(int propIdx) const; |
|
bool setDepthGeneratorProperty(int propIdx, double propVal); |
|
double getImageGeneratorProperty(int propIdx) const; |
|
bool setImageGeneratorProperty(int propIdx, double propVal); |
|
double getIrGeneratorProperty(int propIdx) const; |
|
bool setIrGeneratorProperty(int propIdx, double propVal); |
|
double getCommonProperty(int propIdx) const; |
|
bool setCommonProperty(int propIdx, double propVal); |
|
|
|
// OpenNI context |
|
openni::Device device; |
|
bool isContextOpened; |
|
|
|
// Data generators with its metadata |
|
std::vector<openni::VideoStream> streams; |
|
std::vector<openni::VideoFrameRef> streamFrames; |
|
std::vector<cv::Mat> streamImages; |
|
|
|
int maxBufferSize, maxTimeDuration; // for approx sync |
|
bool isCircleBuffer; |
|
//cv::Ptr<ApproximateSyncGrabber> approxSyncGrabber; |
|
|
|
// Cameras settings: |
|
// TODO find in OpenNI function to convert z->disparity and remove fields "baseline" and depthFocalLength_VGA |
|
// Distance between IR projector and IR camera (in meters) |
|
double baseline; |
|
// Focal length for the IR camera in VGA resolution (in pixels) |
|
int depthFocalLength_VGA; |
|
|
|
// The value for shadow (occluded pixels) |
|
int shadowValue; |
|
// The value for pixels without a valid disparity measurement |
|
int noSampleValue; |
|
|
|
std::vector<OutputMap> outputMaps; |
|
}; |
|
|
|
IplImage* CvCapture_OpenNI2::OutputMap::getIplImagePtr() |
|
{ |
|
if( mat.empty() ) |
|
return 0; |
|
|
|
iplHeader = cvIplImage(mat); |
|
return &iplHeader; |
|
} |
|
|
|
bool CvCapture_OpenNI2::isOpened() const |
|
{ |
|
return isContextOpened; |
|
} |
|
|
|
openni::VideoMode CvCapture_OpenNI2::defaultStreamOutputMode(int stream) |
|
{ |
|
openni::VideoMode mode; |
|
mode.setResolution(640, 480); |
|
mode.setFps(30); |
|
switch (stream) |
|
{ |
|
case CV_DEPTH_STREAM: |
|
mode.setPixelFormat(openni::PIXEL_FORMAT_DEPTH_1_MM); |
|
break; |
|
case CV_COLOR_STREAM: |
|
mode.setPixelFormat(openni::PIXEL_FORMAT_RGB888); |
|
break; |
|
case CV_IR_STREAM: |
|
mode.setPixelFormat(openni::PIXEL_FORMAT_GRAY16); |
|
break; |
|
} |
|
return mode; |
|
} |
|
|
|
|
|
CvCapture_OpenNI2::CvCapture_OpenNI2(int index) : |
|
CvCapture_OpenNI2(index, nullptr) |
|
{ } |
|
|
|
CvCapture_OpenNI2::CvCapture_OpenNI2(const char * filename) : |
|
CvCapture_OpenNI2(-1, filename) |
|
{ } |
|
|
|
CvCapture_OpenNI2::CvCapture_OpenNI2(int index, const char * filename) : |
|
device(), |
|
isContextOpened(false), |
|
streams(CV_MAX_NUM_STREAMS), |
|
streamFrames(CV_MAX_NUM_STREAMS), |
|
streamImages(CV_MAX_NUM_STREAMS), |
|
maxBufferSize(DEFAULT_MAX_BUFFER_SIZE), |
|
maxTimeDuration(DEFAULT_MAX_TIME_DURATION), |
|
isCircleBuffer(DEFAULT_IS_CIRCLE_BUFFER), |
|
baseline(0), |
|
depthFocalLength_VGA(0), |
|
shadowValue(0), |
|
noSampleValue(0), |
|
outputMaps(outputMapsTypesCount) |
|
{ |
|
// Initialize and configure the context. |
|
OpenNI2Initializer::init(); |
|
|
|
const char* deviceURI = openni::ANY_DEVICE; |
|
bool needColor = true; |
|
bool needIR = true; |
|
if (index >= 0) |
|
{ |
|
int deviceType = DEVICE_DEFAULT; |
|
if (index >= 10) |
|
{ |
|
deviceType = index / 10; |
|
index %= 10; |
|
} |
|
// Asus XTION and Occipital Structure Sensor do not have an image generator |
|
needColor = (deviceType != DEVICE_ASUS_XTION); |
|
|
|
// find appropriate device URI |
|
openni::Array<openni::DeviceInfo> ldevs; |
|
if (index > 0) |
|
{ |
|
openni::OpenNI::enumerateDevices(&ldevs); |
|
if (index < ldevs.getSize()) |
|
deviceURI = ldevs[index].getUri(); |
|
else |
|
{ |
|
CV_Error(CV_StsError, "OpenCVKinect2: Device index exceeds the number of available OpenNI devices"); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
deviceURI = filename; |
|
} |
|
|
|
openni::Status status; |
|
status = device.open(deviceURI); |
|
if (status != openni::STATUS_OK) |
|
{ |
|
CV_Error(CV_StsError, std::string("OpenCVKinect2: Failed to open device: ") + openni::OpenNI::getExtendedError()); |
|
} |
|
|
|
toggleStream(CV_DEPTH_STREAM, true); |
|
if (needColor) |
|
toggleStream(CV_COLOR_STREAM, true); |
|
if (needIR) |
|
toggleStream(CV_IR_STREAM, true); |
|
|
|
setProperty(CV_CAP_PROP_OPENNI_REGISTRATION, 1.0); |
|
|
|
// default for Kinect2 camera |
|
setProperty(CV_CAP_PROP_OPENNI2_MIRROR, 0.0); |
|
|
|
isContextOpened = true; |
|
} |
|
|
|
CvCapture_OpenNI2::~CvCapture_OpenNI2() |
|
{ |
|
for (size_t i = 0; i < streams.size(); ++i) |
|
{ |
|
streamFrames[i].release(); |
|
streams[i].stop(); |
|
streams[i].destroy(); |
|
} |
|
device.close(); |
|
} |
|
|
|
void CvCapture_OpenNI2::toggleStream(int stream, bool toggle) |
|
{ |
|
openni::Status status; |
|
|
|
// for logging |
|
static const std::string stream_names[CV_MAX_NUM_STREAMS] = { |
|
"depth", |
|
"color", |
|
"IR" |
|
}; |
|
|
|
static const openni::SensorType stream_sensor_types[CV_MAX_NUM_STREAMS] = { |
|
openni::SENSOR_DEPTH, |
|
openni::SENSOR_COLOR, |
|
openni::SENSOR_IR |
|
}; |
|
|
|
if (toggle) // want to open stream |
|
{ |
|
// already opened |
|
if (streams[stream].isValid()) |
|
return; |
|
|
|
// open stream |
|
status = streams[stream].create(device, stream_sensor_types[stream]); |
|
if (status == openni::STATUS_OK) |
|
{ |
|
// try to set up default stream mode (if available) |
|
const openni::Array<openni::VideoMode>& vm = streams[stream].getSensorInfo().getSupportedVideoModes(); |
|
openni::VideoMode dm = defaultStreamOutputMode(stream); |
|
for (int i = 0; i < vm.getSize(); i++) |
|
{ |
|
if (vm[i].getPixelFormat() == dm.getPixelFormat() && |
|
vm[i].getResolutionX() == dm.getResolutionX() && |
|
vm[i].getResolutionY() == dm.getResolutionY() && |
|
vm[i].getFps() == dm.getFps()) |
|
{ |
|
status = streams[stream].setVideoMode(defaultStreamOutputMode(stream)); |
|
if (status != openni::STATUS_OK) |
|
{ |
|
streams[stream].destroy(); |
|
CV_Error(CV_StsError, std::string("OpenCVKinect2 : Couldn't set ") + |
|
stream_names[stream] + std::string(" stream output mode: ") + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
} |
|
} |
|
} |
|
|
|
// start stream |
|
status = streams[stream].start(); |
|
if (status != openni::STATUS_OK) |
|
{ |
|
streams[stream].destroy(); |
|
CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start ") + |
|
stream_names[stream] + std::string(" stream: ") + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
} |
|
} |
|
else |
|
{ |
|
CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find ") + |
|
stream_names[stream] + " stream: " + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
} |
|
} |
|
else if (streams[stream].isValid()) // want to close stream |
|
{ |
|
//FIX for libfreenect2 |
|
//which stops the whole device when stopping only one stream |
|
|
|
//streams[stream].stop(); |
|
//streams[stream].destroy(); |
|
} |
|
} |
|
|
|
|
|
void CvCapture_OpenNI2::readCamerasParams() |
|
{ |
|
double pixelSize = 0; |
|
if (streams[CV_DEPTH_STREAM].getProperty<double>(XN_STREAM_PROPERTY_ZERO_PLANE_PIXEL_SIZE, &pixelSize) != openni::STATUS_OK) |
|
{ |
|
CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read pixel size!" + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
} |
|
|
|
// pixel size @ VGA = pixel size @ SXGA x 2 |
|
pixelSize *= 2.0; // in mm |
|
|
|
// focal length of IR camera in pixels for VGA resolution |
|
unsigned long long zeroPlaneDistance; // in mm |
|
if (streams[CV_DEPTH_STREAM].getProperty(XN_STREAM_PROPERTY_ZERO_PLANE_DISTANCE, &zeroPlaneDistance) != openni::STATUS_OK) |
|
{ |
|
CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read virtual plane distance!" + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
} |
|
|
|
if (streams[CV_DEPTH_STREAM].getProperty<double>(XN_STREAM_PROPERTY_EMITTER_DCMOS_DISTANCE, &baseline) != openni::STATUS_OK) |
|
{ |
|
CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read base line!" + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
} |
|
|
|
// baseline from cm -> mm |
|
baseline *= 10; |
|
|
|
// focal length from mm -> pixels (valid for 640x480) |
|
depthFocalLength_VGA = (int)((double)zeroPlaneDistance / (double)pixelSize); |
|
} |
|
|
|
double CvCapture_OpenNI2::getProperty( int propIdx ) const |
|
{ |
|
double propValue = 0; |
|
|
|
if( isOpened() ) |
|
{ |
|
int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK; |
|
|
|
if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR ) |
|
{ |
|
propValue = getImageGeneratorProperty( purePropIdx ); |
|
} |
|
else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR ) |
|
{ |
|
propValue = getDepthGeneratorProperty( purePropIdx ); |
|
} |
|
else if ((propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IR_GENERATOR) |
|
{ |
|
propValue = getIrGeneratorProperty(purePropIdx); |
|
} |
|
else |
|
{ |
|
propValue = getCommonProperty( purePropIdx ); |
|
} |
|
} |
|
|
|
return propValue; |
|
} |
|
|
|
bool CvCapture_OpenNI2::setProperty( int propIdx, double propValue ) |
|
{ |
|
bool isSet = false; |
|
if( isOpened() ) |
|
{ |
|
int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK; |
|
|
|
if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR ) |
|
{ |
|
isSet = setImageGeneratorProperty( purePropIdx, propValue ); |
|
} |
|
else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR ) |
|
{ |
|
isSet = setDepthGeneratorProperty( purePropIdx, propValue ); |
|
} |
|
else if ((propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IR_GENERATOR) |
|
{ |
|
isSet = setIrGeneratorProperty(purePropIdx, propValue); |
|
} |
|
else |
|
{ |
|
isSet = setCommonProperty( purePropIdx, propValue ); |
|
} |
|
} |
|
|
|
return isSet; |
|
} |
|
|
|
double CvCapture_OpenNI2::getCommonProperty( int propIdx ) const |
|
{ |
|
double propValue = 0; |
|
|
|
switch( propIdx ) |
|
{ |
|
case CV_CAP_PROP_FRAME_WIDTH : |
|
case CV_CAP_PROP_FRAME_HEIGHT : |
|
case CV_CAP_PROP_FPS : |
|
case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH : |
|
case CV_CAP_PROP_OPENNI_BASELINE : |
|
case CV_CAP_PROP_OPENNI_FOCAL_LENGTH : |
|
case CV_CAP_PROP_OPENNI_REGISTRATION : |
|
propValue = getDepthGeneratorProperty( propIdx ); |
|
break; |
|
case CV_CAP_PROP_OPENNI2_SYNC : |
|
propValue = const_cast<CvCapture_OpenNI2 *>(this)->device.getDepthColorSyncEnabled(); |
|
break; |
|
case CV_CAP_PROP_OPENNI2_MIRROR: |
|
{ |
|
bool isMirroring = false; |
|
for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i) |
|
isMirroring |= streams[i].getMirroringEnabled(); |
|
propValue = isMirroring ? 1.0 : 0.0; |
|
break; |
|
} |
|
default : |
|
CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for getting.", propIdx) ); |
|
} |
|
|
|
return propValue; |
|
} |
|
|
|
bool CvCapture_OpenNI2::setCommonProperty( int propIdx, double propValue ) |
|
{ |
|
bool isSet = false; |
|
|
|
switch( propIdx ) |
|
{ |
|
case CV_CAP_PROP_OPENNI2_MIRROR: |
|
{ |
|
bool mirror = propValue > 0.0 ? true : false; |
|
for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i) |
|
{ |
|
if (streams[i].isValid()) |
|
isSet |= streams[i].setMirroringEnabled(mirror) == openni::STATUS_OK; |
|
} |
|
} |
|
break; |
|
// There is a set of properties that correspond to depth generator by default |
|
// (is they are pass without particular generator flag). |
|
case CV_CAP_PROP_OPENNI_REGISTRATION: |
|
isSet = setDepthGeneratorProperty(propIdx, propValue); |
|
break; |
|
case CV_CAP_PROP_OPENNI2_SYNC: |
|
isSet = device.setDepthColorSyncEnabled(propValue > 0.0) == openni::STATUS_OK; |
|
break; |
|
|
|
case CV_CAP_PROP_FRAME_WIDTH: |
|
case CV_CAP_PROP_FRAME_HEIGHT: |
|
case CV_CAP_PROP_AUTOFOCUS: |
|
isSet = false; |
|
break; |
|
|
|
default: |
|
CV_Error(CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for setting.", propIdx)); |
|
} |
|
|
|
return isSet; |
|
} |
|
|
|
double CvCapture_OpenNI2::getDepthGeneratorProperty( int propIdx ) const |
|
{ |
|
double propValue = 0; |
|
if( !streams[CV_DEPTH_STREAM].isValid() ) |
|
return propValue; |
|
|
|
openni::VideoMode mode; |
|
|
|
switch( propIdx ) |
|
{ |
|
case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT: |
|
propValue = streams[CV_DEPTH_STREAM].isValid(); |
|
break; |
|
case CV_CAP_PROP_FRAME_WIDTH : |
|
propValue = streams[CV_DEPTH_STREAM].getVideoMode().getResolutionX(); |
|
break; |
|
case CV_CAP_PROP_FRAME_HEIGHT : |
|
propValue = streams[CV_DEPTH_STREAM].getVideoMode().getResolutionY(); |
|
break; |
|
case CV_CAP_PROP_FPS : |
|
mode = streams[CV_DEPTH_STREAM].getVideoMode(); |
|
propValue = mode.getFps(); |
|
break; |
|
case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH : |
|
propValue = streams[CV_DEPTH_STREAM].getMaxPixelValue(); |
|
break; |
|
case CV_CAP_PROP_OPENNI_BASELINE : |
|
if(baseline <= 0) |
|
const_cast<CvCapture_OpenNI2*>(this)->readCamerasParams(); |
|
propValue = baseline; |
|
break; |
|
case CV_CAP_PROP_OPENNI_FOCAL_LENGTH : |
|
if(depthFocalLength_VGA <= 0) |
|
const_cast<CvCapture_OpenNI2*>(this)->readCamerasParams(); |
|
propValue = (double)depthFocalLength_VGA; |
|
break; |
|
case CV_CAP_PROP_OPENNI_REGISTRATION : |
|
propValue = device.getImageRegistrationMode(); |
|
break; |
|
case CV_CAP_PROP_POS_MSEC : |
|
propValue = (double)streamFrames[CV_DEPTH_STREAM].getTimestamp(); |
|
break; |
|
case CV_CAP_PROP_POS_FRAMES : |
|
propValue = streamFrames[CV_DEPTH_STREAM].getFrameIndex(); |
|
break; |
|
default : |
|
CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for getting.", propIdx) ); |
|
} |
|
|
|
return propValue; |
|
} |
|
|
|
bool CvCapture_OpenNI2::setDepthGeneratorProperty( int propIdx, double propValue ) |
|
{ |
|
bool isSet = false; |
|
|
|
switch( propIdx ) |
|
{ |
|
case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT: |
|
if (isContextOpened) |
|
{ |
|
toggleStream(CV_DEPTH_STREAM, propValue > 0.0); |
|
isSet = true; |
|
} |
|
break; |
|
case CV_CAP_PROP_OPENNI_REGISTRATION: |
|
{ |
|
CV_Assert(streams[CV_DEPTH_STREAM].isValid()); |
|
if( propValue != 0.0 ) // "on" |
|
{ |
|
// if there isn't image generator (i.e. ASUS XtionPro doesn't have it) |
|
// then the property isn't available |
|
if ( streams[CV_COLOR_STREAM].isValid() ) |
|
{ |
|
openni::ImageRegistrationMode mode = propValue != 0.0 ? openni::IMAGE_REGISTRATION_DEPTH_TO_COLOR : openni::IMAGE_REGISTRATION_OFF; |
|
if( device.getImageRegistrationMode() != mode ) |
|
{ |
|
if (device.isImageRegistrationModeSupported(mode)) |
|
{ |
|
openni::Status status = device.setImageRegistrationMode(mode); |
|
if( status != openni::STATUS_OK ) |
|
CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setDepthGeneratorProperty: ") + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
else |
|
isSet = true; |
|
} |
|
else |
|
CV_Error(CV_StsError, "CvCapture_OpenNI2::setDepthGeneratorProperty: Unsupported viewpoint."); |
|
} |
|
else |
|
isSet = true; |
|
} |
|
} |
|
else // "off" |
|
{ |
|
openni::Status status = device.setImageRegistrationMode(openni::IMAGE_REGISTRATION_OFF); |
|
if( status != openni::STATUS_OK ) |
|
CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setDepthGeneratorProperty: ") + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
else |
|
isSet = true; |
|
} |
|
} |
|
break; |
|
default: |
|
CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for setting.", propIdx) ); |
|
} |
|
|
|
return isSet; |
|
} |
|
|
|
double CvCapture_OpenNI2::getImageGeneratorProperty( int propIdx ) const |
|
{ |
|
double propValue = 0.; |
|
if( !streams[CV_COLOR_STREAM].isValid() ) |
|
return propValue; |
|
|
|
openni::VideoMode mode; |
|
switch( propIdx ) |
|
{ |
|
case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT: |
|
propValue = streams[CV_COLOR_STREAM].isValid(); |
|
break; |
|
case CV_CAP_PROP_FRAME_WIDTH : |
|
propValue = streams[CV_COLOR_STREAM].getVideoMode().getResolutionX(); |
|
break; |
|
case CV_CAP_PROP_FRAME_HEIGHT : |
|
propValue = streams[CV_COLOR_STREAM].getVideoMode().getResolutionY(); |
|
break; |
|
case CV_CAP_PROP_FPS : |
|
propValue = streams[CV_COLOR_STREAM].getVideoMode().getFps(); |
|
break; |
|
case CV_CAP_PROP_POS_MSEC : |
|
propValue = (double)streamFrames[CV_COLOR_STREAM].getTimestamp(); |
|
break; |
|
case CV_CAP_PROP_POS_FRAMES : |
|
propValue = (double)streamFrames[CV_COLOR_STREAM].getFrameIndex(); |
|
break; |
|
default : |
|
CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.", propIdx) ); |
|
} |
|
|
|
return propValue; |
|
} |
|
|
|
bool CvCapture_OpenNI2::setImageGeneratorProperty(int propIdx, double propValue) |
|
{ |
|
bool isSet = false; |
|
|
|
switch( propIdx ) |
|
{ |
|
case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT: |
|
if (isContextOpened) |
|
{ |
|
toggleStream(CV_COLOR_STREAM, propValue > 0.0); |
|
isSet = true; |
|
} |
|
break; |
|
case CV_CAP_PROP_OPENNI_OUTPUT_MODE : |
|
{ |
|
if (!streams[CV_COLOR_STREAM].isValid()) |
|
return isSet; |
|
openni::VideoMode mode = streams[CV_COLOR_STREAM].getVideoMode(); |
|
|
|
switch( cvRound(propValue) ) |
|
{ |
|
case CV_CAP_OPENNI_VGA_30HZ : |
|
mode.setResolution(640,480); |
|
mode.setFps(30); |
|
break; |
|
case CV_CAP_OPENNI_SXGA_15HZ : |
|
mode.setResolution(1280, 960); |
|
mode.setFps(15); |
|
break; |
|
case CV_CAP_OPENNI_SXGA_30HZ : |
|
mode.setResolution(1280, 960); |
|
mode.setFps(30); |
|
break; |
|
case CV_CAP_OPENNI_QVGA_30HZ : |
|
mode.setResolution(320, 240); |
|
mode.setFps(30); |
|
break; |
|
case CV_CAP_OPENNI_QVGA_60HZ : |
|
mode.setResolution(320, 240); |
|
mode.setFps(60); |
|
break; |
|
default : |
|
CV_Error( CV_StsBadArg, "Unsupported image generator output mode."); |
|
} |
|
|
|
openni::Status status = streams[CV_COLOR_STREAM].setVideoMode( mode ); |
|
if( status != openni::STATUS_OK ) |
|
CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setImageGeneratorProperty: ") + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
else |
|
isSet = true; |
|
break; |
|
} |
|
default: |
|
CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.", propIdx) ); |
|
} |
|
|
|
return isSet; |
|
} |
|
|
|
double CvCapture_OpenNI2::getIrGeneratorProperty(int propIdx) const |
|
{ |
|
double propValue = 0.; |
|
if (!streams[CV_IR_STREAM].isValid()) |
|
return propValue; |
|
|
|
openni::VideoMode mode; |
|
switch (propIdx) |
|
{ |
|
case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT: |
|
propValue = streams[CV_IR_STREAM].isValid(); |
|
break; |
|
case CV_CAP_PROP_FRAME_WIDTH: |
|
propValue = streams[CV_IR_STREAM].getVideoMode().getResolutionX(); |
|
break; |
|
case CV_CAP_PROP_FRAME_HEIGHT: |
|
propValue = streams[CV_IR_STREAM].getVideoMode().getResolutionY(); |
|
break; |
|
case CV_CAP_PROP_FPS: |
|
propValue = streams[CV_IR_STREAM].getVideoMode().getFps(); |
|
break; |
|
case CV_CAP_PROP_POS_MSEC: |
|
propValue = (double)streamFrames[CV_IR_STREAM].getTimestamp(); |
|
break; |
|
case CV_CAP_PROP_POS_FRAMES: |
|
propValue = (double)streamFrames[CV_IR_STREAM].getFrameIndex(); |
|
break; |
|
default: |
|
CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.", propIdx)); |
|
} |
|
|
|
return propValue; |
|
} |
|
|
|
bool CvCapture_OpenNI2::setIrGeneratorProperty(int propIdx, double propValue) |
|
{ |
|
bool isSet = false; |
|
|
|
switch (propIdx) |
|
{ |
|
case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT: |
|
if (isContextOpened) |
|
{ |
|
toggleStream(CV_IR_STREAM, propValue > 0.0); |
|
isSet = true; |
|
} |
|
break; |
|
case CV_CAP_PROP_OPENNI_OUTPUT_MODE: |
|
{ |
|
if (!streams[CV_IR_STREAM].isValid()) |
|
return isSet; |
|
openni::VideoMode mode = streams[CV_IR_STREAM].getVideoMode(); |
|
|
|
switch (cvRound(propValue)) |
|
{ |
|
case CV_CAP_OPENNI_VGA_30HZ: |
|
mode.setResolution(640, 480); |
|
mode.setFps(30); |
|
break; |
|
case CV_CAP_OPENNI_SXGA_15HZ: |
|
mode.setResolution(1280, 960); |
|
mode.setFps(15); |
|
break; |
|
case CV_CAP_OPENNI_SXGA_30HZ: |
|
mode.setResolution(1280, 960); |
|
mode.setFps(30); |
|
break; |
|
case CV_CAP_OPENNI_QVGA_30HZ: |
|
mode.setResolution(320, 240); |
|
mode.setFps(30); |
|
break; |
|
case CV_CAP_OPENNI_QVGA_60HZ: |
|
mode.setResolution(320, 240); |
|
mode.setFps(60); |
|
break; |
|
default: |
|
CV_Error(CV_StsBadArg, "Unsupported image generator output mode."); |
|
} |
|
|
|
openni::Status status = streams[CV_IR_STREAM].setVideoMode(mode); |
|
if (status != openni::STATUS_OK) |
|
CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setImageGeneratorProperty: ") + |
|
std::string(openni::OpenNI::getExtendedError())); |
|
else |
|
isSet = true; |
|
break; |
|
} |
|
default: |
|
CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.", propIdx)); |
|
} |
|
|
|
return isSet; |
|
} |
|
|
|
bool CvCapture_OpenNI2::grabFrame() |
|
{ |
|
if( !isOpened() ) |
|
return false; |
|
|
|
bool isGrabbed = false; |
|
|
|
int numActiveStreams = 0; |
|
openni::VideoStream* streamPtrs[CV_MAX_NUM_STREAMS]; |
|
for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i) { |
|
streamPtrs[numActiveStreams++] = &streams[i]; |
|
} |
|
|
|
int currentStream; |
|
openni::Status status = openni::OpenNI::waitForAnyStream(streamPtrs, numActiveStreams, ¤tStream, CV_STREAM_TIMEOUT); |
|
if( status != openni::STATUS_OK ) |
|
return false; |
|
|
|
for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i) |
|
{ |
|
if (streams[i].isValid()) |
|
streams[i].readFrame(&streamFrames[i]); |
|
} |
|
isGrabbed = true; |
|
|
|
return isGrabbed; |
|
} |
|
|
|
inline void getDepthMapFromMetaData(const openni::VideoFrameRef& depthMetaData, cv::Mat& depthMap, int noSampleValue, int shadowValue) |
|
{ |
|
depthMap.create(depthMetaData.getHeight(), depthMetaData.getWidth(), CV_16UC1); |
|
depthMap.data = (uchar*)depthMetaData.getData(); |
|
|
|
cv::Mat badMask = (depthMap == (double)noSampleValue) | (depthMap == (double)shadowValue) | (depthMap == 0); |
|
|
|
// mask the pixels with invalid depth |
|
depthMap.setTo( cv::Scalar::all( CvCapture_OpenNI2::INVALID_PIXEL_VAL ), badMask ); |
|
} |
|
|
|
IplImage* CvCapture_OpenNI2::retrieveDepthMap() |
|
{ |
|
if( !streamFrames[CV_DEPTH_STREAM].isValid() ) |
|
return 0; |
|
|
|
getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue ); |
|
|
|
return outputMaps[CV_CAP_OPENNI_DEPTH_MAP].getIplImagePtr(); |
|
} |
|
|
|
IplImage* CvCapture_OpenNI2::retrievePointCloudMap() |
|
{ |
|
if( !streamFrames[CV_DEPTH_STREAM].isValid() ) |
|
return 0; |
|
|
|
cv::Mat depthImg; |
|
getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], depthImg, noSampleValue, shadowValue); |
|
|
|
const int badPoint = INVALID_PIXEL_VAL; |
|
const float badCoord = INVALID_COORDINATE_VAL; |
|
int cols = streamFrames[CV_DEPTH_STREAM].getWidth(), rows = streamFrames[CV_DEPTH_STREAM].getHeight(); |
|
cv::Mat pointCloud_XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) ); |
|
|
|
float worldX, worldY, worldZ; |
|
for( int y = 0; y < rows; y++ ) |
|
{ |
|
for (int x = 0; x < cols; x++) |
|
{ |
|
openni::CoordinateConverter::convertDepthToWorld(streams[CV_DEPTH_STREAM], x, y, depthImg.at<unsigned short>(y, x), &worldX, &worldY, &worldZ); |
|
|
|
if (depthImg.at<unsigned short>(y, x) == badPoint) // not valid |
|
pointCloud_XYZ.at<cv::Point3f>(y, x) = cv::Point3f(badCoord, badCoord, badCoord); |
|
else |
|
{ |
|
pointCloud_XYZ.at<cv::Point3f>(y, x) = cv::Point3f(worldX*0.001f, worldY*0.001f, worldZ*0.001f); // from mm to meters |
|
} |
|
} |
|
} |
|
|
|
outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].mat = pointCloud_XYZ; |
|
|
|
return outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].getIplImagePtr(); |
|
} |
|
|
|
static void computeDisparity_32F( const openni::VideoFrameRef& depthMetaData, cv::Mat& disp, double baseline, int F, int noSampleValue, int shadowValue) |
|
{ |
|
cv::Mat depth; |
|
getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue ); |
|
CV_Assert( depth.type() == CV_16UC1 ); |
|
|
|
// disparity = baseline * F / z; |
|
|
|
float mult = (float)(baseline /*mm*/ * F /*pixels*/); |
|
|
|
disp.create( depth.size(), CV_32FC1); |
|
disp = cv::Scalar::all( CvCapture_OpenNI2::INVALID_PIXEL_VAL ); |
|
for( int y = 0; y < disp.rows; y++ ) |
|
{ |
|
for( int x = 0; x < disp.cols; x++ ) |
|
{ |
|
unsigned short curDepth = depth.at<unsigned short>(y,x); |
|
if( curDepth != CvCapture_OpenNI2::INVALID_PIXEL_VAL ) |
|
disp.at<float>(y,x) = mult / curDepth; |
|
} |
|
} |
|
} |
|
|
|
IplImage* CvCapture_OpenNI2::retrieveDisparityMap() |
|
{ |
|
if (!streamFrames[CV_DEPTH_STREAM].isValid()) |
|
return 0; |
|
|
|
readCamerasParams(); |
|
|
|
cv::Mat disp32; |
|
computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue); |
|
|
|
disp32.convertTo(outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1); |
|
|
|
return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].getIplImagePtr(); |
|
} |
|
|
|
IplImage* CvCapture_OpenNI2::retrieveDisparityMap_32F() |
|
{ |
|
if (!streamFrames[CV_DEPTH_STREAM].isValid()) |
|
return 0; |
|
|
|
readCamerasParams(); |
|
|
|
computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue); |
|
|
|
return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].getIplImagePtr(); |
|
} |
|
|
|
IplImage* CvCapture_OpenNI2::retrieveValidDepthMask() |
|
{ |
|
if (!streamFrames[CV_DEPTH_STREAM].isValid()) |
|
return 0; |
|
|
|
cv::Mat d; |
|
getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], d, noSampleValue, shadowValue); |
|
|
|
outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].mat = d != CvCapture_OpenNI2::INVALID_PIXEL_VAL; |
|
|
|
return outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].getIplImagePtr(); |
|
} |
|
|
|
inline void getBGRImageFromMetaData( const openni::VideoFrameRef& imageMetaData, cv::Mat& bgrImage ) |
|
{ |
|
cv::Mat bufferImage; |
|
if( imageMetaData.getVideoMode().getPixelFormat() != openni::PIXEL_FORMAT_RGB888 ) |
|
CV_Error( CV_StsUnsupportedFormat, "Unsupported format of grabbed image." ); |
|
|
|
bgrImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3); |
|
bufferImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3); |
|
bufferImage.data = (uchar*)imageMetaData.getData(); |
|
|
|
cv::cvtColor(bufferImage, bgrImage, cv::COLOR_RGB2BGR); |
|
} |
|
|
|
inline void getGrayImageFromMetaData(const openni::VideoFrameRef& imageMetaData, cv::Mat& grayImage) |
|
{ |
|
if (imageMetaData.getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_GRAY8) |
|
{ |
|
grayImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC1); |
|
grayImage.data = (uchar*)imageMetaData.getData(); |
|
} |
|
else if (imageMetaData.getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_GRAY16) |
|
{ |
|
grayImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_16UC1); |
|
grayImage.data = (uchar*)imageMetaData.getData(); |
|
} |
|
else |
|
{ |
|
CV_Error(CV_StsUnsupportedFormat, "Unsupported format of grabbed image."); |
|
} |
|
} |
|
|
|
IplImage* CvCapture_OpenNI2::retrieveBGRImage() |
|
{ |
|
if( !streamFrames[CV_COLOR_STREAM].isValid() ) |
|
return 0; |
|
|
|
getBGRImageFromMetaData(streamFrames[CV_COLOR_STREAM], outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat ); |
|
|
|
return outputMaps[CV_CAP_OPENNI_BGR_IMAGE].getIplImagePtr(); |
|
} |
|
|
|
IplImage* CvCapture_OpenNI2::retrieveGrayImage() |
|
{ |
|
if (!streamFrames[CV_COLOR_STREAM].isValid()) |
|
return 0; |
|
|
|
CV_Assert(streamFrames[CV_COLOR_STREAM].getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_RGB888); // RGB |
|
|
|
cv::Mat rgbImage; |
|
getBGRImageFromMetaData(streamFrames[CV_COLOR_STREAM], rgbImage); |
|
cv::cvtColor( rgbImage, outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].mat, CV_BGR2GRAY ); |
|
|
|
return outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].getIplImagePtr(); |
|
} |
|
|
|
IplImage* CvCapture_OpenNI2::retrieveIrImage() |
|
{ |
|
if (!streamFrames[CV_IR_STREAM].isValid()) |
|
return 0; |
|
|
|
getGrayImageFromMetaData(streamFrames[CV_IR_STREAM], outputMaps[CV_CAP_OPENNI_IR_IMAGE].mat); |
|
|
|
return outputMaps[CV_CAP_OPENNI_IR_IMAGE].getIplImagePtr(); |
|
} |
|
|
|
IplImage* CvCapture_OpenNI2::retrieveFrame( int outputType ) |
|
{ |
|
IplImage* image = 0; |
|
CV_Assert( outputType < outputMapsTypesCount && outputType >= 0); |
|
|
|
if( outputType == CV_CAP_OPENNI_DEPTH_MAP ) |
|
{ |
|
image = retrieveDepthMap(); |
|
} |
|
else if( outputType == CV_CAP_OPENNI_POINT_CLOUD_MAP ) |
|
{ |
|
image = retrievePointCloudMap(); |
|
} |
|
else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP ) |
|
{ |
|
image = retrieveDisparityMap(); |
|
} |
|
else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP_32F ) |
|
{ |
|
image = retrieveDisparityMap_32F(); |
|
} |
|
else if( outputType == CV_CAP_OPENNI_VALID_DEPTH_MASK ) |
|
{ |
|
image = retrieveValidDepthMask(); |
|
} |
|
else if( outputType == CV_CAP_OPENNI_BGR_IMAGE ) |
|
{ |
|
image = retrieveBGRImage(); |
|
} |
|
else if( outputType == CV_CAP_OPENNI_GRAY_IMAGE ) |
|
{ |
|
image = retrieveGrayImage(); |
|
} |
|
else if( outputType == CV_CAP_OPENNI_IR_IMAGE ) |
|
{ |
|
image = retrieveIrImage(); |
|
} |
|
|
|
return image; |
|
} |
|
|
|
CvCapture* cvCreateCameraCapture_OpenNI2( int index ) |
|
{ |
|
CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( index ); |
|
|
|
if( capture->isOpened() ) |
|
return capture; |
|
|
|
delete capture; |
|
return 0; |
|
} |
|
|
|
CvCapture* cvCreateFileCapture_OpenNI2( const char* filename ) |
|
{ |
|
CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( filename ); |
|
|
|
if( capture->isOpened() ) |
|
return capture; |
|
|
|
delete capture; |
|
return 0; |
|
} |
|
|
|
#endif
|
|
|