#include "StdAfx.h" #include "CHDataFitting.h" #include #include "OpenCV/cxcore.h" CCHDataFitting::CCHDataFitting(void) { } CCHDataFitting::~CCHDataFitting(void) { } inline bool CompareValue(double& a, double& b) { return (a < b); } inline double Median(double *pValue, int nSize) { int odd = nSize % 2; int index = nSize / 2; // sort double dTemp = 0.0; for(int i=0; ipValue[j]) { dTemp=pValue[i]; pValue[i]=pValue[j]; pValue[j]=dTemp; } } } if (odd==1) { return pValue[index]; } return ((pValue[index-1]+pValue[index])/2.0); } inline double MedianAbsoluteDeviation(double *pValue, int nSize, double dMedian) { for (int i=0; i= nSize) return 0; int nMatrixSize = nOrder + 1; int nMaxOrder = nOrder * 2 + 1; double *pX = new double[nMatrixSize * nMatrixSize]; double *pA = new double[nMatrixSize]; double *pY = new double[nMatrixSize]; double *pOrderX = new double[nMaxOrder]; memset(pX, 0, sizeof(double)*(nMatrixSize*nMatrixSize)); memset(pA, 0, sizeof(double)*(nMatrixSize)); memset(pY, 0, sizeof(double)*(nMatrixSize)); memset(pOrderX, 0, sizeof(double)*(nMaxOrder)); int nTemp = 1; for (int i=0; i= nSize) return 0; double *pX = new double[nMatrixSize * nMatrixSize]; double *pA = new double[nMatrixSize]; double *pY = new double[nMatrixSize]; double *pOrderX = new double[nMaxOrder]; memset(pX, 0, sizeof(double)*(nMatrixSize*nMatrixSize)); memset(pA, 0, sizeof(double)*(nMatrixSize)); memset(pY, 0, sizeof(double)*(nMatrixSize)); memset(pOrderX, 0, sizeof(double)*(nMaxOrder)); int nTemp = 1; for (int i=0; i= nSize) return 0; int nMatrixSize = nOrder + 1; int nMaxOrder = nOrder * 2 + 1; VectorDouble vectorWeight, vectorResidual; vectorWeight.resize(nSize); vectorResidual.resize(nSize); for (int i=0; i= nSize) return 0; double *pWeight = new double[nSize]; double *pResidual = new double[nSize]; for (int i=0; i dStopThres ) break; dPrevValue = dCurValue; } // copy result memcpy(pResult, pA, sizeof(double)*3); delete [] pWeight; delete [] pResidual; return nReturnIteration+1; } int CCHDataFitting::IRLS_GaussianFitting(VectorDouble& vectorX, VectorDouble& vectorY, VectorDouble& vectorR, int nIteration, double dWeight, double dStopThres) { vectorR.clear(); size_t nSize = vectorX.size(); if (nSize < 3) return 0; VectorDouble vectorWeight, vectorResidual, vectorLY; vectorWeight.resize(nSize); vectorResidual.resize(nSize); vectorLY.resize(nSize); for (size_t i=0; i Ad, bd; double gfp[5], rp[5], t; CvMat A, b, x; const double min_eps = 1e-6; Ad.allocate(nSize*5); bd.allocate(nSize); // first fit for parameters A - E A = cvMat( nSize, 5, CV_64F, Ad ); b = cvMat( nSize, 1, CV_64F, bd ); x = cvMat( 5, 1, CV_64F, gfp ); double avg_x = 0.0; double avg_y = 0.0; for (int i=0; i fabs(gfp[2])*min_eps ) t = gfp[2]/t; else t = gfp[1] - gfp[0]; rp[2] = fabs(gfp[0] + gfp[1] - t); if( rp[2] > min_eps ) rp[2] = sqrt(2.0 / rp[2]); rp[3] = fabs(gfp[0] + gfp[1] + t); if( rp[3] > min_eps ) rp[3] = sqrt(2.0 / rp[3]); pResult[0] = rp[0] + avg_x; // center x pResult[1] = rp[1] + avg_y; // center y pResult[2] = rp[2]*2.0; // size width pResult[3] = rp[3]*2.0; // size height pResult[4] = 90.0 + rp[4]*180.0/CV_PI; // angle if( pResult[2] > pResult[3] ) { double tmp = pResult[2]; pResult[2] = pResult[3]; pResult[3] = tmp; } if( pResult[4]< -180 ) pResult[4] += 360; if( pResult[4] > 360 ) pResult[4] -= 360; return 1; } int CCHDataFitting::EllipseFitting(VectorDouble& vectorX , VectorDouble& vectorY, VectorDouble& vectorResult) { int n = (int) vectorX.size(); if( n < 5 ) return 0; /* * New fitellipse algorithm, contributed by Dr. Daniel Weiss */ cv::AutoBuffer Ad, bd; double gfp[5], rp[5], t; CvMat A, b, x; const double min_eps = 1e-6; Ad.allocate(n*5); bd.allocate(n); // first fit for parameters A - E A = cvMat( n, 5, CV_64F, Ad ); b = cvMat( n, 1, CV_64F, bd ); x = cvMat( 5, 1, CV_64F, gfp ); double avg_x = 0.0; double avg_y = 0.0; for(int i=0; i fabs(gfp[2])*min_eps ) t = gfp[2]/t; else t = gfp[1] - gfp[0]; rp[2] = fabs(gfp[0] + gfp[1] - t); if( rp[2] > min_eps ) rp[2] = sqrt(2.0 / rp[2]); rp[3] = fabs(gfp[0] + gfp[1] + t); if( rp[3] > min_eps ) rp[3] = sqrt(2.0 / rp[3]); vectorResult.clear(); vectorResult.push_back(rp[0] + avg_x); // center x vectorResult.push_back(rp[1] + avg_y); // center y vectorResult.push_back(rp[2]*2.0); // size width vectorResult.push_back(rp[3]*2.0); // size height vectorResult.push_back(90.0 + rp[4]*180.0/CV_PI); // angle if( vectorResult[2] > vectorResult[3] ) { double tmp = vectorResult[2]; vectorResult[2] = vectorResult[3]; vectorResult[3] = tmp; } if( vectorResult[4]< -180 ) vectorResult[4] += 360; if( vectorResult[4] > 360 ) vectorResult[4] -= 360; return 1; } int CCHDataFitting::IRLS_ParaboloidFitting(VectorDouble& vectorX, VectorDouble& vectorY, VectorDouble& vectorZ, VectorDouble& vectorResult, int nIteration, double dWeight, double dStopThres) { vectorResult.clear(); int nSize = (int)vectorX.size(); if (nSize<6) return 0; VectorDouble vectorWeight, vectorResidual; vectorWeight.resize(nSize); vectorResidual.resize(nSize); for (int i=0; i=1;k--) { sum -= a[i][k]*a[j][k]; if (sum<=0.0) { TRACE(""); } } if (i == j) { if (sum<=0.0) { TRACE(""); } else { p[i]=sqrt(sum); } } else { a[j][i]=sum/p[i]; } } } for (i=1; i<=n; i++) { for (j=i; j<=n; j++) { if (i==j) { l[i][i] = p[i]; } else { l[j][i]=a[j][i]; l[i][j]=0.0; } } } delete [] p; } /********************************************************************/ /** Calcola la inversa della matrice B mettendo il risultato **/ /** in InvB . Il metodo usato per l'inversione e' quello di **/ /** Gauss-Jordan. N e' l'ordine della matrice . **/ /** ritorna 0 se l'inversione corretta altrimenti ritorna **/ /** SINGULAR . **/ /********************************************************************/ int inverse(double **TB, double **InvB, int N) { int k,i,j,p,q; double mult; double D,temp; double maxpivot; int npivot; double **B = new double* [N+1]; double **A = new double* [N+1]; double **C = new double* [N+1]; for (int i=0; i=eps) { if (npivot!=k) { for (j=k;j<=2*N+1;j++) { temp=A[npivot][j]; A[npivot][j]=A[k][j]; A[k][j]=temp; } } D=A[k][k]; for (j=2*N+1;j>=k;j--) { A[k][j]=A[k][j]/D; } for (i=1;i<=N;i++) { if (i!=k) { mult=A[i][k]; for (j=2*N+1;j>=k;j--) { A[i][j]=A[i][j]-mult*A[k][j] ; } } } } else { return -1; } } } /** Copia il risultato nella matrice InvB ***/ for (k=1,p=1;k<=N;k++,p++) { for (j=N+2,q=1;j<=2*N+1;j++,q++) { InvB[p][q]=A[k][j]; } } for (int i=0; i 4 && abs(d[ip])+g == abs(d[ip]) && abs(d[iq])+g == abs(d[iq])) { a[ip][iq]=0.0; } else if (abs(a[ip][iq]) > tresh) { h=d[iq]-d[ip]; if (abs(h)+g == abs(h)) { t=(a[ip][iq])/h; } else { theta=0.5*h/(a[ip][iq]); t=1.0/(abs(theta)+sqrt(1.0+theta*theta)); if (theta < 0.0) { t = -t; } } c=1.0/sqrt(1+t*t); s=t*c; tau=s/(1.0+c); h=t*a[ip][iq]; z[ip] -= h; z[iq] += h; d[ip] -= h; d[iq] += h; a[ip][iq]=0.0; for (j=1;j<=ip-1;j++) { ROTATE(a,j,ip,j,iq,tau,s); } for (j=ip+1;j<=iq-1;j++) { ROTATE(a,ip,j,j,iq,tau,s); } for (j=iq+1;j<=n;j++) { ROTATE(a,ip,j,iq,j,tau,s); } for (j=1;j<=n;j++) { ROTATE(v,j,ip,j,iq,tau,s); } ++nrot; } } } for (ip=1;ip<=n;ip++) { b[ip] += z[ip]; d[ip]=b[ip]; z[ip]=0.0; } } delete [] b; delete [] z; //printf("Too many iterations in routine JACOBI"); } int CCHDataFitting::EllipseFitting2(double *pXValue, double *pYValue, int nSize, double *pResult) { if (nSize<6) return 0 ; double **D = new double*[nSize+1]; for (int i=0; i<=nSize; i++) { D[i] = new double[7]; memset(D[i], 0, sizeof(double)*7); } double **S = new double*[7]; double **L = new double*[7]; double **invL = new double*[7]; double **Const = new double*[7]; double **temp = new double*[7]; double **C = new double*[7]; double **V = new double*[7]; double **sol = new double*[7]; double *d = new double[7]; memset(d, 0, sizeof(double)*7); for (int i=0; i<7; i++) { S[i] = new double[7]; memset(S[i], 0, sizeof(double)*7); L[i] = new double[7]; memset(L[i], 0, sizeof(double)*7); invL[i] = new double[7]; memset(invL[i], 0, sizeof(double)*7); Const[i] = new double[7]; memset(Const[i], 0, sizeof(double)*7); temp[i] = new double[7]; memset(temp[i], 0, sizeof(double)*7); C[i] = new double[7]; memset(C[i], 0, sizeof(double)*7); V[i] = new double[7]; memset(V[i], 0, sizeof(double)*7); sol[i] = new double[7]; memset(sol[i], 0, sizeof(double)*7); } double tx,ty; int nrot=0; int mode = 0; switch (mode) { case 0: Const[1][3]=-2; Const[2][2]=1; Const[3][1]=-2; break; case 1: Const[1][1]=2; Const[2][2]=1; Const[3][3]=2; break; } // Now first fill design matrix for (int i=1; i <= nSize; i++) { tx = pXValue[i-1]; ty = pYValue[i-1]; D[i][1] = tx*tx; D[i][2] = tx*ty; D[i][3] = ty*ty; D[i][4] = tx; D[i][5] = ty; D[i][6] = 1.0; } //pm(Const,"Constraint"); // Now compute scatter matrix S A_TperB(D, D, S, nSize, 6, nSize, 6); // (A') * (B) //pm(S,"Scatter"); choldc(S, 6, L); //pm(L,"Cholesky"); inverse(L, invL, 6); //pm(invL,"inverse"); AperB_T(Const, invL, temp, 6, 6, 6, 6); AperB(invL, temp, C, 6, 6, 6, 6); //pm(C,"The C matrix"); jacobi(C, 6, d, V, nrot); //pm(V,"The Eigenvectors"); /* OK */ //pv(d,"The eigevalues"); A_TperB(invL, V, sol, 6, 6, 6, 6); //pm(sol,"The GEV solution unnormalized"); /* SOl */ // Now normalize them for (int j=1;j<=6;j++) /* Scan columns */ { double mod = 0.0; for (int i=1;i<=6;i++) { mod += sol[i][j]*sol[i][j]; } for (int i=1;i<=6;i++) { sol[i][j] /= sqrt(mod); } } //pm(sol,"The GEV solution"); /* SOl */ double zero=10e-20; double minev=10e+20; int solind=0; switch (mode) { case 0: for (int i=1; i<=6; i++) { if (d[i]<0.0 && abs(d[i])>zero) { solind = i; } } break; case 1: // smallest eigenvalue for (int i=1; i<=6; i++) { if (d[i]zero) { solind = i; } } break; } // Now fetch the right solution for (int j=1;j<=6;j++) { pResult[j-1] = sol[j][solind]; } for (int i=0; i<=nSize; i++) { delete [] D[i]; } for (int i=0; i<7; i++) { delete [] S[i]; delete [] L[i]; delete [] invL[i]; delete [] Const[i]; delete [] temp[i]; delete [] C[i]; delete [] V[i]; delete [] sol[i]; } delete [] D; delete [] S; delete [] L; delete [] invL; delete [] Const; delete [] temp; delete [] C; delete [] V; delete [] sol; delete [] d; return 1; } int CCHDataFitting::EllipseFitting2(VectorDouble& vectorX, VectorDouble& vectorY, VectorDouble& vectorResult) { int nSize = (int) vectorX.size(); if (nSize<6) return 0 ; double **D = new double*[nSize+1]; for (int i=0; i<=nSize; i++) { D[i] = new double[7]; memset(D[i], 0, sizeof(double)*7); } double **S = new double*[7]; double **L = new double*[7]; double **invL = new double*[7]; double **Const = new double*[7]; double **temp = new double*[7]; double **C = new double*[7]; double **V = new double*[7]; double **sol = new double*[7]; double *d = new double[7]; memset(d, 0, sizeof(double)*7); for (int i=0; i<7; i++) { S[i] = new double[7]; memset(S[i], 0, sizeof(double)*7); L[i] = new double[7]; memset(L[i], 0, sizeof(double)*7); invL[i] = new double[7]; memset(invL[i], 0, sizeof(double)*7); Const[i] = new double[7]; memset(Const[i], 0, sizeof(double)*7); temp[i] = new double[7]; memset(temp[i], 0, sizeof(double)*7); C[i] = new double[7]; memset(C[i], 0, sizeof(double)*7); V[i] = new double[7]; memset(V[i], 0, sizeof(double)*7); sol[i] = new double[7]; memset(sol[i], 0, sizeof(double)*7); } double tx,ty; int nrot=0; int mode = 0; switch (mode) { case 0: Const[1][3]=-2; Const[2][2]=1; Const[3][1]=-2; break; case 1: Const[1][1]=2; Const[2][2]=1; Const[3][3]=2; break; } // Now first fill design matrix for (int i=1; i <= nSize; i++) { tx = vectorX[i-1]; ty = vectorY[i-1]; D[i][1] = tx*tx; D[i][2] = tx*ty; D[i][3] = ty*ty; D[i][4] = tx; D[i][5] = ty; D[i][6] = 1.0; } //pm(Const,"Constraint"); // Now compute scatter matrix S A_TperB(D, D, S, nSize, 6, nSize, 6); // (A') * (B) //pm(S,"Scatter"); choldc(S, 6, L); //pm(L,"Cholesky"); inverse(L, invL, 6); //pm(invL,"inverse"); AperB_T(Const, invL, temp, 6, 6, 6, 6); AperB(invL, temp, C, 6, 6, 6, 6); //pm(C,"The C matrix"); jacobi(C, 6, d, V, nrot); //pm(V,"The Eigenvectors"); /* OK */ //pv(d,"The eigevalues"); A_TperB(invL, V, sol, 6, 6, 6, 6); //pm(sol,"The GEV solution unnormalized"); /* SOl */ // Now normalize them for (int j=1;j<=6;j++) /* Scan columns */ { double mod = 0.0; for (int i=1;i<=6;i++) { mod += sol[i][j]*sol[i][j]; } for (int i=1;i<=6;i++) { sol[i][j] /= sqrt(mod); } } //pm(sol,"The GEV solution"); /* SOl */ double zero=10e-20; double minev=10e+20; int solind=0; switch (mode) { case 0: for (int i=1; i<=6; i++) { if (d[i]<0.0 && abs(d[i])>zero) { solind = i; } } break; case 1: // smallest eigenvalue for (int i=1; i<=6; i++) { if (d[i]zero) { solind = i; } } break; } // Now fetch the right solution vectorResult.clear(); for (int j=1;j<=6;j++) { vectorResult.push_back(sol[j][solind]); } for (int i=0; i<=nSize; i++) { delete [] D[i]; } for (int i=0; i<7; i++) { delete [] S[i]; delete [] L[i]; delete [] invL[i]; delete [] Const[i]; delete [] temp[i]; delete [] C[i]; delete [] V[i]; delete [] sol[i]; } delete [] D; delete [] S; delete [] L; delete [] invL; delete [] Const; delete [] temp; delete [] C; delete [] V; delete [] sol; delete [] d; return 1; } int CCHDataFitting::Conic2Ellipse(double *conic_param, double *ellipse_param) { double a = conic_param[0]; double b = conic_param[1]; double c = conic_param[2]; double d = conic_param[3]; double e = conic_param[4]; double f = conic_param[5]; // get ellipse orientation double theta = 0.5 * atan2(b, a-c); // get scaled major/minor axes double ct = cos(theta); double st = sin(theta); double ap = a*ct*ct + b*ct*st + c*st*st; double cp = a*st*st + b*ct*st + c*ct*ct; // get translations double cx = (2.0*c*d - b*e) / (b*b - 4*a*c); double cy = (2.0*a*e - b*d) / (b*b - 4*a*c); // get scale factor double val = a*cx*cx + b*cx*cy + c*cy*cy; double scale_inv = val - f; if ((scale_inv/ap) <=0.0 || (scale_inv/cp) <=0.0) { return 0; } // const double min_eps = 1e-6; // double t = sin(2.0 * theta); // if( fabs(t) > fabs(b)*min_eps ) // t = b / t; // else // t = a - c; // // double min = fabs(c + a - t); // if( min > min_eps ) // min = sqrt(2.0 / min); // // double max = fabs(c + a + t); // if( max > min_eps ) // max = sqrt(2.0 / max); ellipse_param[0] = sqrt(scale_inv / ap); ellipse_param[1] = sqrt(scale_inv / cp); ellipse_param[2] = cx; ellipse_param[3] = cy; ellipse_param[4] = theta; return 1; } int CCHDataFitting::Conic2Ellipse(VectorDouble& conic_param, VectorDouble& ellipse_param) { if (conic_param.size()!=6) return 0; double a = conic_param[0]; double b = conic_param[1]; double c = conic_param[2]; double d = conic_param[3]; double e = conic_param[4]; double f = conic_param[5]; // get ellipse orientation double theta = 0.5 * atan2(b, a-c); // get scaled major/minor axes double ct = cos(theta); double st = sin(theta); double ap = a*ct*ct + b*ct*st + c*st*st; double cp = a*st*st + b*ct*st + c*ct*ct; // get translations double cx = (2.0*c*d - b*e) / (b*b - 4*a*c); double cy = (2.0*a*e - b*d) / (b*b - 4*a*c); // get scale factor double val = a*cx*cx + b*cx*cy + c*cy*cy; double scale_inv = val - f; if ((scale_inv/ap) <=0.0 || (scale_inv/cp) <=0.0) { return 0; } // const double min_eps = 1e-6; // double t = sin(2.0 * theta); // if( fabs(t) > fabs(b)*min_eps ) // t = b / t; // else // t = a - c; // // double min = fabs(c + a - t); // if( min > min_eps ) // min = sqrt(2.0 / min); // // double max = fabs(c + a + t); // if( max > min_eps ) // max = sqrt(2.0 / max); ellipse_param.clear(); ellipse_param.push_back(sqrt(scale_inv / ap)); ellipse_param.push_back(sqrt(scale_inv / cp)); ellipse_param.push_back(cx); ellipse_param.push_back(cy); ellipse_param.push_back(theta); return 1; }