注意哦 这里是求圆心 不是球心哦
条件:已知空间N点坐标,格式如下 求圆心坐标,半径
-33.386698 -12.312448 -2301.396442
-33.668120 -12.571431 -2300.390996
-33.838611 -12.774933 -2299.691688
-34.079235 -13.616660 -2298.326277
-34.254998 -13.441280 -2298.192657
-34.356542 -13.755525 -2297.796473
........................................................
实现方法:用最小二乘法拟合出 球面方程 和 平面方程,两者相交即为所求圆曲线
球面方程:(x - a)^2 + (y - b)^2 + (z - c)^2 = R^2
展开: x^2 + y^2 + z ^2 + a^2 +b^2 +c^2 - 2ax - 2by -2cz = R ^2
令 A = 2a ; B =2b ; C =2c D=a^2 +b^2 +c^2 -R^2
得 x^2 + y^2 + z ^2 - Ax -By - Cz + D =0
即:Ax +By +Cz -D = x^2 +y^2 +z^2
用矩阵表示这N组数据如下形式
现在就是求 A B C D 的问题了
具体步骤如下
平面方程 A' x + B' y + C' z + D' = 0
可化为 A x + B y + C z -1 =0
用矩阵表示如下
同样可以求出 A B C
这样就有了球面方程 球心坐标 球半径 和 平面方程了
如图所示(网络找的图,意思着看 囧)
圆心为球心到平面的垂足(也就是 平面外一点到平面的坐标问题)
半径为 sqrt(球半径^2 - 球心到平面的距离^2)
设 平面方程为 A X + B Y + C Z +D = 0 ① 球心坐标(a,b,c)
平面外一点到平面的坐标问题:
则 平面的法向量为 (A ,B ,C )
设垂足即圆心 (x' y' z') 球心到圆心的连线 与法向量是平行的
可以得到如下 (x' -a )/A = (y' -b)/B = (z' - c)/C = t ②
由 ②得 x' = At + a; y' = B t + b ; z' = C t + c;
带入① 可以得到(x' , y' , z')
平面外一点到平面的距离问题
d = abs(Ax' + By' + C z' +D) / sqrt(A^2 + B^2 +C^2)
到此为止已经有了足够的理论知识,下面是代码 分别用 OPENCV 和C 实现
1 // 最小二乘法拟合球.cpp : 定义控制台应用程序的入口点。
2 //
3
4 #include "stdafx.h"
5 #include <iostream>
6 #include <fstream>
7 #include <cmath>
8 usingnamespace std;
9
10 #include <cv.h>
11 #include <cxcore.h>
12 #include <highgui.h>
13
14 #ifdef DEBUG
15 #pragma comment(lib,"cxcore200d.lib")
16 #pragma comment(lib,"cv200d.lib")
17 #pragma comment(lib,"highgui200d.lib")
18 #else
19 #pragma comment(lib,"cxcore200.lib")
20 #pragma comment(lib,"cv200.lib")
21 #pragma comment(lib,"highgui200.lib")
22
23 #endif
24
25 void fitRound(char*filepath,int n)
26 {
27 ifstream file(filepath);
28 //int n = 0; //数据组数
29
30 //file>>n;
31 /*
32 x ~ NX4
33 | x1 y1 z1 -1 |
34 |. .. .... .......... |
35 | .. ...... ..........|
36 |xn yn zn -1|
37 */
38 int xsize =4*n*sizeof(double);
39 double*x = (double*)malloc(xsize);
40 /*
41 y ~ NX1
42 |x1^2 + y1^2 +z1^2 |
43 |.......................................|
44 |.......................................|
45 |xn^2+yn^2+zn^2 |
46 */
47 int ysize = n *sizeof(double);
48 double*y = (double*)malloc(ysize);
49
50 /*
51 z ~NX3
52 |x1 y1 z1|
53 |...............|
54 |...............|
55 |xn yn zn|
56 */
57 int zsize =3* n *sizeof(double);
58 double*z = (double*)malloc(zsize);
59
60 /*
61 p ~ Nx1
62 | 1 |
63 | .. |
64 | .. |
65 | 1 |
66 */
67 int psize = n *sizeof(double);
68 double*p = (double*)malloc(psize);
69
70 for (int i=0;i<n;i++)
71 {
72 file>>*(x+i*4+0)>>*( x+i*4+1)>>*(x +i*4+2);
73 *(x+i*4+3) =-1;
74
75 *(y +i) =*(x+i*4+0) **(x+i*4+0) +*(x+i*4+1) **(x+i*4+1) +*(x+i*4+2) **(x+i*4+2);
76
77 *(z+i*3+0) =*(x+i*4+0);
78 *(z+i*3+1) =*(x+i*4+1);
79 *(z+i*3+2) =*(x+i*4+2);
80
81 *(p+i) =1;
82 }
83
84 // ---------------------------- 球面方程
85 //x^2 +y^2 + z^2 - AX - BY - CZ +D =0
86
87 // x 对应的矩阵
88 CvMat * MAT_X = cvCreateMat(n,4,CV_64FC1);
89 memcpy(MAT_X->data.db,x,xsize);
90
91 // y 对应的矩阵
92 CvMat *MAT_Y = cvCreateMat(n,1,CV_64FC1);
93 memcpy(MAT_Y->data.db,y,ysize);
94
95 //xT -- x的转置矩阵
96 CvMat *MAT_XT = cvCreateMat(4,n,CV_64FC1);
97 cvTranspose(MAT_X,MAT_XT);
98
99 // xT (4xn) * x(n*4) = XT_X(4*4)
100 CvMat *MAT_XT_X = cvCreateMat(4,4,CV_64FC1);
101 cvMatMul(MAT_XT,MAT_X,MAT_XT_X);
102
103 //xT (4xn) * y(n*1) = xT_Y(4*1)
104 CvMat *MAT_XT_Y = cvCreateMat(4,1,CV_64FC1);
105 cvMatMul(MAT_XT,MAT_Y,MAT_XT_Y);
106
107 //MAT_XT_X_INVERT -- MAT_XT_X的逆矩阵
108 CvMat *MAT_XT_X_INVERT = cvCreateMat(4,4,CV_64FC1);
109 cvInvert(MAT_XT_X,MAT_XT_X_INVERT,CV_LU); // 高斯消去法
110
111 //MAT_ABCD 4X1结果矩阵
112 CvMat *MAT_ABCD = cvCreateMat(4,1,CV_64FC1);
113 cvMatMul(MAT_XT_X_INVERT,MAT_XT_Y,MAT_ABCD);
114
115 double c_x,c_y,c_z,c_r;
116 double*ptr = MAT_ABCD->data.db;
117 c_x =*ptr /2;
118 c_y =*(ptr+1)/2;
119 c_z =*(ptr+2)/2;
120 c_r =sqrt (c_x *c_x +c_y *c_y +c_z *c_z -*(ptr+3));
121
122
123 //-----------------------平面方程
124 //E X + F y +G z =1
125
126 // z 对应矩阵
127 CvMat * MAT_Z = cvCreateMat(n,3,CV_64FC1);
128 memcpy(MAT_Z->data.db,z,zsize);
129
130 // p 对应矩阵
131 CvMat *MAT_P = cvCreateMat(n,1,CV_64FC1);
132 memcpy(MAT_P->data.db,p,psize);
133
134 //z 的转置矩阵
135 CvMat *MAT_ZT = cvCreateMat(3,n,CV_64FC1);
136 cvTranspose(MAT_Z,MAT_ZT);
137
138 //zt * z
139 CvMat *MAT_ZT_Z = cvCreateMat(3,3,CV_64FC1);
140 cvMatMul(MAT_ZT,MAT_Z,MAT_ZT_Z);
141
142 //ZT * P
143 CvMat * MAT_ZT_P = cvCreateMat(3,1,CV_64FC1);
144 cvMatMul(MAT_ZT,MAT_P,MAT_ZT_P);
145
146 // MAT_ZT_Z的逆矩阵
147 CvMat *MAT_ZT_Z_INVERT = cvCreateMat(3,3,CV_64FC1);
148 cvInvert(MAT_ZT_Z,MAT_ZT_Z_INVERT,CV_LU);
149
150 //MAT_EFG 3X1结果
151 CvMat *MAT_EFG = cvCreateMat(3,1,CV_64FC1);
152 cvMatMul(MAT_ZT_Z_INVERT,MAT_ZT_P,MAT_EFG);
153
154 double E,F,G;
155 E =* MAT_EFG->data.db;
156 F =*(MAT_EFG->data.db +1);
157 G =*(MAT_EFG->data.db +2 );
158 //圆心坐标 半径
159 double n_x, n_y, n_z, n_r;
160 n_x = ((F*F+G*G)*c_x +E *(-F*c_y - G*c_z +1))/ ( E *E + F *F+ G *G);
n_y = ((E*E+G*G)*c_y +F* (-E*c_x -G*c_z +1))/ ( E *E + F *F+ G *G);
n_z = ((E*E+F*F)*c_z +G*(-E*c_x -F *c_y +1))/( E *E + F *F+ G *G);
162
163
164 n_r = sqrt( c_r *c_r - (E *c_x +F *c_y +G *c_z -1 ) *(E *c_x +F *c_y +G *c_z -1 ) /(E *E +F * F +G *G) );
165
166 printf("%f %f %f %f\n",n_x,n_y,n_z,n_r);
167 file.close();
168 }
169
170 int _tmain(int argc, _TCHAR* argv[])
171 {
172
173
174 for (int i =4 ; i<35;i++)
175 {
176 fitRound("log.txt",i);
177 }
178 getchar();
179 return0;
180 }
C 实现方式
// 最小二乘法求圆心CC++.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;
int InverseMatrix(double *matrix,const int &row);
void swap(double &a,double &b);
int mulMatrix(double *matrixA,int m1,int n1,double *matrixB,int m2,int n2,double *matrixC);
int transPoseMatrix(double *matrixA,int m,int n,double *matrixB);
void fitRoud(char * filepath,int n);
int _tmain(int argc, _TCHAR* argv[])
{
for (int i=4 ;i<35;i++)
{
fitRoud("log.txt",i);
}
getchar();
return 0;
}
void swap(double &a,double &b)
{
double temp=a;
a=b;
b=temp;
}
/**********************************************
*函数名:InverseMatrix
*函数介绍:求逆矩阵(高斯—约当法)
*输入参数:矩阵首地址(二维数组)matrix,阶数row
*输出参数:matrix原矩阵的逆矩阵
*返回值:成功,0;失败,1
*调用函数:swap(double &a,double &b)
**********************************************/
int InverseMatrix(double *matrix,const int &row)
{
double *m=new double[row*row];
double *ptemp,*pt=m;
int i,j;
ptemp=matrix;
for (i=0;i<row;i++)
{
for (j=0;j<row;j++)
{
*pt=*ptemp;
ptemp++;
pt++;
}
}
int k;
int *is=new int[row],*js=new int[row];
for (k=0;k<row;k++)
{
double max=0;
//全选主元
//寻找最大元素
for (i=k;i<row;i++)
{
for (j=k;j<row;j++)
{
if (fabs(*(m+i*row+j))>max)
{
max=*(m+i*row+j);
is[k]=i;
js[k]=j;
}
}
}
if (0 == max)
{
return 1;
}
//行交换
if (is[k]!=k)
{
for (i=0;i<row;i++)
{
swap(*(m+k*row+i),*(m+is[k]*row+i));
}
}
//列交换
if (js[k]!=k)
{
for (i=0;i<row;i++)
{
swap(*(m+i*row+k),*(m+i*row+js[k]));
}
}
*(m+k*row+k)=1/(*(m+k*row+k));
for (j=0;j<row;j++)
{
if (j!=k)
{
*(m+k*row+j)*=*((m+k*row+k));
}
}
for (i=0;i<row;i++)
{
if (i!=k)
{
for (j=0;j<row;j++)
{
if(j!=k)
{
*(m+i*row+j)-=*(m+i*row+k)**(m+k*row+j);
}
}
}
}
for (i=0;i<row;i++)
{
if(i!=k)
{
*(m+i*row+k)*=-(*(m+k*row+k));
}
}
}
int r;
//恢复
for (r=row-1;r>=0;r--)
{
if (js[r]!=r)
{
for (j=0;j<row;j++)
{
swap(*(m+r*row+j),*(m+js[r]*row+j));
}
}
if (is[r]!=r)
{
for (i=0;i<row;i++)
{
swap(*(m+i*row+r),*(m+i*row+is[r]));
}
}
}
ptemp=matrix;
pt=m;
for (i=0;i<row;i++)
{
for (j=0;j<row;j++)
{
*ptemp=*pt;
ptemp++;
pt++;
}
}
delete []is;
delete []js;
delete []m;
return 0;
}
/*
*函数名:mulMatrix
*函数介绍:矩阵相乘
*输入参数 :matrixA ----矩阵首地址
m1,n1 ----- matrixA 行列数
matrixB -----矩阵首地址
m2,n2 ------matrixB 行列数
* matrixC 结果矩阵 行列数 m1 n2
*返回值 : 0 -- 失败
1 -- 成功
*/
int mulMatrix(double *matrixA,int m1,int n1,double *matrixB,int m2,int n2,double *matrixC)
{
/*
if( n1 !=m2 )
return 0;
if( sizeof(matrixC) ! = m1 * n2 * sizeof(double) )
return 0;
*/
for (int i=0;i<m1;++i)
{
for (int j=0;j<n2;++j)
{
*(matrixC + i *n2 +j) =0.0;
// matrixA - i 行 * matrixB -- j 列
for (int k = 0;k<m2;k++)
{
*(matrixC + i *n2 +j) +=*(matrixA + i*n1 + k) * *(matrixB +k * n2 + j);
}
}
}
return 1;
}
/*
*函数名:transPoseMatrix
*函数介绍:矩阵转置
*输入参数 :matrixA ----源矩阵
m1,n1 ----- matrixA 行列数
matrixB -----转置结果
*返回值 : 0 -- 失败
1 -- 成功
*/
int transPoseMatrix(double *matrixA,int m,int n,double *matrixB)
{
for (int i=0;i<m;++i)
{
for (int j=0;j<n;++j)
{
*(matrixB + j *m +i) = *(matrixA + i * n + j);
}
}
return 1;
}
void fitRoud(char * filepath,int n)
{
ifstream file(filepath);
//int n = 0; //数据组数
//file>>n;
/*
x ~ NX4
| x1 y1 z1 -1 |
|. .. .... .......... |
| .. ...... ..........|
|xn yn zn -1|
*/
int xsize = 4*n*sizeof(double);
double *x = (double *)malloc(xsize);
/*
y ~ NX1
|x1^2 + y1^2 +z1^2 |
|.......................................|
|.......................................|
|xn^2+yn^2+zn^2 |
*/
int ysize = n * sizeof(double);
double *y = (double *)malloc(ysize);
/*
z ~NX3
|x1 y1 z1|
|...............|
|...............|
|xn yn zn|
*/
int zsize = 3 * n * sizeof(double);
double *z = (double *)malloc(zsize);
/*
p ~ Nx1
| 1 |
| .. |
| .. |
| 1 |
*/
int psize = n * sizeof(double);
double *p = (double *)malloc(psize);
for (int i=0;i<n;i++)
{
file>>*(x+i*4+0)>>*( x+i*4+1)>>*(x +i*4 +2);
*(x+i*4+3) = -1;
*(y +i) = *(x+i*4+0) * *(x+i*4+0) +*(x+i*4+1) * *(x+i*4+1) + *(x+i*4+2) * *(x+i*4+2);
*(z+i*3+0) = *(x+i*4+0);
*(z+i*3+1) = *(x+i*4+1);
*(z+i*3+2) = *(x+i*4+2);
*(p+i) = 1;
}
file.close();
// ---------------------------- 球面方程
//x^2 +y^2 + z^2 - AX - BY - CZ +D =0
// x 对应的矩阵
double * MAT_X = (double *)malloc(n * 4 * sizeof(double));
memcpy(MAT_X,x,xsize);
// y 对应的矩阵
double *MAT_Y = (double *)malloc(n * 1 *sizeof(double));
memcpy(MAT_Y,y,ysize);
//xT -- x的转置矩阵
double *MAT_XT =(double *)malloc(4 * n * sizeof(double));
transPoseMatrix(MAT_X,n,4,MAT_XT);
// xT (4xn) * x(n*4) = XT_X(4*4)
double *MAT_XT_X = (double *)malloc(4 * 4 * sizeof(double));
mulMatrix(MAT_XT,4,n,MAT_X,n,4,MAT_XT_X);
//xT (4xn) * y(n*1) = xT_Y(4*1)
double *MAT_XT_Y = (double *)malloc(4 * 1 * sizeof(double ));
mulMatrix(MAT_XT,4,n,MAT_Y,n,1,MAT_XT_Y);
//MAT_XT_X_INVERT -- MAT_XT_X的逆矩阵
double *MAT_XT_X_INVERT = NULL;
InverseMatrix(MAT_XT_X,4);
MAT_XT_X_INVERT = MAT_XT_X;
//MAT_ABCD 4X1结果矩阵
double *MAT_ABCD = (double *)malloc(4 * 1 * sizeof(double));
mulMatrix(MAT_XT_X_INVERT,4,4,MAT_XT_Y,4,1,MAT_ABCD);
double c_x,c_y,c_z,c_r;
double *ptr = MAT_ABCD;
c_x = *ptr /2;
c_y = *(ptr+1)/2;
c_z = *(ptr+2)/2;
c_r =sqrt (c_x *c_x +c_y *c_y +c_z *c_z -*(ptr+3));
//-----------------------平面方程
//E X + F y +G z =1
// z 对应矩阵
double * MAT_Z = (double *)malloc(n * 3 * sizeof(double ));
memcpy(MAT_Z,z,zsize);
// p 对应矩阵
double *MAT_P =(double *)malloc(n * 1 * sizeof(double));
memcpy(MAT_P,p,psize);
//z 的转置矩阵
double *MAT_ZT = (double *)malloc(3 * n * sizeof(double));
transPoseMatrix(MAT_Z,n,3,MAT_ZT);
//zt * z
double * MAT_ZT_Z = (double *)malloc(3 * 3 * sizeof(double));
mulMatrix(MAT_ZT,3,n,MAT_Z,n,3,MAT_ZT_Z);
//ZT * P
double * MAT_ZT_P =(double *)malloc( 3 * 1 * sizeof(double));
mulMatrix(MAT_ZT,3,n,MAT_P,n,1,MAT_ZT_P);
// MAT_ZT_Z的逆矩阵
double *MAT_ZT_Z_INVERT = (double *)malloc(3 * 3 * sizeof(double));
InverseMatrix(MAT_ZT_Z,3);
MAT_ZT_Z_INVERT = MAT_ZT_Z;
//MAT_EFG 3X1
double *MAT_EFG = (double *)malloc(3 * 1*sizeof(double));
mulMatrix(MAT_ZT_Z_INVERT,3,3,MAT_ZT_P,3,1,MAT_EFG);
double E,F,G;
E =* MAT_EFG;
F = *(MAT_EFG+1);
G = *(MAT_EFG+2 );
//圆心坐标 半径
double n_x, n_y, n_z, n_r;
n_x = ((F*F+G*G)*c_x +E *(-F*c_y - G*c_z +1))/ ( E *E + F *F+ G *G);
n_y = ((E*E+G*G)*c_y +F* (-E*c_x -G*c_z +1))/ ( E *E + F *F+ G *G);
n_z = ((E*E+F*F)*c_z +G*(-E*c_x -F *c_y +1))/( E *E + F *F+ G *G);
n_r = sqrt( c_r *c_r - (E *c_x +F *c_y +G *c_z -1 ) *(E *c_x +F *c_y +G *c_z -1 ) /(E *E +F * F +G *G) );
printf("%f %f %f %f\n",n_x,n_y,n_z,n_r);
free(x);
free(y);
free(z);
free(MAT_X);
free(MAT_XT);
free(MAT_XT_X);
free(MAT_XT_Y);
free(MAT_Y);
free(MAT_Z);
free(MAT_ZT);
free(MAT_ZT_P);
free(MAT_ZT_Z);
free(MAT_P);
free(MAT_ABCD);
free(MAT_EFG);
}