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);
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
00044
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
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
00078 for (size_t i = 1; i < n; i++)
00079 {
00080 D(i, 0) = compared(i, start) + D(i - 1, 0);
00081 }
00082
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
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
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
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
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
00213
00214 int k = 2 * inpoly(polygons[s], polygons[s - 1].points[u]) - 1;
00215
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
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 }