Ask Your Question

Revision history [back]

First you should work with double instead of float. Yes there is a problem. I think problem is in S1, S2, S3 using scilab(matlab clone) I have got this

--> S1
 S1  = 

   1.666D+13   6.640D+12   4.037D+12
   6.640D+12   4.037D+12   3.387D+12
   4.037D+12   3.387D+12   3.961D+12


--> S2
 S2  = 

   3.988D+10   1.686D+10   1.013D+08
   1.686D+10   1.211D+10   48020669.
   1.211D+10   1.358D+10   48544327.


--> S3
 S3  = 

   1.013D+08   48020669.   288422.
   48020669.   48544327.   192469.
   288422.     192469.     1156.

Data are not good for numerical computation. You have to change origin and scale in your data : normalize between -1 +1 It will give you :

Eigenvalue: [-2.118390551250616;
 -117.9218332186111;
 -122.9426765681663]
Eigenvector: [0.7071067312014415, 0.0001447164181614355, 0.7071068163628255;
 -0.007183290097389554, 0.9999498482088568, 0.006978639585240439;
 0.707070343765731, 0.01001399641712809, -0.707072308072356]
cond =[1.999845198382039, -0.9998939021741439, -1.999951296207895]
[a b c] =[0.7071067312014415;
 -0.007183290097389554;
 0.707070343765731]
[d e f] =[-0.001143313356372834;
 -5.692680060736142e-005;
 -0.6524152428074719]

Parameters are given in new axis. If you want in original system you have to rescale it

with this code

float LeastSquaresEllipseFit(vector<double> xCors, vector<double> yCors){
//Design matrix split into quadratic and linear part
cv::Mat D1(xCors.size(), 3, CV_64FC1); cv::Mat D2(xCors.size(), 3, CV_64FC1);
//Scatter matrix split into quadratic, combined and linear part
cv::Mat S1(3, 3, CV_64FC1); cv::Mat S2(3, 3, CV_64FC1); cv::Mat S3(3, 3, CV_64FC1);

double mx=0,my=0;
for (size_t i = 0; i < xCors.size(); i++)
{
    mx += xCors[i];
    my += yCors[i];
}
mx /= xCors.size();
my /= xCors.size();
cout << mx << "\t"<<my<<endl;
if (mx!=0)
    for (size_t i = 0; i < xCors.size(); i++)
    {
        xCors[i] = (xCors[i]-mx)/mx;
        yCors[i] = (yCors[i]-my)/my;
    }

for (size_t i = 0; i < xCors.size(); i++)
{
    D1.at<double>(i, 0) = xCors[i] * xCors[i];
    D1.at<double>(i, 1) = xCors[i] * yCors[i];
    D1.at<double>(i, 2) = yCors[i] * yCors[i];
    D2.at<double>(i, 0) = xCors[i];
    D2.at<double>(i, 1) = yCors[i];
    D2.at<double>(i, 2) = 1;
}

cv::Mat T(3, 3, CV_64FC1);
cv::Mat M(3, 3, CV_64FC1);
cv::Mat C(3, 3, CV_64FC1); C.setTo(0);

C.at<double>(0, 2) = 2;
C.at<double>(1, 1) = -1;
C.at<double>(2, 0) = 2;

S1 = D1.t() * D1;
S2 = D1.t() * D2;
S3 = D2.t() * D2;
T=-S3.inv(DECOMP_SVD)*S2.t();
//Solution 1:
M = C.inv() * (S1 + S2*(T));


cv::Mat EVal, EVec;

cv::eigen(M, EVal, EVec);

cout << "Eigenvalue: " << EVal << endl;
cout << "Eigenvector: " << EVec << endl;
Mat cond = 4 * EVec.row(0).mul(EVec.row(2)) - EVec.row(1).mul(EVec.row(1));
cout<<"cond ="<<cond<<endl;
int index=-1;
for (int i = 0; i < cond.cols; i++)
{
    if (cond.at<double>(i)>0)
        index =i;
}
cout << "[a b c] ="<<EVec.col(index)<<endl;
cout << "[d e f] ="<<T*EVec.col(index)<<endl;
return abs(d);
}

First you should work with double instead of float. Yes there is a problem. I think problem is in S1, S2, S3 using scilab(matlab clone) I have got this

--> S1
 S1  = 

   1.666D+13   6.640D+12   4.037D+12
   6.640D+12   4.037D+12   3.387D+12
   4.037D+12   3.387D+12   3.961D+12


--> S2
 S2  = 

   3.988D+10   1.686D+10   1.013D+08
   1.686D+10   1.211D+10   48020669.
   1.211D+10   1.358D+10   48544327.


--> S3
 S3  = 

   1.013D+08   48020669.   288422.
   48020669.   48544327.   192469.
   288422.     192469.     1156.

Data are not good for numerical computation. You have to change origin and scale in your data : normalize between -1 +1 It will give you :

Eigenvalue: [-2.118390551250616;
 -117.9218332186111;
 -122.9426765681663]
Eigenvector: [0.7071067312014415, 0.0001447164181614355, 0.7071068163628255;
 -0.007183290097389554, 0.9999498482088568, 0.006978639585240439;
 0.707070343765731, 0.01001399641712809, -0.707072308072356]
cond =[1.999845198382039, -0.9998939021741439, -1.999951296207895]
[a b c] =[0.7071067312014415;
 -0.007183290097389554;
 0.707070343765731]
[d e f] =[-0.001143313356372834;
 -5.692680060736142e-005;
 -0.6524152428074719]

Parameters are given in new axis. If you want in original system you have to rescale it

with this code

float LeastSquaresEllipseFit(vector<double> xCors, vector<double> yCors){
//Design matrix split into quadratic and linear part
cv::Mat D1(xCors.size(), 3, CV_64FC1); cv::Mat D2(xCors.size(), 3, CV_64FC1);
//Scatter matrix split into quadratic, combined and linear part
cv::Mat S1(3, 3, CV_64FC1); cv::Mat S2(3, 3, CV_64FC1); cv::Mat S3(3, 3, CV_64FC1);

double mx=0,my=0;
for (size_t i = 0; i < xCors.size(); i++)
{
    mx += xCors[i];
    my += yCors[i];
}
mx /= xCors.size();
my /= xCors.size();
cout << mx << "\t"<<my<<endl;
if (mx!=0)
    for (size_t i = 0; i < xCors.size(); i++)
    {
        xCors[i] = (xCors[i]-mx)/mx;
        yCors[i] = (yCors[i]-my)/my;
    }

for (size_t i = 0; i < xCors.size(); i++)
{
    D1.at<double>(i, 0) = xCors[i] * xCors[i];
    D1.at<double>(i, 1) = xCors[i] * yCors[i];
    D1.at<double>(i, 2) = yCors[i] * yCors[i];
    D2.at<double>(i, 0) = xCors[i];
    D2.at<double>(i, 1) = yCors[i];
    D2.at<double>(i, 2) = 1;
}

cv::Mat T(3, 3, CV_64FC1);
cv::Mat M(3, 3, CV_64FC1);
cv::Mat C(3, 3, CV_64FC1); C.setTo(0);

C.at<double>(0, 2) = 2;
C.at<double>(1, 1) = -1;
C.at<double>(2, 0) = 2;

S1 = D1.t() * D1;
S2 = D1.t() * D2;
S3 = D2.t() * D2;
T=-S3.inv(DECOMP_SVD)*S2.t();
//Solution 1:
M = C.inv() * (S1 + S2*(T));


cv::Mat EVal, EVec;

cv::eigen(M, EVal, EVec);

cout << "Eigenvalue: " << EVal << endl;
cout << "Eigenvector: " << EVec << endl;
Mat cond = 4 * EVec.row(0).mul(EVec.row(2)) - EVec.row(1).mul(EVec.row(1));
cout<<"cond ="<<cond<<endl;
int index=-1;
for (int i = 0; i < cond.cols; i++)
{
    if (cond.at<double>(i)>0)
        index =i;
}

Mat tmp13=EVec.col(index); Mat tmp46=T*EVec.col(index); if (mx == 0) { cout << "[a b c] ="<<EVec.col(index)<<endl; ="<<tmp13 abs(tmp46.at<double="">(2))<<endl; cout="" &lt;&lt;="" "[d="" e="" f]="&lt;&lt;tmp46/abs(tmp46.at&lt;double&gt;(2))&lt;&lt;endl; } else { double a=tmp13.at&lt;double&gt;(0),b=tmp13.at&lt;double&gt;(1),c=tmp13.at&lt;double&gt;(2); double d=tmp46.at&lt;double&gt;(0),e=tmp46.at&lt;double&gt;(1),f=tmp46.at&lt;double&gt;(2);&lt;/p&gt; &lt;pre&gt;&lt;code&gt;double ac=abs(a+b+c-d-e+f); cout << "[d e f] ="<<T*EVec.col(index)<<endl; &lt;&lt; " [a="" b="" c]="&lt;&lt;a/mx/mx/ac&lt;&lt;" \t"&lt;&lt;b="" mx="" my="" ac&lt;&lt;"\t"&lt;&lt;c="" my="" my="" ac="" &lt;&lt;endl;="" cout="" &lt;&lt;="" "[d="" e="" f]="&lt;&lt;(-b/mx+d/mx-2*a/mx)/ac&lt;&lt;" \t"&lt;&lt;(-b="" my+d="" my-2*c="" my)="" ac&lt;&lt;"\t"&lt;&lt;-1&lt;&lt;endl;="" <="" code="">

} return abs(d); } }

First you should work with double instead of float. Yes there is a problem. I think problem is in S1, S2, S3 using scilab(matlab clone) I have got this

--> S1
 S1  = 

   1.666D+13   6.640D+12   4.037D+12
   6.640D+12   4.037D+12   3.387D+12
   4.037D+12   3.387D+12   3.961D+12


--> S2
 S2  = 

   3.988D+10   1.686D+10   1.013D+08
   1.686D+10   1.211D+10   48020669.
   1.211D+10   1.358D+10   48544327.


--> S3
 S3  = 

   1.013D+08   48020669.   288422.
   48020669.   48544327.   192469.
   288422.     192469.     1156.

Data are not good for numerical computation. You have to change origin and scale in your data : normalize between -1 +1 It will give you :

Eigenvalue: [-2.118390551250616;
 -117.9218332186111;
 -122.9426765681663]
Eigenvector: [0.7071067312014415, 0.0001447164181614355, 0.7071068163628255;
 -0.007183290097389554, 0.9999498482088568, 0.006978639585240439;
 0.707070343765731, 0.01001399641712809, -0.707072308072356]
cond =[1.999845198382039, -0.9998939021741439, -1.999951296207895]
[a b c] =[0.7071067312014415;
 -0.007183290097389554;
 0.707070343765731]
[d e f] =[-0.001143313356372834;
 -5.692680060736142e-005;
 -0.6524152428074719]

Parameters are given in new axis. If you want in original system you have to rescale it

with this code

float LeastSquaresEllipseFit(vector<double> xCors, vector<double> yCors){
//Design matrix split into quadratic and linear part
cv::Mat D1(xCors.size(), 3, CV_64FC1); cv::Mat D2(xCors.size(), 3, CV_64FC1);
//Scatter matrix split into quadratic, combined and linear part
cv::Mat S1(3, 3, CV_64FC1); cv::Mat S2(3, 3, CV_64FC1); cv::Mat S3(3, 3, CV_64FC1);

double mx=0,my=0;
for (size_t i = 0; i < xCors.size(); i++)
{
    mx += xCors[i];
    my += yCors[i];
}
mx /= xCors.size();
my /= xCors.size();
cout << mx << "\t"<<my<<endl;
if (mx!=0)
    for (size_t i = 0; i < xCors.size(); i++)
    {
        xCors[i] = (xCors[i]-mx)/mx;
        yCors[i] = (yCors[i]-my)/my;
    }

for (size_t i = 0; i < xCors.size(); i++)
{
    D1.at<double>(i, 0) = xCors[i] * xCors[i];
    D1.at<double>(i, 1) = xCors[i] * yCors[i];
    D1.at<double>(i, 2) = yCors[i] * yCors[i];
    D2.at<double>(i, 0) = xCors[i];
    D2.at<double>(i, 1) = yCors[i];
    D2.at<double>(i, 2) = 1;
}

cv::Mat T(3, 3, CV_64FC1);
cv::Mat M(3, 3, CV_64FC1);
cv::Mat C(3, 3, CV_64FC1); C.setTo(0);

C.at<double>(0, 2) = 2;
C.at<double>(1, 1) = -1;
C.at<double>(2, 0) = 2;

S1 = D1.t() * D1;
S2 = D1.t() * D2;
S3 = D2.t() * D2;
T=-S3.inv(DECOMP_SVD)*S2.t();
//Solution 1:
M = C.inv() * (S1 + S2*(T));


cv::Mat EVal, EVec;

cv::eigen(M, EVal, EVec);

cout << "Eigenvalue: " << EVal << endl;
cout << "Eigenvector: " << EVec << endl;
Mat cond = 4 * EVec.row(0).mul(EVec.row(2)) - EVec.row(1).mul(EVec.row(1));
cout<<"cond ="<<cond<<endl;
int index=-1;
for (int i = 0; i < cond.cols; i++)
{
    if (cond.at<double>(i)>0)
        index =i;
}

Mat tmp13=EVec.col(index); Mat tmp46=T*EVec.col(index); if (mx == 0) { cout << "[a b c] ="<<tmp13 abs(tmp46.at<double="">(2))<<endl; cout="" &lt;&lt;="" "[d="" e="" f]="&lt;&lt;tmp46/abs(tmp46.at&lt;double&gt;(2))&lt;&lt;endl; ="<<tmp13/abs(tmp46.at<double>(2))<<endl; cout << "[d e f] ="<<tmp46/abs(tmp46.at<double>(2))<<endl; } else { double a=tmp13.at&lt;double&gt;(0),b=tmp13.at&lt;double&gt;(1),c=tmp13.at&lt;double&gt;(2); a=tmp13.at<double>(0),b=tmp13.at<double>(1),c=tmp13.at<double>(2); double d=tmp46.at&lt;double&gt;(0),e=tmp46.at&lt;double&gt;(1),f=tmp46.at&lt;double&gt;(2);&lt;/p&gt; &lt;pre&gt;&lt;code&gt;double d=tmp46.at<double>(0),e=tmp46.at<double>(1),f=tmp46.at<double>(2); double ac=abs(a+b+c-d-e+f); cout &lt;&lt; " [a="" b="" c]="&lt;&lt;a/mx/mx/ac&lt;&lt;" \t"&lt;&lt;b="" mx="" my="" ac&lt;&lt;"\t"&lt;&lt;c="" my="" my="" ac="" &lt;&lt;endl;="" cout="" &lt;&lt;="" "[d="" e="" f]="&lt;&lt;(-b/mx+d/mx-2*a/mx)/ac&lt;&lt;" \t"&lt;&lt;(-b="" my+d="" my-2*c="" my)="" ac&lt;&lt;"\t"&lt;&lt;-1&lt;&lt;endl;="" <="" code="">

<< "[a b c] ="<<a/mx/mx/ac<<"\t"<<b/mx/my/ac<<"\t"<<c/my/my/ac <<endl; cout << "[d e f] ="<<(-b/mx+d/mx-2*a/mx)/ac<<"\t"<<(-b/my+d/my-2*c/my)/ac<<"\t"<<-1<<endl; } return abs(d); }

}