往期文章:
目录
前言:各位朋友们好,我是大脸猫。Halcon里面有关于拟合直线的方法有很多种,包括fit_line_contour_xld、hough_lines等算子,但这些算子都是基于轮廓和区域上去做的拟合。当给出一组数据的时候,我们可以利用矩阵去做数据拟合工作,也可以使用神经网络去做。
🚀🚀1.最小二乘法和MLP拟合直线曲线
1.1 矩阵拟合原理简单介绍
实际上,最小二乘法拟合的思想归根结底是:所有的点到拟合直线的距离最短,即误差的平方和最小。
以下是各点以y=kx+b的形式写出的方程:
那么转换为矩阵形式为:Y=Xβ+ε ,即:
1.2 最小二乘法拟合直线
在这里我们用一篇论文中的已知数据作为算例,为了方便复制已经作为代码形式放在下面:
*数据算例
Number := [1:25]
Y := [10.98,11.13,12.51,8.40,9.27,8.73,6.36,8.50,7.82,9.14,8.24,12.19,11.88,9.57,10.94,9.58,10.09,8.11,6.83,8.88,7.68,8.47,8.86,10.38,11.08]
X := [35.3,29.7,30.8,58.8,61.4,71.3,74.4,76.6,70.7,57.5,46.4,28.9,28.1,39.1,46.8,48.5,59.3,70.0,70.0,74.5,72.1,58.1,44.6,33.4,28.6]
☘️☘️算法如下:
**最小二乘法拟合直线
*现在将生成的点进行直线拟合:f(x) = a*x + b
*转化为: Ax = B
* A=[X, 1],
* x = [a, b]'
* B=f(x)
* 创建|X|行2列,值为1.0的矩阵
create_matrix (|X|, 2, 1, MatrixLineX)
set_value_matrix (MatrixLineX, [0:|X|-1], gen_tuple_const(|X|,0), X)
* 创建|x|行1列,值为y的矩阵
create_matrix (|X|, 1, Y, MatrixLineY)
*X^T*X*A=X^T*Y
mult_matrix (MatrixLineX, MatrixLineX, 'ATB', MatrixLineXTX)
*A=inv(X^T*X)*X^T*Y
invert_matrix (MatrixLineXTX, 'general', 0, MatrixLineInvXTX)
mult_matrix (MatrixLineX, MatrixLineY, 'ATB', MatrixLineXTY)
mult_matrix (MatrixLineInvXTX, MatrixLineXTY, 'AB', MatrixLinekb)
*选择k和b
get_value_matrix (MatrixLinekb, 0, 0, k)
get_value_matrix (MatrixLinekb, 1, 0, b)
Fit := k*X + b
⭐⭐分析:
① 算例的k值实际为-0.0799231779033084,b值实际为13.6284394650024,使用以上代码算出结果为k=-0.0799232,b=13.6284,因此最小二乘法使用矩阵形式拟合直线是可行的。
② 代码里面的操作实际是代入|x|行1列,值为y的矩阵,并求他的逆矩阵,得出kb矩阵,矩阵的第一行就是k值,第二行就是b值。
③ 实际上Halcon的fit_line_contour_xld('‘regression’')就是标准的最小二乘法拟合,跟这里讨论的最小二乘法矩阵拟合效果是一样的。
1.3 最小二乘法拟合曲线
在了解到如何使用矩阵去拟合直线之后,我们将这个思想应用在拟合曲线也是可行的,以下是拿多元多次曲线为例,我们用某化学反应里,测得生成物浓度y(%)与时间t(min)的数据作为算例,为了方便复制已经作为代码形式放在下面:
*数据算例
Y := [4,6.4,8,8.8,9.22,9.5,9.7,9.86,10,10.2,10.32,10.42,10.5,10.55,10.58,10.6]
X := [1:16]
☘️☘️算法如下:
*三元分别赋值X
X1 := X
X2 := X
X3 := X
**最小二乘法拟合三次曲线
*现在将生成的点进行二次曲线拟合:f(x) = a*x^3/3! + b*x^2/2! + c*x + d
*转化为: Ax = B
* A=[X^3, X^2, X, 1],
* x = [a, b, c, d]'
* B=f(x)
* 创建1行|X1|列,值为X1^3的矩阵
create_matrix (|X1|, 1, X1*X1*X1/3*2*1, Mat_X1)
* 创建1行|X2|列,值为X2^2的矩阵
create_matrix (|X2|, 1, X2*X2/2*1, Mat_X2)
* 创建1行|X3|列,值为X3的矩阵
create_matrix (|X3|, 1, X3, Mat_X3)
* 创建1行|X3|列,值为1的矩阵
create_matrix (|X3|, 1, 1, Mat_B)
* 创建4行|X3|列,值为1的矩阵
create_matrix (|X3|, 4, 1, Mat_X)
* 创建|X1|行1列,值为Y的矩阵
create_matrix (|X1|, 1, Y, Mat_Y)
*填充
set_sub_matrix (Mat_X, Mat_X1, 0, 0)
set_sub_matrix (Mat_X, Mat_X2, 0, 1)
set_sub_matrix (Mat_X, Mat_X3, 0, 2)
set_sub_matrix (Mat_X, Mat_B, 0, 3)
* 解方程即可得到a,b,c的系数,记为矩阵MatrixX
solve_matrix (Mat_X, 'general', 0, Mat_Y, Mat_A)
*该函数是得到矩阵MatrixX中0行0列的值
get_value_matrix (Mat_A, 0, 0, a)
get_value_matrix (Mat_A, 1, 0, b)
get_value_matrix (Mat_A, 2, 0, c)
get_value_matrix (Mat_A, 3, 0, d)
*得到多项式的值
Fit1 := a*X1*X1*X1/3*2*1+b*X2*X2/2*1+c*X3+d
⭐⭐分析:
① 使用以上代码算出结果为a=0.0092942,c=2.17269,d=2.48031,且观察拟合结果图像可以得出:最小二乘法使用矩阵形式拟合曲线是可行的。
② 代码里面的操作跟直线拟合是一样的,分别代入|x|行1列,值为y的矩阵,并求他的逆矩阵,得出acd矩阵,矩阵的第一行就是a值,第二行就是c值,第三行就是d值
1.4 神经网络拟合直线曲线
先说出一个观点:回归≠拟合。回归是拟合的一种方法,拟合的概念更广泛,拟合包含回归,还包含插值和逼近。
我们还是使用以上的两组数据,在Halcon里面使用MLP回归去拟合,但Halcon的MLP回归是非线性的。
☘️☘️算法如下:
** 创建MLP
*拟合直线
create_class_mlp (1, 2, 1, 'linear', 'normalization', 0.9, 42, MLPHandle)
*拟合曲线
*create_class_mlp (1, 4, 1, 'linear', 'normalization', 0.9, 42, MLPHandle)
* 训练MLP.
for J := 0 to |X| - 1 by 1
add_sample_class_mlp (MLPHandle, real(X[J]), Y[J])
endfor
set_regularization_params_class_mlp (MLPHandle, 'weight_prior', 0.01)
train_class_mlp (MLPHandle, 500, 1, 0.001, Error, ErrorLog)
![]() |
![]() |
![]() |
![]() |
⭐⭐分析:
① 观察上面MLP拟合情况并对比最小二乘法拟合情况,我们得出:Halcon的MLP拟合使用的激活函数不是线性的,即使他的type写着是lines!
观察对比情况,在以上这些少量数据的表现,MLP拟合效果要比最小二乘法要好的多。因为MLP可以根据拟合效果,去调整改变神经元数量。但在实际应用的时候,谨防过拟合情况。