简体   繁体   English

如何在一组2D点周围拟合边界椭圆

[英]How to fit a bounding ellipse around a set of 2D points

Given a set of 2d points (in Cartesian form), I need to find the minimum-area ellipse such that every point in the set lies either on or inside the ellipse. 给定一组2d点(笛卡尔形式),我需要找到最小面积椭圆,使得集合中的每个点都位于椭圆上或内部。

I have found the solution in the form of pseudo-code on this site, but my attempt to implement the solution in C++ has been unsuccessful. 我在这个网站上找到了伪代码形式的解决方案 ,但是我在C ++中实现解决方案的尝试却没有成功。

The following image illustrates graphically what the solution to my problem looks like: 下图以图形方式说明了我的问题的解决方案是什么样的:

一组带有边界椭圆的点

In my attempt, I used the Eigen library for the various operations on matrices. 在我的尝试中,我使用了特征库来进行矩阵上的各种操作。

//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;

The error occurs on the following line: 错误发生在以下行:

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

and it reads as follows: 它的内容如下:

    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)

Can someone please point out why this error is occurring or even better, give me some advice on how to fit an ellipse to a set of points using C++? 有人可以指出为什么会发生这个错误甚至更好,请给我一些关于如何使用C ++将椭圆拟合到一组点的建议?

With Eigen, you can get the diagonal vector from a matrix with .diagonal() ; 使用Eigen,您可以使用.diagonal()从矩阵中获取对角矢量; you can treat a vector as a diagonal matrix with .asDiagonal() ; 你可以使用.asDiagonal()将矢量视为对角矩阵; but you cannot treat a dense matrix as a diagonal matrix. 但你不能将密集矩阵视为对角矩阵。 So that line should be 那条线应该是

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM