re_visionmodelcreator.cpp
Go to the documentation of this file.
00001 
00047 #include "re_visionmodelcreator.h"
00048 
00049 #include <cv.h>
00050 #include <highgui.h>
00051 #include <boost/foreach.hpp>
00052 #include <QString>
00053 #include <QFile>
00054 #include <QXmlStreamWriter>
00055 
00056 #include <Eigen/Geometry>
00057 #include <pcl/features/normal_3d.h>
00058 #include <pcl/kdtree/kdtree_flann.h>
00059 #include <pcl/common/transforms.h>
00060 
00061 #include <re_vision/SurfSet.h>
00062 #include <re_vision/BundleCamera.h>
00063 #include <re_vision/PLYFile.h>
00064 
00065 using namespace std;
00066 
00067 void re_visionModelCreator::createMetaFile(QDir model_dir, QString modelname, QString modeltype, size_t face_count, double scale) {
00068     QFile metaFile(model_dir.filePath("meta.xml"));
00069     metaFile.open(QIODevice::WriteOnly);
00070     QXmlStreamWriter xml(&metaFile);
00071     xml.setAutoFormatting(true);
00072     xml.writeStartDocument();
00073 
00074     xml.writeStartElement("model");
00075     xml.writeTextElement("name", modelname);
00076     xml.writeTextElement("type", modeltype);
00077     xml.writeTextElement("faces", QString::number(face_count));
00078     xml.writeStartElement("dimensions");
00079     xml.writeTextElement("scale", QString::number(scale));
00080     xml.writeEndElement(); // dimensions
00081     xml.writeEndElement(); // model
00082     xml.writeEndDocument();
00083 }
00084 
00086 Eigen::Affine3f getRe_visionTransformation() {
00087     Eigen::Quaternionf quat(Eigen::AngleAxisf(-0.5*M_PI, Eigen::Vector3f::UnitY()) *
00088                             Eigen::AngleAxisf(0.5*M_PI, Eigen::Vector3f::UnitZ()));
00089 //    transformation.setRotation(quat);
00090     Eigen::Affine3f transformation(quat);
00091     return transformation;
00092 }
00093 
00094 re_visionModelCreator::re_visionModelCreator(const std::vector<boost::shared_ptr<pcl::PointCloud<pcl::PointXYZRGB> > >& pointclouds) : pcls(pointclouds)
00095 {
00096 }
00097 
00098 void re_visionModelCreator::createModel(const QDir &parent_dir, const pcl::PointCloud<pcl::PointXYZRGB> &merged_pcl, const QString& modelname) {
00099     QString drawing_model_filename = parent_dir.absoluteFilePath("drawing_model.ply");
00100     saveAsPLY(merged_pcl.makeShared(), drawing_model_filename);
00101 
00102     int face_counter=0;
00103     BOOST_FOREACH(const boost::shared_ptr<pcl::PointCloud<pcl::PointXYZRGB> >& pcl_ptr, pcls) {
00104         const pcl::PointCloud<pcl::PointXYZRGB>& pcl = *pcl_ptr;
00105 
00106         const QString base_filename = parent_dir.absoluteFilePath(QString("face_%1").arg(face_counter++, 3, 10, QChar('0')));
00107 
00108         // create BGR image from dense pointcloud
00109         cv::Mat3b img_color(cv::Size(pcl.width, pcl.height));
00110         cv::Mat1b mask(img_color.size());
00111         cv::Mat3b masked_img_color(img_color.size());
00112         size_t i=0;
00113         for (size_t u = 0; u < pcl.height; ++u)
00114         {
00115             for (size_t v = 0; v < pcl.width; ++v, ++i)
00116             {
00117                 int32_t rgb = *(int32_t*)(&pcl.points[i].rgb);
00118                 char b = rgb & 0xFF;
00119                 char g = (rgb & (0xFF << 8)) >> 8;
00120                 char r = (rgb & (0xFF << 16)) >> 16;
00121                 img_color(u, v) = cv::Vec3b(b, g, r);
00122                 // If the point is invalid (i.e. belongs to background)
00123                 if (isnan (pcl.points[i].x) || isnan (pcl.points[i].y) || isnan (pcl.points[i].z))
00124                     mask(u, v) = 0;
00125                 else
00126                     mask(u, v) = 1;
00127             }
00128         }
00129         std::cerr << "writing " << base_filename.toStdString() << ".png";
00130         cv::imwrite((base_filename+".png").toStdString(), img_color);
00131 
00132         cv::floodFill(mask, cv::Point2i(0, 0), 2);
00133         for (int u = 0; u < mask.size().height; ++u)
00134         {
00135             for (int v = 0; v < mask.size().width; ++v)
00136             {
00137                 cv::Vec3b color;
00138                 if (mask(u, v) == 2) {
00139                     color = cv::Vec3b(0, 0, 0);
00140                     mask(u, v) = 0;
00141                 }
00142                 else {
00143                     color = img_color.at<cv::Vec3b>(u, v);
00144                     mask(u, v) = 1;
00145                 }
00146 
00147                 masked_img_color.at<cv::Vec3b>(u, v) = color;
00148             }
00149         }
00150         cv::Mat1b masked_img_gray(masked_img_color.size());
00151         cv::cvtColor(masked_img_color, masked_img_gray, CV_BGR2GRAY);
00152 
00153         cv::GaussianBlur(masked_img_gray, masked_img_gray,  cv::Size(3,3), 0);
00154 
00155         DVision::SurfSet surf;
00156         const float surf_th = 400.;
00157         surf.Extract(masked_img_gray, surf_th, false);
00158         cout << "got " << surf.keys.size() << " descriptors" << endl;
00159         const int margin = 3;
00160         cv::Mat erosion = cv::Mat::ones(margin*2+1, margin*2+1, CV_8U);
00161         cv::erode(mask, mask, erosion);
00162 
00163         cv::Mat1b masked_eroded(masked_img_gray.size());
00164         for (int u = 0; u < mask.size().height; ++u)
00165         {
00166             for (int v = 0; v < mask.size().width; ++v)
00167             {
00168                 uchar color;
00169                 if (mask(u, v) == 0)
00170                     color = 0;
00171                 else
00172                     color = masked_img_gray.at<uchar>(u, v);
00173 
00174                 masked_eroded.at<uchar>(u, v) = color;
00175             }
00176         }
00177 
00178         cv::imwrite((base_filename + "_masked.png").toStdString(), masked_eroded);
00179 
00180         boost::shared_ptr<pcl::PointCloud<pcl::PointXYZRGB> > masked_ply
00181                 (new pcl::PointCloud<pcl::PointXYZRGB>());
00182 
00183         DVision::SurfSet surf_cleaned;
00184         for (size_t i=0; i<surf.keys.size(); i++) {
00185             const cv::KeyPoint& kp = surf.keys.at(i);
00186             const pcl::PointXYZRGB& pt3d = pcl.at(kp.pt.x, kp.pt.y);
00187             if ((mask(kp.pt) != 0) && (!isnan(pt3d.x)))
00188             {
00189                 surf_cleaned.keys.push_back(kp);
00190                 for (int j=0; j<surf.GetDescriptorLength(); j++) {
00191                     surf_cleaned.descriptors.push_back(surf.descriptors.at(i*surf.GetDescriptorLength()+j));
00192 
00193                 }
00194                 surf_cleaned.laplacians.push_back(surf.laplacians.at(i));
00195                 masked_ply->push_back(pt3d);
00196             }
00197         }
00198         cout << "surf descriptors after removing borders: " << surf_cleaned.size() << endl;
00199 
00200         surf_cleaned.Save((base_filename + ".key.gz").toStdString());
00201 
00202 
00203         // TODO: take camera parameters from calibration, see http://phototour.cs.washington.edu/bundler/bundler-v0.4-manual.html
00204         //Each camera entry <cameraI> contains the estimated camera intrinsics and extrinsics, and has the form:
00205             //<f> <k1> <k2>   [the focal length, followed by two radial distortion coeffs]
00206             //<R>             [a 3x3 matrix representing the camera rotation]
00207             //<t>             [a 3-vector describing the camera translation]
00208         DVision::Bundle::CameraFile::Camera cam;
00209         // focal length
00210         cam.f = 525.f;
00211         cam.k1 = 0.f;
00212         cam.k2 = 0.f;
00213         Eigen::Vector4f trans(pcl.sensor_origin_);
00214         Eigen::Quaternionf quat(pcl.sensor_orientation_);
00215 
00216         cv::Mat1d camera_translation(3,1);
00217         for (int i=0; i<3; i++) {
00218             camera_translation(i) = trans(i);
00219         }
00220         cam.t = camera_translation;
00221         cout << camera_translation << endl;
00222 
00223         cv::Mat1d camera_rotation(3,3);
00224         Eigen::Matrix3f rot_mat(quat);
00225         for(int i=0; i<3; i++)
00226             for(int j=0; j<3; j++)
00227                 camera_rotation(i, j) = rot_mat(i,j);
00228         cam.R = camera_rotation;
00229         cout << camera_rotation << endl;
00230 
00231         cam.save((base_filename + ".txt").toStdString(), "Generated by re_object_recorder");
00232 
00233         saveAsPLY(masked_ply, base_filename + ".ply");
00234     }
00235 
00236     createMetaFile(parent_dir, modelname, "3D", pcls.size(), 1);
00237 }
00238 
00239 void re_visionModelCreator::saveAsPLY(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr pcl, const QString &filename) {
00240     using DVision::PMVS::PLYFile;
00241 
00242 #ifdef ESTIMATE_NORMALS
00243     pcl::KdTreeFLANN<pcl::PointXYZRGB>::Ptr flann(new pcl::KdTreeFLANN<pcl::PointXYZRGB>);
00244     cerr << "estimating normals" << endl;
00245 
00246     pcl::PointCloud<pcl::Normal>::Ptr normals_cloud(new pcl::PointCloud<pcl::Normal>);
00247     pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> norm_est;
00248     norm_est.setSearchMethod(flann);
00249     norm_est.setInputCloud(pcl);
00250     norm_est.setRadiusSearch(0.01);
00251     norm_est.compute(*normals_cloud);
00252 #endif
00253 
00254     pcl::PointCloud<pcl::PointXYZRGB> transformed_pcl;
00255     pcl::transformPointCloud(*pcl, transformed_pcl, getRe_visionTransformation());
00256 
00257     std::vector<PLYFile::PLYPoint> plyPoints;
00258     for(size_t  i=0; i<transformed_pcl.size(); i++) {
00259         const pcl::PointXYZRGB& pclPt = transformed_pcl.points.at(i);
00260         // nan -> point was filtered out
00261         if (isnan(pclPt.x))
00262             continue;
00263 
00264         PLYFile::PLYPoint plyPt;
00265         plyPt.x = pclPt.x;
00266         plyPt.y = pclPt.y;
00267         plyPt.z = pclPt.z;
00268 #ifdef ESTIMATE_NORMALS
00269         const pcl::Normal& pclNormal = normals_cloud->points.at(i);
00270         plyPt.nx = pclNormal.normal_x;
00271         plyPt.ny = pclNormal.normal_y;
00272         plyPt.nz = pclNormal.normal_z;
00273 #else
00274         plyPt.nx = 0;
00275         plyPt.ny = 0;
00276         plyPt.nz = 0;
00277 #endif
00278         int32_t rgb = *(int32_t*)(&pclPt.rgb);
00279         plyPt.b = rgb & 0xFF;
00280         plyPt.g = (rgb & (0xFF << 8)) >> 8;
00281         plyPt.r = (rgb & (0xFF << 16)) >> 16;
00282         plyPoints.push_back(plyPt);
00283     }
00284     PLYFile::saveFile(filename.toStdString(), plyPoints);
00285 }


re_object_recorder
Author(s): Andreas Koch
autogenerated on Sun Jan 5 2014 11:39:12