00001 #include <place_matcher_hist/dissimilarity_getter.h>
00002
00003 #include <fstream>
00004 #include <algorithm>
00005
00006 namespace place_matcher_hist
00007 {
00008
00009
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
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
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
00140
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
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
00155
00156
00157
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
00171
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
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
00183
00184
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
00195
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
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());
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
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
00245
00246
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
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
00270
00271
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
00295
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 }