00001
00063 #include <map>
00064 #include <iostream>
00065 #include <iomanip>
00066
00067 #include <boost/program_options.hpp>
00068
00069 #include <pcl/io/pcd_io.h>
00070 #include <pcl/common/eigen.h>
00071 #include <pcl/filters/voxel_grid.h>
00072
00073 #include "cob_3d_mapping_common/label_defines.h"
00074 #include "cob_3d_mapping_common/polygon.h"
00075 #include "cob_3d_mapping_tools/io.h"
00076 #include "cob_3d_segmentation/polygon_extraction/polygon_types.h"
00077 #include "cob_3d_segmentation/polygon_extraction/polygon_extraction.h"
00078 #include "cob_3d_segmentation/plane_extraction.h"
00079
00080 typedef pcl::PointXYZRGB PointT;
00081 typedef pcl::PointCloud<PointT> PointCloud;
00082
00083 std::string pc_in, ppm_exp, ppm_pred;
00084
00085
00086 class Cluster;
00087 typedef std::map<int,Cluster> ClusterMap;
00088 std::ostream& operator<< (std::ostream&, Cluster&);
00089 std::string colorHumanReadable(int);
00090
00091 void printNoMatch(Cluster&);
00092 void compare(std::map<int,Cluster>&, std::map<int,Cluster>&);
00093 void pca(PointCloud::Ptr, Cluster&);
00094 void fillPolygonPtr(Cluster& c, cob_3d_segmentation::PolygonContours<cob_3d_segmentation::PolygonPoint>& contour);
00095 void createClusters(PointCloud::Ptr, std::map<int,Cluster>&);
00096
00097
00098 void readOptions(int argc, char* argv[])
00099 {
00100 using namespace boost::program_options;
00101 options_description options("Options");
00102 options.add_options()
00103 ("help", "produce help message")
00104 ("pc_in", value<std::string>(&pc_in), "pcd")
00105 ("ppm_exp", value<std::string>(&ppm_exp), "ppm expected")
00106 ("ppm_pred", value<std::string>(&ppm_pred), "ppm predicted")
00107 ;
00108
00109 positional_options_description p_opt;
00110 p_opt.add("pc_in", 1).add("ppm_exp", 1).add("ppm_pred", 1);
00111 variables_map vm;
00112 store(command_line_parser(argc, argv).options(options).positional(p_opt).run(), vm);
00113 notify(vm);
00114
00115 if (vm.count("help") || !vm.count("pc_in") || !vm.count("ppm_exp") || !vm.count("ppm_pred"))
00116 {
00117 std::cout <<"Compare plane segments" << std::endl;
00118 std::cout <<"<point cloud pcd> <ppm expected> <ppm predicted>" << std::endl;
00119 std::cout << options << std::endl;
00120 exit(0);
00121 }
00122 }
00123
00124 class Cluster
00125 {
00126 public:
00127 Cluster(int id_)
00128 : id(id_)
00129 , centroid(Eigen::Vector3f::Zero())
00130 , comp1(Eigen::Vector3f::Zero())
00131 , comp2(Eigen::Vector3f::Zero())
00132 , comp3(Eigen::Vector3f::Zero())
00133 , values(Eigen::Vector3f::Zero())
00134 , poly(new cob_3d_mapping::Polygon)
00135 { }
00136
00137 inline void addBorder(int x, int y) { borders.push_back(cob_3d_segmentation::PolygonPoint(x,y)); }
00138 inline void addPoint(int idx) { indices.push_back(idx); }
00139
00140 friend std::ostream& operator<<( std::ostream& out, Cluster& c);
00141
00142 int id;
00143 std::vector<int> indices;
00144 std::vector<cob_3d_segmentation::PolygonPoint> borders;
00145
00146 Eigen::Vector3f centroid;
00147 Eigen::Vector3f comp1;
00148 Eigen::Vector3f comp2;
00149 Eigen::Vector3f comp3;
00150 Eigen::Vector3f values;
00151 cob_3d_mapping::Polygon::Ptr poly;
00152 };
00153
00154 std::string colorHumanReadable(int id)
00155 {
00156 std::stringstream ss;
00157 ss << "0x" << std::setfill('0') << std::setw(6) << std::right << std::hex << id << std::dec;
00158 return ss.str();
00159 }
00160
00161 std::ostream& operator<< (std::ostream& out, Cluster& c)
00162 {
00163 out << colorHumanReadable(c.id) << " {";
00164
00165
00166 out << "Size: " << std::setw(6) << std::right << c.indices.size();
00167 out << " N: " << std::setiosflags(std::ios::fixed) << std::setprecision(6)
00168 << std::setw(9) << std::right << c.comp3(0) <<","
00169 << std::setw(9) << std::right << c.comp3(1) <<","
00170 << std::setw(9) << std::right << c.comp3(2);
00171
00172
00173
00174 out<<"}";
00175 return out;
00176 }
00177
00178 void printNoMatch(Cluster& c)
00179 {
00180 std::cout << "No Match: " << c << std::endl;
00181 }
00182
00183 void printForFile(ClusterMap& exp, ClusterMap& pred)
00184 {
00185 int count_no = 0;
00186
00187
00188 const int padding = 3;
00189 std::stringstream ss;
00190 ss << exp.begin()->second;
00191 int col = ss.str().length() + padding;
00192 std::string sep = "| ";
00193 std::cout <<" - \t"<<" - \t"<<"labeled\t"<<" - \t"<<" - \t"<<"-\t"<<" - \t\t"
00194 <<"plane extraction" << std::endl;
00195 std::cout <<"color\t"<<"size\t"<<" n_x\t"<<"n_y\t"<<"n_z\t"<<"d\t"<<"area\t\t"
00196 <<" n_x\t"<<"n_y\t"<<"n_z\t"<<"d\t"<<"area\t"<<"A_diff\t"<<"dot"<<std::endl;
00197 for(ClusterMap::iterator it=exp.begin(); it!= exp.end(); ++it)
00198 {
00199 cob_3d_mapping::Polygon::Ptr p1 = it->second.poly;
00200 float area1 = p1->computeArea3d();
00201 std::cout << colorHumanReadable(it->second.id) << "\t"
00202 << it->second.indices.size() << "\t"
00203 << it->second.comp3[0] << "\t"
00204 << it->second.comp3[1] << "\t"
00205 << it->second.comp3[2] << "\t"
00206 << it->second.centroid.dot(it->second.comp3) << "\t"
00207 << area1 << "\t\t";
00208 ClusterMap::iterator match = pred.find(it->first);
00209 if (match == pred.end())
00210 {
00211 std::cout << "no match" << std::endl;
00212 ++count_no;
00213 continue;
00214 }
00215 float alpha = it->second.comp3.dot(match->second.comp3);
00216 cob_3d_mapping::Polygon::Ptr p2 = match->second.poly;
00217 float area2 = p2->computeArea3d();
00218 float area_diff = 0;
00219
00220
00221
00222
00223
00224
00225 if(p1->isIntersectedWith(p2))
00226 {
00227 area_diff = std::abs(area1 - area2);
00228 }
00229
00230 std::cout << match->second.comp3[0] << "\t"
00231 << match->second.comp3[1] << "\t"
00232 << match->second.comp3[2] << "\t"
00233 << match->second.centroid.dot(match->second.comp3) << "\t"
00234 << area2 << "\t"
00235 << area_diff << "\t"
00236 << alpha << std::endl;
00237 }
00238 }
00239
00240 void compare(ClusterMap& exp, ClusterMap& pred)
00241 {
00242 int count_no = 0;
00243
00244
00245 const int padding = 3;
00246 std::stringstream ss;
00247 ss << exp.begin()->second;
00248 int col = ss.str().length() + padding;
00249 std::string sep = "| ";
00250
00251 for(ClusterMap::iterator it=exp.begin(); it!= exp.end(); ++it)
00252 {
00253 ClusterMap::iterator match = pred.find(it->first);
00254 if (match == pred.end())
00255 {
00256 std::stringstream ss1;
00257 ss1 << it->second;
00258 std::cout << std::setw(col) << std::left << ss1.str() << sep
00259 << std::setw(round(0.3*col)) << " "
00260 << std::setw(round(0.7*col)) << std::left << "--- No Match ---" << sep << std::endl;
00261 ++count_no;
00262 continue;
00263 }
00264 float alpha = it->second.comp3.dot(match->second.comp3);
00265
00266 cob_3d_mapping::Polygon::Ptr p1 = it->second.poly;
00267 cob_3d_mapping::Polygon::Ptr p2 = match->second.poly;
00268 float area1 = p1->computeArea3d();
00269 float area2 = p2->computeArea3d();
00270 float area_diff = 0;
00271 if(p1->isIntersectedWith(p2))
00272 {
00273 area_diff = std::abs(area1 - area2);
00274 }
00275
00276 std::stringstream ss1, ss2;
00277 ss1 << it->second;
00278 ss2 << match->second;
00279 std::cout << std::setw(col) << std::left << ss1.str() << sep
00280 << std::setw(col) << std::left << ss2.str() << sep
00281 << "Dot: " << std::setw(9) << std::left << std::setiosflags(std::ios::fixed) << std::setprecision(6) << alpha
00282 << " A1: "<< area1 << " A2: "<< area2 << " A_Diff: " << area_diff << std::endl;
00283 }
00284 count_no = exp.size() - count_no;
00285 std::cout << "Results:" << std::endl
00286 << std::setw(30) << std::left << "Matching Accuracy"<<"= ("<<count_no<<"/"<<exp.size()<<") "
00287 << std::setiosflags(std::ios::fixed)<<std::setprecision(2)<<(float)count_no/(float)exp.size()*100.0f << "%" << std::endl;
00288 }
00289
00290 void pca(PointCloud::Ptr cloud, Cluster& c)
00291 {
00292 for(std::vector<int>::iterator it=c.indices.begin(); it!=c.indices.end(); ++it)
00293 c.centroid += (*cloud)[*it].getVector3fMap();
00294 c.centroid /= c.indices.size();
00295
00296 Eigen::Matrix3f cov(Eigen::Matrix3f::Zero());
00297 for(std::vector<int>::iterator it=c.indices.begin(); it!=c.indices.end(); ++it)
00298 {
00299 Eigen::Vector3f demean = (*cloud)[*it].getVector3fMap() - c.centroid;
00300 cov += demean * demean.transpose();
00301 }
00302
00303 Eigen::Matrix3f eigenvectors;
00304 pcl::eigen33(cov, eigenvectors, c.values);
00305 c.values /= c.indices.size();
00306 c.comp1 = eigenvectors.col(2);
00307 c.comp2 = eigenvectors.col(1);
00308 c.comp3 = eigenvectors.col(0);
00309 }
00310
00311 void fillPolygonPtr(Cluster& c, cob_3d_segmentation::PolygonContours<cob_3d_segmentation::PolygonPoint>& contour, PointCloud::Ptr cloud)
00312 {
00313 c.poly->centroid << c.centroid, 0;
00314 c.poly->computeAttributes(c.comp3, c.poly->centroid);
00315 int max_points = -1, max_idx = -1;
00316 for (size_t i=0; i<contour.polys_.size(); ++i)
00317 {
00318 if ((int)contour.polys_[i].size() > max_points) { max_points = contour.polys_[i].size(); max_idx = i; }
00319 }
00320
00321 for (size_t i=0; i<contour.polys_.size(); ++i)
00322 {
00323 c.poly->contours.push_back(std::vector<Eigen::Vector3f>());
00324 if ((int)i == max_idx)
00325 {
00326 c.poly->holes.push_back(false);
00327 std::vector<cob_3d_segmentation::PolygonPoint>::iterator it = contour.polys_[i].begin();
00328 for( ; it != contour.polys_[i].end(); ++it)
00329 c.poly->contours.back().push_back( (*cloud)[cob_3d_segmentation::PolygonPoint::getInd(it->x, it->y)].getVector3fMap() );
00330 }
00331 else
00332 {
00333 c.poly->holes.push_back(true);
00334 std::vector<cob_3d_segmentation::PolygonPoint>::reverse_iterator it = contour.polys_[i].rbegin();
00335 for( ; it != contour.polys_[i].rend(); ++it)
00336 c.poly->contours.back().push_back( (*cloud)[cob_3d_segmentation::PolygonPoint::getInd(it->x, it->y)].getVector3fMap() );
00337 }
00338 }
00339 }
00340
00341 void createClusters(PointCloud::Ptr cloud, ClusterMap& cmap)
00342 {
00343 int w = cloud->width, h = cloud->height, s = cloud->size();
00344 int mask[] = { -w, 1, w, -1 };
00345 int mask_size = 4;
00346
00347 for(int idx=0; idx < s; ++idx)
00348 {
00349 int id = (*cloud)[idx].rgba;
00350 int x = idx % w;
00351 int y = idx / w;
00352 int count = 0;
00353
00354 ClusterMap::iterator it = cmap.find(id);
00355 if (it == cmap.end())
00356 {
00357
00358 it = cmap.insert( std::pair<int,Cluster>(id, Cluster(id)) ).first;
00359 }
00360 if (y == 0 || y == h-1 || x == 0 || x == w-1)
00361 {
00362 it->second.addBorder(x,y);
00363 }
00364 else
00365 {
00366 for(int i=0;i<mask_size;++i) { if (id != (*cloud)[idx+mask[i]].rgba) { ++count; } }
00367 if (count < 1) { it->second.addPoint(idx); }
00368 else { it->second.addBorder(x,y); }
00369 }
00370 }
00371
00372 cob_3d_segmentation::PolygonExtraction pe;
00373 ClusterMap::iterator it=cmap.begin();
00374 while(it!=cmap.end())
00375 {
00376 if (it->first == 0xFFFFFF || it->first == LBL_UNDEF || it->second.indices.size() <= 5)
00377 {
00378
00379 cmap.erase(it++);
00380 }
00381 else
00382 {
00383
00384 cob_3d_segmentation::PolygonContours<cob_3d_segmentation::PolygonPoint> poly;
00385 pe.outline(w, h, it->second.borders, poly);
00386 pca(cloud, it->second);
00387 fillPolygonPtr(it->second, poly, cloud);
00388 ++it;
00389 }
00390 }
00391 }
00392
00393 int main(int argc, char** argv)
00394 {
00395 readOptions(argc, argv);
00396
00397 PointCloud::Ptr pc_exp(new PointCloud);
00398 PointCloud::Ptr pc_pred(new PointCloud);
00399 pcl::PCDReader pcd;
00400 cob_3d_mapping_tools::PPMReader ppm;
00401 if (pcd.read(pc_in, *pc_exp) == -1) exit(0);
00402 *pc_pred = *pc_exp;
00403 if (ppm.mapRGB(ppm_exp, *pc_exp, false) == -1) { std::cout<<"Mapping error ["<<ppm_exp<<"]"<<std::endl; exit(0); }
00404 if (ppm.mapRGB(ppm_pred, *pc_pred, false) == -1) { std::cout<<"Mapping error ["<<ppm_pred<<"]"<<std::endl; exit(0); }
00405
00406 ClusterMap exp;
00407 createClusters(pc_exp, exp);
00408
00409 ClusterMap pred;
00410 createClusters(pc_pred, pred);
00411
00412 printForFile(exp, pred);
00413
00414 return 0;
00415 }