回放并入主窗口,并修掉开场尖峰 / 录制时长 / 录制帧率 / 回放被摄像头覆盖等 9 项评审问题 - What: 回放不再是独立窗口——删除 PlaybackDialog,拆成 replay.py::ReplayController(读盘、游标、深度重算,只发信号)与 ui/replay_bar.py(录制选择、可拖拽进度条、单位、重算深度、提示行),品牌轨「历史回放」直接换主窗口布局,文件菜单两条入口都切到该视图,曲线改读 RecordingCurveSource(区间按需读盘 + 缓存包络),2D 面板切「原始图像 / 深度图」;传感器与标定合并到 SensorDialog(类型/配置下拉 + 当前生效标定 + 最近导出系数),标定面板加纵向滚动区、九按钮两行、六列表头 ResizeToContents。评审 9 项:1) 开场尖峰两个根因——push() 遇单位变化只记 _unit 而保留旧单位样本(raw 计数被画在牛顿轴上),改为「切换即换单位」:清缓冲按新单位重建、触发切换的那一帧仍刷数值卡;_start_run 先 session_store.reset() 再 set_store(),新会话不再带上次的尾巴(复现脚本 .repro/probe_item1.py:旧 39 样本峰值 9.841 → 新 37 样本峰值 2.390)。2) 箭头页脚改为「箭头按位移放大 ×{factor}」。3) 表头单位芯片由只读 QLabel 改为可点按钮,一次点击同时改曲线、数值卡与设置区下拉。4-6) 全程总览/框选/返回最新 改为 ui/icons.py 按主题令牌运行时绘制的图标,tooltip 与 accessibleName 保留文字,全程总览区域名仍是文字。7) stats() 在录制进行中即返回 _last_t - _t0,记录条开始计时(此前只在 _finalise 写、整场停在 00:00.0)。8) 容器 fps 改用传感器配置的速率(packet.fps 是"每秒完成多少帧"的计数器,突发/文件源会读到 48),视频按 1/fps 节流并把超前的帧计入 resampled_video(frames.csv/forces.csv 一行不少,报告写明原因),session.json 同时记 fps 与 measured_fps。9) _replay_owns_image() 让回放视图独占 2D 面板,实时帧不再覆盖;push() 在录制源挂载时连单位都不切,曲线/数值卡/单位一并归录制。附带:数值卡改读游标处样本(_readout_at_cursor)、回放按录制实际有的单位打开(_replay_unit_for + ReplayController.set_unit,避免 raw-only 录制在 newton 偏好下画三张空图)、视频速率下限。 - Why: 用户评审 9 点,其中 1/7/8/9 是代码缺陷(开场尖峰、录制时长不更新、录制 48fps 与实际 30fps 不符、回放时 2D 面板仍被摄像头刷新),2-6 是可读性问题(×2 含义不明、单位与视图控制应可点/应符号化)。 - Verification: ui_check.py 524 项 0 失败(新增 chart header and unit chip / acquisition correctness / replay owns the 2D pane 三段)、test_ui_smoke.py 69 项 0 失败(新增 7 个回归用例:单位切换不混单位、单位芯片、图标语义、录制中时长、传感器帧率+节流、回放独占面板、回放游标读数与单位回退)、drive_shared.py 146 项 0 失败、locale_studio.py(268 键齐全、zh==en、prefs 对齐)、reproduce.py、ui_snapshot.py 四张复核图(深色实时/回放、浅色 1280x720 实时与标定)。 - Not in this change: 录制文件格式(forces.csv 列序、frames.csv、session.json 路径与分段规则)不变,节流只影响"哪些帧进视频",并显式计数上报;三维面板仍是占位符。

This commit is contained in:
ykcheungab
2026-09-13 20:46:27 +08:00
parent 35e86ec1f7
commit 824544fc7a
20 changed files with 3129 additions and 834 deletions
+29 -17
View File
@@ -58,13 +58,10 @@
"cancel": "Cancel"
},
"toolbar": {
"source": "Source",
"source_camera": "Camera",
"source_video": "Video file",
"search_cameras": "Search",
"cam_id": "Cam ID",
"browse_video": "Browse…",
"video_placeholder": "No video selected",
"cam_id": "Camera",
"use_camera": "Use camera",
"use_camera_tip": "Go back to acquiring from a camera (a video file is in use)",
"preview": "Preview",
"preview_stop": "Stop preview",
"run": "Run",
@@ -81,7 +78,7 @@
"units_newton": "Newton",
"units_raw": "Raw",
"settings": "Settings",
"settings_tip": "Show or hide the source, camera, unit and product settings"
"settings_tip": "Show or hide the unit, record-mode and preview controls"
},
"units": {
"newton_short": "N",
@@ -92,6 +89,18 @@
"config": "Sensor config",
"type_tip": "Pick the product/sensor: box, mini or finger. It decides which config files and algorithm parameters exist.",
"config_tip": "The algorithm config file (config/*.json) this sensor uses. Switching the sensor switches the available configs with it.",
"summary": "{type} · {config}",
"dialog_title": "Sensor and calibration",
"dialog_tip": "Pick the sensor type and config, and read the calibration in effect and the last exported coefficients",
"calib_section": "Calibration in effect",
"calib_version": "Version confirmed by the device",
"calib_axes": "Calibrated axes",
"calib_config": "Config",
"calib_none": "the device has not confirmed a calibration",
"export_section": "Last exported coefficients",
"export_none": "No coefficients exported yet",
"export_file": "file {name} ({size} KB, {time})",
"export_identity": "file identity type {sensor_type} · SN {sn} · config {config}",
"thumb_placeholder": "Product model"
},
"panels": {
@@ -99,12 +108,16 @@
"view_arrows_pure": "Arrows",
"view_arrows_stitched": "Arrows / Captured",
"view_depth": "Depth map",
"view_recorded": "Recorded image",
"view_mode_tip": "Image display mode while running",
"replay_pipeline": "Recorded video → depth recomputed",
"replay_pipeline_tip": "Replay shows the recorded raw camera image; the depth map is recomputed offline from that video and the config, with no live arrow overlay",
"replay_empty": "No recording open\nPress “Open recording…” below",
"arrow_empty": "No image yet\nPick a video or camera, then press Run",
"arrow_empty_tip": "The deformation arrow image appears here while running or previewing",
"depth_unavailable": "No depth data for this frame\n(not a depth of zero, and no silent fallback to the processed image)",
"depth_scale": "Depth scale {low} – {high}",
"arrow_scale": "Display ×{factor}",
"arrow_scale": "Arrows: displacement ×{factor}",
"arrow_scale_tip": "Display magnification of the relative displacement: the arrows are drawn from the algorithm output of the captured image, with the measured displacement multiplied by this factor and capped at 0.8 of the grid spacing (a capped arrow no longer shows its true factor).",
"arrow_pipeline": "Captured image → algorithm output",
"arrow_pipeline_tip": "Arrows are drawn over the algorithm output, not over the raw camera frame: points below the threshold get no arrow",
@@ -129,6 +142,7 @@
"no_data": "—",
"mode_follow": "Following live",
"mode_browse": "Browsing history (display paused; capture and recording continue)",
"mode_replay": "Replaying a recording (browsing)",
"return_latest": "Back to latest",
"return_latest_tip": "Leave history browsing and follow the newest data again",
"overview": "Whole session",
@@ -139,17 +153,16 @@
"selection_empty": "No valid samples in the selection",
"value_unavailable": "n/a",
"value_unavailable_tip": "No curve is loaded for {channel}, so it has no value in this unit (raw counts are never shown in its place)",
"unit_toggle": "Switch unit",
"unit_toggle_tip": "Click to switch the three curves and readouts between newton and raw units",
"browse_only_tip": "Drag or scroll on the chart to browse history"
},
"layout": {
"default": "Free layout",
"preset_2d_name": "2D mode (depth + charts)",
"preset_2d": "2D mode: depth map on the left, force charts on the right, one shared time axis",
"preset_default": "Free layout restored"
},
"playback": {
"title": "Replay recording",
"open": "Open recording directory…",
"open": "Open recording…",
"open_tip": "Pick a recording directory under outputs/recordings (video + curves + metadata)",
"scrub_tip": "Drag the progress bar to move the playhead: video, depth and the chart cursor follow",
"loaded_short": "{name} · {frames} frames / {duration} s",
"open_failed": "Could not open that recording: {error}",
"none_found": "No recording found under outputs/recordings",
"loaded": "{name} — {frames} frames / {duration} s",
@@ -318,8 +331,7 @@
"phase_connecting": "Connecting",
"phase_running": "Acquiring",
"phase_error": "Error",
"rail_camera": "Camera {id}",
"rail_video": "Video file",
"rail_video_name": "Video file: {name}",
"data_valid": "Data valid",
"data_invalid": "{count} invalid sample(s)",
"calibrated": "Calibrated",
+28 -16
View File
@@ -58,13 +58,10 @@
"cancel": "取消"
},
"toolbar": {
"source": "来源",
"source_camera": "摄像机",
"source_video": "视频文件",
"search_cameras": "搜索",
"cam_id": "摄像机",
"browse_video": "浏览…",
"video_placeholder": "未选择视频",
"use_camera": "使用摄像机",
"use_camera_tip": "回到摄像机采集(当前正在用视频文件采集)",
"preview": "预览",
"preview_stop": "停止预览",
"run": "运行",
@@ -81,7 +78,7 @@
"units_newton": "牛顿",
"units_raw": "原始",
"settings": "设置",
"settings_tip": "展开或收起来源、摄像机、单位与产品配置"
"settings_tip": "展开或收起单位、记录模式与预览"
},
"units": {
"newton_short": "N",
@@ -92,6 +89,18 @@
"config": "传感器配置",
"type_tip": "选择产品/传感器:box、mini、finger。它决定可用的配置文件与算法参数。",
"config_tip": "该传感器使用的算法配置文件(config/*.json)。切换传感器会同时切换可选配置。",
"summary": "{type} · {config}",
"dialog_title": "传感器与标定",
"dialog_tip": "选择传感器类型与配置文件,并查看当前生效的标定与最近导出的系数",
"calib_section": "当前生效的标定",
"calib_version": "设备确认的版本",
"calib_axes": "已标定轴",
"calib_config": "配置",
"calib_none": "设备尚未确认加载标定",
"export_section": "最近导出的系数",
"export_none": "还没有导出过系数",
"export_file": "文件 {name}({size} KB,{time})",
"export_identity": "文件身份 类型 {sensor_type} · SN {sn} · 配置 {config}",
"thumb_placeholder": "产品型号"
},
"panels": {
@@ -99,12 +108,16 @@
"view_arrows_pure": "箭头",
"view_arrows_stitched": "箭头/采集图像",
"view_depth": "深度图",
"view_recorded": "原始图像",
"view_mode_tip": "运行时的图像显示模式",
"replay_pipeline": "录制视频 → 深度重算",
"replay_pipeline_tip": "回放显示的是录制下来的原始相机图像;深度图由录制视频与配置离线重算,不含实时箭头叠加",
"replay_empty": "尚未打开录制\n点击下方「打开录制…」",
"arrow_empty": "尚未采集图像\n请选择视频或摄像机后点击「运行」",
"arrow_empty_tip": "运行或预览后在此显示形变箭头图",
"depth_unavailable": "本帧没有深度数据\n(不是深度为零,也未回退显示普通形变图)",
"depth_scale": "深度色标 {low} – {high}",
"arrow_scale": "放大 ×{factor}",
"arrow_scale": "箭头按位移放大 ×{factor}",
"arrow_scale_tip": "相对位移的显示放大倍率:箭头由原始采集图像经算法输出,长度按测量位移放大后绘制,上限为网格间距的 0.8 倍;触顶的箭头不再呈现真实倍率。",
"arrow_pipeline": "原始图像 → 算法输出",
"arrow_pipeline_tip": "箭头画在算法输出上,不是相机原始帧:阈值以下的区域不画箭头",
@@ -129,6 +142,7 @@
"no_data": "—",
"mode_follow": "跟随实时",
"mode_browse": "浏览历史(显示暂停,采集与记录继续)",
"mode_replay": "回放录制(浏览)",
"return_latest": "返回最新",
"return_latest_tip": "退出历史浏览,恢复跟随最新数据",
"overview": "全程总览",
@@ -139,17 +153,16 @@
"selection_empty": "选区无有效样本",
"value_unavailable": "不可用",
"value_unavailable_tip": "{channel} 轴未加载标定曲线,因此没有该单位的数值(不会用原始值冒充)",
"unit_toggle": "切换单位",
"unit_toggle_tip": "点击在「牛顿」与「原始单位」之间切换三轴曲线与读数",
"browse_only_tip": "拖动或滚轮即可进入历史浏览"
},
"layout": {
"default": "自由布局",
"preset_2d_name": "二维模式(深度图 + 曲线)",
"preset_2d": "已切换到二维模式:左侧深度图、右侧三轴曲线,共用时间轴",
"preset_default": "已恢复自由布局"
},
"playback": {
"title": "录制回放",
"open": "打开录制目录…",
"open": "打开录制…",
"open_tip": "选择 outputs/recordings 下的一个录制目录(视频 + 曲线 + 元数据)",
"scrub_tip": "拖动进度条移动回放位置:视频、深度与曲线游标同步",
"loaded_short": "{name} · {frames} 帧 / {duration} s",
"open_failed": "无法打开该录制: {error}",
"none_found": "outputs/recordings 下没有找到录制",
"loaded": "{name} — {frames} 帧 / {duration} s",
@@ -318,8 +331,7 @@
"phase_connecting": "连接中",
"phase_running": "采集中",
"phase_error": "出错",
"rail_camera": "摄像机 {id}",
"rail_video": "视频文件",
"rail_video_name": "视频文件: {name}",
"data_valid": "数据有效",
"data_invalid": "无效样本 {count}",
"calibrated": "已标定",