通过离散点拟合曲线

文章目录

    • 使用离散点拟合曲线
      • 参考代码路径:
      • 作者源码:
      • 测试代码
      • 效果图:
        • k=3
        • k=4
        • k=5

使用离散点拟合曲线

参考代码路径:

https://www.bragitoff.com/2015/09/c-program-for-polynomial-fit-least-squares/

https://gist.github.com/Thileban/272a67f2affdc14a5f69ad3220e5c24b

https://blog.csdn.net/jpc20144055069/article/details/103232641

作者源码:

//Polynomial Fit
#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
int main()
{
    int i,j,k,n,N;
    cout.precision(4);                        //set precision
    cout.setf(ios::fixed);
    cout<<"\nEnter the no. of data pairs to be entered:\n";        //To find the size of arrays that will store x,y, and z values
    cin>>N;
    double x[N],y[N];
    cout<<"\nEnter the x-axis values:\n";                //Input x-values
    for (i=0;i<N;i++)
        cin>>x[i];
    cout<<"\nEnter the y-axis values:\n";                //Input y-values
    for (i=0;i<N;i++)
        cin>>y[i];
    cout<<"\nWhat degree of Polynomial do you want to use for the fit?\n";
    cin>>n;                                // n is the degree of Polynomial 
    double X[2*n+1];                        //Array that will store the values of sigma(xi),sigma(xi^2),sigma(xi^3)....sigma(xi^2n)
    for (i=0;i<2*n+1;i++)
    {
        X[i]=0;
        for (j=0;j<N;j++)
            X[i]=X[i]+pow(x[j],i);        //consecutive positions of the array will store N,sigma(xi),sigma(xi^2),sigma(xi^3)....sigma(xi^2n)
    }
    double B[n+1][n+2],a[n+1];            //B is the Normal matrix(augmented) that will store the equations, 'a' is for value of the final coefficients
    for (i=0;i<=n;i++)
        for (j=0;j<=n;j++)
            B[i][j]=X[i+j];            //Build the Normal matrix by storing the corresponding coefficients at the right positions except the last column of the matrix
    double Y[n+1];                    //Array to store the values of sigma(yi),sigma(xi*yi),sigma(xi^2*yi)...sigma(xi^n*yi)
    for (i=0;i<n+1;i++)
    {    
        Y[i]=0;
        for (j=0;j<N;j++)
        Y[i]=Y[i]+pow(x[j],i)*y[j];        //consecutive positions will store sigma(yi),sigma(xi*yi),sigma(xi^2*yi)...sigma(xi^n*yi)
    }
    for (i=0;i<=n;i++)
        B[i][n+1]=Y[i];                //load the values of Y as the last column of B(Normal Matrix but augmented)
    n=n+1;                //n is made n+1 because the Gaussian Elimination part below was for n equations, but here n is the degree of polynomial and for n degree we get n+1 equations
    cout<<"\nThe Normal(Augmented Matrix) is as follows:\n";    
    for (i=0;i<n;i++)            //print the Normal-augmented matrix
    {
        for (j=0;j<=n;j++)
            cout<<B[i][j]<<setw(16);
        cout<<"\n";
    }    
    for (i=0;i<n;i++)                    //From now Gaussian Elimination starts(can be ignored) to solve the set of linear equations (Pivotisation)
        for (k=i+1;k<n;k++)
            if (B[i][i]<B[k][i])
                for (j=0;j<=n;j++)
                {
                    double temp=B[i][j];
                    B[i][j]=B[k][j];
                    B[k][j]=temp;
                }
    
    for (i=0;i<n-1;i++)            //loop to perform the gauss elimination
        for (k=i+1;k<n;k++)
            {
                double t=B[k][i]/B[i][i];
                for (j=0;j<=n;j++)
                    B[k][j]=B[k][j]-t*B[i][j];    //make the elements below the pivot elements equal to zero or elimnate the variables
            }
    for (i=n-1;i>=0;i--)                //back-substitution
    {                        //x is an array whose values correspond to the values of x,y,z..
        a[i]=B[i][n];                //make the variable to be calculated equal to the rhs of the last equation
        for (j=0;j<n;j++)
            if (j!=i)            //then subtract all the lhs values except the coefficient of the variable whose value                                   is being calculated
                a[i]=a[i]-B[i][j]*a[j];
        a[i]=a[i]/B[i][i];            //now finally divide the rhs by the coefficient of the variable to be calculated
    }
    cout<<"\nThe values of the coefficients are as follows:\n";
    for (i=0;i<n;i++)
        cout<<"x^"<<i<<"="<<a[i]<<endl;            // Print the values of x^0,x^1,x^2,x^3,....    
    cout<<"\nHence the fitted Polynomial is given by:\ny=";
    for (i=0;i<n;i++)
        cout<<" + ("<<a[i]<<")"<<"x^"<<i;
    cout<<"\n";
    return 0;
}//output attached as .jpg

测试代码

#include <iostream>
#include <iomanip>
#include <cmath>
#include <vector>
#include <numeric>



//第一种方式
QList<double> discrete_point_fitting_curve(std::vector<cv::Point2d> inPoints, int degreeOfPolynomial) {
	int numPoints = inPoints.size();
	std::vector<double> posXs;
	std::vector<double> posYs;
	for (int i = 0; i < numPoints; i++)
	{
		cv::Point2d tmpPoint = inPoints.at(i);
		posXs.push_back(tmpPoint.x);
		posYs.push_back(tmpPoint.y);
	}
	int k = degreeOfPolynomial; //多项式的次数
	//存储 sigma(xi),sigma(xi^2),sigma(xi^3)....sigma(xi^2n)
	std::vector<double> xValue(2 * k + 1);
	for (int i = 0; i < 2 * k + 1; i++)
	{
		xValue[i] = 0;
		for (int j = 0; j < numPoints; j++) {
			xValue[i] = xValue[i] + pow(posXs[j], i);
		}
	}
	//Normal matrix(augmented)
	std::vector<std::vector<double>> matrixNormal(k + 1, std::vector<double>(k + 2, 0));
	//保存参数方程的系数
	std::vector<double> finalParas(k + 1);
	for (int i = 0; i <= k; i++) {
		for (int j = 0; j <= k; j++) {
			matrixNormal[i][j] = xValue[i + j];
		}
	}
	//存储sigma(yi),sigma(xi*yi),sigma(xi^2*yi)…sigma(xi^n*yi)
	std::vector<double> yValue(k + 1);
	for (int i = 0; i < k + 1; i++)
	{
		yValue[i] = 0;
		for (int j = 0; j < numPoints; j++) {
			yValue[i] = yValue[i] + pow(posXs[j], i)*posYs[j];
		}
	}
	//加载yValue作为matrixNormal的最后一列(普通矩阵但增强)
	for (int i = 0; i <= k; i++) {
		matrixNormal[i][k + 1] = yValue[i];
	}
	//k变为n+1,因为下面的高斯消去部分是针对k个方程,但这里k是多项式的次数,对于k次我们得到k+1个方程
	k = k + 1;
	//高斯消元法求解线性方程组
	for (int i = 0; i < k; i++) {
		for (int n = i + 1; n < k; n++) {
			if (matrixNormal[i][i] < matrixNormal[n][i]) {
				for (int j = 0; j <= k; j++)
				{
					double temp = matrixNormal[i][j];
					matrixNormal[i][j] = matrixNormal[n][j];
					matrixNormal[n][j] = temp;
				}
			}
		}
	}
	//循环执行高斯消除
	for (int i = 0; i < k - 1; i++)
	{
		for (int n = i + 1; n < k; n++)
		{
			double t = matrixNormal[n][i] / matrixNormal[i][i];
			for (int j = 0; j <= k; j++) {
				//使主元元素下面的元素等于0或消除变量
				matrixNormal[n][j] = matrixNormal[n][j] - t * matrixNormal[i][j];
			}
		}
	}
	//回代
	//使要计算的变量等于最后一个方程的rhs,然后减去除正在计算的变量的系数之外的所有lhs值,现在最后将 rhs 除以要计算的变量的系数
	for (int i = k - 1; i >= 0; i--)
	{
		finalParas[i] = matrixNormal[i][k];
		for (int j = 0; j < k; j++) {
			if (j != i) {
				finalParas[i] = finalParas[i] - matrixNormal[i][j] * finalParas[j];
			}
		}
		finalParas[i] = finalParas[i] / matrixNormal[i][i];
	}
	QList<double> resParas;
	for (int i = 0; i < finalParas.size(); i++)
	{
		qDebug() << "1--final:" << i << finalParas[i];
		resParas.push_back(finalParas[i]);
	}
	return resParas;
}

//第二种方式--best
QList<double> polyfit(std::vector<cv::Point2d> &chain, int n)
{
	cv::Mat y(chain.size(), 1, CV_32F, cv::Scalar::all(0));
	/* ********【预声明phy超定矩阵】************************/
	/* 多项式拟合的函数为多项幂函数
	* f(x)=a0+a1*x+a2*x^2+a3*x^3+......+an*x^n
	*a0、a1、a2......an是幂系数,也是拟合所求的未知量。设有m个抽样点,则:
	* 超定矩阵phy=1 x1 x1^2 ... ...  x1^n
	*           1 x2 x2^2 ... ...  x2^n
	*           1 x3 x3^2 ... ...  x3^n
	*              ... ... ... ...
	*              ... ... ... ...
	*           1 xm xm^2 ... ...  xm^n
	*  ΦT∗Φ∗a=ΦT∗y
	* *************************************************/
	cv::Mat phy(chain.size(), n, CV_32F, cv::Scalar::all(0));
	for (int i = 0; i < phy.rows; i++)
	{
		float* pr = phy.ptr<float>(i);
		for (int j = 0; j < phy.cols; j++)
		{
			pr[j] = pow(chain[i].x, j);
		}
		y.at<float>(i) = chain[i].y;
	}
	cv::Mat phy_t = phy.t();
	cv::Mat phyMULphy_t = phy.t()*phy;
	cv::Mat phyMphyInv = phyMULphy_t.inv();
	cv::Mat a = phyMphyInv * phy_t;
	a = a * y;
	qDebug() << a.rows << a.cols;
	std::cout << "res a = " << a << ";" << std::endl << std::endl;
	QList<double> resParas;
	for (int i = 0; i < a.rows; i++)
	{
		qDebug() << "2--final:" << i << a.at<float>(i,0);
		resParas.push_back(a.at<float>(i, 0));
	}
	return resParas;
}

//第三种方式  最小二乘曲线拟合
//x[n]       存放给定数据点的X坐标。
//y[n]       存放给定数据点的Y坐标。
//n          给定数据点的个数。
//a[m]       返回m - 1次拟合多项式的系数。
//m          拟合多项式的项数。要求m<=min(n,20)。
//dt[3]      分别返回误差平方和,误差绝对值之和与误差绝对值的最大值。
//void pir1(double x[], double y[], int n, double a[], int m, double dt[])
QList<double> least_squares_curve_fitting(std::vector<cv::Point2d> &inPoins, int m)
{
	double dt[3] = { 0.0 };
	int n = inPoins.size();
	std::vector<double> a(m);
	std::vector<double> x;
	std::vector<double> y;
	for (int i = 0; i < n; i++)
	{
		cv::Point2d tmpPoint = inPoins.at(i);
		x.push_back(tmpPoint.x);
		y.push_back(tmpPoint.y);
	}

	int i, j, k;
	double p, c, g, q, d1, d2, s[20], t[20], b[20];
	for (i = 0; i <= m - 1; i++) a[i] = 0.0;
	if (m > n) m = n;
	if (m > 20) m = 20;
	b[0] = 1.0; d1 = 1.0*n; p = 0.0; c = 0.0;
	for (i = 0; i <= n - 1; i++)
	{
		p = p + x[i]; c = c + y[i];
	}
	c = c / d1; p = p / d1;
	a[0] = c * b[0];
	if (m > 1)
	{
		t[1] = 1.0; t[0] = -p;
		d2 = 0.0; c = 0.0; g = 0.0;
		for (i = 0; i <= n - 1; i++)
		{
			q = x[i] - p; d2 = d2 + q * q;
			c = c + y[i] * q;
			g = g + x[i] * q*q;
		}
		c = c / d2; p = g / d2; q = d2 / d1;
		d1 = d2;
		a[1] = c * t[1]; a[0] = c * t[0] + a[0];
	}
	for (j = 2; j <= m - 1; j++)
	{
		s[j] = t[j - 1];
		s[j - 1] = -p * t[j - 1] + t[j - 2];
		if (j >= 3)
			for (k = j - 2; k >= 1; k--)
				s[k] = -p * t[k] + t[k - 1] - q * b[k];
		s[0] = -p * t[0] - q * b[0];
		d2 = 0.0; c = 0.0; g = 0.0;
		for (i = 0; i <= n - 1; i++)
		{
			q = s[j];
			for (k = j - 1; k >= 0; k--)  q = q * x[i] + s[k];
			d2 = d2 + q * q; c = c + y[i] * q;
			g = g + x[i] * q*q;
		}
		c = c / d2; p = g / d2; q = d2 / d1;
		d1 = d2;
		a[j] = c * s[j]; t[j] = s[j];
		for (k = j - 1; k >= 0; k--)
		{
			a[k] = c * s[k] + a[k];
			b[k] = t[k]; t[k] = s[k];
		}
	}
	dt[0] = 0.0; dt[1] = 0.0; dt[2] = 0.0;
	for (i = 0; i <= n - 1; i++)
	{
		q = a[m - 1];
		for (k = m - 2; k >= 0; k--) q = a[k] + q * x[i];
		p = q - y[i];
		if (fabs(p) > dt[2]) dt[2] = fabs(p);
		dt[0] = dt[0] + p * p;
		dt[1] = dt[1] + fabs(p);
	}

	QList<double> resParas;
	for (int i = 0; i < m; i++)
	{
		qDebug() << "3--final:" << i << a[i];
		resParas.push_back(a[i]);
	}
	return resParas;
}


// 测试程序
void curveFit() {
	std::vector<cv::Point2d> inPoints;
	inPoints.push_back(cv::Point2d(34, 36));
	inPoints.push_back(cv::Point2d(50, 82));
	inPoints.push_back(cv::Point2d(74, 142));
	inPoints.push_back(cv::Point2d(100, 200));
	inPoints.push_back(cv::Point2d(123, 242));
	inPoints.push_back(cv::Point2d(160, 281));
	inPoints.push_back(cv::Point2d(215, 236));
	inPoints.push_back(cv::Point2d(250, 150));
	inPoints.push_back(cv::Point2d(300, 84));
	inPoints.push_back(cv::Point2d(367, 74));
	inPoints.push_back(cv::Point2d(403, 139));
	inPoints.push_back(cv::Point2d(442, 550));
	inPoints.push_back(cv::Point2d(481, 300));

	QList<double> resParas3 = least_squares_curve_fitting(inPoints, 5);
	QList<double> resParas2 = polyfit(inPoints, 5);
	QList<double> resParas = discrete_point_fitting_curve(inPoints, 4);
	qDebug() << "resParas size:" << resParas;
	std::vector<cv::Point2d> newPoints;
	for (int i = 0; i < 500; i++)
	{
		double newY = 0;
		for (int j = 0; j < resParas.size(); j++)
		{
			newY += resParas.at(j) * pow(i, j);
		}
		newPoints.push_back(cv::Point(i, newY));
		newY = 0;
	}

	cv::Mat whiteImage = cv::Mat::zeros(500, 500, CV_8UC3);
	for (size_t i = 0; i < inPoints.size(); i++) {
		cv::circle(whiteImage, inPoints[i], 5.0, cv::Scalar(0, 0, 255), -1);
	}
	for (size_t i = 0; i < newPoints.size() - 1; i++) {
		cv::line(whiteImage, newPoints[i], newPoints[i + 1], cv::Scalar(0, 255, 255), 2, cv::LINE_AA);
	}

	//cv::imwrite("whiteImage.png", whiteImage);

	cv::namedWindow("curveFit");
	cv::imshow("curveFit", whiteImage);
	cv::waitKey(0);

}

效果图:

k=3

在这里插入图片描述

k=4

在这里插入图片描述

k=5

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/321886.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PID横向控制和仿真实现

文章目录 1. PID介绍2. PID横向控制原理3. 算法和仿真实现 1. PID介绍 PID是一种常见的控制算法&#xff0c;全称为Proportional-Integral-Derivative&#xff0c;即比例-积分-微分控制器。PID控制器是一种线性控制器&#xff0c;它将设定值与实际值进行比较&#xff0c;根据误…

基于51单片机的模拟量输入输出通道实验

实验一 模拟量输入输出通道实验&#xff08;C51&#xff09; 一、实验目的&#xff1a; 1、了解A/D、D/A转换的基本原理。 2、了解A/D转换芯片ADC0809、D/A转换芯片DAC0832的性能及编程方法。 3、掌握过程通道中A/D转换与D/A转换与计算机的接口方法。 4、了解计算机如何进…

VSCode 正则表达式 匹配多行

VS Code 正则表达式匹配多行 (.|\n)*? //test.js const test {str: VS Code 正则表达式匹配多行VS Code 正则表达式匹配多行VS Code 正则表达式匹配多行VS Code 正则表达式匹配多行VS Code 正则表达式匹配多行VS Code 正则表达式匹配多行VS Code 正则表达式匹配多行VS Code …

数据库作业二

一&#xff0c;单表查询 1.创建表 1、显示所有职工的基本信息。 2、查询所有职工所属部门的部门号&#xff0c;不显示重复的部门号。 3、求出所有职工的人数。 4、列出最高工和最低工资。 5、列出职工的平均工资和总工资。 6、创建一个只有职工号、姓名和参加工作的…

【WPF.NET开发】WPF中的版式

本文内容 改进的文本质量和性能丰富的版式增强的国际文本支持增强的字体支持新的文本应用程序编程接口 (API) 本主题介绍 WPF 的主要版式功能。 这些功能包括改进的文本呈现质量和性能、OpenType 版式支持、增强的国际文本、增强的字体支持和新的文本应用程序编程接口 (API)。…

2024多系统萎缩最新全球特效药治疗进展

多系统萎缩是一种罕见的神经退行性疾病&#xff0c;由于缺乏有效的治疗方法&#xff0c;患者经常面临症状无法缓解和生活品质下降的困扰。然而&#xff0c;近期刘家峰大夫基于中医理论研究和临床实践&#xff0c;采用中药治疗多系统萎缩取得了显著疗效&#xff0c;给患者带来了…

VUE好看的个人简历模板

文章目录 1.设计来源1.1 首页界面1.2 关于我界面1.3 我的资历界面1.4 项目经验界面1.5 我的技能界面1.6 联系我界面 2.效果和源码2.1 动态效果2.2 源码目录结构 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/…

RMI简介

RMI 介绍 RMI (Remote Method Invocation) 模型是一种分布式对象应用&#xff0c;使用 RMI 技术可以使一个 JVM 中的对象&#xff0c;调用另一个 JVM 中的对象方法并获取调用结果。这里的另一个 JVM 可以在同一台计算机也可以是远程计算机。因此&#xff0c;RMI 意味着需要一个…

线程安全2

文章目录 锁的可重入性死锁内存可见性引起的线程安全 锁的可重入性 直观来看这个代码不能运行 为啥没有出现阻塞&#xff1f; 当前由于是同一个线程&#xff0c;此时的锁对象&#xff0c;就知道了第二次加锁的线程&#xff0c;就是持有锁的线程&#xff0c;第二次操作&#xff…

Linux下如何快速调试I2C设备

Linux下如何快速调试I2C设备 目录 1 什么场景下需要快速调试I2C设备 2 如何快速调试I2C设备 3 如何获取I2C Tools工具集 3.1 获取I2C Tools工具集源码 3.2 编译I2C Tools工具集源码 3.3 为设备添加I2C Tools工具集 4 如何使用I2C Tools工具集 5 小结 1 什么场景下需要快…

VScode设置自动添加自定义注释及修改字体

首先安装snippet mac可以键入commanp&#xff0c;输出> 选择自己所需的需要自动添加的文件类型配置文件 安装自己的需要修改 "Print to console": {"prefix": "xx", // 自己键入内容"body": [ // 注释信息"// xxx …

SpringMVC RESTful案例

文章目录 1、准备工作2、功能清单3、具体功能&#xff1a;访问首页a>配置view-controllerb>创建页面 4、具体功能&#xff1a;查询所有员工数据a>控制器方法b>创建employee_list.html 5、具体功能&#xff1a;删除a>创建处理delete请求方式的表单b>删除超链接…

docker部署私人云盘nextcloud

首先查看效果 1.拉取镜像 docker pull nextcloud 2.创建目录 mkdir -p /data/nextcloud/{config,data,apps} 3.创建实例 docker run -itd --name yznextcloud -v /data/nextcloud/config:/var/www/html/config -v /data/nextcloud/data:/var/www/html/data -v /data/nextc…

Minikube安装

文章目录 简介安装仪表盘 简介 Minikube是一个轻量级的工具&#xff0c;用于在本地机器上运行K8s集群。它允许开发人员在没有云环境的情况下进行K8s应用程序的开发和测试。 和k8s需要一个主机两个从机不同&#xff0c;Minikube用kubectl来控制节点&#xff0c;相当于在虚拟机…

如何制作网址链接活码?网址二维码生成器的使用方法

将网址转二维码图片来使用&#xff0c;是现在很常用的一种二维码类型&#xff0c;一般网址可以根据自己的用途来制作静态码或者活码两种形式。其中静态码只是单纯将网址链接转换成二维码&#xff0c;无法统计与修改&#xff0c;而生成网址活码可以在二维码图片不变情况下替换其…

基于RNN的模型

文本数据是一种典型的具有序列结构的数据&#xff0c;因为文本通常是由一系列的词语或字符组成的序列。每个词语或字符在文本中都有特定的位置和顺序&#xff0c;这种有序的结构对于理解和处理文本的含义至关重要。因此&#xff0c;多数情况下需要使用时间序列建模来完成相应的…

按键精灵调用奥迦插件实现图色字识别模拟键鼠操作源码

奥迦插件于2019年9月开始开发,在Windows 10操作系统上使用Visual Studio 2019编写,适用于所有较新的Windows平台,是一款集网络验证,深度学习,内核,视觉,文字,图色,后台,键鼠,窗口,内存,汇编,进程,文件,网络,系统,算法及其它功能于一身的综合插件 插件使用C语言和COM技术编写,是…

C#编程-属性和反射

属性和反射 属性是将元数据信息和行为添加到应用程序代码中的简单技术。属性是允许您将声明信息添加到程序的元素。此声明信息在运行时用途广泛,可使用应用程序开发工具在设计时使用。 介绍属性 对象是由其属性值描述的。例如,汽车可以使用它的构造、型号或颜色来描述。类似…

解决方案类常用网址

1.操作系统类&#xff08;原版操作系统下载网址&#xff09; https://next.itellyou.cn/ 之前的版本 https://msdn.itellyou.cn/ 2.ppt免费网站&#xff08;不用注册&#xff09; https://www.1ppt.com/