From 9b74c8253bc16df1c95208afaa13300d841c923b Mon Sep 17 00:00:00 2001 From: kang Date: Wed, 27 May 2026 01:05:40 +0800 Subject: [PATCH] auto-save 2026-05-27 01:05 (~2) --- .memory/worklog.json | 7 + index.html | 812 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 794 insertions(+), 25 deletions(-) diff --git a/.memory/worklog.json b/.memory/worklog.json index 0793401..88c2521 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -13,6 +13,13 @@ "message": "init: project scaffold", "hash": "d430655", "files_changed": 9 + }, + { + "ts": "2026-05-27T01:00:12+08:00", + "type": "commit", + "message": "auto-save 2026-05-27 01:00 (~2)", + "hash": "cdee6f6", + "files_changed": 2 } ] } diff --git a/index.html b/index.html index bed73eb..353e058 100644 --- a/index.html +++ b/index.html @@ -3,44 +3,806 @@ - FreeMoCap 源码解析 + FreeMoCap v1.8.2 源码深度解析 -
-

FreeMoCap 源码解析

-

开源动捕系统源码深度解析:多摄像头三角化 + MediaPipe pose + Blender 导出全链路

+
-
-

概述

-

待补充研究内容...

+ + +
+ +
+

FreeMoCap v1.8.2 源码深度解析

+

+ 用普通 webcam 做的开源 3D 动捕——标定、三角化、检测、后处理、Blender 导出全链路逐文件拆开。 +

+
+ ★ 8,840 + v1.8.2 + 14,210 LOC + 145 .py files + Python 3.10–3.12 + PySide6 + AGPL-3.0 + github.com/freemocap/freemocap +
+
+ 结论先行:FreeMoCap 主仓本身不是动捕算法库,而是一个 PySide6 GUI 编排器——把 7 个 skelly_* 子包和 aniposelib 串成端到端流水线。论真正算力,主仓不到 30%,70% 在外部依赖。要抄就抄 aniposelib 和 skellytracker,主仓的价值在 GUI 编排、状态零持久化、Tracker 策略模式 三个工程设计上。 +
+
+ +
+

1一句话定性

+

+ 把 4–6 个普通 webcam / GoPro / 手机摄像头围成半圆,用 ChArUco 棋盘标定相机几何,MediaPipe 在每路视频上跑 2D 关键点,DLT + 加权异常点剔除三角化成 3D 骨架,Butterworth + 刚体约束后处理,最后 Blender 子进程导出 .blend 场景。所有计算本地 CPU 跑,数据不出设备。 +

+

+ 官方话术 "实时动捕" 是录制时实时多机同步采集的实时,不是检测/三角化实时——后者是录完了离线后处理。这一点要在做决策前看清。 +

+
+ +
+

2依赖拓扑:算力在哪里

+

pyproject.toml:68-84,依赖列表就是这个项目的真实地图:

+ + + + + + + + + + + + + + +
外部包版本角色
skellycam2025.09.1097多摄像头采集(PySide6 widget)
skellytracker[all]2025.10.10242D 关键点检测(包 MediaPipe / YOLO / OpenPose)
skelly_synchronize2025.04.1037多机位时间戳软同步(音频 / 亮度)
skellyforge2024.12.1009后处理 task pipeline(插值 / 滤波 / 旋转)
skelly_viewer2025.04.10283D 骨架可视化
ajc27_freemocap_blender_addon2026.04.1039Blender 桥接插件
aniposelib0.4.3多视角几何真核心(DLT、Bundle Adjustment、外参)
opencv-contrib-python4.8.*ChArUco 检测、相机标定底层
PySide66.6–6.8GUI 框架
pydantic2.*数据 schema
+
+

抄什么 ≠ 用什么。如果只想要"多相机三角化"这件事,aniposelib 比 FreeMoCap 主仓干净十倍——后者只是包了一层 GUI。

+
+
+ +
+

3入口与主流程

+ +

3.1 程序入口

+

freemocap/__main__.py:24qt_gui_main() 是唯一入口,CLI 一行带过:

+
def main():
+    ...
+    qt_gui_main()  # gui/qt/main_window/freemocap_main.py:29-59
+

启动后进 PySide6 主事件循环,支持 EXIT_CODE_REBOOT 重启机制(freemocap_main.py:87)。

+ +

3.2 主窗口 5 大 Tab

+

MainWindow(QMainWindow) @ gui/qt/main_window/freemocap_main_window.py:92-150

+ + + + + + + + + +
TabWidget来源
0HomeWidget本仓
1SkellyCamWidget(录制)外部 skellycam
2SkellyViewer(3D 可视化)外部 skelly_viewer
3DirectoryViewWidget本仓
4ActiveRecordingInfoWidget本仓
+

右侧 ControlPanelWidgetwidgets/control_panel/control_panel_dock_widget.py:32-62)3 子 Tab:摄像头配置 → 数据处理 → 导出。

+ +

3.3 端到端流水线

+
[1] 用户 → "Start New Session" → handle_start_new_session_action() freemocap_main_window.py:195 +[2] 录制 Tab:SkellyCamWidget 启动多机位录制(外部) +[3] 录完发信号 videos_saved_to_this_folder_signal freemocap_main_window.py:232 +[4] 若 "Auto Process Videos" 勾上:自动点 Process 按钮 freemocap_main_window.py:177 +[5] 后台处理(独立子进程): + 标定 ─ CHARUCO 视频 → camera_calibration.toml + ↓ + 软同步 ─ skelly_synchronize(audio / brightness) + ↓ + 2D 检测 ─ skellytracker → MediaPipe / YOLO / OpenPose + ↓ + 三角化 ─ aniposelib DLT + 加权异常点剔除 + ↓ + 后处理 ─ skellyforge: 插值 → Butterworth → 找参考帧 → 坐标旋转 + ↓ + 刚体约束 ─ enforce_rigid_bones + ↓ + 质心 ─ segment COM + total body COM + ↓ + 导出 ─ CSV / NPY / Blender .blend / Jupyter +[6] processing_finished_signal → 自动加载到 SkellyViewer Tab
+
+ +
+

4标定 + 三角化(招牌核心)

+ +

4.1 CHARUCO 棋盘定义

+

core_processes/capture_volume_calibration/charuco_stuff/charuco_board_definition.py:7-44

+
@dataclass
+class CharucoBoardDefinition:
+    name: str
+    number_of_squares_width: int
+    number_of_squares_height: int
+    black_square_side_length: int
+    aruco_marker_length_proportional: float
+    aruco_marker_dict: Dict = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_4X4_250)
+

预设两块板:7×5(默认)和 5×3(小空间备选),都用 DICT_4X4_250 字典,marker = 0.8 × square。

+ +

4.2 标定流程

+

主入口:AniposeCameraCalibrator @ anipose_camera_calibration/anipose_camera_calibrator.py:42-87

+
    +
  1. 内参(每相机):CameraGroup.calibrate_videos() @ freemocap_anipose.py:2178-2202cv2.initCameraMatrix2D() 从 ChArUco 角点初始化(:2091)。
  2. +
  3. 外参初始化:get_initial_extrinsics() @ :499-513,调 aniposelib 的 extract_rtvecs
  4. +
  5. 相机图连通性get_calibration_graph() @ :387-403
  6. +
  7. Bundle Adjustment 迭代bundle_adjust_iter() @ :1145-1265
  8. +
+ +

4.3 三角化:Numba 加速的 DLT

+

freemocap_anipose.py:55-67

+
@jit(nopython=True, parallel=False)
+def triangulate_simple(points, camera_mats):
+    num_cams = len(camera_mats)
+    A = np.zeros((num_cams * 2, 4))
+    for i in range(num_cams):
+        x, y = points[i]
+        mat = camera_mats[i]
+        A[(i * 2): (i * 2 + 1)] = x * mat[2] - mat[0]
+        A[(i * 2 + 1): (i * 2 + 2)] = y * mat[2] - mat[1]
+    u, s, vh = np.linalg.svd(A, full_matrices=True)
+    p3d = vh[-1]
+    p3d = p3d[:3] / p3d[3]  # 齐次坐标归一化
+    return p3d
+

线性 DLT:构造 4×N 矩阵 → SVD → 取最小奇异向量 → 齐次归一。@jit(nopython=True) 让单点三角化贴近 C 速度。

+ +

4.4 招牌设计:加权异常点剔除三角化

+

freemocap_anipose.py:88-190triangulate_with_outlier_rejection()

+

不同于硬 RANSAC 的"要么用要么扔",FreeMoCap 走柔和路线:

+
全相机三角化 → 计算重投影误差 + ↓ 若超过 target_reprojection_error +枚举"丢 1 / 2 / ... / maximum_cameras_to_drop 个相机"的所有子集 + ↓ 每个子集都三角化一次 + 算误差 +赋权:weight = exp(-5.0 × error / target_reprojection_error) + ↓ +所有子集的 3D 点加权平均 → 输出最终 3D + 每相机置信度权重
+

参数(freemocap_anipose.py:91-93):

+
+ minimum_cameras_for_triangulation = 2 + maximum_cameras_to_drop = 1 + target_reprojection_error = 0.01 +
+
+

为什么牛:硬剔除会丢信息,软剔除(指数权重)让"还行"的相机也能贡献。对低成本多机位(4–6 个 webcam,难免有 1–2 个角度差)尤其重要。

+
+ +

4.5 重投影误差诊断

+

freemocap_anipose.py:1105-1143CameraGroup.reprojection_error() 返回 (n_cams, n_points, 2) 误差张量。diagnostics/calibration/calculate_calibration_diagnostics.py:12-46 输出 CSV:相邻 ChArUco 角点距离的 mean/median/std/偏差。

+ +

4.6 多机位同步:纯软件

+

没有硬件触发synchronize_videos_thread_worker.py:6,49-61 走两条路:

+
from skelly_synchronize.skelly_synchronize import (
+    synchronize_videos_from_audio,         # 默认:音频对齐
+    synchronize_videos_from_brightness,    # 备选:亮度跳变
+)
+

录制时记每帧时间戳到 synchronized_videos/timestamps/*.npy,对齐在后处理阶段做:找音频对齐峰 → 算相对偏移 → 帧重索引。

+
+ +
+

52D 关键点检测(Tracker 策略模式)

+ +

5.1 支持的 Tracker

+ + + + + + + + +
Tracker状态关键 file:line
MediaPipe Holistic(默认)主流程post_processing_parameter_models.py:6
YOLO实验性experimental/alternative_trackers/run_yolo.py:7
OpenPose实验性experimental/alternative_trackers/run_openpose.py:8
YOLOMediapipeComboYOLO crop → MP poseimage_tracking_pipeline_functions.py:85-86
+

默认 tracker 写死在 recording_info_model.py:42active_tracker="mediapipe"

+ +

5.2 检测入口(极薄)

+

process_motion_capture_videos/processing_pipeline_functions/image_tracking_pipeline_functions.py:26-98

+
def run_image_tracking_pipeline(...) -> np.ndarray:
+    image_data_numCams_numFrames_numTrackedPts_XYZ = process_folder_of_videos(
+        model_info=processing_parameters.tracking_model_info,
+        tracking_params=processing_parameters.tracking_parameters_model,
+        synchronized_video_path=synchronized_videos_folder_path,
+        output_folder_path=output_data_folder_path,
+        num_processes=tracking_params.num_processes,
+    )
+

外包装薄如纸——实际检测全在 skellytracker.process_folder_of_videos() 里。FreeMoCap 不关心 tracker 内部,只接收统一 ndarray。

+ +

5.3 数据格式(钉死)

+

tests/test_image_tracking_data_shape.py:26-61 把 shape 钉死成:

+
shape = (num_cameras, num_frames, num_landmarks, 3)
+                                                  ^^^^^^^^^^^
+                                                  xy + confidence
+

第 4 维是 3 不是 2——多出来的是 confidence。3D 三角化阶段才会丢掉 conf 通道。

+ +

5.4 并发:multiprocessing

+

image_tracking_pipeline_functions.py:89-96tracking_params.num_processes。默认 multiprocessing.cpu_count() - 1。每路视频独立进程,避开 GIL。

+ +

5.5 Landmark 映射:属性反射

+

post_process_skeleton_data/post_process_skeleton.py:130-136

+
def get_landmark_names(model_info: ModelInfo) -> list:
+    if hasattr(model_info, "body_landmark_names"):
+        return model_info.body_landmark_names
+    elif hasattr(model_info, "landmark_names"):
+        return model_info.landmark_names
+

属性反射 + duck typing——加新 tracker 不改主流程,只要 ModelInfo 子类提供 *_landmark_names 字段。

+
+ +
+

63D 后处理(skellyforge 任务管道)

+ +

6.1 Butterworth 滤波参数

+

data_layer/recording_models/post_processing_parameter_models.py:25-28

+
class ButterworthFilterParametersModel(BaseModel):
+    sampling_rate: float = 30
+    cutoff_frequency: float = 7
+    order: int = 4
+

30 fps、7 Hz 截止、4 阶——典型人体运动学滤波(人手脚最快动作 ~10 Hz 上限)。

+ +

6.2 任务管道顺序

+

post_process_skeleton.py:69-104 走 skellyforge TaskWorkerThread,固定顺序(:83):

+
+ TASK_INTERPOLATION + TASK_FILTERING + TASK_FINDING_GOOD_FRAME + TASK_SKELETON_ROTATION +
+

每个任务独立 boolean 开关,挂在 PostProcessingParametersModel 上。

+ +

6.3 刚体约束(自实现,不依赖外部)

+

post_process_skeleton_data/enforce_rigid_bones.py

+
    +
  • calculate_bone_lengths_and_statistics() @ :10-41——每帧算骨长,求 median / stdev
  • +
  • enforce_rigid_bones() @ :44-86——中位数骨长标准化 + 子关节级联传播
  • +
+
direction = (distal - proximal) / |distal - proximal|
+adjustment = (desired_length - current_length) * direction
+rigid_marker_data[distal_marker][frame] += adjustment
+adjust_children(distal_marker, frame, adjustment, ...)  # 递归
+

把当前帧骨长拉回到序列中位数,再把偏移传给下游所有子关节(保持相对位姿)。处理 2D 检测误差导致的"骨头忽长忽短"。

+ +

6.4 坐标系对齐:90° 绕 X 轴

+

utilities/geometry/rotate_by_90_degrees_around_x_axis.py:4-14

+
swapped[:, :, 0] = raw[:, :, 0]    # X 不变
+swapped[:, :, 1] = raw[:, :, 2]    # Y ← Z
+swapped[:, :, 2] = -raw[:, :, 1]   # Z ← -Y
+

从"摄像头坐标系(Z 朝前)"换到"人体运动学坐标系(Y 朝上)"。

+ +

6.5 质心(替代关节角度)

+

post_process_skeleton_data/calculate_center_of_mass.py:12-141 返回:

+
    +
  • segment_com_data:shape (frames, segments, 3)
  • +
  • total_body_com:shape (frames, 3)
  • +
+
+

注意:v1.8.2 不输出原生关节角度(Euler / 四元数),只有关键点位置 + 质心。要做关节角度分析得拿 NPY 自己算。

+
+
+ +
+

7数据导出

+ +

7.1 格式矩阵

+ + + + + + + + + + +
格式路径用途
NPYoutput_data/mediapipe_skeleton_3d.npy主产物 (frames, markers, 3)
CSV (by_trajectory){recording}_by_trajectory.csv每帧一行
CSV (by_frame tidy){recording}_by_frame.csvtidy:frame/timestamp/model/keypoint/x/y/z/err
JSON{recording}_by_frame.json完整原始数据
.blend{recording}.blendBlender 场景(带骨架 armature)
.ipynbauto_generated_notebook.ipynbJupyter 数据探索模板
+

不支持 FBX / glTF——要用得手动从 .blend 二次导出。

+ +

7.2 Blender 桥接(最有意思的设计)

+

策略:不用 bpy 内嵌进程,而是外挂 Blender 可执行作为子进程

+

core_processes/export_data/blender_stuff/export_to_blender/methods/ajc_addon/run_ajc_addon_main.py:73-99

+
command_list = [
+    str(blender_exe_path),
+    "--background",          # 无 GUI
+    "--python",
+    simple_run_script,         # methods/ajc_addon/run_simple.py
+    "--",
+    str(recording_folder_path),
+    str(blender_file_path),
+]
+blender_process = run_subprocess(command_list=command_list)
+while True:
+    output = blender_process.stdout.readline()
+    if blender_process.poll() is not None:
+        break
+    if output:
+        logging.debug(output.strip().decode())
+blender_process.terminate()
+

子进程脚本(run_simple.py:4-8)调用外部插件:

+
from ajc27_freemocap_blender_addon.main import ajc27_run_as_main_function
+ajc27_run_as_main_function(recording_path=..., blend_file_path=...)
+

插件首次运行由 bpy_install_addon.py:33-51 现场安装:打 ZIP → bpy.ops.preferences.addon_installbpy.ops.wm.save_userpref

+

Blender 路径自动检测(get_best_guess_of_blender_path.py:27-86):Windows 扫 Program Files/Blender Foundation,macOS /Applications/Blender.app/Contents/MacOS/Blender,Linux /usr/bin/blender

+
+

为什么聪明:bpy 作为 Python 库装起来很折磨(要 Blender 版本对齐)。子进程模式把 Blender 当成黑盒服务,FreeMoCap 主进程的 Python 环境干净。

+
+ +

7.3 列名约定(tracker-aware)

+

post_process_skeleton_data/split_and_save.py:67-121

+
# 如果 model_info 有具名 landmark:
+column_names.append(f"{category}_{name}_{x|y|z}")    # body_nose_x, body_left_shoulder_y
+# 否则降级到数字索引:
+column_names.append(f"{category}_{i:04d}_{x|y|z}")    # body_0000_x, body_0001_x
+

同时按 category 切(:32-64):body / left_hand / right_hand / face

+ +

7.4 时间戳:CSV 不带

+

CSV 行号即帧索引。帧率元数据存在 PostProcessingParametersModel.framerate(默认 30),不内嵌到导出文件。精确时序分析得拿 synchronized_videos/timestamps/*.npy 配合用。

+
+ +
+

8Skeleton Schema(统一骨架定义)

+ +

8.1 核心 Pydantic 模型

+

data_layer/skeleton_models/skeleton.py:13-133

+
class Skeleton(BaseModel):
+    model_config = ConfigDict(arbitrary_types_allowed=True)
+    markers: MarkerInfo
+    num_tracked_points: int
+    segments: Optional[Dict[str, Segment]] = None
+    marker_data: Dict[str, np.ndarray] = {}             # 每点 (frames, 3)
+    virtual_marker_data: Dict[str, np.ndarray] = {}
+    joint_hierarchy: Optional[Dict[str, List[str]]] = None
+    center_of_mass_definitions: Optional[Dict[str, SegmentAnthropometry]] = None
+    num_frames: Optional[int] = None
+ +

8.2 段定义

+

data_layer/skeleton_models/segments.py:8-17

+
class Segment(BaseModel):
+    proximal: str
+    distal: str
+
+class SegmentAnthropometry(BaseModel):
+    segment_com_length: float       # 质心位置占段长比例
+    segment_com_percentage: float   # 段占全身质量比例
+ +

8.3 虚拟关键点

+

marker_info.py:38-68 支持加权平均生成虚拟点,典型如 mid_shoulder = 0.5 * left_shoulder + 0.5 * right_shoulder。这让上层算法(质心、骨长)能用稳定的解剖学参考点,不受单点遮挡影响。

+
+ +
+

9GUI / 数据层架构

+ +

9.1 RecordingInfoModel:路径属性生成器

+

data_layer/recording_models/recording_info_model.py:41-217

+
class RecordingInfoModel:
+    @property
+    def synchronized_videos_folder_path(self) -> str: ...
+    @property
+    def data_2d_npy_file_path(self) -> str: ...
+    @property
+    def data_3d_npy_file_path(self) -> str: ...
+    @property
+    def calibration_toml_path(self) -> str: ...
+    @property
+    def status_check(self) -> Dict[...]:    # 递归查文件存在性
+        ...
+

不存路径字符串、只用属性生成器——根路径变了之后所有派生路径自动跟。status_check 是状态机的反面:不维护"录制完成 / 处理完成"标志位,而是每次按需扫文件存在性。

+ +

9.2 录制目录结构

+
freemocap_data/recording_sessions/ +└── session_<timestamp>/ + └── recording_<timestamp>/ + ├── synchronized_videos/ + │ ├── camera_0.mp4 + │ ├── camera_1.mp4 + │ └── timestamps/ + │ └── camera_*_timestamps.npy + ├── annotated_videos/ # 可选:2D 叠加 + ├── output_data/ + │ ├── mediapipe_2dData_*.npy + │ ├── raw_data/ + │ │ ├── mediapipe_3dData_*.npy + │ │ └── mediapipe_3dData_*_reprojectionError.npy + │ ├── center_of_mass/ + │ │ └── mediapipe_total_body_center_of_mass_xyz.npy + │ ├── mediapipe_skeleton_3d.npy + │ └── recording_parameters.json + ├── <recording>_camera_calibration.toml + └── <recording>.blend
+

文件名常量集中在 system/paths_and_filenames/file_and_folder_names.py:1-83

+ +

9.3 后台任务:QThread + multiprocessing 双层夹心

+

gui/qt/workers/process_motion_capture_data_thread_worker.py:16-76

+
class ProcessMotionCaptureDataThreadWorker(QThread):
+    in_progress = Signal(...)
+    finished = Signal(bool)
+
+    def run(self):
+        self._process = multiprocessing.Process(
+            target=process_recording_folder,
+            args=(...),
+        )
+        self._process.start()
+        while self._process.is_alive():
+            time.sleep(0.01)
+            if not self._queue.empty():
+                record = self._queue.get()
+                self.in_progress.emit(record)
+        self.finished.emit(self._success)
+
    +
  • QThread 外层:Qt 信号槽友好、生命周期可控、可发 in_progress 给 UI
  • +
  • multiprocessing.Process 内层:真正干活,绕开 GIL
  • +
  • multiprocessing.Queue:从工作进程把日志/进度推回 QThread
  • +
+

GUI 应用的"重活外包"教科书模式:UI 线程绝对不卡,重计算独立崩溃也不杀主进程。

+
+ +
+

10招牌设计 Top 10

+
    +
  1. 加权异常点剔除三角化freemocap_anipose.py:88-190)— exp(-5·error/threshold) 软权重,多相机时鲁棒胜过硬 RANSAC
  2. +
  3. Numba @jit(nopython=True) 单点 DLT:55-67)— Python 几何运算贴近 C
  4. +
  5. RecordingInfoModel 属性生成器 + status_check — 不维护状态机,按需扫文件
  6. +
  7. QThread × multiprocessing.Process × Queue × Signal 四件套 — GUI 重活外包标准范式
  8. +
  9. Tracker 策略模式(ModelInfo + duck typing) — 加新 tracker 不动主流程
  10. +
  11. {tracker}_data_2d.npy 前缀命名 — 多算法结果共存对比
  12. +
  13. skellyforge TaskWorkerThread 管道 — 可拼装的后处理 task 列表
  14. +
  15. 刚体骨长中位数约束 + 子树级联传播enforce_rigid_bones.py)— 不用 IK 就能压住骨头抖
  16. +
  17. Blender 子进程模式--background --python script.py,主进程 Python 环境干净
  18. +
  19. CHARUCO + 软件音频/亮度同步 — 用 webcam 也能搞动捕
  20. +
+
+ +
+

11局限性(别被官方话术骗了)

+ + + + + + + + + +
宣传实情
"实时动作捕捉"离线后处理。录的时候是实时多机同步采集,但 2D 检测 / 三角化 / 后处理全是录完了一起跑
"实时关节角度"不输出关节角度。v1.8.2 只有关键点位置和质心,关节角度得自己算
"支持任意 tracker"主流程默认只接 MediaPipe;YOLO / OpenPose 在 experimental/ 没上主线
"GPU 加速"主仓不暴露 GPU 配置,全靠 MediaPipe 内部判断
"媲美 Vicon"重投影误差量级 ~ 像素级;Vicon 亚毫米级标定。差 2–3 个数量级
+
+ +
+

12适合 / 不适合

+
+
+

✅ 适合

+
    +
  • 教学 / 科研动作分析(人体生物力学、运动学)
  • +
  • 低成本 3D 角色动画毛坯(导 Blender 后人手 retarget)
  • +
  • 隐私敏感场景(数据全本地)
  • +
- -
-

核心发现

-

待补充...

+
+

❌ 不适合

+
    +
  • 实时游戏 / VR 全身追踪
  • +
  • 高精度临床步态分析(亚毫米级)
  • +
  • 商业产品发行(AGPL-3.0 — SaaS 化要开源整个调用链)
  • +
+
+ +
+

13延伸思考(可改造方向)

+
    +
  1. 抽离 aniposelib + 加权剔除算法:单独打个 Python 库给所有"多相机三角化"业务用,不必带 PySide6。
  2. +
  3. 替换 skellyforge 后处理:上 Kalman 滤波 / 双向 LSTM 时序去抖,比 Butterworth 强。
  4. +
  5. 加关节角度计算:拿 Skeleton.joint_hierarchy + Pydantic 模型,每段两个 segment 算夹角,输出 Euler / 四元数。
  6. +
  7. GPU MediaPipe:用 mediapipe.tasks.python.vision.PoseLandmarker 替代旧 holistic API,启 GPU delegate。
  8. +
  9. WebRTC 实时模式:skellycam 出 RTP 流 → 服务器侧实时 2D + 增量三角化 → 真做到"实时动捕"。但要硬件触发同步才靠谱。
  10. +
+
+ +
+

14文件级索引(快速查表)

+ + + + + + + + + + + + + + + + + + + + + + + + + +
模块关键文件
入口freemocap/__main__.py:24gui/qt/freemocap_main.py:29
主窗口gui/qt/main_window/freemocap_main_window.py:92-150
CHARUCO 板core_processes/capture_volume_calibration/charuco_stuff/charuco_board_definition.py:7-44
标定主入口.../run_anipose_capture_volume_calibration.py:17-35
DLT 三角化.../freemocap_anipose.py:55-67
加权异常点剔除.../freemocap_anipose.py:88-190
Bundle Adjustment.../freemocap_anipose.py:1145-1265
重投影误差.../freemocap_anipose.py:1105-1143
软同步.../synchronize_videos_thread_worker.py:6,49-61
2D 检测入口.../image_tracking_pipeline_functions.py:26-98
Tracker 参数data_layer/recording_models/post_processing_parameter_models.py:25-44
后处理任务管道core_processes/post_process_skeleton_data/post_process_skeleton.py:69-104
刚体约束.../enforce_rigid_bones.py:10-86
坐标系旋转utilities/geometry/rotate_by_90_degrees_around_x_axis.py:4-14
质心计算.../calculate_center_of_mass.py:12-141
Blender 子进程.../export_to_blender/methods/ajc_addon/run_ajc_addon_main.py:73-99
Blender 路径检测.../get_best_guess_of_blender_path.py:27-86
Skeleton schemadata_layer/skeleton_models/skeleton.py:13-133
RecordingInfoModeldata_layer/recording_models/recording_info_model.py:41-217
后台任务 workergui/qt/workers/process_motion_capture_data_thread_worker.py:16-76
跨平台路径system/paths_and_filenames/path_getters.py:31-250
+
+ + + +
+
+ + +