diff --git a/modules/highgui/include/opencv2/highgui/highgui_c.h b/modules/highgui/include/opencv2/highgui/highgui_c.h index 87fa0e6ea6..b98fb682ac 100644 --- a/modules/highgui/include/opencv2/highgui/highgui_c.h +++ b/modules/highgui/include/opencv2/highgui/highgui_c.h @@ -288,9 +288,9 @@ enum CV_CAP_DSHOW =700, // DirectShow (via videoInput) - CV_CAP_PVAPI =800, // PvAPI, Prosilica GigE SDK + CV_CAP_PVAPI =800, // PvAPI, Prosilica GigE SDK - CV_CAP_OPENNI =900 // OpenNI (for Kinect) + CV_CAP_OPENNI =900 // OpenNI (for Kinect) }; /* start capturing frames from camera: index = camera_index + domain_offset (CV_CAP_*) */ @@ -383,6 +383,32 @@ enum OPENNI_GRAY_IMAGE = 6 }; +// OpenNI map generators +enum +{ + OPENNI_DEPTH_GENERATOR = 0, + OPENNI_IMAGE_GENERATOR = 1 << 31 +}; + +// Properties of Kinect (additional to ones begining from CV_CAP_PROP_...) +enum +{ + OPENNI_OUTPUT_MODE = 20, + OPENNI_FRAME_MAX_DEPTH = 21, // in mm + OPENNI_BASELINE = 22, // in mm + OPENNI_FOCAL_LENGTH = 23, // in pixels + OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = OPENNI_IMAGE_GENERATOR + OPENNI_OUTPUT_MODE, + OPENNI_DEPTH_GENERATOR_BASELINE = OPENNI_DEPTH_GENERATOR + OPENNI_BASELINE, + OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = OPENNI_DEPTH_GENERATOR + OPENNI_FOCAL_LENGTH +}; + +// Supported output modes of OpenNI image generator +enum +{ + OPENNI_VGA_30HZ = 0, + OPENNI_SXGA_15HZ = 1 +}; + const int OPENNI_BAD_DEPTH_VAL = 0; const int OPENNI_BAD_DISP_VAL = 0; diff --git a/modules/highgui/src/cap_openni.cpp b/modules/highgui/src/cap_openni.cpp index d517daf320..575bf3d08e 100644 --- a/modules/highgui/src/cap_openni.cpp +++ b/modules/highgui/src/cap_openni.cpp @@ -119,6 +119,11 @@ protected: void readCamerasParams(); + double getDepthGeneratorProperty(int); + bool setDepthGeneratorProperty(int, double); + double getImageGeneratorProperty(int); + bool setImageGeneratorProperty(int, double); + // OpenNI context xn::Context context; bool m_isOpened; @@ -126,9 +131,11 @@ protected: // Data generators with its metadata xn::DepthGenerator depthGenerator; xn::DepthMetaData depthMetaData; + XnMapOutputMode depthOutputMode; xn::ImageGenerator imageGenerator; xn::ImageMetaData imageMetaData; + XnMapOutputMode imageOutputMode; // Cameras settings: #if 1 @@ -163,17 +170,20 @@ CvCapture_OpenNI::CvCapture_OpenNI() { XnStatus status = XN_STATUS_OK; - // Initialize the context with default configuration. - status = context.Init(); - m_isOpened = (status == XN_STATUS_OK); - - if( m_isOpened ) + // Initialize image output modes (VGA_30HZ by default). + depthOutputMode.nXRes = imageOutputMode.nXRes = XN_VGA_X_RES; + depthOutputMode.nYRes = imageOutputMode.nYRes = XN_VGA_Y_RES; + depthOutputMode.nFPS = imageOutputMode.nFPS = 30; + + m_isOpened = false; + + // Initialize and configure the context. + if( context.Init() == XN_STATUS_OK ) { - // Configure the context. #ifdef HACK_WITH_XML // Write configuration to the temporary file. // This is a hack, because there is a bug in RunXmlScript(). - // TODO: remove hack when bug in RunXmlScript() will be fixed. + // TODO: remove hack when bug in RunXmlScript() will be fixed. char xmlFilename[100]; tmpnam( xmlFilename ); std::ofstream outfile( xmlFilename ); @@ -187,10 +197,12 @@ CvCapture_OpenNI::CvCapture_OpenNI() #else status = context.RunXmlScript( XMLConfig.c_str() ); #endif - if( status != XN_STATUS_OK ) - CV_Error(CV_StsError, ("Failed to apply XML configuration: " + std::string(xnGetStatusString(status))).c_str() ); + m_isOpened = ( status == XN_STATUS_OK ); + } - // Initialize generators. + if( m_isOpened ) + { + // Associate generators with context. status = depthGenerator.Create( context ); if( status != XN_STATUS_OK ) CV_Error(CV_StsError, ("Failed to create depth generator: " + std::string(xnGetStatusString(status))).c_str() ); @@ -198,6 +210,10 @@ CvCapture_OpenNI::CvCapture_OpenNI() if( status != XN_STATUS_OK ) CV_Error(CV_StsError, ("Failed to create image generator: " + std::string(xnGetStatusString(status))).c_str() ); + // Set map output mode. + CV_Assert( depthGenerator.SetMapOutputMode( depthOutputMode ) == XN_STATUS_OK ); // xn::DepthGenerator supports VGA only! (Jan 2011) + CV_Assert( imageGenerator.SetMapOutputMode( imageOutputMode ) == XN_STATUS_OK ); + // Start generating data. status = context.StartGeneratingAll(); if( status != XN_STATUS_OK ) @@ -247,18 +263,141 @@ void CvCapture_OpenNI::readCamerasParams() CV_Error( CV_StsError, "Could not read no sample value!" ); } -double CvCapture_OpenNI::getProperty(int) +double CvCapture_OpenNI::getProperty( int propIdx ) { - assert(0); - // TODO - return 0; + double propValue = -1; + + if( isOpened() ) + { + if( propIdx & OPENNI_IMAGE_GENERATOR ) + { + propValue = getImageGeneratorProperty( propIdx ^ OPENNI_IMAGE_GENERATOR ); + } + else // depth generator (by default, OPENNI_DEPTH_GENERATOR == 0) + { + propValue = getDepthGeneratorProperty( propIdx /*^ OPENNI_DEPTH_GENERATOR*/ ); + } + } + + return propValue; } -bool CvCapture_OpenNI::setProperty(int, double) +bool CvCapture_OpenNI::setProperty( int propIdx, double propValue ) { - assert(0); - // TODO - return true; + bool res = false; + if( isOpened() ) + { + if( propIdx & OPENNI_IMAGE_GENERATOR ) + { + res = setImageGeneratorProperty( propIdx ^ OPENNI_IMAGE_GENERATOR, propValue ); + } + else // depth generator (by default, OPENNI_DEPTH_GENERATOR == 0) + { + res = setDepthGeneratorProperty( propIdx /*^ OPENNI_DEPTH_GENERATOR*/, propValue ); + } + } + + return false; +} + +double CvCapture_OpenNI::getDepthGeneratorProperty( int propIdx ) +{ + CV_Assert( depthGenerator.IsValid() ); + + double res = -1; + switch( propIdx ) + { + case CV_CAP_PROP_FRAME_WIDTH : + res = depthOutputMode.nXRes; + break; + case CV_CAP_PROP_FRAME_HEIGHT : + res = depthOutputMode.nYRes; + break; + case CV_CAP_PROP_FPS : + res = depthOutputMode.nFPS; + break; + case OPENNI_FRAME_MAX_DEPTH : + res = depthGenerator.GetDeviceMaxDepth(); + break; + case OPENNI_BASELINE : + res = baseline; + break; + case OPENNI_FOCAL_LENGTH : + res = depthFocalLength_VGA; + break; + default : + CV_Error( CV_StsBadArg, "Depth generator does not support such parameter for getting.\n"); + } + + return res; +} + +bool CvCapture_OpenNI::setDepthGeneratorProperty( int propIdx, double propValue ) +{ + CV_Assert( depthGenerator.IsValid() ); + CV_Error( CV_StsBadArg, "Depth generator does not support such parameter for setting.\n"); +} + +double CvCapture_OpenNI::getImageGeneratorProperty( int propIdx ) +{ + CV_Assert( imageGenerator.IsValid() ); + + double res = -1; + switch( propIdx ) + { + case CV_CAP_PROP_FRAME_WIDTH : + res = imageOutputMode.nXRes; + break; + case CV_CAP_PROP_FRAME_HEIGHT : + res = imageOutputMode.nYRes; + break; + case CV_CAP_PROP_FPS : + res = imageOutputMode.nFPS; + break; + default : + CV_Error( CV_StsBadArg, "Image generator does not support such parameter for getting.\n"); + } + + return res; +} + +bool CvCapture_OpenNI::setImageGeneratorProperty( int propIdx, double propValue ) +{ + bool res = false; + + CV_Assert( imageGenerator.IsValid() ); + XnMapOutputMode newImageOutputMode = imageOutputMode; + switch( propIdx ) + { + case OPENNI_OUTPUT_MODE : + switch( cvRound(propValue) ) + { + case OPENNI_VGA_30HZ : + newImageOutputMode.nXRes = XN_VGA_X_RES; + newImageOutputMode.nYRes = XN_VGA_Y_RES; + newImageOutputMode.nFPS = 30; + break; + case OPENNI_SXGA_15HZ : + newImageOutputMode.nXRes = XN_SXGA_X_RES; + newImageOutputMode.nYRes = XN_SXGA_Y_RES; + newImageOutputMode.nFPS = 15; + break; + default : + CV_Error( CV_StsBadArg, "Unsupported image generator output mode.\n"); + } + break; + + default: + CV_Error( CV_StsBadArg, "Image generator does not support such parameter for setting.\n"); + } + + if( imageGenerator.SetMapOutputMode( newImageOutputMode ) == XN_STATUS_OK ) + { + imageOutputMode = newImageOutputMode; + res = true; + } + + return res; } bool CvCapture_OpenNI::grabFrame() diff --git a/samples/cpp/kinect_maps.cpp b/samples/cpp/kinect_maps.cpp index 2a2004cddd..4eeead95cd 100644 --- a/samples/cpp/kinect_maps.cpp +++ b/samples/cpp/kinect_maps.cpp @@ -6,14 +6,20 @@ using namespace cv; using namespace std; -void colorizeDisparity( const Mat& gray, Mat& rgb, float S=1.f, float V=1.f ) +#define COLORIZED_DISP 1 +#define IMAGE_GENERATOR_VGA_30HZ 1 +#define FIXED_MAX_DISP 0 + +void colorizeDisparity( const Mat& gray, Mat& rgb, double maxDisp=-1.f, float S=1.f, float V=1.f ) { CV_Assert( !gray.empty() ); CV_Assert( gray.type() == CV_8UC1 ); - // TODO do maxDisp constant (when camera properties will be accessible) - double maxDisp = 0; - minMaxLoc( gray, 0, &maxDisp ); + if( maxDisp <= 0 ) + { + maxDisp = 0; + minMaxLoc( gray, 0, &maxDisp ); + } rgb.create( gray.size(), CV_8UC3 ); for( int y = 0; y < gray.rows; y++ ) @@ -70,6 +76,18 @@ void help() << endl; } +float getMaxDisparity( VideoCapture& capture ) +{ +#if FIXED_MAX_DISP + const int minDistance = 400; // mm + float b = capture.get( OPENNI_DEPTH_GENERATOR_BASELINE ); // mm + float F = capture.get( OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH ); // pixels + return b * F / minDistance; +#else + return -1; +#endif +} + /* * To work with Kinect the user must install OpenNI library and PrimeSensorModule for OpenNI and * configure OpenCV with WITH_OPENNI flag is ON (using CMake). @@ -88,6 +106,24 @@ int main() return -1; } +#if IMAGE_GENERATOR_VGA_30HZ + capture.set( OPENNI_IMAGE_GENERATOR_OUTPUT_MODE, OPENNI_VGA_30HZ ); // default +#else + capture.set( OPENNI_IMAGE_GENERATOR_OUTPUT_MODE, OPENNI_SXGA_15HZ ); +#endif + + // Print some avalible Kinect settings. + cout << "Depth generator output mode:" << endl << + "FRAME_WIDTH " << capture.get( CV_CAP_PROP_FRAME_WIDTH ) << endl << + "FRAME_HEIGHT " << capture.get( CV_CAP_PROP_FRAME_HEIGHT ) << endl << + "FRAME_MAX_DEPTH " << capture.get( OPENNI_FRAME_MAX_DEPTH ) << " mm" << endl << + "FPS " << capture.get( CV_CAP_PROP_FPS ) << endl; + + cout << "Image generator output mode:" << endl << + "FRAME_WIDTH " << capture.get( OPENNI_IMAGE_GENERATOR+CV_CAP_PROP_FRAME_WIDTH ) << endl << + "FRAME_HEIGHT " << capture.get( OPENNI_IMAGE_GENERATOR+CV_CAP_PROP_FRAME_HEIGHT ) << endl << + "FPS " << capture.get( OPENNI_IMAGE_GENERATOR+CV_CAP_PROP_FPS ) << endl; + for(;;) { Mat depthMap; @@ -112,14 +148,14 @@ int main() if( capture.retrieve( disparityMap, OPENNI_DISPARITY_MAP ) ) { -#if 0 // original disparity - imshow( "original disparity map", disparityMap ); -#else // colorized disparity for more visibility +#if COLORIZED_DISP // colorized disparity for more visibility Mat colorDisparityMap; - colorizeDisparity( disparityMap, colorDisparityMap ); + colorizeDisparity( disparityMap, colorDisparityMap, getMaxDisparity( capture ) ); Mat validColorDisparityMap; colorDisparityMap.copyTo( validColorDisparityMap, disparityMap != OPENNI_BAD_DISP_VAL ); imshow( "colorized disparity map", validColorDisparityMap ); +#else // original disparity + imshow( "original disparity map", disparityMap ); #endif }