当前位置: 首页 > news >正文

【JS开源库】基于最小二乘法的离散点拟合圆形,计算圆心坐标和半径

介绍

使用的开源库:https://github.com/Meakk/circle-fit

一个用于快速拟合一组二维点的JavaScript库。
该实现基于最小二乘法来找到3个未知数:x和y坐标以及半径。


该算法不包含任何迭代求解器,将在线性时间内找到解,这意味着您将立即得到结果。
当您没有足够的非共线点通过返回错误标志来确定正确的圆时,此库会处理退化情况。


该库使用起来很简单。只有一个circlefit.js,全局对象circlefit会自动创建。此对象有3种方法:
addPoint(x,y):在集合中添加一个点
clearPoints():删除所有点
compute():执行求解器并返回一个包含结果的对象。


返回的结果对象不仅包含圆的基本参数,还有其他参数:

  • success(布尔值):计算状态
  • points(数组):用户给出的所有点
  • projections (数组):将每个点投影到圆上的点
  • distances (数组):每个点到圆的距离
  • center(Object):圆的中心
  • radius(数字):圆的半径
  • residue (数字):最小二乘法的残差,可用于定义圆的质量
  • computationTime(Number):计算所花费的时间(以毫秒为单位)

示例

circlefit.js库的源码

出处:https://github.com/Meakk/circle-fit/blob/master/circlefit.js
是MIT协议。

源码复制到下面了:

var CIRCLEFIT = (function () {var my = {},points = [];function linearSolve2x2(matrix, vector) {var det = matrix[0]*matrix[3] - matrix[1]*matrix[2];if (det < 1e-8) return false; //no solutionvar y = (matrix[0]*vector[1] - matrix[2]*vector[0])/det;var x = (vector[0] - matrix[1]*y)/matrix[0];return [x,y];}my.addPoint = function (x, y) {points.push({x: x, y: y});}my.resetPoints = function () {points = [];}my.compute = function () {var result = {points: points,projections: [],distances: [],success: false,center: {x:0, y:0},radius: 0,residue: 0,computationTime: performance.now()};//meansvar m = points.reduce(function(p, c) {return {x: p.x + c.x/points.length,y: p.y + c.y/points.length};},{x:0, y:0});//centered pointsvar u = points.map(function(e){return {x: e.x - m.x,y: e.y - m.y};});//solve linear equationvar Sxx = u.reduce(function(p,c) {return p + c.x*c.x;},0);var Sxy = u.reduce(function(p,c) {return p + c.x*c.y;},0);var Syy = u.reduce(function(p,c) {return p + c.y*c.y;},0);var v1 = u.reduce(function(p,c) {return p + 0.5*(c.x*c.x*c.x + c.x*c.y*c.y);},0);var v2 = u.reduce(function(p,c) {return p + 0.5*(c.y*c.y*c.y + c.x*c.x*c.y);},0);var sol = linearSolve2x2([Sxx, Sxy, Sxy, Syy], [v1, v2]);if (sol === false) {//not enough points or points are colinearsreturn result;}result.success = true;//compute radius from circle equationvar radius2 = sol[0]*sol[0] + sol[1]*sol[1] + (Sxx+Syy)/points.length;result.radius = Math.sqrt(radius2);result.center.x = sol[0] + m.x;result.center.y = sol[1] + m.y;points.forEach(function(p) {var v = {x: p.x - result.center.x, y: p.y - result.center.y};var len2 = v.x*v.x + v.y*v.y;result.residue += radius2 - len2;var len = Math.sqrt(len2);result.distances.push(len - result.radius);result.projections.push({x: result.center.x + v.x*result.radius/len,y: result.center.y + v.y*result.radius/len});     });result.computationTime = performance.now() - result.computationTime;return result;}return my;
}());//为了方便测试,笔者额外加的
module.exports = {CIRCLEFIT
}

测试用例1与效果图

var util=require("./circlefit.js");
var CIRCLEFIT = util.CIRCLEFIT;var pts = [[137, 17672.52 ],[104.97, 17640.08],[12.52, 17539.34],[-45.99, 17469.43],[-101.92, 17397.44],[-180.79, 17285.75],[-253.44, 17169.91],[-319.65, 17050.28],[-379.22, 16927.2],[-431.98, 16801.05],[-463.28, 16715.43],[-491.44, 16628.72],
]for (let i = 0; i < pts.length; i++) {CIRCLEFIT.addPoint(pts[i][0], pts[i][1]);
}var result = CIRCLEFIT.compute();
if (result.success) {var c =  result.center;var x = Math.round(c.x);var y = Math.round(c.y);var r = Math.round(result.radius);console.log(`圆心=(${x},${y})`);console.log(`半径={${r}}`);
}

运行结果:

圆心=(1900,15900)
半径={2500}

效果图:

在这里插入图片描述

测试用例2与效果图

将点数组换成:

var pts = [[0, 0],[1, 1.1],[1.5, 0.8],[2, -0.5],
]

效果图:
在这里插入图片描述

补充

  • 毕竟是最小二乘法来拟合,当点的噪音太大、太多时,可能拟合效果就不太好了。
  • 可根据需要,转用其他语言重写。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 关于redisson的序列化配置
  • vs code 插件: Crabviz
  • MAC上设置快捷打开终端以及如何运用剪切快捷键
  • 编程-设计模式 2:抽象工厂模式
  • YOLO好像也没那么难?
  • Windows图形界面(GUI)-MFC-C/C++ - CSliderCtrl
  • 沪深300股指期货如何操作套期保值?
  • small bird
  • SpringBoot获取resources文件夹下文件并且实现下载
  • 视频懒加载
  • 深入理解 Go 的 init 函数:以 GORM 数据库连接为例
  • [SWPUCTF 2021 新生赛]include
  • Arrays类、Random类和包装类(8大基本数据类型)的用法
  • 加密软件有哪些常见的安全特性
  • Linux驱动开发—设备树分析:GPIO,中断,时钟信息,CPU信息
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 【EOS】Cleos基础
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • C++类中的特殊成员函数
  • css选择器
  • Docker: 容器互访的三种方式
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • leetcode-27. Remove Element
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • MaxCompute访问TableStore(OTS) 数据
  • springMvc学习笔记(2)
  • XForms - 更强大的Form
  • 对象引论
  • 简单数学运算程序(不定期更新)
  • 聊聊hikari连接池的leakDetectionThreshold
  • 我有几个粽子,和一个故事
  • 移动端 h5开发相关内容总结(三)
  • 用 Swift 编写面向协议的视图
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • #{} 和 ${}区别
  • #如何使用 Qt 5.6 在 Android 上启用 NFC
  • (06)金属布线——为半导体注入生命的连接
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (第一天)包装对象、作用域、创建对象
  • (二)pulsar安装在独立的docker中,python测试
  • (分类)KNN算法- 参数调优
  • (附源码)springboot 智能停车场系统 毕业设计065415
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (算法)Travel Information Center
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (游戏设计草稿) 《外卖员模拟器》 (3D 科幻 角色扮演 开放世界 AI VR)
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)ABI是什么
  • (转)程序员疫苗:代码注入
  • .net 4.0发布后不能正常显示图片问题
  • .Net Core 中间件与过滤器
  • .NET 中 GetProcess 相关方法的性能
  • .NET4.0并行计算技术基础(1)