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 ¶ms);
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
00197
00198 float max_patch_width[] = {
00199 params.W,
00200 params.D,
00201 params.W,
00202 params.D,
00203 params.W,
00204 params.W
00205 };
00206
00207
00208 float max_patch_height[] = {
00209 params.H,
00210 params.H,
00211 params.H,
00212 params.H,
00213 params.D,
00214 params.D
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
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 ¶ms)
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
00320 params.hessian = atoi(argv[i]);
00321 ++i;
00322 }
00323 else
00324 {
00325
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
00370 oTps.push_back( DUtilsCV::Transformations::transl(0,0, -d2) );
00371
00372 oTps.push_back( DUtilsCV::Transformations::roty(-M_PI/2, w2, 0, 0) );
00373
00374 oTps.push_back( DUtilsCV::Transformations::rotz(M_PI)
00375 * DUtilsCV::Transformations::rotx(M_PI, 0, 0, d2) );
00376
00377 oTps.push_back( DUtilsCV::Transformations::roty(M_PI/2, -w2, 0, 0) );
00378
00379 oTps.push_back( DUtilsCV::Transformations::rotx(-M_PI/2, 0, -h2, 0) );
00380
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);
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