基于TensorFlow的手势识别实战:从数据集构建到CNN模型调优
简介面向计算机及相关专业中需要完成手势识别类期末大作业、课程设计或毕业设计的学生尤其适合对TensorFlow掌握尚不牢固、希望参考高分项目来快速搭建系统的新手。项目基于TensorFlow框架实现了一套完整的手势识别流程包含Python源代码、整理好的手势图像数据集以及Markdown格式的项目操作说明覆盖环境配置、数据处理、模型训练与结果评估等关键环节。压缩包内共有2000个文件其中最主要的是1996张jpg格式手势样本图片图片已按类别归档可直接用于模型训练代码文件为3个.py脚本注释详细逻辑清晰便于理解网络结构与训练思路另附1份.md说明文档指导下载后如何简单部署并运行项目。资源包整体大小为48.68MB轻量实用。该资源已有168人浏览学习项目曾获98分高分并受到导师认可对毕业设计及课程设计的整体框架搭建具有较高参考价值。1. 期末大作业选TensorFlow手势识别为什么这个题目值得做期末周最容易被高估的环节是模型不是数据。拿到基于 TensorFlow 的手势识别这个题目很多同学第一反应是抄一个现成的 CNN在 MNIST 上跑通就换数据交差结果准确率卡在 80% 以下答辩时被问数据怎么来的就露馅。手势识别适合当期末大作业是因为它覆盖了数据集采集、预处理、建模、评估到实时演示的完整链路0 到 9 手势识别类别可控、演示直观、调参余地大。下面按能拿高分的完整项目来拆数据集怎么选、怎么造CNN 怎么搭、参数怎么设最后是别人照着能跑通的项目操作说明。TensorFlow 2.x 已把 Keras 内置为高层 API用 tf.keras 写这套流程最省事课程评分环境里也比折腾 PyTorch 的依赖更稳妥。2. 手势识别数据集怎么选、怎么造公开集、自采与数据增强2.1 公开数据集怎么选0到9手势识别优先看这四类先给结论做 0 到 9 手势识别不建议拿 MNIST 当主力数据集。MNIST 是 28x28 的手写数字灰度图加载方便、教程多但它属于手写数字识别而不是手势识别答辩时容易被一句这和手势有什么关系问住。更合适的是以真实手势图像为主体的公开集或者自己采一份数据。数据集/来源类别数规模特点适用场景MNIST107 万张28x28 灰度加载快、教程多验证模型流程不适合当大作业主体Kaggle 手势识别库LeapGestRecog10每类约 2000 张真实手势、带背景变化可直接用于 0 到 9 手势识别自采数据集自定义每类 300~500 张与演示环境完全一致差异化亮点答辩加分项LeapGestRecog 是 0 到 9 手势识别里用得最多的一份开源数据10 个类别、每类约 2000 张图像原始帧较大且包含手臂区域通常裁剪后缩放成 100x100 或 128x128 再进网络。需要提醒的是它的类别定义和国内课堂演示的习惯手势不一定完全一致比如1有时是伸食指有时是伸出整个手掌下载后先抽样看几十张图确认每个类别对应哪个动作否则训练出来的模型和答辩演示对不上。2.2 自采数据集用OpenCV造一份与环境匹配的专属数据如果想把数据处理这块讲出亮点自采数据集是最直接的差异化手段。常见做法是用 OpenCV 读摄像头把画面裁剪出固定区域作为手部 ROI每按一次空格保存一帧每个类别收集 300 到 500 张。下面是采集脚本的核心逻辑import cv2 import os def collect_gesture(class_id, count300, save_rootdata/train): save_dir os.path.join(save_root, str(class_id)) os.makedirs(save_dir, exist_okTrue) cap cv2.VideoCapture(0) # 0 表示默认摄像头 captured 0 while captured count: ok, frame cap.read() if not ok: continue roi frame[120:420, 160:460] # 固定裁剪区域保证手部位置一致 cv2.rectangle(frame, (160, 120), (460, 420), (0, 255, 0), 2) cv2.putText(frame, f{captured}/{count}, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imshow(collect, frame) key cv2.waitKey(1) 0xFF if key ord( ): # 空格保存当前帧 cv2.imwrite(os.path.join(save_dir, f{captured:04d}.jpg), roi) captured 1 elif key 27: # Esc 中断 break cap.release() cv2.destroyAllWindows() collect_gesture(0, 300) # 采集类别 0共 300 张这段代码里有几个参数要在项目操作说明里写清楚ROI 的坐标范围决定手必须出现在画面哪个区域采集时用绿色框提示位置count 决定每类样本量低于 200 张很容易过拟合保存用 JPEG 格式对分类任务影响很小且省磁盘目录名直接按类别数字命名后面 flow_from_directory 才能直接按目录读标签。需要额外注意的是采集时不要只对着同一面墙拍换几个背景、角度和距离验证集和测试集最好单独采集不要从同一段视频里抽帧否则验证结果会虚高。提示验证集和测试集不要混用。测试集只在最终评估时碰一次反复拿它调参会让结果虚高答辩时被追问就不好收场。2.3 数据增强参数怎么设数字手势不要开水平翻转自采数据量不够时数据增强是让准确率往上走的常规手段。tf.keras 的 ImageDataGenerator 在训练时逐批做在线增强每轮都生成略有差异的图相当于免费扩充数据from tensorflow.keras.preprocessing.image import ImageDataGenerator train_datagen ImageDataGenerator( rescale1./255, # 像素归一化必须先做 rotation_range15, # 随机旋转 ±15 度 width_shift_range0.15, # 水平平移 15% height_shift_range0.15, # 垂直平移 15% zoom_range0.15, # 随机缩放 brightness_range(0.8, 1.2), # 亮度扰动模拟光线变化 fill_modenearest, # 平移后的空缺用邻近像素填补 validation_split0.2 # 从训练目录里留 20% 做验证 )参数上最容易犯的错是打开 horizontal_flip。0 到 9 手势里水平翻转会让部分类别语义发生变化比如6和9这类依赖朝向的手势翻转后可能被模型当成另一个类别来学验证集准确率反而下降。rotation_range 也不宜超过 20 度旋转太夸张会增加学习难度。rescale 必须放在增强参数之前指定否则像素值在 0~1 和 0~255 两套尺度下混用模型收敛速度会明显变慢。增强参数的最终幅度要以验证集表现为准增强不是越猛越好。3. 用TensorFlow搭建手势识别模型CNN结构与关键参数3.1 为什么手势识别用CNN而不是全连接网络手势图像分类问题里CNN 的三个特性正好对应三个需求局部感受野让网络先学边缘、纹理再组合成手部形状权值共享把参数量压到全连接网络的几十分之一降低过拟合风险池化带来的平移鲁棒性让手稍微偏离采集区域时预测结果也不至于突变。这些概念光看书容易绕建议到 TensorFlow Playground 里拖几个参数看决策边界的变化对卷积和激活函数的理解比看公式快得多。选型边界也要在操作说明里写清楚如果项目要求实时识别且背景复杂CNN 直接对整帧分类的效果通常不如先检测手部再分类的两阶段方案。常见做法是先用 MediaPipe Hands 提取 21 个手部关键点再把关键点坐标或裁剪后的手部区域送入 TF 模型。期末大作业阶段固定 ROI 加 CNN 已经够用两阶段方案可以作为答辩时的扩展方向主动讲出来比被动挨问好。3.2 搭一个能跑的手势识别模型结构代码与参数说明这里给一个 4 个卷积块加全局池化的结构不加 BatchNorm 也能在自采数据上稳定收敛加了 BatchNorm 可以再快一点import tensorflow as tf from tensorflow.keras import layers def build_gesture_model(input_shape(128, 128, 3), num_classes10): inputs tf.keras.Input(shapeinput_shape) x layers.Conv2D(32, (3, 3), activationrelu, paddingsame)(inputs) x layers.MaxPooling2D((2, 2))(x) x layers.Conv2D(64, (3, 3), activationrelu, paddingsame)(x) x layers.MaxPooling2D((2, 2))(x) x layers.Conv2D(128, (3, 3), activationrelu, paddingsame)(x) x layers.MaxPooling2D((2, 2))(x) x layers.Conv2D(256, (3, 3), activationrelu, paddingsame)(x) x layers.GlobalAveragePooling2D() # 替代 Flatten参数量更少 x layers.Dropout(0.5)(x) # 全连接前的随机失活 outputs layers.Dense(num_classes, activationsoftmax)(x) return tf.keras.Model(inputs, outputs) model build_gesture_model() model.summary()照抄之前先理解这几个参数卷积核用 3x3 是惯例两层 3x3 堆叠的感受野等价一层 5x5但参数量更少、非线性更强paddingsame 保证卷积前后特征图尺寸不变MaxPooling2D 再把尺寸减半四次池化后 128x128 的输入变成 8x8特征图已经足够小GlobalAveragePooling2D 替代 Flatten把每个通道压缩成一个数参数量从几十万降到几千配合 Dropout(0.5) 对两万张左右的数据量是合理配置。如果输入改小到 64x64池化层要减一层否则特征图会被压到 1x1空间信息全部丢失。3.3 损失函数、优化器和评估指标的配置手势识别是 10 类互斥分类输出层用 softmax损失就该用交叉熵。tf.keras 里有两个容易混的接口标签是整数时用 SparseCategoricalCrossentropy标签是 one-hot 时用 CategoricalCrossentropy。前面 ImageDataGenerator 的 class_modecategorical 输出的是 one-hot所以用下面这段是配套的model.compile( optimizertf.keras.optimizers.Adam(learning_rate1e-3), losstf.keras.losses.CategoricalCrossentropy(label_smoothing0.1), metrics[accuracy] )label_smoothing0.1 是容易被忽略但很实用的参数它把 one-hot 的 0/1 目标变成接近 0.025/0.925 的软目标让网络不过分自信对自采数据里少量标注错误也有抑制作用。metrics 只挂 accuracy 就够期末展示想在答辩时多一个维度可以追加 tf.keras.metrics.TopKCategoricalAccuracy(k2)统计正确类别是否落在前两个预测里能直观反映容错率。4. 手势识别模型训练与评估把准确率往97%调的实操细节4.1 训练流程回调函数怎么配才不浪费epoch直接写 model.fit 硬跑几十轮会遇到两个常见问题最好的权重可能出现在某一轮最后一轮的模型反而不是最优过拟合之后继续训练只会浪费时间和算力。所以训练时我会配三个回调ModelCheckpoint 保存最优权重、EarlyStopping 做早停、ReduceLROnPlateau 自动降学习率callbacks [ tf.keras.callbacks.ModelCheckpoint( models/best.h5, monitorval_accuracy, modemax, save_best_onlyTrue, verbose1), tf.keras.callbacks.EarlyStopping( monitorval_loss, patience10, restore_best_weightsTrue), tf.keras.callbacks.ReduceLROnPlateau( monitorval_loss, factor0.5, patience3, min_lr1e-6) ] history model.fit( train_datagen.flow_from_directory( data/train, target_size(128, 128), batch_size32, class_modecategorical, subsettraining), validation_dataval_generator, epochs50, callbackscallbacks )ModelCheckpoint 只监控验证集准确率modemax 表示数值越大越好EarlyStopping 的 patience10 容忍连续 10 轮不提升才停避免验证集的正常波动触发误停ReduceLROnPlateau 在验证损失连续 3 轮不降时把学习率减半最低压到 1e-6。epochs 写 50 只是上限有早停兜底不会真的跑满。batch_size32 对两万张量级是稳妥起步值显存充足可以调 64但 batch 太大收敛变慢太小梯度噪声大一般先固定 32 再动其他参数。4.2 训练结果怎么看loss曲线和混淆矩阵训练完第一件事不是看准确率数字而是画两条曲线判断有没有过拟合import matplotlib.pyplot as plt acc history.history[accuracy] val_acc history.history[val_accuracy] plt.plot(acc, labeltrain_acc) plt.plot(val_acc, labelval_acc) plt.legend() plt.savefig(results/acc_curve.png)train_acc 一路走高而 val_acc 在某个 epoch 之后不再涨甚至掉头就是过拟合信号优先调 Dropout 和数据增强幅度两者都低时查学习率loss 震荡剧烈先把学习率降到 3e-4。混淆矩阵建议用 sklearn 在测试集上算它能暴露哪些类别互相混淆。比如 0 和 6 经常分不清多半是采集时手型差异不明显是数据问题而不是模型结构问题import numpy as np from sklearn.metrics import confusion_matrix, classification_report y_pred np.argmax(model.predict(test_generator), axis1) print(classification_report(test_generator.classes, y_pred))如果某个类别的 F1 明显低于其他类别回到对应目录里看图片通常能找到标注错误或样本太少。4.3 三个影响分数的调参点调参点参数观察信号调整方向学习率learning_rateval_loss 震荡从 1e-3 降到 1e-4正则化Dropouttrain_acc 高、val_acc 低0.5 提到 0.6数据量增强幅度val_acc 波动大减弱 rotation/zoom学习率最优先调。从 1e-3 起步跑 10 轮如果 loss 在前三轮没有明显下降就降一半再试直到找到下降快且不震荡的档位。Dropout 放在全局池化之后而不是每个卷积层后在卷积层扔特征会让浅层学不到稳定形状。数据增强幅度要和真实场景匹配自采数据背景本来单一时过度增强反而让模型学到错误先验。这三个点调完两万张量级的 0 到 9 手势识别测试集准确率做到 97% 以上是这个题目的正常水平。5. 项目操作说明与交付照文档跑通TensorFlow手势识别5.1 环境准备tensorflow安装与依赖锁定项目操作说明的第一部分必须是环境怎么来评分点里通常有可复现性这一项。用 conda 建独立环境把版本写进 requirements.txtconda create -n gesture python3.9 -y conda activate gesture pip install tensorflow2.13.0 opencv-python4.8.1.78 \ numpy matplotlib scikit-learn pip freeze requirements.txt这里有一个常见的跑不通坑tensorflow 安装后先执行 model.summary() 验证 TensorFlow 和 Keras 是否能正常加载不要等到训练时才报错。不用 GPU 时 CPU 版足够跑完整流程单轮训练在分钟级不建议在不支持 CUDA 的机器上折腾 GPU 版本。操作说明里还要注明在项目根目录执行全部命令这类前提否则路径相对关系一错数据集读取就直接失败。5.2 项目结构怎么组织让评分老师一眼看懂推荐用 src 放代码、data 放数据、models 放权重、results 放图表根目录只留 README 和 requirementsgesture_project/ ├── data/ │ ├── train/ │ │ ├── 0/ ... ──── 9/ │ └── val/ │ └── 0/ ... ├── src/ │ ├── collect_data.py # 数据采集 │ ├── train.py # 模型训练 │ ├── predict.py # 单张图片/摄像头预测 │ └── config.py # 路径与超参数集中管理 ├── models/ │ └── best.h5 ├── results/ │ ├── acc_curve.png │ └── confusion_matrix.png ├── requirements.txt └── README.mdREADME 按环境安装、数据准备、训练、预测四段写每段只给命令和预期输出。比如训练段写python src/train.py注明看到 val_accuracy 超过 0.95 即为正常预测段写清输出格式。答辩时评分老师会先打开 README 而不是代码这部分写清楚比在代码里多写两行注释更值分。config.py 里集中放路径和超参数后续调参不用翻训练代码。5.3 演示与验收的脚本化技巧最后一个实用技巧把摄像头实时识别做成一条命令的脚本。predict.py 里用 cv2.VideoCapture 读帧每帧先截 ROI、resize 到 128x128、归一化再 model.predict 取 argmax把类别名和 FPS 画在画面上。注意两个问题模型加载要放在循环外否则每帧 load_model 会卡到没法演示predict 的输入要加 batch 维度shape 从 (128, 128, 3) 变成 (1, 128, 128, 3)。演示前在一个没参与训练的背景上先跑一遍如果准确率明显下降优先补拍现场照片扩充训练集而不是继续调模型结构。答辩时把 val 曲线、混淆矩阵和实时演示三样放齐帧率数字直接显示在画面左上角这个实时帧率比任何口头说明都有说服力。本文还有配套的精品资源点击获取

相关新闻

2026车载电器配件选购指南:车规级认证与材料耐候性实战解析

2026车载电器配件选购指南:车规级认证与材料耐候性实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 4:17:11 阅读更多 →
LabVIEW报表生成与打印控制:从文本到DIAdem自动化出图

LabVIEW报表生成与打印控制:从文本到DIAdem自动化出图

简介:面向LabVIEW开发者和自动化测试工程师的报表设计示例包,聚焦报表布局与打印输出,解决自定义报表、数据展示及打印参数配置等常见需求,适用于科学实验、工程测量和自动化测试等场景。压缩包共14个文件,大小仅1.58M…

2026/9/15 4:17:11 阅读更多 →
静态电商网站30页实战:数据驱动与模板化开发

静态电商网站30页实战:数据驱动与模板化开发

简介:一份面向数码类电商购物场景的静态网站完整设计资源包,内含30个网页模块,覆盖首页、购物车、登录窗口、商品详细页等核心页面,配套毕业设计论文与答辩PPT,适用于计算机相关专业毕业设计、课程设计或前端入门实践。…

2026/9/15 4:17:11 阅读更多 →

最新新闻

本地离线IP地址库:高性能、零依赖的IP地理定位方案

本地离线IP地址库:高性能、零依赖的IP地理定位方案

1. 什么是“最好的本地离线IP地址库”?它到底解决什么问题?“最好的本地离线IP地址库”——这八个字背后,藏着大量开发者、运维工程师、安全研究员甚至普通技术爱好者每天都在面对的真实痛点。不是“能用就行”,而是“必须快、必须…

2026/9/15 5:01:20 阅读更多 →
PyTorch实现Transformer多维时间序列分类完整指南

PyTorch实现Transformer多维时间序列分类完整指南

简介:这套基于PyTorch与Transformer的多维时间序列分类项目源码,适合具备一定深度学习基础、希望将注意力机制应用于时序数据建模的开发者学习参考。内容围绕Gated Transformer结构展开,覆盖数据处理、模型训练、热力图与特征图可视化、聚类分…

2026/9/15 5:01:20 阅读更多 →
代理IP选型三大硬指标:地域精度、IP寿命、并发稳定性

代理IP选型三大硬指标:地域精度、IP寿命、并发稳定性

1. 为什么代理IP选型不是“越便宜越好”——从一次订单失败说起去年做电商比价系统时,我踩过一个典型的坑:用某家标称“海量IP池”的低价代理服务,跑了一晚上爬虫,结果第二天发现93%的请求被目标网站识别为异常流量,订…

2026/9/15 5:01:20 阅读更多 →
隧道代理选型三大硬指标:并发承载力、协议兼容性与IP生命周期管理

隧道代理选型三大硬指标:并发承载力、协议兼容性与IP生命周期管理

1. 为什么“代理IP选购”不是选便宜货,而是选“不掉链子”的关键节点最近帮三个做电商比价系统的客户排查数据采集失败问题,最后发现全卡在同一个环节:代理IP池。不是代码写错了,不是反爬策略升级了,更不是服务器崩了—…

2026/9/15 5:01:20 阅读更多 →
2026代理IP选型指南:协议栈、热池活性与风控协同三维评估

2026代理IP选型指南:协议栈、热池活性与风控协同三维评估

1. 项目概述:为什么2026年代理IP选型已不是“挑便宜”,而是“挑生存”2026年做数据采集、市场监测、SEO分析或跨境电商业务的朋友,最近是不是明显感觉到——以前能跑通的脚本,现在隔三差五就卡在登录页?验证码越来越智…

2026/9/15 5:01:20 阅读更多 →
2026 IDE横评:传统工具与AI原生IDE的选型指南

2026 IDE横评:传统工具与AI原生IDE的选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 5:00:20 阅读更多 →

日新闻

Java高级技术:从语言特性到性能优化全解析

Java高级技术:从语言特性到性能优化全解析

1. Java高级技术概述Java作为一门成熟的编程语言,经过二十多年的发展已经形成了完整的生态系统。在企业级应用开发、大数据处理、移动开发等领域,Java都占据着重要地位。掌握Java高级技术不仅意味着能够编写更高效的代码,更代表着开发者能够解…

2026/9/15 0:00:23 阅读更多 →
C#与Halcon结合的工业视觉处理实战指南

C#与Halcon结合的工业视觉处理实战指南

1. 项目概述:C#与Halcon强强联合的视觉处理利器这个基于C#和Halcon的视觉处理Demo项目,是我在工业质检领域摸爬滚打多年后提炼出的实战精华。它完美融合了C#的界面开发优势与Halcon强大的图像处理能力,就像给视觉工程师配上了一把瑞士军刀。项…

2026/9/15 0:00:23 阅读更多 →
32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

1. 为什么“32路复合型”不是营销话术,而是工业现场真实痛点的硬解你有没有遇到过这样的场景:在某大型能源站的PLC机柜里,十几台不同年代、不同品牌的温控仪、电表、气体分析仪、阀门控制器,全靠RS-485总线挂在一根线上&#xff0…

2026/9/15 0:00:23 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/14 5:45:49 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/15 1:32:25 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/15 1:32:21 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/14 17:35:10 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/14 16:59:29 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/14 5:45:14 阅读更多 →