计算机视觉——OpenCV实现Lucas-Kanade 光流

1.光流

光流法是计算机视觉中用于估计图像序列中物体运动的关键技术。它类似于观察夜空中的彗星,通过其在天空中的运动轨迹来追踪它的路径。在图像处理中,光流帮助我们理解像素点如何在连续的帧之间移动。

1.1 稀疏光流法

稀疏光流法关注于图像中的关键点(通常是角点或显著的特征点),并计算这些点在连续帧中的运动。Lucas-Kanade算法是这种方法的一个经典例子,它通过比较特征点在连续两帧中的灰度值变化来估计这些点的运动。Lucas-Kanade方法适用于跟踪图像序列中的局部运动,尤其是当特征点清晰且显著时。

1.2 稠密光流法

与稀疏光流法不同,稠密光流法计算图像中每个像素的运动,生成一个速度场,其中每个像素都有一个对应的运动向量。Horn-Schunck算法是稠密光流法的一个代表,它通过平滑约束来优化光流场,假设图像亮度在物体运动的方向上变化不大。

1.3 Lucas-Kanade光流

在Lucas-Kanade光流中,图像的灰度值被视为位置和时间的函数。对于一个固定空间点,尽管其在世界坐标系中的位置是固定的,但在图像平面上的像素坐标会随着相机的运动会发生变化。Lucas-Kanade算法通过最小化重投影误差来估计这些像素坐标的变化,即:

I ( x , y , t ) = I ( x + Δ x , y + Δ y , t + Δ t ) I(x, y, t) = I(x + \Delta x, y + \Delta y, t + \Delta t) I(x,y,t)=I(x+Δx,y+Δy,t+Δt)

其中, I ( x , y , t ) I(x, y, t) I(x,y,t)是在时间 t t t的图像中的灰度值, ( d x , d y ) (dx, dy) (dx,dy)是像素在图像平面上的位移,而 d t dt dt是时间间隔。通过建立一个关于位移 ( d x , d y ) (dx, dy) (dx,dy)的方程组,Lucas-Kanade算法可以估计出特征点的运动。

2. 光流基本假设推导过程

2.1. 光流法的基本假设
光流法的基本假设是同一个空间点的像素灰度值,在各个图像中的是固定不变的。公式描述为:
I ( x , y , t ) = I ( x + Δ x , y + Δ y , t + Δ t ) I(x, y, t) = I(x + \Delta x, y + \Delta y, t + \Delta t) I(x,y,t)=I(x+Δx,y+Δy,t+Δt)

2.2. 泰勒展开
对上式右侧进行泰勒展开,得到:
I ( x + Δ x , y + Δ y , t + Δ t ) ≈ I ( x , y , t ) + ∂ I ∂ x Δ x + ∂ I ∂ y Δ y + ∂ I ∂ t Δ t I(x + \Delta x, y + \Delta y, t + \Delta t) \approx I(x, y, t) + \frac{\partial I}{\partial x}\Delta x + \frac{\partial I}{\partial y}\Delta y + \frac{\partial I}{\partial t}\Delta t I(x+Δx,y+Δy,t+Δt)I(x,y,t)+xIΔx+yIΔy+tIΔt

2.3. 光流约束方程
因为假设了灰度不变,即 I ( x , y , t ) I(x, y, t) I(x,y,t)不随 Δ x , Δ y , Δ t \Delta x, \Delta y, \Delta t Δx,Δy,Δt变化,因此有:
∂ I ∂ x Δ x + ∂ I ∂ y Δ y + ∂ I ∂ t Δ t = 0 \frac{\partial I}{\partial x}\Delta x + \frac{\partial I}{\partial y}\Delta y + \frac{\partial I}{\partial t}\Delta t = 0 xIΔx+yIΔy+tIΔt=0

2.4. 速度和梯度
将像素在 x 轴上的速度记为 u u u,在 y 轴上的速度记为 v v v,上述方程可以写为:
∂ I ∂ x u Δ t + ∂ I ∂ y v Δ t = − ∂ I ∂ t \frac{\partial I}{\partial x}u\Delta t + \frac{\partial I}{\partial y}v\Delta t = -\frac{\partial I}{\partial t} xIuΔt+yIvΔt=tI

2.5. 矩阵形式
写成矩阵形式有:
[ I x I y ] [ u v ] = − I t \begin{bmatrix} I_x & I_y \end{bmatrix} \begin{bmatrix} u \\ v \end{bmatrix} = -I_t [IxIy][uv]=It

2.6. 超定线性方程组
在 Lucas-Kanade 光流中,引入了新的假设作为约束,即某一个窗口内的像素具有相同的运动。考虑一个大小为 w × h w \times h w×h 的窗口,其包含 k k k个像素。因为假设该窗口内像素具有相同的运动,因此可以得到 k k k个方程:
[ I x 1 I y 1 I x 2 I y 2 ⋮ ⋮ I x k I y k ] [ u v ] = − [ I t 1 I t 2 ⋮ I t k ] \begin{bmatrix} I_x^1 & I_y^1 \\ I_x^2 & I_y^2 \\ \vdots & \vdots \\ I_x^k & I_y^k \end{bmatrix} \begin{bmatrix} u \\ v \end{bmatrix} = -\begin{bmatrix} I_t^1 \\ I_t^2 \\ \vdots \\ I_t^k \end{bmatrix} Ix1Ix2IxkIy1Iy2Iyk [uv]= It1It2Itk

A = [ I x 1 I y 1 ⋮ I x k I y k ] A = \begin{bmatrix} I_x^1 & I_y^1 \\ \vdots \\ I_x^k & I_y^k \end{bmatrix} A= Ix1IxkIy1Iyk b = [ I t 1 ⋮ I t k ] b = \begin{bmatrix} I_t^1 \\ \vdots \\ I_t^k \end{bmatrix} b= It1Itk ,则方程组可以写为:
A [ u v ] = b A\begin{bmatrix} u \\ v \end{bmatrix} = b A[uv]=b

2.7. 最小二乘解
该方程是关于 u u u v v v 的超定线性方程组,可以使用最小二乘法求解:
[ u v ] ∗ = − ( A T A ) − 1 A T b \begin{bmatrix} u \\ v \end{bmatrix}^* = -(A^TA)^{-1}A^Tb [uv]=(ATA)1ATb

值得注意的是,上述公式中的 I x , I y , I t I_x, I_y,I_t Ix,Iy,It 分别表示图像在该点的 x 方向梯度、y 方向梯度和时间方向的梯度。 Δ x , Δ y \Delta x,\Delta y Δx,Δy是像素点在图像平面上的位移,而 Δ t \Delta t Δt 是时间间隔。 u u u v v v是像素点在 x 和 y 方向上的速度。

3.OpenCV中calcOpticalFlowPyrLK函数

OpenCV中calcOpticalFlowPyrLK方法使用迭代Lucas-Kanade算法计算稀疏特征点的光流,用来做特征点跟踪,该方法使用了金字塔,因此具有一定的尺度不变性。
函数原型:

void cv::calcOpticalFlowPyrLK(	InputArray 	        prevImg,InputArray 	        nextImg,InputArray 	        prevPts,InputOutputArray 	nextPts,OutputArray 	    status,OutputArray 	    err,Size 	            winSize = Size(21, 21),int 	            maxLevel = 3,TermCriteria 	    criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),int 	            flags = 0,double          	minEigThreshold = 1e-4 
);
  • prevImg:上一帧图像
  • nextImg:下一帧图像
  • prevPts:上一帧图像中关键点
  • nextPts:根据光流计算的上一帧关键点在当前帧中的位置
  • status:关键点的跟踪状态,vector,1表示OK,0表示LOST
  • err:每个特征点的跟踪误差vector<float>len(status)==len(nextPts)==len(prePts)==len(err)
  • winSize:在每层金字塔中,LK算法中用来求解计算像素运动而假设具有相同运动的窗口大小。
  • maxLevel:金字塔的层数,层数多,尺度不变性能更好,运算时间更久
  • criteria:迭代搜索算法的终止条件,默认值表示在指定的最大迭代次数criteria.maxCount(30)之后或当搜索窗口移动小于criteria.epsilon(0.01)时终止迭代
  • flags:设置误差或者初始值参数,可选下面两个值:
    • OPTFLOW_USE_INITIAL_FLOW设置使用nextPts中的值作为迭代的初始值,如果不设置为OPTFLOW_USE_INITIAL_FLOW,初始状态就使用prevPts中的值,直接从prevPts复制到nextPts,OpenCV源码中对OPTFLOW_USE_INITIAL_FLOW的使用方式为:

      if( flags & OPTFLOW_USE_INITIAL_FLOW )nextPt = nextPts[ptidx]*(float)(1./(1 << level));
      elsenextPt = prevPt;
      
      • OPTFLOW_LK_GET_MIN_EIGENVALS,flags设置为这个值时使用光流运动方程2x2的正规矩阵,也即空间梯度矩阵的最小特征值作为误差项。如果不设置成OPTFLOW_LK_GET_MIN_EIGENVALS,将原始点和移动点周围像素的距离除以窗口中的像素作为误差项。
  • minEigThreshold:迭代LK算法会计算光流运动方程2x2的正规矩阵,也即空间梯度矩阵的最小特征值,然后再除以运动不变窗口中的像素总数作为一个误差评价标准,当其小于minEigThreshold时,说明这个点已经追踪不到了,会将其从追踪特征点中移除,避免其对应相素运动的计算,可提升性能。

calcOpticalFlowPyrLK通常和goodFeatureToTrack方法一起使用,先使用GFTTDetector提取特征点的位置,再使用calcOpticalFlowPyrLK追踪其在连续视频流中的位置,避免了特征描述子的计算和特征点的匹配,可以极大的提升追踪的性能。

c++实现:

#include <memory> 
#include <vector>
#include <cstdlib>#include <opencv2/features2d.hpp>
#include <opencv2/opencv.hpp>// 定义一个名为TestOpticalFlowLK的类,用于处理光流跟踪
class TestOpticalFlowLK {public:// 使用std::shared_ptr来定义智能指针,便于管理类的实例typedef std::shared_ptr<TestOpticalFlowLK> Ptr;// 构造函数TestOpticalFlowLK();// 默认的析构函数// track函数用于处理特征点的跟踪void track(std::vector<cv::String> &filenames) const;private:// 使用cv::Ptr来定义一个智能指针,指向GFTTDetector对象cv::Ptr<cv::GFTTDetector> gftt_ptr_;
};// 实现TestOpticalFlowLK类的构造函数
TestOpticalFlowLK::TestOpticalFlowLK()
{// 初始化GFTTDetector对象,用于特征点检测gftt_ptr_ = cv::GFTTDetector::create(500, 0.2, 50);
}// 实现track函数,用于处理特征点的跟踪
void TestOpticalFlowLK::track(std::vector<cv::String> &filenames) const
{// 确保filenames至少有一个元素assert(filenames.size() > 1);// 存储检测到的特征点std::vector<cv::KeyPoint> kps1;// 存储上一帧和当前帧中特征点的位置std::vector<cv::Point2f> pts1, pts2;// 存储绘制特征点时使用的颜色std::vector<cv::Scalar> colors;// 读取第一帧图像,并初始化last_imgcv::Mat last_img = cv::imread(filenames[0], 0), cur_img;// 创建一个掩码,用于绘制特征点cv::Mat mask(last_img.size(), CV_8UC1, 255);// 使用GFTTDetector检测第一帧图像中的特征点gftt_ptr_->detect(last_img, kps1, mask);// 遍历所有检测到的特征点for(auto &kp : kps1) {// 为每个特征点生成一个随机颜色int r = (int)(255. * rand() / (RAND_MAX + 1.f));int g = (int)(255. * rand() / (RAND_MAX + 1.f));int b = (int)(255. * rand() / (RAND_MAX + 1.f));// 输出随机颜色的值std::cout << "r:" << r << "g:" << g << "b:" << b << std::endl;// 将颜色添加到colors数组中colors.emplace_back(r, g, b);// 将特征点的位置添加到pts1和pts2数组中pts1.push_back(kp.pt);pts2.push_back(kp.pt);}// 存储特征点的跟踪状态std::vector<uchar> status;// 存储每个特征点的跟踪误差std::vector<float> err;// 将掩码转换为BGR格式,以便绘制cv::cvtColor(mask, mask, cv::COLOR_GRAY2BGR);// 创建一个Mat对象,用于存储绘制特征点后的图像cv::Mat frame;// 遍历所有提供的图像文件名for (auto &filename : filenames){// 输出当前处理的文件名std::cout << "filename: " << filename << std::endl;// 读取当前帧图像cur_img = cv::imread(filename, 0);// 使用calcOpticalFlowPyrLK计算特征点的光流cv::calcOpticalFlowPyrLK(last_img,cur_img,pts1,pts2,status,err,cv::Size(13, 13),3,cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 30, 0.01),cv::OPTFLOW_USE_INITIAL_FLOW);// 将当前帧图像转换为BGR格式cv::cvtColor(cur_img, cur_img, cv::COLOR_GRAY2BGR);int cnt = 0; // 用于计数成功跟踪的特征点数量// 遍历所有特征点for(size_t i = 0; i < status.size(); i++) {// 输出当前特征点的跟踪误差std::cout << " " << err[i];// 如果特征点未成功跟踪,则跳过if(!status[i]) continue;// 如果特征点的移动距离超过80像素,则跳过if(abs((pts1[i].x - pts2[i].x)) > 80 || abs((pts1[i].y - pts2[i].y)) > 80) continue;// 在掩码上绘制特征点之间的连线cv::line(mask, pts1[i], pts2[i], colors[i], 2);// 在当前帧图像上绘制特征点cv::circle(cur_img, pts2[i], 10, colors[i], 1);// 更新pts1中的坐标为pts2中的坐标pts1[i].x = pts2[i].x;pts1[i].y = pts2[i].y;// 增加成功跟踪的特征点计数cnt += 1;}// 输出每帧成功跟踪的特征点数量std::cout << std::endl;// 将掩码和当前帧图像混合,以便同时显示原始图像和特征点cv::addWeighted(mask, 0.5, cur_img, 0.5, -65, frame);// 显示混合后的图像cv::imshow("frame", frame);// 等待用户按键,0表示无限等待cv::waitKey(0);// 更新last_img为当前帧图像cv::cvtColor(cur_img, cur_img, cv::COLOR_BGR2GRAY);last_img = cur_img;// 保存混合后的图像到文件cv::imwrite("frame.png", frame);}
}

在这里插入图片描述

Python 代码:

import cv2
import numpy as np
import randomclass TestOpticalFlowLK:def __init__(self):# 初始化GFTTDetector对象,用于特征点检测self.gftt_ptr_ = cv2.GFTTDetector_create(500, 0.2, 50)def track(self, filenames):assert len(filenames) > 1, "At least one filename is required"last_img = cv2.imread(filenames[0], 0)kps1 = self.gftt_ptr_.detect(last_img)pts1 = np.array([kp.pt for kp in kps1], dtype='float32')pts2 = np.zeros((len(pts1), 2), dtype='float32')colors = [((random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) for _ in range(len(kps1)))]status = np.zeros((len(pts1),), dtype='uint8')err = np.zeros((len(pts1),), dtype='float32')for filename in filenames[1:]:print("Processing file:", filename)cur_img = cv2.imread(filename, 0)pts2, status, err = cv2.calcOpticalFlowPyrLK(last_img, cur_img, pts1, pts2, None, winSize=(13, 13), maxLevel=3,criteria=(cv2.TERM_CRITERIA_COUNT | cv2.TERM_CRITERIA_EPS, 30, 0.01),flags=cv2.OPTFLOW_USE_INITIAL_FLOW)img = cv2.cvtColor(cur_img, cv2.COLOR_GRAY2BGR)for i, (pt1, pt2, stat) in enumerate(zip(pts1, pts2, status)):if stat:# 确保坐标是一维数组pt1 = pt1.reshape(-1)pt2 = pt2.reshape(-1)cv2.line(img, (int(pt1[0]), int(pt1[1])), (int(pt2[0]), int(pt2[1])), (255), 2)cv2.circle(img, (int(pt2[0]), int(pt2[1])), 10, (127), 1)pts1 = pts2.copy()last_img = cur_imgcv2.imshow("frame", img)cv2.waitKey(0)cv2.destroyAllWindows()if __name__ == "__main__":# 假设我们有一个包含图像文件路径的列表filenames = ['data/00001.jpg', 'data/00001.jpg', 'data/00002.jpg','data/00003.jpg']  # 以此类推flow_tracker = TestOpticalFlowLK()flow_tracker.track(filenames)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/10185.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web3空投入门:如何增加空投成功的几率

今天分享空投如何避免限制以提高效率&#xff0c;增加成功几率&#xff0c;首先我们来了解什么是空投加密&#xff0c;有哪些空投类型。 一、什么是空投加密&#xff1f; 加密货币空投是一种营销策略&#xff0c;包括向用户的钱包地址发送免费的硬币或代币。 加密货币项目使用…

Leetcode—155. 最小栈【中等】

2024每日刷题&#xff08;130&#xff09; Leetcode—155. 最小栈 实现代码 class MinStack { public:MinStack() {}void push(int val) {if(st.empty()) {st.emplace(val, val);} else {st.emplace(val, min(val, st.top().second));}}void pop() {if(st.empty()) {return;}…

【漏洞复现】用友U8-Cloud XChangeServlet XXE漏洞

0x01 产品简介 用友U8Cloud是用友推出的新一代云ERP,主要聚焦成长型、创新型企业,提供企业级云ERP整体解决方案。 0x02 漏洞概述 用友U8 cloud /service/XChangeServlet接口存在XXE漏洞,未授权的攻击者可通过此漏洞获取数据库敏感信息,从而盗取服务器数据,造成服务器信…

林更新博士之路星途璀璨再启航

林更新&#xff1a;博士之路&#xff0c;星途璀璨再启航在这个充满机遇与挑战的时代&#xff0c;有一位演员以其出色的演技和不懈的努力&#xff0c;赢得了无数观众的喜爱。他&#xff0c;就是林更新。今日&#xff0c;一条消息如重磅炸弹般在娱乐圈炸开&#xff0c;让无数粉丝…

UBOOT介绍

一、UBOOT简介 U-boot全称 Universal Boot Loader&#xff0c;是遵循GPL条款的开放源码项目&#xff0c;uboot 是一个裸机代码&#xff0c;可以看作是一个裸机综合例程&#xff0c;执行启动内核的功能。 补充&#xff1a;GPL条款&#xff08;GNU General Public License&…

空间复杂度与链表刷题

"一切的一切都是你自己在感应." 本文索引 空间复杂度复杂度实例实例1实例2实例3 链表题目1. 返回倒数第K个节点2. 链表的回文结构3. 相交链表4. 随机链表的复制5. 环形链表 总结: 前言: 本文主要探究空间复杂度与链表题目讲解 更多文章点击主页: 酷酷学!!! 如果此文对…

构建内网yum仓库

1、环境介绍 系统&#xff1a;龙蜥os 7.9 2、安装epel源 yum install epel-release -y3、安装nginx服务器并启动 yum install nginx httpd -y配置 server {listen 80;server_name repo.wtown.com;root /usr/share/nginx/html/repo;index index.html index.htm;location / {…

Sora惊艳亮相:AI技术掀起创作革命,影视产业迎来新风貌!

Sora平台近期发布了名为"Sora首次印象"的更新&#xff0c;为用户带来了令人瞩目的变化。该更新不仅展示了Sora平台的发展方向&#xff0c;还介绍了其在电影制作、广告宣传等领域的潜在应用。 同时&#xff0c;Sora的首席执行官Sam Altman与好莱坞影视工作室进行了会…

基于Python的数据分组技术:将数据按照1, 2, 3规则分为三个列表

目录 一、引言 二、数据分组原理与意义 三、案例分析 四、代码实现与解释 五、对新手友好的解释 六、技术细节与扩展 七、实际应用场景 八、总结 一、引言 在数据处理和分析的广阔领域中&#xff0c;数据分组是一项基础且重要的任务。数据分组通常指的是将数据集中的元…

在做题中学习(55):一维前缀和模板

【模板】前缀和_牛客题霸_牛客网 (nowcoder.com) 题目解释&#xff1a; 注意&#xff1a;下标从1开始的。 l 和 r就是对这n个整数去取一个区间&#xff0c;例如示例一&#xff1a; (1,2) 区间 就是算出1 2 4 中 1&#xff0c;2下标对应值的和&#xff0c;12 3 同理,(2,3) …

springboot2.x集成Elasticsearch7.7.0

一、前言 elasticsearch安装就不做过多介绍了&#xff0c;网上一搜一大堆&#xff1b;最需要注意的就是Elasticsearch与spring版本&#xff0c;防止版本不兼容导致的后续的一系列问题。我这里springbootspring-data-elasticsearch&#xff0c;他们的版本对照关系可以参照sprin…

vue2后台管理项目

一:项目准备 1)拉取模板代码 远程仓库复制到本地仓库. 2)安装后的项目 路径 code 文件夹 会打开vscode的文件夹. 3)安装vetur和eslint插件可以保存时自动修改不规范的地方. 4)App内有一级路由,路由组件导入如果是layout架子,会导入的是文件夹下的index.js没有则导入index.v…

有什么实用的还原试卷的app免费?6个软件教你快速进行还原试卷

有什么实用的还原试卷的app免费&#xff1f;6个软件教你快速进行还原试卷 在现代化的教学环境中&#xff0c;使用数字化工具进行试卷还原变得愈发重要。以下是六个实用的、免费的应用程序&#xff0c;它们为还原试卷提供了便捷的解决方案。 FunAI&#xff1a; 这款应用程序可…

SD-WAN提升Microsoft 365用户体验

随着数字化时代的到来&#xff0c;SaaS应用如Microsoft 365已经成为各类企业的主流选择。在这一趋势下&#xff0c;企业需要以更加灵活、高效的方式使用Microsoft 365&#xff0c;以满足日益增长的业务需求。而传统的网络基础设施可能无法满足这一需求&#xff0c;因此&#xf…

指针的奥秘(三):数组指针+函数指针(+typedef)+函数数组指针+转移表

指针 一.数组指针1.数组指针变量是什么&#xff1f;2.指针数组和数组指针区别和口诀3.数组指针变量怎么初始化4.二维数组传参的本质 二.函数指针1.函数指针变量的创建2.函数指针变量的使用3.两段有趣的代码1.( *( void ( * )( ) )0 ) ( );2.void( *signle(int, void( * )(int) …

TCP协议的确认应答机制

TCP&#xff08;Transmission Control Protocol&#xff09;是一种面向连接的、可靠的、基于字节流的传输层协议&#xff0c;它在网络通信中扮演着至关重要的角色。其中&#xff0c;确认应答机制是TCP协议中的一个核心概念&#xff0c;它确保了数据的可靠传输。本文将详细介绍J…

【QA】Java集合常用的函数

文章目录 前言Collection接口通用函数 | Collections工具类通用函数 | List接口 Set接口List接口ArrayListLinkedList Set接口TreeSetHashSetLinkedHashSet Map接口通用函数TreeMapHashMapLinkedHashMap 前言 本文介绍Java集合中常用的函数。 Collection接口 通用函数 | Co…

WP All Import Pro插件下载 - 一键导入,无限可能

在当今快节奏的数字时代&#xff0c;网站内容的更新和管理是每个网站管理员和开发者的日常工作。但是&#xff0c;传统的手动更新方法不仅耗时&#xff0c;而且容易出错。现在&#xff0c;有了WP All Import Pro&#xff0c;这一切都将改变。 WP All Import Pro 是一款专为Wor…

ABAP ZCL_EXCEL 实际用的案例 对账单

ABAP ZCL_EXCEL 实际用的案例 FORM GETITEMSANDOUTPUT USING PGS_HEAD TYPE GSHEAD.DATA:FILENAME TYPE STRING.DATA:LKUNNR TYPE KNA1-KUNNR.DATA:PROW TYPE I.DATA:LSDATE TYPE STRING.DATA:SUMXSJE TYPE DMBTR,ZYMYE TYPE DMBTR, "月末余额SUMBYXSYE TYPE DMBT…

全新神经网络架构KAN——本文用于学习与探索

论文地址&#xff1a;https://arxiv.org/pdf/2404.19756 Github&#xff1a;GitHub - KindXiaoming/pykan: Kolmogorov Arnold Networks 文档说明&#xff1a;Welcome to Kolmogorov Arnold Network (KAN) documentation! — Kolmogorov Arnold Network documentation 本文仅…