00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00046 #include <string>
00047
00048
00049 #include <ros/ros.h>
00050 #include <boost/algorithm/string.hpp>
00051 #include <boost/filesystem.hpp>
00052
00053 #include <pcl/ros/register_point_struct.h>
00054 #include <pcl/io/pcd_io.h>
00055 #include <pcl/filters/voxel_grid.h>
00056 #include <pcl/point_types.h>
00057
00058
00059 #include <itpp/itbase.h>
00060 #include <itpp/itstat.h>
00061 #include <itpp/signal/sigfun.h>
00062
00063
00064 #include <vtkMath.h>
00065 #include <vtkGeneralTransform.h>
00066 #include <vtkPlatonicSolidSource.h>
00067 #include <vtkLoopSubdivisionFilter.h>
00068 #include <vtkPLYReader.h>
00069 #include <vtkSmartPointer.h>
00070 #include <vtkCellLocator.h>
00071 #include <vtkPolyData.h>
00072
00073
00074 #include <terminal_tools/print.h>
00075 #include <terminal_tools/parse.h>
00076
00077
00078 #include "pcl_vtk_tools/misc.h"
00079
00080 #include <vector>
00081 #define EPS 0.00001
00082
00083 struct ScanParameters
00084 {
00085 int nr_scans;
00086 int nr_points_in_scans;
00087 double vert_res;
00088 double hor_res;
00089 double max_dist;
00090 };
00091
00093
00097 vtkPolyData*
00098 loadPLYAsDataSet (const char* file_name)
00099 {
00100 vtkPLYReader* reader = vtkPLYReader::New ();
00101 reader->SetFileName (file_name);
00102 reader->Update ();
00103 return (reader->GetOutput ());
00104 }
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 int
00119 main (int argc, char** argv)
00120 {
00121 if (argc < 3)
00122 {
00123 ROS_INFO("Usage %s -single_view <0|1> -view_point <x,y,z> -target_point <x,y,z> <model.ply | model.vtk>", argv[0]);
00124 return -1;
00125 }
00126 std::string filename;
00127
00128 std::vector<int> p_file_indices_vtk = terminal_tools::parse_file_extension_argument (argc, argv, ".vtk");
00129 std::vector<int> p_file_indices_ply = terminal_tools::parse_file_extension_argument (argc, argv, ".ply");
00130 bool object_coordinates = true;
00131 terminal_tools::parse_argument (argc, argv, "-object_coordinates", object_coordinates);
00132 bool single_view = false;
00133 terminal_tools::parse_argument (argc, argv, "-single_view", single_view);
00134 double vx = 0, vy = 0, vz = 0;
00135 terminal_tools::parse_3x_arguments (argc, argv, "-view_point", vx, vy, vz);
00136 double tx = 0, ty = 0, tz = 0;
00137 terminal_tools::parse_3x_arguments (argc, argv, "-target_point", tx, ty, tz);
00138 vtkSmartPointer<vtkPolyData> data;
00139
00140 if (p_file_indices_vtk.size() != 0)
00141 {
00142 data = load_poly_data_as_data_set(argv[p_file_indices_vtk.at (0)]);
00143 std::stringstream filename_stream;
00144 filename_stream << argv[p_file_indices_vtk.at (0)];
00145 filename = filename_stream.str();
00146 ROS_INFO ("Loading vtk model with %d vertices/points.", (int)data->GetNumberOfPoints ());
00147 }
00148
00149 else if (p_file_indices_ply.size() != 0)
00150 {
00151 std::stringstream filename_stream;
00152 filename_stream << argv[p_file_indices_ply.at (0)];
00153 filename = filename_stream.str();
00154 data = loadPLYAsDataSet (filename.c_str());
00155 ROS_INFO ("Loading ply model with %d vertices/points.", (int)data->GetNumberOfPoints ());
00156 }
00157 else
00158 {
00159 ROS_ERROR("Unrecognized file format");
00160 return -1;
00161 }
00162
00163 ScanParameters sp;
00164 sp.nr_scans = 900;
00165 sp.nr_points_in_scans = 900;
00166 sp.max_dist = 30000;
00167 sp.vert_res = 0.25;
00168 sp.hor_res = 0.25;
00169
00170 int noise_model = 0;
00171 double noise_std = 0.5;
00172
00173 int subdiv_level = 1;
00174 double scan_dist = 3;
00175 std::string fname, base;
00176 char seq[256];
00177
00178
00179 double vert_start = - ((double)(sp.nr_scans-1) / 2.0) * sp.vert_res;
00180 double vert_end = + ((sp.nr_scans-1) * sp.vert_res) + vert_start;
00181 double hor_start = - ((double)(sp.nr_points_in_scans-1) / 2.0) * sp.hor_res;
00182 double hor_end = + ((sp.nr_points_in_scans-1) * sp.hor_res) + hor_start;
00183
00184
00185 pcl::PointCloud<pcl::PointWithViewpoint> cloud;
00186
00187
00188 pcl::VoxelGrid<pcl::PointWithViewpoint> grid;
00189 grid.setLeafSize (2.5, 2.5, 2.5);
00190
00191
00192 itpp::RNG_randomize ();
00193
00194 itpp::Normal_RNG n_rng (0.0, noise_std*noise_std);
00195 itpp::Laplace_RNG lap_rng (0.0, noise_std*noise_std);
00196
00197 std::vector<std::string> st;
00198
00199 double eye[3] = {0.0, 0.0, 0.0};
00200 double viewray[3] = {0.0, 0.0, 0.0};
00201 double up[3] = {0.0, 0.0, 0.0};
00202 double right[3] = {0.0, 0.0, 0.0};
00203 double x_axis[3] = {1.0, 0.0, 0.0};
00204 double z_axis[3] = {0.0, 0.0, 1.0};
00205 double bounds[6];
00206 double temp_beam[3], beam[3], p[3];
00207 double p_coords[3], x[3], t;
00208 int subId;
00209
00210
00211 vtkSmartPointer<vtkPlatonicSolidSource> icosa = vtkSmartPointer<vtkPlatonicSolidSource>::New ();
00212 icosa->SetSolidTypeToIcosahedron ();
00213
00214
00215
00216 vtkSmartPointer<vtkLoopSubdivisionFilter> subdivide = vtkSmartPointer<vtkLoopSubdivisionFilter>::New ();
00217 subdivide->SetNumberOfSubdivisions (subdiv_level);
00218 subdivide->SetInputConnection (icosa->GetOutputPort ());
00219
00220
00221 vtkPolyData *sphere = subdivide->GetOutput ();
00222 sphere->Update ();
00223 if(!single_view)
00224 ROS_INFO ("Created %d camera position points.", (int)sphere->GetNumberOfPoints ());
00225
00226
00227 vtkSmartPointer<vtkCellLocator> tree = vtkSmartPointer<vtkCellLocator>::New ();
00228 tree->SetDataSet (data);
00229 tree->CacheCellBoundsOn ();
00230 tree->SetTolerance (0.0);
00231 tree->SetNumberOfCellsPerBucket (1);
00232 tree->AutomaticOn ();
00233 tree->BuildLocator ();
00234 tree->Update ();
00235
00236
00237 data->GetBounds (bounds);
00238
00239
00240 int number_of_points = sphere->GetNumberOfPoints ();
00241 if (single_view)
00242 number_of_points = 1;
00243
00244 int sid = -1;
00245 for (int i = 0; i < number_of_points; i++)
00246 {
00247 sphere->GetPoint (i, eye);
00248 if (fabs(eye[0]) < EPS) eye[0] = 0;
00249 if (fabs(eye[1]) < EPS) eye[1] = 0;
00250 if (fabs(eye[2]) < EPS) eye[2] = 0;
00251
00252 viewray[0] = -eye[0];
00253 viewray[1] = -eye[1];
00254 viewray[2] = -eye[2];
00255 eye[0] *= scan_dist;
00256 eye[1] *= scan_dist;
00257 eye[2] *= scan_dist;
00258
00259 if (single_view)
00260 {
00261 eye[0] = vx;
00262 eye[1] = vy;
00263 eye[2] = vz;
00264 viewray[0] = tx - vx;
00265 viewray[1] = ty - vy;
00266 viewray[2] = tz - vz;
00267 double len = sqrt (viewray[0]*viewray[0] + viewray[1]*viewray[1] + viewray[2]*viewray[2]);
00268 if (len == 0)
00269 {
00270 ROS_ERROR ("The single_view option is enabled but the view_point and the target_point are the same!");
00271 break;
00272 }
00273 viewray[0] /= len;
00274 viewray[1] /= len;
00275 viewray[2] /= len;
00276 }
00277
00278 if ((viewray[0] == 0) && (viewray[1] == 0))
00279 vtkMath::Cross (viewray, x_axis, right);
00280 else
00281 vtkMath::Cross (viewray, z_axis, right);
00282 if (fabs(right[0]) < EPS) right[0] = 0;
00283 if (fabs(right[1]) < EPS) right[1] = 0;
00284 if (fabs(right[2]) < EPS) right[2] = 0;
00285
00286 vtkMath::Cross (viewray, right, up);
00287 if (fabs(up[0]) < EPS) up[0] = 0;
00288 if (fabs(up[1]) < EPS) up[1] = 0;
00289 if (fabs(up[2]) < EPS) up[2] = 0;
00290
00291 if (!object_coordinates)
00292 {
00293
00294 double right_len = sqrt (right[0]*right[0] + right[1]*right[1] + right[2]*right[2]);
00295 right[0] /= right_len;
00296 right[1] /= right_len;
00297 right[2] /= right_len;
00298 double up_len = sqrt (up[0]*up[0] + up[1]*up[1] + up[2]*up[2]);
00299 up[0] /= up_len;
00300 up[1] /= up_len;
00301 up[2] /= up_len;
00302
00303
00304 cerr << "Viewray Right Up:" << endl;
00305 cerr << viewray[0] << " " << viewray[1] << " " << viewray[2] << " " << endl;
00306 cerr << right[0] << " " << right[1] << " " << right[2] << " " << endl;
00307 cerr << up[0] << " " << up[1] << " " << up[2] << " " << endl;
00308 }
00309
00310
00311 vtkGeneralTransform* tr1 = vtkGeneralTransform::New ();
00312 vtkGeneralTransform* tr2 = vtkGeneralTransform::New ();
00313
00314
00315 vtkMath::Cross (viewray, up, right);
00316
00317
00318 for (double vert = vert_start; vert <= vert_end; vert += sp.vert_res)
00319 {
00320 sid++;
00321
00322 tr1->Identity ();
00323 tr1->RotateWXYZ (vert, right);
00324 tr1->InternalTransformPoint (viewray, temp_beam);
00325
00326
00327 int pid = -1;
00328 for (double hor = hor_start; hor <= hor_end; hor += sp.hor_res)
00329 {
00330 pid ++;
00331
00332
00333 tr2->Identity ();
00334 tr2->RotateWXYZ (hor, up);
00335 tr2->InternalTransformPoint (temp_beam, beam);
00336 vtkMath::Normalize (beam);
00337
00338
00339 for (int d = 0; d < 3; d++)
00340 p[d] = eye[d] + beam[d] * sp.max_dist;
00341
00342
00343 vtkIdType cellId;
00344 if (tree->IntersectWithLine (eye, p, 0, t, x, p_coords, subId, cellId))
00345 {
00346 pcl::PointWithViewpoint pt;
00347 if (object_coordinates)
00348 {
00349 pt.x = x[0]; pt.y = x[1]; pt.z = x[2];
00350 pt.vp_x = eye[0]; pt.vp_y = eye[1]; pt.vp_z = eye[2];
00351 }
00352 else
00353 {
00354
00355
00356
00357 pt.x = -right[0]*x[1] + up[0]*x[2] + viewray[0]*x[0] + eye[0];
00358 pt.y = -right[1]*x[1] + up[1]*x[2] + viewray[1]*x[0] + eye[1];
00359 pt.z = -right[2]*x[1] + up[2]*x[2] + viewray[2]*x[0] + eye[2];
00360 pt.vp_x = pt.vp_y = pt.vp_z = 0.0;
00361 }
00362 cloud.points.push_back(pt);
00363 }
00364 }
00365 }
00366
00367
00368
00369 for (size_t cp = 0; cp < cloud.points.size (); ++cp)
00370 {
00371
00372 switch (noise_model)
00373 {
00374
00375 case 1: { cloud.points[cp].x += n_rng (); cloud.points[cp].y += n_rng (); cloud.points[cp].z += n_rng (); break; }
00376
00377 case 2: { cloud.points[cp].x += lap_rng (); cloud.points[cp].y += lap_rng (); cloud.points[cp].z += lap_rng (); break; }
00378 }
00379 }
00380
00381
00382 pcl::PointCloud<pcl::PointWithViewpoint> cloud_downsampled;
00383 grid.setInputCloud (boost::make_shared<pcl::PointCloud<pcl::PointWithViewpoint> > (cloud));
00384
00385
00386
00387 sprintf (seq, "%d", (int)i);
00388 boost::trim (filename);
00389 boost::split (st, filename, boost::is_any_of ("/"), boost::token_compress_on);
00390
00391 std::stringstream ss;
00392 std::string output_dir = st.at (st.size () - 1);
00393 boost::filesystem::path outpath (output_dir);
00394 if (!boost::filesystem::exists (outpath))
00395 {
00396 if (!boost::filesystem::create_directories (outpath))
00397 {
00398 ROS_ERROR ("Error creating directory %s.", output_dir.c_str ());
00399 return (-1);
00400 }
00401 ROS_INFO ("Creating directory %s", output_dir.c_str ());
00402 }
00403
00404 fname = st.at (st.size () - 1) + seq + ".pcd";
00405 ROS_INFO ("Writing %d points to %s", (int)cloud.points.size (), fname.c_str ());
00406 pcl::io::savePCDFile (fname.c_str (), cloud);
00407 }
00408 return (0);
00409 }
00410