首页 > 其他分享 >.NET 白板书写预测-曲线拟合

.NET 白板书写预测-曲线拟合

时间:2024-10-10 20:34:41浏览次数:8  
标签:曲线拟合 预测 parameters Point int 书写 白板 var NET

白板软件书写速度是其最核心的功能,注册StylusPlugin从触摸线程拿触摸点数据并在另一UI线程绘制渲染是比较稳妥的方案,具体的可以查看小伙伴德熙的2019-1-28-WPF-高性能笔 - lindexi - 博客园 (cnblogs.com)

上面StylusPlugin方案能提升在大屏目前如富创通、华欣触摸框的主要产品版本上,1帧16ms左右的书写性能。除了这个跳过一些流程来减少延时,我们还能继续优化书写性能么?答案肯定是可以的

本文我们介绍下书写加速的一类实现方向,通过预测下一个甚至N个点,提前绘制笔迹来降低书写延迟。

曲线拟合预测

书写预测,这里介绍下曲线拟合的方案:

取N个点拟合成一条曲线,算出它的曲线公式,然后下一个点可以输入它的X位置得到Y -- 以X方法或者Y方法为基准,拟合出以X为参数的曲线。

我们来试试,这里采用的是开源组件MathNet.Numerics,先安装其Nuget包MathNet.Numerics:

<PackageReference Include="MathNet.Numerics" Version="5.0.0" />

引用using MathNet.Numerics;我们以X坐标为基准预测Y坐标值,已经写好函数:

 1     private static Point[] PredictPointsNormal(Point[] pointArray, int degree, int predictCount)
 2     {
 3         Debug.WriteLine("输入:" + string.Join(",", pointArray.Select(i => $"({i.X},{i.Y})")));
 4         var xList = pointArray.Select(i => i.X).ToArray();
 5         var yList = pointArray.Select(i => i.Y).ToArray();
 6         var lastX = xList[xList.Length - 1];
 7         var lastX1 = xList[xList.Length - 2];
 8         var lastPointLength = lastX - lastX1;
 9         double[] parameters = Fit.Polynomial(xList, yList, degree);
10         var predictPoints = new Point[predictCount];
11         for (int i = 0; i < predictCount; i++)
12         {
13             var currentX = lastX + (i + 1) * lastPointLength;
14             var currentY = 0d;
15             for (int j = 0; j < degree + 1; j++)
16             {
17                 var parameterJ = parameters[j];
18                 for (int k = 0; k < j; k++)
19                 {
20                     parameterJ *= currentX;
21                 }
22 
23                 currentY += parameterJ;
24             }
25 
26             var newPoint = new Point(currentX, currentY);
27             predictPoints[i] = newPoint;
28         }
29         Debug.WriteLine("输出:" + string.Join(",", predictPoints.Select(i => $"({i.X},{i.Y})")));
30         return predictPoints;
31     }

这里的double[] parameters = Fit.Polynomial(xList, yList, degree),表示通过X以及Y系列数据,以阶数degree(如二阶曲线)计算出当前多项式参数值parameters。

如果degree是2阶,可以计算得到y值:

y = parameters[0] + parameters[1]*x + parameters[2]*x^2

如果是Y轴向上递增的二队曲线,如下图,从左到右绿色点是已知点列表,黄色为预测的点。这里我们依次预测4个点:

这类场景,预测结果是比较正常的。

我们再看看抛物线的场景,沿X方向Y坐标值依次递减,即顺时针角度值增加,预测点如下:

从上图可以看出,Y方向值递减时预测结果是抛物线的另一半,Y轴值另一侧反向加速递减。但我们的期望肯定不是像这类抛物线,我们期望它能延着绿色轨迹向斜上方走。

为何它会快速弹回来呢?原因就是拟合的2阶曲线,公式如此。

这类方法,只能做到一维的预测,即遇到X、Y方向值不变或者值变化较少时,曲线变化就会像抛物线一样到达它的顶端后,就会快速弹回来。

以拟合成曲线公式来计算,会有一定缺陷。这个我们也是能优化的,上方的函数里我们是以X轴为基准,得到的公式中X为变化量,下面换一下以Y轴为基准:

 1     public static Point[] PredictPointsNormalY(Point[] pointArray, int degree, int predictCount)
 2     {
 3         Debug.WriteLine("输入:" + string.Join(",", pointArray.Select(i => $"({i.X},{i.Y})")));
 4         var xList = pointArray.Select(i => i.X).ToArray();
 5         var yList = pointArray.Select(i => i.Y).ToArray();
 6         var lastY = yList[yList.Length - 1];
 7         var lastY1 = yList[yList.Length - 2];
 8         var lastPointLength = lastY - lastY1;
 9         double[] parameters = Fit.Polynomial(yList, xList, degree);
10         var predictPoints = new Point[predictCount];
11         for (int i = 0; i < predictCount; i++)
12         {
13             var currentY = lastY + (i + 1) * lastPointLength;
14             var currentX = 0d;
15             for (int j = 0; j < degree + 1; j++)
16             {
17                 var parameterJ = parameters[j];
18                 for (int k = 0; k < j; k++)
19                 {
20                     parameterJ *= currentY;
21                 }
22 
23                 currentX += parameterJ;
24             }
25 
26             var newPoint = new Point(currentX, currentY);
27             predictPoints[i] = newPoint;
28         }
29         Debug.WriteLine("输出:" + string.Join(",", predictPoints.Select(i => $"({i.X},{i.Y})")));
30         return predictPoints;
31     }

这里的二阶拟合曲线就变成了:

x = parameters[0] + parameters[1]*y + parameters[2]*y^2

同样预测4个点,看下结果:

这个预测趋势就符合我们的期望了。

所以上方X方向以及Y方向分别为基准,拟合二队曲线,然后输出预测点,我们综合取一个比较适合的点即可。

如何取呢?可以看到我们期望的点是变化趋势变化小的一个。即以最后俩个数据点的角度A为基准,预测点与最后数据点的向量角度B1与B2,顺时针角度变化较小的点是我们期望输出的。

曲线拟合其它问题

上面我们解决了坐标点场景,单方向拟合时输出点快速弹回的问题。在验证书写时,我们还发现一类预测失准问题:

如上图,黄色点往上偏了(黄色点是直线,并且角度不符合原有趋势),真实期望我们是想要沿着原有角度减少的趋势,预测点为角度略偏下的方向:

这里预测失准的原因是,X方向值无法正常预测。因为按我们上面曲线拟合的方案,这类抛物线场景是以Y轴为基准,输入Y得到X方向值,但按曲线变化的方向输入一个最后俩点之间Y轴变化量,预测点的X值应该是接近无限大的,超出了曲线范围。

这里可以根据曲线点角度变化量来处理,看上图点与点之间角度是按顺时针依次增加的,所以预测出来的点也应该要继续顺时针增加角度。所以可以将输出的点按最后俩点Point(n)、Point(n-1)之间向量角度值,或者再增加最后三点之间角度的差值angleChange。

我使用的是增加角度变化量,如下图输出效果:

最后,我们按上面的方案验证下真实书写预测的效果。输出书写痕迹,我们换个颜色,蓝色为真实点、红色为预测点。

预测1个点,红色与真实书写曲线重合:

预测2个点,红色是第一个预测点,粉色是第二个预测点。粉色点偏移的较多:

这里预测效果是在我的开发触摸屏设备(Dell P2418HT,1080p)上验证的。

需要注意的是,书写预测与屏幕报点率(帧率)强相关。一般情况下,输出俩点之间间隔时间越长,俩点之间间距越大,预测点的误差也会变大,但相应的预测距离变远了即书写延迟会降低很大。

我这Dell触摸屏触摸移动时,输入平均间隔33.3ms,一次输入包含2-3个点,点平均间隔在16.6ms。俩点平均间隔16.6ms,说明触摸框是60fps报点。另外,详细的触摸框报点率数据以及开启WM_POINTER消息提升应用层的触摸输入帧率可以看下:白板书写延迟-触摸屏报点率 - 唐宋元明清2188 - 博客园 (cnblogs.com)

根据上面触摸报点数据,上面书写预测方案预测1个点,在这台Dell触摸屏上书写延迟可以降低16ms左右。

标签:曲线拟合,预测,parameters,Point,int,书写,白板,var,NET
From: https://www.cnblogs.com/kybs0/p/18442316

相关文章

  • .Net微信服务商平台ApiV3接口
    转载:https://www.cnblogs.com/xilen/p/15380183.html开始在开始之前建议仔细读微信官方文档,接口规则及api文档https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay-1.shtmlhttps://pay.weixin.qq.com/wiki/doc/apiv3_partner/index.shtml目录整个流程开......
  • 游戏革命!Series AI获2800万美元融资,携手Netflix、戴尔打造GenAI游戏开发平台
     一句话定位Series是一家通过生成式AI技术,为游戏开发者提供全栈游戏创作平台的公司,致力于革新未来的游戏开发模式。一、数据概览成立时间:2023年种子轮融资:790万美元,由a16z领投A轮融资:2800万美元,投资方包括Netflix、DellTechnologiesCapital、a16z、BITKRAFT和F4Fu......
  • 白板书写延迟-触摸屏报点率
    触摸书写延迟,是触摸屏很核心的参数。从用户在触摸屏上进行触控操作到设备作出响应之间的时间差,这个延迟高低会影响快速反应的应用场景使用如白板书写、玩游戏。而触摸延迟主要影响因素有:触摸框报点率、软件框架延时(用于触摸数据接收、线程切换)、软件业务逻辑处理我们这里介绍......
  • 机器学习之神经网络Neural Network
    第一部分:基本含义神经网络(NeuralNetwork)是一种模仿人脑神经元连接方式的机器学习模型,用于处理复杂的非线性问题。通过大量的参数和层级结构,神经网络可以学习数据中的特征,应用于分类、回归等任务。机器学习和人类实现人生巅峰的例子对比:如果把人比作神经网络,一次次摔倒就是......
  • 网络最常用的几个命令(arp ,net view,tracert)
    除非了ping常用外,其实命令行,dos命令,还是很多时候可以检查出一个局域网的情况,特别排查问题,找到情况。网络最好用的几个命令arp  显示和修改地址解析协议(ARP)使用的“IP到物理”地址转换表。ARP-sinet_addreth_addr[if_addr]ARP-dinet_addr[if_addr]ARP-a[inet_a......
  • .NET 实现的交互式 OA 系统
    前言近期,我们在后台收到了粉丝们的留言,需要一个高效办公自动化(OA)系统。为了回应大家的期待,今天我们推荐一款既灵活又强大的OA系统解决方案,帮助提升日常办公效率和团队协作水平。在日常工作中,我们经常遇到各种表单。传统的系统开发中,多一个录入界面就意味着要设计一个新的输入......
  • 福建联通吉比特H80g进telnet获取超级密码改桥接
    本人博客原文链接:福建联通吉比特H80g进telnet获取超级密码改桥接最近福建联通宽带换了一个光猫,型号是吉比特H80G,自己尝试了获取管理员密码,大致流程是:1、记录自己的loid、宽带帐号、密码等配置信息;2、长按光猫reset键回复出场设置,此时管理员账户和密码是CUAdminCUAdmin,在高级......
  • 在 ASP.NET Core 中编写高性能 Web API 的4个小技巧
    WebAPI通常用来与外部模块进行通信、发送和接收数据,作为后端开发人员,应该把写出高性能的应用作为目标。下面4个技巧是我在编写WebAPI的小技巧。1、大量数据使用分页查询接口传输大量数据可能会导致严重的性能问题、过多的内存消耗和速度减慢。为了缓解这些可能的瓶颈,强......
  • 【K8s】专题十四(1):Kubernetes 安全机制之 RBAC
    本文内容均来自个人笔记并重新梳理,如有错误欢迎指正!如果对您有帮助,烦请点赞、关注、转发、订阅专栏!专栏订阅入口| 精选文章 | Kubernetes |Docker|Linux |羊毛资源 | 工具推荐 |往期精彩文章【Docker】(全网首发)KylinV10下MySQL容器内存占用异常的解决......
  • asp.net c#获取内部网关地址
    在ASP.NET中获取内部网关地址,可以使用NetworkInterface类来获取所有网络接口的信息,然后找到默认网关的IP地址。以下是一个示例代码:usingSystem;usingSystem.Net;usingSystem.Net.NetworkInformation;publicclassProgram{publicstaticvoidMain(){......