圆的方程可以表示为:
R 2 = ( x − A ) 2 + ( y − B ) 2 (1) R^2 = (x-A)^2+(y-B)^2\tag{1} R2=(x−A)2+(y−B)2(1)
展开后为:
R 2 = x 2 − 2 A x + A 2 + y 2 − 2 B y + B 2 R^2 = x^2-2Ax+A^2+y^2-2By+B^2 R2=x2−2Ax+A2+y2−2By+B2
令 a = − 2 A , b = − 2 B , c = A 2 + B 2 − R 2 a=-2A,b=-2B,c=A^2+B^2-R^2 a=−2A,b=−2B,c=A2+B2−R2:
则式 ( 1 ) (1) (1)可表示为:
x 2 + y 2 + a x + b y + c = 0 x^2+y^2+ax+by+c=0 x2+y2+ax+by+c=0
− a x − b y − c = x 2 + y 2 -ax-by-c = x^2+y^2 −ax−by−c=x2+y2
矩阵形式可表示为:
[ − x 1 − y 1 − 1 − x 2 − y 2 − 1 ⋯ ⋯ ⋯ − x n − y n − 1 ] [ a b c ] = [ x 1 2 + y 1 2 x 2 2 + y 2 2 ⋯ x n 2 + y n 2 ] \begin{gathered} \quad \begin{bmatrix} -x_1 & -y_1 & -1 \\ -x_2 & -y_2 & -1 \\ \cdots & \cdots & \cdots \\ -x_n & -y_n & -1 \end{bmatrix} \begin{bmatrix} a \\ b \\ c \end{bmatrix} = \begin{bmatrix} x_1^2+y_1^2 \\ x_2^2+y_2^2 \\ \cdots \\ x_n^2+y_n^2 \end{bmatrix} \end{gathered} −x1−x2⋯−xn−y1−y2⋯−yn−1−1⋯−1 abc = x12+y12x22+y22⋯xn2+yn2
得到 R ⋅ A = Y R \cdot A = Y R⋅A=Y的矩阵形式后,便可利用 A = ( R T ⋅ R ) − 1 ⋅ R T ⋅ Y A = (R^T \cdot R)^{-1} \cdot R^T \cdot Y A=(RT⋅R)−1⋅RT⋅Y得到 a 、 b 、 c a、b、c a、b、c的值。
Python代码为:
def Fit_Circle(x=None, y=None):
if x is None:
x = [1, 0, -1, 0]
if y is None:
y = [0, 1, 0, -1]
Y = []
R = []
for i in range(len(x)):
R.append([-x[i], -y[i], -1])
Y.append(np.square(x[i]) + np.square(y[i]))
R = np.mat(R)
A = np.dot(np.dot(np.linalg.inv(np.dot(R.T, R)), R.T), Y)
A = np.array(A, dtype='float32').flatten()
return round(-(A[0] / 2), 2), round(-(A[1] / 2), 2), round(np.sqrt(np.square(A[0]) + np.square(A[1]) - 4 * A[2]) / 2, 2)
根据圆心坐标和半径画出圆的代码为:
def Show_Circle(x=0, y=0, r=2):
theta = np.arange(0, 2 * np.pi, 0.01)
x = x + r * np.cos(theta)
y = y + r * np.sin(theta)
fig = plt.figure()
axes = fig.add_subplot(111)
axes.plot(x, y)
axes.axis('equal')
plt.show()
Python完整代码为:
import matplotlib.pyplot as plt
import numpy as np
def Show_Circle(x=0, y=0, r=2):
theta = np.arange(0, 2 * np.pi, 0.01)
x = x + r * np.cos(theta)
y = y + r * np.sin(theta)
fig = plt.figure()
axes = fig.add_subplot(111)
axes.plot(x, y)
axes.axis('equal')
plt.show()
def Fit_Circle(x=None, y=None):
if x is None:
x = [1, 0, -1, 0]
if y is None:
y = [0, 1, 0, -1]
Y = []
R = []
for i in range(len(x)):
R.append([-x[i], -y[i], -1])
Y.append(np.square(x[i]) + np.square(y[i]))
R = np.mat(R)
A = np.dot(np.dot(np.linalg.inv(np.dot(R.T, R)), R.T), Y)
A = np.array(A, dtype='float32').flatten()
return round(-(A[0] / 2), 2), round(-(A[1] / 2), 2), round(np.sqrt(np.square(A[0]) + np.square(A[1]) - 4 * A[2]) / 2, 2)
if __name__ == '__main__':
a = [2, 0, -2, 0]
b = [0, 2, 0, -2]
X, Y, R = Fit_Circle(x=a, y=b)
Show_Circle(X, Y, R)
C++完整代码为:
#include
#include
#include
using namespace std;
double a[][2] = {{2,0},{0,2},{-2,0},{0,-2}};
int M = sizeof(a) / sizeof(a[0]);
void matrix_inverse(double(*a)[3], double(*b)[3]);
int main()
{
double R[M][3] = {0};
double R_T[3][M] = {0};
double RR[3][3] = {0}; // R_T * R
double RR_1[3][3] = {0};
double RR_1R_T[3][M] = {0}; // RR_1 * R_T
double Y[M][1] = {0};
double A[3][1] = {0};
for(int i = 0; i < M; i++)
{
R[i][0] = -a[i][0];
R[i][1] = -a[i][1];
R[i][2] = -1;
R_T[0][i] = -a[i][0];
R_T[1][i] = -a[i][1];
R_T[2][i] = -1;
Y[i][0] = pow(a[i][0], 2) + pow(a[i][1], 2);
}
for(int i = 0; i < 3; ++i) // 矩阵相乘 (k的取值来源于左边矩阵的列数或右边矩阵的行数)
for(int j = 0; j < 3; ++j)
{
RR[i][j] = 0;
for(int k = 0; k < M; ++k)
RR[i][j] += R_T[i][k] * R[k][j];
}
matrix_inverse(RR, RR_1);
for(int i = 0; i < 3; ++i) // 矩阵相乘 (k的取值来源于左边矩阵的列数或右边矩阵的行数)
for(int j = 0; j < M; ++j)
{
RR_1R_T[i][j] = 0;
for(int k = 0; k < 3; ++k)
RR_1R_T[i][j] += RR_1[i][k] * R_T[k][j];
}
for(int i = 0; i < 3; ++i) // 矩阵相乘 (k的取值来源于左边矩阵的列数或右边矩阵的行数)
for(int j = 0; j < 1; ++j)
{
A[i][j] = 0;
for(int k = 0; k < M; ++k)
A[i][j] += RR_1R_T[i][k] * Y[k][j];
}
double x = -(A[0][0] / 2);
double y = -(A[1][0] / 2);
double r = pow(pow(x, 2) + pow(y, 2) - A[2][0], 0.5);
cout.setf(ios::fixed);
cout << "圆心坐标:(" << setprecision(2) << x << "," << setprecision(2) << y << ")" << endl;
cout << "半径:" << setprecision(2) << r << endl;
return 0;
}
void matrix_inverse(double(*a)[3], double(*b)[3]) // 矩阵求逆
{
using namespace std;
int i, j, k;
double max, temp;
// 定义一个临时矩阵t
double t[3][3];
// 将a矩阵临时存放在矩阵t[n][n]中
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
t[i][j] = a[i][j];
// 初始化B矩阵为单位矩阵
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
b[i][j] = (i == j) ? (double)1 : 0;
// 进行列主消元,找到每一列的主元
for (i = 0; i < 3; i++)
{
max = t[i][i];
// 用于记录每一列中的第几个元素为主元
k = i;
// 寻找每一列中的主元元素
for (j = i + 1; j < 3; j++)
{
if (fabs(t[j][i]) > fabs(max))
{
max = t[j][i];
k = j;
}
}
//cout<<"the max number is "<
// 如果主元所在的行不是第i行,则进行行交换
if (k != i)
{
// 进行行交换
for (j = 0; j < 3; j++)
{
temp = t[i][j];
t[i][j] = t[k][j];
t[k][j] = temp;
// 伴随矩阵B也要进行行交换
temp = b[i][j];
b[i][j] = b[k][j];
b[k][j] = temp;
}
}
if (t[i][i] == 0)
{
cout << "\nthe matrix does not exist inverse matrix\n";
break;
}
// 获取列主元素
temp = t[i][i];
// 将主元所在的行进行单位化处理
//cout<<"\nthe temp is "<
for (j = 0; j < 3; j++)
{
t[i][j] = t[i][j] / temp;
b[i][j] = b[i][j] / temp;
}
for (j = 0; j < 3; j++)
{
if (j != i)
{
temp = t[j][i];
//消去该列的其他元素
for (k = 0; k < 3; k++)
{
t[j][k] = t[j][k] - temp * t[i][k];
b[j][k] = b[j][k] - temp * b[i][k];
}
}
}
}
}