博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
思考: 从曲线中提取出近似直线的一段
阅读量:5882 次
发布时间:2019-06-19

本文共 2513 字,大约阅读时间需要 8 分钟。

        这个问题也是别人问我的, 我思考了一些时间, 希望抛砖引玉, 得到更好的方法.

        问题是这样的: 有一些离散的点, 在坐标系中把它们拟合成一条曲线, 其中有一段看上去很像是直线, 现在要求出这段"直线"的起始坐标和结束坐标, 并把这条线的方程求出来. 如下图:

2011082300583973.jpg

        从图中可以用肉眼看出标注的那一段近似一条直线, 问题是如果通过程序求出来.

我的想法

        我的想法是这样的, 假设这条线是存在的, 那么这条线里的点, 它们相邻两两之间Y之差应该是"相似"的, 具体相似要什么程度, 需要有一个"允许误差值". 在这个允许误差值下, 尽可能多的把这条曲线上连续的点拉拢到一条直线上, 最后根据这些点用就可以求得直线方程了.

获取这些连续的点:

static List
GetSequential(List
points, double allowLapse){ var resultList = new List
>(); var currentResult = new List
(); currentResult.Add(points[0]); for (int i = 1; i < points.Count; i++) { //如果这个点与前一个点的高度差在一个合理的范围内 if ((points[i].Y - points[i - 1].Y) < allowLapse) currentResult.Add(points[i]); else { resultList.Add(currentResult); currentResult = new List
(); currentResult.Add(points[i]); } } resultList.Add(currentResult); //从集合中选出点的数量最多的那组数据 List
result = resultList.OrderByDescending(list => list.Count).First(); return result;}

Point类的定义, 很简单:

internal class Point{    public double X { get; private set; }    public double Y { get; private set; }    public Point(double x, double y)    {        X = x; Y = y;    }}

根据一些点, 用最小二乘法求出直线:

static void LeastSquare(List
points){ double avgX = points.Average(point => point.X); double avgY = points.Average(point => point.Y); double numerator = points.Sum(point => (point.X - avgX) * (point.Y - avgY)); double denominator = points.Sum(point => (point.X - avgX) * (point.X - avgX)); double K = numerator / denominator; //斜率 double X0 = avgY - K * avgX; //为了方便测试, 我直接在这里输出结果 Console.WriteLine("Y={0} + {1}X\nStart ({2}, {3})\tEnd ({4}, {5})\nPoints Count: {6}", X0, K, points.First().X, points.First().Y, points.Last().X, points.Last().Y, points.Count);}

测试结果

允许Y差值 方程 起点 终点 包含点数
0.005 Y=0.27 + 0.45X (0.13, 0.328201) (0.15, 0.337173) 3
0.010 Y=0.25 + 0.60X (0.12, 0.318606) (0.17, 0.350823) 6
0.015 Y=0.48 + 1.08X (0.54, 1.060612) (0.77, 1.318348) 24
0.020 Y=0.23 + 1.46X (0.28, 0.611221) (0.77, 1.318348) 50
0.025 Y=0.22 + 1.48X (0.26, 0.56426) (0.77, 1.318348) 52
0.030 Y=0.13 + 1.64X (0.09, 0.255596) (0.77, 1.318348) 69
0.035 Y=0.13 + 1.64X (0.08, 0.222174) (0.77, 1.318348) 70
0.040 Y=0.12 + 1.65X (0.07, 0.183729) (0.77, 1.318348) 71

        对比文中开头的插图, 可以看出"允许Y差值"在0.020和0.025, 得到的数据还是比较靠谱的. 但这样的做法还有一点问题, 如果每个点都比前一个点高一点(在允许Y差值范围内), 等到点积累多了, 从整体看, 这些点组成的线就是一条向上的抛物线了, 那么这个算法就存在问题.

       如果您有什么想法, 欢迎交流, 附上(数据只含Y坐标值, X从0.0开始, 相邻两点X间隔0.01).

转载地址:http://pipix.baihongyu.com/

你可能感兴趣的文章
nginx的信号量
查看>>
云im php,网易云IM
查看>>
河南农业大学c语言平时作业答案,河南农业大学2004-2005学年第二学期《C语言程序设计》期末考试试卷(2份,有答案)...
查看>>
c语言打开alist文件,C语言 文件的打开与关闭详解及示例代码
查看>>
c语言 中的共用体和结构体如何联合定义,结构体(Struct)、联合体(Union)和位域
查看>>
SDL如何嵌入到QT中?!
查看>>
P1026 统计单词个数
查看>>
[js高手之路] html5 canvas系列教程 - 状态详解(save与restore)
查看>>
poi excel 常用api
查看>>
AD提高动态的方法(附SNR计算)
查看>>
[转]轻松实现可伸缩性,容错性,和负载平衡的大规模多人在线系统
查看>>
五 数组
查看>>
也谈跨域数据交互解决方案
查看>>
EntityFramework中使用Include可能带来的问题
查看>>
面试题28:字符串的排列
查看>>
css important
查看>>
WPF 实现窗体拖动
查看>>
来自维基百科程序员Brandon Harris
查看>>
NULL不是数值
查看>>
CentOS 5 全功能WWW服务器搭建全教程
查看>>