From ad896ae640b99f63fbed9e98d8e346caa2087e36 Mon Sep 17 00:00:00 2001 From: Maria Dimashova Date: Fri, 4 Feb 2011 13:41:10 +0000 Subject: [PATCH] refactored OpenNI integration --- CMakeLists.txt | 38 +--- OpenCVFindOpenNI.cmake | 82 +++++++++ doc/user_guide/user_highgui.tex | 8 +- .../include/opencv2/highgui/highgui_c.h | 81 ++++----- modules/highgui/src/cap_openni.cpp | 133 ++++++++------ samples/cpp/kinect_maps.cpp | 172 ++++++++++++------ 6 files changed, 321 insertions(+), 193 deletions(-) create mode 100644 OpenCVFindOpenNI.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ab15fce6..5c6a3e9ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -775,37 +775,11 @@ endif() ############################### OpenNI ################################ set(HAVE_OPENNI FALSE) -set(HAVE_PRIME_SENSOR_FOR_OPENNI FALSE) +set(HAVE_OPENNI_PRIME_SENSOR_MODULE FALSE) if(WITH_OPENNI) - # find OpenNI library - unset(OPENNI_LIBRARY CACHE) - unset(PRIME_SENSOR_MODULES_FOR_OPENNI CACHE) - find_library(OPENNI_LIBRARY "OpenNI" PATHS "/usr/lib" "c:/Program Files/OpenNI/Lib" DOC "OpenNI library") - - if(OPENNI_LIBRARY) - set(HAVE_OPENNI TRUE) - - # set OpenNI include directory - if(WIN32) - set(OPENNI_INCLUDE_DIR "c:/Program Files/OpenNI/Include") - elseif(UNIX OR APPLE) - set(OPENNI_INCLUDE_DIR "/usr/include/ni") - endif() - - # the check: are PrimeSensor Modules for OpenNI installed? - if(WIN32) - find_file(PRIME_SENSOR_MODULES_FOR_OPENNI "XnCore.dll" PATHS "c:/Program Files/Prime Sense/Sensor/Bin" DOC "Core library of PrimeSensor Modules for OpenNI") - elseif(UNIX OR APPLE) - find_library(PRIME_SENSOR_MODULES_FOR_OPENNI "XnCore" PATHS "/usr/lib" DOC "Core library of PrimeSensor Modules for OpenNI") - endif() - if(PRIME_SENSOR_MODULES_FOR_OPENNI) - set(HAVE_PRIME_SENSOR_FOR_OPENNI TRUE) - endif() - - endif() #if(OPENNI_LIBRARY) - -endif() #if(WITH_OPENNI) + include(OpenCVFindOpenNI.cmake) +endif() ############################## Eigen2 ############################## @@ -1383,11 +1357,11 @@ else() message(STATUS " OpenEXR: NO") endif() -if(NOT HAVE_OPENNI OR HAVE_PRIME_SENSOR_FOR_OPENNI) +if(NOT HAVE_OPENNI OR HAVE_OPENNI_PRIME_SENSOR_MODULE) message(STATUS " OpenNI: ${HAVE_OPENNI}") else() -message(STATUS " OpenNI: ${HAVE_OPENNI} (WARNING: PrimeSensor Modules for OpenNI are not installed.)") -endif() #if(NOT HAVE_OPENNI OR HAVE_PRIME_SENSOR_FOR_OPENNI) +message(STATUS " OpenNI: ${HAVE_OPENNI} (WARNING: PrimeSensor Modules for OpenNI are not installed (not found in OPENNI_PRIME_SENSOR_MODULE_BIN_DIR).)") +endif() if(UNIX AND NOT APPLE) message(STATUS "") diff --git a/OpenCVFindOpenNI.cmake b/OpenCVFindOpenNI.cmake new file mode 100644 index 000000000..9efc137dd --- /dev/null +++ b/OpenCVFindOpenNI.cmake @@ -0,0 +1,82 @@ +# Main variables: +# OPENNI_LIBRARY and OPENNI_INCLUDES to link OpenCV modules with OpenNI +# HAVE_OPENNI for conditional compilation OpenCV with/without OpenNI + +set(OPENNI_LIB_DESCR "Path to the directory of OpenNI libraries" CACHE INTERNAL "Description" ) +set(OPENNI_INCLUDE_DESCR "Path to the directory of OpenNI includes" CACHE INTERNAL "Description" ) +set(OPENNI_PRIME_SENSOR_MODULE_BIN_DESCR "Path to the directory of PrimeSensor Module binaries" CACHE INTERNAL "Description" ) + +if(NOT "${OPENNI_LIB_DIR}" STREQUAL "${OPENNI_LIB_DIR_INTERNAL}") + unset(OPENNI_LIBRARY CACHE) +endif() + +if(NOT "${OPENNI_INCLUDE_DIR}" STREQUAL "${OPENNI_INCLUDE_DIR_INTERNAL}") + unset(OPENNI_INCLUDES CACHE) +endif() + +if(NOT "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}" STREQUAL "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}") + unset(OPENNI_PRIME_SENSOR_MODULE CACHE) +endif() + +if(NOT OPENNI_LIB_DIR OR OPENNI_LIB_DIR STREQUAL "") + if(WIN32) + set(OPENNI_LIB_DIR "c:/Program Files/OpenNI/Lib" CACHE PATH ${OPENNI_LIB_DESCR}) + elseif(UNIX OR APPLE) + set(OPENNI_LIB_DIR "/usr/lib" CACHE PATH ${OPENNI_LIB_DESCR}) + endif() +endif() + +if(NOT OPENNI_INCLUDE_DIR OR OPENNI_INCLUDE_DIR STREQUAL "") + if(WIN32) + set(OPENNI_INCLUDE_DIR "c:/Program Files/OpenNI/Include" CACHE PATH ${OPENNI_INCLUDE_DESCR}) + elseif(UNIX OR APPLE) + set(OPENNI_INCLUDE_DIR "/usr/include/ni" CACHE PATH ${OPENNI_INCLUDE_DESCR}) + endif() +endif() + +if(NOT OPENNI_PRIME_SENSOR_MODULE_BIN_DIR OR OPENNI_PRIME_SENSOR_MODULE_BIN_DIR STREQUAL "") + if(WIN32) + set(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR "c:/Program Files/Prime Sense/Sensor/Bin" CACHE PATH ${OPENNI_PRIME_SENSOR_MODULE_BIN_DESCR}) + elseif(UNIX OR APPLE) + set(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR "/usr/lib" CACHE PATH ${OPENNI_PRIME_SENSOR_MODULE_BIN_DESCR}) + endif() +endif() + +find_library(OPENNI_LIBRARY "OpenNI" PATHS ${OPENNI_LIB_DIR} DOC "OpenNI library" NO_DEFAULT_PATH) +find_path(OPENNI_INCLUDES "XnCppWrapper.h" PATHS ${OPENNI_INCLUDE_DIR} DOC "OpenNI c++ interface header" NO_DEFAULT_PATH) + +if(OPENNI_LIBRARY AND OPENNI_INCLUDES) + set(HAVE_OPENNI TRUE) + # the check: are PrimeSensor Modules for OpenNI installed? + if(WIN32) + find_file(OPENNI_PRIME_SENSOR_MODULE "XnCore.dll" PATHS ${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR} DOC "Core library of PrimeSensor Modules for OpenNI" NO_DEFAULT_PATH) + elseif(UNIX OR APPLE) + find_library(OPENNI_PRIME_SENSOR_MODULE "XnCore" PATHS ${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR} DOC "Core library of PrimeSensor Modules for OpenNI" NO_DEFAULT_PATH) + endif() + + if(OPENNI_PRIME_SENSOR_MODULE) + set(HAVE_OPENNI_PRIME_SENSOR_MODULE TRUE) + endif() +endif() #if(OPENNI_LIBRARY AND OPENNI_INCLUDES) + +if(OPENNI_LIBRARY) + set(OPENNI_LIB_DIR_INTERNAL "${OPENNI_LIB_DIR}" CACHE INTERNAL "This is the value of the last time OPENNI_LIB_DIR was set successfully." FORCE) +else() + set(OPENNI_LIB_DIR "${OPENNI_LIB_DIR}-NOTFOUND or does not have OpenNI libraries" CACHE PATH ${OPENNI_LIB_DESCR} FORCE) +endif() + +if(OPENNI_INCLUDES) + set(OPENNI_INCLUDE_DIR_INTERNAL "${OPENNI_INCLUDE_DIR}" CACHE INTERNAL "This is the value of the last time OPENNI_INCLUDE_DIR was set successfully." FORCE) +else() + set(OPENNI_INCLUDE_DIR "${OPENNI_INCLUDE_DIR}-NOTFOUND or does not have OpenNI includes" CACHE PATH ${OPENNI_INCLUDE_DESCR} FORCE) +endif() + +if(OPENNI_PRIME_SENSOR_MODULE) + set(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR_INTERNAL "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}" CACHE INTERNAL "This is the value of the last time OPENNI_PRIME_SENSOR_MODULE_BIN_DIR was set successfully." FORCE) +else() + set(OPENNI_PRIME_SENSOR_MODULE_BIN_DIR "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}-NOTFOUND or does not have PrimeSensor Module binaries" CACHE PATH ${OPENNI_PRIME_SENSOR_MODULE_BIN_DESCR} FORCE) +endif() + +mark_as_advanced(FORCE OPENNI_PRIME_SENSOR_MODULE) +mark_as_advanced(FORCE OPENNI_LIBRARY) +mark_as_advanced(FORCE OPENNI_INCLUDES) diff --git a/doc/user_guide/user_highgui.tex b/doc/user_guide/user_highgui.tex index 33f7e6be3..39954fd40 100644 --- a/doc/user_guide/user_highgui.tex +++ b/doc/user_guide/user_highgui.tex @@ -13,8 +13,7 @@ output can be retrieved by using familiar interface of \texttt{VideoCapture}.\pa In order to use Kinect with OpenCV you should do the following preliminary steps:\newline 1) Install OpenNI library and PrimeSensor Module for OpenNI from here \url{http://www.openni.org/downloadfiles}. -The installation should be done to default folders listed in the instruc- -tions of these products: +The installation should be done to default folders listed in the instructions of these products: \begin{lstlisting} OpenNI: Linux & MacOSX: @@ -25,12 +24,13 @@ OpenNI: Includes into: c:/Program Files/OpenNI/Include PrimeSensor Module: Linux & MacOSX: - Libs into: /usr/lib Bins into: /usr/bin Windows: - Libs into: c:/Program Files/Prime Sense/Sensor/Lib Bins into: c:/Program Files/Prime Sense/Sensor/Bin \end{lstlisting} +If one or both products were installed to the other folders, the user should change corresponding CMake variables +(\texttt{OPENNI\_LIB\_DIR}, \texttt{OPENNI\_INCLUDE\_DIR} or/and +\texttt{OPENNI\_PRIME\_SENSOR\_MODULE\_BIN\_DIR}).\newline 2) Configure OpenCV with OpenNI support by setting \texttt{WITH\_OPENNI} flag in CMake. If OpenNI is found in default install folders OpenCV will be built with OpenNI library regardless of whether PrimeSensor Module is found or not. If PrimeSensor Module was not found you will get a warning diff --git a/modules/highgui/include/opencv2/highgui/highgui_c.h b/modules/highgui/include/opencv2/highgui/highgui_c.h index 72b0f08fb..0a6838d42 100644 --- a/modules/highgui/include/opencv2/highgui/highgui_c.h +++ b/modules/highgui/include/opencv2/highgui/highgui_c.h @@ -334,7 +334,42 @@ enum CV_CAP_PROP_CONVERT_RGB =16, CV_CAP_PROP_WHITE_BALANCE =17, CV_CAP_PROP_RECTIFICATION =18, - CV_CAP_PROP_MONOCROME =19 + CV_CAP_PROP_MONOCROME =19, + + // OpenNI map generators + CV_CAP_OPENNI_DEPTH_GENERATOR = 0, + CV_CAP_OPENNI_IMAGE_GENERATOR = 1 << 31, + CV_CAP_OPENNI_GENERATORS_MASK = 1 << 31, + + // Properties of cameras avalible through OpenNI interfaces + CV_CAP_PROP_OPENNI_OUTPUT_MODE = 20, + CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH = 21, // in mm + CV_CAP_PROP_OPENNI_BASELINE = 22, // in mm + CV_CAP_PROP_OPENNI_FOCAL_LENGTH = 23, // in pixels + 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_FOCAL_LENGTH = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_FOCAL_LENGTH +}; + +enum +{ + // Data given from depth generator. + CV_CAP_OPENNI_DEPTH_MAP = 0, // Depth values in mm (CV_16UC1) + CV_CAP_OPENNI_POINT_CLOUD_MAP = 1, // XYZ in meters (CV_32FC3) + CV_CAP_OPENNI_DISPARITY_MAP = 2, // Disparity in pixels (CV_8UC1) + CV_CAP_OPENNI_DISPARITY_MAP_32F = 3, // Disparity in pixels (CV_32FC1) + CV_CAP_OPENNI_VALID_DEPTH_MASK = 4, // CV_8UC1 + + // Data given from RGB image generator. + CV_CAP_OPENNI_BGR_IMAGE = 5, + CV_CAP_OPENNI_GRAY_IMAGE = 6 +}; + +// Supported output modes of OpenNI image generator +enum +{ + CV_CAP_OPENNI_VGA_30HZ = 0, + CV_CAP_OPENNI_SXGA_15HZ = 1 }; /* retrieve or set capture properties */ @@ -369,50 +404,6 @@ CVAPI(int) cvWriteFrame( CvVideoWriter* writer, const IplImage* image ); /* close video file writer */ CVAPI(void) cvReleaseVideoWriter( CvVideoWriter** writer ); -enum -{ - // Data given from depth generator. - OPENNI_DEPTH_MAP = 0, // Depth values in mm (CV_16UC1) - OPENNI_POINT_CLOUD_MAP = 1, // XYZ in meters (CV_32FC3) - OPENNI_DISPARITY_MAP = 2, // Disparity in pixels (CV_8UC1) - OPENNI_DISPARITY_MAP_32F = 3, // Disparity in pixels (CV_32FC1) - OPENNI_VALID_DEPTH_MASK = 4, // CV_8UC1 - - // Data given from RGB image generator. - OPENNI_BGR_IMAGE = 5, - OPENNI_GRAY_IMAGE = 6 -}; - -// OpenNI map generators -enum -{ - OPENNI_DEPTH_GENERATOR = 0, - OPENNI_IMAGE_GENERATOR = 1 << 31 -}; - -// Properties of cameras avalible through OpenNI interfaces -// (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; - /****************************************************************************************\ * Obsolete functions/synonyms * \****************************************************************************************/ diff --git a/modules/highgui/src/cap_openni.cpp b/modules/highgui/src/cap_openni.cpp index c69cf30b3..e4ab55556 100644 --- a/modules/highgui/src/cap_openni.cpp +++ b/modules/highgui/src/cap_openni.cpp @@ -84,13 +84,15 @@ const std::string XMLConfig = class CvCapture_OpenNI : public CvCapture { public: + static const int INVALID_PIXEL_VAL = 0; + CvCapture_OpenNI(); virtual ~CvCapture_OpenNI(); - virtual double getProperty(int); - virtual bool setProperty(int, double); + virtual double getProperty(int propIdx); + virtual bool setProperty(int probIdx, double propVal); virtual bool grabFrame(); - virtual IplImage* retrieveFrame(int); + virtual IplImage* retrieveFrame(int outputType); bool isOpened() const; @@ -116,10 +118,10 @@ protected: void readCamerasParams(); - double getDepthGeneratorProperty(int); - bool setDepthGeneratorProperty(int, double); - double getImageGeneratorProperty(int); - bool setImageGeneratorProperty(int, double); + double getDepthGeneratorProperty(int propIdx); + bool setDepthGeneratorProperty(int propIdx, double propVal); + double getImageGeneratorProperty(int propIdx); + bool setImageGeneratorProperty(int propIdx, double propVal); // OpenNI context xn::Context context; @@ -135,12 +137,12 @@ protected: XnMapOutputMode imageOutputMode; // Cameras settings: -#if 1 + // 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) XnDouble baseline; // Focal length for the IR camera in VGA resolution (in pixels) XnUInt64 depthFocalLength_VGA; -#endif + // The value for shadow (occluded pixels) XnUInt64 shadowValue; // The value for pixels without a valid disparity measurement @@ -230,7 +232,6 @@ CvCapture_OpenNI::~CvCapture_OpenNI() void CvCapture_OpenNI::readCamerasParams() { -#if 1 XnDouble pixelSize = 0; if( depthGenerator.GetRealProperty( "ZPPS", pixelSize ) != XN_STATUS_OK ) CV_Error( CV_StsError, "Could not read pixel size!" ); @@ -239,8 +240,8 @@ void CvCapture_OpenNI::readCamerasParams() pixelSize *= 2.0; // in mm // focal length of IR camera in pixels for VGA resolution - XnUInt64 zpd; // in mm - if( depthGenerator.GetIntProperty( "ZPD", zpd ) != XN_STATUS_OK ) + XnUInt64 zeroPlanDistance; // in mm + if( depthGenerator.GetIntProperty( "ZPD", zeroPlanDistance ) != XN_STATUS_OK ) CV_Error( CV_StsError, "Could not read virtual plane distance!" ); if( depthGenerator.GetRealProperty( "LDDIS", baseline ) != XN_STATUS_OK ) @@ -250,14 +251,13 @@ void CvCapture_OpenNI::readCamerasParams() baseline *= 10; // focal length from mm -> pixels (valid for 640x480) - depthFocalLength_VGA = (XnUInt64)((double)zpd / (double)pixelSize); -#endif + depthFocalLength_VGA = (XnUInt64)((double)zeroPlanDistance / (double)pixelSize); if( depthGenerator.GetIntProperty( "ShadowValue", shadowValue ) != XN_STATUS_OK ) - CV_Error( CV_StsError, "Could not read shadow value!" ); + CV_Error( CV_StsError, "Could not read property \"ShadowValue\"!" ); if( depthGenerator.GetIntProperty("NoSampleValue", noSampleValue ) != XN_STATUS_OK ) - CV_Error( CV_StsError, "Could not read no sample value!" ); + CV_Error( CV_StsError, "Could not read property \"NoSampleValue\"!" ); } double CvCapture_OpenNI::getProperty( int propIdx ) @@ -266,13 +266,19 @@ double CvCapture_OpenNI::getProperty( int propIdx ) if( isOpened() ) { - if( propIdx & OPENNI_IMAGE_GENERATOR ) + int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK; + + if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR ) { - propValue = getImageGeneratorProperty( propIdx ^ OPENNI_IMAGE_GENERATOR ); + propValue = getImageGeneratorProperty( purePropIdx ); } - else // depth generator (by default, OPENNI_DEPTH_GENERATOR == 0) + else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR ) { - propValue = getDepthGeneratorProperty( propIdx /*^ OPENNI_DEPTH_GENERATOR*/ ); + propValue = getDepthGeneratorProperty( purePropIdx ); + } + else + { + CV_Error( CV_StsError, "Unsupported generator prefix!" ); } } @@ -284,13 +290,19 @@ bool CvCapture_OpenNI::setProperty( int propIdx, double propValue ) bool res = false; if( isOpened() ) { - if( propIdx & OPENNI_IMAGE_GENERATOR ) + int purePropIdx = propIdx & ~CV_CAP_OPENNI_GENERATORS_MASK; + + if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IMAGE_GENERATOR ) { - res = setImageGeneratorProperty( propIdx ^ OPENNI_IMAGE_GENERATOR, propValue ); + res = setImageGeneratorProperty( purePropIdx, propValue ); } - else // depth generator (by default, OPENNI_DEPTH_GENERATOR == 0) + else if( (propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_DEPTH_GENERATOR ) { - res = setDepthGeneratorProperty( propIdx /*^ OPENNI_DEPTH_GENERATOR*/, propValue ); + res = setDepthGeneratorProperty( purePropIdx, propValue ); + } + else + { + CV_Error( CV_StsError, "Unsupported generator prefix!" ); } } @@ -313,13 +325,13 @@ double CvCapture_OpenNI::getDepthGeneratorProperty( int propIdx ) case CV_CAP_PROP_FPS : res = depthOutputMode.nFPS; break; - case OPENNI_FRAME_MAX_DEPTH : + case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH : res = depthGenerator.GetDeviceMaxDepth(); break; - case OPENNI_BASELINE : + case CV_CAP_PROP_OPENNI_BASELINE : res = baseline; break; - case OPENNI_FOCAL_LENGTH : + case CV_CAP_PROP_OPENNI_FOCAL_LENGTH : res = depthFocalLength_VGA; break; default : @@ -333,6 +345,7 @@ 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"); + return false; } double CvCapture_OpenNI::getImageGeneratorProperty( int propIdx ) @@ -366,15 +379,15 @@ bool CvCapture_OpenNI::setImageGeneratorProperty( int propIdx, double propValue XnMapOutputMode newImageOutputMode = imageOutputMode; switch( propIdx ) { - case OPENNI_OUTPUT_MODE : + case CV_CAP_PROP_OPENNI_OUTPUT_MODE : switch( cvRound(propValue) ) { - case OPENNI_VGA_30HZ : + case CV_CAP_OPENNI_VGA_30HZ : newImageOutputMode.nXRes = XN_VGA_X_RES; newImageOutputMode.nYRes = XN_VGA_Y_RES; newImageOutputMode.nFPS = 30; break; - case OPENNI_SXGA_15HZ : + case CV_CAP_OPENNI_SXGA_15HZ : newImageOutputMode.nXRes = XN_SXGA_X_RES; newImageOutputMode.nYRes = XN_SXGA_Y_RES; newImageOutputMode.nFPS = 15; @@ -402,7 +415,7 @@ bool CvCapture_OpenNI::grabFrame() if( !isOpened() ) return false; - XnStatus status = context.WaitAnyUpdateAll(); + XnStatus status = context.WaitAndUpdateAll(); if( status != XN_STATUS_OK ) return false; @@ -426,7 +439,7 @@ inline void getDepthMapFromMetaData( const xn::DepthMetaData& depthMetaData, cv: cv::Mat badMask = (depthMap == noSampleValue) | (depthMap == shadowValue) | (depthMap == 0); // mask the pixels with invalid depth - depthMap.setTo( cv::Scalar::all( OPENNI_BAD_DEPTH_VAL ), badMask ); + depthMap.setTo( cv::Scalar::all( CvCapture_OpenNI::INVALID_PIXEL_VAL ), badMask ); } IplImage* CvCapture_OpenNI::retrieveDepthMap() @@ -434,9 +447,9 @@ IplImage* CvCapture_OpenNI::retrieveDepthMap() if( depthMetaData.XRes() <= 0 || depthMetaData.YRes() <= 0 ) return 0; - getDepthMapFromMetaData( depthMetaData, outputMaps[OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue ); + getDepthMapFromMetaData( depthMetaData, outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue ); - return outputMaps[OPENNI_DEPTH_MAP].getIplImagePtr(); + return outputMaps[CV_CAP_OPENNI_DEPTH_MAP].getIplImagePtr(); } IplImage* CvCapture_OpenNI::retrievePointCloudMap() @@ -449,7 +462,7 @@ IplImage* CvCapture_OpenNI::retrievePointCloudMap() getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue ); const float badPoint = 0; - cv::Mat XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) ); + cv::Mat pointCloud_XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) ); for( int y = 0; y < rows; y++ ) { @@ -458,7 +471,7 @@ IplImage* CvCapture_OpenNI::retrievePointCloudMap() unsigned short d = depth.at(y, x); // Check for invalid measurements - if( d == OPENNI_BAD_DEPTH_VAL ) // not valid + if( d == CvCapture_OpenNI::INVALID_PIXEL_VAL ) // not valid continue; XnPoint3D proj, real; @@ -466,13 +479,13 @@ IplImage* CvCapture_OpenNI::retrievePointCloudMap() proj.Y = y; proj.Z = d; depthGenerator.ConvertProjectiveToRealWorld(1, &proj, &real); - XYZ.at(y,x) = cv::Point3f( real.X*0.001f, real.Y*0.001f, real.Z*0.001f); // from mm to meters + pointCloud_XYZ.at(y,x) = cv::Point3f( real.X*0.001f, real.Y*0.001f, real.Z*0.001f); // from mm to meters } } - outputMaps[OPENNI_POINT_CLOUD_MAP].mat = XYZ; + outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].mat = pointCloud_XYZ; - return outputMaps[OPENNI_POINT_CLOUD_MAP].getIplImagePtr(); + return outputMaps[CV_CAP_OPENNI_POINT_CLOUD_MAP].getIplImagePtr(); } void computeDisparity_32F( const xn::DepthMetaData& depthMetaData, cv::Mat& disp, XnDouble baseline, XnUInt64 F, @@ -488,13 +501,13 @@ void computeDisparity_32F( const xn::DepthMetaData& depthMetaData, cv::Mat& disp float mult = baseline /*mm*/ * F /*pixels*/; disp.create( depth.size(), CV_32FC1); - disp = cv::Scalar::all( OPENNI_BAD_DISP_VAL ); + disp = cv::Scalar::all( CvCapture_OpenNI::INVALID_PIXEL_VAL ); for( int y = 0; y < disp.rows; y++ ) { for( int x = 0; x < disp.cols; x++ ) { unsigned short curDepth = depth.at(y,x); - if( curDepth != OPENNI_BAD_DEPTH_VAL ) + if( curDepth != CvCapture_OpenNI::INVALID_PIXEL_VAL ) disp.at(y,x) = mult / curDepth; } } @@ -508,9 +521,9 @@ IplImage* CvCapture_OpenNI::retrieveDisparityMap() cv::Mat disp32; computeDisparity_32F( depthMetaData, disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue ); - disp32.convertTo( outputMaps[OPENNI_DISPARITY_MAP].mat, CV_8UC1 ); + disp32.convertTo( outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1 ); - return outputMaps[OPENNI_DISPARITY_MAP].getIplImagePtr(); + return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].getIplImagePtr(); } IplImage* CvCapture_OpenNI::retrieveDisparityMap_32F() @@ -518,9 +531,9 @@ IplImage* CvCapture_OpenNI::retrieveDisparityMap_32F() if( depthMetaData.XRes() <= 0 || depthMetaData.YRes() <= 0 ) return 0; - computeDisparity_32F( depthMetaData, outputMaps[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 ); - return outputMaps[OPENNI_DISPARITY_MAP_32F].getIplImagePtr(); + return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].getIplImagePtr(); } IplImage* CvCapture_OpenNI::retrieveValidDepthMask() @@ -531,9 +544,9 @@ IplImage* CvCapture_OpenNI::retrieveValidDepthMask() cv::Mat depth; getDepthMapFromMetaData( depthMetaData, depth, noSampleValue, shadowValue ); - outputMaps[OPENNI_VALID_DEPTH_MASK].mat = depth != OPENNI_BAD_DEPTH_VAL; + outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].mat = depth != CvCapture_OpenNI::INVALID_PIXEL_VAL; - return outputMaps[OPENNI_VALID_DEPTH_MASK].getIplImagePtr(); + return outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].getIplImagePtr(); } inline void getBGRImageFromMetaData( const xn::ImageMetaData& imageMetaData, cv::Mat& bgrImage ) @@ -555,9 +568,9 @@ IplImage* CvCapture_OpenNI::retrieveBGRImage() if( imageMetaData.XRes() <= 0 || imageMetaData.YRes() <= 0 ) return 0; - getBGRImageFromMetaData( imageMetaData, outputMaps[OPENNI_BGR_IMAGE].mat ); + getBGRImageFromMetaData( imageMetaData, outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat ); - return outputMaps[OPENNI_BGR_IMAGE].getIplImagePtr(); + return outputMaps[CV_CAP_OPENNI_BGR_IMAGE].getIplImagePtr(); } IplImage* CvCapture_OpenNI::retrieveGrayImage() @@ -569,41 +582,41 @@ IplImage* CvCapture_OpenNI::retrieveGrayImage() cv::Mat rgbImage; getBGRImageFromMetaData( imageMetaData, rgbImage ); - cv::cvtColor( rgbImage, outputMaps[OPENNI_GRAY_IMAGE].mat, CV_BGR2GRAY ); + cv::cvtColor( rgbImage, outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].mat, CV_BGR2GRAY ); - return outputMaps[OPENNI_GRAY_IMAGE].getIplImagePtr(); + return outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].getIplImagePtr(); } -IplImage* CvCapture_OpenNI::retrieveFrame( int dataType ) +IplImage* CvCapture_OpenNI::retrieveFrame( int outputType ) { IplImage* image = 0; - CV_Assert( dataType < outputTypesCount && dataType >= 0); + CV_Assert( outputType < outputTypesCount && outputType >= 0); - if( dataType == OPENNI_DEPTH_MAP ) + if( outputType == CV_CAP_OPENNI_DEPTH_MAP ) { image = retrieveDepthMap(); } - else if( dataType == OPENNI_POINT_CLOUD_MAP ) + else if( outputType == CV_CAP_OPENNI_POINT_CLOUD_MAP ) { image = retrievePointCloudMap(); } - else if( dataType == OPENNI_DISPARITY_MAP ) + else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP ) { image = retrieveDisparityMap(); } - else if( dataType == OPENNI_DISPARITY_MAP_32F ) + else if( outputType == CV_CAP_OPENNI_DISPARITY_MAP_32F ) { image = retrieveDisparityMap_32F(); } - else if( dataType == OPENNI_VALID_DEPTH_MASK ) + else if( outputType == CV_CAP_OPENNI_VALID_DEPTH_MASK ) { image = retrieveValidDepthMask(); } - else if( dataType == OPENNI_BGR_IMAGE ) + else if( outputType == CV_CAP_OPENNI_BGR_IMAGE ) { image = retrieveBGRImage(); } - else if( dataType == OPENNI_GRAY_IMAGE ) + else if( outputType == CV_CAP_OPENNI_GRAY_IMAGE ) { image = retrieveGrayImage(); } diff --git a/samples/cpp/kinect_maps.cpp b/samples/cpp/kinect_maps.cpp index b3dc31902..7ac7542b6 100644 --- a/samples/cpp/kinect_maps.cpp +++ b/samples/cpp/kinect_maps.cpp @@ -6,9 +6,22 @@ using namespace cv; using namespace std; -#define COLORIZED_DISP 1 -#define IMAGE_GENERATOR_VGA_30HZ 1 -#define FIXED_MAX_DISP 0 +void help() +{ + cout << "\nThis program demonstrates usage of Kinect sensor.\n" + "The user gets some of the supported output images.\n" + "\nAll supported output map types:\n" + "1.) Data given from depth generator\n" + " OPENNI_DEPTH_MAP - depth values in mm (CV_16UC1)\n" + " OPENNI_POINT_CLOUD_MAP - XYZ in meters (CV_32FC3)\n" + " OPENNI_DISPARITY_MAP - disparity in pixels (CV_8UC1)\n" + " OPENNI_DISPARITY_MAP_32F - disparity in pixels (CV_32FC1)\n" + " OPENNI_VALID_DEPTH_MASK - mask of valid pixels (not ocluded, not shaded etc.) (CV_8UC1)\n" + "2.) Data given from RGB image generator\n" + " OPENNI_BGR_IMAGE - color image (CV_8UC3)\n" + " OPENNI_GRAY_IMAGE - gray image (CV_8UC1)\n" + << endl; +} void colorizeDisparity( const Mat& gray, Mat& rgb, double maxDisp=-1.f, float S=1.f, float V=1.f ) { @@ -59,45 +72,98 @@ void colorizeDisparity( const Mat& gray, Mat& rgb, double maxDisp=-1.f, float S= } } -void help() -{ - cout << "\nThis program demonstrates usage of Kinect sensor.\n" - "The user gets some of the supported output images.\n" - "\nAll supported output map types:\n" - "1.) Data given from depth generator\n" - " OPENNI_DEPTH_MAP - depth values in mm (CV_16UC1)\n" - " OPENNI_POINT_CLOUD_MAP - XYZ in meters (CV_32FC3)\n" - " OPENNI_DISPARITY_MAP - disparity in pixels (CV_8UC1)\n" - " OPENNI_DISPARITY_MAP_32F - disparity in pixels (CV_32FC1)\n" - " OPENNI_VALID_DEPTH_MASK - mask of valid pixels (not ocluded, not shaded etc.) (CV_8UC1)\n" - "2.) Data given from RGB image generator\n" - " OPENNI_BGR_IMAGE - color image (CV_8UC3)\n" - " OPENNI_GRAY_IMAGE - gray image (CV_8UC1)\n" - << 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 + float b = capture.get( CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE ); // mm + float F = capture.get( CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH ); // pixels return b * F / minDistance; -#else - return -1; -#endif +} + +void printCommandLineParams() +{ + cout << "-cd Colorized disparity? (0 or 1; 1 by default) Ignored if disparity map is not selected to show." << endl; + cout << "-fmd Fixed max disparity? (0 or 1; 0 by default) Ignored if disparity map is not colorized (-cd 0)." << endl; + cout << "-sxga SXGA resolution of image? (0 or 1; 0 by default) Ignored if rgb image or gray image are not selected to show." << endl; + cout << " If -sxga is 0 then vga resolution will be set by default." << endl; + cout << "-m Mask to set which output images are need. It is a string of size 5. Each element of this is '0' or '1' and" << endl; + cout << " determine: is depth map, disparity map, valid pixels mask, rgb image, gray image need or not (correspondently)?" << endl ; + cout << " By default -m 01010 i.e. disparity map and rgb image will be shown." << endl ; +} + +void parseCommandLine( int argc, char* argv[], bool& isColorizeDisp, bool& isFixedMaxDisp, bool& isSetSXGA, bool retrievedImageFlags[] ) +{ + // set defaut values + isColorizeDisp = true; + isSetSXGA = false; + retrievedImageFlags[0] = false; + retrievedImageFlags[1] = true; + retrievedImageFlags[2] = false; + retrievedImageFlags[3] = true; + retrievedImageFlags[4] = false; + + if( argc == 1 ) + { + help(); + } + else + { + for( int i = 1; i < argc; i++ ) + { + if( !strcmp( argv[i], "--help" ) ) + { + printCommandLineParams(); + exit(0); + } + else if( !strcmp( argv[i], "-cd" ) ) + { + isColorizeDisp = atoi(argv[++i]) == 0 ? false : true; + } + else if( !strcmp( argv[i], "-fmd" ) ) + { + isFixedMaxDisp = atoi(argv[++i]) == 0 ? false : true; + } + else if( !strcmp( argv[i], "-sxga" ) ) + { + isSetSXGA = atoi(argv[++i]) == 0 ? false : true; + } + else if( !strcmp( argv[i], "-m" ) ) + { + string mask( argv[++i] ); + if( mask.size() != 5) + CV_Error( CV_StsBadArg, "Incorrect length of -m argument string" ); + int val = atoi(mask.c_str()); + + int l = 100000, r = 10000, sum = 0; + for( int i = 0; i < 5; i++ ) + { + retrievedImageFlags[i] = ((val % l) / r ) == 0 ? false : true; + l /= 10; r /= 10; + if( retrievedImageFlags[i] ) sum++; + } + + if( sum == 0 ) + { + cout << "No one output image is selected." << endl; + exit(0); + } + } + } + } } /* * 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). */ -int main() +int main( int argc, char* argv[] ) { - help(); + bool isColorizeDisp, isFixedMaxDisp, isSetSXGA; + bool retrievedImageFlags[5]; + parseCommandLine( argc, argv, isColorizeDisp, isFixedMaxDisp, isSetSXGA, retrievedImageFlags ); cout << "Kinect opening ..." << endl; - VideoCapture capture(0); // or CV_CAP_OPENNI + VideoCapture capture( CV_CAP_OPENNI ); cout << "done." << endl; if( !capture.isOpened() ) @@ -106,23 +172,22 @@ 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 + if( isSetSXGA ) + capture.set( CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE, CV_CAP_OPENNI_SXGA_15HZ ); + else + capture.set( CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE, CV_CAP_OPENNI_VGA_30HZ ); // default // Print some avalible Kinect settings. cout << "\nDepth 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 << + "FRAME_MAX_DEPTH " << capture.get( CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH ) << " mm" << endl << "FPS " << capture.get( CV_CAP_PROP_FPS ) << endl; cout << "\nImage 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; + "FRAME_WIDTH " << capture.get( CV_CAP_OPENNI_IMAGE_GENERATOR+CV_CAP_PROP_FRAME_WIDTH ) << endl << + "FRAME_HEIGHT " << capture.get( CV_CAP_OPENNI_IMAGE_GENERATOR+CV_CAP_PROP_FRAME_HEIGHT ) << endl << + "FPS " << capture.get( CV_CAP_OPENNI_IMAGE_GENERATOR+CV_CAP_PROP_FPS ) << endl; for(;;) { @@ -139,33 +204,36 @@ int main() } else { - if( capture.retrieve( depthMap, OPENNI_DEPTH_MAP ) ) + if( retrievedImageFlags[0] && capture.retrieve( depthMap, CV_CAP_OPENNI_DEPTH_MAP ) ) { const float scaleFactor = 0.05f; Mat show; depthMap.convertTo( show, CV_8UC1, scaleFactor ); imshow( "depth map", show ); } - if( capture.retrieve( disparityMap, OPENNI_DISPARITY_MAP ) ) + if( retrievedImageFlags[1] && capture.retrieve( disparityMap, CV_CAP_OPENNI_DISPARITY_MAP ) ) { -#if COLORIZED_DISP // colorized disparity for more visibility - Mat 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 + if( isColorizeDisp ) + { + Mat colorDisparityMap; + colorizeDisparity( disparityMap, colorDisparityMap, isFixedMaxDisp ? getMaxDisparity(capture) : -1 ); + Mat validColorDisparityMap; + colorDisparityMap.copyTo( validColorDisparityMap, disparityMap != 0 ); + imshow( "colorized disparity map", validColorDisparityMap ); + } + else + { + imshow( "original disparity map", disparityMap ); + } } - if( capture.retrieve( validDepthMap, OPENNI_VALID_DEPTH_MASK ) ) + if( retrievedImageFlags[2] && capture.retrieve( validDepthMap, CV_CAP_OPENNI_VALID_DEPTH_MASK ) ) imshow( "valid depth mask", validDepthMap ); - if( capture.retrieve( bgrImage, OPENNI_BGR_IMAGE ) ) + if( retrievedImageFlags[3] && capture.retrieve( bgrImage, CV_CAP_OPENNI_BGR_IMAGE ) ) imshow( "rgb image", bgrImage ); - if( capture.retrieve( grayImage, OPENNI_GRAY_IMAGE ) ) + if( retrievedImageFlags[4] && capture.retrieve( grayImage, CV_CAP_OPENNI_GRAY_IMAGE ) ) imshow( "gray image", grayImage ); }