//-------------------------------------------------------------------------------------------------- PointCloud::Ptr generatePointCloudOfChessboard( const cv::Mat& cameraWorldMtx, const cv::Mat& cameraCalibMtx, int32_t imageWidth, int32_t imageHeight, const cv::Mat& chessboardPoseMtx ) { double focalLengthPixels = cameraCalibMtx.at<double>( 0, 0 ); PointCloud::Ptr pCloud( new PointCloud( imageWidth, imageHeight, (float)focalLengthPixels ) ); std::vector<PointData> points = generateImagePoints( cameraWorldMtx, cameraCalibMtx, imageWidth, imageHeight, chessboardPoseMtx ); for ( uint32_t pointIdx = 0; pointIdx < points.size(); pointIdx++ ) { const PointData& point = points[ pointIdx ]; uint8_t r, g, b, a; if ( ePC_Black == point.mPixelColour ) { r = 0; g = 0; b = 0; a = 255; } else if ( ePC_White == point.mPixelColour ) { r = 255; g = 255; b = 255; a = 255; } else { // Unrecognised colour continue; } pCloud->addPoint( Eigen::Vector3f( (float)point.mWorldX, (float)point.mWorldY, (float)point.mWorldZ ), r, g, b, a ); } return pCloud; }
int main (int argc, char ** argv) { typedef pcl::PointXYZRGB PointT; std::string scene_dir, input_mask_dir, output_dir = "/tmp/dol/"; bool visualize = false; bool save_views = false; size_t min_mask_points = 50; bool first_frame_only=false; // used for evaluation when only using the first view v4r::object_modelling::IOL m; po::options_description desc("Evaluation Dynamic Object Learning with Ground Truth\n======================================\n **Allowed options"); desc.add_options() ("help,h", "produce help message") ("scenes_dir,s", po::value<std::string>(&scene_dir)->required(), "input directory with .pcd files of the scenes. Each folder is considered as seperate sequence. Views are sorted alphabetically and object mask is applied on first view.") ("input_mask_dir,m", po::value<std::string>(&input_mask_dir)->required(), "directory containing the object masks used as a seed to learn the object in the first cloud") ("output_dir,o", po::value<std::string>(&output_dir)->default_value(output_dir), "Output directory where the model, training data, timing information and parameter values will be stored") ("save_views", po::bool_switch(&save_views), "if true, also saves point clouds, camera pose and object masks for each training views. This is necessary for recognition.") ("radius,r", po::value<double>(&m.param_.radius_)->default_value(m.param_.radius_), "Radius used for region growing. Neighboring points within this distance are candidates for clustering it to the object model.") ("dot_product", po::value<double>(&m.param_.eps_angle_)->default_value(m.param_.eps_angle_), "Threshold for the normals dot product used for region growing. Neighboring points with a surface normal within this threshold are candidates for clustering it to the object model.") ("dist_threshold_growing", po::value<double>(&m.param_.dist_threshold_growing_)->default_value(m.param_.dist_threshold_growing_), "") ("seed_res", po::value<double>(&m.param_.seed_resolution_)->default_value(m.param_.seed_resolution_), "") ("voxel_res", po::value<double>(&m.param_.voxel_resolution_)->default_value(m.param_.voxel_resolution_), "") ("ratio", po::value<double>(&m.param_.ratio_supervoxel_)->default_value(m.param_.ratio_supervoxel_), "") ("do_erosion", po::value<bool>(&m.param_.do_erosion_)->default_value(m.param_.do_erosion_), "") ("do_mst_refinement", po::value<bool>(&m.param_.do_mst_refinement_)->default_value(m.param_.do_mst_refinement_), "") ("do_sift_based_camera_pose_estimation", po::value<bool>(&m.param_.do_sift_based_camera_pose_estimation_)->default_value(m.param_.do_sift_based_camera_pose_estimation_), "") ("transfer_latest_only", po::value<bool>(&m.param_.transfer_indices_from_latest_frame_only_)->default_value(m.param_.transfer_indices_from_latest_frame_only_), "") ("chop_z,z", po::value<double>(&m.param_.chop_z_)->default_value(m.param_.chop_z_), "Cut-off distance of the input clouds with respect to the camera. Points further away than this distance will be ignored.") ("normal_method,n", po::value<int>(&m.param_.normal_method_)->default_value(m.param_.normal_method_), "") ("ratio_cluster_obj_supported", po::value<double>(&m.param_.ratio_cluster_obj_supported_)->default_value(m.param_.ratio_cluster_obj_supported_), "") ("ratio_cluster_occluded", po::value<double>(&m.param_.ratio_cluster_occluded_)->default_value(m.param_.ratio_cluster_occluded_), "") ("stat_outlier_removal_meanK", po::value<int>(&m.sor_params_.meanK_)->default_value(m.sor_params_.meanK_), "MeanK used for statistical outlier removal (see PCL documentation)") ("stat_outlier_removal_std_mul", po::value<double>(&m.sor_params_.std_mul_)->default_value(m.sor_params_.std_mul_), "Standard Deviation multiplier used for statistical outlier removal (see PCL documentation)") ("inlier_threshold_plane_seg", po::value<double>(&m.p_param_.inlDist)->default_value(m.p_param_.inlDist), "") ("min_points_smooth_cluster", po::value<int>(&m.p_param_.minPointsSmooth)->default_value(m.p_param_.minPointsSmooth), "Minimum number of points for a cluster") ("min_plane_points", po::value<int>(&m.p_param_.minPoints)->default_value(m.p_param_.minPoints), "Minimum number of points for a cluster to be a candidate for a plane") ("smooth_clustering", po::value<bool>(&m.p_param_.smooth_clustering)->default_value(m.p_param_.smooth_clustering), "If true, does smooth clustering. Otherwise only plane clustering.") ("visualize,v", po::bool_switch(&visualize), "turn visualization on") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); if (vm.count("help")) { std::cout << desc << std::endl; return false; } try { po::notify(vm); } catch(std::exception& e) { std::cerr << "Error: " << e.what() << std::endl << std::endl << desc << std::endl; return false; } m.initSIFT(); v4r::io::createDirIfNotExist(output_dir); ofstream param_file; param_file.open ((output_dir + "/param.nfo").c_str()); m.printParams(param_file); param_file << "stat_outlier_removal_meanK" << m.sor_params_.meanK_ << std::endl << "stat_outlier_removal_std_mul" << m.sor_params_.std_mul_ << std::endl << "inlier_threshold_plane_seg" << m.p_param_.inlDist << std::endl << "min_points_smooth_cluster" << m.p_param_.minPointsSmooth << std::endl << "min_plane_points" << m.p_param_.minPoints << std::endl; param_file.close(); std::vector< std::string> sub_folder_names = v4r::io::getFoldersInDirectory( scene_dir ); if( sub_folder_names.empty() ) sub_folder_names.push_back(""); v4r::io::createDirIfNotExist(output_dir + "/models"); for (const std::string &sub_folder_name : sub_folder_names) { const std::string output_rec_model = output_dir + "/" + sub_folder_name + "/models"; v4r::io::createDirIfNotExist(output_rec_model); const std::string annotations_dir = input_mask_dir + "/" + sub_folder_name; std::vector< std::string > mask_file_v = v4r::io::getFilesInDirectory(annotations_dir, ".*.txt", false); for (size_t o_id=0; o_id<mask_file_v.size(); o_id++) { const std::string mask_file = annotations_dir + "/" + mask_file_v[o_id]; size_t idx_tmp; std::vector<size_t> mask; std::ifstream initial_mask_file ( mask_file.c_str() ); while (initial_mask_file >> idx_tmp) mask.push_back(idx_tmp); initial_mask_file.close(); if ( mask.size() < min_mask_points) // not enough points to grow an object continue; const std::string scene_path = scene_dir + "/" + sub_folder_name; std::vector< std::string > views = v4r::io::getFilesInDirectory(scene_path, ".*.pcd", false); std::cout << "Learning object from mask " << mask_file << " for scene " << scene_path << std::endl; timeval start, stop; gettimeofday(&start, NULL); for(size_t v_id=0; v_id<views.size(); v_id++) { const std::string view_file = scene_path + "/" + views[ v_id ]; pcl::PointCloud<PointT>::Ptr pCloud(new pcl::PointCloud<PointT>()); pcl::io::loadPCDFile(view_file, *pCloud); const Eigen::Matrix4f trans = v4r::RotTrans2Mat4f(pCloud->sensor_orientation_, pCloud->sensor_origin_); pCloud->sensor_origin_ = Eigen::Vector4f::Zero(); // for correct visualization pCloud->sensor_orientation_ = Eigen::Quaternionf::Identity(); if (v_id==0) m.learn_object(*pCloud, trans, mask); else { if(!first_frame_only) m.learn_object(*pCloud, trans); } } gettimeofday(&stop, NULL); std::string out_fn = mask_file_v[o_id]; boost::replace_last (out_fn, "mask.txt", "dol"); m.save_model(output_rec_model, out_fn, save_views); if (visualize) m.visualize(); m.clear(); // write running time to file const std::string timing_fn = output_dir+"/"+sub_folder_name+"/timing.nfo"; double learning_time = getTimeDiff(stop, start); ofstream f( timing_fn.c_str() ); f << learning_time; f.close(); } } return 0; }