#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/calib3d/calib3d.hpp" #include "opencv2/contrib/contrib.hpp" #include "opencv2/highgui/highgui.hpp" #include #include #include using namespace cv; using namespace std; static void cvtDepth2Cloud( const Mat& depth, Mat& cloud, const Mat& cameraMatrix ) { const float inv_fx = 1.f/cameraMatrix.at(0,0); const float inv_fy = 1.f/cameraMatrix.at(1,1); const float ox = cameraMatrix.at(0,2); const float oy = cameraMatrix.at(1,2); cloud.create( depth.size(), CV_32FC3 ); for( int y = 0; y < cloud.rows; y++ ) { Point3f* cloud_ptr = (Point3f*)cloud.ptr(y); const float* depth_prt = (const float*) depth.ptr(y); for( int x = 0; x < cloud.cols; x++ ) { float z = depth_prt[x]; cloud_ptr[x].x = (x - ox) * z * inv_fx; cloud_ptr[x].y = (y - oy) * z * inv_fy; cloud_ptr[x].z = z; } } } template static void warpImage( const Mat& image, const Mat& depth, const Mat& Rt, const Mat& cameraMatrix, const Mat& distCoeff, Mat& warpedImage ) { const Rect rect = Rect(0, 0, image.cols, image.rows); vector points2d; Mat cloud, transformedCloud; cvtDepth2Cloud( depth, cloud, cameraMatrix ); perspectiveTransform( cloud, transformedCloud, Rt ); projectPoints( transformedCloud.reshape(3,1), Mat::eye(3,3,CV_64FC1), Mat::zeros(3,1,CV_64FC1), cameraMatrix, distCoeff, points2d ); Mat pointsPositions( points2d ); pointsPositions = pointsPositions.reshape( 2, image.rows ); warpedImage.create( image.size(), image.type() ); warpedImage = Scalar::all(0); Mat zBuffer( image.size(), CV_32FC1, FLT_MAX ); for( int y = 0; y < image.rows; y++ ) { for( int x = 0; x < image.cols; x++ ) { const Point3f p3d = transformedCloud.at(y,x); const Point p2d = pointsPositions.at(y,x); if( !cvIsNaN(cloud.at(y,x).z) && cloud.at(y,x).z > 0 && rect.contains(p2d) && zBuffer.at(p2d) > p3d.z ) { warpedImage.at(p2d) = image.at(y,x); zBuffer.at(p2d) = p3d.z; } } } } int main(int argc, char** argv) { float vals[] = {525., 0., 3.1950000000000000e+02, 0., 525., 2.3950000000000000e+02, 0., 0., 1.}; const Mat cameraMatrix = Mat(3,3,CV_32FC1,vals); const Mat distCoeff(1,5,CV_32FC1,Scalar(0)); if( argc != 5 && argc != 6 ) { cout << "Format: image0 depth0 image1 depth1 [transformationType]" << endl; cout << "Depth file must be 16U image stored depth in mm." << endl; cout << "Transformation types:" << endl; cout << " -rbm - rigid body motion (default)" << endl; cout << " -r - rotation rotation only" << endl; cout << " -t - translation only" << endl; return -1; } Mat colorImage0 = imread( argv[1] ); Mat depth0 = imread( argv[2], -1 ); Mat colorImage1 = imread( argv[3] ); Mat depth1 = imread( argv[4], -1 ); if( colorImage0.empty() || depth0.empty() || colorImage1.empty() || depth1.empty() ) { cout << "Data (rgb or depth images) is empty."; return -1; } int transformationType = TransformationType::RIGID_BODY_MOTION; if( argc == 6 ) { string ttype = argv[5]; if( ttype == "-rbm" ) { transformationType = TransformationType::RIGID_BODY_MOTION; } else if ( ttype == "-r") { transformationType = TransformationType::ROTATION; } else if ( ttype == "-t") { transformationType = TransformationType::TRANSLATION; } else { cout << "Unsupported transformation type." << endl; return -1; } } Mat grayImage0, grayImage1, depthFlt0, depthFlt1/*in meters*/; cvtColor( colorImage0, grayImage0, CV_BGR2GRAY ); cvtColor( colorImage1, grayImage1, CV_BGR2GRAY ); depth0.convertTo( depthFlt0, CV_32FC1, 1./1000 ); depth1.convertTo( depthFlt1, CV_32FC1, 1./1000 ); TickMeter tm; Mat Rt; vector iterCounts(4); iterCounts[0] = 7; iterCounts[1] = 7; iterCounts[2] = 7; iterCounts[3] = 10; vector minGradMagnitudes(4); minGradMagnitudes[0] = 12; minGradMagnitudes[1] = 5; minGradMagnitudes[2] = 3; minGradMagnitudes[3] = 1; const float minDepth = 0; //in meters const float maxDepth = 3; //in meters const float maxDepthDiff = 0.07; //in meters tm.start(); bool isFound = cv::RGBDOdometry( Rt, Mat(), grayImage0, depthFlt0, Mat(), grayImage1, depthFlt1, Mat(), cameraMatrix, minDepth, maxDepth, maxDepthDiff, iterCounts, minGradMagnitudes, transformationType ); tm.stop(); cout << "Rt = " << Rt << endl; cout << "Time = " << tm.getTimeSec() << " sec." << endl; if( !isFound ) { cout << "Rigid body motion cann't be estimated for given RGBD data." << endl; return -1; } Mat warpedImage0; warpImage >( colorImage0, depthFlt0, Rt, cameraMatrix, distCoeff, warpedImage0 ); imshow( "image0", colorImage0 ); imshow( "warped_image0", warpedImage0 ); imshow( "image1", colorImage1 ); waitKey(); return 0; }