使用自制CtlPointsCurve.dll组件实现样条曲线拟合

博客围绕数据采集重绘处理中的曲线生成方法展开。先介绍两点一线法及其问题,引出样条曲线计算方法。重点讲述在VB里实现曲线拟合,借助ATL编写ACTIVEX COM DLL封装计算方法供VB调用,还说明了使用CtlPointsCurve.dll的具体步骤及相关API和变量定义。

对于现在数据采集重绘处理,很多情况下都用到了曲线重绘,而曲线生成的方法也有多种 

最简单的一种就是两点一线法,简单来说就是对每个采集点做直线连接,使到其趋向一曲线,这种方法的好处是保证数据的真实性,但同时也引申出很多问题.首先,采集点必须要足够多,否则的话就成了线段组,而并非曲线了,这样对于一些无法多点采集的技术领域,或者采集成本很高的技术领域来说,便无法满足其分析需求了.因此,产生了样条曲线的计算方法.

样条曲线的计算法则中,最复杂的可以算是B样条多次曲线拟合,其思路是在当前采样点的前提下,根据其计算公式,推算出对于采样点符合条件的曲线目标点,然后再在目标点间连线.这样就可以在采样点少的情况下,画出趋向曲线的点了.

 

理论的东西就说那么多,至于计算法则,我相信数学书上比我写的要详细很多,接下来就介绍在程序里面的实现,特别是VB里面的实现.

 

关于曲线拟合的VC代码,网络上面已经可以找到很多,推荐大家可以到codeguru里面找找,有位Tom Chan的控制点曲线计算(Control Point Curve)的类已经封装得很好了,特别对于不关心具体算法的用户可以放心使用,而至于VB上面实现的代码,到目前为止在下还没有找到.于是引申自己编写的念头.

在实现过程中,发觉VB对数的处理能力,特别是数组的处理能力实在不敢恭维(是因为VB里面的数组都为SALFARRAY的原因吧).

于是想到可以借助Tom Chan的计算类来实现.首先使用ATL编写ACTIVEX COM DLL,DLL里封装了Tom Chan的计算方法,然后给予VB接口的调用,这样不但可以加快运算的速度,也可以减低VB做算法的负担.(要知道,如果用VB里面的安全数组来做算法的话,对CPU实在是一种浪费)

下图为在下的程序演示:

 

 

至于该组件--CtlPointsCurve.dll ,可以Email给在下(Xeden3@hotmail.com).

 

现在,我们具体看看如何使用这个CtlPointsCurve.dll.

 

首先,我们必须要给一个画线的空间给他,当然,PICTUREBOX是最好的选择。

然后我们定义两个按键,一个用于绘出曲线,一个清空,以便重新绘制。


 

Private Declare Function Polyline Lib "gdi32" (ByVal hdc As Long, lpPoint As POINTAPI, ByVal nCount As Long) As Long

Private Declare Function Ellipse Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long



定义两个
API Ellipse()用于在PICTUREBOX绘制鼠标点击的采样点,Polyline()用于画出最后目标点连线。



Dim ctlPointCurveMathMaker As New CTLPOINTSCURVELib.CtlPointsCurveMath

Dim posSrc(5000) As CTLPOINTSCURVELib.Point

Private Type POINTAPI

X As Long

Y As Long

End Type



ctlPointCurveMathMaker
对象,作为计算样条曲线用。

posSrc定义最大的采样点,内部结构与POINTAPI相同,现在设定的最大采样值是5000点。POINTAPI 结构,用于表示2D坐标。

m_Count当前采样点数。



由于样条计算是在
CTLPOINTSCURVELib.CtlPointsCurveMath内部进行,所以必须把API2D坐标结构POINTAPI转化到CTLPOINTSCURVELib.Point内,同样,生成目标点的坐标也要转换到API2D坐标结构POINTAPI以便绘制。

 


Private Sub cmdClear_Click()

Picture1.Cls
m_Count = 0

End Sub



清空



Private Sub Picture1_MouseDown(Buton As Integer, Shift As Integer, X As Single, Y As Single)

Picture1.ForeColor = vbBlue
posSrc(m_Count).pixX = X
posSrc(m_Count).pixY = Y
m_Count = m_Count + 1
Ellipse Picture1.hdc, X, Y, X + 5, Y + 5
Picture1.Refresh

End Sub



当鼠标点击Picture1后,把鼠标当前坐标作为采样点赋值到posSrc(m_Count)内,并且绘制一个半径为5pixel的圆。



Private Sub cmdRun_Click()

Dim posDest() As CTLPOINTSCURVELib.Point
Dim ptAPI() As POINTAPI

Dim ptCount As Long
ctlPointCurveMathMaker.InputCtlPoints m_Count, posSrc(0)
ctlPointCurveMathMaker.Generate
ptCount = ctlPointCurveMathMaker.GetCurveCount
ReDim posDest(ptCount - 1)
ReDim ptAPI(ptCount - 1)
ctlPointCurveMathMaker.GetCurve ptCount, posDest(0)
For i = 0 To ptCount - 1
   ptAPI(i).X = posDest(i).pixX
   ptAPI(i).Y = posDest(i).pixY
Next i
Picture1.ForeColor = vbRed
Polyline Picture1.hdc, ptAPI(0), ptCount
Picture1.Refresh

 End Sub



Dim posDest() As CTLPOINTSCURVELib.Point
定义生成的目标点的坐标。

Dim ptAPI() As POINTAPI 当然,这个就是把posDest转化过来,用于绘制曲线用的。ctlPointCurveMathMaker.InputCtlPoints m_Count, posSrc(0) 入采样点,m_Count为采样数。posSrc(0)为采样点。

 

ctlPointCurveMathMaker.Generate 开始计算样条曲线。

ptCount = ctlPointCurveMathMaker.GetCurveCount 获取目标点数目。

ReDim posDest(ptCount - 1)

ReDim ptAPI(ptCount - 1)

 

好了,我们现在根据得到的ptCount,重新定义posDestptAPI的大小。

ctlPointCurveMathMaker.GetCurve ptCount, posDest(0) 读取目标点。

 

For i = 0 To ptCount - 1

    ptAPI(i).X = posDest(i).pixX
    ptAPI(i).Y = posDest(i).pixY
Next i

把目标点转化到ptAPI里面,然后调用Polyline Picture1.hdc, ptAPI(0), ptCount绘制出来。

 

Picture1内容,也把当前采样点数m_Count0
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值