00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <algorithm>
00020 #include <iostream>
00021 #include <fstream>
00022 #include <limits>
00023 #include <cmath>
00024 #include <cassert>
00025
00026 #include <boost/numeric/ublas/matrix.hpp>
00027 #include <boost/numeric/ublas/io.hpp>
00028
00029 #include <ros/ros.h>
00030 #include <std_msgs/String.h>
00031 #include <lama_common/point.h>
00032 #include <lama_common/polygon.h>
00033 #include <polygon_matcher/PolygonDissimilarity.h>
00034
00035
00036 unsigned int g_num_samples;
00037
00038
00039 unsigned int g_max_sigma;
00040
00041 bool g_rotation_invariance;
00042
00043 using std::sqrt;
00044 using std::abs;
00045
00046 typedef boost::numeric::ublas::matrix<double> matrix;
00047 typedef std::vector<geometry_msgs::Polygon> polygon_list;
00048
00049 int inpoly(const geometry_msgs::Polygon& p, const geometry_msgs::Point32& point)
00050 {
00051 float x = point.x;
00052 float y = point.y;
00053 unsigned int i, j, c = 0;
00054 for (i = 0, j = p.points.size() - 1; i < p.points.size(); j = i++)
00055 {
00056 if ((((p.points[i].y <= y) && (y < p.points[j].y)) ||
00057 ((p.points[j].y <= y) && (y < p.points[i].y))) &&
00058 (x < (p.points[j].x - p.points[i].x) * (y - p.points[i].y) / (p.points[j].y - p.points[i].y) + p.points[i].x))
00059 c = !c;
00060 }
00061 return c;
00062 }
00063
00064 bool evolve(geometry_msgs::Polygon& input, polygon_list& output, unsigned int maxSigma)
00065 {
00066 double distance;
00067 double value;
00068 output.push_back(input);
00069 for (unsigned int s = 1; s < maxSigma; s++)
00070 {
00071 geometry_msgs::Polygon pSigma;
00072 for (unsigned int i = 0; i < input.points.size(); i++)
00073 {
00074 double sumX = 0;
00075 double sumY = 0;
00076 for (unsigned int j = 0; j < input.points.size(); j++)
00077 {
00078
00079
00080 distance = std::min(abs(j - i), abs(input.points.size() - abs(j - i)));
00081 value = 1.0 / (s * sqrt(2.0 * M_PI)) * exp(-(distance * distance) / (2.0 * s * s));
00082 sumX += input.points[j].x * value;
00083 sumY += input.points[j].y * value;
00084 }
00085 geometry_msgs::Point32 p;
00086 p.x = sumX;
00087 p.y = sumY;
00088 p.z = 0;
00089 pSigma.points.push_back(p);
00090 }
00091 output.push_back(pSigma);
00092 }
00093 return true;
00094 }
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 double compute_convexity(const polygon_list& polygons, matrix& m)
00109 {
00110 double complexity = 0;
00111
00112 for (unsigned int s = 1; s < g_max_sigma; s++)
00113 {
00114 double cMax = 0;
00115 double cMin = std::numeric_limits<double>::max();
00116
00117 for (unsigned int u = 0; u < g_num_samples; u++)
00118 {
00119
00120
00121 int k = 2 * inpoly(polygons[s], polygons[s-1].points[u]) - 1;
00122
00123 m(u,s-1) = k * sqrt(
00124 (polygons[s].points[u].x - polygons[s-1].points[u].x) *
00125 (polygons[s].points[u].x - polygons[s-1].points[u].x) +
00126 (polygons[s].points[u].y - polygons[s-1].points[u].y) *
00127 (polygons[s].points[u].y - polygons[s-1].points[u].y));
00128
00129 if (m(u,s-1) < cMin)
00130 {
00131 cMin = m(u,s-1);
00132 }
00133 if (m(u,s-1) > cMax)
00134 {
00135 cMax = m(u,s-1);
00136 }
00137 }
00138 complexity += (cMax - cMin);
00139 }
00140 complexity /= (g_max_sigma - 1);
00141 return complexity;
00142 }
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 matrix compare(matrix& a, matrix& b)
00153 {
00154 assert(a.size2() == b.size2());
00155
00156 matrix ret(a.size1(), b.size1());
00157
00158 size_t last_row_shift = 1;
00159 if (g_rotation_invariance)
00160 {
00161 last_row_shift = b.size1();
00162 }
00163
00164 for (size_t i = 0; i < a.size1(); i++)
00165 {
00166 for (size_t j = 0; j < last_row_shift; j++)
00167 {
00168 double sum = 0;
00169
00170
00171 for (size_t s = 1; s < a.size2() - 1; s++)
00172 {
00173 sum += std::fabs(a(i,s) - b(j,s));
00174 }
00175
00176
00177 ret(i,j) = (1.0 / a.size2()) * sum;
00178 }
00179 }
00180 return ret;
00181 }
00182
00183
00184
00185 geometry_msgs::Polygon center(geometry_msgs::Polygon& p)
00186 {
00187 float sumx = 0;
00188 float sumy = 0;
00189 geometry_msgs::Polygon centeredPolygon;
00190 centeredPolygon.points.reserve(p.points.size());
00191 for (size_t i = 0; i < p.points.size(); ++i)
00192 {
00193 sumx += p.points[i].x;
00194 sumy += p.points[i].y;
00195 }
00196 for (size_t i = 0; i < p.points.size(); ++i)
00197 {
00198 geometry_msgs::Point32 outpoint;
00199 outpoint.x = p.points[i].x - sumx;
00200 outpoint.y = p.points[i].y - sumy;
00201 centeredPolygon.points.push_back(outpoint);
00202 }
00203 return centeredPolygon;
00204 }
00205
00206
00207
00208 double minDistance(const matrix& compared, const int start)
00209 {
00210 size_t n = compared.size1();
00211 size_t m = compared.size2();
00212 matrix D(n, m);
00213 D(0,0) = compared(0,start);
00214
00215
00216 for (size_t i = 1; i < n; i++)
00217 {
00218 D(i,0) = compared(i,start) + D(i-1,0);
00219 }
00220
00221 for (size_t j = 1; j < m; j++)
00222 {
00223 D(0,j) = compared(0,(j+start) % m) + D(0,j-1);
00224 }
00225
00226
00227
00228
00229
00230
00231 for (size_t i = 1 ; i < n; i++)
00232 {
00233 for (size_t j = 1; j < m; j++)
00234 {
00235 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))));
00236 }
00237 }
00238 return D(n - 1, m - 1);
00239 }
00240
00241
00242
00243
00244
00245 bool dissimilarity(polygon_matcher::PolygonDissimilarity::Request& req,
00246 polygon_matcher::PolygonDissimilarity::Response& res)
00247 {
00248
00249 ROS_DEBUG("Request: size_1=%zu, size_2=%zu", req.polygon1.points.size(), req.polygon2.points.size());
00250 ros::Time start = ros::Time::now();
00251
00252
00253
00254
00255
00256 geometry_msgs::Polygon polygon1res;
00257 geometry_msgs::Polygon polygon2res;
00258 double delta;
00259 polygon1res.points = lama_common::resamplePolygon(req.polygon1.points, g_num_samples, delta);
00260 polygon2res.points = lama_common::resamplePolygon(req.polygon2.points, g_num_samples, delta);
00261 polygon_list polygon1evo;
00262 polygon_list polygon2evo;
00263
00264 evolve(polygon1res, polygon1evo, g_max_sigma);
00265 evolve(polygon2res, polygon2evo, g_max_sigma);
00266
00267
00268 res.processing_time = ros::Time::now() - start;
00269 ROS_DEBUG("Multi-polygon representation created after %.1f s", res.processing_time.toSec());
00270 matrix mcc1(g_num_samples, g_max_sigma);
00271 matrix mcc2(g_num_samples, g_max_sigma);
00272
00273
00274 double C1 = compute_convexity(polygon1evo, mcc1);
00275 double C2 = compute_convexity(polygon2evo, mcc2);
00276 ROS_DEBUG("Complexity normalization of polygon 1 = %f", C1);
00277 ROS_DEBUG("Complexity normalization of polygon 2 = %f", C2);
00278
00279 res.processing_time = ros::Time::now() - start;
00280 ROS_DEBUG("Multi-scale representation created after %.1f s", res.processing_time.toSec());
00281
00282 matrix comp = compare(mcc1, mcc2);
00283
00284 res.processing_time = ros::Time::now() - start;
00285 ROS_DEBUG("Comparison created after %.1f s", res.processing_time.toSec());
00286
00287 std::vector<double> result;
00288 result.reserve(comp.size2());
00289 for (size_t i = 0; i < comp.size2(); i++)
00290 {
00291 result.push_back(minDistance(comp, i));
00292 }
00293 res.raw_dissimilarity = (*std::min_element(result.begin(), result.end())) * 2.0 / ((C1 + C2) * (g_num_samples));
00294
00295 res.processing_time = ros::Time::now() - start;
00296 ROS_DEBUG("Sending back response: %f (in %.1f s)", res.raw_dissimilarity, res.processing_time.toSec());
00297
00298 return true;
00299 }
00300
00301 int main(int argc, char **argv)
00302 {
00303 int max_thread;
00304 ros::init(argc, argv, "mcc_polygon_dissimilarity_server");
00305 ros::NodeHandle nh("~");
00306
00307 nh.param<int>("max_thread", max_thread, 1);
00308
00309
00310 int sample_count;
00311 nh.param<int>("sample_count", sample_count, 100);
00312 g_num_samples = sample_count;
00313
00314
00315
00316 int scale_count;
00317 nh.param<int>("scale_count", scale_count, 20);
00318 g_max_sigma = scale_count;
00319
00320
00321 bool rotation_invariance;
00322 nh.param<bool>("rotation_invariance", rotation_invariance, true);
00323 g_rotation_invariance = rotation_invariance;
00324
00325 ros::ServiceServer service = nh.advertiseService("compute_dissimilarity", dissimilarity);
00326
00327
00328 ROS_INFO("Ready to work (with %i threads)", max_thread);
00329
00330
00331
00332
00333 ros::MultiThreadedSpinner spinner(max_thread);
00334 spinner.spin();
00335
00336 return 0;
00337 }