dissimilarity_getter.cpp
Go to the documentation of this file.
00001 #include <place_matcher_hist/dissimilarity_getter.h>
00002 
00003 #include <fstream> // DEBUG
00004 #include <algorithm> // DEBUG
00005 
00006 namespace place_matcher_hist
00007 {
00008 
00009 /* DEBUG */
00010 void saveToFile(const std::string& filename, const geometry_msgs::Polygon& poly)
00011 {
00012   std::ofstream fout(filename.c_str());
00013   if (!fout.is_open())
00014   {
00015     std::cerr << "\"" << filename << "\" cannot be opened for writing";
00016     return;
00017   }
00018   std::vector<geometry_msgs::Point32>::const_iterator it = poly.points.begin();
00019   for (; it < poly.points.end(); ++it)
00020   {
00021     fout << it->x << "," << it->y << "\n";
00022   }
00023 }
00024 /* DEBUG */
00025 
00026 static void getXMinMax(const geometry_msgs::Polygon& poly1, const geometry_msgs::Polygon& poly2, double& x_min, double& x_max)
00027 {
00028   x_min = std::numeric_limits<float>::max();
00029   x_max = std::numeric_limits<float>::min();
00030 
00031   std::vector<geometry_msgs::Point32>::const_iterator pt;
00032   for (pt = poly1.points.begin(); pt != poly1.points.end(); ++pt)
00033   {
00034     if (x_min > pt->x)
00035     {
00036       x_min = pt->x;
00037     }
00038     else if (x_max < pt->x)
00039     {
00040       x_max = pt->x;
00041     }
00042   }
00043   for (pt = poly2.points.begin(); pt != poly2.points.end(); ++pt)
00044   {
00045     if (x_min > pt->x)
00046     {
00047       x_min = pt->x;
00048     }
00049     else if (x_max < pt->x)
00050     {
00051       x_max = pt->x;
00052     }
00053   }
00054 }
00055 
00056 static void getYMinMax(const geometry_msgs::Polygon& poly1, const geometry_msgs::Polygon& poly2, double& y_min, double& y_max)
00057 {
00058   y_min = std::numeric_limits<float>::max();
00059   y_max = std::numeric_limits<float>::min();
00060 
00061   std::vector<geometry_msgs::Point32>::const_iterator pt;
00062   for (pt = poly1.points.begin(); pt != poly1.points.end(); ++pt)
00063   {
00064     if (y_min > pt->y)
00065     {
00066       y_min = pt->y;
00067     }
00068     else if (y_max < pt->y)
00069     {
00070       y_max = pt->y;
00071     }
00072   }
00073   for (pt = poly2.points.begin(); pt != poly2.points.end(); ++pt)
00074   {
00075     if (y_min > pt->y)
00076     {
00077       y_min = pt->y;
00078     }
00079     else if (y_max < pt->y)
00080     {
00081       y_max = pt->y;
00082     }
00083   }
00084 }
00085 
00088 inline geometry_msgs::Polygon rotatedPolygon(const geometry_msgs::Polygon& poly_in, double angle)
00089 {
00090   geometry_msgs::Polygon poly_out;
00091   poly_out.points.reserve(poly_in.points.size());
00092   const double cos_ = std::cos(angle);
00093   const double sin_ = std::sin(angle);
00094   std::vector<geometry_msgs::Point32>::const_iterator pt;
00095   for (pt = poly_in.points.begin(); pt != poly_in.points.end(); ++pt)
00096   {
00097     geometry_msgs::Point32 pt_out;
00098     pt_out.x = pt->x * cos_ - pt->y * sin_;
00099     pt_out.y = pt->x * sin_ + pt->y * cos_;
00100     poly_out.points.push_back(pt_out);
00101   }
00102   return poly_out;
00103 }
00104 
00105 DissimilarityGetter::DissimilarityGetter(const ros::NodeHandle& nh_private) :
00106   trans_resolution_(0.1),
00107   max_trans_bin_count_(200),
00108   rot_resolution_(0.017453292519943295),
00109   max_dist_(0.5),
00110   nh_private_(nh_private)
00111 {
00112   initParams();
00113 }
00114 
00115 /* Init parameters of the csm method
00116  */
00117 void DissimilarityGetter::initParams()
00118 {
00119   nh_private_.getParam("translational_resolution", trans_resolution_);
00120   if (trans_resolution_ == 0)
00121   {
00122     ROS_ERROR_STREAM(nh_private_.getNamespace() << "/translational_resolution cannot be 0, setting to default");
00123     trans_resolution_ = 0.1;
00124   }
00125   nh_private_.getParam("rotational_resolution", rot_resolution_);
00126   nh_private_.getParam("max_distance_normal_considered", max_dist_);
00127   nh_private_.getParam("max_trans_bin_count", max_trans_bin_count_);
00128   if (max_trans_bin_count_ < 1)
00129   {
00130     ROS_ERROR_STREAM(nh_private_.getNamespace() << "/max_trans_bin_count cannot be 0, setting to default");
00131     max_trans_bin_count_ = 200;
00132   }
00133 }
00134 
00135 bool DissimilarityGetter::getDissimilarity(place_matcher_msgs::PolygonDissimilarityRequest& req, place_matcher_msgs::PolygonDissimilarityResponse& res)
00136 {
00137   ros::WallTime start = ros::WallTime::now();
00138 
00139   // Compute the angle histogram for both polygons and the rotation between
00140   // both histograms.
00141   Hist rot_hist_1 = getRotHist(req.polygon1);
00142   Hist rot_hist_2 = getRotHist(req.polygon2);
00143   const size_t angle_index = crossCorrelationHist(rot_hist_1, rot_hist_2);
00144   const double dyaw = angle_index * rot_resolution_;
00145 
00146   /* DEBUG */
00147   ROS_INFO("dyaw = %f", dyaw);
00148   std::ofstream ofs1("/tmp/rot_hist_1.dat");
00149   std::copy(rot_hist_1.begin(), rot_hist_1.end(), std::ostream_iterator<double>(ofs1, " "));
00150   ofs1.close();
00151   std::ofstream ofs2("/tmp/rot_hist_2.dat");
00152   std::copy(rot_hist_2.begin(), rot_hist_2.end(), std::ostream_iterator<double>(ofs2, " "));
00153   ofs2.close();
00154   /* DEBUG */
00155   
00156 
00157   // Get the main normal direction for rot_hist_1.
00158   size_t max_idx_hist1 = 0; 
00159   unsigned int max_bin = 0;
00160   for (size_t i = 0; i < rot_hist_1.size(); ++i)
00161   {
00162     if (rot_hist_1[i] > max_bin)
00163     {
00164       max_bin = rot_hist_1[i];
00165       max_idx_hist1 = i;
00166     }
00167   }
00168   const double main_axis_poly1 = max_idx_hist1 * rot_resolution_;
00169 
00170   // Rotate both polygons so that they are aligned and that req.polygon1
00171   // is oriented according to its second main direction (main direction of the normals).
00172   const geometry_msgs::Polygon poly1_rotated = rotatedPolygon(req.polygon1, main_axis_poly1);
00173   const geometry_msgs::Polygon poly2_rotated = rotatedPolygon(req.polygon2, main_axis_poly1 - dyaw);
00174 
00175   /* DEBUG */
00176   saveToFile("/tmp/poly_ref_rotated.csv", poly1_rotated);
00177   saveToFile("/tmp/poly_sens_rotated.csv", poly2_rotated);
00178   Hist rot_hist_3 = getRotHist(poly2_rotated);
00179   std::ofstream ofs3("/tmp/rot_hist_2_rot.dat");
00180   std::copy(rot_hist_3.begin(), rot_hist_3.end(), std::ostream_iterator<double>(ofs3, " "));
00181   ofs3.close();
00182   /* DEBUG */
00183 
00184   // Get the translation between both polygons.
00185   double x_min;
00186   double x_max;
00187   double y_min;
00188   double y_max;
00189   getXMinMax(poly1_rotated, poly2_rotated, x_min, x_max);
00190   getYMinMax(poly1_rotated, poly2_rotated, y_min, y_max);
00191   const size_t trans_x_bin_count = std::min(getTransBinCount(x_min, x_max), max_trans_bin_count_);
00192   const size_t trans_y_bin_count = std::min(getTransBinCount(y_min, y_max), max_trans_bin_count_);
00193 
00194   // Set the bin width slightly larger so that the index for the value that is
00195   // x_mmax or y_max is correct.
00196   const double bin_width_x = 1.00001 * (x_max - x_min) / trans_x_bin_count;
00197   const double bin_width_y = 1.00001 * (y_max - y_min) / trans_y_bin_count;
00198 
00199   if (bin_width_x < 1e-6 || bin_width_y < 1e-6)
00200   {
00201     ROS_ERROR("Null bin width");
00202     return false;
00203   }
00204 
00205   // Compute the histograms for translations and get the max. correlation.
00206   Hist hist_x_1(trans_x_bin_count, 0);
00207   Hist hist_y_1(trans_y_bin_count, 0);
00208   ROS_INFO("hist_x1.size() = %zu, hist_y_1.size() = %zu", hist_x_1.size(), hist_y_1.size()); // DEBUG
00209   for (size_t i = 0; i < poly1_rotated.points.size(); ++i)
00210   {
00211     hist_x_1[(size_t) std::floor((poly1_rotated.points[i].x - x_min) / bin_width_x)] += 1;
00212     hist_y_1[(size_t) std::floor((poly1_rotated.points[i].y - y_min) / bin_width_y)] += 1;
00213   }
00214 
00215   Hist hist_x_2(trans_x_bin_count, 0);
00216   Hist hist_y_2(trans_y_bin_count, 0);
00217   for (size_t i = 0; i < poly2_rotated.points.size(); ++i)
00218   {
00219     hist_x_2[(size_t) std::floor((poly2_rotated.points[i].x - x_min) / bin_width_x)] += 1;
00220     hist_y_2[(size_t) std::floor((poly2_rotated.points[i].y - y_min) / bin_width_y)] += 1;
00221   }
00222   int x_index = crossCorrelationHist(hist_x_1, hist_x_2);
00223   int y_index = crossCorrelationHist(hist_y_1, hist_y_2);
00224   if (x_index > trans_x_bin_count / 2)
00225   {
00226     x_index -= trans_x_bin_count;
00227   }
00228   if (y_index > trans_y_bin_count / 2)
00229   {
00230     y_index -= trans_y_bin_count;
00231   }
00232   const double dx_rotated = x_index * bin_width_x;
00233   const double dy_rotated = y_index * bin_width_y;
00234 
00235   /* DEBUG */
00236   ROS_INFO("main_axis_poly1 = %f", main_axis_poly1);
00237   ROS_INFO("bbox = (%f, %f), (%f, %f)", x_min, y_min, x_max, y_max);
00238   ROS_INFO("bin_width_x = %f", bin_width_x);
00239   ROS_INFO("bin_width_y = %f", bin_width_y);
00240   ROS_INFO("x_index = %d", x_index);
00241   ROS_INFO("y_index = %d", y_index);
00242   ROS_INFO("dx_rotated = %f", dx_rotated);
00243   ROS_INFO("dy_rotated = %f", dy_rotated);
00244   /* DEBUG */
00245 
00246   // Get the translation in the original frame (poly1)
00247   const double cos_ = std::cos(-main_axis_poly1 + dyaw);
00248   const double sin_ = std::sin(-main_axis_poly1 + dyaw);
00249   const double dx = cos_ * dx_rotated - sin_* dy_rotated;
00250   const double dy = sin_ * dx_rotated + cos_ * dy_rotated;
00251   
00252   /* DEBUG */
00253   ROS_INFO("dx = %f", dx);
00254   ROS_INFO("dy = %f", dy);
00255 #if 0
00256   std::ofstream ofs4("/tmp/hist_x_1.dat");
00257   std::copy(hist_x_1.begin(), hist_x_1.end(), std::ostream_iterator<double>(ofs4, " "));
00258   ofs4.close();
00259   std::ofstream ofs5("/tmp/hist_y_1.dat");
00260   std::copy(hist_y_1.begin(), hist_y_1.end(), std::ostream_iterator<double>(ofs5, " "));
00261   ofs5.close();
00262   std::ofstream ofs6("/tmp/hist_x_2.dat");
00263   std::copy(hist_x_2.begin(), hist_x_2.end(), std::ostream_iterator<double>(ofs6, " "));
00264   ofs6.close();
00265   std::ofstream ofs7("/tmp/hist_y_2.dat");
00266   std::copy(hist_y_2.begin(), hist_y_2.end(), std::ostream_iterator<double>(ofs7, " "));
00267   ofs7.close();
00268 #endif
00269   /* DEBUG */
00270 
00271   // Set the response.
00272   res.pose.position.x = dx;
00273   res.pose.position.y = dy;
00274   res.pose.orientation = tf::createQuaternionMsgFromYaw(dyaw);
00275   res.processing_time = ros::Duration((ros::WallTime::now() - start).toSec());
00276   return true;
00277 }
00278 
00279 DissimilarityGetter::Hist DissimilarityGetter::getRotHist(const geometry_msgs::Polygon poly)
00280 {
00281   const size_t n = poly.points.size();
00282   const size_t bin_count = (size_t) std::ceil(2 * M_PI / rot_resolution_);
00283   Hist hist(bin_count, 0);
00284 
00285   for (size_t i = 0; i < n; ++i)
00286   {
00287     for (size_t shift = 1; shift < shift_ + 1; ++shift)
00288     {
00289       const double dx = poly.points[(i + shift) % n].x - poly.points[i].x;
00290       const double dy = poly.points[(i + shift) % n].y - poly.points[i].y;
00291       const double distance = std::sqrt(dx * dx + dy * dy);
00292       if (distance < max_dist_)
00293       {
00294         // We compute the normal of the angle by rotating the vector (dx, dy)
00295         // by 90 deg ==> normal = (-dy, dx).
00296         double angle = std::atan2(dx, -dy);
00297         if (angle < 0)
00298         {
00299           angle += 2 * M_PI;
00300         }
00301         hist[(size_t) std::floor(angle / rot_resolution_)] += 1;
00302       }
00303     }
00304   }
00305   return hist;
00306 }
00307 
00311 size_t DissimilarityGetter::crossCorrelationHist(DissimilarityGetter::Hist h1, DissimilarityGetter::Hist h2)
00312 {
00313   const size_t n1 = h1.size();
00314   const size_t n2 = h2.size();
00315   double max_sum = 0.0;
00316   size_t ind_max = 0;
00317   for (size_t shift = 0; shift < n1; ++shift)
00318   {
00319     double sum = 0.0; 
00320     for (size_t i = 0; i < n1; ++i)
00321     {
00322       sum += h1[i] * h2[(i + shift) % n2];
00323     }
00324     if (sum > max_sum)
00325     {
00326       max_sum = sum;
00327       ind_max = shift;
00328     }
00329   }
00330   return ind_max;
00331 }
00332 
00333 
00334 } /* namespace place_matcher_hist */


place_matcher_hist
Author(s):
autogenerated on Sat Jun 8 2019 19:53:03