statistics.cpp
Go to the documentation of this file.
00001 #include <pcl/point_types.h>
00002 #include <pcl/conversions.h>
00003 #include <pcl/io/pcd_io.h>
00004 #include <pcl/filters/filter_indices.h>
00005 #include <pcl_conversions/pcl_conversions.h>
00006 #include <sensor_msgs/Image.h>
00007 #include <sensor_msgs/PointCloud2.h>
00008 
00009 #include <ros/ros.h>
00010 #include <rosbag/bag.h>
00011 #include <rosbag/view.h>
00012 
00013 #include <sstream>
00014 #include <fstream>
00015 #include <boost/filesystem.hpp>
00016 #include <boost/foreach.hpp>
00017 
00018 #include <shape_reconstruction/SRUtils.h>
00019 
00020 #include <opencv2/highgui/highgui.hpp>
00021 
00022 #include <regex>
00023 
00024 using namespace std;
00025 using namespace boost::filesystem;
00026 
00027 namespace omip {
00028 
00029 
00030 void compareAlignedDensePointClouds(SRPointCloud::Ptr& gt_pc, SRPointCloud::Ptr& seg_pc, int& tp, int& tn, int& fp, int& fn, int& error) {
00031     tp=0, tn=0, fp=0, fn=0, error=0;
00032 
00033     // TODO compare to ground truth
00034     if (gt_pc->size() != seg_pc->size()) {
00035         ROS_ERROR(" Cannot compare; sizes differ!");
00036         return;
00037     } else {
00038         for (int i = 0; i < gt_pc->size(); i++) {
00039             SRPoint& p_gt =  gt_pc->points[i];
00040             SRPoint& p_seg =  seg_pc->points[i];
00041 
00042             bool gt_nan = !(!isnan(p_gt.x) && !isnan(p_gt.y) && !isnan(p_gt.z));
00043             bool seg_nan = !(!isnan(p_seg.x) && !isnan(p_seg.y) && !isnan(p_seg.z));
00044 
00045             if (gt_nan && seg_nan)
00046                 tn++;
00047             else if (gt_nan && !seg_nan)
00048                 fp++;
00049             else if (!gt_nan && seg_nan)
00050                 fn++;
00051             else if ( p_gt.x == p_seg.x && p_gt.y == p_seg.y && p_gt.z == p_seg.z )
00052                 tp++;
00053             else
00054                 error++;
00055         }
00056     }
00057 
00058     if (error>0){
00059         ROS_ERROR_STREAM(endl << "          ERROR non matching points: " << error << " - are the point clouds really aligned?");
00060     }
00061 }
00062 
00063 std::string getTimeStampString(const ros::Time& t) {
00064     double sec = t.toSec();
00065 
00066     char c[255];
00067     sprintf(c, "%.3f\n", sec);
00068 
00069     return string(c);
00070 }
00071 
00072 void writeCSV( std::ofstream& out, std::vector<std::string>& labels, std::vector<std::vector<double> >& values ) {
00073     assert (out.is_open());
00074 
00075     out.precision(25);
00076 
00077     out << "#";
00078     for (vector<string >::iterator it = labels.begin(); it != labels.end(); it++) {
00079         out << *it << " ";
00080     }
00081     out << endl;
00082 
00083     for (vector<vector<double> >::iterator it = values.begin(); it != values.end(); it++) {
00084         for (vector<double>::iterator it2 = it->begin(); it2 != it->end(); it2++) {
00085             out << *it2 << " ";
00086         }
00087         out << endl;
00088     }
00089 }
00090 
00091 void get_ochs_result_file_list(const string& ochs_result_dir, vector<string>& dense_recons) {
00092     cout << "Listing Ochs results:  " << ochs_result_dir << endl;
00093     path ochs_dir(ochs_result_dir);
00094     directory_iterator end_iter;    
00095 
00096     //vector<path> dense_recons;
00097     dense_recons.clear();
00098 
00099     if ( !exists(ochs_dir) || !is_directory(ochs_dir)) {
00100         cout << "ERROR: directory does not exist" << endl;
00101         return;
00102     }
00103     for( directory_iterator dir_iter(ochs_dir) ; dir_iter != end_iter ; ++dir_iter) {
00104         if (!is_regular_file(dir_iter->status()) ) {
00105             continue;
00106         }
00107         //const directory_entry& entry = *dir_iter;
00108         const path& p = dir_iter->path();
00109         if (p.leaf().string().find("dense") != string::npos) {
00110             dense_recons.push_back(p.string());
00111         }
00112     }
00113 
00114     std::sort(dense_recons.begin(), dense_recons.end());
00115 
00116     for (int i = 0; i < dense_recons.size(); i++) {
00117         cout << "   " << dense_recons[i] << endl;
00118     }
00119 
00120 }
00121 
00122 
00123 void getOchsSegments(const cv::Mat img, SRPointCloud::ConstPtr orig_pc,  vector<SRPointCloud::Ptr>& segments) {
00124     // collect colors
00125     segments.clear();
00126 
00127     map<string,SRPointCloud::Ptr> colors;
00128     int idx=0;
00129     for (int h=0; h<img.rows; h++) {
00130         for (int w=0; w<img.cols; w++) {
00131             cv::Vec3b c = img.at<cv::Vec3b>(h,w);
00132             ostringstream hash;
00133             hash << static_cast<int>(c[0]) << static_cast<int>(c[1]) << static_cast<int>(c[2]);
00134             map<string,SRPointCloud::Ptr>::iterator it = colors.find(hash.str());
00135             if (it == colors.end()) {
00136                 cout << "create new point cloud #" << colors.size() << " for hash " << hash.str() << endl;
00137                 SRPointCloud::Ptr pc(new SRPointCloud);
00138                 pc->width = img.cols;
00139                 pc->height = img.rows;
00140                 for (int h=0; h<img.rows; h++) {
00141                     for (int w=0; w<img.cols; w++) {
00142                         SRPoint po; po.data[0] = po.data[1] = po.data[2] = std::numeric_limits<float>::quiet_NaN();
00143                         pc->points.push_back(po);
00144                     }
00145                 }
00146 
00147 //                cout << pcl::isFinite(pc->points[0]) << endl;
00148 //                cout << "orig_pc: " << orig_pc->width << ", " << orig_pc->height << " (" << orig_pc->points.size() << ")" << endl;
00149 //                cout << orig_pc->points.at(0) << endl;
00150 //                cout << "pc: " << pc->width << ", " << pc->height << " (" << pc->points.size() << ")" << endl;
00151 
00152                 colors[hash.str()] = pc;
00153             }
00154             SRPointCloud::Ptr pc = colors[hash.str()];
00155             SRPoint &p = pc->points.at(idx);
00156             p = orig_pc->points.at(idx);
00157 
00158             idx++;
00159         }
00160     }
00161 
00162     for (map<string,SRPointCloud::Ptr>::iterator it = colors.begin(); it != colors.end(); it++) {
00163         segments.push_back(it->second);
00164     }
00165 
00166 }
00167 
00168 void process(rosbag::Bag& results_bag, rosbag::Bag& gt_bag, const path& output_dir, const string& ochs_result_dir="") {
00169     static const int rb_max = 5;
00170 
00171     vector<string> labels;
00172     labels.push_back("time");
00173     labels.push_back("tp");
00174     labels.push_back("tn");
00175     labels.push_back("fp");
00176     labels.push_back("fn");
00177 
00178     map<string, vector<vector<double> > > results;
00179 
00180     // find topics
00181     std::vector<std::string> topics;
00182 
00183     topics.push_back("/camera/depth_registered/points");
00184     topics.push_back("/real_selected_points");
00185 
00186     std::vector<std::string> segment_topics;
00187     segment_topics.push_back("/shape_recons/segment_rb");
00188     segment_topics.push_back("/shape_recons/segment_depth_rb");
00189     segment_topics.push_back("/shape_recons/segment_color_rb");
00190     segment_topics.push_back("/shape_recons/segment_ext_d_and_c_rb");
00191     segment_topics.push_back("/shape_recons/segment_ext_d_rb");
00192     segment_topics.push_back("/shape_recons/segment_ext_c_rb");
00193 
00194     segment_topics.push_back("/shape_recons/segment_naive_rb");
00195     segment_topics.push_back("/shape_recons/segment_naive_depth_rb");
00196     segment_topics.push_back("/shape_recons/segment_naive_color_rb");
00197 
00198     for (vector<string>::iterator it = segment_topics.begin(); it != segment_topics.end(); it++) {
00199         for (int i = 2; i < rb_max; i++) {
00200             stringstream ss;
00201             ss << *it << i;
00202             topics.push_back(ss.str());
00203 
00204             cout << "       adding topic " << ss.str() << endl;
00205         }
00206     }
00207     cout << endl;
00208 
00209     rosbag::View view_results(results_bag, rosbag::TopicQuery(topics));
00210     rosbag::View view_gt(gt_bag, rosbag::TopicQuery(topics));
00211 
00212 
00213     vector<rosbag::View::const_iterator> gt_pc_list;
00214     vector<rosbag::View::const_iterator> res_full_pc_list;
00215     map< string, vector<rosbag::View::const_iterator> > res_seg_pc_map;
00216 
00217     // collect
00218     cout << "COLLECTING ground truth " << endl;
00219     rosbag::View::const_iterator git = view_gt.begin();
00220     for (; git != view_gt.end(); git++) {
00221         // get ground truth point cloud
00222         rosbag::MessageInstance const& m = *git;
00223         assert (m.getTopic() == "/real_selected_points");
00224 
00225         sensor_msgs::PointCloud2ConstPtr gt_msg = m.instantiate<sensor_msgs::PointCloud2>();
00226         cout << "    found gt at time: " << gt_msg->header.stamp << endl;
00227         gt_pc_list.push_back(git);
00228     }
00229     cout << endl;
00230 
00231     cout << "COLLECTING segmentation results" << endl;
00232     rosbag::View::const_iterator rit = view_results.begin();
00233     for (; rit != view_results.end(); rit++) {
00234         // get ground truth point cloud
00235         rosbag::MessageInstance const& m = *rit;
00236         if (m.getTopic() == "/camera/depth_registered/points") {
00237             sensor_msgs::PointCloud2ConstPtr pc_msg = m.instantiate<sensor_msgs::PointCloud2>();
00238             res_full_pc_list.push_back(rit);
00239             cout << " Found PC at time      " << pc_msg->header.stamp << endl;
00240         } else {
00241             sensor_msgs::PointCloud2ConstPtr pc_msg = m.instantiate<sensor_msgs::PointCloud2>();
00242             res_seg_pc_map[getTimeStampString(pc_msg->header.stamp)].push_back(rit);
00243             cout << " Found segment " << m.getTopic() << " at time " << pc_msg->header.stamp << endl;
00244 
00245             SRPointCloud::Ptr seg_pc(new SRPointCloud);
00246             rosbag::MessageInstance const& m = *rit;
00247             sensor_msgs::PointCloud2ConstPtr seg_msg = m.instantiate<sensor_msgs::PointCloud2>();
00248             pcl::fromROSMsg(*seg_msg, *seg_pc);
00249 
00250 //            SRPointCloud::Ptr seg_pc_no_nan(new SRPointCloud);
00251 //            std::vector<int> not_nan_indices;
00252 //            pcl::removeNaNFromPointCloud<SRPoint>(*seg_pc,*seg_pc_no_nan, not_nan_indices);
00253 //            cout << "   Segment contains " << seg_pc_no_nan->size() << " not-nan points" << endl;
00254 
00255         }
00256     }
00257 
00258     cout << "SUMMARY" << endl;
00259     cout << "  ground truth:   " << gt_pc_list.size() << " full point clouds " << endl;
00260     cout << "      segments:   " << res_full_pc_list.size() << " full point clouds " << endl;
00261     cout << "                  " << res_seg_pc_map.size() << " entries " << endl;
00262 
00263     cout << "---------------------------" << endl << endl;
00264 
00265     if (gt_pc_list.size() != res_full_pc_list.size()) {
00266         ROS_WARN_STREAM("Ground truth and result bag have different sizes!");
00267         if (gt_pc_list.size() > res_full_pc_list.size())
00268             ROS_WARN_STREAM("Assuming results contain a subset, but start at the same time step");
00269         else {
00270             ROS_ERROR_STREAM("Results bag has more than ground truth! aborting");
00271             return;
00272         }
00273     }
00274 
00275 
00276     // collect ochs results
00277     vector<string> ochs_results;
00278     if (ochs_result_dir != "") {
00279         get_ochs_result_file_list(ochs_result_dir, ochs_results);
00280     }
00281 
00282 
00284     // now iterate over the two
00285     vector<rosbag::View::const_iterator>::iterator gvit = gt_pc_list.begin();
00286     vector<rosbag::View::const_iterator>::iterator rvit = res_full_pc_list.begin();
00287     int idx=0;
00288 
00289     for (; gvit != gt_pc_list.end() && rvit != res_full_pc_list.end(); gvit++, rvit++, idx++) {
00290         // get ground truth PC
00291         rosbag::MessageInstance const& m_gt = **gvit;
00292         SRPointCloud::Ptr gt_pc_with_nan(new SRPointCloud);
00293         sensor_msgs::PointCloud2ConstPtr gt_msg = m_gt.instantiate<sensor_msgs::PointCloud2>();
00294         pcl::fromROSMsg(*gt_msg, *gt_pc_with_nan);
00295 
00296 //        SRPointCloud::Ptr gt_pc;
00297 //        gt_pc.reset(new SRPointCloud);
00298 //        std::vector<int> not_nan_indices;
00299 //        pcl::removeNaNFromPointCloud<SRPoint>(*gt_pc_with_nan,*gt_pc, not_nan_indices);
00300 //        cout << "Ground truth contains " << gt_pc->size() << " not-nan points" << endl;
00301 
00302         // get full scene PC
00303         rosbag::MessageInstance const& m_full = **rvit;
00304         sensor_msgs::PointCloud2ConstPtr full_msg = m_full.instantiate<sensor_msgs::PointCloud2>();
00305 
00306         cout << "TIME: " << full_msg->header.stamp << endl;
00307         cout << "    time ground truth: " << gt_msg->header.stamp << endl;
00308 
00309         // get ochs segments and take best
00310         if (!ochs_results.empty()) {
00311             cout << "   " <<  "Looking at Ochs result: " << idx << endl;
00312 
00313             SRPointCloud::Ptr full_pc(new SRPointCloud);
00314             pcl::fromROSMsg(*full_msg, *full_pc);
00315 
00316             cv::Mat ochs_result_current = cv::imread(ochs_results[idx]);
00317             vector<SRPointCloud::Ptr> ochs_segments;
00318             getOchsSegments(ochs_result_current, full_pc,  ochs_segments);
00319 
00320             // select best segment
00321             int best_ochs_segment = -1;
00322             double best_f_score = 0.;
00323             vector<double> res;
00324             for (int i= 0; i < ochs_segments.size(); i++) {
00325                 int tp, tn, fp, fn, error;
00326                 compareAlignedDensePointClouds(gt_pc_with_nan, ochs_segments[i], tp, tn, fp, fn, error);
00327                 double precision=0.0, recall=0.0, fscore=0.0;
00328 
00329                 precision = ((double)tp) / (tp+fp);
00330                 recall = ((double)tp) / (tp+fn);
00331                 fscore = 2* ((double) precision*recall)/(precision+recall);
00332 
00333                 cout << "   " << "  ochs segment " << i << " p=" << precision << ", r=" << recall << ", f=" << fscore << endl;
00334                 if (fscore>best_f_score) {
00335                     best_ochs_segment = i;
00336                     best_f_score = fscore;
00337                     cout << "     " << i << " is best so far" << endl;
00338                     res.clear();
00339                     res.push_back(full_msg->header.stamp.toSec());
00340                     res.push_back(tp); res.push_back(tn); res.push_back(fp); res.push_back(fn);
00341                 }
00342             }
00343             results[ "ochs" ].push_back(res);
00344 
00345             // <debug>
00346             cv::imshow("ochs segmentation", ochs_result_current);
00347             for (int i= 0; i < ochs_segments.size(); i++) {
00348                 stringstream nm;
00349                 nm << "segment " << i;
00350                 SRPointCloud::Ptr sgm_pc = ochs_segments[i];
00351                 cv::Mat sgm_dm(480,640,CV_32FC1);
00352                 OrganizedPC2DepthMap(sgm_pc, sgm_dm);
00353                 cv::imshow(nm.str(), sgm_dm);
00354             }
00355             //cv::waitKey(-1);
00356             //cv::waitKey(50);
00357             // </debug>
00358         }
00359 
00360 
00361         // compare also SR segments to ground truth
00362         vector<rosbag::View::const_iterator>& segment_list = res_seg_pc_map[getTimeStampString(full_msg->header.stamp)];
00363         cout << " Segment list contains " << segment_list.size() << " points" << endl;
00364         if (segment_list.empty()) {
00365             ROS_WARN_STREAM("No segments at time " << full_msg->header.stamp);
00366             continue;
00367         }
00368 
00369         vector<rosbag::View::const_iterator>::iterator svit = segment_list.begin();
00370         for (; svit != segment_list.end(); svit++) {
00371 
00372             SRPointCloud::Ptr seg_pc(new SRPointCloud);
00373             rosbag::MessageInstance const& m_res = **svit;
00374             sensor_msgs::PointCloud2ConstPtr seg_msg = m_res.instantiate<sensor_msgs::PointCloud2>();
00375             pcl::fromROSMsg(*seg_msg, *seg_pc);
00376 
00377 //            SRPointCloud::Ptr seg_pc_no_nan(new SRPointCloud);
00378 //            std::vector<int> not_nan_indices;
00379 //            pcl::removeNaNFromPointCloud<SRPoint>(*seg_pc,*seg_pc_no_nan, not_nan_indices);
00380 //            cout << "   Segment contains " << seg_pc_no_nan->size() << " not-nan points" << endl;
00381 
00382             int tp,fp,tn,fn,error;
00383             compareAlignedDensePointClouds(gt_pc_with_nan, seg_pc, tp, tn, fp, fn, error);
00384 
00385             /*
00386             cv::Mat gt_mat(480, 640, CV_8UC3), seg_mat(480, 640, CV_8UC3);
00387             omip::OrganizedPC2ColorMap(gt_pc_with_nan, gt_mat);
00388             omip::OrganizedPC2ColorMap(seg_pc, seg_mat);
00389 
00390             cv::Mat gt_depth_mat(480, 640, CV_32FC1), seg_depth_mat(480, 640, CV_32FC1), seg_depth_mat_rev(480, 640, CV_32FC1);
00391             omip::OrganizedPC2DepthMap(gt_pc_with_nan, gt_depth_mat);
00392             omip::OrganizedPC2DepthMap(seg_pc, seg_depth_mat);
00393             omip::OrganizedPC2DepthMap(seg_pc, seg_depth_mat_rev);
00394 
00395             cv::imshow("Ground truth", gt_mat);
00396             cv::imshow(m_res.getTopic(), seg_mat);
00397 
00398             cv::imshow("Ground truth depth", gt_depth_mat);
00399             cv::imshow(m_res.getTopic()  + " depth", seg_depth_mat);
00400             cv::imshow(m_res.getTopic()  + " depth rev", seg_depth_mat_rev);
00401             cv::waitKey(-1);
00402             */
00403 
00404             cout << m_res.getTopic() << endl;
00405             cout << "  tp= " << tp;
00406             cout << "  tn= " << tn;
00407             cout << "  fp= " << fp;
00408             cout << "  fn= " << fn << endl;
00409 
00410             vector<double> res;
00411             res.push_back(seg_msg->header.stamp.toSec());
00412             res.push_back(tp); res.push_back(tn); res.push_back(fp); res.push_back(fn);
00413             results[ m_res.getTopic() ].push_back(res);
00414         }
00415     }
00416 
00417 
00418     for (map<string, vector<vector<double> > >::iterator it = results.begin(); it != results.end(); it++) {
00419         cout << "Writing out results for " << it->first << endl;
00420         cout << "  has " << it->second.size() << " entries" << endl;
00421         // prepare output file
00422         vector<string> strs;
00423         boost::split(strs, it->first,boost::is_any_of("/"));
00424 
00425         path output_path = output_dir;;
00426         output_path /=  strs[strs.size()-1] + ".txt";
00427 
00428         cout <<"  Output path: " << output_path.string() << endl;
00429 
00430         ofstream output;
00431         output.open(output_path.string().c_str());
00432         writeCSV(output, labels, it->second);
00433         output.close();
00434     }
00435 }
00436 
00437 }
00438 
00439 // Main program
00440 int main(int argc, char** argv)
00441 {
00442     if (argc < 3) {
00443         cout << "Usage: rosrun statistics <full_pc_and_segmentation> <ground_truth> [ochs_results_dir]" << endl;
00444         return 0;
00445     }
00446 
00447     path results_bag_path(argv[1]);
00448     if (!exists(results_bag_path.string())) {
00449         cerr << " results bag does not exist:  " << results_bag_path.string() << endl;
00450         return -1;
00451     }
00452     path gt_bag_path(argv[2]);
00453     if (!exists(gt_bag_path.string())) {
00454         cerr << " ground truth bag does not exist:  " << gt_bag_path.string() << endl;
00455         return -1;
00456     }
00457 
00458     string ochs_result_dir("");
00459     if (argc > 3) {
00460         ochs_result_dir = argv[3];
00461     }
00462 
00463     // prepare out path
00464     path output_dir = results_bag_path.parent_path();
00465     output_dir /= results_bag_path.stem().string();
00466 
00467     if (!boost::filesystem::exists(output_dir)) {
00468         if (!boost::filesystem::create_directories(output_dir)) {
00469             ROS_ERROR_NAMED("statistics", "Output directory for statistics does not exist and cannot be created!");
00470             return -1;
00471         }
00472     }
00473 
00474     // open rosbags
00475     rosbag::Bag results_bag;
00476     results_bag.open(results_bag_path.string(), rosbag::bagmode::Read);
00477 
00478     rosbag::Bag gt_bag;
00479     gt_bag.open(gt_bag_path.string(), rosbag::bagmode::Read);
00480 
00481     omip::process(results_bag, gt_bag, output_dir, ochs_result_dir);
00482     results_bag.close();
00483     gt_bag.close();
00484 
00485     return (0);
00486 }


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:36:33