00001 #include <agile_grasp/quadric.h>
00002
00003 Quadric::Quadric(const std::vector<Eigen::Matrix4d, Eigen::aligned_allocator<Eigen::Matrix4d> >& T_cams,
00004 const PointCloud::Ptr& input, const Eigen::Vector3d& sample, bool is_deterministic) :
00005 input_(input), sample_(sample), is_deterministic_(is_deterministic)
00006 {
00007 cam_origins_.resize(3, T_cams.size());
00008 for (int i = 0; i < cam_origins_.cols(); i++)
00009 {
00010 cam_origins_.col(i) = T_cams.at(i).block < 3, 1 > (0, 3);
00011 }
00012 }
00013
00014 void Quadric::fitQuadric(const std::vector<int> &indices)
00015 {
00016 int n = indices.size();
00017
00018
00019 Eigen::Matrix<double, TAUBIN_MATRICES_SIZE, TAUBIN_MATRICES_SIZE> M;
00020 Eigen::Matrix<double, TAUBIN_MATRICES_SIZE, TAUBIN_MATRICES_SIZE> N;
00021 M.setZero(10, 10);
00022 N.setZero(10, 10);
00023
00024 for (int i = 0; i < n; i++)
00025 {
00026 if (isnan(input_->points[indices[i]].x))
00027 continue;
00028
00029 double x = input_->points[indices[i]].x;
00030 double y = input_->points[indices[i]].y;
00031 double z = input_->points[indices[i]].z;
00032 double x2 = x * x;
00033 double y2 = y * y;
00034 double z2 = z * z;
00035 double xy = x * y;
00036 double yz = y * z;
00037 double xz = x * z;
00038
00039
00040 M(0, 0) += x2 * x2;
00041 M(0, 1) += x2 * y2;
00042 M(0, 2) += x2 * z2;
00043 M(0, 3) += x2 * xy;
00044 M(0, 4) += x2 * yz;
00045 M(0, 5) += x2 * xz;
00046 M(0, 6) += x2 * x;
00047 M(0, 7) += x2 * y;
00048 M(0, 8) += x2 * z;
00049 M(0, 9) += x2;
00050 M(1, 1) += y2 * y2;
00051 M(1, 2) += y2 * z2;
00052 M(1, 3) += y2 * xy;
00053 M(1, 4) += y2 * yz;
00054 M(1, 5) += y2 * xz;
00055 M(1, 6) += y2 * x;
00056 M(1, 7) += y2 * y;
00057 M(1, 8) += y2 * z;
00058 M(1, 9) += y2;
00059 M(2, 2) += z2 * z2;
00060 M(2, 3) += z2 * xy;
00061 M(2, 4) += z2 * yz;
00062 M(2, 5) += z2 * xz;
00063 M(2, 6) += z2 * x;
00064 M(2, 7) += z2 * y;
00065 M(2, 8) += z2 * z;
00066 M(2, 9) += z2;
00067 M(3, 8) += x * yz;
00068 M(3, 9) += xy;
00069 M(4, 9) += yz;
00070 M(5, 9) += xz;
00071 M(6, 9) += x;
00072 M(7, 9) += y;
00073 M(8, 9) += z;
00074
00075
00076 M(3, 3) = M(0, 1);
00077 M(5, 5) = M(0, 2);
00078 M(3, 5) = M(0, 4);
00079 M(3, 6) = M(0, 7);
00080 M(5, 6) = M(0, 8);
00081 M(6, 6) = M(0, 9);
00082
00083 M(4, 4) = M(1, 2);
00084 M(3, 4) = M(1, 5);
00085 M(3, 7) = M(1, 6);
00086 M(4, 7) = M(1, 8);
00087 M(7, 7) = M(1, 9);
00088
00089 M(4, 5) = M(2, 3);
00090 M(5, 8) = M(2, 6);
00091 M(4, 8) = M(2, 7);
00092 M(8, 8) = M(2, 9);
00093
00094 M(4, 6) = M(3, 8);
00095 M(5, 7) = M(3, 8);
00096 M(6, 7) = M(3, 9);
00097
00098 M(7, 8) = M(4, 9);
00099
00100 M(6, 8) = M(5, 9);
00101
00102
00103 N(0, 0) += 4.0 * x2;
00104 N(0, 3) += 2.0 * xy;
00105 N(0, 5) += 2.0 * xz;
00106 N(0, 6) += 2.0 * x;
00107
00108 N(1, 1) += 4.0 * y2;
00109 N(1, 3) += 2.0 * xy;
00110 N(1, 4) += 2.0 * yz;
00111 N(1, 7) += 2.0 * y;
00112
00113 N(2, 2) += 4.0 * z2;
00114 N(2, 4) += 2.0 * yz;
00115 N(2, 5) += 2.0 * xz;
00116 N(2, 8) += 2.0 * z;
00117
00118 N(3, 3) += x2 + y2;
00119 N(3, 4) += xz;
00120 N(3, 5) += yz;
00121 N(3, 6) += y;
00122 N(3, 7) += x;
00123
00124 N(4, 4) += y2 + z2;
00125 N(4, 5) += xy;
00126 N(4, 7) += z;
00127 N(4, 8) += y;
00128
00129 N(5, 5) += x2 + z2;
00130 N(5, 6) += z;
00131 N(5, 8) += x;
00132 }
00133
00134 M(9, 9) = n;
00135
00136 M.triangularView<Eigen::StrictlyLower>() = M.triangularView<Eigen::StrictlyUpper>().transpose();
00137 N(6, 6) = n;
00138 N(7, 7) = n;
00139 N(8, 8) = n;
00140
00141 N.triangularView<Eigen::StrictlyLower>() = N.triangularView<Eigen::StrictlyUpper>().transpose();
00142
00143
00144
00145
00146 Eigen::MatrixXd eigen_vectors;
00147 Eigen::MatrixXd lambda;
00148 solveGeneralizedEigenProblem(M, N, eigen_vectors, lambda);
00149 Eigen::VectorXd eigen_values = lambda.col(0).cwiseQuotient(lambda.col(2));
00150 int min_index;
00151 eigen_values.segment(0, 9).minCoeff(&min_index);
00152 parameters_ = eigen_vectors.col(min_index);
00153 parameters_.segment(3, 3) *= 0.5;
00154
00155
00156 unpackQuadric();
00157 }
00158
00159 void Quadric::findTaubinNormalAxis(const std::vector<int> &indices, const Eigen::VectorXi& cam_source)
00160 {
00161
00162 double a = parameters_(0);
00163 double b = parameters_(1);
00164 double c = parameters_(2);
00165 double d = 2.0 * parameters_(3);
00166 double e = 2.0 * parameters_(4);
00167 double f = 2.0 * parameters_(5);
00168 double g = parameters_(6);
00169 double h = parameters_(7);
00170 double i = parameters_(8);
00171
00172
00173 Eigen::Matrix3Xd samples;
00174 Eigen::VectorXi samples_cam_source;
00175 if (!is_deterministic_)
00176 {
00177 int num_samples = 50;
00178 samples.resize(3, num_samples);
00179 samples_cam_source.resize(num_samples);
00180 if (indices.size() > num_samples)
00181 {
00182 for (int t = 0; t < num_samples; t++)
00183 {
00184 int r = rand() % indices.size();
00185 while (isnan(input_->points[indices[r]].x))
00186 {
00187 r = rand() % indices.size();
00188 }
00189
00190 samples.col(t) << input_->points[indices[r]].x, input_->points[indices[r]].y, input_->points[indices[r]].z;
00191 samples_cam_source(t) = cam_source(r);
00192 }
00193 }
00194 else
00195 {
00196 samples_cam_source = cam_source;
00197 samples.resize(3, indices.size());
00198 for (int t = 0; t < indices.size(); t++)
00199 {
00200 samples.col(t) << input_->points[indices[t]].x, input_->points[indices[t]].y, input_->points[indices[t]].z;
00201 }
00202 }
00203 }
00204 else
00205 {
00206 samples_cam_source = cam_source;
00207 samples.resize(3, indices.size());
00208 for (int t = 0; t < indices.size(); t++)
00209 {
00210 samples.col(t) << input_->points[indices[t]].x, input_->points[indices[t]].y, input_->points[indices[t]].z;
00211 }
00212 }
00213
00214
00215
00216
00217 Eigen::VectorXd num_source(this->cam_origins_.cols());
00218 num_source << 0, 0;
00219 for (int cami = 0; cami < samples_cam_source.size(); cami++)
00220 {
00221
00222 if (samples_cam_source(cami) == 0)
00223 num_source(0)++;else
00224 if (samples_cam_source(cami) == 1)
00225 num_source(1)++;}
00226 num_source .maxCoeff(&majority_cam_source_);
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 Eigen::MatrixXd fx = (2.0 * a * samples.row(0) + d * samples.row(1) + f * samples.row(2)).array() + g;
00239
00240 Eigen::MatrixXd fy = (2.0 * b * samples.row(1) + d * samples.row(0) + e * samples.row(2)).array() + h;
00241
00242 Eigen::MatrixXd fz = (2.0 * c * samples.row(2) + e * samples.row(1) + f * samples.row(0)).array() + i;
00243
00244 Eigen::MatrixXd normals(3, samples.cols());
00245 normals << fx, fy, fz;
00246 Eigen::MatrixXd gradient_magnitude = ((normals.cwiseProduct(normals)).colwise().sum()).cwiseSqrt();
00247 normals = normals.cwiseQuotient(gradient_magnitude.replicate(3, 1));
00248
00249
00250 findAverageNormalAxis(normals);
00251 }
00252
00253 void Quadric::print()
00254 {
00255 std::cout << "sample: " << sample_.transpose() << std::endl;
00256 std::cout << "parameters: " << parameters_.transpose() << std::endl;
00257 std::cout << "normals_ratio: " << normals_ratio_ << std::endl;
00258 std::cout << "normals_axis: " << curvature_axis_.transpose() << std::endl;
00259 std::cout << "normals_average: " << normal_.transpose() << std::endl;
00260 std::cout << "binormal: " << binormal_.transpose() << std::endl;
00261 }
00262
00263 void Quadric::findAverageNormalAxis(const Eigen::MatrixXd &normals)
00264 {
00265
00266 Eigen::Matrix3d M = normals * normals.transpose();
00267
00268 Eigen::EigenSolver<Eigen::MatrixXd> eigen_solver(M);
00269 Eigen::Vector3d eigen_values = eigen_solver.eigenvalues().real();
00270 Eigen::Matrix3d eigen_vectors = eigen_solver.eigenvectors().real();
00271
00272
00273 Eigen::Vector3d sorted_eigen_values = eigen_values;
00274 std::sort(sorted_eigen_values.data(), sorted_eigen_values.data() + sorted_eigen_values.size());
00275
00276
00277 normals_ratio_ = sorted_eigen_values(1) / sorted_eigen_values(2);
00278 int min_index;
00279 eigen_values.minCoeff(&min_index);
00280 curvature_axis_ = eigen_vectors.col(min_index);
00281
00282
00283 int max_index;
00284 (normals.transpose() * normals).array().pow(6).colwise().sum().maxCoeff(&max_index);
00285 Eigen::Vector3d normpartial = (Eigen::MatrixXd::Identity(3, 3)
00286 - curvature_axis_ * curvature_axis_.transpose()) * normals.col(max_index);
00287
00288 normal_ = normpartial / normpartial.norm();
00289
00290
00291 binormal_ = curvature_axis_.cross(normal_);
00292
00293
00294 Eigen::Vector3d source_to_sample = sample_ - cam_origins_.col(majority_cam_source_);
00295
00296
00297
00298 if (normal_.dot(source_to_sample) > 0)
00299 normal_ *= -1.0;
00300 if (binormal_.dot(source_to_sample) > 0)
00301 binormal_ *= -1.0;
00302
00303
00304 curvature_axis_ = normal_.cross(binormal_);
00305 }
00306
00307 void Quadric::unpackQuadric()
00308 {
00309 double a = parameters_(0);
00310 double b = parameters_(1);
00311 double c = parameters_(2);
00312 double d = parameters_(3);
00313 double e = parameters_(4);
00314 double f = parameters_(5);
00315 double g = parameters_(6);
00316 double h = parameters_(7);
00317 double i = parameters_(8);
00318 double j = parameters_(9);
00319
00320 Eigen::Matrix3d parameter_matrix;
00321 parameter_matrix << a, d, f, d, b, e, f, e, c;
00322 Eigen::Vector3d ghi;
00323 ghi << g, h, i;
00324 Eigen::Matrix3d inverse_parameter_matrix = parameter_matrix.inverse();
00325 centroid_ = -0.5 * inverse_parameter_matrix * ghi;
00326 double k = j - 0.25 * ghi.transpose() * inverse_parameter_matrix * ghi;
00327 covariance_matrix_ = -1 * parameter_matrix / k;
00328 }
00329
00330 bool Quadric::solveGeneralizedEigenProblem(const Eigen::MatrixXd& A, const Eigen::MatrixXd& B,
00331 Eigen::MatrixXd& v, Eigen::MatrixXd& lambda)
00332 {
00333 int N = A.cols();
00334 if (B.cols() != N || A.rows() != N || B.rows() != N)
00335 return false;
00336
00337 v.resize(N, N);
00338 lambda.resize(N, 3);
00339
00340 int LDA = A.outerStride();
00341 int LDB = B.outerStride();
00342 int LDV = v.outerStride();
00343
00344 double WORKDUMMY;
00345 int LWORK = -1;
00346 int INFO = 0;
00347
00348 double* alphar = const_cast<double*>(lambda.col(0).data());
00349 double* alphai = const_cast<double*>(lambda.col(1).data());
00350 double* beta = const_cast<double*>(lambda.col(2).data());
00351
00352
00353 dggev_("N", "V", &N, A.data(), &LDA, B.data(), &LDB, alphar, alphai, beta, 0, &LDV, v.data(), &LDV,
00354 &WORKDUMMY, &LWORK, &INFO);
00355
00356 LWORK = int(WORKDUMMY) + 32;
00357 Eigen::VectorXd WORK(LWORK);
00358
00359 dggev_("N", "V", &N, A.data(), &LDA, B.data(), &LDB, alphar, alphai, beta, 0, &LDV, v.data(), &LDV,
00360 WORK.data(), &LWORK, &INFO);
00361
00362 return INFO == 0;
00363 }
00364
00365 void Quadric::plotAxes(void* viewer_void, int id) const
00366 {
00367 boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer = *static_cast<boost::shared_ptr<
00368 pcl::visualization::PCLVisualizer> *>(viewer_void);
00369
00370 pcl::PointXYZ p, q, r;
00371 p.x = sample_(0);
00372 p.y = sample_(1);
00373 p.z = sample_(2);
00374 q.x = p.x + 0.02 * curvature_axis_(0);
00375 q.y = p.y + 0.02 * curvature_axis_(1);
00376 q.z = p.z + 0.02 * curvature_axis_(2);
00377 r.x = p.x + 0.02 * normal_(0);
00378 r.y = p.y + 0.02 * normal_(1);
00379 r.z = p.z + 0.02 * normal_(2);
00380
00381
00382
00383 viewer->addLine<pcl::PointXYZ>(p, q, 0, 0, 255, "curvature_axis_" + boost::lexical_cast<std::string>(id));
00384 viewer->addLine<pcl::PointXYZ>(p, r, 255, 0, 0, "normal_axis_" + boost::lexical_cast<std::string>(id));
00385 }