00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00033 #include <door_handle_detector/sample_consensus/sac_model_circle.h>
00034 #include <door_handle_detector/geometry/nearest.h>
00035
00036 #include <cminpack.h>
00037
00038 #define SQR(a) ((a)*(a))
00039
00040 namespace sample_consensus
00041 {
00043
00048 void
00049 SACModelCircle2D::getSamples (int &iterations, std::vector<int> &samples)
00050 {
00051 samples.resize (3);
00052 double trand = indices_.size () / (RAND_MAX + 1.0);
00053
00054
00055 int idx = (int)(rand () * trand);
00056
00057 samples[0] = indices_.at (idx);
00058
00059
00060 do
00061 {
00062 idx = (int)(rand () * trand);
00063 samples[1] = indices_.at (idx);
00064 iterations++;
00065 } while (samples[1] == samples[0]);
00066 iterations--;
00067
00068 double Dx1, Dy1, Dz1, Dx2, Dy2, Dz2, Dy1Dy2;
00069
00070 Dx1 = cloud_->points[samples[1]].x - cloud_->points[samples[0]].x;
00071 Dy1 = cloud_->points[samples[1]].y - cloud_->points[samples[0]].y;
00072 Dz1 = cloud_->points[samples[1]].z - cloud_->points[samples[0]].z;
00073
00074 int iter = 0;
00075 do
00076 {
00077
00078 do
00079 {
00080 idx = (int)(rand () * trand);
00081 samples[2] = indices_.at (idx);
00082 iterations++;
00083 } while ( (samples[2] == samples[1]) || (samples[2] == samples[0]) );
00084 iterations--;
00085
00086
00087 Dx2 = cloud_->points[samples[2]].x - cloud_->points[samples[0]].x;
00088 Dy2 = cloud_->points[samples[2]].y - cloud_->points[samples[0]].y;
00089 Dz2 = cloud_->points[samples[2]].z - cloud_->points[samples[0]].z;
00090
00091 Dy1Dy2 = Dy1 / Dy2;
00092 iter++;
00093
00094 if (iter > MAX_ITERATIONS_COLLINEAR )
00095 {
00096 ROS_WARN ("[SACModelCircle2D::getSamples] WARNING: Could not select 3 non collinear points in %d iterations!", MAX_ITERATIONS_COLLINEAR);
00097 break;
00098 }
00099 iterations++;
00100 }
00101
00102 while (((Dx1 / Dx2) == Dy1Dy2) && (Dy1Dy2 == (Dz1 / Dz2)));
00103 iterations--;
00104
00105 return;
00106 }
00107
00109
00116 void
00117 SACModelCircle2D::selectWithinDistance (const std::vector<double> &model_coefficients, double threshold, std::vector<int> &inliers)
00118 {
00119 int nr_p = 0;
00120 inliers.resize (indices_.size ());
00121
00122
00123 for (unsigned int i = 0; i < indices_.size (); i++)
00124 {
00125
00126
00127 double distance_to_circle = fabs (sqrt (
00128 ( cloud_->points.at (indices_[i]).x - model_coefficients.at (0) ) *
00129 ( cloud_->points.at (indices_[i]).x - model_coefficients.at (0) ) +
00130
00131 ( cloud_->points.at (indices_[i]).y - model_coefficients.at (1) ) *
00132 ( cloud_->points.at (indices_[i]).y - model_coefficients.at (1) )
00133 ) - model_coefficients.at (2));
00134 if (distance_to_circle < threshold)
00135 {
00136
00137 inliers[nr_p] = indices_[i];
00138 nr_p++;
00139 }
00140 }
00141 inliers.resize (nr_p);
00142 return;
00143 }
00144
00146
00150 void
00151 SACModelCircle2D::getDistancesToModel (const std::vector<double> &model_coefficients, std::vector<double> &distances)
00152 {
00153 distances.resize (indices_.size ());
00154
00155
00156 for (unsigned int i = 0; i < indices_.size (); i++)
00157
00158
00159 distances[i] = fabs (sqrt (
00160 ( cloud_->points.at (indices_[i]).x - model_coefficients.at (0) ) *
00161 ( cloud_->points.at (indices_[i]).x - model_coefficients.at (0) ) +
00162
00163 ( cloud_->points.at (indices_[i]).y - model_coefficients.at (1) ) *
00164 ( cloud_->points.at (indices_[i]).y - model_coefficients.at (1) )
00165 ) - model_coefficients.at (2));
00166 return;
00167 }
00168
00170
00176 void
00177 SACModelCircle2D::projectPoints (const std::vector<int> &inliers, const std::vector<double> &model_coefficients,
00178 sensor_msgs::PointCloud &projected_points)
00179 {
00180
00181 projected_points = *cloud_;
00182
00183 double cx = model_coefficients[0];
00184 double cy = model_coefficients[1];
00185 double r = model_coefficients[2];
00186 for(size_t i=0;i<cloud_->get_points_size();i++) {
00187 double dx = cloud_->points[i].x - cx;
00188 double dy = cloud_->points[i].y - cy;
00189 double a = sqrt( SQR(r) / ( SQR(dx) + SQR(dy) ));
00190 projected_points.points[i].x = a*dx + cx;
00191 projected_points.points[i].y = a*dy + cy;
00192 }
00193 }
00194
00196
00201 void
00202 SACModelCircle2D::projectPointsInPlace (const std::vector<int> &inliers, const std::vector<double> &model_coefficients)
00203 {
00204 std::cerr << "[SACModelCircle2D::projecPointsInPlace] Not implemented yet." << std::endl;
00205 }
00206
00208
00212 bool
00213 SACModelCircle2D::computeModelCoefficients (const std::vector<int> &samples)
00214 {
00215 model_coefficients_.resize (3);
00216
00217 geometry_msgs::Point32 u, v, m;
00218 u.x = ( cloud_->points.at (samples.at (0)).x + cloud_->points.at (samples.at (1)).x ) / 2;
00219 u.y = ( cloud_->points.at (samples.at (1)).x + cloud_->points.at (samples.at (2)).x ) / 2;
00220
00221 v.x = ( cloud_->points.at (samples.at (0)).y + cloud_->points.at (samples.at (1)).y ) / 2;
00222 v.y = ( cloud_->points.at (samples.at (1)).y + cloud_->points.at (samples.at (2)).y ) / 2;
00223
00224 m.x = -( cloud_->points.at (samples.at (1)).x - cloud_->points.at (samples.at (0)).x ) /
00225 ( cloud_->points.at (samples.at (1)).y - cloud_->points.at (samples.at (0)).y );
00226 m.y = -( cloud_->points.at (samples.at (2)).x - cloud_->points.at (samples.at (1)).x ) /
00227 ( cloud_->points.at (samples.at (2)).y - cloud_->points.at (samples.at (1)).y );
00228
00229
00230 model_coefficients_[0] = (m.x * u.x - m.y * u.y - (v.x - v.y) ) / (m.x - m.y);
00231 model_coefficients_[1] = (m.x * m.y * (u.x - u.y) + m.x * v.y - m.y * v.x) / (m.x - m.y);
00232
00233
00234 model_coefficients_[2] = sqrt (
00235 ( model_coefficients_[0] - cloud_->points.at (samples.at (0)).x ) *
00236 ( model_coefficients_[0] - cloud_->points.at (samples.at (0)).x ) +
00237
00238 ( model_coefficients_[1] - cloud_->points.at (samples.at (0)).y ) *
00239 ( model_coefficients_[1] - cloud_->points.at (samples.at (0)).y )
00240 );
00241 return (true);
00242 }
00243
00245
00250 void
00251 SACModelCircle2D::refitModel (const std::vector<int> &inliers, std::vector<double> &refit_coefficients)
00252 {
00253 if (inliers.size () == 0)
00254 {
00255 ROS_ERROR ("[SACModelCircle2D::RefitModel] Cannot re-fit 0 inliers!");
00256 refit_coefficients = model_coefficients_;
00257 return;
00258 }
00259 if (model_coefficients_.size () == 0)
00260 {
00261 ROS_WARN ("[SACModelCircle2D::RefitModel] Initial model coefficients have not been estimated yet - proceeding without an initial solution!");
00262 best_inliers_ = indices_;
00263 }
00264
00265 tmp_inliers_ = &inliers;
00266
00267 int m = inliers.size ();
00268
00269 double *fvec = new double[m];
00270
00271 int n = 3;
00272 int iwa[n];
00273
00274 int lwa = m * n + 5 * n + m;
00275 double *wa = new double[lwa];
00276
00277
00278 double x[3] = {0.0, 0.0, 0.0};
00279 if ((int)model_coefficients_.size () == n)
00280 for (int d = 0; d < n; d++)
00281 x[d] = model_coefficients_.at (d);
00282
00283
00284 double tol = sqrt (dpmpar (1));
00285
00286
00287 int info = lmdif1 (&sample_consensus::SACModelCircle2D::functionToOptimize, this, m, n, x, fvec, tol, iwa, wa, lwa);
00288
00289
00290 ROS_DEBUG ("LM solver finished with exit code %i, having a residual norm of %g. \nInitial solution: %g %g %g \nFinal solution: %g %g %g",
00291 info, enorm (m, fvec), model_coefficients_.at (0), model_coefficients_.at (1), model_coefficients_.at (2), x[0], x[1], x[2]);
00292
00293 refit_coefficients.resize (n);
00294 for (int d = 0; d < n; d++)
00295 refit_coefficients[d] = x[d];
00296
00297 free (wa); free (fvec);
00298 }
00299
00301
00309 int
00310 SACModelCircle2D::functionToOptimize (void *p, int m, int n, const double *x, double *fvec, int iflag)
00311 {
00312 SACModelCircle2D *model = (SACModelCircle2D*)p;
00313
00314 for (int i = 0; i < m; i ++)
00315 {
00316
00317 double xt = model->cloud_->points[model->tmp_inliers_->at (i)].x - x[0];
00318 double yt = model->cloud_->points[model->tmp_inliers_->at (i)].y - x[1];
00319
00320
00321 fvec[i] = sqrt (xt * xt + yt * yt) - x[2];
00322 }
00323 return (0);
00324 }
00325
00327
00331 bool
00332 SACModelCircle2D::doSamplesVerifyModel (const std::set<int> &indices, double threshold)
00333 {
00334
00335 for (std::set<int>::iterator it = indices.begin (); it != indices.end (); ++it)
00336 {
00337
00338
00339 double distance_to_circle = fabs (sqrt (
00340 ( cloud_->points.at (*it).x - model_coefficients_.at (0) ) *
00341 ( cloud_->points.at (*it).x - model_coefficients_.at (0) ) +
00342
00343 ( cloud_->points.at (*it).y - model_coefficients_.at (1) ) *
00344 ( cloud_->points.at (*it).y - model_coefficients_.at (1) )
00345 ) - model_coefficients_.at (2));
00346 if (distance_to_circle > threshold)
00347 return (false);
00348 }
00349 return (true);
00350 }
00351 }