2016-06-19 22 views
6

Bei einem Satz von 2D-Punkten (in kartesischer Form) muss ich die Ellipse mit dem kleinsten Bereich finden, so dass jeder Punkt auf oder in der Ellipse liegt .Wie man eine Begrenzungsellipse um einen Satz von 2D-Punkten anordnet

Ich habe found the solution in Form von Pseudocode auf dieser Website, aber mein Versuch, die Lösung in C++ zu implementieren, war nicht erfolgreich.

Das folgende Bild zeigt in graphischer Form, was die Lösung für mein Problem wie folgt aussieht:

a set of points with a bounding ellipse

In meinem Versuch, ich die Eigen Bibliothek für die verschiedenen Operationen auf Matrizen verwendet.

//The tolerance for error in fitting the ellipse 
double tolerance = 0.2; 
int n = 10; // number of points 
int d = 2; // dimension 
MatrixXd p = MatrixXd::Random(d,n); //Fill matrix with random points 

MatrixXd q = p; 
q.conservativeResize(p.rows() + 1, p.cols()); 

for(size_t i = 0; i < q.cols(); i++) 
{ 
    q(q.rows() - 1, i) = 1; 
} 

int count = 1; 
double err = 1; 

const double init_u = 1.0/(double) n; 
MatrixXd u = MatrixXd::Constant(n, 1, init_u); 


while(err > tolerance) 
{ 
    MatrixXd Q_tr = q.transpose(); 
    cout << "1 " << endl; 
    MatrixXd X = q * u.asDiagonal() * Q_tr; 
    cout << "1a " << endl; 
    MatrixXd M = (Q_tr * X.inverse() * q).asDiagonal(); 
    cout << "1b " << endl; 



    int j_x, j_y; 
    double maximum = M.maxCoeff(&j_x, &j_y); 
    double step_size = (maximum - d - 1)/((d + 1) * (maximum + 1)); 

    MatrixXd new_u = (1 - step_size) * u; 
    new_u(j_x, 0) += step_size; 

    cout << "2 " << endl; 

    //Find err 
    MatrixXd u_diff = new_u - u; 
    for(size_t i = 0; i < u_diff.rows(); i++) 
    { 
     for(size_t j = 0; j < u_diff.cols(); j++) 
      u_diff(i, j) *= u_diff(i, j); // Square each element of the matrix 
    } 
    err = sqrt(u_diff.sum()); 
    count++; 
    u = new_u; 
} 

cout << "3 " << endl; 
MatrixXd U = u.asDiagonal(); 
MatrixXd A = (1.0/(double) d) * (p * U * p.transpose() - (p * u) * (p * u).transpose()).inverse(); 
MatrixXd c = p * u; 

Der Fehler tritt in der folgenden Zeile:

MatrixXd M = (Q_tr * X.inverse() * q).asDiagonal(); 

und lautet wie folgt:

run: /usr/include/eigen3/Eigen/src/Core/DenseBase.h:261: void Eigen::DenseBase<Derived>::resize(Eigen::Index, Eigen::Index) [with Derived = Eigen::Diagonal<Eigen::Matrix<double, -1, -1>, 0>; Eigen::Index = long int]: Assertion `rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."' failed. 
Aborted (core dumped) 

Kann jemand bitte darauf hinweisen, warum dieser Fehler auftritt, oder noch besser, geben mir einen Tipp, wie man mit C++ eine Ellipse an eine Menge von Punkten anpasst?

Antwort

1

Mit Eigen, können Sie den Diagonalvektor von einer Matrix mit .diagonal(); Sie können einen Vektor als diagonale Matrix mit .asDiagonal() behandeln; aber Sie können eine dichte Matrix nicht als diagonale Matrix behandeln. So sollte diese Linie

sein
MatrixXd M = (Q_tr * X.inverse() * q).diagonal(); 
+1

Dies vollständig gelöst das Problem und der Algorithmus findet die Ellipse. Sieht so aus, als ob das Problem von meinem fehlenden Verständnis der linearen Algebra und nicht von C++ herrührt. Vielen Dank! – Dziugas