最小二乘法拟合圆——MATLAB和Qt-C++实现

本节Jungle尝试用最小二乘法来拟合圆,并用MATLAB和C++实现

1.理论知识

根据圆心(A,B)和半径R可确定平面上一个圆。平面上圆方程的通式为
这里写图片描述
其中
这里写图片描述
第一个圆的通式是关于a、b和c的线性方程。利用最小二乘法建立圆拟合的数学模型,求得参数a、b和c的值,再根据第二个方程组求出圆的实际参数A、B和R。
在原始测得的N(N≥3)组数据(xi,yi),(i=1,2,3,…,N)中,根据式通式和最小二乘法原理,需求目标函数
这里写图片描述
的最小值。将F(a,b,c)对a、b、c求偏导,令偏导等于零,得到极值点,得到
这里写图片描述
求解上述方程可得到a、b、c,结合式第二个方程组可得到圆的参数。

2.MATLAB实现

function [ p ] = Circle_Fitting( XZ )
N = size(XZ,1);
x = XZ(:,1);
z = XZ(:,2);
sum_X_Raw = 0;
sum_Z_Raw = 0;
sum_XSquare_Raw = 0;
sum_ZSquare_Raw = 0;
sum_XCube_Raw = 0;
sum_ZCube_Raw = 0;
sum_XZZ_Raw = 0;
sum_XZ_Raw = 0;
sum_XXZ_Raw = 0;

for i=1:N
    sum_X_Raw = sum_X_Raw+x(i);
    sum_Z_Raw = sum_Z_Raw+z(i);
    sum_XSquare_Raw = sum_XSquare_Raw+x(i)*x(i);
    sum_ZSquare_Raw = sum_ZSquare_Raw+z(i)*z(i);
    sum_XCube_Raw = sum_XCube_Raw+x(i)*x(i)*x(i);
    sum_ZCube_Raw = sum_ZCube_Raw+z(i)*z(i)*z(i);
    sum_XZ_Raw = sum_XZ_Raw+x(i)*z(i);
    sum_XZZ_Raw = sum_XZZ_Raw+x(i)*z(i)*z(i);
    sum_XXZ_Raw = sum_XXZ_Raw+x(i)*x(i)*z(i);
end
D = N*sum_XZ_Raw-sum_X_Raw*sum_Z_Raw;
C = N*sum_XSquare_Raw-sum_X_Raw*sum_X_Raw;
E = N*sum_XCube_Raw+N*sum_XZZ_Raw-(sum_XSquare_Raw+sum_ZSquare_Raw)*sum_X_Raw;
G = N*sum_ZSquare_Raw-sum_Z_Raw*sum_Z_Raw;
H = N*sum_ZCube_Raw+N*sum_XXZ_Raw-(sum_XSquare_Raw+sum_ZSquare_Raw)*sum_Z_Raw;

a = (H*D-E*G)/(C*G-D*D);
b = (H*C-E*D)/(D*D-G*C);
c = -((sum_XSquare_Raw+sum_ZSquare_Raw)+a*sum_X_Raw+b*sum_Z_Raw)/N;

p(1) = -0.5*a;
p(2) = -0.5*b;
p(3) = 0.5*sqrt(a*a+b*b-4*c);
end

3.C++和Qt实现

同样,先定义一个数据结构Data,用于存放二维坐标、

#ifndef DATA
#define DATA
class Data
{
public:
	Data();
	Data(double ix = 0, double iy = 0):x(ix),y(iy){}
	~Data();

	double x;
	double y;
};
#endif //DATA

Jungle把拟合圆的方法以及相关参数封装为一个类CircleFitting和相关方法。类中用了Qt自带的数据结构QList,也可以用数组或者STL中的数据结构,如vector。

#ifndef CIRCLEFITTING_H
#define CIRCLEFITTING_H

#include 
#include 
#include "math.h"

class CircleFitting
{
public:
	CircleFitting(QList);
	~CircleFitting(void);

	///拟合椭圆
	void fittingData();
	QList getResultList();

private:
	///拟合椭圆的重要参数:圆心坐标(Xc,Yc),半径R
	double Xc;
	double Yc;
	double R;
	///拟合结果列表
	QListresultList;
	///原始数据集合
	QList PrimiDataSet;
};
#endif CIRCLEFITTING_H

实现

#include "CircleFitting.h"

CircleFitting::CircleFitting(QListidataset)
{
	this->PrimiDataSet.clear();
	this->resultList.clear();
	this->Xc = 0.00;
	this->Yc = 0.00;
	this->R = 0.00;
	for(int i=0;iPrimiDataSet<fittingData();
}

CircleFitting::~CircleFitting(void)
{
}

void CircleFitting::fittingData()
{
	////原始数据量
	int N = this->PrimiDataSet.size();
	////定义用于拟合的参数
	double D,C,E,G,H;
	////原始数据X点总和
	double sum_X_Raw = 0.00;
	////原始数据Z点总和
	double sum_Z_Raw = 0.00;
	////原始数据X的平方和
	double sum_XSquare_Raw = 0.00;
	////原始数据Z的平方和
	double sum_ZSquare_Raw = 0.00;
	////原始数据X的立方和
	double sum_XCube_Raw = 0.00;
	////原始数据Z的立方和
	double sum_ZCube_Raw = 0.00;
	////原始数据xzz和
	double sum_XZZ_Raw = 0.00;
	////原始数据xz和
	double sum_XZ_Raw = 0.00;
	////原始数据xxz和
	double sum_XXZ_Raw = 0.00;

	for(int i = 0;i < this->PrimiDataSet.size();i++)
	{
		sum_X_Raw += PrimiDataSet[i]->x;
		sum_Z_Raw += PrimiDataSet[i]->y;
		sum_XSquare_Raw += PrimiDataSet[i]->x*PrimiDataSet[i]->x;
		sum_ZSquare_Raw += PrimiDataSet[i]->y*PrimiDataSet[i]->y;
		sum_XCube_Raw += PrimiDataSet[i]->x*PrimiDataSet[i]->x*PrimiDataSet[i]->x;
		sum_ZCube_Raw += PrimiDataSet[i]->y*PrimiDataSet[i]->y*PrimiDataSet[i]->y;
		sum_XZ_Raw +=  PrimiDataSet[i]->x*PrimiDataSet[i]->y;
		sum_XZZ_Raw += PrimiDataSet[i]->x*PrimiDataSet[i]->y*PrimiDataSet[i]->y;
		sum_XXZ_Raw += PrimiDataSet[i]->x*PrimiDataSet[i]->x*PrimiDataSet[i]->y;
	}
	D = N*sum_XZ_Raw - sum_X_Raw*sum_Z_Raw;
	C = N*sum_XSquare_Raw-sum_X_Raw*sum_X_Raw;
	E = N*sum_XCube_Raw+N*sum_XZZ_Raw-(sum_XSquare_Raw+sum_ZSquare_Raw)*sum_X_Raw;
	G = N*sum_ZSquare_Raw-sum_Z_Raw*sum_Z_Raw;
	H = N*sum_ZCube_Raw+N*sum_XXZ_Raw-(sum_XSquare_Raw+sum_ZSquare_Raw)*sum_Z_Raw;

	double a = (H*D-E*G)/(C*G-D*D);
	double b = (H*C-E*D)/(D*D-G*C);
	double c = -((sum_XSquare_Raw+sum_ZSquare_Raw)+a*sum_X_Raw+b*sum_Z_Raw)/N;

	double A = -0.5*1.00000*a;
	double B = -0.5*1.00000*b;
	double R = 0.5*1.00000*sqrt(a*a+b*b-4*c);
	this->resultList<最小二乘法拟合圆——MATLAB和Qt-C++实现_第1张图片

你可能感兴趣的:(数据结构与算法,C++应用)