完善项目导入、模板与分割工作区交互
- 增强 DICOM/视频项目导入与演示数据:DICOM 按文件名自然顺序处理,导入后展示上传与解析任务进度,恢复演示出厂设置保留演示视频和演示 DICOM 项目,并补充 demo media seed 逻辑。 - 完善项目管理:项目支持重命名、删除、复制,删除使用站内确认弹窗,复制支持新项目重置和全内容复制,DICOM 项目不显示生成帧入口。 - 完善 GT Mask 与导出链路:只支持 8-bit maskid 图导入,非法/全背景图明确拒绝,尺寸自动适配,高精度 polygon 回显;统一导出默认当前帧,GT_label 使用 uint8 和真实 maskid,待分类 maskid 0 与背景一致。 - 完善分割工作区交互:新增画笔和橡皮擦并支持尺寸控制,移除创建点/线段入口,工具栏按类别分隔,AI 智能分割使用明确 AI 图标,取消黄色 seed point,清空/删除传播 mask 后同步清理空帧时间轴状态。 - 完善传播与时间轴:自动传播使用 SAM 2.1 权重任务,参考帧无遮罩时提示,传播历史按同一蓝色系递进变暗,删除/清空传播链时保留人工或独立 AI 标注来源。 - 完善模板库:新增头颈部 CT 分割默认模板,所有模板保留 maskid 0 待分类,支持鼠标复制模板、拖拽层级、JSON 批量导入预览、删除 label 和站内删除确认。 - 完善用户与高风险确认:用户改密码、删除用户、恢复演示出厂设置和清空人工/AI 标注帧均改为站内确认交互,避免浏览器原生 prompt/confirm。 - 补充前后端测试与文档:更新项目、模板、GT 导入、导出、传播、DICOM、用户管理等测试,并同步 README、AGENTS 和 doc 下实现/契约/测试计划文档。
This commit is contained in:
@@ -36,23 +36,22 @@ Word 方案描述的理想系统包含:
|
||||
| MinIO 对象存储 | 已落地 | `backend/minio_client.py` |
|
||||
| Redis 连接 | 已落地 | 用于 Celery broker/result backend,并通过 `seg:progress` pub/sub 转发任务进度 |
|
||||
| 视频拆帧 | 已落地 | `backend/services/frame_parser.py`、`backend/routers/media.py` |
|
||||
| DICOM 批量导入 | 部分落地 | 上传和解析存在,项目级体验还需完善 |
|
||||
| DICOM 批量导入 | 已落地 | 上传、文件名自然排序、解析任务创建和项目库解析进度回显均已接入 |
|
||||
| WebSocket 进度 | 已落地 | 拆帧进度写入任务表后发布到 Redis `seg:progress`,FastAPI 广播到 `/ws/progress` |
|
||||
| SAM 推理 | 部分落地 | 当前产品入口启用 SAM 2.1 tiny/small/base+/large 和真实 GPU/SAM2.1 状态接口;SAM 2.1 已接 point/box/interactive 和 video predictor 片段传播。SAM 3 桥接源码保留,但前端入口和后端 registry 已禁用 |
|
||||
| 模板库 | 部分落地 | 分类、颜色、maskid 和拖拽排序能存储和编辑;右侧语义分类树也可拖拽调整内部覆盖顺序;PNG mask 导出时会按内部优先级做语义融合裁决,前端预览裁决尚未落地 |
|
||||
| 标注持久化 | 部分落地 | 后端有 `Annotation` 表,前端已接入新增、回显、分类更新、传播链前后帧同目标同步换类、当前帧删除、手工绘制、GT mask 导入、seed point 编辑、polygon 顶点拖动/删除、边中点插点和多 polygon 子区域编辑;复杂洞结构编辑未落地 |
|
||||
| COCO / Mask 导出 | 已落地基础能力 | `backend/routers/export.py`;COCO JSON、兼容 PNG mask ZIP 和统一分割结果 ZIP 均已接入;统一 ZIP 包含 maskid/GT 像素值映射、原始图片、按帧/类别合并的分开 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图;GT_label 像素值使用类别真实 maskid,缺失 maskid 的旧标注才补下一个可用正整数 |
|
||||
| 模板库 | 部分落地 | 分类、颜色、maskid、JSON 批量导入预览和拖拽排序能存储和编辑;右侧语义分类树也可拖拽调整内部覆盖顺序;PNG mask 导出时会按内部优先级做语义融合裁决,前端预览裁决尚未落地 |
|
||||
| 标注持久化 | 部分落地 | 后端有 `Annotation` 表,前端已接入新增、回显、分类更新、传播链前后帧同目标同步换类、当前帧删除、手工绘制、GT mask 导入、polygon 顶点拖动/删除、边中点插点和多 polygon 子区域编辑;复杂洞结构编辑未落地 |
|
||||
| COCO / Mask 导出 | 已落地基础能力 | `backend/routers/export.py`;COCO JSON、兼容 PNG mask ZIP 和统一分割结果 ZIP 均已接入;统一 ZIP 包含 maskid/GT 像素值映射、原始图片、按帧/类别合并的分开 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图;GT_label 固定为 8-bit uint8 PNG,像素值使用类别真实 maskid,其中 `maskid:0` 的“待分类”和背景同为 0,缺失 maskid 的旧标注才补下一个可用正整数,正整数 maskid 超出 1-255 会拒绝导出 |
|
||||
|
||||
## 当前代码尚未落地的目标
|
||||
|
||||
- SAM 3:`sam3_engine.py`、`sam3_external_worker.py` 和 `setup_sam3_env.sh` 作为历史实现保留;由于当前系统不给文本提示,前端不再展示 SAM 3,后端 registry 也不暴露 `sam3`。官方没有 SAM 3 tiny/small 权重,当前可选最小真实 SAM 权重仍是 SAM 2.1 tiny。
|
||||
- Celery 异步任务队列:已注册 Celery app 和拆帧 worker task,`/api/media/parse` 会创建任务表记录并入队。
|
||||
- GT mask 导入:当前已支持二值 mask、灰度/16-bit GT_label 图和 RGB 三通道完全相同的 `[X,X,X]` maskid 图导入,后端会按 maskid 拆分区域,生成 polygon 标注和距离变换 seed point;超出现有类别的 maskid 可舍弃或导入为未定义类别;普通彩色类别图会被拒绝,尺寸不一致会自动最近邻拉伸到当前帧;骨架提取、HDBSCAN 和更复杂的模板自动映射尚未实现。
|
||||
- Mask 到点区域的拓扑降维:当前完成 distance transform seed point 和前端 seed point 拖拽编辑;骨架提取、HDBSCAN 等增强尚未实现。
|
||||
- GT mask 导入:当前仅支持 8-bit 二值/灰度 maskid 图和 8-bit RGB 三通道完全相同的 `[X,X,X]` maskid 图导入,后端会按 maskid 拆分区域,生成高精度 polygon 标注;超出现有类别的 maskid 可舍弃或导入为未定义类别;16-bit/uint16 GT_label 和普通彩色类别图会被拒绝,尺寸不一致会自动最近邻拉伸到当前帧;骨架提取、HDBSCAN 和更复杂的模板自动映射尚未实现。
|
||||
- Mask 到点区域的拓扑降维:后端保留 distance transform seed point 数据兼容;前端不再显示黄色 seed point,也不提供 seed point 拖拽编辑;骨架提取、HDBSCAN 等增强尚未实现。
|
||||
- 类别优先级融合:PNG mask 导出时已按内部优先级生成语义融合 mask;前端裁决预览尚未实现。
|
||||
- 撤销/重做:当前已有全局 mask 历史栈。
|
||||
- 保存状态按钮:工作区按钮按待保存数量显示“保存 X 个改动”或“已全部保存”,并调用 `POST /api/ai/annotate` 保存当前未归档 mask,通过 `PATCH /api/ai/annotations/{id}` 更新 dirty mask。
|
||||
|
||||
## 结论
|
||||
|
||||
当前项目已经从 UI 原型推进到“可上传、可异步拆帧、可取消/重试任务、可查看失败详情、可实时查看任务进度、可浏览项目帧、可维护模板、可手工绘制、可逐点编辑 polygon、可边中点插点、可多 polygon 子区域编辑、可区域合并/去除、可用可选 SAM 2.1 做点/框 AI 推理、可对点/框 prompt 做裁剪推理和背景过滤、可用 SAM 2.1 进行视频片段传播、可导入多类别 GT mask、可编辑 seed point、可保存标注、可导出 COCO/语义 mask ZIP、可查看 Dashboard 后端概览”的全栈雏形。下一阶段最重要的是继续补齐复杂洞结构编辑、GT mask 骨架/聚类增强和传播任务异步化。
|
||||
当前项目已经从 UI 原型推进到“可上传、可异步拆帧、可取消/重试任务、可查看失败详情、可实时查看任务进度、可浏览项目帧、可维护模板、可手工绘制、可逐点编辑 polygon、可边中点插点、可多 polygon 子区域编辑、可区域合并/去除、可用可选 SAM 2.1 做点/框 AI 推理、可对点/框 prompt 做裁剪推理和背景过滤、可用 SAM 2.1 后台任务进行视频片段传播、可导入多类别 GT mask、可保存标注、可导出 COCO/语义 mask ZIP、可查看 Dashboard 后端概览”的全栈雏形。下一阶段最重要的是继续补齐复杂洞结构编辑、GT mask 骨架/聚类增强和前端语义融合预览。
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
- 检查 MinIO bucket。
|
||||
- 测试 Redis。
|
||||
- Seed 默认模板。
|
||||
- 如果存在 `Data_MyVideo_1.mp4`,创建默认项目并拆前 100 帧。
|
||||
- 如果存在 `demo_video_path` 和配置的 `demo_dicom_dir` DICOM 序列,创建默认演示视频项目和演示 DICOM 项目,DICOM 按文件名自然顺序生成帧。
|
||||
|
||||
## 前端模块切换
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
2. `UserAdmin.tsx` 调用 `GET/POST/PATCH/DELETE /api/admin/users` 完成用户新增、停用/启用、角色修改、改密码和删除无项目用户。
|
||||
3. `UserAdmin.tsx` 调用 `GET /api/admin/audit-logs` 展示登录成功/失败以及用户管理操作审计。
|
||||
4. `UserAdmin.tsx` 危险区“恢复演示出厂设置”需要浏览器确认和输入 `RESET_DEMO_FACTORY`,随后调用 `POST /api/admin/demo-factory-reset`。
|
||||
5. 后端 `backend/routers/admin.py` 会阻止管理员删除、停用或降级自己,并阻止删除仍拥有项目的用户;演示出厂重置会清空其它用户、项目帧、标注、任务和私有模板,重新创建一个尚未生成帧的 `Data_MyVideo_1` 视频项目。
|
||||
5. 后端 `backend/routers/admin.py` 会阻止管理员删除、停用或降级自己,并阻止删除仍拥有项目的用户;演示出厂重置会清空其它用户、项目帧、标注、任务和私有模板,重新创建演示视频项目和一个已按文件名自然顺序生成帧的演示 DICOM 项目。
|
||||
|
||||
### 项目与拆帧
|
||||
|
||||
@@ -111,6 +111,6 @@
|
||||
|
||||
- 前端 API/WS 地址虽然已支持环境变量和 hostname 推导,但部署时仍需要确认浏览器可访问 `:8000` 后端。
|
||||
- AI 当前启用 SAM 2.1 tiny/small/base+/large 点/框/interactive 路径;语义文本提示和 SAM 3 产品入口已禁用,`model=sam3` 会被后端拒绝。SAM 3 源码保留但不计入当前可用功能。
|
||||
- 工作区顶部“分割结果导出”和保存状态按钮、左侧工具栏“导入 GT Mask”已接入统一导出、GT 多类别导入、seed point 回显/编辑、标注新增和 dirty 标注更新;导入 GT Mask 支持二值 mask、低数值/16-bit GT_label 图和 RGB 三通道完全相同的 `[X,X,X]` maskid 图,未知 maskid 可由用户选择舍弃或导入为未定义类别,普通彩色类别图会被拒绝,尺寸不同会自动最近邻拉伸到当前帧。保存状态按钮会按待保存数量显示“保存 X 个改动”或“已全部保存”;统一导出可选择整体视频、特定范围帧或当前图片,并勾选分开 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图;特定范围帧导出支持直接输入起止帧,也支持在播放进度条或视频处理进度条上点击/拖拽选择范围;Mix_label 支持默认 0.3 的透明度调节和首帧预览;后端统一导出 ZIP 固定包含 maskid/GT 像素值映射 JSON 与原始图片文件夹,GT_label 像素值使用类别真实 maskid,缺失 maskid 的旧标注才补下一个可用正整数,并按客户命名规则输出分开 Mask、GT_label、Pro_label 和 Mix_label 文件夹;清空当前帧遮罩会删除对应后端标注。手工绘制、polygon 顶点拖动/删除、区域合并/去除和撤销重做已经落到前端 mask 数据结构。
|
||||
- 工作区顶部“分割结果导出”和保存状态按钮、左侧工具栏“导入 GT Mask”已接入统一导出、GT 多类别导入、标注新增和 dirty 标注更新;导入 GT Mask 仅支持 8-bit 二值/灰度 maskid 图和 8-bit RGB 三通道完全相同的 `[X,X,X]` maskid 图,未知 maskid 可由用户选择舍弃或导入为未定义类别,16-bit/uint16 GT_label 和普通彩色类别图会被拒绝,尺寸不同会自动最近邻拉伸到当前帧;GT 连通域会生成高精度 polygon,导入后和普通 mask 一样不显示黄色 seed point,并与普通 mask 共用拓扑统计、边缘平滑、编辑和保存链路。保存状态按钮会按待保存数量显示“保存 X 个改动”或“已全部保存”;统一导出可选择整体视频、特定范围帧或当前图片,并勾选分开 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图;特定范围帧导出支持直接输入起止帧,也支持在播放进度条或视频处理进度条上点击/拖拽选择范围;Mix_label 支持默认 0.3 的透明度调节和首帧预览;后端统一导出 ZIP 固定包含 maskid/GT 像素值映射 JSON 与原始图片文件夹,GT_label 固定输出 8-bit uint8 PNG,像素值使用类别真实 maskid,其中 `maskid:0` 的“待分类”和背景同为 0,缺失 maskid 的旧标注才补下一个可用正整数,正整数 maskid 超出 1-255 会拒绝导出,并按客户命名规则输出分开 Mask、GT_label、Pro_label 和 Mix_label 文件夹;清空当前帧遮罩会删除对应后端标注。手工绘制、polygon 顶点拖动/删除、区域合并/去除和撤销重做已经落到前端 mask 数据结构。
|
||||
- Dashboard 初始统计、队列和活动日志来自后端聚合接口;解析队列来自 `processing_tasks`,worker 进度通过 Redis `seg:progress` 转发到 WebSocket。任务取消、重试和失败详情已接入前后端。
|
||||
- 后端已接入 Bearer JWT 鉴权、当前用户项目隔离和角色权限;写入类业务接口要求 `admin/annotator`,管理员用户后台要求 `admin`。当前审计覆盖登录和用户管理操作,全业务级审计仍可继续扩展。
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
| 修改角色 / 启停用 / 改密码 | 真实可用 | 调用 `PATCH /api/admin/users/{id}`;后端禁止管理员把自己降级或停用,避免锁死后台 |
|
||||
| 删除用户 | 真实可用 | 调用 `DELETE /api/admin/users/{id}`;后端禁止删除自己,且用户名下仍有项目时返回 409,避免悬空项目数据 |
|
||||
| 审计日志 | 真实可用 | 调用 `GET /api/admin/audit-logs`,展示登录成功/失败、用户新增、修改和删除等管理操作 |
|
||||
| 恢复演示出厂设置 | 真实可用 | 管理员点击危险区按钮后先浏览器确认,再输入 `RESET_DEMO_FACTORY`;前端调用 `POST /api/admin/demo-factory-reset`,后端只保留默认 admin 与一个尚未生成帧的演示视频项目,并清空用户、项目帧、标注、任务和私有模板等演示数据 |
|
||||
| 恢复演示出厂设置 | 真实可用 | 管理员点击危险区按钮后先浏览器确认,再输入 `RESET_DEMO_FACTORY`;前端调用 `POST /api/admin/demo-factory-reset`,后端只保留默认 admin、演示视频项目和一个已按文件名自然顺序生成帧的演示 DICOM 项目,并清空用户、项目帧、标注、任务和私有模板等演示数据 |
|
||||
|
||||
## Dashboard 系统概况
|
||||
|
||||
@@ -59,11 +59,11 @@
|
||||
| 项目卡片缩略图 | 真实可用 | 后端返回 MinIO 预签名 `thumbnail_url` 时显示 |
|
||||
| 点击项目进入工作区 | 真实可用 | 设置 `currentProject` 后切到 `workspace` |
|
||||
| 新建项目 | 真实可用 | 调用 `POST /api/projects` |
|
||||
| 导入视频文件 | 真实可用 | 创建项目、上传源视频、刷新项目列表;不会自动拆帧 |
|
||||
| 导入视频文件 | 真实可用 | 创建项目、上传源视频、刷新项目列表;不会自动拆帧;上传期间显示项目库导入进度条、百分比和已上传字节 |
|
||||
| 生成帧按钮 | 真实可用 | 仅对已导入源视频且尚无帧、非 parsing 状态的项目显示,调用 `parseMedia(projectId, { parseFps })` |
|
||||
| 生成帧 FPS 滑块 | 真实可用 | 值传入 `/api/media/parse?parse_fps=...`,决定后台拆帧目标 FPS |
|
||||
| 项目卡片 FPS 徽标 | 真实可用 | 右上角显示关键帧序列目标 `parse_fps`;原始视频帧率只在卡片底部以“原 xx fps”显示 |
|
||||
| 导入 DICOM 序列 | 部分可用 | 可上传 `.dcm` 并触发解析;体验和错误反馈较粗 |
|
||||
| 导入 DICOM 序列 | 真实可用 | 可上传 `.dcm` 并触发解析;上传前按文件名自然顺序排序,后端解析也保持同一顺序;上传期间显示导入进度条、有效 DICOM 文件数量和已上传字节,上传完成后继续显示解析任务进度直到完成、失败或取消 |
|
||||
| 项目状态徽标 | 真实可用 | 项目状态统一为 `pending/parsing/ready/error`,前端兼容归一化旧状态值 |
|
||||
| 删除项目按钮 | 真实可用 | 点击垃圾桶按钮会确认删除,调用 `DELETE /api/projects/{id}`,成功后从项目库移除;若删除的是当前项目,会清空工作区当前项目、帧、mask 和选区 |
|
||||
| 操作成功/失败提示 | 真实可用 | 使用非阻塞 `TransientNotice` 浮层,自动消失,不会拦截后续按钮、输入框或画布操作 |
|
||||
@@ -78,8 +78,8 @@
|
||||
| 无帧项目提示 | 真实可用 | 如果 `video_path` 存在但无帧,只提示回到项目库生成帧,不自动创建拆帧任务 |
|
||||
| SAM 模型状态徽标 | 真实可用 | 工作区顶栏使用紧凑 GPU/CPU 状态徽标,避免和旁边的“传播权重”下拉重复显示 SAM 2.1 变体名称;悬停仍可查看模型状态说明 |
|
||||
| 已保存标注回显 | 真实可用 | 加载工作区帧后调用 `GET /api/ai/annotations` 并渲染已保存 mask;回显时保留当前项目帧里尚未保存的 AI/手工 draft mask,避免从 AI 页推送的候选被覆盖 |
|
||||
| “分割结果导出”按钮 | 真实可用 | 原“导出 JSON 标注集”和“导出 PNG Mask ZIP”已合并为一个入口;点击后可选择整体视频、特定范围帧或当前图片,默认导出范围为当前图片,并勾选导出分开二值 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图;选择“特定范围帧”后会进入和自动传播、清空遮罩一致的时间轴范围选择模式,可在播放进度条或视频处理进度条上点击/拖拽选择导出起止帧,也可直接修改起止帧输入框;选择 Mix_label 时可调透明度,默认 0.3,并显示当前/待导出第一帧预览;提交前会保存未归档 mask,然后调用 `GET /api/export/{project_id}/results` 下载 ZIP;浏览器下载名和后端 `Content-Disposition` 均使用 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`;时间戳格式为 `0h00m00s000ms`,帧序号来自项目抽帧后的 1-based 顺序,不使用原视频帧号;包内固定包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json` 和 `原始图片/`;选择分开 mask 时包含按帧子目录组织且同类合并的 `分开Mask分割结果/`,选择 GT_label/Pro_label/Mix_label 时分别包含 `GT_label图/`、`Pro_label彩色分割结果/`、`Mix_label重叠覆盖彩色分割结果/`。GT_label 图中背景为 0,语义类别值使用类别真实 maskid,缺失 maskid 的旧标注才补下一个可用正整数 |
|
||||
| “导入 GT Mask”按钮 | 真实可用 | 入口已从工作区顶栏移动到左侧工具栏“重叠区域去除”之后,使用紫色图标底色;选择图片后先弹出导入结果预览和未知 maskid 策略选择,可舍弃未知类别或导入为未定义类别;随后调用 `POST /api/ai/import-gt-mask`,后端支持二值 mask、低数值/16-bit GT_label 图和 RGB 三通道完全相同的 `[X,X,X]` maskid 图,不符合灰度/maskid 图要求时返回错误;尺寸不同会自动最近邻拉伸到当前帧,再按类别/连通域生成 polygon 标注与距离变换 seed point,最后回显到工作区 |
|
||||
| “分割结果导出”按钮 | 真实可用 | 原“导出 JSON 标注集”和“导出 PNG Mask ZIP”已合并为一个入口;点击后可选择整体视频、特定范围帧或当前图片,默认导出范围为当前图片,并勾选导出分开二值 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图;选择“特定范围帧”后会进入和自动传播、清空遮罩一致的时间轴范围选择模式,可在播放进度条或视频处理进度条上点击/拖拽选择导出起止帧,也可直接修改起止帧输入框;选择 Mix_label 时可调透明度,默认 0.3,并显示当前/待导出第一帧预览;提交前会保存未归档 mask,然后调用 `GET /api/export/{project_id}/results` 下载 ZIP;浏览器下载名和后端 `Content-Disposition` 均使用 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`;时间戳格式为 `0h00m00s000ms`,帧序号来自项目抽帧后的 1-based 顺序,不使用原视频帧号;包内固定包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json` 和 `原始图片/`;选择分开 mask 时包含按帧子目录组织且同类合并的 `分开Mask分割结果/`,选择 GT_label/Pro_label/Mix_label 时分别包含 `GT_label图/`、`Pro_label彩色分割结果/`、`Mix_label重叠覆盖彩色分割结果/`。GT_label 图固定为 8-bit uint8 PNG,背景为 0,语义类别值使用类别真实 maskid,`maskid: 0` 的“待分类”与背景同为 0,Pro_label 中也与背景同为黑色 `[0,0,0]`,缺失 maskid 的旧标注才补下一个可用正整数,正整数 maskid 超出 1-255 会拒绝导出 |
|
||||
| “导入 GT Mask”按钮 | 真实可用 | 入口已从工作区顶栏移动到左侧工具栏“重叠区域去除”之后,使用紫色图标底色;选择图片后先弹出导入结果预览和未知 maskid 策略选择,可舍弃未知类别或导入为未定义类别;随后调用 `POST /api/ai/import-gt-mask`,后端仅支持 8-bit 二值/灰度 maskid 图和 8-bit RGB 三通道完全相同的 `[X,X,X]` maskid 图,不符合 8-bit 灰度/maskid 图要求时返回错误,16-bit/uint16 GT_label 会被拒绝;尺寸不同会自动最近邻拉伸到当前帧,再按类别/连通域生成高精度 polygon 标注,最后回显到工作区;导入 mask 与普通 mask 一样不显示黄色 seed point,并共用拓扑锚点统计、边缘平滑、编辑、分类和保存链路 |
|
||||
| 参考帧/起止帧/传播权重/自动传播 | 真实可用 | 当前打开帧即参考帧,前端会使用该帧全部 mask 作为 seed;工作区顶栏有独立“传播权重”下拉,可在传播前二次选择 SAM 2.1 tiny/small/base+/large 权重,不提供 SAM2/SAM3 家族切换,不影响 AI 智能分割页的单帧推理权重选择;传播权重下拉使用深色背景和青色文字,避免默认灰底白字不可读;如果用户尚未显式设置范围,点击“自动传播”会先进入时间轴范围选择模式,播放进度条和视频处理进度条都可点击/拖拽回填传播起始帧和传播结束帧,再点击“开始传播”提交;用户也可直接改数字框后点击按钮传播。提交后前端把传播权重 id、seed mask、seed 来源 id、未编辑传播结果的原始 seed 签名和前/后方向步骤提交到 `POST /api/ai/propagate/task`,后端先规范化/校验权重 id,再创建 `processing_tasks` 并由 Celery 执行对应 SAM 2.1 video predictor;worker 会在本次目标帧段内按 seed 来源和几何/语义签名做幂等判断,未改变且目标帧已有结果的 seed 直接跳过,已改变、目标帧只部分覆盖或换权重时会先删除本次目标帧段内同源旧自动传播标注再重新传播;历史或外部 seed 若仍带边缘平滑参数,后端仍按完整签名兼容处理;当前前端平滑应用会直接改写 polygon,因此传播以新几何参与签名;中间帧人工新增/修改同一物体后重新传播时,后端会按语义和目标帧空间重叠清理旧传播结果,写入前清理不受旧结果 `propagation_direction` 限制,避免 backward 重传时与旧 forward mask 重叠;传播中顶栏显示任务进度、已处理帧次、删除旧区域数和已保存区域数,前端轮询 `GET /api/tasks/{task_id}` 并刷新已保存标注;任务可取消,若完成后 0 个新区域会明确提示没有生成新 mask 或已跳过未改变 mask |
|
||||
| 清空片段遮罩 | 真实可用 | 点击“清空片段遮罩”后会进入和自动传播一致的时间轴范围选择模式,用户可在播放进度条或视频处理进度条上点击/拖拽选择起止帧;顶栏提供“清空全部”和“保留人工/AI”两种模式,默认清空全部以保持旧行为;“清空全部”会删除该帧段内所有本地 draft mask,并对已保存 mask 调用 `DELETE /api/ai/annotations/{annotation_id}`,若范围内存在人工绘制或 AI 智能分割生成的红色“人工/AI 标注帧”会先弹出确认;“保留人工/AI”只删除自动传播/推理 mask,不弹出人工帧确认,人工/AI 标注帧、范围外 mask 和未被清空的选区会保留;同时按清空范围裁剪当前会话的自动传播历史条,避免已清空片段仍显示最近传播进度 |
|
||||
| 保存状态按钮 | 真实可用 | 顶栏按钮按当前项目待保存数量显示为“保存 X 个改动”或“已全部保存”;未保存 mask 写入 `POST /api/ai/annotate`,dirty mask 写入 `PATCH /api/ai/annotations/{id}`;保存成功后会重新拉取后端标注,并用 saved annotation 替换本次提交的 draft mask,避免仍显示未保存 |
|
||||
@@ -97,11 +97,10 @@
|
||||
| AI 推理中提示 | 真实可用 | 请求期间会显示 |
|
||||
| 手工多边形/矩形/圆/画笔/橡皮擦 | 真实可用 | 多边形点击取点后可按 Enter 完成,也可在三点后点击首节点闭合;矩形/圆拖拽生成 polygon;画笔按当前语义分类生成连续圆形笔触并在松开时 union 成 mask,若与选中 mask 连通则自动合并;橡皮擦从选中 mask 中扣除笔触区域;均写入 `Mask.segmentation`,可归档保存 |
|
||||
| 画布上下文提示 | 真实可用 | 切换到多边形、矩形、圆、画笔、橡皮擦、区域合并/去除、调整多边形等隐性操作工具时,画布左上角显示当前工具的完成/取消/选择顺序提示;提示会在数秒后自动隐藏,避免长期遮挡待编辑图像,工具或操作状态变化时会重新出现 |
|
||||
| Mask 渲染 | 真实可用 | 前端会把推理、手工绘制、GT 导入和已保存标注转成 Konva `pathData` 渲染;未选中特定 mask 时,当前帧 mask 会按右侧“语义分类树”拖拽得到的内部覆盖优先级从低到高渲染,使高优先级类别显示在上层;有选中 mask 时保留编辑态置顶行为,方便操作 |
|
||||
| Mask 渲染 | 真实可用 | 前端会把推理、手工绘制、GT 导入和已保存标注转成 Konva `pathData` 渲染;普通 mask 和导入 mask 都不显示黄色 seed point;未选中特定 mask 时,当前帧 mask 会按右侧“语义分类树”拖拽得到的内部覆盖优先级从低到高渲染,使高优先级类别显示在上层;有选中 mask 时保留编辑态置顶行为,方便操作 |
|
||||
| Mask 透明度 | 真实可用 | 右侧语义分类树上方的“遮罩透明度”滑杆写入全局 `maskPreviewOpacity`,工作区 Canvas 和 AI 智能分割页都会使用该值调整 mask 预览透明度,选中 mask 会在该基础上略微加亮 |
|
||||
| 传播链跨帧选区跟随 | 真实可用 | 用户选中某个 mask 后切到同一自动传播结果覆盖的其他帧时,`CanvasArea` 会根据 `source_annotation_id`、`source_mask_id` 和 `propagation_seed_key` 查找目标帧对应传播 mask 并自动选中;找不到同链结果时才清空选区 |
|
||||
| Polygon 逐点编辑 / 删除 | 真实可用 | 点击 mask 后显示 polygon 顶点;按住顶点即可直接拖动并实时重算 `pathData/segmentation/bbox/area`,不需要先单击选中顶点,已保存 mask 标为 dirty;顶点拖拽结束不会触发 Stage 平移,Canvas 当前缩放和位置保持不变;选中顶点后 Delete/Backspace 可删点但保留至少三点;选中 mask 但未选中顶点时 Delete/Backspace 删除整个 mask,已保存 mask 会同步调用后端删除 |
|
||||
| GT seed point 回显/编辑 | 真实可用 | 已保存标注的 `points` 会显示为黄色 seed 点;拖动后标记为 dirty,归档保存会更新后端 |
|
||||
| Polygon 逐点编辑 / 删除 | 真实可用 | 点击 mask 后显示 polygon 顶点;按住顶点即可直接拖动并实时重算 `pathData/segmentation/bbox/area`,不需要先单击选中顶点,已保存 mask 标为 dirty;顶点拖拽结束不会触发 Stage 平移,Canvas 当前缩放和位置保持不变;选中顶点后 Delete/Backspace 可删点但保留至少三点;选中 mask 但未选中顶点时 Delete/Backspace 删除整个 mask,已保存 mask 会同步调用后端删除;若删除对象是传播 seed 或传播结果,前端会按 `source_annotation_id`、`source_mask_id` 和 `propagation_seed_key` 同步删除同链自动传播 mask,但不删除其他帧独立 AI 推理/人工 mask |
|
||||
| 应用分类 | 真实可用 | Canvas 右下角按钮可将当前选择的模板分类应用到本帧 mask,并同步同一传播链前后帧的对应 mask;右侧语义分类树点击分类时会优先改当前已选 mask,并通过 `source_annotation_id`、`source_mask_id` 和 `propagation_seed_key` 同步更新同一传播链上的前后传播 mask,同时把已选 mask 移到前端渲染最上层方便继续编辑;已保存 mask 会标为 dirty,归档保存时更新后端 |
|
||||
| 清空遮罩 | 真实可用 | 工作区中会删除当前帧已保存标注并清空当前帧本地 mask |
|
||||
| 保存状态计数 | 真实可用 | 底部显示已保存、未保存、待更新数量 |
|
||||
@@ -115,9 +114,9 @@
|
||||
| 拖拽/选择 | 真实可用 | 控制 Canvas 是否可拖拽 |
|
||||
| 调整多边形 | 真实可用 | 选中 polygon mask 后显示顶点和边中点;支持按住顶点直接拖动、点击边中点插点、双击边界按位置插点 |
|
||||
| 多边形/矩形/圆/画笔/橡皮擦 | 真实可用 | 切换 activeTool 后由 `CanvasArea` 生成或编辑可保存的 polygon mask;画笔/橡皮擦在工具栏显示尺寸滑杆 |
|
||||
| 区域合并/去除 | 真实可用 | 选择工具后点击多个 mask,右下角显示已选数量和操作按钮;合并/去除模式会隐藏 polygon 编辑手柄,避免手柄抢占多选点击;布尔选择态中第一个选中的主区域用黄色实线轮廓,后续参与合并/扣除的区域用红色虚线轮廓,避免主区域和扣除区域看起来像随机阴影差异;使用 `polygon-clipping` 做 union / difference;合并会保留主 mask 并移除被合并 mask,去除会从主 mask 扣除后续选中 mask;内含扣除会保留 hole ring 并用 even-odd 规则渲染 |
|
||||
| 区域合并/去除 | 真实可用 | 选择工具后点击多个 mask,右下角显示已选数量和操作按钮;合并/去除模式会隐藏 polygon 编辑手柄,避免手柄抢占多选点击;布尔选择态中第一个选中的主区域用黄色实线轮廓,后续参与合并/扣除的区域用红色虚线轮廓,避免主区域和扣除区域看起来像随机阴影差异;使用 `polygon-clipping` 做 union / difference;合并会保留主 mask 并移除被合并 mask,且移除次级 mask 时会同步删除其同链自动传播结果;去除会从主 mask 扣除后续选中 mask;内含扣除会保留 hole ring 并用 even-odd 规则渲染 |
|
||||
| 导入 GT Mask | 真实可用 | 位于“重叠区域去除”之后,点击后打开文件选择器,并在上传前选择未知类别处理策略;该入口不切换 activeTool |
|
||||
| 魔法棒 SAM 触发 | 部分可用 | 切到 AI 页面;不是直接执行推理 |
|
||||
| AI 智能分割跳转入口 | 真实可用 | 切到 AI 智能分割页;不是直接执行推理 |
|
||||
| AI 正向选点/反向选点/框选 | 不在工作区工具栏显示 | 这些是 AI 智能分割页功能,工作区左侧工具栏不再提供正向选点、反向选点和边界框选按钮 |
|
||||
| AI 智能分割入口 | 真实可用 | 位于工作区工具栏底部,使用和侧栏一致的 Bot + Sparkles 组合图标;点击后切到 AI 智能分割页 |
|
||||
| 撤销/重做 | 真实可用 | 绑定 Zustand `maskHistory/maskFuture`,工作区只保留顶栏按钮和快捷键 `Ctrl/Cmd+Z`、`Ctrl/Cmd+Shift+Z`、`Ctrl/Cmd+Y`,AI 页保留自己的按钮;左侧工具栏不再重复放置撤销/重做;输入框聚焦时不拦截快捷键;工作区顶栏撤销图标使用琥珀色、重做图标使用蓝紫色,提高深色顶栏里的识别度 |
|
||||
@@ -131,7 +130,7 @@
|
||||
| 点击缩略图跳帧 | 真实可用 | 调用 `setCurrentFrame(idx)`;非当前帧中,人工/AI 标注帧使用红色边框,自动传播/推理帧使用蓝色边框;同一帧同时有人工/AI 标注和自动传播结果时,红色标注边框优先保留,蓝色传播状态以内描边表达;当前帧仍用青色外框高亮优先,若当前帧同时是人工/AI 标注帧,则在青色外框内增加红色内描边,固定为外层当前帧、内层人工/AI 标注,避免状态颜色互相覆盖 |
|
||||
| 顶部 range 拖动 | 真实可用 | 改变当前帧 |
|
||||
| 具体时间显示 | 真实可用 | 根据项目 `parse_fps/original_fps` 显示当前时间和总时长,格式为 `mm:ss.cc` |
|
||||
| 播放进度条 / 视频处理进度条 | 真实可用 | 播放进度条位于上方,视频处理进度条位于下方;当前帧位置用一条白色竖线贯穿两条进度条,避免和青色播放进度、红/蓝处理状态混淆;视频处理进度条普通状态下可点击跳转到对应帧;根据已保存标注回显的 `mask_data.source`、`propagated_from_frame_id`、`source_annotation_id`、`source_mask_id` 或 `propagation_seed_key` 识别自动传播生成的帧并显示蓝色区段,人工绘制或 AI 智能分割生成的帧显示红色竖线,红/蓝标识也可点击跳转到对应帧;每次自动传播成功处理帧后,工作区会在当前会话记录最近传播范围,并在视频处理进度条上叠加同一蓝色系的纯色片段,按距最新传播的时间顺序逐次变暗,且第 5 次及更早统一为阈值旧记录色,辅助识别第一次、第二次、第 N 次传播;清空片段遮罩会同步移除或裁剪与清空范围重叠的传播历史片段;未处理背景使用中性灰以和红/蓝/传播历史标记区分;工作区进入自动传播或清空片段遮罩的范围选择模式时,两条进度条显示 amber 选区,并额外用洋红色起始线和黄绿色结束线贯穿两条进度条,表示待处理起止帧,颜色避开附近的青色、红色、蓝色和 amber 元素 |
|
||||
| 播放进度条 / 视频处理进度条 | 真实可用 | 播放进度条位于上方,视频处理进度条位于下方;当前帧位置用一条白色竖线贯穿两条进度条,避免和青色播放进度、红/蓝处理状态混淆;视频处理进度条普通状态下可点击跳转到对应帧;根据已保存标注回显的 `mask_data.source`、`propagated_from_frame_id`、`source_annotation_id`、`source_mask_id` 或 `propagation_seed_key` 识别自动传播生成的帧并显示蓝色区段,人工绘制或 AI 智能分割生成的帧显示红色竖线,红/蓝标识也可点击跳转到对应帧;每次自动传播成功处理帧后,工作区会在当前会话记录最近传播范围,并在视频处理进度条上叠加同一蓝色系的纯色片段,按距最新传播的时间顺序逐次变暗,且第 5 次及更早统一为阈值旧记录色,辅助识别第一次、第二次、第 N 次传播;传播历史片段会按当前仍存在的自动传播 mask 自动裁剪或拆分,清空片段遮罩或单独删除传播 mask 后,无任何 mask 的帧不会继续显示红/蓝颜色;未处理背景使用中性灰以和红/蓝/传播历史标记区分;工作区进入自动传播或清空片段遮罩的范围选择模式时,两条进度条显示 amber 选区,并额外用洋红色起始线和黄绿色结束线贯穿两条进度条,表示待处理起止帧,颜色避开附近的青色、红色、蓝色和 amber 元素 |
|
||||
| 播放/暂停 | 真实可用 | 当前代码按 `parse_fps/original_fps` 推进帧,最多 30fps |
|
||||
| 方向键切帧 | 真实可用 | 全局监听左右方向键切到上一帧/下一帧;焦点在 input、textarea、select 或 contentEditable 内时不会拦截 |
|
||||
|
||||
@@ -139,7 +138,7 @@
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 模板选择 | 部分可用 | 读取全局 templates,可切换 activeTemplateId |
|
||||
| 模板选择 | 真实可用 | 读取全局 templates,可切换 activeTemplateId,并会驱动分类树、mask 分类和导出类别信息 |
|
||||
| 面板滚动条 | 真实可用 | 右侧本体/语义分类面板内容过长时自身滚动;滚动条使用 `seg-scrollbar`,默认低对比融入深色侧栏,hover/focus 时才增强显示 |
|
||||
| 面板标题 | 已简化 | 原“本体论与属性分类管理树”固定说明栏已移除,右侧面板直接展示模板、透明度和语义分类树 |
|
||||
| 分类树展示 / 换标签 | 真实可用 | 显示当前模板 classes;点击分类会设为后续新 mask 的 activeClass,如果 Canvas 已选 mask,则同步更新已选 mask 及同一传播链前后帧对应 mask 的标签、颜色和 class 元数据,并把已选 mask 移到前端渲染最上层;当用户在 Canvas 点击已有 mask 时,本面板会按 mask 的 class id / 名称自动切换模板、设置 active class,并滚动/聚焦到对应分类按钮 |
|
||||
@@ -179,13 +178,12 @@
|
||||
| 编辑模板 | 真实可用 | 调用 `PATCH /api/templates/{id}` |
|
||||
| 删除模板 | 真实可用 | 调用 `DELETE /api/templates/{id}` |
|
||||
| 添加/删除分类 | 真实可用 | 保存在模板 `mapping_rules.classes` |
|
||||
| 拖拽排序 | 真实可用 | 模板库和工作区右侧语义分类树都可拖拽调整内部覆盖优先级,保存时写后端;工作区拖拽会同步当前同类 mask 的 `classZIndex` 并标记待保存;界面只显示类别稳定 maskid,maskid 不作为排序规范 |
|
||||
| JSON 批量导入 | 部分可用 | 前端解析 JSON 并加入编辑态,保存后才落库 |
|
||||
| 载入腹腔镜 35 分类 | 真实可用 | 前端内置数据;后端也 seed 默认模板 |
|
||||
| 拖拽排序 | 真实可用 | 模板库详情页、模板编辑弹窗和工作区右侧语义分类树都可拖拽调整内部覆盖优先级,保存时写后端;模板库详情页拖拽会刷新当前详情并同步当前工作区同类 mask 的 `classZIndex`,工作区拖拽也会同步当前同类 mask 的 `classZIndex` 并标记待保存;界面只显示类别稳定 maskid,maskid 不作为排序规范;黑色 `maskid: 0` 的“待分类”保留类固定在最后,不可删除或拖拽上移 |
|
||||
| JSON 批量导入 | 真实可用 | 前端解析 JSON 并显示导入数量、maskid 起点和缺失颜色提示;导入后加入编辑态,保存模板时落库 |
|
||||
| mapping rules | 部分可用 | 可存 `rules`,但当前没有运行时映射执行引擎;适合后续用于导入外部标签、别名归一化或跨数据集类别映射 |
|
||||
|
||||
## 总体结论
|
||||
|
||||
当前前端真实可用的主链路是:JWT 登录、刷新恢复用户、退出登录、Dashboard 当前用户概览、当前用户项目列表、新建项目、上传视频/DICOM、显式生成帧、浏览帧、播放帧、工作区手工绘制、点/框 AI 推理、视频片段传播、GT mask 导入、标注保存/回显、COCO 导出、PNG mask ZIP 导出、模板 CRUD。
|
||||
当前前端真实可用的主链路是:JWT 登录、刷新恢复用户、退出登录、Dashboard 当前用户概览、当前用户项目列表、新建项目、上传视频/DICOM、显式生成帧、浏览帧、播放帧、工作区手工绘制、点/框 AI 推理、视频片段传播、GT mask 导入、标注保存/回显、统一分割结果 ZIP 导出、兼容 COCO/PNG mask ZIP 导出、模板 CRUD。
|
||||
|
||||
当前最主要的 Mock 或未打通链路是:真正的文本语义分割已因无文本提示入口而暂时禁用;复杂洞结构编辑、骨架/HDBSCAN 级别的 mask 降维增强、任务历史筛选、项目更多菜单、全业务操作审计和 mapping rules 运行时映射执行引擎仍未落地。登录页“端到端加密”等安全文案仍只是 UI 文案;登录和用户管理操作审计已落库并可在管理员后台查看。
|
||||
|
||||
@@ -26,13 +26,13 @@ Authorization: Bearer <token>
|
||||
| `getProjects()` | `GET /api/projects` | 对齐 | 前端映射 `frame_count`、`thumbnail_url` 等字段 |
|
||||
| `createProject(payload)` | `POST /api/projects` | 对齐 | 支持 `name`、`description`、`parse_fps` |
|
||||
| `updateProject(id, payload)` | `PATCH /api/projects/{id}` | 对齐 | 后端是 `PATCH /api/projects/{id}` |
|
||||
| `deleteProject(id)` | `DELETE /api/projects/{id}` | 对齐 | 当前 UI 未明显接入 |
|
||||
| `deleteProject(id)` | `DELETE /api/projects/{id}` | 对齐 | 项目卡片删除按钮已接入,删除前使用站内确认弹窗 |
|
||||
| `getTemplates()` | `GET /api/templates` | 对齐 | 前端从 `mapping_rules` 取 classes/rules |
|
||||
| `createTemplate(payload)` | `POST /api/templates` | 对齐 | 后端会打包 classes/rules 到 mapping_rules |
|
||||
| `updateTemplate(id, payload)` | `PATCH /api/templates/{id}` | 对齐 | 模板编辑页使用 |
|
||||
| `deleteTemplate(id)` | `DELETE /api/templates/{id}` | 对齐 | 模板编辑页使用 |
|
||||
| `uploadMedia(file, projectId)` | `POST /api/media/upload` | 对齐 | multipart form-data |
|
||||
| `uploadDicomBatch(files, projectId)` | `POST /api/media/upload/dicom` | 对齐 | multipart form-data |
|
||||
| `uploadMedia(file, projectId, options?)` | `POST /api/media/upload` | 对齐 | multipart form-data;`options.onProgress` 用于项目库上传进度 |
|
||||
| `uploadDicomBatch(files, projectId, options?)` | `POST /api/media/upload/dicom` | 对齐 | multipart form-data;`options.onProgress` 用于项目库上传进度,上传完成后项目库轮询解析任务进度 |
|
||||
| `parseMedia(projectId, options?)` | `POST /api/media/parse?project_id=...` | 对齐 | 创建异步拆帧任务并返回 task;由项目库“生成帧”显式调用,支持 `parse_fps`、`max_frames`、`target_width` |
|
||||
| `getTask(taskId)` | `GET /api/tasks/{task_id}` | 对齐 | 查询异步任务状态 |
|
||||
| `cancelTask(taskId)` | `POST /api/tasks/{task_id}/cancel` | 对齐 | 取消 queued/running 任务,后端写 cancelled 并尝试 revoke Celery |
|
||||
@@ -47,7 +47,7 @@ Authorization: Bearer <token>
|
||||
| `saveAnnotation(payload)` | `POST /api/ai/annotate` | 对齐 | 工作区归档保存当前项目未保存 mask |
|
||||
| `updateAnnotation(annotationId, payload)` | `PATCH /api/ai/annotations/{annotation_id}` | 对齐 | 工作区归档保存 dirty mask |
|
||||
| `deleteAnnotation(annotationId)` | `DELETE /api/ai/annotations/{annotation_id}` | 对齐 | 工作区清空当前帧已保存标注 |
|
||||
| `importGtMask(file, projectId, frameId, templateId?, options?)` | `POST /api/ai/import-gt-mask` | 对齐 | multipart 上传 GT mask;支持 `unknown_color_policy=discard/undefined`;后端仅接受灰度 maskid 图或 RGB 三通道完全相同的 `[X,X,X]` maskid 图,0 为背景、X 为 maskid;按模板 `maskId` 匹配类别,未知 maskid 可舍弃或导入为未定义类别;尺寸不同会最近邻拉伸到当前帧,连通域会生成 polygon 标注和 seed point |
|
||||
| `importGtMask(file, projectId, frameId, templateId?, options?)` | `POST /api/ai/import-gt-mask` | 对齐 | multipart 上传 GT mask;支持 `unknown_color_policy=discard/undefined`;后端仅接受 8-bit 灰度 maskid 图或 8-bit RGB 三通道完全相同的 `[X,X,X]` maskid 图,0 为背景、X 为 1-255 的 maskid;16-bit/uint16 GT_label、全背景 0 图和普通彩色类别图会被拒绝,全背景错误信息固定为“GT Mask 图片中没有非背景 maskid 区域。”;按模板 `maskId` 匹配类别,未知 maskid 可舍弃或导入为未定义类别;尺寸不同会最近邻拉伸到当前帧,连通域会生成高精度 polygon 标注;导入标注可直接用于 `/api/ai/analyze-mask` 和 `/api/ai/smooth-mask`,前端不显示或拖动 seed point |
|
||||
| `getDashboardOverview()` | `GET /api/dashboard/overview` | 对齐 | Dashboard 初始统计、队列和活动日志 |
|
||||
| `exportCoco(projectId)` | `GET /api/export/{projectId}/coco` | 对齐 | 后端实际是 `GET /api/export/{project_id}/coco` |
|
||||
| `exportMasks(projectId)` | `GET /api/export/{projectId}/masks` | 对齐 | 下载单标注 mask、语义融合 mask 和类别映射 ZIP |
|
||||
@@ -63,7 +63,7 @@ Authorization: Bearer <token>
|
||||
| GET | `/api/auth/me` | 当前用户 |
|
||||
| GET/POST/PATCH/DELETE | `/api/admin/users` | 管理员用户管理 |
|
||||
| GET | `/api/admin/audit-logs` | 管理员审计日志 |
|
||||
| POST | `/api/admin/demo-factory-reset` | 演示部署恢复出厂设置;请求体需 `confirmation=RESET_DEMO_FACTORY` |
|
||||
| POST | `/api/admin/demo-factory-reset` | 演示部署恢复出厂设置;请求体需 `confirmation=RESET_DEMO_FACTORY`;重置后保留默认 admin、演示视频项目和一个已按文件名自然顺序生成帧的演示 DICOM 项目;响应包含兼容单个 `project` 和完整 `projects` 列表 |
|
||||
| POST | `/api/projects` | 创建项目 |
|
||||
| GET | `/api/projects` | 项目列表 |
|
||||
| GET | `/api/projects/{project_id}` | 项目详情 |
|
||||
@@ -98,7 +98,7 @@ Authorization: Bearer <token>
|
||||
| GET | `/api/dashboard/overview` | Dashboard 聚合快照 |
|
||||
| GET | `/api/export/{project_id}/coco` | 导出 COCO JSON |
|
||||
| GET | `/api/export/{project_id}/masks` | 导出 PNG mask ZIP |
|
||||
| GET | `/api/export/{project_id}/results` | 统一导出分割结果 ZIP,包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json`、`原始图片/` 和按参数选择的 `分开Mask分割结果/`、`GT_label图/`、`Pro_label彩色分割结果/`、`Mix_label重叠覆盖彩色分割结果/`;GT_label 背景为 0,类别值使用模板中的真实 maskid,缺失 maskid 的旧标注才补下一个可用正整数 |
|
||||
| GET | `/api/export/{project_id}/results` | 统一导出分割结果 ZIP,包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json`、`原始图片/` 和按参数选择的 `分开Mask分割结果/`、`GT_label图/`、`Pro_label彩色分割结果/`、`Mix_label重叠覆盖彩色分割结果/`;GT_label 固定输出 8-bit uint8 PNG,背景为 0,类别值使用模板中的真实 maskid,`maskid:0` 待分类和背景同为 0,缺失 maskid 的旧标注才补下一个可用正整数;正整数 maskid 超出 1-255 时拒绝导出 |
|
||||
| GET | `/health` | 健康检查 |
|
||||
| WS | `/ws/progress` | WebSocket 进度通道,未出现在 OpenAPI paths 中 |
|
||||
|
||||
@@ -301,7 +301,7 @@ SAM 2.1 变体使用对应 video predictor 的 mask seed 传播;`model=sam2`
|
||||
- `getProjectAnnotations()` 已接入 `GET /api/ai/annotations`。
|
||||
- `updateAnnotation()` 已接入 `PATCH /api/ai/annotations/{annotationId}`。
|
||||
- `deleteAnnotation()` 已接入 `DELETE /api/ai/annotations/{annotationId}`。
|
||||
- `importGtMask()` 已接入 `POST /api/ai/import-gt-mask`,导入后端生成的 polygon 标注、原始 `gt_label_value`、原图尺寸/是否拉伸信息和 seed point。导入端使用 `cv2.IMREAD_UNCHANGED` 保留低数值/16-bit GT_label 图的像素值;灰度图和 RGB 三通道相等图均按模板 `maskId` 匹配类别,不再按彩色图 RGB 颜色匹配类别;超出现有类别时由 `unknown_color_policy` 决定舍弃或写为 `gt_unknown_class` 未定义类别。
|
||||
- `importGtMask()` 已接入 `POST /api/ai/import-gt-mask`,导入后端生成的高精度 polygon 标注、原始 `gt_label_value`、原图尺寸/是否拉伸信息。导入端使用 `cv2.IMREAD_UNCHANGED` 读取后校验 dtype,仅接受 8-bit 灰度图和 8-bit RGB 三通道相等图,并按模板 `maskId` 匹配类别;16-bit/uint16 GT_label、全背景 0 图和普通彩色 RGB 类别图都会返回格式错误,全背景图保留“GT Mask 图片中没有非背景 maskid 区域。”提示;超出现有类别时由 `unknown_color_policy` 决定舍弃或写为 `gt_unknown_class` 未定义类别。导入 mask 与普通 mask 共用拓扑统计、边缘平滑和保存更新接口,前端不显示黄色 seed point。
|
||||
- `exportMasks()` 已接入 `GET /api/export/{projectId}/masks`。
|
||||
- `parseMedia()` 已改为创建 Celery 后台任务,并返回 `ProcessingTask`。
|
||||
- `queuePropagationTask()` 已接入 `/api/ai/propagate/task`,自动传播不再依赖长时间同步 HTTP 请求。
|
||||
@@ -312,7 +312,7 @@ SAM 2.1 变体使用对应 video predictor 的 mask seed 传播;`model=sam2`
|
||||
- Dashboard 任务列表已展示 queued/running/success/failed/cancelled 任务,并可通过 `getTask()` 查看失败详情;`summary.parsing_task_count` 仍只统计 queued/running。
|
||||
- 工作区“分割结果导出”已调用 `exportSegmentationResults()`,并会先保存未归档 mask;旧的 `exportCoco()` / `exportMasks()` 仍保留为兼容接口。
|
||||
- PNG mask ZIP 已包含每帧 `semantic_frame_*.png` 和 `semantic_classes.json`,重叠区域按 zIndex 裁决。
|
||||
- 统一导出 ZIP 下载文件名为 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`;项目名来自 `Project.name` 并会替换文件系统不安全字符,时间戳来自帧 `timestamp_ms` 并格式化为 `0h00m00s000ms`,帧号使用项目抽帧后的 1-based `frame_index + 1`,不使用原视频 `source_frame_number`。ZIP 内包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json` 和 `原始图片/`。原始图片按 `视频名称_时间戳_项目帧序号` 命名;选择分开 mask 时写入 `分开Mask分割结果/{视频名称_时间戳_项目帧序号}_分别导出/{视频名称_时间戳_项目帧序号}_{类别名称}_maskid{maskid}.png`,同一帧同一类别会合并为一张二值 mask;选择 GT_label 图时写入 `GT_label图/{视频名称_时间戳_项目帧序号}.png`;选择 Pro_label 彩色图时写入 `Pro_label彩色分割结果/{视频名称_时间戳_项目帧序号}.png`;选择 Mix_label 叠加图时写入 `Mix_label重叠覆盖彩色分割结果/{视频名称_时间戳_项目帧序号}.png`,透明度由 `mix_opacity` 控制,默认 0.3。导出时 maskid 与 GT_label 像素值相同;有模板 maskid 的类别保留真实 maskid,缺失 maskid 的旧标注补下一个可用正整数并写入映射 JSON,跨图一致;maskid 不参与覆盖排序,覆盖顺序仍使用内部拖拽排序字段。
|
||||
- 统一导出 ZIP 下载文件名为 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`;项目名来自 `Project.name` 并会替换文件系统不安全字符,时间戳来自帧 `timestamp_ms` 并格式化为 `0h00m00s000ms`,帧号使用项目抽帧后的 1-based `frame_index + 1`,不使用原视频 `source_frame_number`。ZIP 内包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json` 和 `原始图片/`。原始图片按 `视频名称_时间戳_项目帧序号` 命名;选择分开 mask 时写入 `分开Mask分割结果/{视频名称_时间戳_项目帧序号}_分别导出/{视频名称_时间戳_项目帧序号}_{类别名称}_maskid{maskid}.png`,同一帧同一类别会合并为一张二值 mask;选择 GT_label 图时写入 `GT_label图/{视频名称_时间戳_项目帧序号}.png`,固定为 8-bit uint8 PNG;选择 Pro_label 彩色图时写入 `Pro_label彩色分割结果/{视频名称_时间戳_项目帧序号}.png`;选择 Mix_label 叠加图时写入 `Mix_label重叠覆盖彩色分割结果/{视频名称_时间戳_项目帧序号}.png`,透明度由 `mix_opacity` 控制,默认 0.3。导出时 maskid 与 GT_label 像素值相同;有模板 maskid 的类别保留真实 maskid,其中 `maskid:0` 的“待分类”和背景同为 0,缺失 maskid 的旧标注补下一个可用正整数并写入映射 JSON,跨图一致;正整数 maskid 必须在 1-255 内,超出时拒绝导出;maskid 不参与覆盖排序,覆盖顺序仍使用内部拖拽排序字段。
|
||||
|
||||
## 仍需处理的接口问题
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
1. COCO JSON 调用 `/api/export/{projectId}/coco`。
|
||||
2. PNG Mask ZIP 调用 `/api/export/{projectId}/masks`。
|
||||
3. 兼容 PNG Mask ZIP 仍保留单标注二值 `mask_*.png`,同时输出 `semantic_frame_*.png` 和 `semantic_classes.json`。
|
||||
4. 统一导出调用 `/api/export/{projectId}/results`,支持整体视频、特定范围帧、当前图片三种范围,以及分开 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图;ZIP 固定包含 maskid/GT 像素值映射 JSON 和原始图片文件夹,各输出文件夹按客户指定的 `视频名称_0h00m00s000ms_项目帧序号` 规则命名;GT_label 图背景为 0,类别值优先使用模板中的真实 maskid,缺失 maskid 的旧标注才补下一个可用正整数。
|
||||
4. 统一导出调用 `/api/export/{projectId}/results`,支持整体视频、特定范围帧、当前图片三种范围,以及分开 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图;ZIP 固定包含 maskid/GT 像素值映射 JSON 和原始图片文件夹,各输出文件夹按客户指定的 `视频名称_0h00m00s000ms_项目帧序号` 规则命名;GT_label 图固定为 8-bit uint8 PNG,背景为 0,类别值优先使用模板中的真实 maskid,其中 `maskid:0` 的“待分类”和背景同为 0,缺失 maskid 的旧标注才补下一个可用正整数,正整数 maskid 超出 1-255 会拒绝导出。
|
||||
|
||||
剩余建议:
|
||||
|
||||
@@ -95,17 +95,17 @@ Dashboard 的解析队列现在已经从“项目状态派生”升级为任务
|
||||
|
||||
## 阶段 6:GT 导入与点区域(已完成基础增强版)
|
||||
|
||||
Word 方案中的完整版本包含距离变换、骨架提取和聚类。当前已经完成基础增强版:导入二值/标签 mask 图片后,后端按非零像素值拆分类别,再按连通域生成 polygon 标注,并用距离变换提取一个正向 seed point。
|
||||
Word 方案中的完整版本包含距离变换、骨架提取和聚类。当前已经完成基础增强版:导入二值/标签 mask 图片后,后端按非零像素值拆分类别,再按连通域生成高精度 polygon 标注;导入结果与普通 mask 共用拓扑统计、边缘平滑、编辑和保存链路,前端不显示或拖动 seed point。
|
||||
|
||||
已完成:
|
||||
|
||||
1. 工作区左侧工具栏提供“导入 GT Mask”入口,位置在“重叠区域去除”之后。
|
||||
2. 前端调用 `POST /api/ai/import-gt-mask` multipart 接口。
|
||||
3. 后端按非零像素值拆分多类别 mask。
|
||||
4. 后端使用 OpenCV contour 提取每个类别下的连通域。
|
||||
5. 后端使用 distance transform 生成 `points` seed。
|
||||
4. 后端使用 OpenCV 高精度 contour 提取每个类别下的连通域,尽量保留边界细节,并用点数上限保护前端性能。
|
||||
5. 后端保留 distance transform `points` seed 供数据兼容。
|
||||
6. 导入结果写入 `annotations` 表并回显为工作区 mask。
|
||||
7. 前端把 seed point 转为像素坐标显示在 Canvas 上,拖动后会标记标注为 dirty 并可归档保存。
|
||||
7. 前端不显示 seed point,也不提供 seed point 拖动;导入 mask 与普通 mask 保持一致的可选中、顶点编辑、拓扑统计、边缘平滑和保存体验。
|
||||
|
||||
剩余建议:
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
- 角色包括 `admin`、`annotator` 和 `viewer`;`admin/annotator` 可写入业务数据和触发 AI/传播,`viewer` 只能访问读接口,用户管理后台仅 `admin` 可用。
|
||||
- 管理员侧栏显示“用户管理”入口;管理员可以新增用户、修改角色、停用/启用、修改密码、删除无项目用户。
|
||||
- 系统记录登录成功/失败和用户管理操作到 `audit_logs`,管理员后台可查看最近审计日志。
|
||||
- 管理员后台提供“恢复演示出厂设置”危险操作;前端必须二次确认,后端也必须校验 `confirmation=RESET_DEMO_FACTORY`,执行后只保留默认 admin 账号、系统模板和一个尚未生成帧的演示视频项目,清空其它用户、项目、帧、标注、任务、用户模板和旧审计记录,并写入本次重置审计。
|
||||
- 管理员后台提供“恢复演示出厂设置”危险操作;前端必须二次确认,后端也必须校验 `confirmation=RESET_DEMO_FACTORY`,执行后只保留默认 admin 账号、系统模板、演示视频项目和一个已按文件名自然顺序生成帧的演示 DICOM 项目,清空其它用户、项目、帧、标注、任务、用户模板和旧审计记录,并写入本次重置审计。
|
||||
- 系统默认模板至少包含“腹腔镜胆囊切除术”和“头颈部CT分割”;恢复演示出厂设置不得删除系统默认模板。
|
||||
|
||||
## R2 项目管理
|
||||
|
||||
@@ -24,10 +25,12 @@
|
||||
- 用户可以新建项目,前端调用 `POST /api/projects`;后端把项目归属到当前登录用户。
|
||||
- 用户可以选择项目,进入工作区。
|
||||
- 用户可以导入视频文件,前端创建项目、上传文件并刷新项目列表;导入视频不自动拆帧。
|
||||
- 用户可以对已导入且尚未生成帧的视频项目点击“生成帧”,在弹窗中选择目标 FPS 后创建拆帧任务。
|
||||
- 用户可以对已导入且尚未生成帧的视频项目点击“生成帧”,在弹窗中选择目标 FPS 后创建拆帧任务;项目名称编辑状态下不能显示/触发生成帧入口,DICOM 项目不能显示生成帧入口。
|
||||
- 用户可以导入 DICOM 序列,前端上传 DICOM、触发拆帧、刷新项目列表。
|
||||
- 用户可以在项目库项目卡片上修改项目名称,名称不能为空。
|
||||
- 用户可以在项目卡片删除按钮旁复制项目;复制时可选择“新项目重置”或“全内容复制”。新项目重置必须复制项目媒体字段和已生成帧序列,但不复制标注或 mask 元数据;全内容复制必须额外复制标注和关联 mask 元数据,并将复制标注重新指向新项目中的对应帧。任务运行历史不复制。
|
||||
- 用户可以在项目卡片上删除项目;前端调用 `DELETE /api/projects/{id}`,删除成功后从项目库移除,若删除当前项目则清空工作区当前项目、帧、mask 和选区。
|
||||
- 后端支持项目创建、列表、详情、局部更新和删除。
|
||||
- 后端支持项目创建、列表、详情、局部更新、复制和删除。
|
||||
- 后端删除项目时通过 ORM 级联删除项目帧、标注、导出 mask 元数据和后台任务记录。
|
||||
- 后端支持项目帧创建、列表和单帧查询。
|
||||
|
||||
@@ -36,9 +39,11 @@
|
||||
- 后端允许上传视频、图片、DICOM 文件,其他扩展名返回 400。
|
||||
- 未提供项目 ID 上传时,后端自动创建项目。
|
||||
- 提供项目 ID 上传时,后端把上传对象关联到该项目。
|
||||
- 项目库导入视频和导入 DICOM 序列时,前端必须显示导入进度条;浏览器提供上传总字节数时显示百分比和已上传/总字节数,未提供总字节数时显示已上传字节的非确定进度。DICOM 导入还必须显示本次有效 `.dcm` 文件数量,并在上传完成后持续显示解析任务进度,直到成功、失败或取消。
|
||||
- 拆帧接口根据项目 `source_type` 处理视频或 DICOM。
|
||||
- 拆帧接口支持 `parse_fps`、`max_frames` 和 `target_width` 参数,用于生成可被 SAM 2 视频处理复用的标准帧序列。
|
||||
- 视频帧使用连续 `frame_%06d.jpg` 命名,默认从 `frame_000000.jpg` 开始,并按 `target_width` 缩放。
|
||||
- DICOM 批量导入和解析必须按文件名自然顺序处理 `.dcm` 文件,避免数字文件名被字符串排序打乱。
|
||||
- 视频/DICOM 解析后都使用连续 `frame_%06d.jpg` 命名,默认从 `frame_000000.jpg` 开始;视频帧按 `target_width` 缩放。
|
||||
- 拆帧完成后写入 `frames` 记录,并把项目状态设为 `ready`。
|
||||
- 每条帧记录包含 `frame_index`、`image_url`、`width`、`height`、`timestamp_ms` 和 `source_frame_number`。
|
||||
- 任务完成结果包含 `frame_sequence` 元数据:`original_fps`、`parse_fps`、`frame_count`、`duration_ms`、`target_width`、帧宽高和对象存储前缀。
|
||||
@@ -68,21 +73,22 @@
|
||||
- 工具栏可以切换当前 active tool。
|
||||
- 工作区左侧工具栏不展示正向点、反向点、框选工具;这些入口只属于 AI 智能分割页。
|
||||
- 侧栏“AI智能分割”和工作区工具栏 AI 跳转入口必须使用带明确 AI 语义的图标,而不是普通魔法棒等泛化工具图标。
|
||||
- 魔法棒按钮切换到 AI 页面。
|
||||
- 工作区 AI 智能分割入口切换到 AI 页面。
|
||||
- 多边形、矩形、圆、画笔、橡皮擦工具会在 Canvas 上生成或编辑可保存的 polygon mask;左侧工具栏不再提供创建点和创建线段入口。
|
||||
- 多边形通过点击取点并按 Enter 完成,也支持三点后点击首节点闭合;矩形、圆通过拖拽生成;画笔和橡皮擦支持调整大小。
|
||||
- 画笔工具只在语义分类树有选中类别时可用,按住拖动时以圆形笔触采样,鼠标松开后一次性 union 成连续区域;如果笔触与当前选中 mask 连通,默认合并到该 mask,否则生成新的当前类别 mask。
|
||||
- 橡皮擦工具只在当前帧已选中 mask 时可用,按住拖动时以圆形笔触采样,鼠标松开后从选中 mask 中 difference 扣除;扣空时删除该 mask,已保存 mask 仍需同步后端删除。
|
||||
- 创建多边形、创建矩形、区域合并/去除、调整多边形等 Canvas 左上角上下文提示只作为短提示,切换工具或操作状态变化时显示,数秒后自动隐藏,避免长期遮挡待编辑图像;再次切换工具或操作状态变化会重新显示。
|
||||
- 绘制工具点击已有 mask 时应继续执行当前绘制动作,不应被 mask 选择逻辑吞掉。
|
||||
- 工具栏提供“调整多边形”工具,用户可以点击 mask 进入 polygon 顶点编辑态;按住顶点即可直接拖动并实时更新 mask 几何,不需要先单击选中顶点,已保存 mask 会标记为 dirty;顶点和 seed point 等子节点拖拽不能冒泡成画布拖拽,编辑结束后 Canvas 当前缩放和平移视口必须保持不变。
|
||||
- 所有 polygon mask 都不显示黄色 seed point,也不提供 seed point 拖动;普通手工/AI/GT mask 在画布上应保持一致的区域渲染、选择、顶点编辑、拓扑统计、边缘平滑和保存体验。
|
||||
- 工具栏提供“调整多边形”工具,用户可以点击 mask 进入 polygon 顶点编辑态;按住顶点即可直接拖动并实时更新 mask 几何,不需要先单击选中顶点,已保存 mask 会标记为 dirty;顶点拖拽不能冒泡成画布拖拽,编辑结束后 Canvas 当前缩放和平移视口必须保持不变。
|
||||
- 工具栏在“重叠区域去除”之后提供“导入 GT Mask”入口;该入口使用区别于普通编辑工具的紫色底色,不切换 activeTool。
|
||||
- 顶点编辑态显示边中点插入手柄;点击边中点会在该边中间新增顶点。
|
||||
- “调整多边形”工具下双击 polygon 边界时,会在最接近的线段上按双击位置新增顶点。
|
||||
- 顶点编辑态下选中顶点后可用 Delete/Backspace 删除顶点,但不会让 polygon 少于三点。
|
||||
- 选中整个 mask 且未选中具体顶点时,Delete/Backspace 删除该 mask;已保存 mask 同步调用后端删除接口。
|
||||
- 选中整个 mask 且未选中具体顶点时,Delete/Backspace 删除该 mask;已保存 mask 同步调用后端删除接口;如果删除对象属于自动传播链或是传播 seed,应同步删除同一传播链上的自动传播 mask,但不能删除其他帧独立 AI 推理或人工标注 mask。
|
||||
- 撤销、重做绑定全局 `maskHistory/maskFuture`,工作区支持顶栏按钮和 Canvas 快捷键,AI 页支持自己的按钮;左侧工具栏不重复放置撤销/重做入口。
|
||||
- 区域合并工具支持多选当前帧 mask,并使用 polygon union 生成合并后的主 mask。
|
||||
- 区域合并工具支持多选当前帧 mask,并使用 polygon union 生成合并后的主 mask;被合并移除的次级 mask 若带传播链,应同步删除其同链自动传播结果。
|
||||
- 区域去除工具支持多选当前帧 mask,并从第一个选中的主 mask 中扣除后续选中 mask。
|
||||
- 区域合并/去除模式显示已选数量,并隐藏 polygon 编辑手柄以避免手柄抢占多选点击;第一个选中的主区域使用黄色实线轮廓,后续参与合并/扣除的区域使用红色虚线轮廓。
|
||||
- 区域去除结果包含内洞时,前端保留 hole ring 并用 even-odd 规则渲染。
|
||||
@@ -118,7 +124,8 @@
|
||||
- 工作区传播功能以当前打开帧作为参考帧,并使用该帧全部 mask 作为 seed;用户不再选择“选中区域/当前帧全部”传播对象。
|
||||
- 工作区传播功能允许设置传播起始帧和传播结束帧;前端以当前参考帧为 seed,只向起止范围内位于参考帧之前和之后的帧传播,源帧不重复保存。
|
||||
- 工作区只保留一个“自动传播”按钮,点击后在指定范围内按前向/后向自动生成 mask。
|
||||
- 自动传播提交前,前端必须先保存当前项目中的 draft/dirty mask;参考帧 seed 优先使用后端 `annotation_id` 作为稳定来源,避免第一次用前端临时 id 传播、后续保存后无法替换旧传播结果。
|
||||
- 当前参考帧没有 mask 时,点击“开始传播”必须提示“当前参考帧无遮罩”,且不得提交传播任务或保存其它帧标注。
|
||||
- 自动传播提交前,前端必须只保存当前参考帧中的 draft/dirty mask;参考帧 seed 优先使用后端 `annotation_id` 作为稳定来源,避免第一次用前端临时 id 传播、后续保存后无法替换旧传播结果;其它帧的脏标注不能在传播准备阶段触发无关后端更新。
|
||||
- 前端会把多个 seed 或双向范围拆成 `steps`,通过 `POST /api/ai/propagate/task` 创建 `propagate_masks` 后台任务,避免长 HTTP 请求卡在浏览器侧,同时避免并发抢占 GPU。
|
||||
- `POST /api/ai/propagate` 作为单 seed 同步兼容接口保留;`POST /api/ai/propagate/task` 是工作区自动传播使用的任务接口。两者当前支持四个 SAM 2.1 变体;兼容 `model=sam2` 并归一化为 tiny。SAM 2.1 使用官方 `SAM2VideoPredictor.add_new_mask()` 和 `propagate_in_video()`。
|
||||
- 自动传播任务写入 `processing_tasks`,前端轮询 `GET /api/tasks/{task_id}` 显示进度并刷新标注;Dashboard 也能看到该任务,任务可取消和重试。
|
||||
@@ -143,17 +150,19 @@
|
||||
- 工作区加载项目帧后会查询已保存标注并回显。
|
||||
- 工作区支持导入 GT mask 图片,前端调用 `POST /api/ai/import-gt-mask`。
|
||||
- 导入 GT Mask 时,前端必须让用户选择未知 maskid 处理策略:舍弃未知类别,或导入为“未定义类别”等待后续重新命名。
|
||||
- 后端导入 GT mask 时必须支持二值 mask、灰度/16-bit `GT_label图`,以及 RGB 三通道完全相同的 `[X,X,X]` maskid 图;0 是背景,X 是 maskid。灰度/RGB 等通道图按当前模板 `maskId` 匹配类别,超出现有类别时按用户选择的策略处理;普通彩色 RGB 类别图不再视为合法 GT mask,必须返回图片不符合要求的明确错误。
|
||||
- 后端导入 GT mask 时必须仅支持 8-bit 二值/灰度 `GT_label图`,以及 8-bit RGB 三通道完全相同的 `[X,X,X]` maskid 图;0 是背景,X 是 1-255 的 maskid。灰度/RGB 等通道图按当前模板 `maskId` 匹配类别,超出现有类别时按用户选择的策略处理;16-bit/uint16 GT_label 和普通彩色 RGB 类别图不再视为合法 GT mask,必须返回图片不符合要求的明确错误。
|
||||
- 后端导入 GT mask 时必须把全背景 0 图视为非法 GT mask,返回“GT Mask 图片中没有非背景 maskid 区域。”,前端导入预览也必须保留同一提示并禁止继续导入。
|
||||
- 导入 GT mask 前端必须提供导入结果预览,显示检测到的 maskid、未知 maskid 和尺寸适配提示;如果 mask 图片尺寸与当前帧不同,后端导入前必须按当前帧长宽用最近邻插值拉伸,使 mask 可适配当前图片。
|
||||
- 后端导入 GT mask 时按非背景像素值或颜色拆分多类别区域,再按连通域生成 polygon 标注,并通过距离变换写入 seed point。
|
||||
- 前端会回显导入标注的 seed point;拖动 seed point 后,已保存标注会变为 dirty,归档保存时会更新后端 `points`。
|
||||
- 后端导入 GT mask 时按非背景像素值或颜色拆分多类别区域,再按连通域生成高精度 polygon 标注;轮廓提取应尽量保留边界细节,同时对单轮廓点数设置上限避免严重影响前端渲染和编辑性能;可通过距离变换写入内部 `points` seed 供数据兼容。
|
||||
- 前端不回显导入标注的 seed point,也不提供 seed point 拖动;导入 mask 必须与普通 mask 共用拓扑锚点统计、边缘平滑、顶点编辑、分类和保存能力。
|
||||
|
||||
## R8 模板库
|
||||
|
||||
- 前端展示模板列表,调用 `GET /api/templates`。
|
||||
- 用户可以新建、编辑、删除模板。
|
||||
- 用户可以新建、编辑、删除模板,也可以在“生效中模板架构清单”中用鼠标复制现有模板为当前用户私有副本。
|
||||
- 模板分类存放在 `mapping_rules.classes`,规则存放在 `mapping_rules.rules`。
|
||||
- 前端支持添加/删除分类、拖拽排序后更新内部覆盖优先级、JSON 批量导入、加载腹腔镜默认分类。界面不展示内部优先级数值,只展示每个类别稳定的 `maskid`。
|
||||
- 所有新建、复制、批量导入和后端返回的模板必须包含 `maskid: 0`、颜色 `[0,0,0]`/`#000000`、名称为“待分类”的保留分类;该分类固定显示在语义分类树最后,不能删除,也不能通过拖拽上移。
|
||||
- 前端支持添加/删除分类、拖拽排序后更新内部覆盖优先级和 JSON 批量导入。模板详情页分类区标题必须显示为“语义分类树(拖拽调层级)”,右上角按钮必须显示为“+ 新建分类”;分类行右侧不得显示“未分类/批量导入/模板名”等描述标签,必须显示垃圾桶图标并可点击删除该 label。复制模板必须保留分类名称、颜色、`maskid`、内部层级顺序和规则,但要重建类别内部 id。界面不展示内部优先级数值,只展示每个类别稳定的 `maskid`。
|
||||
- 后端支持模板创建、列表、详情、局部更新和删除。
|
||||
|
||||
## R9 本体检查面板
|
||||
@@ -162,11 +171,12 @@
|
||||
- 面板显示模板分类;新增自定义分类会写入当前激活模板的后端 `mapping_rules.classes`。
|
||||
- 用户可以选择具体分类;新 AI mask 会记录 `classId`、`className`、`classZIndex`,并在保存时写入 `mask_data.class`。
|
||||
- 如果 Canvas 当前已经选中一个或多个 mask,点击语义分类树会把这些 mask 的 `label`、`color` 和 class 元数据改为该分类;如果这些 mask 属于自动传播链,还必须通过 `source_annotation_id`、`source_mask_id` 和 `propagation_seed_key` 同步更新同一传播链前后帧的对应 mask;已保存 mask 会进入 `dirty` 状态,归档保存时更新后端。
|
||||
- 打开工作区回显项目标注时,如果已保存 mask 的 class 不再存在于其所属模板中,前端必须把该 mask 转为 `maskid: 0` 的“待分类”mask,保留几何,标记为 dirty,等待用户重新分类并保存。
|
||||
- 添加自定义分类需要先选择模板,保存时调用 `PATCH /api/templates/{id}` 并同步全局模板 store。
|
||||
- “特定目标实例属性追踪”下方显示当前选中 mask 的 `className/label`,不显示全局 active class 的旧值。
|
||||
- 当前实例属性面板不展示“当前选中区域”计数;当前 mask 交互以单选为主,计数长期为 1,不作为有效业务信息展示。
|
||||
- 选中 mask 后,拓扑锚点调用 `POST /api/ai/analyze-mask` 自动读取,不再显示固定占位值;后端 `topology_anchor_count` 必须表示 polygon 的真实顶点数量,不能用抽样后的展示点数代替;前端必须静默忽略 abort/cancel 或过期的分析请求,避免快速切换 mask、拖动平滑预览或卸载组件时误显示“后端属性读取失败”;前端不再展示“后端模型置信度”条目,也不再提供“重新提取拓扑锚点”调试按钮。
|
||||
- 选中 mask 后,右侧实例属性面板提供“边缘平滑强度”和“应用边缘平滑”;调整滑杆时必须立即更新数值,但后端预览请求需要做短防抖,用户停止拖动约 220ms 后再调用 `POST /api/ai/smooth-mask` 并用返回 polygon 临时预览当前 mask 边缘,避免连续拖动时请求过密造成卡顿;预览阶段不标 dirty;点击“应用边缘平滑”后确认当前预览结果,前端必须把平滑 polygon 作为新的实际 mask 几何写入当前 mask,并同步写入同一传播链前后对应 mask;整次平滑应用必须作为一个撤销/重做历史步骤,撤销/重做要同时作用于当前 mask 和传播链对应 mask;应用后相关 mask 标记为 dirty/draft,平滑强度重置为 0,用户仍可继续用 polygon 编辑工具编辑平滑后的新多边形,并通过顶栏保存状态按钮落库。后端平滑必须对 AI/SAM 密集轮廓执行去噪简化、Chaikin 平滑和二次简化,使结果 polygon 的密集边缘点实际减少;强度映射必须低段温和、高段继续递进,避免 20% 左右已经过度平滑且后续档位无明显变化。
|
||||
- 选中 mask 后,右侧实例属性面板提供“边缘平滑强度”和“应用边缘平滑”;调整滑杆时必须立即更新数值,但后端预览请求需要做短防抖,用户停止拖动约 220ms 后再调用 `POST /api/ai/smooth-mask` 并用返回 polygon 临时预览当前 mask 边缘,避免连续拖动时请求过密造成卡顿;预览阶段不标 dirty;点击“应用边缘平滑”后确认当前预览结果,前端必须把平滑 polygon 作为新的实际 mask 几何写入当前 mask,并同步写入同一传播链前后对应 mask;整次平滑应用必须作为一个撤销/重做历史步骤,撤销/重做要同时作用于当前 mask 和传播链对应 mask;应用后相关 mask 标记为 dirty/draft,平滑强度重置为 0,用户仍可继续用 polygon 编辑工具编辑平滑后的新多边形,并通过顶栏保存状态按钮落库;保存 dirty 传播链 mask 时必须保留传播来源 metadata,不能让原本自动传播帧变为人工/AI 标注帧。后端平滑必须对 AI/SAM 密集轮廓执行去噪简化、Chaikin 平滑和二次简化,使结果 polygon 的密集边缘点实际减少;强度映射必须低段温和、高段继续递进,避免 20% 左右已经过度平滑且后续档位无明显变化。
|
||||
|
||||
## R10 Dashboard 与 WebSocket
|
||||
|
||||
@@ -187,11 +197,11 @@
|
||||
- 后端支持 `GET /api/export/{project_id}/coco` 导出 COCO JSON。
|
||||
- 后端支持 `GET /api/export/{project_id}/masks` 导出 PNG mask ZIP。
|
||||
- 后端支持 `GET /api/export/{project_id}/results` 统一导出分割结果 ZIP,参数支持整体视频、特定范围帧和当前图片三种范围,并支持分开二值 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图;Mix_label 透明度默认 0.3。
|
||||
- 统一导出 ZIP 必须固定包含 `maskid_GT像素值_类别映射.json`,记录当前导出中每个类别的 `maskid`、GT_label 像素值、中文名、类别名、RGB 值、颜色和类别 key;GT_label 背景值固定为 0,语义类别值使用类别真实 maskid,缺失 maskid 的旧标注才补下一个可用正整数,且同一类别跨图片保持一致。
|
||||
- 统一导出 ZIP 必须固定包含 `maskid_GT像素值_类别映射.json`,记录当前导出中每个类别的 `maskid`、GT_label 像素值、中文名、类别名、RGB 值、颜色和类别 key;GT_label 必须固定输出 8-bit uint8 PNG,背景值固定为 0,语义类别值使用类别真实 maskid,缺失 maskid 的旧标注才补下一个可用正整数,且同一类别跨图片保持一致;`maskid: 0` 的“待分类”必须在映射中保留为 0,GT_label 内与背景同为 0;正整数 maskid 超出 1-255 时必须拒绝导出。
|
||||
- 统一导出 ZIP 必须固定包含 `原始图片/` 文件夹,导出范围内每帧的原始图片命名为 `视频名称_时间戳_项目帧序号` 加原图片扩展名;视频名称来自项目视频文件名,时间戳来自帧 `timestamp_ms` 并格式化为 `0h00m00s000ms`,帧号使用项目抽帧后的 1-based `frame_index + 1`,不使用原视频帧号。
|
||||
- 选择“分开 Mask”时,统一导出 ZIP 必须包含 `分开Mask分割结果/`;每帧建立 `{视频名称_时间戳_项目帧序号}_分别导出` 子文件夹,同一帧同一类别的所有 annotation 合并为一张二值 PNG,文件名包含 `视频名称_时间戳_项目帧序号_{类别名称}_maskid{maskid}`。
|
||||
- 选择“GT_label 黑白图”时,统一导出 ZIP 必须包含 `GT_label图/`;每帧输出一张融合后的 GT_label PNG,文件名为 `视频名称_时间戳_项目帧序号`,重叠区域仍按内部拖拽排序从低到高覆盖;maskid 不构成排序规范。
|
||||
- 选择“Pro_label 彩色图”时,统一导出 ZIP 必须包含 `Pro_label彩色分割结果/`;每帧输出一张按类别 RGB 上色的 PNG,背景为 `[0,0,0]`。
|
||||
- 选择“Pro_label 彩色图”时,统一导出 ZIP 必须包含 `Pro_label彩色分割结果/`;每帧输出一张按类别 RGB 上色的 PNG,背景为 `[0,0,0]`,`maskid: 0` 的“待分类”也必须输出为黑色 `[0,0,0]`。
|
||||
- 选择“Mix_label 叠加图”时,统一导出 ZIP 必须包含 `Mix_label重叠覆盖彩色分割结果/`;每帧输出一张彩色 label 叠加原始图片的 PNG,透明度可选且默认为 0.3。
|
||||
- GT_label、Pro_label 和 Mix_label 的重叠区域覆盖顺序必须和右侧“语义分类树”的内部覆盖优先级一致,低优先级先写入,高优先级后写入。
|
||||
- 分割结果导出 ZIP 文件名必须使用 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`;项目名来自项目库中的 `Project.name`,时间戳来自导出范围首尾帧 `timestamp_ms` 并格式化为 `0h00m00s000ms`,帧号使用项目抽帧后的 1-based `frame_index + 1`。
|
||||
@@ -200,7 +210,7 @@
|
||||
- 当前前端 `exportSegmentationResults()` API 封装已对齐统一导出路径。
|
||||
- 工作区“分割结果导出”按钮已替代原 JSON/PNG 两个按钮;点击后在下拉栏内选择导出范围、勾选导出内容,并在选择 Mix_label 时调节遮罩透明度和查看当前/待导出第一帧预览;导出范围默认选中“当前图片”,导出前会先保存当前未归档 mask。选择“特定范围帧”时,用户既可以直接修改起止帧输入框,也可以像自动传播、清空遮罩一样在播放进度条或视频处理进度条上点击/拖拽选择导出范围。
|
||||
- PNG mask ZIP 包含单标注二值 mask、按 zIndex 融合后的每帧语义 mask 和 `semantic_classes.json`。
|
||||
- 统一导出的 GT_label 图背景值固定为 0,所有语义类别值优先保留模板类别真实 maskid,缺失 maskid 的旧标注才按下一个可用正整数补值。
|
||||
- 统一导出的 GT_label 图必须是 8-bit uint8 PNG,背景值固定为 0,所有语义类别值优先保留模板类别真实 maskid,缺失 maskid 的旧标注才按下一个可用正整数补值;有效类别值范围为 0-255,其中 0 仅用于背景和系统保留的“待分类”。
|
||||
|
||||
## R12 配置
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
| 模型状态 | `src/components/ModelStatusBadge.tsx` | 展示 GPU 与当前 SAM 模型真实可用状态;工作区顶栏使用 compact 形态,只显示 GPU/CPU 状态,具体传播权重由旁边下拉负责 |
|
||||
| 登录页 | `src/components/Login.tsx` | 调用登录 API,写入 store |
|
||||
| Dashboard | `src/components/Dashboard.tsx` | 展示统计、任务控制、失败详情和 WebSocket 进度消息 |
|
||||
| 项目库 | `src/components/ProjectLibrary.tsx` | 项目列表、新建、删除、导入视频/DICOM、显式生成帧 |
|
||||
| 项目库 | `src/components/ProjectLibrary.tsx` | 项目列表、新建、重命名、删除、导入视频/DICOM、显式生成帧 |
|
||||
| 工作区 | `src/components/VideoWorkspace.tsx` | 加载帧和模板,组织工具栏、Canvas、本体面板、时间轴 |
|
||||
| Canvas | `src/components/CanvasArea.tsx` | 显示帧、缩放平移、点/框提示、渲染 mask |
|
||||
| 工具栏 | `src/components/ToolsPalette.tsx` | 切换工作区编辑工具、在“重叠区域去除”后触发 GT Mask 导入、跳转 AI 页面;AI 跳转入口复用 Bot + Sparkles 组合图标以明确表达 AI 智能分割;不再放置 AI 正/反点和框选工具,也不重复放置撤销/重做;拖拽/选择到创建圆、画笔/橡皮擦/区域合并/重叠区域去除、导入 GT Mask/AI 智能分割三类工具之间用浅灰横线分隔;紧凑垂直布局,高度不足时自身滚动;外层宽 56px,按钮列固定 48px,滚动条使用右侧外扩空间和低对比 `seg-scrollbar` |
|
||||
@@ -34,7 +34,7 @@
|
||||
| 时间轴 | `src/components/FrameTimeline.tsx` | 帧导航、播放进度、视频处理进度条、自动传播历史片段、自动传播/清空遮罩/导出范围选择、左右方向键切帧、播放和当前/总时长显示 |
|
||||
| 本体面板 | `src/components/OntologyInspector.tsx` | 模板选择、工作区 mask 透明度、分类树、后端自定义分类、mask 后端属性分析;内容过长时自身滚动,滚动条使用低对比 `seg-scrollbar` |
|
||||
| AI 页面 | `src/components/AISegmentation.tsx` | 独立 AI 推理视图,使用当前项目帧 |
|
||||
| 模板库 | `src/components/TemplateRegistry.tsx` | 模板 CRUD、分类编辑、导入、排序 |
|
||||
| 模板库 | `src/components/TemplateRegistry.tsx` | 模板 CRUD、分类编辑、导入、详情页和编辑弹窗拖拽排序 |
|
||||
| 短提示浮层 | `src/components/TransientNotice.tsx` | 项目库和模板库的非阻塞成功/失败提示,自动消失 |
|
||||
|
||||
## 后端模块
|
||||
@@ -88,21 +88,22 @@
|
||||
2. 项目、帧、媒体上传/拆帧、AI 标注、传播任务、任务列表、Dashboard 和导出接口都通过当前 JWT 用户过滤项目资源。
|
||||
3. `Template.owner_user_id` 支持用户模板;`owner_user_id IS NULL` 的模板视为系统模板,可作为默认分类体系对用户可见。
|
||||
4. 角色分为 `admin`、`annotator`、`viewer`:`admin/annotator` 可调用写入类业务接口,`viewer` 只能调用读接口;`/api/admin/*` 仅允许 `admin`。
|
||||
5. `UserAdmin.tsx` 仅在当前用户角色为 `admin` 时从 `Sidebar` 展示,调用 `/api/admin/users` 完成新增、角色修改、停用/启用、密码修改和删除无项目用户,调用 `/api/admin/audit-logs` 展示登录和管理操作审计;危险区“恢复演示出厂设置”先用浏览器确认,再要求输入 `RESET_DEMO_FACTORY`,随后调用 `/api/admin/demo-factory-reset`。
|
||||
6. `POST /api/admin/demo-factory-reset` 仅允许 `admin`,会重置默认 admin 密码/角色/启用状态,删除其它用户、项目、帧、标注、mask、任务、用户模板和旧审计,重新创建 `Data_MyVideo_1` 项目并上传 `settings.demo_video_path` 指向的视频作为未生成帧的源视频项目;系统模板保留以保证重置后仍可标注。
|
||||
5. `UserAdmin.tsx` 仅在当前用户角色为 `admin` 时从 `Sidebar` 展示,调用 `/api/admin/users` 完成新增、角色修改、停用/启用、密码修改和删除无项目用户,调用 `/api/admin/audit-logs` 展示登录和管理操作审计;改密码、删除用户和危险区“恢复演示出厂设置”均使用站内弹窗确认,恢复出厂设置要求输入 `RESET_DEMO_FACTORY` 后调用 `/api/admin/demo-factory-reset`。
|
||||
6. `POST /api/admin/demo-factory-reset` 仅允许 `admin`,会重置默认 admin 密码/角色/启用状态,删除其它用户、项目、帧、标注、mask、任务、用户模板和旧审计,重新创建 `settings.demo_video_path` 指向的演示视频项目,以及 `settings.demo_dicom_dir` 指向的演示 DICOM 项目;DICOM 会按文件名自然顺序上传和生成帧;系统模板保留以保证重置后仍可标注。
|
||||
7. 缺失、过期或伪造的 Bearer token 会在业务路由返回 401,权限不足返回 403,其他用户项目资源对当前用户表现为 404。
|
||||
|
||||
### 项目导入与生成帧
|
||||
|
||||
1. `ProjectLibrary` 创建项目。
|
||||
2. 导入视频时上传源视频到 `/api/media/upload` 并关联项目;该步骤不调用 `/api/media/parse`。
|
||||
2. 导入视频时上传源视频到 `/api/media/upload` 并关联项目;该步骤不调用 `/api/media/parse`。上传期间项目库显示导入进度条、百分比和已上传字节,完成后短暂显示“视频导入完成”。
|
||||
3. 用户在项目卡片点击“生成帧”,在弹窗中选择目标 FPS。
|
||||
4. 前端调用 `/api/media/parse` 创建异步拆帧任务;可通过 `parse_fps`、`max_frames` 和 `target_width` 指定标准帧序列参数。
|
||||
5. Celery worker 执行 FFmpeg/OpenCV/pydicom 拆帧,视频帧按 `frame_%06d.jpg` 从 `frame_000000.jpg` 连续命名,并按目标宽度缩放。
|
||||
5. Celery worker 执行 FFmpeg/OpenCV/pydicom 拆帧;DICOM 在前端选择、后端上传、worker 下载和 pydicom 读取时都按文件名自然顺序排序;视频/DICOM 解析结果都按 `frame_%06d.jpg` 从 `frame_000000.jpg` 连续命名,视频帧按目标宽度缩放。
|
||||
6. worker 写入 `frames.timestamp_ms` 和 `frames.source_frame_number`,并在任务 `result.frame_sequence` 中记录 FPS、帧数、时长、尺寸和对象存储前缀。
|
||||
7. worker 持续更新 `processing_tasks`,并发布 Redis `seg:progress`。
|
||||
8. 刷新项目列表;项目卡片右上角 FPS 徽标显示生成关键帧序列时选择的 `parse_fps`,原始视频 FPS 仅作为底部“原 xx fps”辅助信息显示。
|
||||
9. 导入视频、生成帧、上传 DICOM 和失败反馈使用 `TransientNotice`,不再使用浏览器 `alert()` 阻塞操作;提示默认数秒后自动消失。
|
||||
9. 导入视频、生成帧、上传 DICOM 和失败反馈使用 `TransientNotice`,不再使用浏览器 `alert()` 阻塞操作;提示默认数秒后自动消失。视频和 DICOM 上传阶段额外显示项目库内的导入进度面板,DICOM 面板显示有效文件数量,并在上传完成后切换为解析任务进度,轮询 `GET /api/tasks/{task_id}` 直到成功、失败或取消。
|
||||
10. DICOM 和视频帧序列写入同一 `frames` 表并共用工作区、时间轴、AI 传播、标注保存、GT 导入和导出链路,差异只存在于项目库导入入口和后端解析器。
|
||||
|
||||
### 任务控制
|
||||
|
||||
@@ -123,14 +124,14 @@
|
||||
6. `CanvasArea` 会把全局 `selectedMaskIds` 中仍存在于当前帧的 id 同步回本地选区,避免帧初始化时的临时清空覆盖 AI 页推送过来的选中态;如果切换到另一帧时原 id 不存在,但目标帧存在同一自动传播链的结果,前端会用 `source_annotation_id`、`source_mask_id` 和 `propagation_seed_key` 匹配对应传播 mask 并自动选中。
|
||||
7. `CanvasArea` 根据容器和帧尺寸按 86% 适配比例计算初始 scale/position,使底图默认居中且尽量大,但保留画布边距;滚轮缩放和拖拽平移仍由用户后续控制。
|
||||
8. `CanvasArea` 未选中特定 mask 时,会按 `classZIndex` 从低到高渲染当前帧 mask;该值来自右侧“语义分类树”的拖拽排序,因此高优先级类别会后渲染并覆盖低优先级类别。有选中 mask 时,编辑态可保留选中区域置顶,方便拖点、换类和布尔操作。
|
||||
9. `FrameTimeline` 顶部播放进度条显示当前播放位置;其下方视频处理进度条根据 `Mask.metadata.source` / `propagated_from_frame_id` 计算自动传播帧并显示蓝色区段,对人工绘制或 AI 智能分割等非传播 mask 帧显示红色竖线。当前帧另用白色竖线贯穿播放进度条和视频处理进度条,和青色播放进度、红色标注、蓝色传播状态区分。普通状态下,视频处理进度条可点击跳转到对应帧,红色人工/AI 标注帧和蓝色自动传播帧标识本身也可点击跳转。处理条未处理背景使用中性灰,和红色/蓝色标记保持明显区分。`VideoWorkspace` 会记录当前会话最近 8 次成功处理过的自动传播范围,并通过 `propagationHistory` 传给 `FrameTimeline`;时间轴会把这些片段叠加为同一蓝色系的纯色条,按距最新传播的时间顺序逐次变暗,且第 5 次及更早统一为阈值旧记录色,不再在单个片段内部使用渐变。清空片段遮罩时,`VideoWorkspace` 会按清空范围移除或裁剪本地传播历史片段,避免已清空的处理范围仍显示最近传播条。底部缩略图导航轴对非当前帧使用红色边框标识人工/AI 标注帧,使用蓝色边框标识自动传播/推理帧;如果同一帧同时存在人工/AI 标注和自动传播结果,红色人工/AI 标注边框优先保留,自动传播状态只作为蓝色内描边。当前帧使用青色外框高亮优先,若当前帧同时是人工/AI 标注帧,则以青色外框加红色内描边同时表达两个状态,外层当前帧框和内层人工/AI 框的顺序固定。工作区进入自动传播、清空片段遮罩或特定范围帧导出选择模式时,播放进度条和视频处理进度条显示 amber 覆盖层,并额外用洋红色起始线和黄绿色结束线贯穿两条进度条,表达待处理或待导出范围边界,可点击/拖拽设置起止帧。
|
||||
9. `FrameTimeline` 顶部播放进度条显示当前播放位置;其下方视频处理进度条根据 `Mask.metadata.source` / `propagated_from_frame_id` 计算自动传播帧并显示蓝色区段,对人工绘制或 AI 智能分割等非传播 mask 帧显示红色竖线。当前帧另用白色竖线贯穿播放进度条和视频处理进度条,和青色播放进度、红色标注、蓝色传播状态区分。普通状态下,视频处理进度条可点击跳转到对应帧,红色人工/AI 标注帧和蓝色自动传播帧标识本身也可点击跳转。处理条未处理背景使用中性灰,和红色/蓝色标记保持明显区分。`VideoWorkspace` 会记录当前会话最近 8 次成功处理过的自动传播范围,并通过 `propagationHistory` 传给 `FrameTimeline`;时间轴会把这些片段叠加为同一蓝色系的纯色条,按距最新传播的时间顺序逐次变暗,且第 5 次及更早统一为阈值旧记录色,不再在单个片段内部使用渐变。传播历史条只显示当前仍有自动传播 mask 的帧,`VideoWorkspace` 会在 mask 变化时按剩余传播 mask 裁剪本地传播历史;`FrameTimeline` 渲染时也会按当前传播 mask 再次拆分/过滤,避免单独删除传播 mask 后空帧仍显示红/蓝颜色。底部缩略图导航轴对非当前帧使用红色边框标识人工/AI 标注帧,使用蓝色边框标识自动传播/推理帧;如果同一帧同时存在人工/AI 标注和自动传播结果,红色人工/AI 标注边框优先保留,自动传播状态只作为蓝色内描边。当前帧使用青色外框高亮优先,若当前帧同时是人工/AI 标注帧,则以青色外框加红色内描边同时表达两个状态,外层当前帧框和内层人工/AI 框的顺序固定。工作区进入自动传播、清空片段遮罩或特定范围帧导出选择模式时,播放进度条和视频处理进度条显示 amber 覆盖层,并额外用洋红色起始线和黄绿色结束线贯穿两条进度条,表达待处理或待导出范围边界,可点击/拖拽设置起止帧。
|
||||
10. 当前帧传入 `CanvasArea`。
|
||||
11. 工作区顶栏短状态文本会在空闲状态下自动消失;保存、导出、导入 GT 和传播任务运行中仍保留进度状态,无帧项目提示也会保留。
|
||||
12. 左侧工具栏和右侧本体/语义分类面板使用 `seg-scrollbar` 定制纵向滚动条;默认滚动条 thumb 低透明度融入深色背景,hover/focus 时增强为青色提示,避免系统默认滚动条在工具区中过于突兀。左侧工具栏额外保留右侧滚动条槽位,按钮列仍按原 48px 布局,避免滚动条和图标抢空间。
|
||||
12. 右侧面板不再显示“本体论与属性分类管理树”固定说明栏,直接展示实际可操作内容。
|
||||
13. 右侧“遮罩透明度”滑杆写入 Zustand `maskPreviewOpacity`,`CanvasArea` 和 `AISegmentation` 都用该值计算 mask group opacity;选中 mask 在基础透明度上加亮或按基础透明度显示,方便保留选中反馈。
|
||||
14. Canvas 点击 mask 后,全局 `selectedMaskIds` 会同步到 `OntologyInspector`;本体面板按选中 mask 的 `classId`、`className/label` 和颜色匹配模板分类,自动设置 active class,并把分类按钮滚动/聚焦到可见区域。
|
||||
15. 工作区顶栏“清空片段遮罩”和“自动传播”共用时间轴范围选择交互;第一次点击“清空片段遮罩”会进入范围选择模式,按钮变为“确认清空”,用户可在播放进度条或视频处理进度条上点击/拖拽选择起止帧;进入清空模式后顶栏显示“清空全部 / 保留人工/AI”两段式模式选择,默认“清空全部”。“清空全部”会对范围内已保存 mask 调用 `DELETE /api/ai/annotations/{id}`,同时移除范围内本地 draft mask、被清空的选区和与清空范围重叠的本地传播历史条;若范围内存在非自动传播来源的 mask,也就是时间轴红色“人工/AI 标注帧”,执行前会弹出“是否清除“人工/AI标注帧”?”确认,取消则不删除任何 mask。“保留人工/AI”只删除范围内自动传播/推理 mask,不删除人工绘制或 AI 智能分割生成的红色标注帧,不弹出人工帧确认;范围外 mask 和传播历史片段保持不变。
|
||||
15. 工作区顶栏“清空片段遮罩”和“自动传播”共用时间轴范围选择交互;第一次点击“清空片段遮罩”会进入范围选择模式,按钮变为“确认清空”,用户可在播放进度条或视频处理进度条上点击/拖拽选择起止帧;进入清空模式后顶栏显示“清空全部 / 保留人工/AI”两段式模式选择,默认“清空全部”。“清空全部”会对范围内已保存 mask 调用 `DELETE /api/ai/annotations/{id}`,同时移除范围内本地 draft mask、被清空的选区和与清空范围重叠的本地传播历史条;若范围内存在非自动传播来源的 mask,也就是时间轴红色“人工/AI 标注帧”,执行前会显示站内确认弹窗,取消则不删除任何 mask。“保留人工/AI”只删除范围内自动传播/推理 mask,不删除人工绘制或 AI 智能分割生成的红色标注帧,不弹出人工帧确认;范围外 mask 和传播历史片段保持不变。
|
||||
|
||||
### AI 点/框推理
|
||||
|
||||
@@ -191,12 +192,13 @@
|
||||
|
||||
1. 用户选择“调整多边形”或“拖拽/选择”后点击 Canvas 上的 mask path,`CanvasArea` 记录 `selectedMaskId` 并显示该 mask 第一条 polygon 的顶点控制点和边中点插入手柄。
|
||||
2. 顶点 `mousedown/dragstart` 会立即设置当前顶点选择;拖动过程中通过 `dragMove` 实时重算 `pathData`、像素 `segmentation`、`bbox`、`area`,不需要先单击顶点再拖动。
|
||||
3. Stage 的 `onDragEnd` 只处理 Stage 自身拖拽;polygon 顶点、GT seed point 等子节点拖拽结束事件会被忽略,避免子节点坐标误写入 Canvas `position` 导致视口跳动。
|
||||
3. Stage 的 `onDragEnd` 只处理 Stage 自身拖拽;polygon 顶点等子节点拖拽结束事件会被忽略,避免子节点坐标误写入 Canvas `position` 导致视口跳动。
|
||||
4. 点击边中点手柄会在该边中点插入新顶点;在“调整多边形”工具下双击 polygon path 会在最接近的线段上按双击位置插入新顶点。
|
||||
5. 如果 mask 已有 `annotationId`,编辑会把 `saveStatus` 标成 `dirty` 且 `saved=false`。
|
||||
6. 归档保存时复用现有 `PATCH /api/ai/annotations/{annotation_id}` 链路,把更新后的 normalized polygon 写回后端。
|
||||
7. 选中顶点后 Delete/Backspace 可删除顶点;前端保持 polygon 至少三点。
|
||||
8. 未选中具体顶点但选中了 mask 时,Delete/Backspace 从前端 store 删除该 mask;如果包含 `annotationId`,通过工作区回调调用后端删除接口。
|
||||
8. 未选中具体顶点但选中了 mask 时,Delete/Backspace 从前端 store 删除该 mask;如果包含 `annotationId`,通过工作区回调调用后端删除接口;删除对象属于传播链或传播 seed 时,删除范围会扩展到同链自动传播 mask,但不移除其他帧独立 AI 推理/人工 mask。
|
||||
9. 普通 mask 和导入 mask 都不显示黄色 seed point,也不提供 seed point 拖动;保存 payload 仍可保留已有 `points` 数据兼容,但画布体验统一为区域选择和 polygon 顶点编辑。
|
||||
|
||||
### 区域合并与去除
|
||||
|
||||
@@ -205,7 +207,7 @@
|
||||
3. Canvas 左上角提示布尔选择顺序:第一个选中的是主区域,后续区域参与合并或扣除。
|
||||
4. 布尔选择态按选择顺序区分角色:第一个选中的主区域使用黄色实线轮廓,后续参与合并/扣除的区域使用红色虚线轮廓;所有已选区域填充透明度保持一致,避免被误解为阴影模式异常。
|
||||
5. `CanvasArea` 把 `Mask.segmentation` 转为 `polygon-clipping` 的 MultiPolygon。
|
||||
6. `area_merge` 使用 union,更新第一个选中的主 mask,并从前端 store 移除后续被合并 mask;如果被移除 mask 已保存,会调用工作区传入的删除回调删除后端标注。
|
||||
6. `area_merge` 使用 union,更新第一个选中的主 mask,并从前端 store 移除后续被合并 mask;如果被移除 mask 已保存,会调用工作区传入的删除回调删除后端标注;被移除 mask 的同链自动传播结果也会一并删除。
|
||||
7. `area_remove` 使用 difference,从第一个选中的主 mask 中扣除后续选中 mask,扣除对象本身保留;如果 difference 产生内洞,`segmentation` 保留外圈和 hole ring,渲染时使用 even-odd fill。
|
||||
8. 结果会重算 `pathData`、`segmentation`、`bbox`、`area`,已保存主 mask 会进入 dirty 状态并复用归档 PATCH 链路;带洞结果的面积按外圈减内洞计算。
|
||||
|
||||
@@ -215,10 +217,10 @@
|
||||
2. 前端 `importGtMask()` 以 multipart form-data 调用 `POST /api/ai/import-gt-mask`,携带 `project_id` 和 `frame_id`。
|
||||
3. 后端验证项目、帧、模板后使用 OpenCV 读取灰度 mask。
|
||||
4. 后端按非零像素值拆分多类别标签。
|
||||
5. 后端对每个类别的前景做 contour 提取,每个连通域保存为一个 `Annotation`。
|
||||
6. `points` 字段保存距离变换中心 seed point,`mask_data.polygons` 保存 normalized polygon,`mask_data.gt_label_value` 保存原始像素类别值。
|
||||
5. 后端对每个类别的前景做高精度 contour 提取,每个连通域保存为一个 `Annotation`;轮廓使用未压缩链提取并以较小 `approxPolyDP` epsilon 保留细节,超过点数上限时才逐步增加简化强度或抽样。
|
||||
6. `points` 字段可保存距离变换中心 seed point 供数据兼容,`mask_data.polygons` 保存 normalized polygon,`mask_data.gt_label_value` 保存原始像素类别值;导入后的 polygon 与普通 mask 走同一套拓扑锚点统计、边缘平滑、编辑和保存链路。
|
||||
7. 前端重新读取项目标注并回显。
|
||||
8. `annotationToMask()` 会把 normalized seed point 转成像素坐标,Canvas 以可拖拽点显示;拖动后 `buildAnnotationPayload()` 会把点再归一化写回后端。
|
||||
8. `annotationToMask()` 仍可把后端 `points` 转成像素坐标保存在 mask 数据中,但 Canvas 不显示 seed point,也不提供拖动;普通 polygon 若没有后端 seed point,保存逻辑可按 polygon 自动计算内部代表点写入,以保持数据兼容。
|
||||
|
||||
### 模板管理
|
||||
|
||||
@@ -227,18 +229,19 @@
|
||||
3. 保存时调用 `createTemplate()` 或 `updateTemplate()`。
|
||||
4. 后端把 `classes`、`rules` 打包进 `mapping_rules`。
|
||||
5. 返回时再解包给前端。
|
||||
6. `CanvasArea` 把当前选中的 mask id 同步到全局 `selectedMaskIds`;切换工具、切换帧或卸载 Canvas 时会清空选择。
|
||||
7. `AISegmentation` 生成 mask 后会写入全局 `masks` 并把生成的 mask id 写入 `selectedMaskIds`;点击 AI 页预览 mask 也会更新 `selectedMaskIds`。
|
||||
8. AI 页“推送至工作区编辑”会先检查待推送 AI 候选 mask 是否具备 `classId` 或 `className`;缺少语义分类时清空普通推理反馈,并通过 `TransientNotice` 右上角 error toast 提示用户先点右侧语义分类树,不切换模块、不修改工具状态。
|
||||
9. `AISegmentation` 卸载时会清理仍缺少 `classId/className` 的本页 AI 候选,并同步移除对应 `selectedMaskIds`,避免用户绕过推送按钮从侧栏切到工作区时带入无语义 mask。
|
||||
10. AI 页语义校验通过后会切换到工作区并把 `activeTool` 设为 `edit_polygon`;`CanvasArea` 初始读取全局 `selectedMaskIds`,让 AI 页选中的 mask 在工作区继续保持选中。
|
||||
11. 工作区帧/标注异步加载完成后,`hydrateSavedAnnotations()` 会合并本地未保存 draft mask 和后端已保存 mask,不会用后端回显结果直接覆盖整个 `masks` store。
|
||||
12. `OntologyInspector` 可以选择具体分类;选择结果进入全局 store,供 `CanvasArea` 和 `AISegmentation` 新建/更新 mask 时使用。
|
||||
13. 如果 `selectedMaskIds` 中存在当前 store 的 mask,点击分类时会立即更新这些 mask 的 `templateId`、`classId`、`className`、`classZIndex`、`label` 和 `color`。
|
||||
14. 对属于自动传播链的 mask,分类更新会复用 `source_annotation_id`、`source_mask_id` 和 `propagation_seed_key` 查找同一目标实例在前后帧中的传播结果,并同步更新这些传播 mask 的分类元数据,避免同一物体跨帧语义不一致。
|
||||
15. 同一次点击会把这些已选 mask 移动到前端 `masks` 数组末尾;`CanvasArea` 按数组顺序渲染,后渲染的 Path 显示在最上层,方便用户继续编辑刚换标签的区域。该显示置顶不改变模板 `zIndex` 或后端导出语义覆盖规则。
|
||||
16. 已保存 mask 被重新分类后进入 `dirty` 且 `saved=false`,同传播链被同步更新的已保存 mask 也进入 `dirty`,继续复用工作区归档保存的 PATCH 链路。
|
||||
16. 模板保存、删除和 JSON 导入失败使用 `TransientNotice` 非阻塞提示,默认数秒后自动消失。
|
||||
6. 模板详情页和编辑弹窗都支持拖拽调整语义类别层级顺序;拖拽后重算 `zIndex`,保存到后端模板并刷新当前详情页,`maskId` 保持不变。所有模板都会归一化包含黑色 `maskId: 0` 的“待分类”保留类,该类固定在语义分类树最后,不参与删除和拖拽上移。编辑弹窗中的 JSON 批量导入会先显示分类数量、maskid 分配起点和缺失颜色提示,语法或结构错误以内联错误展示,确认导入后进入编辑态,保存模板时落库。
|
||||
7. `CanvasArea` 把当前选中的 mask id 同步到全局 `selectedMaskIds`;切换工具、切换帧或卸载 Canvas 时会清空选择。
|
||||
8. `AISegmentation` 生成 mask 后会写入全局 `masks` 并把生成的 mask id 写入 `selectedMaskIds`;点击 AI 页预览 mask 也会更新 `selectedMaskIds`。
|
||||
9. AI 页“推送至工作区编辑”会先检查待推送 AI 候选 mask 是否具备 `classId` 或 `className`;缺少语义分类时清空普通推理反馈,并通过 `TransientNotice` 右上角 error toast 提示用户先点右侧语义分类树,不切换模块、不修改工具状态。
|
||||
10. `AISegmentation` 卸载时会清理仍缺少 `classId/className` 的本页 AI 候选,并同步移除对应 `selectedMaskIds`,避免用户绕过推送按钮从侧栏切到工作区时带入无语义 mask。
|
||||
11. AI 页语义校验通过后会切换到工作区并把 `activeTool` 设为 `edit_polygon`;`CanvasArea` 初始读取全局 `selectedMaskIds`,让 AI 页选中的 mask 在工作区继续保持选中。
|
||||
12. 工作区帧/标注异步加载完成后,`hydrateSavedAnnotations()` 会合并本地未保存 draft mask 和后端已保存 mask,不会用后端回显结果直接覆盖整个 `masks` store。
|
||||
13. `OntologyInspector` 可以选择具体分类;选择结果进入全局 store,供 `CanvasArea` 和 `AISegmentation` 新建/更新 mask 时使用。
|
||||
14. 如果 `selectedMaskIds` 中存在当前 store 的 mask,点击分类时会立即更新这些 mask 的 `templateId`、`classId`、`className`、`classZIndex`、`label` 和 `color`。
|
||||
15. 对属于自动传播链的 mask,分类更新会复用 `source_annotation_id`、`source_mask_id` 和 `propagation_seed_key` 查找同一目标实例在前后帧中的传播结果,并同步更新这些传播 mask 的分类元数据,避免同一物体跨帧语义不一致。
|
||||
16. 同一次点击会把这些已选 mask 移动到前端 `masks` 数组末尾;`CanvasArea` 按数组顺序渲染,后渲染的 Path 显示在最上层,方便用户继续编辑刚换标签的区域。该显示置顶不改变模板 `zIndex` 或后端导出语义覆盖规则。
|
||||
17. 已保存 mask 被重新分类后进入 `dirty` 且 `saved=false`,同传播链被同步更新的已保存 mask 也进入 `dirty`,继续复用工作区归档保存的 PATCH 链路。
|
||||
18. 模板保存、删除和 JSON 导入失败使用 `TransientNotice` 非阻塞提示,默认数秒后自动消失。
|
||||
|
||||
### 导出
|
||||
|
||||
@@ -247,7 +250,7 @@
|
||||
3. PNG mask 导出还会按 `mask_data.class.zIndex` 或模板 `z_index` 从低到高覆盖,生成每帧语义融合 mask。
|
||||
4. ZIP 内写入 `semantic_classes.json`,记录语义值到类别、颜色和 zIndex 的映射。
|
||||
5. 前端使用“分割结果导出”统一入口替代原 JSON/PNG 两个按钮;点击后在下拉栏选择整体视频、特定范围帧或当前图片,默认选中当前图片,并勾选分开二值 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图。选择“特定范围帧”时,导出起止帧输入框和 `FrameTimeline` 的范围拖拽选择共用同一组导出范围状态;选择 Mix_label 时显示透明度滑杆,默认 0.3,并用当前/待导出第一帧做遮罩预览。提交前会保存待归档标注,然后下载统一 ZIP。下载文件名使用 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`;项目名来自 `currentProject.name`,起止帧按当前导出范围取首尾帧,时间戳格式为 `0h00m00s000ms`,帧号使用项目抽帧后的 1-based 顺序,项目名中的文件系统不安全字符会替换为 `_`。
|
||||
6. 统一导出 ZIP 固定包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json` 和 `原始图片/`;原始图片文件名使用 `视频名称_时间戳_项目帧序号`。导出会保留类别真实 maskid,GT_label 像素值与 maskid 相同并跨图一致;缺失 maskid 的旧标注才补下一个可用正整数并写入映射 JSON。选择分开 mask 时包含 `分开Mask分割结果/`,每帧建立 `{视频名称_时间戳_项目帧序号}_分别导出` 子文件夹,并按“同一帧同一类别合并一张图”的方式输出 `{视频名称_时间戳_项目帧序号}_{类别名称}_maskid{maskid}.png`。选择 GT_label 图时包含 `GT_label图/{视频名称_时间戳_项目帧序号}.png`;选择 Pro_label 图时包含 `Pro_label彩色分割结果/{视频名称_时间戳_项目帧序号}.png`;选择 Mix_label 图时包含 `Mix_label重叠覆盖彩色分割结果/{视频名称_时间戳_项目帧序号}.png`。GT_label、Pro_label 和 Mix_label 的重叠区域按内部拖拽排序从低到高覆盖,和未选中状态下的画布显示顺序一致;maskid 不参与排序。后端直接下载接口的 `Content-Disposition` 使用同一 ZIP 命名规则,并用 `filename*` 支持中文项目名。
|
||||
6. 统一导出 ZIP 固定包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json` 和 `原始图片/`;原始图片文件名使用 `视频名称_时间戳_项目帧序号`。导出会保留类别真实 maskid,GT_label 固定为 8-bit uint8 PNG,像素值与 maskid 相同并跨图一致;`maskId: 0` 的“待分类”保持 0,和背景同为黑色,Pro_label 中也输出为 `[0,0,0]`;缺失 maskid 的旧标注才补下一个可用正整数并写入映射 JSON;正整数 maskid 超出 1-255 会拒绝导出。选择分开 mask 时包含 `分开Mask分割结果/`,每帧建立 `{视频名称_时间戳_项目帧序号}_分别导出` 子文件夹,并按“同一帧同一类别合并一张图”的方式输出 `{视频名称_时间戳_项目帧序号}_{类别名称}_maskid{maskid}.png`。选择 GT_label 图时包含 `GT_label图/{视频名称_时间戳_项目帧序号}.png`;选择 Pro_label 图时包含 `Pro_label彩色分割结果/{视频名称_时间戳_项目帧序号}.png`;选择 Mix_label 图时包含 `Mix_label重叠覆盖彩色分割结果/{视频名称_时间戳_项目帧序号}.png`。GT_label、Pro_label 和 Mix_label 的重叠区域按内部拖拽排序从低到高覆盖,和未选中状态下的画布显示顺序一致;maskid 不参与排序。后端直接下载接口的 `Content-Disposition` 使用同一 ZIP 命名规则,并用 `filename*` 支持中文项目名。
|
||||
7. 右侧 `OntologyInspector` 的语义分类树支持拖拽调整内部覆盖顺序;拖拽后保存到模板并同步当前工作区同类 mask 的 `classZIndex`,但保留类别 maskid 不变。
|
||||
|
||||
## 接口契约
|
||||
@@ -264,7 +267,7 @@
|
||||
- `propagateMasks()` 使用 `POST /api/ai/propagate`,请求体为 `project_id`、`frame_id`、`model`、`seed`、`direction`、`max_frames`,作为单 seed 同步兼容接口保留。
|
||||
- `queuePropagationTask()` 使用 `POST /api/ai/propagate/task`,请求体为 `project_id`、`frame_id`、`model`、`steps`、`include_source`、`save_annotations`,返回 `ProcessingTask`。
|
||||
- `saveAnnotation()` 使用 `POST /api/ai/annotate`。
|
||||
- `importGtMask()` 使用 `POST /api/ai/import-gt-mask` multipart form-data,并传入 `unknown_color_policy=discard|undefined`。前端上传前弹出导入结果预览和未知 maskid 策略选择;后端使用 `cv2.IMREAD_UNCHANGED` 保留低数值/16-bit GT_label 像素值。合法 GT mask 限定为灰度图或 RGB 三通道完全相同的 `[X,X,X]` maskid 图,0 为背景、X 为 maskid;灰度/RGB 等通道图按模板 `maskId` 匹配类别,普通彩色 RGB 类别图不再按颜色匹配并会返回格式错误;未知类别按策略舍弃或保存为 `gt_unknown_class` 未定义类别。若 GT mask 尺寸和当前帧不同,后端用最近邻插值拉伸到当前帧尺寸后再生成 polygon。
|
||||
- `importGtMask()` 使用 `POST /api/ai/import-gt-mask` multipart form-data,并传入 `unknown_color_policy=discard|undefined`。前端上传前弹出导入结果预览和未知 maskid 策略选择;后端使用 `cv2.IMREAD_UNCHANGED` 读取后校验 dtype。合法 GT mask 限定为 8-bit 灰度图或 8-bit RGB 三通道完全相同的 `[X,X,X]` maskid 图,0 为背景、X 为 1-255 的 maskid;灰度/RGB 等通道图按模板 `maskId` 匹配类别,16-bit/uint16 GT_label、全背景 0 图和普通彩色 RGB 类别图不再按颜色匹配并会返回格式错误;全背景图提示为“GT Mask 图片中没有非背景 maskid 区域。”;未知类别按策略舍弃或保存为 `gt_unknown_class` 未定义类别。若 GT mask 尺寸和当前帧不同,后端用最近邻插值拉伸到当前帧尺寸后再生成高精度 polygon。
|
||||
- `getProjectAnnotations()` 使用 `GET /api/ai/annotations`。
|
||||
- `updateAnnotation()` 使用 `PATCH /api/ai/annotations/{annotationId}`。
|
||||
- `deleteAnnotation()` 使用 `DELETE /api/ai/annotations/{annotationId}`。
|
||||
@@ -294,8 +297,8 @@
|
||||
以下能力属于当前冻结版本的占位或半可用功能:
|
||||
|
||||
- Dashboard 初始快照来自 `GET /api/dashboard/overview`;任务进度区由 `processing_tasks` queued/running/success/failed/cancelled 任务生成,处理中统计只计算 queued/running。
|
||||
- 已保存标注支持通过“应用分类”、polygon 顶点拖动/删除、边中点插入、多 polygon 子区域编辑和区域合并/去除进入 dirty 状态并归档更新;选中整块 mask 可用 Delete/Backspace 删除并同步后端;复杂洞结构编辑尚未实现。
|
||||
- 已保存标注支持通过“应用分类”、polygon 顶点拖动/删除、边中点插入、多 polygon 子区域编辑和区域合并/去除进入 dirty 状态并归档更新;选中整块 mask 可用 Delete/Backspace 删除并同步后端,同传播链自动传播结果会随传播 seed/传播结果删除而一并清理,独立 AI 推理/人工 mask 保留;复杂洞结构编辑尚未实现。
|
||||
- SAM 3 文本语义分割已从当前产品路径中禁用;相关源码保留,恢复时需要重新接入前端入口、registry、状态接口和测试。
|
||||
- 自定义分类通过 `PATCH /api/templates/{id}` 写入当前激活模板的 `mapping_rules.classes`。
|
||||
- 选中 mask 后,本体面板的“特定目标实例属性追踪”标题值来自当前 mask 的 `className/label`,不使用全局 active class;面板不再展示长期为 1 的“当前选中区域”计数;面板调用 `POST /api/ai/analyze-mask` 自动显示拓扑锚点数量等属性,`topology_anchor_count` 是真实 polygon 顶点数量,`topology_anchors` 只保留最多 64 个抽样点用于调试展示;`OntologyInspector` 会为分析请求维护递增序号,旧请求返回时不再回写状态,并静默忽略 Axios abort/cancel 错误,避免快速切换、平滑预览或组件卸载时把正常中止误报成失败;不再提供“重新提取拓扑锚点”调试按钮;“边缘平滑强度”滑杆会即时更新数值,但 `POST /api/ai/smooth-mask` 预览请求经过约 220ms 防抖后才发送,返回 polygon 作为临时预览写入当前 mask 显示,预览不改变保存状态;点击“应用边缘平滑”后,前端把平滑 polygon 作为新的实际几何写入当前 mask,并按传播 lineage 同步写入传播链前后对应 mask,相关 mask 标记为 dirty/draft,整次操作通过一次 `setMasks()` 进入撤销/重做历史;应用后不保留 `geometry_smoothing` 参数,平滑强度重置为 0。前端不再展示“后端模型置信度”。
|
||||
- GT mask 导入已完成多类别像素值拆分、contour、distance transform seed point 和前端 seed point 拖拽编辑;骨架提取、HDBSCAN 聚类和模板自动映射尚未实现。
|
||||
- GT mask 导入已完成多类别像素值拆分、contour 和 distance transform seed point 数据兼容;前端不显示或拖动 seed point,导入 mask 与普通 mask 共享拓扑统计、边缘平滑、顶点编辑、分类和保存体验;骨架提取、HDBSCAN 聚类和模板自动映射尚未实现。
|
||||
|
||||
@@ -14,17 +14,17 @@
|
||||
|
||||
| 需求 | 测试文件 | 覆盖点 |
|
||||
|------|----------|--------|
|
||||
| R1 登录与会话 | `src/components/Login.test.tsx`, `src/components/Sidebar.test.tsx`, `src/components/UserAdmin.test.tsx`, `src/store/useStore.test.ts`, `backend/tests/test_auth.py`, `backend/tests/test_admin.py` | 成功登录、JWT/token 写入、当前用户写入、刷新恢复基础状态、失败提示、登录输入 autocomplete、后端 401、`/api/auth/me`、管理员入口、用户 CRUD、角色权限、审计日志、viewer 读写权限边界、演示出厂设置二次确认和重置结果 |
|
||||
| R2 项目管理 | `src/lib/api.test.ts`, `src/components/ProjectLibrary.test.tsx`, `backend/tests/test_projects.py` | 前端字段映射、PATCH 更新、项目卡片删除、DELETE 契约、后端 CRUD、删除级联、帧列表、项目按当前 JWT 用户隔离 |
|
||||
| R3 媒体上传与拆帧 | `src/components/ProjectLibrary.test.tsx`, `src/components/TransientNotice.test.tsx`, `backend/tests/test_media.py`, `backend/tests/test_tasks.py` | 视频导入不自动拆帧、显式生成帧 FPS 选择、项目卡片显示目标 parse_fps 而非原视频 FPS、扩展名校验、自动建项目、关联项目、创建异步任务、非阻塞自动消失操作提示、标准帧序列参数、帧时间戳/源帧号、任务序列元数据、worker 注册帧、取消任务、重试任务、取消后 worker 停止 |
|
||||
| R4 工作区与帧浏览 | `src/components/VideoWorkspace.test.tsx`, `src/components/FrameTimeline.test.tsx` | 加载帧、无帧项目不自动解析并提示生成帧、工作区短状态自动消失、工作区/AI 画布底图默认居中且保留边距、工作区 mask 透明度、回显已保存标注时保留本地未保存 draft mask、选中 mask 后跨帧自动跟随同一传播链结果、清空片段遮罩进入时间轴范围选择并按选区批量清空、清空全部模式、保留人工/AI 模式只清传播 mask、清空人工/AI 标注帧前二次确认、取消确认不删除、仅自动传播帧不确认、清空后裁剪/移除重叠传播历史条、传播权重下拉深色可读配色、缩略图/range/视频处理进度条、视频处理进度条点击跳帧、人工/AI 标注帧红色竖线和标识点击跳帧、自动传播帧通过 source/lineage metadata 识别为蓝色区段和标识点击跳帧、最近自动传播历史片段同一蓝色系按新旧递进纯色显示,旧记录第 5 次后统一阈值色、当前帧白色贯穿线、传播/清空范围洋红/黄绿色边界贯穿线、缩略图红/蓝边框、人工/AI 标注帧叠加传播状态时红框优先保留并显示蓝色内描边、当前人工/AI 标注帧青色外框加红色内描边、普通状态不显示传播范围黄色选区、播放进度条和视频处理进度条选择传播/清空范围、左右方向键切帧、播放、按项目 FPS 显示当前/总时长 |
|
||||
| R5 工具栏 | `src/components/ToolsPalette.test.tsx`, `src/components/CanvasArea.test.tsx`, `src/components/VideoWorkspace.test.tsx`, `src/store/useStore.test.ts` | 工具切换、工具栏紧凑垂直布局和高度不足时滚动、工具栏低对比滚动条、工具栏外扩滚动条槽位不挤占按钮列、调整多边形工具、AI 跳转、GT Mask 导入位于重叠区域去除之后且使用紫色底色、GT Mask 未知类别导入策略选择、工作区工具栏不展示 AI 正/反点和框选、左侧工具栏不重复撤销/重做、左侧工具栏不展示创建点/创建线段、矩形/圆/多边形手工 mask 绘制、画笔/橡皮擦尺寸控制、画笔新建当前类别 mask、画笔与选中 mask 连通时自动合并、橡皮擦从选中 mask 扣除、未选中 mask 时画布按语义分类树内部优先级渲染、多边形 Enter/首节点闭合、上下文提示提示 Enter/Esc/首节点闭合且数秒后自动隐藏、polygon 顶点直接拖动/删除、顶点拖拽结束不改变 Canvas 视口、边中点插点、双击边界按位置插点、整块 mask 删除、区域合并/去除、布尔选择主区域/扣除区域视觉区分和选择顺序提示、内含去除 hole 渲染、合并模式隐藏编辑手柄、工作区顶栏撤销/重做按钮、顶栏撤销/重做图标强调色、撤销/重做快捷键和输入框快捷键跳过、撤销/重做历史栈 |
|
||||
| R6 AI 推理 | `src/lib/api.test.ts`, `src/components/CanvasArea.test.tsx`, `src/components/AISegmentation.test.tsx`, `src/components/VideoWorkspace.test.tsx`, `src/components/ModelStatusBadge.test.tsx`, `backend/tests/test_ai.py`, `backend/tests/test_sam2_engine.py` | SAM 2.1 变体选择、点/框/interactive 契约、semantic 禁用、SAM 3 入口隐藏和后端拒绝、SAM 2.1 最高分候选去重、SAM 2.1 框选后正负点细化同一候选 mask、AI 页框选发送 box prompt、AI 页框选后加点发送 interactive prompt、AI 页提示工具上下文提示、AI 页重复执行替换旧候选、SAM 2.1 反向点启用背景过滤且空结果移除旧候选、AI 页不渲染工作区已有 mask、AI 页可在候选 mask 上继续添加正/反点、AI 页可单点删除提示点并删除最近锚点、AI 页可删除选中候选且不删除工作区 mask、AI 页清空只移除本页候选、AI 页参数开关可读性文案且 options 字段不变、AI 页/右侧共享遮罩透明度只改预览 opacity、AI 页生成 mask 自动选中并可通过分类树换标签、AI 页无语义候选禁止推送到工作区并用 error toast 提示、离开 AI 页时清理未分类候选、AI 页推送到工作区编辑保留选择和当前帧、SAM 2.1 视频以当前参考帧全部 mask 和起止帧范围自动传播、传播前自动保存 draft/dirty seed mask、传播前独立选择 SAM 2.1 tiny/small/base+/large 权重、自动传播创建 Celery 任务、传播入队权重 id 规范化/拒绝不支持 id、传播 seed 来源 id/签名和历史平滑 metadata 兼容、历史平滑 seed 保存前对 forward/backward polygon 实际应用边缘平滑并减少密集轮廓点、边缘平滑强度缓入递进曲线、未编辑传播结果作为 seed 时继承原始签名并跳过重复传播、已编辑传播结果保留 lineage 但重算签名并清理旧结果、中间帧人工新增替代 seed 时清理下游同物体旧传播结果、中间帧 backward 传播清理旧 forward 结果、换权重传播先清理旧结果、旧临时 seed id 传播结果兼容清理、传播中轮询任务进度、传播任务取消/重试、传播来源 metadata 回显、空提示/空结果反馈、GPU/SAM2.1 状态、AI 参数 options、局部裁剪推理、背景过滤、状态徽标、坐标归一化、正负点 labels、polygons 转 path、后端 fake registry |
|
||||
| R7 标注保存 | `src/components/VideoWorkspace.test.tsx`, `src/components/CanvasArea.test.tsx`, `src/lib/api.test.ts`, `backend/tests/test_ai.py` | 保存状态按钮“保存 X 个改动/已全部保存”、保存标注、保存后用后端 saved annotation 替换已提交 draft、加载回显、更新 dirty 标注、清空删除已保存标注、GT mask 多类别导入、seed point 回显/归一化、项目不存在、帧不存在 |
|
||||
| R8 模板库 | `src/components/TemplateRegistry.test.tsx`, `src/components/TransientNotice.test.tsx`, `src/lib/api.test.ts`, `backend/tests/test_templates.py` | 前端模板加载/新建/编辑/删除、JSON 分类导入、JSON/保存错误非阻塞提示、mapping_rules 解包/打包、后端模板 CRUD |
|
||||
| R9 本体检查面板 | `src/components/OntologyInspector.test.tsx`, `src/components/CanvasArea.test.tsx`, `src/store/useStore.test.ts`, `backend/tests/test_ai.py` | 模板选择、面板标题简化、面板低对比滚动条、工作区遮罩透明度滑杆、分类展示、具体分类选择、Canvas 选区同步、点击 Canvas mask 后自动聚焦对应语义分类、点击分类给已选 mask 换标签并移动到前端渲染最上层、分类变更同步同一传播链前后帧对应 mask、自定义分类 PATCH 后端模板、目标实例标题显示当前 mask label、隐藏当前选中区域计数、隐藏后端模型置信度、选中 mask 后端拓扑属性分析、拓扑锚点数量按真实 polygon 顶点数显示、分析请求 abort/cancel 静默忽略且旧请求不覆盖新状态、边缘平滑强度防抖预览不标 dirty、应用边缘平滑后将 mask 标记为 dirty、平滑作为实际几何编辑、平滑同步传播链对应 mask、平滑保存时保留传播 lineage 而不把传播帧变成人工/AI 标注帧、平滑撤销/重做、平滑应用后强度归零 |
|
||||
| R1 登录与会话 | `src/components/Login.test.tsx`, `src/components/Sidebar.test.tsx`, `src/components/UserAdmin.test.tsx`, `src/store/useStore.test.ts`, `backend/tests/test_auth.py`, `backend/tests/test_admin.py` | 成功登录、JWT/token 写入、当前用户写入、刷新恢复基础状态、失败提示、登录输入 autocomplete、后端 401、`/api/auth/me`、管理员入口、用户 CRUD、角色权限、审计日志、viewer 读写权限边界、改密码/删除用户站内确认、演示出厂设置站内二次确认和重置结果 |
|
||||
| R2 项目管理 | `src/lib/api.test.ts`, `src/components/ProjectLibrary.test.tsx`, `backend/tests/test_projects.py` | 前端字段映射、PATCH 更新、项目卡片复制/删除、修改项目名称时隐藏生成帧、DICOM 项目不显示生成帧、复制项目 reset/full 契约、DELETE 契约、后端 CRUD、删除级联、帧列表、项目按当前 JWT 用户隔离 |
|
||||
| R3 媒体上传与拆帧 | `src/components/ProjectLibrary.test.tsx`, `src/components/TransientNotice.test.tsx`, `backend/tests/test_media.py`, `backend/tests/test_tasks.py` | 视频导入不自动拆帧、视频/DICOM 上传进度可视化、DICOM 导入显示有效文件数量并在上传后持续显示解析任务进度、显式生成帧 FPS 选择、项目卡片显示目标 parse_fps 而非原视频 FPS、扩展名校验、自动建项目、关联项目、创建异步任务、非阻塞自动消失操作提示、标准帧序列参数、帧时间戳/源帧号、任务序列元数据、worker 注册帧、取消任务、重试任务、取消后 worker 停止 |
|
||||
| R4 工作区与帧浏览 | `src/components/VideoWorkspace.test.tsx`, `src/components/FrameTimeline.test.tsx` | 加载帧、无帧项目不自动解析并提示生成帧、工作区短状态自动消失、工作区/AI 画布底图默认居中且保留边距、工作区 mask 透明度、回显已保存标注时保留本地未保存 draft mask、选中 mask 后跨帧自动跟随同一传播链结果、清空片段遮罩进入时间轴范围选择并按选区批量清空、清空全部模式、保留人工/AI 模式只清传播 mask、清空人工/AI 标注帧前二次确认、取消确认不删除、仅自动传播帧不确认、清空后裁剪/移除重叠传播历史条、删除单个传播 mask 后空帧不保留传播历史颜色、传播权重下拉深色可读配色、缩略图/range/视频处理进度条、视频处理进度条点击跳帧、人工/AI 标注帧红色竖线和标识点击跳帧、自动传播帧通过 source/lineage metadata 识别为蓝色区段和标识点击跳帧、最近自动传播历史片段同一蓝色系按新旧递进纯色显示,旧记录第 5 次后统一阈值色、当前帧白色贯穿线、传播/清空范围洋红/黄绿色边界贯穿线、缩略图红/蓝边框、人工/AI 标注帧叠加传播状态时红框优先保留并显示蓝色内描边、当前人工/AI 标注帧青色外框加红色内描边、普通状态不显示传播范围黄色选区、播放进度条和视频处理进度条选择传播/清空范围、左右方向键切帧、播放、按项目 FPS 显示当前/总时长 |
|
||||
| R5 工具栏 | `src/components/ToolsPalette.test.tsx`, `src/components/CanvasArea.test.tsx`, `src/components/VideoWorkspace.test.tsx`, `src/store/useStore.test.ts` | 工具切换、工具栏紧凑垂直布局和高度不足时滚动、工具栏低对比滚动条、工具栏外扩滚动条槽位不挤占按钮列、调整多边形工具、AI 跳转、GT Mask 导入位于重叠区域去除之后且使用紫色底色、GT Mask 未知类别导入策略选择、工作区工具栏不展示 AI 正/反点和框选、左侧工具栏不重复撤销/重做、左侧工具栏不展示创建点/创建线段、矩形/圆/多边形手工 mask 绘制、普通/导入 polygon mask 不显示黄色 seed point、画笔/橡皮擦尺寸控制、画笔新建当前类别 mask、画笔与选中 mask 连通时自动合并、橡皮擦从选中 mask 扣除、未选中 mask 时画布按语义分类树内部优先级渲染、多边形 Enter/首节点闭合、上下文提示提示 Enter/Esc/首节点闭合且数秒后自动隐藏、polygon 顶点直接拖动/删除、顶点拖拽结束不改变 Canvas 视口、边中点插点、双击边界按位置插点、整块 mask 删除、传播链自动传播 mask 随 seed/传播结果删除、独立 AI 推理 mask 不被误删、区域合并/去除、布尔选择主区域/扣除区域视觉区分和选择顺序提示、内含去除 hole 渲染、合并模式隐藏编辑手柄、工作区顶栏撤销/重做按钮、顶栏撤销/重做图标强调色、撤销/重做快捷键和输入框快捷键跳过、撤销/重做历史栈 |
|
||||
| R6 AI 推理 | `src/lib/api.test.ts`, `src/components/CanvasArea.test.tsx`, `src/components/AISegmentation.test.tsx`, `src/components/VideoWorkspace.test.tsx`, `src/components/ModelStatusBadge.test.tsx`, `backend/tests/test_ai.py`, `backend/tests/test_sam2_engine.py` | SAM 2.1 变体选择、点/框/interactive 契约、semantic 禁用、SAM 3 入口隐藏和后端拒绝、SAM 2.1 最高分候选去重、SAM 2.1 框选后正负点细化同一候选 mask、AI 页框选发送 box prompt、AI 页框选后加点发送 interactive prompt、AI 页提示工具上下文提示、AI 页重复执行替换旧候选、SAM 2.1 反向点启用背景过滤且空结果移除旧候选、AI 页不渲染工作区已有 mask、AI 页可在候选 mask 上继续添加正/反点、AI 页可单点删除提示点并删除最近锚点、AI 页可删除选中候选且不删除工作区 mask、AI 页清空只移除本页候选、AI 页参数开关可读性文案且 options 字段不变、AI 页/右侧共享遮罩透明度只改预览 opacity、AI 页生成 mask 自动选中并可通过分类树换标签、AI 页无语义候选禁止推送到工作区并用 error toast 提示、离开 AI 页时清理未分类候选、AI 页推送到工作区编辑保留选择和当前帧、SAM 2.1 视频以当前参考帧全部 mask 和起止帧范围自动传播、当前参考帧无遮罩提示、传播前只保存参考帧 draft/dirty seed mask、传播前独立选择 SAM 2.1 tiny/small/base+/large 权重、自动传播创建 Celery 任务、传播入队权重 id 规范化/拒绝不支持 id、传播 seed 来源 id/签名和历史平滑 metadata 兼容、历史平滑 seed 保存前对 forward/backward polygon 实际应用边缘平滑并减少密集轮廓点、边缘平滑强度缓入递进曲线、未编辑传播结果作为 seed 时继承原始签名并跳过重复传播、已编辑传播结果保留 lineage 但重算签名并清理旧结果、中间帧人工新增替代 seed 时清理下游同物体旧传播结果、中间帧 backward 传播清理旧 forward 结果、换权重传播先清理旧结果、旧临时 seed id 传播结果兼容清理、传播中轮询任务进度、传播任务取消/重试、传播来源 metadata 回显、空提示/空结果反馈、GPU/SAM2.1 状态、AI 参数 options、局部裁剪推理、背景过滤、状态徽标、坐标归一化、正负点 labels、polygons 转 path、后端 fake registry |
|
||||
| R7 标注保存 | `src/components/VideoWorkspace.test.tsx`, `src/components/CanvasArea.test.tsx`, `src/lib/api.test.ts`, `backend/tests/test_ai.py` | 保存状态按钮“保存 X 个改动/已全部保存”、保存标注、保存后用后端 saved annotation 替换已提交 draft、加载回显、更新 dirty 标注、清空删除已保存标注、GT mask 多类别导入、高精度 GT contour、导入 mask 可直接拓扑统计和边缘平滑、后端 seed point 归一化兼容但前端不显示或拖动、缺失 seed point 的普通 polygon 保存时自动写入代表点、项目不存在、帧不存在 |
|
||||
| R8 模板库 | `src/components/TemplateRegistry.test.tsx`, `src/components/TransientNotice.test.tsx`, `src/lib/api.test.ts`, `backend/tests/test_templates.py` | 前端模板加载/新建/编辑/删除、删除模板站内确认、鼠标复制模板为私有副本、所有模板归一化包含黑色 `maskid:0`“待分类”保留类、保留类固定最后且不可删除/拖拽上移、详情页“语义分类树(拖拽调层级)”标题、详情页“+ 新建分类”、详情页垃圾桶删除 label 且不显示来源标签、编辑后详情页刷新、详情页和编辑弹窗拖拽语义层级顺序、拖拽保存 `zIndex` 且不改变 maskid、JSON 分类导入预览、JSON 错误内联提示、保存错误非阻塞提示、mapping_rules 解包/打包、后端模板 CRUD |
|
||||
| R9 本体检查面板 | `src/components/OntologyInspector.test.tsx`, `src/components/CanvasArea.test.tsx`, `src/components/VideoWorkspace.test.tsx`, `src/store/useStore.test.ts`, `backend/tests/test_ai.py` | 模板选择、面板标题简化、面板低对比滚动条、工作区遮罩透明度滑杆、分类展示、具体分类选择、模板类别删除后项目旧 mask 回显为 `maskid:0` 待分类、Canvas 选区同步、点击 Canvas mask 后自动聚焦对应语义分类、点击分类给已选 mask 换标签并移动到前端渲染最上层、分类变更同步同一传播链前后帧对应 mask、自定义分类 PATCH 后端模板、目标实例标题显示当前 mask label、隐藏当前选中区域计数、隐藏后端模型置信度、选中 mask 后端拓扑属性分析、拓扑锚点数量按真实 polygon 顶点数显示、分析请求 abort/cancel 静默忽略且旧请求不覆盖新状态、边缘平滑强度防抖预览不标 dirty、应用边缘平滑后将 mask 标记为 dirty、平滑作为实际几何编辑、平滑同步传播链对应 mask、平滑保存时保留传播 lineage 而不把传播帧变成人工/AI 标注帧、平滑撤销/重做、平滑应用后强度归零 |
|
||||
| R10 Dashboard 与 WebSocket | `src/lib/api.test.ts`, `src/lib/websocket.test.ts`, `src/components/Dashboard.test.tsx`, `backend/tests/test_dashboard.py`, `backend/tests/test_main.py`, `backend/tests/test_progress_events.py`, `backend/tests/test_tasks.py` | 后端概览接口、任务表驱动进度区、最近完成任务保留显示、任务取消/重试/详情、cancelled 事件、Redis 进度事件 payload/发布、地址推导、消息订阅、连接状态回调、队列更新、heartbeat、主动断开不重连 |
|
||||
| R11 导出 | `src/components/VideoWorkspace.test.tsx`, `src/lib/api.test.ts`, `backend/tests/test_export.py` | 统一分割结果导出下拉、导出前自动保存、整体/范围/当前帧范围参数、特定范围帧可通过播放进度条/视频处理进度条拖拽选择、下载 ZIP 按项目名/`0h00m00s000ms` 起止时间戳/起止项目帧序号命名、导出内容 outputs 参数、Mix_label 透明度参数和预览、兼容 COCO/PNG 路径、JSON 结构、maskid/GT 像素值映射 JSON、原始图片文件夹、按帧/按类别合并的分开 Mask 文件夹、GT_label 黑白图文件夹、Pro_label 彩色图文件夹、Mix_label 原图叠加图文件夹、GT/Pro/Mix 按内部优先级覆盖且和语义分类树顺序一致、GT_label 背景 0、保留类别真实 maskid、导出 GT_label 再导入保持类别一致 |
|
||||
| R11 导出 | `src/components/VideoWorkspace.test.tsx`, `src/lib/api.test.ts`, `backend/tests/test_export.py` | 统一分割结果导出下拉、导出前自动保存、整体/范围/当前帧范围参数、特定范围帧可通过播放进度条/视频处理进度条拖拽选择、下载 ZIP 按项目名/`0h00m00s000ms` 起止时间戳/起止项目帧序号命名、导出内容 outputs 参数、Mix_label 透明度参数和预览、兼容 COCO/PNG 路径、JSON 结构、maskid/GT 像素值映射 JSON、原始图片文件夹、按帧/按类别合并的分开 Mask 文件夹、GT_label 黑白图文件夹、Pro_label 彩色图文件夹、Mix_label 原图叠加图文件夹、GT/Pro/Mix 按内部优先级覆盖且和语义分类树顺序一致、GT_label 固定 uint8、GT_label 背景 0、保留类别真实 maskid、`maskid:0` 待分类在 GT_label/Pro_label 中与背景同为黑色 0、正整数 maskid 超出 1-255 拒绝导出、导出 GT_label 再导入保持类别一致 |
|
||||
| R12 配置 | `src/lib/config.test.ts` | env 优先、hostname 推导、WS 推导 |
|
||||
| R13 文档与测试 | `doc/09-test-plan.md` | 测试覆盖矩阵 |
|
||||
|
||||
@@ -32,18 +32,18 @@
|
||||
|
||||
| 需求 | 功能点 | 对应测试 | 当前状态 |
|
||||
|------|--------|----------|----------|
|
||||
| R1 | 登录页、默认开发管理员、JWT 写入、当前用户写入、刷新恢复基础状态、失败提示、后端 401、`/api/auth/me`、管理员用户管理、角色权限、审计日志、演示出厂设置二次确认、重置后只保留 admin 和未生成帧演示视频项目 | `Login.test.tsx`, `Sidebar.test.tsx`, `UserAdmin.test.tsx`, `useStore.test.ts`, `test_auth.py`, `test_admin.py` | 已覆盖 |
|
||||
| R2 | 项目列表/创建/选择、项目按用户隔离、视频导入、DICOM 导入、后端项目和帧 CRUD | `ProjectLibrary.test.tsx`, `api.test.ts`, `test_projects.py` | 已覆盖 |
|
||||
| R3 | 文件类型校验、自动/指定项目上传、视频导入与生成帧分离、显式 FPS 生成帧、项目卡片 FPS 徽标显示 `parse_fps`、视频/DICOM 拆帧任务、非阻塞自动消失操作提示、`parse_fps/max_frames/target_width`、标准帧序列 metadata、任务查询、取消、重试、worker 取消停止 | `ProjectLibrary.test.tsx`, `TransientNotice.test.tsx`, `api.test.ts`, `test_media.py`, `test_tasks.py` | 已覆盖 |
|
||||
| R4 | 工作区加载帧、无帧项目不自动解析、工作区短状态自动消失、后端标注回显保留本地未保存 draft mask、Canvas/AI 底图居中适配且保留边距、工作区 mask 透明度、选中 mask 后跨帧自动跟随同一传播链结果、清空片段遮罩进入时间轴范围选择并按选区批量清空、清空全部模式、保留人工/AI 模式只清传播 mask、清空人工/AI 标注帧前二次确认、取消确认不删除、仅自动传播帧不确认、清空后裁剪/移除重叠传播历史条、传播权重下拉深色可读配色、缩略图/range/视频处理进度条、视频处理进度条点击跳帧、人工/AI 标注帧红色竖线和标识点击跳帧、自动传播帧蓝色区段和标识点击跳帧、最近自动传播历史片段同一蓝色系按新旧递进显示,旧记录第 5 次后统一阈值色、当前帧白色贯穿线、传播/清空范围洋红/黄绿色边界贯穿线、缩略图红/蓝边框、人工/AI 标注帧叠加传播状态时红框优先保留并显示蓝色内描边、当前人工/AI 标注帧青色外框加红色内描边、普通状态不显示传播范围黄色选区、播放进度条/视频处理进度条拖拽选择传播/清空范围、Canvas/AI 画布拖拽平移回写 position state、左右方向键切帧、播放、按 FPS 显示时间 | `VideoWorkspace.test.tsx`, `FrameTimeline.test.tsx`, `CanvasArea.test.tsx`, `AISegmentation.test.tsx` | 已覆盖 |
|
||||
| R1 | 登录页、默认开发管理员、JWT 写入、当前用户写入、刷新恢复基础状态、失败提示、后端 401、`/api/auth/me`、管理员用户管理、角色权限、审计日志、演示出厂设置二次确认、重置后只保留 admin、演示视频项目和已生成帧的自然排序演示 DICOM 项目 | `Login.test.tsx`, `Sidebar.test.tsx`, `UserAdmin.test.tsx`, `useStore.test.ts`, `test_auth.py`, `test_admin.py` | 已覆盖 |
|
||||
| R2 | 项目列表/创建/选择/重命名/复制、重命名时不触发生成帧、DICOM 不显示生成帧、项目复制 reset/full、项目按用户隔离、视频导入、DICOM 导入、DICOM 前端选择自然排序、后端项目和帧 CRUD | `ProjectLibrary.test.tsx`, `api.test.ts`, `test_projects.py` | 已覆盖 |
|
||||
| R3 | 文件类型校验、自动/指定项目上传、视频导入与生成帧分离、视频/DICOM 上传进度可视化、DICOM 导入显示有效文件数量并在上传后持续显示解析任务进度、显式 FPS 生成帧、项目卡片 FPS 徽标显示 `parse_fps`、视频/DICOM 拆帧任务、DICOM 上传/下载/读取自然排序、非阻塞自动消失操作提示、`parse_fps/max_frames/target_width`、标准帧序列 metadata、任务查询、取消、重试、worker 取消停止 | `ProjectLibrary.test.tsx`, `TransientNotice.test.tsx`, `api.test.ts`, `test_media.py`, `test_tasks.py` | 已覆盖 |
|
||||
| R4 | 工作区加载帧、无帧项目不自动解析、工作区短状态自动消失、后端标注回显保留本地未保存 draft mask、Canvas/AI 底图居中适配且保留边距、工作区 mask 透明度、选中 mask 后跨帧自动跟随同一传播链结果、清空片段遮罩进入时间轴范围选择并按选区批量清空、清空全部模式、保留人工/AI 模式只清传播 mask、清空人工/AI 标注帧前二次确认、取消确认不删除、仅自动传播帧不确认、清空后裁剪/移除重叠传播历史条、删除单个传播 mask 后空帧不保留传播历史颜色、传播权重下拉深色可读配色、缩略图/range/视频处理进度条、视频处理进度条点击跳帧、人工/AI 标注帧红色竖线和标识点击跳帧、自动传播帧蓝色区段和标识点击跳帧、最近自动传播历史片段同一蓝色系按新旧递进显示,旧记录第 5 次后统一阈值色、当前帧白色贯穿线、传播/清空范围洋红/黄绿色边界贯穿线、缩略图红/蓝边框、人工/AI 标注帧叠加传播状态时红框优先保留并显示蓝色内描边、当前人工/AI 标注帧青色外框加红色内描边、普通状态不显示传播范围黄色选区、播放进度条/视频处理进度条拖拽选择传播/清空范围、Canvas/AI 画布拖拽平移回写 position state、左右方向键切帧、播放、按 FPS 显示时间 | `VideoWorkspace.test.tsx`, `FrameTimeline.test.tsx`, `CanvasArea.test.tsx`, `AISegmentation.test.tsx` | 已覆盖 |
|
||||
| R5 | 工具切换、工具栏紧凑滚动布局、低对比滚动条、外扩滚动条槽位、调整多边形入口、GT Mask 导入入口位置和紫色底色、工作区工具栏隐藏 AI 正/反点和框选、左侧工具栏不重复撤销/重做、AI 跳转、矩形/圆/线/点/多边形绘制、已有 mask 上继续绘制、多边形和布尔工具上下文提示、Canvas 上下文提示数秒后自动隐藏 | `ToolsPalette.test.tsx`, `CanvasArea.test.tsx` | 已覆盖 |
|
||||
| R5 | 顶点直接拖动编辑、顶点拖拽结束不改变 Canvas 视口、边中点插点、双击边界按位置插点、顶点删除、整块删除、工作区顶栏撤销/重做按钮、顶栏撤销/重做图标强调色、撤销/重做快捷键、区域合并、区域去除、布尔选择主区域黄色实线/扣除区域红色虚线、布尔选择顺序提示、hole even-odd 渲染 | `CanvasArea.test.tsx`, `VideoWorkspace.test.tsx`, `useStore.test.ts` | 已覆盖 |
|
||||
| R6 | SAM 2.1 变体选择、点/框/interactive、semantic 禁用、SAM 3 入口隐藏和后端拒绝、SAM 2.1 最高分候选去重、AI 页框选/框选后加点、AI 页提示工具上下文提示、AI 页重复执行替换旧候选、AI 页不渲染工作区已有 mask、AI 页可在候选 mask 上继续添加正/反点、AI 页可删除提示点、AI 页可删除选中候选、AI 页清空只移除本页候选、AI 页/右侧共享遮罩透明度只改预览 opacity、AI 页生成 mask 自动选中并可换标签、AI 页无语义候选禁止推送到工作区并用 error toast 提示、离开 AI 页时清理未分类候选、AI 页推送到工作区编辑保留选择和当前帧、SAM 2.1 视频按参考帧全部 mask 和范围自动传播、传播前自动保存 draft/dirty seed mask、传播前独立选择 SAM 2.1 tiny/small/base+/large 权重、自动传播 Celery 任务入队、传播入队权重 id 规范化/拒绝不支持 id、传播 seed 来源 id/签名和历史平滑 metadata 兼容、历史平滑 seed 保存前对 forward/backward polygon 实际应用边缘平滑并减少密集轮廓点、边缘平滑强度缓入递进曲线、未编辑传播结果作为 seed 时继承原始签名并跳过重复传播、已编辑传播结果保留 lineage 但重算签名并清理旧结果、中间帧人工新增替代 seed 时清理下游同物体旧传播结果、中间帧 backward 传播清理旧 forward 结果、换权重传播先清理旧结果、旧临时 seed id 传播结果兼容清理、前端任务轮询进度、传播任务 runner 保存标注和结果权重 id、传播任务重试、传播空结果提示、GPU/模型状态、参数 options、polygons 转 mask | `api.test.ts`, `CanvasArea.test.tsx`, `AISegmentation.test.tsx`, `VideoWorkspace.test.tsx`, `ModelStatusBadge.test.tsx`, `test_ai.py`, `test_tasks.py`, `test_sam2_engine.py` | 已覆盖 |
|
||||
| R7 | 保存状态按钮“保存 X 个改动/已全部保存”、保存、保存后替换已提交 draft、查询、更新、删除标注、工作区回显、清空已保存标注、GT mask 导入和 seed point 回写、低数值/16-bit GT_label 图导入、RGB 等通道 maskid 图导入、导入预览、未知 maskid 导入策略、非法彩色 GT mask 拒绝、尺寸不一致自动最近邻拉伸 | `VideoWorkspace.test.tsx`, `CanvasArea.test.tsx`, `api.test.ts`, `test_ai.py` | 已覆盖 |
|
||||
| R8 | 模板加载、新建、编辑、删除、JSON 分类导入、JSON/保存错误非阻塞提示、mapping_rules 映射、后端 CRUD | `TemplateRegistry.test.tsx`, `TransientNotice.test.tsx`, `api.test.ts`, `test_templates.py` | 已覆盖 |
|
||||
| R9 | 模板选择、面板标题简化、工作区遮罩透明度滑杆、分类展示、分类选择、分类树拖拽调整内部覆盖顺序且不改变 maskid、拖拽后同步同类 mask 层级并标记待保存、点击 mask 自动聚焦对应分类、已选 mask 换标签并置顶显示、分类变更同步同一传播链前后帧对应 mask、自定义分类写入后端模板、目标实例标题显示当前 mask label、隐藏当前选中区域计数、隐藏后端模型置信度、后端拓扑属性分析、拓扑锚点真实顶点计数、分析请求 abort/cancel 静默忽略且旧请求不覆盖新状态、边缘平滑强度防抖预览、边缘平滑应用后确认 dirty、平滑作为实际几何编辑、平滑同步传播链对应 mask、平滑撤销/重做、平滑应用后强度归零、占位状态 | `OntologyInspector.test.tsx`, `CanvasArea.test.tsx`, `useStore.test.ts`, `test_ai.py` | 已覆盖 |
|
||||
| R5 | 顶点直接拖动编辑、顶点拖拽结束不改变 Canvas 视口、边中点插点、双击边界按位置插点、顶点删除、整块删除、删除传播链自动传播 mask 且保留独立 AI 推理 mask、工作区顶栏撤销/重做按钮、顶栏撤销/重做图标强调色、撤销/重做快捷键、区域合并、区域去除、布尔选择主区域黄色实线/扣除区域红色虚线、布尔选择顺序提示、hole even-odd 渲染 | `CanvasArea.test.tsx`, `VideoWorkspace.test.tsx`, `useStore.test.ts` | 已覆盖 |
|
||||
| R6 | SAM 2.1 变体选择、点/框/interactive、semantic 禁用、SAM 3 入口隐藏和后端拒绝、SAM 2.1 最高分候选去重、AI 页框选/框选后加点、AI 页提示工具上下文提示、AI 页重复执行替换旧候选、AI 页不渲染工作区已有 mask、AI 页可在候选 mask 上继续添加正/反点、AI 页可删除提示点、AI 页可删除选中候选、AI 页清空只移除本页候选、AI 页/右侧共享遮罩透明度只改预览 opacity、AI 页生成 mask 自动选中并可换标签、AI 页无语义候选禁止推送到工作区并用 error toast 提示、离开 AI 页时清理未分类候选、AI 页推送到工作区编辑保留选择和当前帧、SAM 2.1 视频按参考帧全部 mask 和范围自动传播、当前参考帧无遮罩提示、传播前只保存参考帧 draft/dirty seed mask、传播前独立选择 SAM 2.1 tiny/small/base+/large 权重、自动传播 Celery 任务入队、传播入队权重 id 规范化/拒绝不支持 id、传播 seed 来源 id/签名和历史平滑 metadata 兼容、历史平滑 seed 保存前对 forward/backward polygon 实际应用边缘平滑并减少密集轮廓点、边缘平滑强度缓入递进曲线、未编辑传播结果作为 seed 时继承原始签名并跳过重复传播、已编辑传播结果保留 lineage 但重算签名并清理旧结果、中间帧人工新增替代 seed 时清理下游同物体旧传播结果、中间帧 backward 传播清理旧 forward 结果、换权重传播先清理旧结果、旧临时 seed id 传播结果兼容清理、前端任务轮询进度、传播任务 runner 保存标注和结果权重 id、传播任务重试、传播空结果提示、GPU/模型状态、参数 options、polygons 转 mask | `api.test.ts`, `CanvasArea.test.tsx`, `AISegmentation.test.tsx`, `VideoWorkspace.test.tsx`, `ModelStatusBadge.test.tsx`, `test_ai.py`, `test_tasks.py`, `test_sam2_engine.py` | 已覆盖 |
|
||||
| R7 | 保存状态按钮“保存 X 个改动/已全部保存”、保存、保存后替换已提交 draft、查询、更新、删除标注、工作区回显、清空已保存标注、GT mask 导入和 seed point 数据兼容、导入 mask 不显示黄色 seed point、高精度 GT contour、导入 mask 拓扑统计和边缘平滑、8-bit 低数值 GT_label 图导入、16-bit/uint16 GT_label 图拒绝、全背景 0 GT_label 图拒绝并保留“没有非背景 maskid 区域”提示、RGB 等通道 maskid 图导入、导入预览、未知 maskid 导入策略、非法彩色 GT mask 拒绝、尺寸不一致自动最近邻拉伸 | `VideoWorkspace.test.tsx`, `CanvasArea.test.tsx`, `api.test.ts`, `test_ai.py` | 已覆盖 |
|
||||
| R8 | 模板加载、新建、编辑、删除、删除模板站内确认、鼠标复制模板为私有副本并保留 maskid/颜色/层级/规则、所有模板归一化包含黑色 `maskid:0`“待分类”保留类、保留类固定最后且不可删除/拖拽上移、详情页标题/新建分类/垃圾桶删 label、默认模板“腹腔镜胆囊切除术”和“头颈部CT分割”幂等 seed、恢复出厂设置保留系统模板、编辑后详情页刷新、详情页和编辑弹窗拖拽语义层级顺序、拖拽保存 `zIndex` 且不改变 maskid、JSON 分类导入预览、JSON 错误内联提示、保存错误非阻塞提示、mapping_rules 映射、后端 CRUD | `TemplateRegistry.test.tsx`, `TransientNotice.test.tsx`, `api.test.ts`, `test_templates.py`, `test_admin.py` | 已覆盖 |
|
||||
| R9 | 模板选择、面板标题简化、工作区遮罩透明度滑杆、分类展示、分类选择、模板类别删除后项目旧 mask 回显为 `maskid:0` 待分类、分类树拖拽调整内部覆盖顺序且不改变 maskid、拖拽后同步同类 mask 层级并标记待保存、点击 mask 自动聚焦对应分类、已选 mask 换标签并置顶显示、分类变更同步同一传播链前后帧对应 mask、自定义分类写入后端模板、目标实例标题显示当前 mask label、隐藏当前选中区域计数、隐藏后端模型置信度、后端拓扑属性分析、拓扑锚点真实顶点计数、分析请求 abort/cancel 静默忽略且旧请求不覆盖新状态、边缘平滑强度防抖预览、边缘平滑应用后确认 dirty、平滑作为实际几何编辑、平滑同步传播链对应 mask、平滑撤销/重做、平滑应用后强度归零、占位状态 | `OntologyInspector.test.tsx`, `VideoWorkspace.test.tsx`, `CanvasArea.test.tsx`, `useStore.test.ts`, `test_ai.py` | 已覆盖 |
|
||||
| R10 | Dashboard 概览、任务进度区、最近完成任务保留显示、活动日志、WebSocket progress/complete/error/status/cancelled、取消/重试/详情、连接状态回调、heartbeat | `Dashboard.test.tsx`, `websocket.test.ts`, `test_dashboard.py`, `test_main.py`, `test_progress_events.py`, `test_tasks.py` | 已覆盖 |
|
||||
| R11 | 统一“分割结果导出”下拉、整体视频/特定范围帧/当前图片导出、特定范围帧时间轴拖拽选择、ZIP 文件名 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`、时间戳 `0h00m00s000ms` 格式、项目帧序号使用抽帧后 1-based 顺序、分开 Mask/GT_label/Pro_label/Mix_label outputs、Mix_label 透明度、导出前保存、兼容 COCO/PNG ZIP 路径、JSON/ZIP 结构、maskid/GT 像素值映射、原始图片导出、分开 Mask 按帧子目录与同类合并命名、GT_label/Pro_label/Mix_label 命名、GT/Pro/Mix 内部优先级融合且和语义分类树顺序一致、GT_label 背景 0、保留类别真实 maskid、导出的 GT_label 可按同一模板导回 | `VideoWorkspace.test.tsx`, `api.test.ts`, `test_export.py` | 已覆盖 |
|
||||
| R11 | 统一“分割结果导出”下拉、整体视频/特定范围帧/当前图片导出、特定范围帧时间轴拖拽选择、ZIP 文件名 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`、时间戳 `0h00m00s000ms` 格式、项目帧序号使用抽帧后 1-based 顺序、分开 Mask/GT_label/Pro_label/Mix_label outputs、Mix_label 透明度、导出前保存、兼容 COCO/PNG ZIP 路径、JSON/ZIP 结构、maskid/GT 像素值映射、原始图片导出、分开 Mask 按帧子目录与同类合并命名、GT_label/Pro_label/Mix_label 命名、GT/Pro/Mix 内部优先级融合且和语义分类树顺序一致、GT_label 固定 uint8、GT_label 背景 0、保留类别真实 maskid、`maskid:0` 待分类导出为黑色 0、正整数 maskid 超出 1-255 拒绝导出、导出的 GT_label 可按同一模板导回 | `VideoWorkspace.test.tsx`, `api.test.ts`, `test_export.py` | 已覆盖 |
|
||||
| R12 | API/WS 地址 env 优先和 hostname 推导 | `config.test.ts` | 已覆盖 |
|
||||
| R13 | 文档测试矩阵与功能点追踪 | `doc/09-test-plan.md` | 已覆盖 |
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
- R6:补充传播去重回归测试,验证前端传播前会先保存 draft seed mask 并用稳定 `source_annotation_id` 入队;后端在 seed 来源由前端临时 id 迁移到后端 annotation id、用户换用其他 SAM 2.1 权重、未编辑传播结果再次作为 seed、已编辑传播结果重新作为 seed、中间帧人工新增替代 seed 时,会分别跳过或清理旧传播标注再保存新结果。
|
||||
- R6:`backend/tests/test_sam3_engine.py` 已标记跳过,仅作为历史保留实现的参考测试,不计入当前产品功能覆盖。
|
||||
- R3:补充 `parseMedia()` 查询参数和后端拆帧任务 payload 测试,验证 `parse_fps`、`max_frames`、`target_width` 会进入任务。
|
||||
- R3:补充 `ProjectLibrary.test.tsx` 和 `api.test.ts` 中上传进度测试,验证视频/DICOM 上传通过 Axios `onUploadProgress` 回调更新项目库导入进度条,并显示 DICOM 文件数量和解析任务轮询进度。
|
||||
- R3:补充 worker 注册标准帧序列测试,验证帧 `timestamp_ms`、`source_frame_number` 和 `result.frame_sequence` 元数据。
|
||||
- R8:补充 `TemplateRegistry.test.tsx` 中模板编辑、删除测试,验证前端调用真实 API 封装并更新全局 store。
|
||||
- R9:补充 Canvas 选中 mask id 全局同步、本体树点击分类给已选 mask 换标签并移到渲染最上层的测试,验证已保存 mask 会进入 dirty 状态。
|
||||
|
||||
@@ -192,6 +192,7 @@ access_token_expire_minutes=1440
|
||||
default_admin_username=admin
|
||||
default_admin_password=123456
|
||||
demo_video_path=/home/wkmgc/Desktop/Seg_Server/Data_MyVideo_1.mp4
|
||||
demo_dicom_dir=/home/wkmgc/Desktop/Seg_Server/2024_2_5_王芳/※2F458C45CFAA4C7CB76A39AA2BFE436B
|
||||
EOF
|
||||
```
|
||||
|
||||
@@ -313,7 +314,7 @@ admin / 123456
|
||||
|
||||
首次启动会自动创建默认管理员,密码以哈希形式写入 `users` 表;登录返回签名 JWT,业务接口会校验 `Authorization: Bearer <token>`。生产环境必须修改 `jwt_secret_key` 和默认管理员密码。
|
||||
|
||||
默认管理员登录后会看到“用户管理”后台,可新增用户、停用/启用用户、修改角色、重置密码、删除无项目用户并查看登录与用户管理审计日志。角色分为 `admin`、`annotator`、`viewer`:`admin/annotator` 可以执行写入类业务操作,`viewer` 只读。演示部署可在该后台使用“恢复演示出厂设置”,二次确认后只保留默认 admin 和一个尚未生成帧的演示视频项目;该视频来自 `demo_video_path`。
|
||||
默认管理员登录后会看到“用户管理”后台,可新增用户、停用/启用用户、修改角色、重置密码、删除无项目用户并查看登录与用户管理审计日志。角色分为 `admin`、`annotator`、`viewer`:`admin/annotator` 可以执行写入类业务操作,`viewer` 只读。演示部署可在该后台使用“恢复演示出厂设置”,二次确认后只保留默认 admin、演示视频项目和一个已按文件名自然顺序生成帧的演示 DICOM 项目;视频来自 `demo_video_path`,DICOM 序列来自 `demo_dicom_dir`。
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user