RangeImagePlanar.hpp
Go to the documentation of this file.
00001 /*
00002  * RangeImagePlanar.hpp
00003  *
00004  *      Author: roberto
00005  *
00006  * This is a modified implementation of the method for online estimation of kinematic structures described in our paper
00007  * "Online Interactive Perception of Articulated Objects with Multi-Level Recursive Estimation Based on Task-Specific Priors"
00008  * (Martín-Martín and Brock, 2014) and the extension to segment, reconstruct and track shapes introduced in our paper
00009  * "An Integrated Approach to Visual Perception of Articulated Objects" (Martín-Martín, Höfer and Brock, 2016)
00010  * This implementation can be used to reproduce the results of the paper and to be applied to new research.
00011  * The implementation allows also to be extended to perceive different information/models or to use additional sources of information.
00012  * A detail explanation of the method and the system can be found in our paper.
00013  *
00014  * If you are using this implementation in your research, please consider citing our work:
00015  *
00016 @inproceedings{martinmartin_ip_iros_2014,
00017 Title = {Online Interactive Perception of Articulated Objects with Multi-Level Recursive Estimation Based on Task-Specific Priors},
00018 Author = {Roberto {Mart\'in-Mart\'in} and Oliver Brock},
00019 Booktitle = {Proceedings of the IEEE/RSJ International Conference on Intelligent Robots and Systems},
00020 Pages = {2494-2501},
00021 Year = {2014},
00022 Location = {Chicago, Illinois, USA},
00023 Note = {http://www.robotics.tu-berlin.de/fileadmin/fg170/Publikationen_pdf/martinmartin_ip_iros_2014.pdf},
00024 Url = {http://www.robotics.tu-berlin.de/fileadmin/fg170/Publikationen_pdf/martinmartin_ip_iros_2014.pdf},
00025 Projectname = {Interactive Perception}
00026 }
00027 
00028 @inproceedings{martinmartin_hoefer_iros_2016,
00029 Title = {An Integrated Approach to Visual Perception of Articulated Objects},
00030 Author = {Roberto {Mart\'{i}n-Mart\'{i}n} and Sebastian H\"ofer and Oliver Brock},
00031 Booktitle = {Proceedings of the IEEE International Conference on Robotics and Automation},
00032 Pages = {5091 - 5097},
00033 Year = {2016},
00034 Doi = {10.1109/ICRA.2016.7487714},
00035 Location = {Stockholm, Sweden},
00036 Month = {05},
00037 Note = {http://www.redaktion.tu-berlin.de/fileadmin/fg170/Publikationen_pdf/martin_hoefer_15_iros_sr_opt.pdf},
00038 Url = {http://www.redaktion.tu-berlin.de/fileadmin/fg170/Publikationen_pdf/martin_hoefer_15_iros_sr_opt.pdf},
00039 Url2 = {http://ieeexplore.ieee.org/xpl/articleDetails.jsp?tp=&arnumber=7487714},
00040 Projectname = {Interactive Perception}
00041 }
00042  * If you have questions or suggestions, contact us:
00043  * roberto.martinmartin@tu-berlin.de
00044  *
00045  * Enjoy!
00046  */
00047 
00048 #ifndef SHAPE_RECONSTRUCTION_RANGE_IMAGE_PLANAR_IMPL
00049 #define SHAPE_RECONSTRUCTION_RANGE_IMAGE_PLANAR_IMPL
00050 
00051 #include "shape_reconstruction/RangeImagePlanar.h"
00052 
00053 #include <opencv2/core/core.hpp>
00054 
00055 namespace shape_reconstruction {
00056 
00057 template <typename PointCloudType> void
00058 RangeImagePlanar::doZBufferAndStorePoints (const PointCloudType& point_cloud,
00059                                            float noise_level, float min_range, int& top, int& right, int& bottom, int& left)
00060 {
00061     typedef typename PointCloudType::PointType PointType2;
00062     const typename pcl::PointCloud<PointType2>::VectorType &points2 = point_cloud.points;
00063 
00064     unsigned int size = width*height;
00065     int* counters = new int[size];
00066     ERASE_ARRAY (counters, size);
00067 
00068     resetPointIndex(width, height);
00069 
00070     top=height; right=-1; bottom=-1; left=width;
00071 
00072     float x_real, y_real, range_of_current_point;
00073     int x, y;
00074     int idx=0;
00075 
00076     for (typename pcl::PointCloud<PointType2>::VectorType::const_iterator it=points2.begin (); it!=points2.end (); ++it, ++idx)
00077     {
00078         if (!isFinite (*it))  // Check for NAN etc
00079             continue;
00080         pcl::Vector3fMapConst current_point = it->getVector3fMap ();
00081 
00082         this->getImagePoint (current_point, x_real, y_real, range_of_current_point);
00083         this->real2DToInt2D (x_real, y_real, x, y);
00084 
00085         if (range_of_current_point < min_range|| !isInImage (x, y))
00086             continue;
00087         //std::cout << " ("<<current_point[0]<<", "<<current_point[1]<<", "<<current_point[2]<<") falls into pixel "<<x<<","<<y<<".\n";
00088 
00089         // Do some minor interpolation by checking the three closest neighbors to the point, that are not filled yet.
00090         int floor_x = pcl_lrint (floor (x_real)), floor_y = pcl_lrint (floor (y_real)),
00091                 ceil_x  = pcl_lrint (ceil (x_real)),  ceil_y  = pcl_lrint (ceil (y_real));
00092 
00093         int neighbor_x[4], neighbor_y[4];
00094         neighbor_x[0]=floor_x; neighbor_y[0]=floor_y;
00095         neighbor_x[1]=floor_x; neighbor_y[1]=ceil_y;
00096         neighbor_x[2]=ceil_x;  neighbor_y[2]=floor_y;
00097         neighbor_x[3]=ceil_x;  neighbor_y[3]=ceil_y;
00098         //std::cout << x_real<<","<<y_real<<": ";
00099 
00100         for (int i=0; i<4; ++i)
00101         {
00102             int n_x=neighbor_x[i], n_y=neighbor_y[i];
00103             //std::cout << n_x<<","<<n_y<<" ";
00104             if (n_x==x && n_y==y)
00105                 continue;
00106             if (isInImage (n_x, n_y))
00107             {
00108                 int neighbor_array_pos = n_y*width + n_x;
00109                 if (counters[neighbor_array_pos]==0)
00110                 {
00111                     float& neighbor_range = points[neighbor_array_pos].range;
00112                     //neighbor_range = (pcl_isinf (neighbor_range) ? range_of_current_point : (std::min) (neighbor_range, range_of_current_point));
00113                     top= (std::min) (top, n_y); right= (std::max) (right, n_x); bottom= (std::max) (bottom, n_y); left= (std::min) (left, n_x);
00114 
00115                     if (pcl_isinf (neighbor_range) || range_of_current_point < neighbor_range) {
00116                         neighbor_range = range_of_current_point;
00117                         setPointIndex(n_x, n_y, idx);
00118                     }
00119 
00120                     //img_coord_to_point_idx[std::make_pair(n_x,n_y)] = idx;
00121 //                    std::cout << "Interpolating point "<<n_x<<","<<n_y << std::endl;
00122 //                    std::cout << " --> idx=" << idx << ", val=" << neighbor_range<< std::endl;
00123                 }
00124             }
00125         }
00126         //std::cout <<std::endl;
00127 
00128         // The point itself
00129         int arrayPos = y*width + x;
00130         float& range_at_image_point = points[arrayPos].range;
00131         int& counter = counters[arrayPos];
00132         bool addCurrentPoint=false, replace_with_current_point=false;
00133 
00134         if (counter==0)
00135         {
00136             replace_with_current_point = true;
00137         }
00138         else
00139         {
00140             if (range_of_current_point < range_at_image_point-noise_level)
00141             {
00142                 replace_with_current_point = true;
00143             }
00144             else if (fabs (range_of_current_point-range_at_image_point)<=noise_level)
00145             {
00146                 addCurrentPoint = true;
00147             }
00148         }
00149 
00150         if (replace_with_current_point)
00151         {
00152 //            if (counter == 0) {
00153 //                std::cout << "Replacing point "<<x<<","<<y;
00154 //            } else {
00155 //                std::cout << "Add point "<<x<<","<<y << std::endl;
00156 //                std::cout << ", was " << img_coord_to_point_idx[std::make_pair(x,y)];
00157 //            }
00158 //            std::cout << " --> idx=" << idx << ", val=" << range_of_current_point<< std::endl;
00159 
00160             counter = 1;
00161             range_at_image_point = range_of_current_point;
00162             top= (std::min) (top, y); right= (std::max) (right, x); bottom= (std::max) (bottom, y); left= (std::min) (left, x);
00163 
00164             setPointIndex(x, y, idx);
00165         }
00166         else if (addCurrentPoint)
00167         {
00168             ++counter;
00169             range_at_image_point += (range_of_current_point-range_at_image_point)/counter;
00170             //std::cout << "Averaging point "<<x<<","<<y << std::endl;
00171         }
00172 
00173     }
00174     delete[] counters;
00175 }
00176 
00178 template <typename PointCloudType> void
00179 RangeImagePlanar::createFromPointCloudWithFixedSizeAndStorePoints(const PointCloudType& point_cloud,
00180                                   int di_width, int di_height,
00181                                   float di_center_x, float di_center_y,
00182                                   float di_focal_length_x, float di_focal_length_y,
00183                                   const Eigen::Affine3f& sensor_pose,
00184                                   CoordinateFrame coordinate_frame, float noise_level,
00185                                   float min_range)
00186 {
00187   //std::cout << "Starting to create range image from "<<point_cloud.points.size ()<<" points.\n";
00188 
00189   width = di_width;
00190   height = di_height;
00191   center_x_ = di_center_x;
00192   center_y_ = di_center_y;
00193   focal_length_x_ = di_focal_length_x;
00194   focal_length_y_ = di_focal_length_y;
00195   focal_length_x_reciprocal_ = 1 / focal_length_x_;
00196   focal_length_y_reciprocal_ = 1 / focal_length_y_;
00197 
00198   is_dense = false;
00199 
00200   getCoordinateFrameTransformation (coordinate_frame, to_world_system_);
00201   to_world_system_ = sensor_pose * to_world_system_;
00202 
00203   to_range_image_system_ = to_world_system_.inverse (Eigen::Isometry);
00204 
00205   unsigned int size = width*height;
00206   points.clear ();
00207   points.resize (size, unobserved_point);
00208 
00209   int top=height, right=-1, bottom=-1, left=width;
00210 
00211   doZBufferAndStorePoints (point_cloud, noise_level, min_range, top, right, bottom, left);
00212 
00213   // Do not crop
00214   //cropImage (border_size, top, right, bottom, left);
00215   recalculate3DPointPositions ();
00216 }
00217 
00219 
00220 template <typename PointCloudType> void
00221 RangeImagePlanar::computeZandMatchingPoints (const PointCloudType& point_cloud,
00222                                            //float noise_level,
00223                                            float min_range,
00224                                            const cv::Mat& matching_im, const float matching_im_min_range,
00225                                            pcl::PointIndicesPtr& matching_indices_in_pc,
00226                                            pcl::PointIndicesPtr& matching_indices_in_matching_im,
00227                                            pcl::PointIndicesPtr& indices_to_remove,
00228                                            int height, int width)
00229 {
00230     assert (height == matching_im.rows);
00231     assert (width == matching_im.cols);
00232     assert (matching_indices_in_pc);
00233     assert (matching_indices_in_matching_im);
00234     assert (indices_to_remove);
00235     assert (matching_im.type() == CV_32FC1);
00236 
00237     // debug
00238     pcl::PointIndicesPtr occluded_indices(new pcl::PointIndices);
00239 
00240     int top=height;
00241     int right=-1;
00242     int bottom=-1;
00243     int left=width;
00244 
00245     typedef typename PointCloudType::PointType PointType2;
00246     const typename pcl::PointCloud<PointType2>::VectorType &points2 = point_cloud.points;
00247 
00248     unsigned int size = width*height;
00249     int* counters = new int[size];
00250     ERASE_ARRAY (counters, size);
00251 
00252     std::vector<bool> removal_candidates(points2.size(), true);
00253     std::vector<bool> matching_in_matching_m(size, false);
00254 
00255     top=height; right=-1; bottom=-1; left=width;
00256 
00257     float x_real, y_real, range_of_current_point;
00258     int x, y;
00259     int idx=0;
00260     int matching_im_idx=0;
00261     for (typename pcl::PointCloud<PointType2>::VectorType::const_iterator it=points2.begin (); it!=points2.end (); ++it, ++idx)
00262     {
00263         if (!isFinite (*it))  { // Check for NAN etc
00264             ROS_ERROR_STREAM_NAMED("RangeImagePlanar.computeZandMatchingPoints", "Error! Point " << idx << " is NaN!");
00265             throw 0;
00266             //continue;
00267         }
00268 
00269         pcl::Vector3fMapConst current_point = it->getVector3fMap ();
00270 
00271         this->getImagePoint (current_point, x_real, y_real, range_of_current_point);
00272         this->real2DToInt2D (x_real, y_real, x, y);
00273 
00274         if (range_of_current_point < min_range|| !isInImage (x, y)) {
00275             removal_candidates[idx] = false;
00276             occluded_indices->indices.push_back(idx); // DEBUGGING
00277             continue;
00278         }
00279 
00280         // calculate z for current point
00281         Eigen::Vector3f current_point_z;
00282         calculate3DPoint(x, y, range_of_current_point, current_point_z);
00283 
00284         // get values from matching image
00285         float m_im_z = matching_im.at< float >(y,x);
00286         matching_im_idx = y*width+x;
00287 
00288         // do some minor interpolation by comparing the z value of the
00289         // projected point cloud to the z value of the to the four closest neighbors
00290         // in the matching_im.
00291         int floor_x = pcl_lrint (floor (x_real)), floor_y = pcl_lrint (floor (y_real)),
00292                 ceil_x  = pcl_lrint (ceil (x_real)),  ceil_y  = pcl_lrint (ceil (y_real));
00293         int neighbor_x[4], neighbor_y[4];
00294         neighbor_x[0]=floor_x; neighbor_y[0]=floor_y;
00295         neighbor_x[1]=floor_x; neighbor_y[1]=ceil_y;
00296         neighbor_x[2]=ceil_x;  neighbor_y[2]=floor_y;
00297         neighbor_x[3]=ceil_x;  neighbor_y[3]=ceil_y;
00298 
00299         for (int i=0; i<4; ++i)
00300         {
00301             int n_x=neighbor_x[i], n_y=neighbor_y[i];
00302             if (n_x==x && n_y==y)
00303                 continue;
00304 
00305             //int neighbor_array_pos = n_y*width + n_x;
00306             //float& neighbor_range = points[neighbor_array_pos].range;
00307 
00308             // if the neighbor location is outside the image we cannot compare
00309             if (!isInImage (n_x, n_y)) {
00310                 continue;
00311             }
00312             float n_m_im_z = matching_im.at< float >(n_y,n_x);
00313 
00314             // if matching_im is nan at this point we cannot compare
00315             if (isnan(n_m_im_z)) {
00316                 continue;
00317             }
00318 
00319 
00320             // if PC's z matches to the matching_im at the neighbor's position, we keep it and are done
00321             if ( fabs(n_m_im_z - current_point_z[2]) < matching_im_min_range) {
00322                 removal_candidates[idx] = false;
00323 
00324                 matching_im_idx = n_y*width+n_x;
00325                 // avoid adding duplicates
00326                 if (!matching_in_matching_m[matching_im_idx]) {
00327                     matching_indices_in_matching_im->indices.push_back(matching_im_idx);
00328                     matching_in_matching_m[matching_im_idx] = true;
00329                 }
00330 
00331 //                std::stringstream debug;
00332 //                debug << " Neighbor search -> keeping " << idx
00333 //                 << " (x,y)=" << x << "," << y << " "<< " (n_x,n_y)=" << n_x << "," << n_y
00334 //                 << " matching_im.n_z=" << m_im_z << ", "
00335 //                 << " matching_im.z=" << n_m_im_z << " vs. z=" << current_point_z[2] << std::endl;
00336 //                ROS_DEBUG_STREAM_NAMED("RangeImagePlanar.computeZandMatchingPoints", debug.str());
00337 
00338                 // do not break in order to get all matching_indices_in_matching_im
00339                 //break;
00340             }
00341 
00342             // matching_im neighbor's z is either lower (occluding) or higher (occluded) than the PC's z.
00343             // so leave the decision to comparing at x,y
00344         }
00345         if (removal_candidates[idx] == false) {
00346             // the neighbor computation found a match; we don't need to look further
00347             matching_indices_in_pc->indices.push_back(idx);
00348             //matching_indices_in_matching_im->indices.push_back(matching_im_idx);
00349             continue;
00350         }
00351 
00352         // can't say anything about nan image point
00353         if (isnan(m_im_z)) {
00354             removal_candidates[idx] = false;
00355             occluded_indices->indices.push_back(idx); // DEBUGGING
00356             continue;
00357         }
00358 
00359 
00360         if ( fabs(m_im_z - current_point_z[2]) < matching_im_min_range) {
00361             // keep this point
00362             removal_candidates[idx] = false;
00363             matching_indices_in_pc->indices.push_back(idx);
00364             matching_indices_in_matching_im->indices.push_back(matching_im_idx);
00365             continue;
00366         }
00367 
00368         // value from image closer than projected point
00369         // -> current point is occluded, keep!
00370         if ( m_im_z < current_point_z[2] ) {
00371             removal_candidates[idx] = false;
00372             occluded_indices->indices.push_back(idx); // DEBUGGING
00373             continue;
00374         }
00375 
00376 
00377 
00378         /*
00379         // Do some minor interpolation by checking the three closest neighbors to the point, that are not filled yet.
00380         int floor_x = pcl_lrint (floor (x_real)), floor_y = pcl_lrint (floor (y_real)),
00381                 ceil_x  = pcl_lrint (ceil (x_real)),  ceil_y  = pcl_lrint (ceil (y_real));
00382 
00383         int neighbor_x[4], neighbor_y[4];
00384         neighbor_x[0]=floor_x; neighbor_y[0]=floor_y;
00385         neighbor_x[1]=floor_x; neighbor_y[1]=ceil_y;
00386         neighbor_x[2]=ceil_x;  neighbor_y[2]=floor_y;
00387         neighbor_x[3]=ceil_x;  neighbor_y[3]=ceil_y;
00388 
00389         for (int i=0; i<4; ++i)
00390         {
00391             int n_x=neighbor_x[i], n_y=neighbor_y[i];
00392             //std::cout << n_x<<","<<n_y<<" ";
00393             if (n_x==x && n_y==y)
00394                 continue;
00395             if (isInImage (n_x, n_y))
00396             {
00397                 int neighbor_array_pos = n_y*width + n_x;
00398                 if (counters[neighbor_array_pos]==0)
00399                 {
00400                     float& neighbor_range = points[neighbor_array_pos].range;
00401                     neighbor_range = (pcl_isinf (neighbor_range) ? range_of_current_point : (std::min) (neighbor_range, range_of_current_point));
00402                     top= (std::min) (top, n_y); right= (std::max) (right, n_x); bottom= (std::max) (bottom, n_y); left= (std::min) (left, n_x);
00403 
00404                     Eigen::Vector3f n_point;
00405                     calculate3DPoint(n_x, n_y, neighbor_range, n_point);
00406 
00407                     if ( fabs(m_im_z - n_point[2]) < matching_im_min_range) {
00408                         // remove this point
00409                         matching_indices->indices.push_back(idx);
00410                         removal_candidates[idx] = false;
00411                         break;
00412                     }
00413 
00414                 }
00415             }
00416         }
00417         */
00418     }
00419 
00420     // finally collect removal_candidates
00421     for (int i = 0; i < points2.size(); i++) {
00422         if (removal_candidates[i]) {
00423           indices_to_remove->indices.push_back(i);
00424         }
00425     }
00426 
00427     // sanity check
00428 //    for (int i = 0; i < points2.size(); i++) {
00429 //        if (!isFinite(points2[i])) {
00430 //            ROS_ERROR_STREAM_NAMED("RangeImagePlanar.computeZandMatchingPoints", "Error! Point " << i << " is NaN!");
00431 //            throw 0;
00432 //        }
00433 //    }
00434 
00435 //    {
00436 //    std::stringstream debug;
00437 //    debug << " occluded = " << occluded_indices->indices.size();
00438 //    debug << " matching = " << matching_indices_in_pc->indices.size();
00439 //    debug << " matching in dm_source = " << matching_indices_in_matching_im->indices.size();
00440 //    debug << " removal  = " << indices_to_remove->indices.size() << std::endl;
00441 //    debug << "  SUM = " << (occluded_indices->indices.size()+indices_to_remove->indices.size()+matching_indices_in_pc->indices.size()) << std::endl;
00442 //    debug << "  TOTAL = " << points2.size() << std::endl;
00443 //    }
00444 
00445     delete[] counters;
00446 
00447 }
00448 
00449 
00450 template <typename PointCloudType> void
00451 RangeImagePlanar::matchPointCloudAndImage (const PointCloudType& point_cloud,
00452                                            int di_width, int di_height,
00453                                            float di_center_x, float di_center_y,
00454                                            float di_focal_length_x, float di_focal_length_y,
00455                                            const Eigen::Affine3f& sensor_pose,
00456                                            CoordinateFrame coordinate_frame,
00457                                            const cv::Mat& matching_im, const float matching_im_min_range,
00458                                            pcl::PointIndicesPtr& matching_indices,
00459                                            pcl::PointIndicesPtr& matching_indices_in_matching_im,
00460                                            pcl::PointIndicesPtr& indices_to_remove,
00461                                            float min_range
00462                                            )
00463 {
00464   //std::cout << "Starting to create range image from "<<point_cloud.points.size ()<<" points.\n";
00465 
00466   width = di_width;
00467   height = di_height;
00468   center_x_ = di_center_x;
00469   center_y_ = di_center_y;
00470   focal_length_x_ = di_focal_length_x;
00471   focal_length_y_ = di_focal_length_y;
00472   focal_length_x_reciprocal_ = 1 / focal_length_x_;
00473   focal_length_y_reciprocal_ = 1 / focal_length_y_;
00474 
00475   is_dense = false;
00476 
00477   getCoordinateFrameTransformation (coordinate_frame, to_world_system_);
00478   to_world_system_ = sensor_pose * to_world_system_;
00479 
00480   to_range_image_system_ = to_world_system_.inverse (Eigen::Isometry);
00481 
00482   unsigned int size = width*height;
00483   points.clear ();
00484   points.resize (size, unobserved_point);
00485 
00486   computeZandMatchingPoints (point_cloud,
00487                              min_range,
00488                              matching_im,
00489                              matching_im_min_range,
00490                              matching_indices,
00491                              matching_indices_in_matching_im,
00492                              indices_to_remove,
00493                              height, width);
00494 
00495 }
00496 
00497 
00498 }
00499 
00500 #endif


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