删除深度重算引擎;修好回放视频每帧重开文件导致的无法播放,运输控制改到状态轨主按钮 - What: 1) 彻底删除深度重算引擎:shared/.../record/depth.py(DepthRecomputer/DepthResult)与 depth_backends.py(BoxReplay/FingerReplay)、其专属测试 test_depth_replay.py,record/__init__ 不再导出,playback.py::replay_warnings 不再报 depth_recomputed;apps/studio/replay.py 由 515 行瘦身为只做读盘+游标+视频帧+提示,回放视图的 2D 面板只提供「原始图像」;session.json 的 depth.replay 由 recompute 改为 none;删除 31 个只剩深度使用的文案键(depth_*/warn_state_*/warn_reset_*),warn_config_changed 与 warn_sdk_changed 改为描述"由视频重算";ui_check 深度段、studio 两个深度用例、test_playback 三例、drive_shared 的 test_depth_replay 与 reproduce.py 的深度段一并清理(shared 套件 150→134 项)。2) 无法播放的根因是 RecordingReader.video_frame_at 每帧都 cv2.VideoCapture 重开并 seek:小片段已 ~10 ms/帧,1080p H.264 每次 seek 需从关键帧解码(上百 ms),而播放每 33 ms 要一帧且全在 UI 线程上,视频因此看着不动;改为按分段缓存解码器、顺序帧用 read() 步进(实测 10 ms → 0.5 ms/帧)、跳转才 seek,新增 RecordingReader.close() 释放。运输控制按用户建议上移到状态轨主按钮:toolbar.set_run_role("playback") 使回放视图的主按钮变成「▶ 回放」/「⏸ 暂停」(实时视图仍是「▶ 运行」),点按以 1× 推进游标(墙钟计时,漏拍不变慢)、到末尾自动停,拖动游标/框选/滚轮/拖总览条经 ForcePlotsPanel.timeline_taken_over 自动暂停,空格键同效;曲线表头不再放第二个播放按钮;按钮样式在回放角色下不再套用"停止"的红色语义。 - Why: 用户要求先清掉深度重算引擎、并反馈"现在无法播放视频",建议把上方播放按钮在历史回放形式下改为回放。 - Verification: ui_check.py 554 项 0 失败(新增 seek<250ms/步进<60ms 的解码预算、回放按钮文字随播放/暂停切换、手动拖游标即暂停、切回实时视图按钮恢复运行、按深度视图已移除);test_ui_smoke.py 71 项 0 失败;drive_shared.py 134 项 0 失败(深度引擎用例随代码删除);locale_studio.py 262 键齐全、zh==en;reproduce.py 退出 0;.repro/probe_play.py 实测按「回放」后 0.75 s 内游标推进 0.689 s、面板 12/12 帧都在更新;两张复核图(回放视图的「▶ 回放」、实时视图的「▶ 运行」)。 - Not in this change: 录制文件格式与 CSV 列序不变(raw_*.mp4 与 forces.csv 继续一起写);「由视频重算」复核模式保留(它复用实时管线,是有状态、只能顺序前进的一遍)。
This commit is contained in:
@@ -273,37 +273,28 @@ outputs/recordings/<UTC 时间戳>_session<NNNN>/
|
||||
(`calibration_session_*.json`,`force/calibration_session.py`),并可用「打开标定记录」
|
||||
重新载入检查。界面上的降采样 trace 只是预览,不是审计数据。
|
||||
|
||||
### 7.5 深度重算与游标同步(P1-3、P1-4)
|
||||
### 7.5 深度重算引擎(已删除)
|
||||
|
||||
- **不再重开回放位置**:`DepthRecomputer` 记录当前已读到的段内帧号,请求第 2 帧再请求第 3
|
||||
帧只多读 1 帧(旧实现每次都从头读,2 和 3 会落到 5);往回退才重开视频。
|
||||
- 每帧都执行**实时同一条链路**:盒子 `compute_deformation + compute_contact`,手指再加上
|
||||
`FingerRuntime` 的展开与有效区域(`_BoxReplay` / `_FingerReplay`)。
|
||||
- `config_name` 用**完整解析后的配置路径**(`load_fixed_mode`),不再缩减成父目录名或
|
||||
stem —— 那可能加载同名但不同的配置,而哈希校验还在比对原路径。
|
||||
- **算法参考状态**:SDK 的跟踪器/滤波是有状态的,离线复现需要历史。两条可用依据:
|
||||
1. 操作归零(`zeroing` 事件,带帧号)会清空跟踪器,因此从该帧重放是**精确**的;
|
||||
2. 录制开始前采集线程保留 `PREROLL_FRAMES`(30 帧,且不超过 192 MiB)的预处理帧,
|
||||
录制开始时写入 `preroll_0001.mp4`,`session.json` 记 `preroll_frames` /
|
||||
`preroll_segment`,回放先把它们喂给 SDK 再进入首帧。
|
||||
都不满足时(跨分段、无归零、无预卷)仍然重算,但结果带
|
||||
`state_approximate` / `state_across_segment` 提示,**不假装与当时一致**。
|
||||
- 回放游标与深度结果按**请求序号 + 帧号**绑定:等待期间移动游标会作废旧请求,结果回来
|
||||
只渲染属于当前帧的那一张;否则面板显示「当前游标位置尚未重算深度」,绝不复用旧图。
|
||||
这一节记录的 `DepthRecomputer` / `depth_backends`(离线把录制视频喂回 SDK 重算深度、按
|
||||
帧号增量读、归零/预卷恢复算法状态、请求绑定帧号)**已整体删除**:用户明确不需要"为回放再
|
||||
录/再算一遍深度"这条路径,回放视图只放录制的原始相机图像。要复核算法的当前做法是
|
||||
「视图 → 由视频重算力值」(把录制视频跑一遍采集管线,见 `docs/shell-lifecycle.md` §2.1),
|
||||
它复用实时那条链路,因此不再需要一份离线复现实现。
|
||||
|
||||
`session.json` 里的深度块保留(它说明"深度没有保存"这一事实),但 `replay` 字段改为
|
||||
`"none"`;`RecordingReader.replay_warnings()` 不再报 `depth_recomputed`。
|
||||
|
||||
---
|
||||
|
||||
## 7. 同步回放与深度重算
|
||||
## 7. 同步回放与深度(不保存深度)
|
||||
|
||||
**决定:不保存深度。** 回放时按录像与配置**离线重算**。
|
||||
|
||||
理由是体积:30 Hz、320×240 的 float32 深度每帧约 300 KB,一小时就是 ~16 GB;
|
||||
即使降频到 1 Hz 也要百兆级。所以 `session.json` 里明确写:
|
||||
**决定:不保存深度。** 理由是体积:30 Hz、320×240 的 float32 深度每帧约 300 KB,
|
||||
一小时就是 ~16 GB;即使降频到 1 Hz 也要百兆级。所以 `session.json` 里明确写:
|
||||
|
||||
```json
|
||||
"depth": {
|
||||
"stored": false,
|
||||
"replay": "recompute",
|
||||
"replay": "none",
|
||||
"quantity": "relative deformation / algorithm response, not a calibrated length",
|
||||
"method": "re-run the SDK over raw_*.mp4 with this config_ref",
|
||||
"config_sha256": "...",
|
||||
@@ -311,23 +302,26 @@ outputs/recordings/<UTC 时间戳>_session<NNNN>/
|
||||
}
|
||||
```
|
||||
|
||||
代价是重算要 SDK 能复现同样结果,因此 `RecordingReader.replay_warnings()` 会主动
|
||||
比对**当前配置文件哈希**与录制时的哈希、以及 SDK 版本,回放窗口顶部把这些提示出来:
|
||||
因此 `RecordingReader.replay_warnings()` 会比对**当前配置文件哈希**与录制时的哈希、以及
|
||||
SDK 版本,「由视频重算」前这些提示必须让操作者看到(回放视图里放在来源摘要的 tooltip 与
|
||||
一条 6 秒通知里):
|
||||
|
||||
| 提示 | 含义 |
|
||||
|---|---|
|
||||
| `depth_recomputed` | 深度来自离线重算,不是当时保存的数据(始终提示) |
|
||||
| `config_changed` | 配置文件已变,重算结果可能与当时不同 |
|
||||
| `config_changed` | 配置文件已变,由视频重算的结果可能与当时不同 |
|
||||
| `sdk_changed` | SDK 版本已变,重算结果可能不同 |
|
||||
| `config_missing` | 缺少配置哈希,无法校验一致性 |
|
||||
| `rows_skipped` | 有无法解析的 CSV 行被跳过 |
|
||||
| `frames_dropped` | 有帧在队列溢出时丢失,只留索引行 |
|
||||
| `out_of_order` | 旧版本写入的行序不是时间序 |
|
||||
|
||||
### 回放界面
|
||||
|
||||
回放**与实时是同一套界面**:`ui/playback_dialog.py` 与 `ui/replay_bar.py` 都已删除。
|
||||
`replay.py::ReplayController` 只读录制并发信号,主窗口把它接到同一套面板上——曲线表头的
|
||||
播放按钮就是播放头,来源槽在回放视图里换成「选择录制视频…」。布局、单位、看点与关闭流程
|
||||
见 `docs/shell-lifecycle.md` §2(含「由视频重算」复核模式)。
|
||||
回放**与实时是同一套界面**:`ui/playback_dialog.py`、`ui/replay_bar.py` 与深度重算引擎都
|
||||
已删除。`replay.py::ReplayController` 只读录制并发信号,主窗口把它接到同一套面板上——
|
||||
状态轨的主按钮在回放视图里变成「▶ 回放 / ⏸ 暂停」(`toolbar.set_run_role`),来源槽换成
|
||||
「选择录制视频…」。布局、单位、看点与关闭流程见 `docs/shell-lifecycle.md` §2
|
||||
(含「由视频重算」复核模式)。
|
||||
|
||||
- **一个游标驱动三处**:移动位置同时更新视频帧与三张曲线的游标线;并且通过 `cursor_moved`
|
||||
信号同步到主界面的曲线面板。
|
||||
@@ -339,10 +333,9 @@ outputs/recordings/<UTC 时间戳>_session<NNNN>/
|
||||
原始计数的曲线旁边会写着实时的 `0.0`,看起来就像"回放根本没打开"。
|
||||
实时视图仍是"最新样本就是游标",所以跟随状态下不额外读盘。
|
||||
- 帧未被写入视频时(记录队列曾溢出)明确提示,而不是显示上一帧冒充当前帧。
|
||||
- **深度不随录制保存,界面也不再提供深度视图**(用户明确不需要这条回放路径);需要复核
|
||||
算法时用「由视频重算」,它把录制视频重新跑一遍管线(含深度、形变与接触)。离线深度重算
|
||||
引擎(`ReplayController.request_depth` / `DepthRecomputer`)保留在 `replay.py` 里并有
|
||||
独立测试,但已没有界面入口。
|
||||
- **解码器常开**(`RecordingReader.video_frame_at`):以前每帧重开文件 + seek,1080p 下
|
||||
每帧上百毫秒,30 fps 播放时视频根本不动;现在按分段缓存解码器、顺序帧 `read()` 步进
|
||||
(实测 0.5 ms/帧),跳转才 seek。
|
||||
|
||||
两个必须知晓的边界:
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
| 视图 | 面板 | 曲线 | 比例(3D,2D,曲线,标定) |
|
||||
|---|---|---|---|
|
||||
| 实时监测 `live` | 2D 图像 + 力曲线(+ 手指三维) | 跟随实时 | `0, 360, 1080, 0` |
|
||||
| 历史回放 `replay` | 2D 图像 + 力曲线 + **回放条** | 读打开的录制;未打开时仍是实时跟随 | `0, 320, 1120, 0` |
|
||||
| 历史回放 `replay` | 2D 图像 + 力曲线(**与实时同布局**) | 读打开的录制;未打开时仍是实时跟随 | `0, 360, 1080, 0` |
|
||||
| 标定 `calibration` | 标定面板 + 力曲线 | 不变 | `0, 0, 560, 880` |
|
||||
| 自由 `custom`(启动默认) | 由视图菜单决定 | 不变 | 用户在分割条上摆的位置 |
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|---|---|
|
||||
| 实时监测 + 摄像机 | `摄像机 [编号] [搜索]` |
|
||||
| 实时监测 + 视频文件 | `使用摄像机` 按钮 + 摘要里的 `视频文件: xxx.mp4` |
|
||||
| 历史回放 | 不占位(回放条里有录制选择与路径) |
|
||||
| 历史回放 | 「选择录制视频…」按钮 + 摘要里的视频名 |
|
||||
|
||||
「用视频文件跑一次采集」仍从「文件 → 打开视频…」进入,`source_mode` / `video_path`
|
||||
偏好保留,但不再有一个需要先选「来源」才能用的下拉。
|
||||
@@ -61,10 +61,10 @@
|
||||
`ui/replay_bar.py`(进度条 + 录制目录选择)与 `PlaybackDialog` 都已删除。
|
||||
|
||||
- `apps/studio/src/orisys_studio/replay.py::ReplayController(QObject)`:录制读取、游标、
|
||||
离线深度重算引擎(daemon 线程 + 120 ms 轮询、请求绑定 `(_record_serial, seq, frame)`、
|
||||
旧结果一律丢弃;**界面已不提供深度视图**)、深度色标、回放提示(降采样 / 跨版本)。
|
||||
它不画任何东西,只发信号:`position_changed` / `frames_changed` /
|
||||
`status_changed` / `recording_changed`。
|
||||
回放提示(降采样 / 跨版本)。它不画任何东西,只发信号:`position_changed` /
|
||||
`frames_changed` / `status_changed` / `recording_changed`。深度重算引擎
|
||||
(`DepthRecomputer` / `depth_backends`)已随回放条一起删除——用户不需要这条回放路径,
|
||||
要复核算法就用「由视频重算」。
|
||||
- **选视频即选录制**:状态轨的「选择录制视频…」(`toolbar.btn_replay_video`)与
|
||||
「文件 → 打开视频…」都走 `_load_replay_video(path)`——视频所在目录就是录制目录,
|
||||
于是曲线自动配对同目录的 `forces.csv`。视频与 CSV 仍然同时记录(录制格式不变)。
|
||||
@@ -77,9 +77,15 @@
|
||||
- 2D 面板:`ArrowPanel.set_source_kind("replay")` 把视图下拉换成「原始图像」一项
|
||||
(`REPLAY_VIEW_MODES`;录制里没有光流,也没有存储深度),页脚显示「录制视频(原始相机
|
||||
图像)」并隐藏放大倍率与有效区域。
|
||||
- **游标就是播放头**:曲线表头的播放按钮(`chart.play` / `chart.pause`,编辑器习惯:
|
||||
空格键同效)以 1× 推进游标,到末尾自动停;拖动游标、框选、滚轮平移或拖总览条都会
|
||||
**自动暂停**(`ForcePlotsPanel.pause_playback`)。没有独立进度条。
|
||||
- **游标就是播放头,运输控制就是状态轨上那颗主按钮**:回放视图里
|
||||
`toolbar.set_run_role("playback")` 把它换成「▶ 回放」/「⏸ 暂停」(实时视图仍是「运行」),
|
||||
以 1× 推进游标,到末尾自动停;拖动游标、框选、滚轮平移或拖总览条都会**自动暂停**
|
||||
(`ForcePlotsPanel.timeline_taken_over` → `_pause_playback`)。空格键同效。没有独立进度条,
|
||||
曲线表头也不再放第二个播放按钮(一个运输控制,不会两处打架)。
|
||||
- **视频解码器常开**:`RecordingReader.video_frame_at` 以前每帧 `VideoCapture` 重开 + seek
|
||||
(小片段 10 ms,1080p H.264 上百 ms),30 fps 播放时每一拍都卡在 UI 线程上,视频看起来
|
||||
根本不动。现在按分段缓存一个解码器,**顺序帧用 `read()` 步进**(实测 0.5 ms/帧),
|
||||
跳转才 seek,`RecordingReader.close()` 负责释放。
|
||||
- **数值卡读游标处的那一帧**(`ForcePlotsPanel._readout_at_cursor`)。浏览历史或回放时,
|
||||
三个大数字是播放头所指的样本;跟随实时时"最新样本就是游标",不额外读盘。旧写法在回放
|
||||
时显示实时采集的最后一个样本,于是一张 7.5e5 原始计数的曲线旁边写着实时的 `0.0`。
|
||||
@@ -106,7 +112,7 @@
|
||||
| 用途 | 看当时的记录 | 复核算法版本(mp4 有损,数值与原记录会有差异) |
|
||||
|
||||
打开它时会立即开始这一遍(`_on_recompute_toggled` → `force_plots.set_playing(True)` →
|
||||
`_on_chart_play_toggled` → `_start_run`,只有一条启动路径,避免按钮与菜单各启动一次);
|
||||
`_on_transport_toggled` → `_start_run`,只有一条启动路径,避免按钮与菜单各启动一次);
|
||||
关闭时停止该遍并挂回 CSV。`_replay_owns_image()` 在这一遍运行期间为 False,2D 面板交给
|
||||
管线自己画。
|
||||
|
||||
|
||||
@@ -180,15 +180,15 @@ flow_ramp = 画布色, #6E4AD0, #FA02F3, #FF8A6B, #D8FF00
|
||||
| 品牌轨(`QFrame#brandBar`) | 28 px | logo + 字标 + 三个顶层视图(实时监测 / 历史回放 / 标定)+ 右侧产品名 |
|
||||
| 状态轨(`ToolbarWidget` 的 rail) | ~30 px | **传感器摘要按钮**、阶段、**当前视图的来源选择**(摄像机编号 + 搜索 / 使用摄像机)、标定状态、数据有效性、记录状态、记录/运行/重置/设置 |
|
||||
| 设置区(默认收起) | 0 / ~40 px | 单位、记录模式、预览 |
|
||||
| 回放条(仅历史回放视图) | ~50 px | 录制选择、录制信息、进度条、位置、单位、重算深度、提示行 |
|
||||
| ~~回放条~~(已取消) | 0 px | 回放视图与实时同布局:运输控制就是状态轨的主按钮(实时=运行,回放=回放/暂停) |
|
||||
|
||||
四点规则:
|
||||
|
||||
1. **传感器区是一个摘要按钮,不是两个下拉**。轨上只有 `BOX · box/sensor.json`;类型、配置
|
||||
与「当前生效的标定 / 最近导出的系数」都在它打开的 `SensorDialog` 里(见
|
||||
`docs/shell-lifecycle.md` §1.2)。摘要按钮属于状态轨,因此文本必须完整显示(见第 5 条)。
|
||||
2. **来源选择随视图**:实时视图显示摄像机编号 + 搜索;用视频文件采集时显示「使用摄像机」;
|
||||
回放视图不占位(回放条里有录制选择)。没有「来源」下拉,因此没有"先选来源才能用"的状态。
|
||||
2. **来源选择随视图**:实时视图显示摄像机编号 + 搜索;回放视图显示「选择录制视频…」,视频名
|
||||
写在来源摘要里(只在回放视图)。没有「来源」下拉,因此没有"先选来源才能用"的状态。
|
||||
3. **导航按钮在品牌底上取品牌前景色**。`navButton` 用 `brand_bar_fg_muted`,当前视图用
|
||||
`brand_bar_fg` + `navActive="true"`;两者都在 §2 的品牌底对比度审计里(7.67 / 12.94),
|
||||
不新增色值。
|
||||
|
||||
Reference in New Issue
Block a user