added image and depth synchronization

This commit is contained in:
Maria Dimashova 2012-03-27 07:41:48 +00:00
parent bd13e9479b
commit 550fd8e57c
4 changed files with 512 additions and 40 deletions

View File

@ -126,7 +126,7 @@ Flags specifing the needed generator type must be used in combination with parti
- ``CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_OUTPUT_MODE`` - ``CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_OUTPUT_MODE``
- ``CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_BASELINE`` - ``CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_BASELINE``
- ``CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_FOCAL_LENGTH`` - ``CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_FOCAL_LENGTH``
- ``CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_REGISTRATION_ON`` - ``CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_REGISTRATION``
For more information please refer to the example of usage openni_capture.cpp_ in ``opencv/samples/cpp`` folder. For more information please refer to the example of usage openni_capture.cpp_ in ``opencv/samples/cpp`` folder.

View File

@ -375,26 +375,32 @@ enum
CV_CAP_PROP_PREVIEW_FORMAT=1026, // readonly, tricky property, returns cpnst char* indeed CV_CAP_PROP_PREVIEW_FORMAT=1026, // readonly, tricky property, returns cpnst char* indeed
// OpenNI map generators // OpenNI map generators
CV_CAP_OPENNI_DEPTH_GENERATOR = 0, CV_CAP_OPENNI_DEPTH_GENERATOR = 1 << 31,
CV_CAP_OPENNI_IMAGE_GENERATOR = 1 << 31, CV_CAP_OPENNI_IMAGE_GENERATOR = 1 << 30,
CV_CAP_OPENNI_GENERATORS_MASK = 1 << 31, CV_CAP_OPENNI_GENERATORS_MASK = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_OPENNI_IMAGE_GENERATOR,
// Properties of cameras available through OpenNI interfaces // Properties of cameras available through OpenNI interfaces
CV_CAP_PROP_OPENNI_OUTPUT_MODE = 100, CV_CAP_PROP_OPENNI_OUTPUT_MODE = 100,
CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH = 101, // in mm CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH = 101, // in mm
CV_CAP_PROP_OPENNI_BASELINE = 102, // in mm CV_CAP_PROP_OPENNI_BASELINE = 102, // in mm
CV_CAP_PROP_OPENNI_FOCAL_LENGTH = 103, // in pixels CV_CAP_PROP_OPENNI_FOCAL_LENGTH = 103, // in pixels
CV_CAP_PROP_OPENNI_REGISTRATION_ON = 104, // flag CV_CAP_PROP_OPENNI_REGISTRATION = 104, // flag
CV_CAP_PROP_OPENNI_REGISTRATION = CV_CAP_PROP_OPENNI_REGISTRATION_ON, // flag that synchronizes the remapping depth map to image map CV_CAP_PROP_OPENNI_REGISTRATION_ON = CV_CAP_PROP_OPENNI_REGISTRATION, // flag that synchronizes the remapping depth map to image map
// by changing depth generator's view point (if the flag is "on") or // by changing depth generator's view point (if the flag is "on") or
// sets this view point to its normal one (if the flag is "off"). // sets this view point to its normal one (if the flag is "off").
CV_CAP_PROP_OPENNI_GENERATOR_PRESENT = 105, CV_CAP_PROP_OPENNI_APPROX_FRAME_SYNC = 105,
CV_CAP_PROP_OPENNI_MAX_BUFFER_SIZE = 106,
CV_CAP_PROP_OPENNI_CIRCLE_BUFFER = 107,
CV_CAP_PROP_OPENNI_MAX_TIME_DURATION = 108,
CV_CAP_PROP_OPENNI_GENERATOR_PRESENT = 109,
CV_CAP_OPENNI_IMAGE_GENERATOR_PRESENT = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT, CV_CAP_OPENNI_IMAGE_GENERATOR_PRESENT = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT,
CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_OUTPUT_MODE, CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_OUTPUT_MODE,
CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_BASELINE, CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_BASELINE,
CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_FOCAL_LENGTH, CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_FOCAL_LENGTH,
CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_REGISTRATION_ON, CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_REGISTRATION,
CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION,
// Properties of cameras available through GStreamer interface // Properties of cameras available through GStreamer interface
CV_CAP_GSTREAMER_QUEUE_LENGTH = 200, // default is 1 CV_CAP_GSTREAMER_QUEUE_LENGTH = 200, // default is 1

View File

@ -45,6 +45,7 @@
#ifdef HAVE_OPENNI #ifdef HAVE_OPENNI
#include <iostream> #include <iostream>
#include <queue>
#include "XnCppWrapper.h" #include "XnCppWrapper.h"
const std::string XMLConfig = const std::string XMLConfig =
@ -76,12 +77,346 @@ const std::string XMLConfig =
"</ProductionNodes>" "</ProductionNodes>"
"</OpenNI>\n"; "</OpenNI>\n";
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ApproximateSyncGrabber
{
public:
ApproximateSyncGrabber( xn::Context &context,
xn::DepthGenerator &depthGenerator,
xn::ImageGenerator &imageGenerator,
int maxBufferSize, bool isCircleBuffer, int maxTimeDuration ) :
context(context), depthGenerator(depthGenerator), imageGenerator(imageGenerator),
maxBufferSize(maxBufferSize), isCircleBuffer(isCircleBuffer), maxTimeDuration(maxTimeDuration)
{
task = 0;
CV_Assert( depthGenerator.IsValid() );
CV_Assert( imageGenerator.IsValid() );
}
void setMaxBufferSize( int _maxBufferSize )
{
maxBufferSize = _maxBufferSize;
#ifdef HAVE_TBB
task->setMaxBufferSize();
#endif
}
inline int getMaxBufferSize() const { return maxBufferSize; }
void setIsCircleBuffer( bool _isCircleBuffer ) { isCircleBuffer = _isCircleBuffer; }
bool getIsCircleBuffer() const { return isCircleBuffer; }
void setMaxTimeDuration( int _maxTimeDuration ) { maxTimeDuration = _maxTimeDuration; }
int getMaxTimeDuration() const { return maxTimeDuration; }
bool grab( xn::DepthMetaData& depthMetaData,
xn::ImageMetaData& imageMetaData )
{
CV_Assert( task );
while( task->grab(depthMetaData, imageMetaData) == false )
{
#ifndef HAVE_TBB
task->spin();
#endif
}
return true;
}
void start()
{
CV_Assert( depthGenerator.IsValid() );
CV_Assert( imageGenerator.IsValid() );
#ifdef HAVE_TBB
task = new( tbb::task::allocate_root() ) TBBApproximateSynchronizerTask( *this );
tbb::task::enqueue(*task);
#else
task = new ApproximateSynchronizer( *this );
#endif
}
void finish()
{
#ifdef HAVE_TBB
if( task )
tbb::task::destroy( *task );
#else
task.release();
#endif
}
bool isRun() const { return task != 0; }
xn::Context &context;
xn::DepthGenerator &depthGenerator;
xn::ImageGenerator &imageGenerator;
private:
int maxBufferSize;
bool isCircleBuffer;
int maxTimeDuration;
class ApproximateSynchronizerBase
{
public:
ApproximateSynchronizerBase( ApproximateSyncGrabber& approxSyncGrabber ) :
approxSyncGrabber(approxSyncGrabber), isDepthFilled(false), isImageFilled(false)
{}
virtual bool isSpinContinue() const = 0;
virtual void pushDepthMetaData( xn::DepthMetaData& depthMetaData ) = 0;
virtual void pushImageMetaData( xn::ImageMetaData& imageMetaData ) = 0;
virtual bool popDepthMetaData( xn::DepthMetaData& depthMetaData ) = 0;
virtual bool popImageMetaData( xn::ImageMetaData& imageMetaData ) = 0;
void spin()
{
while(isSpinContinue() == true)
{
XnStatus status = approxSyncGrabber.context.WaitAnyUpdateAll();
if( status != XN_STATUS_OK )
continue;
xn::DepthMetaData depth;
xn::ImageMetaData image;
approxSyncGrabber.depthGenerator.GetMetaData(depth);
approxSyncGrabber.imageGenerator.GetMetaData(image);
if( depth.Data() && depth.IsDataNew() )
pushDepthMetaData( depth );
if( image.Data() && image.IsDataNew() )
pushImageMetaData( image );
}
}
virtual bool grab( xn::DepthMetaData& depthMetaData,
xn::ImageMetaData& imageMetaData )
{
while(1)
{
if( !isDepthFilled )
isDepthFilled = popDepthMetaData(depth);
if( !isImageFilled )
isImageFilled = popImageMetaData(image);
if( !isDepthFilled || !isImageFilled )
break;
double timeDiff = 1e-3 * std::abs(static_cast<double>(depth.Timestamp()) - static_cast<double>(image.Timestamp()));
if( timeDiff <= approxSyncGrabber.maxTimeDuration )
{
depthMetaData.InitFrom(depth);
imageMetaData.InitFrom(image);
isDepthFilled = isImageFilled = false;
return true;
}
else
{
if( depth.Timestamp() < image.Timestamp() )
isDepthFilled = false;
else
isImageFilled = false;
}
}
return false;
}
protected:
ApproximateSyncGrabber& approxSyncGrabber;
xn::DepthMetaData depth;
xn::ImageMetaData image;
bool isDepthFilled;
bool isImageFilled;
};
// If there isn't TBB the synchronization will be executed in the main thread.
class ApproximateSynchronizer: public ApproximateSynchronizerBase
{
public:
ApproximateSynchronizer( ApproximateSyncGrabber& approxSyncGrabber ) :
ApproximateSynchronizerBase(approxSyncGrabber)
{}
virtual bool isSpinContinue() const
{
int maxBufferSize = approxSyncGrabber.getMaxBufferSize();
return (maxBufferSize <= 0) || (static_cast<int>(depthQueue.size()) < maxBufferSize &&
static_cast<int>(imageQueue.size()) < maxBufferSize); // "<" to may push
}
virtual inline void pushDepthMetaData( xn::DepthMetaData& depthMetaData )
{
cv::Ptr<xn::DepthMetaData> depthPtr = new xn::DepthMetaData;
depthPtr->CopyFrom(depthMetaData);
depthQueue.push(depthPtr);
}
virtual inline void pushImageMetaData( xn::ImageMetaData& imageMetaData )
{
cv::Ptr<xn::ImageMetaData> imagePtr = new xn::ImageMetaData;
imagePtr->CopyFrom(imageMetaData);
imageQueue.push(imagePtr);
}
virtual inline bool popDepthMetaData( xn::DepthMetaData& depthMetaData )
{
if( depthQueue.empty() )
return false;
depthMetaData.CopyFrom(*depthQueue.front());
depthQueue.pop();
return true;
}
virtual inline bool popImageMetaData( xn::ImageMetaData& imageMetaData )
{
if( imageQueue.empty() )
return false;
imageMetaData.CopyFrom(*imageQueue.front());
imageQueue.pop();
return true;
}
private:
std::queue<cv::Ptr<xn::DepthMetaData> > depthQueue;
std::queue<cv::Ptr<xn::ImageMetaData> > imageQueue;
};
#ifdef HAVE_TBB
// If there is TBB the synchronization will be executed in own thread.
class TBBApproximateSynchronizer: public ApproximateSynchronizerBase
{
public:
TBBApproximateSynchronizer( ApproximateSyncGrabber& approxSyncGrabber ) :
ApproximateSynchronizerBase(approxSyncGrabber)
{
setMaxBufferSize();
}
void setMaxBufferSize()
{
int maxBufferSize = ApproximateSynchronizerBase::approxSyncGrabber.getMaxBufferSize();
if( maxBufferSize >= 0 )
{
depthQueue.set_capacity( maxBufferSize );
imageQueue.set_capacity( maxBufferSize );
}
}
virtual inline bool isSpinContinue() const { return true; }
virtual inline void pushDepthMetaData( xn::DepthMetaData& depthMetaData )
{
cv::Ptr<xn::DepthMetaData> depthPtr = new xn::DepthMetaData, tmp;
depthPtr->CopyFrom(depthMetaData);
tbb::mutex mtx;
mtx.lock();
if( depthQueue.try_push(depthPtr) == false )
{
if( approxSyncGrabber.getIsCircleBuffer() )
{
CV_Assert( depthQueue.try_pop(tmp) );
CV_Assert( depthQueue.try_push(depthPtr) );
}
}
mtx.unlock();
}
virtual inline void pushImageMetaData( xn::ImageMetaData& imageMetaData )
{
cv::Ptr<xn::ImageMetaData> imagePtr = new xn::ImageMetaData, tmp;
imagePtr->CopyFrom(imageMetaData);
tbb::mutex mtx;
mtx.lock();
if( imageQueue.try_push(imagePtr) == false )
{
if( approxSyncGrabber.getIsCircleBuffer() )
{
CV_Assert( imageQueue.try_pop(tmp) );
CV_Assert( imageQueue.try_push(imagePtr) );
}
}
mtx.unlock();
}
virtual inline bool popDepthMetaData( xn::DepthMetaData& depthMetaData )
{
cv::Ptr<xn::DepthMetaData> depthPtr;
bool isPop = depthQueue.try_pop(depthPtr);
if( isPop )
depthMetaData.CopyFrom(*depthPtr);
return isPop;
}
virtual inline bool popImageMetaData( xn::ImageMetaData& imageMetaData )
{
cv::Ptr<xn::ImageMetaData> imagePtr;
bool isPop = imageQueue.try_pop(imagePtr);
if( isPop )
imageMetaData.CopyFrom(*imagePtr);
return isPop;
}
private:
tbb::concurrent_bounded_queue<cv::Ptr<xn::DepthMetaData> > depthQueue;
tbb::concurrent_bounded_queue<cv::Ptr<xn::ImageMetaData> > imageQueue;
};
class TBBApproximateSynchronizerTask: public tbb::task
{
public:
TBBApproximateSynchronizerTask( ApproximateSyncGrabber& approxSyncGrabber ) :
synchronizer(approxSyncGrabber)
{}
void setMaxBufferSize()
{
synchronizer.setMaxBufferSize();
}
bool grab( xn::DepthMetaData& depthMetaData,
xn::ImageMetaData& imageMetaData )
{
return synchronizer.grab( depthMetaData, imageMetaData );
}
private:
tbb::task* execute()
{
synchronizer.spin();
return 0;
}
TBBApproximateSynchronizer synchronizer;
};
#endif // HAVE_TBB
#ifdef HAVE_TBB
TBBApproximateSynchronizerTask* task;
#else
cv::Ptr<ApproximateSynchronizer> task;
#endif
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CvCapture_OpenNI : public CvCapture class CvCapture_OpenNI : public CvCapture
{ {
public: public:
static const int INVALID_PIXEL_VAL = 0; static const int INVALID_PIXEL_VAL = 0;
static const int INVALID_COORDINATE_VAL = 0; static const int INVALID_COORDINATE_VAL = 0;
#ifdef HAVE_TBB
static const int DEFAULT_MAX_BUFFER_SIZE = 8;
#else
static const int DEFAULT_MAX_BUFFER_SIZE = 2;
#endif
static const int DEFAULT_IS_CIRCLE_BUFFER = 1;
static const int DEFAULT_MAX_TIME_DURATION = 20;
CvCapture_OpenNI(int index=0); CvCapture_OpenNI(int index=0);
CvCapture_OpenNI(const char * filename); CvCapture_OpenNI(const char * filename);
virtual ~CvCapture_OpenNI(); virtual ~CvCapture_OpenNI();
@ -119,11 +454,13 @@ protected:
bool setDepthGeneratorProperty(int propIdx, double propVal); bool setDepthGeneratorProperty(int propIdx, double propVal);
double getImageGeneratorProperty(int propIdx); double getImageGeneratorProperty(int propIdx);
bool setImageGeneratorProperty(int propIdx, double propVal); bool setImageGeneratorProperty(int propIdx, double propVal);
double getCommonProperty(int propIdx);
bool setCommonProperty(int propIdx, double propVal);
// OpenNI context // OpenNI context
xn::Context context; xn::Context context;
bool isContextOpened; bool isContextOpened;
xn::ProductionNode productionNode; xn::ProductionNode productionNode;
// Data generators with its metadata // Data generators with its metadata
@ -133,6 +470,10 @@ protected:
xn::ImageGenerator imageGenerator; xn::ImageGenerator imageGenerator;
xn::ImageMetaData imageMetaData; xn::ImageMetaData imageMetaData;
int maxBufferSize, maxTimeDuration; // for approx sync
bool isCircleBuffer;
cv::Ptr<ApproximateSyncGrabber> approxSyncGrabber;
// Cameras settings: // Cameras settings:
// TODO find in OpenNI function to convert z->disparity and remove fields "baseline" and depthFocalLength_VGA // 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) // Distance between IR projector and IR camera (in meters)
@ -176,6 +517,9 @@ CvCapture_OpenNI::CvCapture_OpenNI( int index )
XnStatus status; XnStatus status;
isContextOpened = false; isContextOpened = false;
maxBufferSize = DEFAULT_MAX_BUFFER_SIZE;
isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER;
maxTimeDuration = DEFAULT_MAX_TIME_DURATION;
// Initialize and configure the context. // Initialize and configure the context.
status = context.Init(); status = context.Init();
@ -209,7 +553,8 @@ CvCapture_OpenNI::CvCapture_OpenNI( int index )
return; return;
} }
status = context.RunXmlScript( XMLConfig.c_str() ); xn::ScriptNode scriptNode;
status = context.RunXmlScript( XMLConfig.c_str(), scriptNode );
if( status != XN_STATUS_OK ) if( status != XN_STATUS_OK )
{ {
std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to run xml script: " std::cerr << "CvCapture_OpenNI::CvCapture_OpenNI : Failed to run xml script: "
@ -263,9 +608,13 @@ CvCapture_OpenNI::CvCapture_OpenNI( int index )
// Set map output mode. // Set map output mode.
if( depthGenerator.IsValid() ) if( depthGenerator.IsValid() )
{
CV_DbgAssert( depthGenerator.SetMapOutputMode(defaultMapOutputMode()) == XN_STATUS_OK ); // xn::DepthGenerator supports VGA only! (Jan 2011) CV_DbgAssert( depthGenerator.SetMapOutputMode(defaultMapOutputMode()) == XN_STATUS_OK ); // xn::DepthGenerator supports VGA only! (Jan 2011)
}
if( imageGenerator.IsValid() ) if( imageGenerator.IsValid() )
{
CV_DbgAssert( imageGenerator.SetMapOutputMode(defaultMapOutputMode()) == XN_STATUS_OK ); CV_DbgAssert( imageGenerator.SetMapOutputMode(defaultMapOutputMode()) == XN_STATUS_OK );
}
// Start generating data. // Start generating data.
status = context.StartGeneratingAll(); status = context.StartGeneratingAll();
@ -294,6 +643,9 @@ CvCapture_OpenNI::CvCapture_OpenNI(const char * filename)
XnStatus status; XnStatus status;
isContextOpened = false; isContextOpened = false;
maxBufferSize = DEFAULT_MAX_BUFFER_SIZE;
isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER;
maxTimeDuration = DEFAULT_MAX_TIME_DURATION;
// Initialize and configure the context. // Initialize and configure the context.
status = context.Init(); status = context.Init();
@ -330,7 +682,7 @@ CvCapture_OpenNI::CvCapture_OpenNI(const char * filename)
CvCapture_OpenNI::~CvCapture_OpenNI() CvCapture_OpenNI::~CvCapture_OpenNI()
{ {
context.StopGeneratingAll(); context.StopGeneratingAll();
context.Shutdown(); context.Release();
} }
bool CvCapture_OpenNI::readCamerasParams() bool CvCapture_OpenNI::readCamerasParams()
@ -398,7 +750,7 @@ double CvCapture_OpenNI::getProperty( int propIdx )
} }
else else
{ {
CV_Error( CV_StsError, "Unsupported generator prefix!" ); propValue = getCommonProperty( purePropIdx );
} }
} }
@ -407,26 +759,131 @@ double CvCapture_OpenNI::getProperty( int propIdx )
bool CvCapture_OpenNI::setProperty( int propIdx, double propValue ) bool CvCapture_OpenNI::setProperty( int propIdx, double propValue )
{ {
bool res = false; bool isSet = false;
if( isOpened() ) if( isOpened() )
{ {
int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK; int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK;
if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR ) if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR )
{ {
res = setImageGeneratorProperty( purePropIdx, propValue ); isSet = setImageGeneratorProperty( purePropIdx, propValue );
} }
else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR ) else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR )
{ {
res = setDepthGeneratorProperty( purePropIdx, propValue ); isSet = setDepthGeneratorProperty( purePropIdx, propValue );
} }
else else
{ {
CV_Error( CV_StsError, "Unsupported generator prefix!" ); isSet = setCommonProperty( purePropIdx, propValue );
} }
} }
return res; return isSet;
}
double CvCapture_OpenNI::getCommonProperty( int propIdx )
{
double propValue = 0;
switch( propIdx )
{
// There is a set of properties that correspond to depth generator by default
// (is they are pass without particular generator flag). Two reasons of this:
// 1) We can assume that depth generator is the main one for depth sensor.
// 2) In the initial vertions of OpenNI integration to OpenCV the value of
// flag CV_CAP_OPENNI_DEPTH_GENERATOR was 0 (it isn't zero now).
case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT :
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_OPENNI_APPROX_FRAME_SYNC :
propValue = !approxSyncGrabber.empty() && approxSyncGrabber->isRun() ? 1. : 0.;
break;
case CV_CAP_PROP_OPENNI_MAX_BUFFER_SIZE :
propValue = maxBufferSize;
break;
case CV_CAP_PROP_OPENNI_CIRCLE_BUFFER :
propValue = isCircleBuffer ? 1. : 0.;
break;
case CV_CAP_PROP_OPENNI_MAX_TIME_DURATION :
propValue = maxTimeDuration;
break;
default :
{
std::stringstream ss;
ss << "Such parameter (propIdx=" << propIdx << ") isn't supported for getting.\n";
CV_Error( CV_StsBadArg, ss.str().c_str() );
}
}
return propValue;
}
bool CvCapture_OpenNI::setCommonProperty( int propIdx, double propValue )
{
bool isSet = false;
switch( propIdx )
{
// 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_OPENNI_APPROX_FRAME_SYNC :
if( propValue && depthGenerator.IsValid() && imageGenerator.IsValid() )
{
// start synchronization
if( approxSyncGrabber.empty() )
{
approxSyncGrabber = new ApproximateSyncGrabber( context, depthGenerator, imageGenerator, maxBufferSize, isCircleBuffer, maxTimeDuration );
}
else
{
approxSyncGrabber->finish();
// update params
approxSyncGrabber->setMaxBufferSize(maxBufferSize);
approxSyncGrabber->setIsCircleBuffer(isCircleBuffer);
approxSyncGrabber->setMaxTimeDuration(maxTimeDuration);
}
approxSyncGrabber->start();
}
else if( !propValue && !approxSyncGrabber.empty() )
{
// finish synchronization
approxSyncGrabber->finish();
}
break;
case CV_CAP_PROP_OPENNI_MAX_BUFFER_SIZE :
maxBufferSize = cvRound(propValue);
if( !approxSyncGrabber.empty() )
approxSyncGrabber->setMaxBufferSize(maxBufferSize);
break;
case CV_CAP_PROP_OPENNI_CIRCLE_BUFFER :
if( !approxSyncGrabber.empty() )
approxSyncGrabber->setIsCircleBuffer(isCircleBuffer);
break;
case CV_CAP_PROP_OPENNI_MAX_TIME_DURATION :
maxTimeDuration = cvRound(propValue);
if( !approxSyncGrabber.empty() )
approxSyncGrabber->setMaxTimeDuration(maxTimeDuration);
break;
default:
{
std::stringstream ss;
ss << "Such parameter (propIdx=" << propIdx << ") isn't supported for setting.\n";
CV_Error( CV_StsBadArg, ss.str().c_str() );
}
}
return isSet;
} }
double CvCapture_OpenNI::getDepthGeneratorProperty( int propIdx ) double CvCapture_OpenNI::getDepthGeneratorProperty( int propIdx )
@ -536,7 +993,7 @@ double CvCapture_OpenNI::getImageGeneratorProperty( int propIdx )
{ {
double propValue = 0.; double propValue = 0.;
if( !imageGenerator.IsValid() ) if( !imageGenerator.IsValid() )
return propValue; return propValue;
XnMapOutputMode mode; XnMapOutputMode mode;
switch( propIdx ) switch( propIdx )
@ -570,10 +1027,10 @@ double CvCapture_OpenNI::getImageGeneratorProperty( int propIdx )
bool CvCapture_OpenNI::setImageGeneratorProperty( int propIdx, double propValue ) bool CvCapture_OpenNI::setImageGeneratorProperty( int propIdx, double propValue )
{ {
bool isSet = false; bool isSet = false;
if( !imageGenerator.IsValid() ) if( !imageGenerator.IsValid() )
return isSet; return isSet;
switch( propIdx ) switch( propIdx )
{ {
case CV_CAP_PROP_OPENNI_OUTPUT_MODE : case CV_CAP_PROP_OPENNI_OUTPUT_MODE :
@ -624,16 +1081,25 @@ bool CvCapture_OpenNI::grabFrame()
if( !isOpened() ) if( !isOpened() )
return false; return false;
XnStatus status = context.WaitAndUpdateAll(); bool isGrabbed = false;
if( status != XN_STATUS_OK ) if( !approxSyncGrabber.empty() && approxSyncGrabber->isRun() )
return false; {
isGrabbed = approxSyncGrabber->grab( depthMetaData, imageMetaData );
}
else
{
XnStatus status = context.WaitAndUpdateAll();
if( status != XN_STATUS_OK )
return false;
if( depthGenerator.IsValid() ) if( depthGenerator.IsValid() )
depthGenerator.GetMetaData( depthMetaData ); depthGenerator.GetMetaData( depthMetaData );
if( imageGenerator.IsValid() ) if( imageGenerator.IsValid() )
imageGenerator.GetMetaData( imageMetaData ); imageGenerator.GetMetaData( imageMetaData );
isGrabbed = true;
}
return true; return isGrabbed;
} }
inline void getDepthMapFromMetaData( const xn::DepthMetaData& depthMetaData, cv::Mat& depthMap, XnUInt64 noSampleValue, XnUInt64 shadowValue ) inline void getDepthMapFromMetaData( const xn::DepthMetaData& depthMetaData, cv::Mat& depthMap, XnUInt64 noSampleValue, XnUInt64 shadowValue )
@ -656,7 +1122,7 @@ inline void getDepthMapFromMetaData( const xn::DepthMetaData& depthMetaData, cv:
IplImage* CvCapture_OpenNI::retrieveDepthMap() IplImage* CvCapture_OpenNI::retrieveDepthMap()
{ {
if( depthMetaData.XRes() <= 0 || depthMetaData.YRes() <= 0 ) if( !depthMetaData.Data() )
return 0; return 0;
getDepthMapFromMetaData( depthMetaData, outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue ); getDepthMapFromMetaData( depthMetaData, outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue );
@ -666,8 +1132,7 @@ IplImage* CvCapture_OpenNI::retrieveDepthMap()
IplImage* CvCapture_OpenNI::retrievePointCloudMap() IplImage* CvCapture_OpenNI::retrievePointCloudMap()
{ {
int cols = depthMetaData.XRes(), rows = depthMetaData.YRes(); if( !depthMetaData.Data() )
if( cols <= 0 || rows <= 0 )
return 0; return 0;
cv::Mat depth; cv::Mat depth;
@ -675,6 +1140,7 @@ IplImage* CvCapture_OpenNI::retrievePointCloudMap()
const int badPoint = INVALID_PIXEL_VAL; const int badPoint = INVALID_PIXEL_VAL;
const float badCoord = INVALID_COORDINATE_VAL; const float badCoord = INVALID_COORDINATE_VAL;
int cols = depthMetaData.XRes(), rows = depthMetaData.YRes();
cv::Mat pointCloud_XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) ); cv::Mat pointCloud_XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) );
cv::Ptr<XnPoint3D> proj = new XnPoint3D[cols*rows]; cv::Ptr<XnPoint3D> proj = new XnPoint3D[cols*rows];
@ -738,7 +1204,7 @@ void computeDisparity_32F( const xn::DepthMetaData& depthMetaData, cv::Mat& disp
IplImage* CvCapture_OpenNI::retrieveDisparityMap() IplImage* CvCapture_OpenNI::retrieveDisparityMap()
{ {
if( depthMetaData.XRes() <= 0 || depthMetaData.YRes() <= 0 ) if( !depthMetaData.Data() )
return 0; return 0;
cv::Mat disp32; cv::Mat disp32;
@ -751,7 +1217,7 @@ IplImage* CvCapture_OpenNI::retrieveDisparityMap()
IplImage* CvCapture_OpenNI::retrieveDisparityMap_32F() IplImage* CvCapture_OpenNI::retrieveDisparityMap_32F()
{ {
if( depthMetaData.XRes() <= 0 || depthMetaData.YRes() <= 0 ) if( !depthMetaData.Data() )
return 0; return 0;
computeDisparity_32F( depthMetaData, outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue ); computeDisparity_32F( depthMetaData, outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue );
@ -761,7 +1227,7 @@ IplImage* CvCapture_OpenNI::retrieveDisparityMap_32F()
IplImage* CvCapture_OpenNI::retrieveValidDepthMask() IplImage* CvCapture_OpenNI::retrieveValidDepthMask()
{ {
if( depthMetaData.XRes() <= 0 || depthMetaData.YRes() <= 0 ) if( !depthMetaData.Data() )
return 0; return 0;
cv::Mat depth; cv::Mat depth;
@ -787,7 +1253,7 @@ inline void getBGRImageFromMetaData( const xn::ImageMetaData& imageMetaData, cv:
IplImage* CvCapture_OpenNI::retrieveBGRImage() IplImage* CvCapture_OpenNI::retrieveBGRImage()
{ {
if( imageMetaData.XRes() <= 0 || imageMetaData.YRes() <= 0 ) if( !imageMetaData.Data() )
return 0; return 0;
getBGRImageFromMetaData( imageMetaData, outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat ); getBGRImageFromMetaData( imageMetaData, outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat );
@ -797,7 +1263,7 @@ IplImage* CvCapture_OpenNI::retrieveBGRImage()
IplImage* CvCapture_OpenNI::retrieveGrayImage() IplImage* CvCapture_OpenNI::retrieveGrayImage()
{ {
if( imageMetaData.XRes() <= 0 || imageMetaData.YRes() <= 0 ) if( !imageMetaData.Data() )
return 0; return 0;
CV_Assert( imageMetaData.BytesPerPixel() == 3 ); // RGB CV_Assert( imageMetaData.BytesPerPixel() == 3 ); // RGB

View File

@ -8,7 +8,7 @@ using namespace std;
void help() void help()
{ {
cout << "\nThis program demonstrates usage of depth sensors(Kinect,XtionPRO,...).\n" cout << "\nThis program demonstrates usage of depth sensors (Kinect, XtionPRO,...).\n"
"The user gets some of the supported output images.\n" "The user gets some of the supported output images.\n"
"\nAll supported output map types:\n" "\nAll supported output map types:\n"
"1.) Data given from depth generator\n" "1.) Data given from depth generator\n"