createCubeModel.cpp
Go to the documentation of this file.
00001 
00059 #include "ros/ros.h"
00060 
00061 #include <iostream>
00062 #include <iomanip>
00063 #include <vector>
00064 #include <string>
00065 #include <sstream>
00066 
00067 #include <opencv/cv.h>
00068 #include <opencv/highgui.h>
00069 
00070 #include "../MetaFile.h"
00071 
00072 #include "DUtils.h"
00073 #include "DUtilsCV.h"
00074 #include "DVision.h"
00075 
00076 typedef DVision::PMVS::PLYFile PLYFile;
00077 typedef DVision::PMVS::PLYFile::PLYPoint PLYPoint;
00078 typedef DVision::Bundle::CameraFile::Camera Camera;
00079 
00080 using namespace std;
00081 
00082 // ---------------------------------------------------------------------------
00083 
00084 struct tParamsPatch
00085 {
00086   bool is_present;
00087   std::string image_filename;
00088   float w, h;
00089 };
00090 
00091 struct tParams
00092 {
00093   std::string object_name;
00094   std::string out_model_dir;
00095   float W, H, D;
00096   tParamsPatch patches[6];
00097   int hessian;
00098 };
00099 
00100 // ---------------------------------------------------------------------------
00101 
00114 void createPLYpoints(const cv::Mat &img, float width, float height,
00115   const cv::Mat& oTp,
00116   const DVision::SurfSet &surfset, std::vector<PLYPoint> &plypoints);
00117 
00127 void saveFace(const std::string &model_dir, int face_idx, const cv::Mat &img,
00128   const DVision::SurfSet &surfs, const std::vector<PLYPoint> &plypoints,
00129   const Camera &camera);
00130 
00138 bool parseParams(int argc, char *argv[], tParams &params);
00139 
00149 void cropImage(cv::Mat &im, float& current_width, float& current_height,
00150   float max_width, float max_height);
00151 
00160 void calculatePatchTransformations(std::vector<cv::Mat> &oTps,
00161   float W, float H, float D);
00162 
00173 void createCamera(const cv::Mat &im, float width, float height,
00174   const cv::Mat &oTp, Camera &camera);
00175 
00176 // ---------------------------------------------------------------------------
00177 
00178 static const int DEFAULT_HESSIAN_THRESHOLD = 300;
00179 
00180 // ---------------------------------------------------------------------------
00181 
00182 int main(int argc, char *argv[])
00183 {
00184   ros::init(argc, argv, "createCubeModel");
00185  
00186   tParams params;
00187   if(!parseParams(argc, argv, params))
00188   {
00189     ROS_WARN("Usage: createCubeModel <object name> <Wo> <Ho> <Do> "
00190       "<output model dir> "
00191       "{<patch A> <wa> <ha> | - } [ ... [ {<patch F> <wf> <hf> | - } "
00192       "[<surf threshold>] ] ]");
00193     return 1;
00194   }
00195 
00196   // max real width of each patch according to its position in the cuboid
00197   // and the real dimensions of the object
00198   float max_patch_width[] = { 
00199     params.W, // patch A
00200     params.D, // patch B
00201     params.W, // patch C
00202     params.D, // patch D
00203     params.W, // patch E
00204     params.W  // patch F
00205   };
00206   
00207   // idem for height
00208   float max_patch_height[] = { 
00209     params.H, // patch A
00210     params.H, // patch B
00211     params.H, // patch C
00212     params.H, // patch D
00213     params.D, // patch E
00214     params.D  // patch F
00215   };
00216 
00217   ROS_INFO("Computing the object coordinate frame...");
00218   vector<cv::Mat> oTps;
00219   calculatePatchTransformations(oTps, params.W, params.H, params.D);
00220 
00221   if(!DUtils::FileFunctions::DirExists(params.out_model_dir.c_str()))
00222     DUtils::FileFunctions::MkDir(params.out_model_dir.c_str());
00223 
00224   MetaFile::MetaData meta;
00225 
00226   int face_idx = 0;
00227   for(int patch_idx = 0; patch_idx < 6; ++patch_idx)
00228   {
00229     if(params.patches[patch_idx].is_present)
00230     {
00231       ROS_INFO(":: Patch %c", 'A' + patch_idx);
00232       const tParamsPatch& pp = params.patches[patch_idx];
00233       
00234       ROS_INFO("Reading image...");
00235       cv::Mat im = cv::imread(pp.image_filename, 1);
00236       
00237       float max_width = max_patch_width[patch_idx];
00238       float max_height = max_patch_height[patch_idx];
00239       
00240       float real_width = pp.w;
00241       float real_height = pp.h;
00242       
00243       if(real_width > max_width || real_height > max_height)
00244       {
00245         ROS_INFO("Patch size is %.3fx%.3f metres, but the maximum size is "
00246           "%.3fx%.3f. Cropping...", 
00247           real_width, real_height, max_width, max_height);
00248         
00249         cropImage(im, real_width, real_height, max_width, max_height);
00250       }
00251       
00252       ROS_INFO("Extracting SURFs (hessian threshold: %d)...", params.hessian);
00253       cv::Mat bw_img;
00254       if(im.depth() == 1) bw_img = im;
00255       else cv::cvtColor(im, bw_img, CV_BGR2GRAY);
00256       
00257       DVision::SurfSet surfset;
00258       surfset.Extract(bw_img, params.hessian);
00259       ROS_INFO("  %d points obtained", surfset.size());
00260 
00261       ROS_INFO("Computing 3D coords and camera info...");
00262       vector<PLYPoint> plypoints;
00263       createPLYpoints(im, real_width, real_height, oTps[patch_idx],
00264         surfset, plypoints);
00265       
00266       Camera camera;
00267       createCamera(im, real_width, real_height, oTps[patch_idx], camera);
00268       
00269       ROS_INFO("Saving face %d from patch %c...", face_idx, 'A' + patch_idx);
00270       saveFace(params.out_model_dir, face_idx, im, surfset, plypoints, camera);
00271       
00272       // save dimension info
00273       meta.Dimensions.Planar.Faces.push_back(MetaFile::MetaData::tFaceDim());
00274       MetaFile::MetaData::tFaceDim &face_dim = 
00275         meta.Dimensions.Planar.Faces.back();
00276       face_dim.Width = real_width;
00277       face_dim.Height = real_height;
00278       face_dim.oTf = oTps[patch_idx];
00279       
00280       face_idx++;
00281     }
00282   }
00283   
00284   ROS_INFO("Saving meta data...");
00285   meta.Name = params.object_name;
00286   meta.Type = "planar";
00287   meta.NFaces = meta.Dimensions.Planar.Faces.size();
00288   meta.Dimensions.Planar.Width = params.W;
00289   meta.Dimensions.Planar.Height = params.H;
00290   meta.Dimensions.Planar.Depth = params.D;
00291   
00292   MetaFile::saveFile(params.out_model_dir + "/meta.xml", meta);
00293   
00294   ROS_INFO("Done");
00295   
00296   return 0;
00297 }
00298 
00299 // ---------------------------------------------------------------------------
00300 
00301 bool parseParams(int argc, char *argv[], tParams &params)
00302 {
00303   if(argc < 9) return false;
00304   
00305   params.object_name = argv[1];
00306   params.W = atof(argv[2]);
00307   params.H = atof(argv[3]);
00308   params.D = atof(argv[4]);
00309   params.out_model_dir = argv[5];
00310   params.hessian = DEFAULT_HESSIAN_THRESHOLD;
00311   
00312   bool some_present = false;
00313   int patch_idx = 0;
00314   int i = 6;
00315   while(i < argc)
00316   {
00317     if(patch_idx == 6)
00318     {
00319       // reading surf threshold
00320       params.hessian = atoi(argv[i]);
00321       ++i;
00322     }
00323     else
00324     {
00325       // reading a face
00326       std::string s = argv[i];
00327       if(s == "-")
00328       {
00329         params.patches[patch_idx].is_present = false;
00330         ++patch_idx;
00331         ++i;
00332       }
00333       else
00334       {
00335         if(i + 2 < argc)
00336         {
00337           params.patches[patch_idx].is_present = true;
00338           some_present = true;
00339           
00340           params.patches[patch_idx].image_filename = argv[i];
00341           params.patches[patch_idx].w = atof(argv[i+1]);
00342           params.patches[patch_idx].h = atof(argv[i+2]);
00343 
00344           i += 3;
00345           ++patch_idx;
00346         }
00347         else{ return false; }
00348       }
00349     }
00350   }
00351   
00352   for(; patch_idx < 6; ++patch_idx) 
00353     params.patches[patch_idx].is_present = false;
00354   
00355   return some_present;
00356 }
00357 
00358 // ---------------------------------------------------------------------------
00359 
00360 void calculatePatchTransformations(std::vector<cv::Mat> &oTps, 
00361   float W, float H, float D)
00362 {
00363   oTps.clear();
00364   
00365   const float w2 = W/2.f;
00366   const float h2 = H/2.f;
00367   const float d2 = D/2.f;
00368 
00369   // A
00370   oTps.push_back( DUtilsCV::Transformations::transl(0,0, -d2) );
00371   // B
00372   oTps.push_back( DUtilsCV::Transformations::roty(-M_PI/2, w2, 0, 0) );
00373   // C 
00374   oTps.push_back( DUtilsCV::Transformations::rotz(M_PI)
00375     * DUtilsCV::Transformations::rotx(M_PI, 0, 0, d2) );
00376   // D
00377   oTps.push_back( DUtilsCV::Transformations::roty(M_PI/2, -w2, 0, 0) );
00378   // E 
00379   oTps.push_back( DUtilsCV::Transformations::rotx(-M_PI/2, 0, -h2, 0) );
00380   // F
00381   oTps.push_back( DUtilsCV::Transformations::rotx(M_PI/2, 0, h2, 0) );
00382 }
00383 
00384 // ---------------------------------------------------------------------------
00385 
00386 void cropImage(cv::Mat &im, float& current_width, float& current_height,
00387   float max_width, float max_height)
00388 {
00389   float pxperm = 
00390     ( ((float)im.cols / current_width) + ((float)im.rows / current_height) )/2;
00391   
00392   int cols = im.cols;
00393   int rows = im.rows;
00394   bool crop = false;
00395   
00396   if(current_width > max_width)
00397   {
00398     cols = max_width * pxperm;
00399     current_width = max_width;
00400     crop = true;
00401   }
00402   
00403   if(current_height > max_height)
00404   {
00405     rows = max_height * pxperm;
00406     current_height = max_height;
00407     crop = true;
00408   }
00409   
00410   if(crop)
00411   {
00412     cv::Mat aux;
00413     cv::getRectSubPix(im, cv::Size(cols, rows), 
00414       cv::Point2f((float)im.cols/2.f, (float)im.rows/2.f), aux);
00415     im = aux;
00416   }
00417   
00418 }
00419 
00420 // ---------------------------------------------------------------------------
00421 
00422 void createCamera(const cv::Mat &im, float width, float height,
00423   const cv::Mat &oTp, Camera &camera)
00424 {
00425   cv::Mat cTp = DUtilsCV::Transformations::transl(0, 0, 1);
00426   cv::Mat cTo = cTp * DUtilsCV::Transformations::inv(oTp);
00427   
00428   float fx = im.cols / width;
00429   float fy = im.rows / height;
00430   camera.f = (fx + fy) / 2;
00431   camera.k1 = camera.k2 = 0;
00432   
00433   camera.t = cv::Mat::zeros(3, 1, CV_64F);
00434   DUtilsCV::Transformations::decomposeRt(cTo, camera.R, camera.t);
00435 }
00436 
00437 // ---------------------------------------------------------------------------
00438 
00439 void createPLYpoints(const cv::Mat &img, float width, float height,
00440   const cv::Mat &oTp,
00441   const DVision::SurfSet &surfset, std::vector<PLYPoint> &plypoints)
00442 {
00443   plypoints.resize(0);
00444   if(surfset.keys.empty()) return;
00445 
00446   double mperpixel;
00447   if(width > 0.f && height > 0.f)
00448     mperpixel = ((width / (float)img.cols) + (height / (float)img.rows)) / 2.f;
00449   else if(width > 0.f) mperpixel = width / (float)img.cols;
00450   else mperpixel = height / (float)img.rows;
00451   
00452   const float cx = (float)img.cols / 2.f;
00453   const float cy = (float)img.rows / 2.f;
00454   
00455   cv::Mat pP(4, surfset.size(), CV_64F);
00456   
00457   vector<cv::KeyPoint>::const_iterator kit;
00458   for(kit = surfset.keys.begin(); kit != surfset.keys.end(); ++kit)
00459   {
00460     int i = kit - surfset.keys.begin();
00461     pP.at<double>(0, i) = (kit->pt.x - cx) * mperpixel;
00462     pP.at<double>(1, i) = (kit->pt.y - cy) * mperpixel;
00463     pP.at<double>(2, i) = 0.;
00464     pP.at<double>(3, i) = 1.;
00465   }
00466   
00467   cv::Mat oP = oTp * pP;
00468   cv::Mat oN = oTp.col(2); // normal of patch: oTp * [0 0 1 0]'
00469   
00470   vector<cv::Mat> bgr_planes;
00471   cv::split(img, bgr_planes);
00472   
00473   plypoints.reserve(surfset.size());
00474   
00475   for(kit = surfset.keys.begin(); kit != surfset.keys.end(); ++kit)
00476   {
00477     int i = kit - surfset.keys.begin();
00478     
00479     plypoints.push_back(PLYPoint());
00480     PLYPoint &p = plypoints.back();
00481  
00482     p.x = oP.at<double>(0, i) / oP.at<double>(3, i);
00483     p.y = oP.at<double>(1, i) / oP.at<double>(3, i);
00484     p.z = oP.at<double>(2, i) / oP.at<double>(3, i);
00485     
00486     p.nx = oN.at<double>(0, 0);
00487     p.ny = oN.at<double>(1, 0);
00488     p.nz = oN.at<double>(2, 0);
00489 
00490     p.r = bgr_planes[2].at<uchar>(kit->pt.y, kit->pt.x);
00491     p.g = bgr_planes[1].at<uchar>(kit->pt.y, kit->pt.x);
00492     p.b = bgr_planes[0].at<uchar>(kit->pt.y, kit->pt.x);
00493   }
00494   
00495 }
00496 
00497 // ---------------------------------------------------------------------------
00498 
00499 void saveFace(const std::string &model_dir, int face_idx, const cv::Mat &img,
00500   const DVision::SurfSet &surfs, const std::vector<PLYPoint> &plypoints,
00501   const Camera &camera)
00502 {
00503   stringstream prefix;
00504   prefix << model_dir << "/face_" << setw(3) << setfill('0') << face_idx;
00505   
00506   cv::imwrite(prefix.str() + ".png", img);
00507   surfs.Save(prefix.str() + ".key.gz");
00508   PLYFile::saveFile(prefix.str() + ".ply", plypoints);
00509   camera.save(prefix.str() + ".txt", 
00510     "Fake camera. Assumes cx=w/2, cy=h/2, Z_object=1");
00511 }
00512 
00513 // ---------------------------------------------------------------------------
00514 


re_vision
Author(s): Dorian Galvez-Lopez
autogenerated on Sun Jan 5 2014 11:30:59