简介
之前做直线拟合时,自己写了一个利用最小二乘做直线拟合的程序,但是由于直线检测的误差比较大,拟合的效果并不好。个人不知道是什么原因,因此想尝试更改一下直线拟合的算法,后来找到了OpenCV中的fitline函数,也是一个距离最小化函数,它完全包含了最小二乘法。由于网上没有找到相关的与python有关的资源,这里总结如下。
1. 函数调用
python3中fitline函数的调用形式如下:
import cv2 output = cv2.fitLine(InputArray points, distType, param, reps, aeps)
参数定义:
a. 输入参数:
InputArray Points: 待拟合的直线的集合,必须是矩阵形式;
distType: 距离类型。fitline为距离最小化函数,拟合直线时,要使输入点到拟合直线的距离和最小化。这里的 距离的类型有以下几种:
param: 距离参数,跟所选的距离类型有关,值可以设置为0。
reps, aeps: 第5/6个参数用于表示拟合直线所需要的径向和角度精度,通常情况下两个值均被设定为1e-2.
b. 输出结果:
output : 对于二维直线,输出output为4维,前两维代表拟合出的直线的方向,后两位代表直线上的一点。(即通常说的点斜式直线)
备注:
函数说明部分参考C++中 cv:: fitLine()介绍。
2. 实例程序
功能: 实现几条直线的直线拟合,输出为拟合后直线点的斜率k和偏移b.
代码:
def Cal_kb_linear_fitline(data_line1): loc = [] # 坐标 for line in data_line1: x1, y1, x2, y2 = line[0] loc.append([x1,y1]) loc.append([x2,y2]) loc = np.array(loc) # loc 必须为矩阵形式,且表示[x,y]坐标 output = cv2.fitLine(loc, cv2.DIST_L2, 0, 0.01, 0.01) k = output[1] / output[0] b = output[3] - k[key] * output[2] return k,b
这里,data_line1 表示直线检测出的直线的数据。
若只是想实现几个点坐标的直线拟合,把第3-8行去掉并把参数输入改为loc即可。
3. RLS直线拟合(不用fitline函数)
简介中提过,在用fitline函数之前,实现了N条直线的最小二乘直线拟合,同样展示程序如下:
def Cal_kb_linear(data_line1): X_line,Y_line = XY_line2Classifier_line(data_line1) r = leastsq(residuals, [1, 0], args=(X_line, Y_line)) # scipy.optimize.leastsq k, b = r[0] # 最小二乘直线拟合的斜率和偏移 return k,b # 输出直线的X/Y坐标 def XY_line2Classifier_line(data_line1): X_line = [] # 存放分为同一类的直线的所有的x坐标 Y_line = [] # 存放分为同一类的直线的所有的y坐标 for line in data_line1: x1, y1, x2, y2 = line[0] X_line.append(x1), X_line.append(x2) Y_line.append(y1), Y_line.append(y2) X_line = np.array(X_line) Y_line = np.array(Y_line) return X_line,Y_line # 直线拟合残差计算 def residuals(p, x, y_): k, b = p return y_ - (k * x + b)
备注:
注意,这里是N条直线的直线拟合,拟合思路为提取N条直线的坐标点,然后进行点的直线拟合。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/207654.html原文链接:https://javaforall.net
