dissimilarity_getter.cpp
Go to the documentation of this file.
00001 #include <place_matcher_mcc/dissimilarity_getter.h>
00002 
00003 namespace place_matcher_mcc
00004 {
00005 
00006 using std::sqrt;
00007 using std::abs;
00008 
00009 int inpoly(const geometry_msgs::Polygon& poly, const geometry_msgs::Point32& point)
00010 {
00011   float x = point.x;
00012   float y = point.y;
00013   unsigned int i;
00014   unsigned int j;
00015   unsigned int c = 0;
00016 
00017   for (i = 0, j = poly.points.size() - 1; i < poly.points.size(); j = i++)
00018   {
00019     if ((((poly.points[i].y <= y) && (y < poly.points[j].y)) ||
00020           ((poly.points[j].y <= y) && (y < poly.points[i].y))) &&
00021         (x < (poly.points[j].x - poly.points[i].x) * (y - poly.points[i].y) / (poly.points[j].y - poly.points[i].y) + poly.points[i].x))
00022       c = !c;
00023   }
00024   return c;
00025 }
00026 
00033 bool evolve(const geometry_msgs::Polygon& input, polygon_list& output, unsigned int max_sigma)
00034 {
00035   output.clear();
00036   output.reserve(max_sigma);
00037   output.push_back(input);  // With sigma == 0.
00038   const int size = input.points.size();
00039   for (unsigned int s = 1; s < max_sigma; s++)
00040   {
00041     geometry_msgs::Polygon evolved_polygon;
00042     evolved_polygon.points.reserve(size);
00043     // Index distance to consider the filter impulse reponse negligeable.
00044     // https://en.wikipedia.org/wiki/Scale_space_implementation#The_sampled_Gaussian_kernel.
00045     const int max_dist_to_filter = std::min((int)(4 * s + 1), size);
00046     for (int i = 0; i < size; i++)
00047     {
00048       double sumX = 0;
00049       double sumY = 0;
00050       for (int j = -max_dist_to_filter; j < max_dist_to_filter + 1; j++)
00051       {
00052         // Apply a Gaussian kernel.
00053         const double filter = 1.0 / (s * sqrt(2.0 * M_PI)) * std::exp(-((double)j * (double)j) / (2.0 * s * s));
00054         sumX += input.points[(i - j + size) % size].x * filter;
00055         sumY += input.points[(i - j + size) % size].y * filter;
00056       }
00057       geometry_msgs::Point32 p;
00058       p.x = sumX;
00059       p.y = sumY;
00060       p.z = 0;
00061       evolved_polygon.points.push_back(p);
00062     }
00063     output.push_back(evolved_polygon);
00064   }
00065   return true;
00066 }
00067 
00070 double minDistance(const matrix& compared, int start)
00071 {
00072   size_t n = compared.size1();
00073   size_t m = compared.size2();
00074   matrix D(n, m);
00075   D(0, 0) = compared(0, start);
00076   
00077   // Fill start column.
00078   for (size_t i = 1; i < n; i++)
00079   {
00080     D(i, 0) = compared(i, start) + D(i - 1, 0);
00081   }
00082   // Fill first row.
00083   for (size_t j = 1; j < m; j++)
00084   {
00085     D(0, j) = compared(0, (j+start) % m) + D(0, j - 1);
00086   }
00087 
00088   for (size_t i = 1 ; i < n; i++)
00089   {
00090     for (size_t j = 1; j < m; j++)
00091     {
00092       D(i, j) = compared(i, (j+start) % m) + std::min(D(i - 1, j), std::min(D(i, (j - 1)), D(i - 1, (j - 1))));
00093     }
00094   }
00095   return D(n - 1, m - 1); 
00096 } 
00097 
00098 DissimilarityGetter::DissimilarityGetter() :
00099   scale_count(10),
00100   sample_count(100),
00101   rotation_invariance(true)
00102 {
00103 }
00104 
00105 double DissimilarityGetter::getDissimilarity(const geometry_msgs::Polygon& polygon1, const geometry_msgs::Polygon& polygon2)
00106 {
00107   geometry_msgs::Polygon polygon1res;
00108   geometry_msgs::Polygon polygon2res; 
00109   double delta;
00110   polygon1res.points = lama_common::resamplePolygon(polygon1.points, sample_count, delta);
00111   polygon2res.points = lama_common::resamplePolygon(polygon2.points, sample_count, delta);
00112   // Create multi-scale representation (increasing sigma).
00113   polygon_list polygon1evo;
00114   polygon_list polygon2evo;
00115   evolve(polygon1res, polygon1evo, scale_count);
00116   evolve(polygon2res, polygon2evo, scale_count);
00117 
00118   matrix mcc1(sample_count, scale_count);
00119   matrix mcc2(sample_count, scale_count);
00120 
00121   // TODO: discuss with Karel the interest of the complexity normalization.
00122   const double C1 = compute_convexity(polygon1evo, mcc1);
00123   const double C2 = compute_convexity(polygon2evo, mcc2);
00124   ROS_DEBUG("Complexity normalization of polygon 1 = %f", C1);
00125   ROS_DEBUG("Complexity normalization of polygon 2 = %f", C2);
00126 
00127   matrix comp = compare(mcc1, mcc2);
00128 
00129   std::vector<double> result;
00130   result.reserve(comp.size2());
00131   for (size_t i = 0; i < comp.size2(); i++)
00132   {
00133     result.push_back(minDistance(comp, i));
00134   }
00135   return (*std::min_element(result.begin(), result.end())) * 2.0 / ((C1 + C2) * (sample_count));
00136 }
00137 
00138 bool DissimilarityGetter::getDissimilarity(place_matcher_msgs::PolygonDissimilarityRequest& req, place_matcher_msgs::PolygonDissimilarityResponse& res)
00139 {
00140 
00141   ROS_DEBUG("Request: size_1 = %zu, size_2 = %zu", req.polygon1.points.size(), req.polygon2.points.size());
00142   ros::WallTime start = ros::WallTime::now();
00143 
00144   geometry_msgs::Polygon polygon1res;
00145   geometry_msgs::Polygon polygon2res; 
00146   double delta;
00147   polygon1res.points = lama_common::resamplePolygon(req.polygon1.points, sample_count, delta);
00148   polygon2res.points = lama_common::resamplePolygon(req.polygon2.points, sample_count, delta);
00149   // Create multi-scale representation (increasing sigma).
00150   polygon_list polygon1evo;
00151   polygon_list polygon2evo;
00152   evolve(polygon1res, polygon1evo, scale_count);
00153   evolve(polygon2res, polygon2evo, scale_count);
00154   res.processing_time = ros::Duration((ros::WallTime::now() - start).toSec());
00155   ROS_DEBUG("Evolved polygons created after %.4f s", res.processing_time.toSec());
00156 
00157   matrix mcc1(sample_count, scale_count);
00158   matrix mcc2(sample_count, scale_count);
00159 
00160   // TODO: discuss with Karel the interest of the complexity normalization.
00161   const double C1 = compute_convexity(polygon1evo, mcc1);
00162   const double C2 = compute_convexity(polygon2evo, mcc2);
00163   ROS_DEBUG("Complexity normalization of polygon 1 = %f", C1);
00164   ROS_DEBUG("Complexity normalization of polygon 2 = %f", C2);
00165 
00166   res.processing_time = ros::Duration((ros::WallTime::now() - start).toSec());
00167   ROS_DEBUG("Multi-scale convexity-concavity computed after %.4f s", res.processing_time.toSec());
00168 
00169   matrix comp = compare(mcc1, mcc2);
00170 
00171   res.processing_time = ros::Duration((ros::WallTime::now() - start).toSec());
00172   ROS_DEBUG("Comparison created after %.4f s", res.processing_time.toSec());
00173 
00174   std::vector<double> result;
00175   result.reserve(comp.size2());
00176   for (size_t i = 0; i < comp.size2(); i++)
00177   {
00178     result.push_back(minDistance(comp, i));
00179   }
00180   res.raw_dissimilarity = (*std::min_element(result.begin(), result.end())) * 2.0 / ((C1 + C2) * (sample_count));
00181 
00182   res.processing_time = ros::Duration((ros::WallTime::now() - start).toSec());
00183   ROS_DEBUG("Sending back response: %f  (in %.4f s)", res.raw_dissimilarity, res.processing_time.toSec());
00184 
00185   return true;
00186 }
00187 
00201 double DissimilarityGetter::compute_convexity(const polygon_list& polygons, matrix& m)
00202 {
00203   double complexity = 0;
00204 
00205   for (unsigned int s = 1; s < scale_count; s++)
00206   {
00207     double cMax = 0;
00208     double cMin = std::numeric_limits<double>::max();      
00209 
00210     for (unsigned int u = 0; u < sample_count; u++)
00211     {
00212       // k = 1 if point inside polygon; -1 otherwise.
00213       // k = 1 for convex part of the polygon contour.
00214       int k = 2 * inpoly(polygons[s], polygons[s - 1].points[u]) - 1;
00215       // TODO: talk with Karel why not m(u,s) as stated in the article.
00216       m(u, s - 1) = k * sqrt(
00217           (polygons[s].points[u].x - polygons[s - 1].points[u].x) *
00218           (polygons[s].points[u].x - polygons[s - 1].points[u].x) + 
00219           (polygons[s].points[u].y - polygons[s - 1].points[u].y) *
00220           (polygons[s].points[u].y - polygons[s - 1].points[u].y));
00221 
00222       if (m(u, s - 1) < cMin)
00223       {
00224         cMin = m(u, s - 1);
00225       }
00226       if (m(u, s - 1) > cMax)
00227       {
00228         cMax = m(u, s - 1);
00229       }
00230     }
00231     complexity += (cMax - cMin);
00232   }
00233   complexity /= (scale_count - 1);
00234   return complexity;
00235 }
00236 
00249 matrix DissimilarityGetter::compare(const matrix& a, const matrix& b)
00250 {
00251   assert(a.size2() == b.size2());
00252 
00253   matrix ret(a.size1(), b.size1());
00254 
00255   size_t last_row_shift = 1;
00256   if (rotation_invariance)
00257   {
00258     last_row_shift = b.size1();
00259   }
00260 
00261   for (size_t index_row_a = 0; index_row_a < a.size1(); index_row_a++)
00262   {
00263     for (size_t index_row_b = 0; index_row_b < last_row_shift; index_row_b++)
00264     {
00265       double sum = 0;
00266       // First and last scale levels are excluded.
00267       for (size_t s = 1; s < a.size2() - 1; s++)
00268       {
00269         sum += abs(a(index_row_a, s) - b(index_row_b, s));
00270       }
00271       ret(index_row_a, index_row_b) = (1.0 / a.size2()) * sum;
00272     }
00273   }
00274   return ret;
00275 }       
00276 
00277 } /* namespace place_matcher_mcc */


place_matcher_mcc
Author(s): Gaël Ecorchard , Karel Košnar
autogenerated on Sat Jun 8 2019 19:53:05