新闻详情

新闻详情

首页 / 资讯中心 / 详情

手语识别实战:Mediapipe关键点与随机森林搭建完整识别系统

发布时间:2026/9/28 14:36:31来源:尧图网络
手语识别实战:Mediapipe关键点与随机森林搭建完整识别系统
简介一份基于Python、OpenCV与Mediapipe实现的手语手势识别检测源码包面向计算机相关专业学生、高校教师及开发者可直接用于课程设计、毕业设计也是计算机视觉入门后二次开发的不错起点。压缩包共6个文件以4个Python脚本为主线覆盖图像采集、数据集创建、模型训练与推理分类等完整流程另含1个Markdown说明文档和1个requirements.txt依赖清单包体仅4KB结构轻量、上手门槛低。项目利用Mediapipe完成手部关键点提取配合OpenCV进行图像处理与可视化代码逻辑清晰、易于阅读和修改读者可据此理解手势识别从数据准备到模型推理的全链路实现并进一步扩展至其他手势或动作识别场景。目前已有210人学习/下载适合希望将理论转化为实战能力的AI与CV学习者借由这套源码快速搭建属于自己的手语识别DEMO。1. 手语识别项目没有想象中神秘一条Mediapipe骨架线撑起整个识别链路手语识别在外行人看来像是个纯深度学习课题动辄要上视频Transformer或者复现CVPR的专用模型。真把这个项目在本地从零跑过一遍就会明白静态手语里占大头的数字、字母和部分语义手势用OpenCV负责视频帧读取与画框Mediapipe抽出21个手部关键点再喂给随机森林或轻量MLP就能达到实用级准确率。真正决定项目死活的不是模型的层数而是关键点特征怎么构造、数据怎么采集。这套方案适合两类人一是课程设计或毕设需要快速跑通完整识别链路的学生二是想做无障碍交互原型的从业者。它不需要GPU不依赖标好的大规模手语数据集一个普通摄像头加一台笔记本就能完成采集、训练、推理的闭环。下面按一条可复现的路线展开从环境搭建讲到特征工程再讲训练与部署最后把最容易翻车的几个细节单独列出来。2. 搭建最小可跑环境Python/OpenCV/Mediapipe版本匹配与首帧验证2.1 为什么版本匹配是手语项目的第一道门槛拿到这类“手语识别源码包”后第一件事不是读代码而是确认解释器版本和Mediapipe版本。Mediapipe的API在2023年前后发生过一次大分裂老版本走的是mp.solutions.hands这条路新版本走的是mp.tasks.vision.HandLandmarker。很多源码还在用老写法装上新版Mediapipe后一跑就报AttributeError: module mediapipe has no attribute solutions这不是代码写错了是API迁移导致的兼容性断裂。另外Mediapipe对Python版本也挑某些小版本在Python 3.12上找不到对应的轮子安装时直接报编译错误。我的习惯是锁定Python 3.9到3.11之间的版本环境越干净后面查问题越省心。建议用VSCode单独建虚拟环境来跑手语项目避免把系统Python搞乱。2.2 最小环境安装命令与版本核对在虚拟环境里执行以下命令注意区分CPU版和GPU版手语识别项目用CPU版就足够python -m venv .venv # Windows: .venv\Scripts\activate Linux/macOS: source .venv/bin/activate pip install --upgrade pip pip install opencv-python mediapipe scikit-learn numpy joblib安装完成后先别急着跑识别花十秒钟核对一下版本python -c import cv2, mediapipe, sklearn; print(cv2.__version__); print(mediapipe.__version__); print(sklearn.__version__)参数说明这里用的都是当前主流稳定版。OpenCV提供图像读写和绘制函数Mediapipe提供手部关键点检测scikit-learn用来训练分类器joblib负责把训练好的模型保存到磁盘。如果你发现pip install mediapipe在Python 3.12上卡住或者报编译错误直接换Python 3.10再试这是最省事的解法而不是硬着头皮编译。2.3 跑通“摄像头取帧关键点可视化”的最小代码环境就绪后先验证摄像头和Mediapipe能否协同工作不涉及任何手语逻辑。下面是老版Mediapipe0.8.x系列的经典写法import cv2 import mediapipe as mp mp_hands mp.solutions.hands mp_draw mp.solutions.drawing_utils hands mp_hands.Hands( static_image_modeFalse, # 视频流模式 max_num_hands1, # 手语场景通常只追踪一只手 min_detection_confidence0.5, min_tracking_confidence0.5, ) cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while cap.isOpened(): ret, frame cap.read() if not ret: break frame cv2.flip(frame, 1) # 镜像让画面和真实动作一致 rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results hands.process(rgb) if results.multi_hand_landmarks: for hand_landmarks in results.multi_hand_landmarks: mp_draw.draw_landmarks( frame, hand_landmarks, mp_hands.HAND_CONNECTIONS) cv2.imshow(hand landmark, frame) if cv2.waitKey(1) 0xFF 27: # ESC 退出 break hands.close() cap.release() cv2.destroyAllWindows()逻辑说明static_image_modeFalse表示按视频流模式处理Mediapipe会利用上一帧的跟踪结果来加速当前帧检测max_num_hands1在手语识别里很重要两个手同时入镜会导致关键点混淆。process()方法要求输入RGB图像所以OpenCV读到的BGR帧必须先做一次cvtColor。如果你装的是新版Mediapipe代码换成下面的写法import cv2 import mediapipe as mp from mediapipe.tasks import python from mediapipe.tasks.python import vision base_options python.BaseOptions(model_asset_pathhand_landmarker.task) options vision.HandLandmarkerOptions( base_optionsbase_options, num_hands1, min_hand_detection_confidence0.5, min_hand_presence_confidence0.5, ) detector vision.HandLandmarker.create_from_options(options) cap cv2.VideoCapture(0) while cap.isOpened(): ret, frame cap.read() if not ret: break frame cv2.flip(frame, 1) rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) mp_image mp.Image(image_formatmp.ImageFormat.SRGB, datargb) result detector.detect(mp_image) if result.hand_landmarks: hand result.hand_landmarks[0] h, w frame.shape[:2] # 手动连线Mediapipe的HAND_CONNECTIONS常量仍然可用 for conn in mp.solutions.hands.HAND_CONNECTIONS: p1, p2 hand[conn[0]], hand[conn[1]] cv2.line(frame, (int(p1.x * w), int(p1.y * h)), (int(p2.x * w), int(p2.y * h)), (0, 255, 0), 2) cv2.imshow(hand landmark, frame) if cv2.waitKey(1) 0xFF 27: break cap.release() cv2.destroyAllWindows()注意新版API要求先下载hand_landmarker.task模型文件这是Mediapipe官方发布的模型资产运行时会从本地加载。如果你看到代码里带着solutions但实际装的是新版Mediapipe一种省事做法是显式安装老版本比如指定0.8.x系列版本让源码和API保持一致这比改写所有调用更轻松。3. 把手部骨架变成特征向量关键点归一化、相对坐标与角度特征3.1 直接用关键点坐标训练为什么效果飘Mediapipe返回的21个关键点坐标是归一化到[0,1]比例的浮点数看似可以直接当特征实际上一用就会发现问题摄像头视野大小变化时同一手势的关键点坐标整体缩放手在画面里左右移动时所有坐标整体平移手离镜头远近不同坐标分布的尺度也不一样。把这些原始坐标直接丢给分类器模型学到的其实是“手在画面中的位置”而不是“手做出什么形状”。有个更隐蔽的坑是Mediapipe的z轴坐标。它在老版本里表示关键点相对于手腕的深度但这个深度是通过模型推断出来的噪声很大直接拼进特征向量反而带偏分类器。我一般把x和y作为主力特征z只用来辅助计算某些夹角不单独进特征。3.2 特征构造以手腕为原点做尺度归一化我的标准做法是以0号关键点手腕为原点把其余20个点的坐标转换为相对坐标再用4号关键点中指根部到手腕的距离做尺度归一化。这样得到的特征对平移和缩放不敏感。import math def extract_features(hand_landmarks) - list | None: # hand_landmarks 是 Mediapipe 返回的单手关键点对象 lm [(p.x, p.y, p.z) for p in hand_landmarks.landmark] wrist lm[0] # 相对坐标所有点以手腕为原点 rel [(x - wrist[0], y - wrist[1], z - wrist[2]) for x, y, z in lm] # 尺度归一化用中指根部到手腕的欧氏距离当“手掌宽度” scale math.sqrt( (rel[4][0] - rel[0][0]) ** 2 (rel[4][1] - rel[0][1]) ** 2 (rel[4][2] - rel[0][2]) ** 2 ) if scale 1e-6: return None norm [(x / scale, y / scale, z / scale) for x, y, z in rel] # 特征向量取 index 1~20 的 x, yz 轴噪声大默认丢弃 features [] for i in range(1, 21): features.append(norm[i][0]) features.append(norm[i][1]) return features参数说明scale 1e-6用来过滤失败帧当手部离镜头过近或检测质量差时这个距离会退化成一个极小值强行归一化会把噪声放大到失控。特征向量默认是40维20个点×2个坐标你可以测试加入z轴后准确率的变化但多数情况下z轴带来的是负优化。3.3 加入夹角特征与指尖距离比例纯坐标特征对“形变”比较敏感但对手指弯曲程度的鉴别力不够。手语里很多手势靠的就是手指关节的弯曲角度差异所以我会额外计算几个关键夹角拼接到坐标特征后面。def calc_angle(a, b, c) - float: # 计算向量 BA 与 BC 的夹角弧度 v1 (a[0] - b[0], a[1] - b[1]) v2 (c[0] - b[0], c[1] - b[1]) dot v1[0] * v2[0] v1[1] * v2[1] m1 math.hypot(v1[0], v1[1]) m2 math.hypot(v2[0], v2[1]) if m1 * m2 1e-6: return 0.0 return math.acos(max(-1.0, min(1.0, dot / (m1 * m2)))) def add_angle_features(norm_coords, features): # 拇指手腕(0)-腕掌(1)-拇指尖(4) features.append(calc_angle(norm_coords[0], norm_coords[1], norm_coords[4])) # 食指腕掌(5)-近指(6)-食指尖(8) features.append(calc_angle(norm_coords[5], norm_coords[6], norm_coords[8])) # 中指近指(9)-中指根(10)-中指尖(12) features.append(calc_angle(norm_coords[9], norm_coords[10], norm_coords[12])) # 无名指近指(13)-无名根(14)-无名尖(16) features.append(calc_angle(norm_coords[13], norm_coords[14], norm_coords[16])) # 小指近指(17)-小指根(18)-小指尖(20) features.append(calc_angle(norm_coords[17], norm_coords[18], norm_coords[20]))逻辑说明手指的弯曲会显著改变这三个关键点构成的夹角把5个手指的夹角加入特征后特征维度变成45维。这样做的好处是即使手在画面里旋转了一定角度夹角特征仍然保持相对稳定。注意Mediapipe关键点索引的语义并不直观建议对照官方手部连接图把索引打印一遍再写代码避免把食指和中指算反。匹配特征向量时记得将坐标归一化和角度计算合并成一个完整流程采集和推理阶段必须使用完全相同的特征顺序否则训练时是45维、推理时变成40维分类器会直接报维度错误。3.4 角度特征的真实增益与边界加不加夹角特征对结果的影响取决于你的手势集构成。如果只是识别“石头剪刀布”这种形状区分度很大的手势坐标特征就够用但手语里的数字1到10很多手势形状非常接近比如数字1和数字9都涉及食指动作这时候夹角的区分度优势就体现出来了。这里有个容易被忽略的边界条件Mediapipe对指尖的定位精度会随着手指并拢而下降。当两根手指紧贴在一起时指尖关键点可能落在两根手指中间导致夹角特征出现无规律的跳动。所以特征工程不是越多越好而是要在可视化调试中确认每个特征是否稳定。4. 用随机森林在本地训练一个手语分类器数据集采集、训练与模型落盘4.1 采集脚本与标签设计训练集的质量决定模型上限。手语数据集没有现成可用的常见做法是自己录。设计标签时不要直接用中文或拼音用一个整数映射表方便按键盘数字键采集。import csv import math import cv2 import mediapipe as mp # 标签映射数字键0-9对应手势编号 LABELS { 0: one, 1: two, 2: three, 3: four, 4: five, 5: six, 6: seven, 7: eight, 8: nine, 9: ten } hand mp.solutions.hands.Hands( static_image_modeFalse, max_num_hands1, min_detection_confidence0.6, min_tracking_confidence0.6, ) cap cv2.VideoCapture(0) with open(hand_data.csv, w, newline) as f: writer csv.writer(f) # 写入表头45个特征 label writer.writerow([ff{i} for i in range(45)] [label]) print(对准镜头做出手势按数字键0-9保存按ESC退出) while cap.isOpened(): ret, frame cap.read() if not ret: break frame cv2.flip(frame, 1) rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results hand.process(rgb) if results.multi_hand_landmarks: lm [p for p in results.multi_hand_landmarks[0].landmark] norm normalize_landmarks(lm) # 复用上一章的函数 feat build_feature_vector(norm) # 坐标 夹角拼接 if feat is None: continue key cv2.waitKey(1) if 48 key 57: # 数字键0-9 label LABELS[key - 48] writer.writerow(feat [label]) print(fsaved sample for {label}, total rows: {sum(1 for _ in open(hand_data.csv)) - 1}) cv2.imshow(collect, frame) if cv2.waitKey(1) 0xFF 27: break hand.close() cap.release() cv2.destroyAllWindows()逻辑说明采集时每按一次数字键就保存一帧特征到CSV。这里有个细节cv2.waitKey(1)在每次循环中已经调用过一次代码里又调用一次会导致按键响应变得迟钝。更稳妥的做法是单独用一次cv2.waitKey(1)接收按键并处理不要让两个waitKey叠加。收集样本时每个手势至少采集200到300帧并且要有意变换手的远近、左右位置和倾斜角度。只固定在一个位置采样的数据训练出来的模型换个距离就失灵。4.2 训练脚本随机森林的核心参数说明采集完数据后用随机森林训练一个基线分类器这是手语识别里性价比最高的做法。它的优点是特征维度不高时不需要调参而且能给出特征重要性排序。import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report import joblib df pd.read_csv(hand_data.csv) X df.drop(columns[label]).values y df[label].values X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy) model RandomForestClassifier( n_estimators300, max_depth12, min_samples_leaf2, random_state42, n_jobs-1, ) model.fit(X_train, y_train) y_pred model.predict(X_test) print(classification_report(y_test, y_pred)) joblib.dump(model, hand_model.joblib)参数说明n_estimators300在45维特征上已经足够稳定再加大收益很小训练时间却线性增长。max_depth12用来控制树的复杂度防止对采集时的特定光照和位置过拟合。stratifyy必须加它保证每个手势类别在训练集和测试集中的比例一致否则某个手势样本少时会直接漏进测试集导致指标失真。随机森林的缺点是无法处理时序它只对当前帧的静态形状做分类。当你看到准确率还不错但实际部署时预测结果在几个类之间跳来跳去那不是随机森林的问题而是静态分类器对帧间抖动天然敏感这就需要一个推理阶段的平滑策略。4.3 实时推理把分类器接到Mediapipe上训练好模型后实时识别脚本就变得非常简单核心流程是取帧、提关键点、构造特征、模型预测、画结果。import cv2 import mediapipe as mp import joblib model joblib.load(hand_model.joblib) labels [one, two, three, four, five, six, seven, eight, nine, ten] history [] hands mp.solutions.hands.Hands(max_num_hands1) cap cv2.VideoCapture(0) while cap.isOpened(): ret, frame cap.read() if not ret: break frame cv2.flip(frame, 1) rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results hands.process(rgb) if results.multi_hand_landmarks: lm [p for p in results.multi_hand_landmarks[0].landmark] feat build_feature_vector(normalize_landmarks(lm)) if feat is not None: pred model.predict([feat])[0] history.append(pred) # 取最近5帧的众数消除偶发抖动 if len(history) 5: history.pop(0) final max(set(history), keyhistory.count) cv2.putText(frame, str(final), (30, 60), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 255, 0), 3) cv2.imshow(sign, frame) if cv2.waitKey(1) 0xFF 27: break hands.close() cap.release() cv2.destroyAllWindows()逻辑说明history列表就是一个滑动的投票窗口长度为5。当某帧预测出错时单帧噪声被多数票压掉但代价是输出会延迟大约5帧这对交互场景完全可以接受。这里有个值得说的点实时推理里不要再用max_num_hands2之类的配置去追双手。静态手语识别领域单手的准确率远高于双手因为双手交叠时Mediapipe的关键点会互相遮挡产生大量低质量样本。先把单手做到稳定再考虑扩展。5. 避坑Mediapipe版本API、镜像翻转、摄像头拉流中断与特征抖动排查记录5.1 现象AttributeError: module mediapipe has no attribute solutions把老源码在2024年后发布的Mediapipe版本上直接运行会看到这个错误。原因是新版本把解决方案API从主模块里拆了出去mp.solutions不再自动暴露官方推荐改用mediapipe.tasks系列API。解决办法有两个。一是安装兼容的老版本这是最快路径pip install mediapipe0.8.11需要注意的是这个老版本在Python 3.11上也能正常工作但在3.12上装不上。二是按新API重写调用层也就是前面第二章展示的HandLandmarker写法。做项目迁移时我建议选第一个方案因为老版本的文档和示例代码数量庞大手语项目的坑往往在特征工程而不是API上不值得为了追新浪费排查时间。5.2 现象画面里的手是镜像的但关键点坐标跟直觉对不上摄像头读取的帧相当于你在镜子里的像左手动作显示成右手右手显示成左手。很多人第一次做手语手势识别时在画面上做cv2.flip(frame, 1)把图像镜像回来却忘了Mediapipe看到的是翻转前的帧导致检测正常、手势左右颠倒。解决办法是明确一条原则翻转必须在最前面完成且只做一次。先对原帧做cv2.flip把翻转后的RGB图像传给Mediapipe拿到关键点后再在原帧或翻转帧上绘制。如果你是在截取ROI区域后再检测记得ROI的坐标也要基于翻转后的帧计算否则画框和手的位置会错位。5.3 现象cap.isOpened()返回True但cap.read()一直返回FalseUSB摄像头在手语项目里偶尔会突然丢流尤其是在长时间运行后。常见表现是程序没有崩溃也没有报错就是画面冻结或一直黑屏。原因是摄像头驱动层面的缓冲区长死或者设备被系统重新枚举OpenCV的isOpened()只反映初始化状态不反映实时连接状态。解决办法是给读取加一个超时重置逻辑。连续读不到帧超过30帧时主动释放摄像头并延迟200毫秒后重新初始化。另外用cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)减小内部缓冲可以降低延迟和丢帧概率。手语识别是实时交互缓冲过大反而容易拿到很旧的帧。5.4 现象模型在测试集上准确率很高实时推理却疯狂跳变测试集用的是采集时同一批摄像头、同一光照下的数据所以指标虚高。实时光照变化、手部角度微调、指尖检测抖动都会让特征在小范围内波动而随机森林这类模型对特征微调非常敏感经常出现上一帧预测“three”下一帧变成“five”再下一帧又跳回来。解决办法分两层。第一层是特征层面的平滑不要直接用单帧特征可以对连续3帧的特征向量做加权平均。第二层是输出层面的投票用前面代码里的history众数窗口。经验是用窗口长度为5的投票配合特征平滑跳变能减少90%以上。如果仍然抖得厉害优先检查有没有真的做了尺度归一化和角度特征而不是调大投票窗口。5.5 现象样本采集时只固定在同一个位置部署后换个距离就全错这个问题几乎出现在每一个自制手语数据集里。按键盘保存样本时人的本能是把手放在画面中央一个舒服的位置导致所有样本的坐标分布区间很窄。模型学到的手势模式被“位置”绑架一旦人坐的位置稍微偏移特征分布整体漂移准确率断崖式下跌。解决的办法不出在模型上而在采集阶段。给每次按键保存的样本做一次数据增强对坐标做水平翻转、随机平移、随机缩放再写入CSV。def augment_features(features, label): # 水平翻转x坐标取反对应索引0, 2, 4, ... 为x维 flipped features.copy() for i in range(0, 42, 2): flipped[i] 1.0 - flipped[i] samples [(features, label), (flipped, label)] # 对原始特征加轻微扰动增强鲁棒性 for _ in range(2): noisy features np.random.normal(0, 0.01, sizelen(features)) samples.append((noisy, label)) return samples逻辑说明这里把挑选水平翻转、随机噪声作为补充样本扩充数据量。需要注意的是翻转后的x坐标取值范围从相对坐标变成以手腕为中心的反向值归一化时按手掌宽度除以后又落在相近的量级分类器能学到对称性。这种做法对数字手势有效对左右手有明确语义差异的手语手势需要谨慎使用翻转等于把左手变成了右手。5.6 现象安装时提示No module named sklearn或joblib缺失源码包里常常见到只写了pip install opencv-python mediapipe但训练脚本里导入了sklearn和joblib。按文档跑的时候前面都正常到训练那一步直接ModuleNotFoundError。解决办法是在项目根目录创建一个requirements.txt把所有依赖锁住避免换机器后逐个踩缺失模块的坑。6. 让识别结果可验证可进阶离线回放、静态/动态手势边界与抖动抑制6.1 离线回放验证把录制的视频逐帧判定准确率实时演示看着流畅不代表模型真正可用我习惯在部署前做一次离线回放验证。用OpenCV的VideoWriter录制一段测试视频录制时同时输出每帧的真实标签到文本文件然后离线跑一次推理脚本比对预测结果和标签文件统计每个手势的逐类准确率。import cv2 import joblib import mediapipe as mp model joblib.load(hand_model.joblib) label_map [one, two, three, four, five, six, seven, eight, nine, ten] cap cv2.VideoCapture(test_video.avi) hands mp.solutions.hands.Hands(max_num_hands1) ground_truth {} with open(labels.txt) as f: for line in f: frame_id, label line.strip().split(,) ground_truth[int(frame_id)] label correct, total 0, 0 frame_idx 0 while cap.isOpened(): ret, frame cap.read() if not ret: break rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results hands.process(rgb) if results.multi_hand_landmarks: feat build_feature_vector(normalize_landmarks( results.multi_hand_landmarks[0].landmark)) if feat is not None and frame_idx in ground_truth: pred model.predict([feat])[0] correct (pred ground_truth[frame_idx]) total 1 frame_idx 1 print(faccuracy on recorded video: {correct / max(total, 1):.2%})这样测出来的指标才有参考价值。书面上的推荐是每个手势录制至少30秒的有效动作覆盖左右移动和远近变化总计测试帧数不低于500帧。6.2 静态手语的边界与动态手势延伸何时该上LSTM或MediaPipe Model Maker这个项目的完整链路本质上是静态手势识别。手语里“数字”“字母”以及“好”“坏”这类能定格的动作都能覆盖但“谢谢”“你好”这类有时间序列的动作单帧随机森林是无解的。我见过不少人在这个边界上反复碰壁以为是数据量不够其实是方案选型错了。如果要做动态手语建议把每一帧的45维特征按时间顺序拼接成序列样本。采集时按住按键连续记录一个动作的30帧左右特征序列标签改为动作名称用Keras搭一个两层LSTM或者一维卷积分类器。MediaPipe官方也提供了Model Maker工具来做自定义手势识别它更适合“手型”级别的任务而手语的动态语义仍然需要你自己构建序列数据集。6.3 三个让结果稳定的工程习惯第一个习惯是固定摄像头分辨率为640×480并关闭自动白平衡。分辨率过高会让关键点检测变慢低速下用户会明显感觉到延迟自动白平衡会让颜色不断漂移间接影响检测置信度。第二个习惯是在界面左上角实时显示FPS和当前模型置信度方便在现场快速判断是检测问题还是分类问题。第三个习惯是把“检测到几只手”作为调试信息打印出来很多误识别其实是两只手同时入镜导致的。手语识别做到能演示、能交任务、能写清楚边界比盲目追求端到端模型更能让人踏实。我个人的习惯是把这些经验沉淀成一个可复用的Python模块特征提取函数和模型文件单独放下次换手势集的时候只改标签和重新采集不用重写推理逻辑。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Win/Mac 双端通用 OpenClaw 2.7.9 可视化落地完整实操流程:TaoToken 统一 Key 配置与验证 2026/9/28 19:44:14

Win/Mac 双端通用 OpenClaw 2.7.9 可视化落地完整实操流程:TaoToken 统一 Key 配置与验证

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

阅读更多 →
电子信息专业四年规划:嵌入式与芯片双赛道学习路线指南 2026/9/28 19:44:14

电子信息专业四年规划:嵌入式与芯片双赛道学习路线指南

选了电子信息专业,大学四年到底怎么过,可能是这个专业最让人焦虑的问题。尤其是当“嵌入式”和“芯片”这两个词同时摆在面前,很多人大一迷茫,大二乱学,大三发现自己简历上没东西可写。这篇文章是我结合身边同学、行业…

阅读更多 →
应届生产品经理面试全攻略:从 0 到 1 准备指南与 TaoToken 配置助力 2026/9/28 19:44:01

应届生产品经理面试全攻略:从 0 到 1 准备指南与 TaoToken 配置助力

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

阅读更多 →
Windows下编译IEC 61850依赖库:TaoToken统一Key接入VS工程配置骨架 2026/9/28 19:44:01

Windows下编译IEC 61850依赖库:TaoToken统一Key接入VS工程配置骨架

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

阅读更多 →
每天介绍一家新质生产力公司37 2026/9/28 19:44:01

每天介绍一家新质生产力公司37

https://mp.weixin.qq.com/s/Xe3JtKppkLaIOAHDZOP3mw

阅读更多 →
从0开始:小白也能学会的 Cline 配置 fetch MCP 服务器模块完整教程 2026/9/28 19:44:01

从0开始:小白也能学会的 Cline 配置 fetch MCP 服务器模块完整教程

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

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉