让新建绘制并入选中遮罩

- 多边形、矩形、圆和画笔在当前已有选中 mask 时,将新几何 union 并入选中 mask,即使区域不重叠也保持为同一个多 polygon mask。

- 无选中 mask 时仍按原新建流程创建并自动选中新 mask;画笔无选区时仍要求右侧语义分类树有选中类别。

- 补充 CanvasArea 回归测试,覆盖创建工具保留选区、分离矩形并入选中 mask、画笔无 active class 时并入选中 mask。

- 更新前端审计、需求冻结、设计冻结、状态机、测试计划和项目指南文档。
This commit is contained in:
2026-05-04 04:57:53 +08:00
parent 1971640a67
commit 85de1ffbb2
9 changed files with 118 additions and 44 deletions

View File

@@ -112,6 +112,6 @@
- 前端 API/WS 地址虽然已支持环境变量和 hostname 推导,但部署时仍需要确认浏览器可访问 `:8000` 后端。
- AI 当前启用 SAM 2.1 tiny/small/base+/large 点/框/interactive 路径;语义文本提示和 SAM 3 产品入口已禁用,`model=sam3` 会被后端拒绝。SAM 3 源码保留但不计入当前可用功能。
- 工作区顶部“分割结果导出”和保存状态按钮、左侧工具栏“导入 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 文件夹;清空当前帧遮罩会删除对应后端标注,存在传播链时同一弹窗提供取消/当前帧/按帧范围选择/所有传播帧,按范围清空复用时间轴范围选择和最终确认;按范围或全部清空遇到人工/AI 标注帧时会二次确认选择保留则整帧保留。手工绘制、polygon 顶点拖动/删除、区域合并/去除和撤销重做已经落到前端 mask 数据结构;无选中分类的多边形/矩形/圆/画笔会默认归入 `maskid:0` 的“待分类”;多边形、矩形、圆和画笔新建后会自动选中 mask,画笔始终生成独立 mask不与当前选中 mask 自动合并`Esc` 只取消选区和临时绘制状态,不删除已有 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 文件夹;清空当前帧遮罩会删除对应后端标注,存在传播链时同一弹窗提供取消/当前帧/按帧范围选择/所有传播帧,按范围清空复用时间轴范围选择和最终确认;按范围或全部清空遇到人工/AI 标注帧时会二次确认选择保留则整帧保留。手工绘制、polygon 顶点拖动/删除、区域合并/去除和撤销重做已经落到前端 mask 数据结构;多边形、矩形、圆和画笔创建遵循“有选中 mask 则并入选中 mask、无选中 mask 才新建”的规则,即使新几何和旧区域不重叠也会组成同一个多 polygon mask无选中分类的新建多边形/矩形/圆会默认归入 `maskid:0` 的“待分类”,画笔无选中 mask 时仍要求右侧语义分类树有 active class`Esc` 只取消选区和临时绘制状态,不删除已有 mask。
- Dashboard 初始统计、队列和活动日志来自后端聚合接口;解析队列来自 `processing_tasks`worker 进度通过 Redis `seg:progress` 转发到 WebSocket。任务取消、重试和失败详情已接入前后端。
- 后端已接入 Bearer JWT 鉴权、当前用户项目隔离和角色权限;写入类业务接口要求 `admin/annotator`,管理员用户后台要求 `admin`。当前审计覆盖登录和用户管理操作,全业务级审计仍可继续扩展。

View File

@@ -95,7 +95,7 @@
| 正向/反向选点 | 真实可用 | UI 能加点,并按当前帧 `frame.id` 调用 `/api/ai/predict`;结果需点击归档保存才持久化 |
| 框选 | 真实可用 | UI 能画框,并把框坐标归一化后调用后端推理;结果需点击归档保存才持久化 |
| AI 推理中提示 | 真实可用 | 请求期间会显示 |
| 手工多边形/矩形/圆/画笔/橡皮擦 | 真实可用 | 多边形点击取点后可按 Enter 完成,也可在三点后点击首节点闭合;矩形/圆拖拽生成 polygon切换到多边形/矩形/圆会清空旧 mask 选区,创建完成后自动选中 mask,并在创建工具下显示边界顶点作为只读选中提示;多边形/矩形/圆未选语义分类时自动归入黑色 `maskid:0` 的“待分类”;画笔按当前语义分类生成连续圆形笔触并在松开时 union 成新的独立 mask即使与选中 mask 连通或重叠也不自动合并;画笔闭合形成中空区域时保留内洞 ring使用 even-odd 渲染并显示内外圈顶点;按 `Esc` 或点击左侧“取消选中”按钮可清空选区和临时绘制状态;橡皮擦从选中 mask 中扣除笔触区域;均写入 `Mask.segmentation`,可归档保存 |
| 手工多边形/矩形/圆/画笔/橡皮擦 | 真实可用 | 多边形点击取点后可按 Enter 完成,也可在三点后点击首节点闭合;矩形/圆拖拽生成 polygon切换到多边形/矩形/圆会保留当前 mask 选区,选中 mask 时新创建的多边形/矩形/圆会通过 polygon union 并入该 mask即使两块区域不重叠也合并为同一个多 polygon mask没有选中 mask 时才创建新 mask未选语义分类时自动归入黑色 `maskid:0` 的“待分类”;画笔按当前语义分类或当前选中 mask 生成连续圆形笔触,松开后有选中 mask 则并入选中 mask没有选中 mask 才创建新的当前类别 mask;画笔闭合形成中空区域时保留内洞 ring使用 even-odd 渲染并显示内外圈顶点;按 `Esc` 或点击左侧“取消选中”按钮可清空选区和临时绘制状态;橡皮擦从选中 mask 中扣除笔触区域;均写入 `Mask.segmentation`,可归档保存 |
| 画布上下文提示 | 真实可用 | 切换到多边形、矩形、圆、画笔、橡皮擦、区域合并/去除、调整多边形等隐性操作工具时,画布左上角显示当前工具的完成/取消/选择顺序提示;提示会在数秒后自动隐藏,避免长期遮挡待编辑图像,工具或操作状态变化时会重新出现 |
| Mask 渲染 | 真实可用 | 前端会把推理、手工绘制、GT 导入和已保存标注转成 Konva `pathData` 渲染;普通 mask 和导入 mask 都不显示黄色 seed point未选中特定 mask 时,当前帧 mask 会按右侧“语义分类树”拖拽得到的内部覆盖优先级从低到高渲染,使高优先级类别显示在上层;有选中 mask 时保留编辑态置顶行为,方便操作 |
| Mask 透明度 | 真实可用 | 右侧语义分类树上方的“遮罩透明度”滑杆写入全局 `maskPreviewOpacity`,工作区 Canvas 和 AI 智能分割页都会使用该值调整 mask 预览透明度,选中 mask 会在该基础上略微加亮 |

View File

@@ -75,8 +75,8 @@
- 侧栏“AI智能分割”和工作区工具栏 AI 跳转入口必须使用带明确 AI 语义的图标,而不是普通魔法棒等泛化工具图标。
- 工作区 AI 智能分割入口切换到 AI 页面。
- 多边形、矩形、圆、画笔、橡皮擦工具会在 Canvas 上生成或编辑可保存的 polygon mask左侧工具栏不再提供创建点和创建线段入口。
- 多边形通过点击取点并按 Enter 完成,也支持三点后点击首节点闭合;矩形、圆通过拖拽生成;点击创建多边形、创建矩形或创建圆工具时必须清空当前 mask 选区;新建完成后必须自动选中新创建 mask在仍处于创建工具时显示该 mask 边界顶点作为只读选中提示;画笔和橡皮擦支持调整大小。
- 画笔工具在语义分类树有选中类别时可用,按住拖动时以圆形笔触采样,鼠标松开后一次性 union 成新的独立 mask即使笔触与当前选中 mask 连通或重叠,也不能自动合并到旧 mask笔触只在当前图像范围内采样最终几何也必须裁剪到当前帧边界内如果画笔闭合形成中空区域必须保留外圈与内洞 ring 分组,并按中空 mask 规则渲染、编辑和保存。
- 多边形通过点击取点并按 Enter 完成,也支持三点后点击首节点闭合;矩形、圆通过拖拽生成;点击创建多边形、创建矩形或创建圆工具时必须保留当前 mask 选区;如果当前有选中 mask新建多边形/矩形/圆必须并入该选中 mask即使两块区域不重叠也作为同一个多 polygon mask如果当前没有选中 mask创建 mask 并自动选中,在仍处于创建工具时显示该 mask 边界顶点作为只读选中提示;画笔和橡皮擦支持调整大小。
- 画笔工具在语义分类树有选中类别或当前已有选中 mask 时可用,按住拖动时以圆形笔触采样,鼠标松开后一次性 union;如果当前有选中 mask笔触必须并入该 mask不论是否重叠如果当前没有选中 mask才创建新的当前类别 mask笔触只在当前图像范围内采样最终几何也必须裁剪到当前帧边界内如果画笔闭合形成中空区域必须保留外圈与内洞 ring 分组,并按中空 mask 规则渲染、编辑和保存。
- 橡皮擦工具只在当前帧已选中 mask 时可用,按住拖动时以圆形笔触采样,鼠标松开后从选中 mask 中 difference 扣除;扣空时删除该 mask已保存 mask 仍需同步后端删除;进入画笔或橡皮擦模式后,当前选中 mask 的顶点提示仍保持可见,但这些顶点在笔触模式下只读不可拖动。
- 创建多边形、创建矩形、区域合并/去除、调整多边形等 Canvas 左上角上下文提示只作为短提示,切换工具或操作状态变化时显示,数秒后自动隐藏,避免长期遮挡待编辑图像;再次切换工具或操作状态变化会重新显示。
- 绘制工具点击已有 mask 时应继续执行当前绘制动作,不应被 mask 选择逻辑吞掉;按 `Esc` 或点击左侧工具栏“取消选中”实体按钮,必须清空当前 mask 选区和正在绘制的临时点/笔触,使用户可以重新选择语义分类并用画笔创建一个新 mask。

View File

@@ -183,8 +183,8 @@
3. 多边形工具逐次记录节点,三点后点击首节点或按 Enter 时生成闭合 polygon。
4. Canvas 左上角根据当前工具和操作阶段显示上下文短提示;多边形提示会随已放置点数切换,明确 Enter 完成、Esc 取消和点击首节点闭合。`Esc` 和左侧工具栏“取消选中”按钮只取消当前 mask 选区、临时多边形点、矩形/圆拖拽状态、画笔/橡皮擦临时笔触和顶点选择,不删除已有 mask也不清空右侧语义分类树的当前类别。提示会在工具或操作状态变化时出现并在数秒后自动隐藏避免长期遮挡底图。
5. mask path 只在 `move``edit_polygon``area_merge``area_remove` 工具下拦截点击;绘制、画笔、橡皮擦和 AI prompt 工具点击已有 mask 时继续冒泡给 Stage。
6. 画笔/橡皮擦尺寸保存在 Zustand 中;拖动期间只保留采样后的圆形笔触预览,鼠标松开后再用 `polygon-clipping` 计算一次几何结果,避免拖动中反复重算复杂 polygon。画笔把本次采样笔触 union 成一个新的独立 mask不与当前选中 mask 自动合并;如果画笔笔触闭合形成中空区域,`segmentation` 保留外圈和内洞 ring`metadata.hasHoles/polygonRingCounts` 记录 ring 分组,并使用 even-odd 渲染;橡皮擦则对当前选中 mask 执行 difference 扣除。
7. 多边形、矩形、圆和画笔创建新 mask 写入 `pathData`、像素 `segmentation``bbox``area` 和当前模板分类元数据,并自动写入 `selectedMaskIds` 成为当前选中 mask。若右侧没有选中具体分类新建 mask 默认使用 `maskid: 0` 的“待分类”。创建工具仍处于激活状态时,刚创建选中 mask 会显示只读边界顶点;切换到 `move` 或“调整多边形”后这些顶点可拖动编辑。
6. 画笔/橡皮擦尺寸保存在 Zustand 中;拖动期间只保留采样后的圆形笔触预览,鼠标松开后再用 `polygon-clipping` 计算一次几何结果,避免拖动中反复重算复杂 polygon。画笔有选中 mask 时会把本次采样笔触 union 进选中 mask即使笔触和旧区域不重叠也形成同一个多 polygon mask没有选中 mask 时才按当前语义分类创建新的独立 mask;如果画笔笔触闭合形成中空区域,`segmentation` 保留外圈和内洞 ring`metadata.hasHoles/polygonRingCounts` 记录 ring 分组,并使用 even-odd 渲染;橡皮擦则对当前选中 mask 执行 difference 扣除。
7. 多边形、矩形、圆和画笔完成时,如果当前帧有选中 mask会把新几何 union 进该 mask保留原 mask 的语义分类并将已保存 mask 标为 dirty如果当前没有选中 mask创建新 mask写入 `pathData`、像素 `segmentation``bbox``area` 和当前模板分类元数据,并自动写入 `selectedMaskIds` 成为当前选中 mask。若右侧没有选中具体分类新建 mask 默认使用 `maskid: 0` 的“待分类”。创建工具仍处于激活状态时,刚创建/被并入的选中 mask 会显示只读边界顶点;切换到 `move` 或“调整多边形”后这些顶点可拖动编辑。
8. `addMask()``setMasks()``updateMask()``clearMasks()` 会维护 `maskHistory/maskFuture`
9. 工作区撤销/重做只保留顶栏按钮和快捷键入口AI 页保留自己的撤销/重做按钮;工作区由 `VideoWorkspace` 在 window capture 阶段统一处理 `Ctrl/Cmd+Z``Ctrl/Cmd+Shift+Z``Ctrl/Cmd+Y`,快捷键判断由 `src/lib/keyboardShortcuts.ts` 同时兼容 `event.key` 与物理键码 `event.code=KeyZ/KeyY`;输入框、下拉框和可编辑文本聚焦时跳过快捷键,避免影响帧范围输入。
@@ -230,7 +230,7 @@
4. 后端把 `classes``rules` 打包进 `mapping_rules`
5. 返回时再解包给前端。
6. 模板详情页和编辑弹窗都支持拖拽调整语义类别层级顺序;拖拽后重算 `zIndex`,保存到后端模板并刷新当前详情页,`maskId` 保持不变。所有模板都会归一化包含黑色 `maskId: 0` 的“待分类”保留类,该类固定在语义分类树最后,不参与删除和拖拽上移。编辑弹窗点击分类后只编辑分类名称,不展示或编辑旧 `category` 来源元信息。编辑弹窗中的 JSON 批量导入支持 `[[colors], [names]]``{colors, names}` 两种格式,并兼容带前缀、代码块、未加引号 keys、单引号、中文逗号/冒号和尾随逗号的粘贴内容导入前会先显示分类数量、maskid 分配起点和缺失颜色提示,语法或结构错误以内联错误展示,确认导入后进入编辑态,保存模板时落库。
7. `CanvasArea` 把当前选中的 mask id 同步到全局 `selectedMaskIds`;切换到多边形、矩形、圆、AI prompt 等非选区创建工具时会清空旧 mask 选区,切换到移动、调整多边形、画笔、橡皮擦、区域合并或重叠区域去除时保留当前选区供用户继续参照或操作。切换帧时会优先沿传播链跟随同一 mask找不到对应结果时才清空卸载 Canvas 时清空选择。
7. `CanvasArea` 把当前选中的 mask id 同步到全局 `selectedMaskIds`;切换到多边形、矩形、圆、画笔、橡皮擦、移动、调整多边形、区域合并或重叠区域去除时保留当前选区,创建工具会把新几何并入当前选中 mask只有 `Esc`、左侧“取消选中”、删除 mask、AI prompt 等显式离开选区的动作会清空旧 mask 选区。切换帧时会优先沿传播链跟随同一 mask找不到对应结果时才清空卸载 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。

View File

@@ -18,7 +18,7 @@
| 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 后跨帧自动跟随同一传播链结果、左侧工具栏清空遮罩优先作用于当前帧选中 mask/无选中时作用于当前帧全部 mask、无传播链时直接执行、有传播链时可选取消/只清当前帧/按帧范围选择/清空所有传播帧且按范围清空需最终确认、按范围清空或清空所有传播帧遇到人工/AI 标注帧时二次询问并支持保留人工帧、顶栏不显示重复的清空片段遮罩、传播进度存在时任务 message 只显示在蓝色进度面板内且不重复出现在灰色状态文字里、传播链布尔操作按帧范围选择并二次确认、清空/删除前预检后端 annotation id 并跳过本地陈旧 id、删除单个传播 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/lib/keyboardShortcuts.test.ts`, `src/store/useStore.test.ts` | 工具切换、切换到多边形/矩形/圆会清空旧 mask 选区、手工新建 mask 后自动选中新 mask 并显示创建后边界点、Esc 和左侧“取消选中”按钮清空当前 mask 选区和临时绘制状态、工具栏紧凑垂直布局和高度不足时滚动、工具栏低对比滚动条、工具栏外扩滚动条槽位不挤占按钮列、调整多边形工具、AI 跳转、清空遮罩唯一左侧工具栏入口、清空遮罩上方 DEL 删除按钮、橡皮擦下方彩色 AI自动推理入口、Canvas 右下角不再重复显示清空遮罩或应用分类按钮、GT Mask 导入位于清空遮罩分隔线之后且使用紫色底色、工具栏分隔线位于创建圆后、AI自动推理后和清空遮罩后、GT Mask 未知类别导入策略选择、工作区工具栏不展示 AI 正/反点和框选、左侧工具栏不重复撤销/重做、左侧工具栏不展示创建点/创建线段、矩形/圆/多边形手工 mask 绘制且未选分类时默认待分类、普通/导入 polygon mask 不显示黄色 seed point、画笔/橡皮擦尺寸控制、画笔新建当前类别独立 mask、画笔与选中 mask 连通或重叠时也不自动合并、画笔/橡皮擦模式下保留当前选中 mask 顶点提示且只读、画笔从图外落笔不创建 mask、靠边画笔生成几何裁剪到当前帧边界内、橡皮擦从选中 mask 扣除、未选中 mask 时画布按语义分类树内部优先级渲染、多边形 Enter/首节点闭合、上下文提示提示 Enter/Esc/首节点闭合且数秒后自动隐藏、polygon 顶点直接拖动/删除、顶点拖拽结束不改变 Canvas 视口、边中点插点、双击边界按位置插点、多 polygon/分离区域全部显示编辑顶点、中空 mask 与中空画笔 mask 内洞 ring 顶点和插点可编辑、整块 mask 删除、DEL 和 Delete/Backspace 删除共用传播链范围确认、同帧传播链分散 mask 点选联动高亮、传播链自动传播 mask 随 seed/传播结果删除、独立 AI 推理 mask 不被误删、区域合并/去除存在传播帧时弹窗选择当前帧/所有传播帧/按帧范围选择、范围确认前重新开始当前帧布尔操作会取消旧顶栏范围请求、区域合并/去除按帧范围同步到对应传播帧且保留传播 metadata、布尔选择主区域/扣除区域视觉区分和选择顺序提示、内含去除 hole 渲染和 ring 分组保存、合并模式隐藏编辑手柄、工作区顶栏撤销/重做按钮、顶栏撤销/重做图标强调色、撤销/重做快捷键 Ctrl/Cmd+Z、Ctrl/Cmd+Shift+Z、Ctrl/Cmd+Y、物理键码 fallback 和输入框快捷键跳过、撤销/重做历史栈 |
| R5 工具栏 | `src/components/ToolsPalette.test.tsx`, `src/components/CanvasArea.test.tsx`, `src/components/VideoWorkspace.test.tsx`, `src/lib/keyboardShortcuts.test.ts`, `src/store/useStore.test.ts` | 工具切换、切换到多边形/矩形/圆会保留旧 mask 选区、有选中 mask 时多边形/矩形/圆/画笔新几何会并入选中 mask 且不要求重叠、无选中 mask 时手工新建 mask 后自动选中新 mask 并显示创建后边界点、Esc 和左侧“取消选中”按钮清空当前 mask 选区和临时绘制状态、工具栏紧凑垂直布局和高度不足时滚动、工具栏低对比滚动条、工具栏外扩滚动条槽位不挤占按钮列、调整多边形工具、AI 跳转、清空遮罩唯一左侧工具栏入口、清空遮罩上方 DEL 删除按钮、橡皮擦下方彩色 AI自动推理入口、Canvas 右下角不再重复显示清空遮罩或应用分类按钮、GT Mask 导入位于清空遮罩分隔线之后且使用紫色底色、工具栏分隔线位于创建圆后、AI自动推理后和清空遮罩后、GT Mask 未知类别导入策略选择、工作区工具栏不展示 AI 正/反点和框选、左侧工具栏不重复撤销/重做、左侧工具栏不展示创建点/创建线段、矩形/圆/多边形手工 mask 绘制且未选分类时默认待分类、普通/导入 polygon mask 不显示黄色 seed point、画笔/橡皮擦尺寸控制、画笔无选中时新建当前类别 mask、画笔/橡皮擦模式下保留当前选中 mask 顶点提示且只读、画笔从图外落笔不创建 mask、靠边画笔生成几何裁剪到当前帧边界内、橡皮擦从选中 mask 扣除、未选中 mask 时画布按语义分类树内部优先级渲染、多边形 Enter/首节点闭合、上下文提示提示 Enter/Esc/首节点闭合且数秒后自动隐藏、polygon 顶点直接拖动/删除、顶点拖拽结束不改变 Canvas 视口、边中点插点、双击边界按位置插点、多 polygon/分离区域全部显示编辑顶点、中空 mask 与中空画笔 mask 内洞 ring 顶点和插点可编辑、整块 mask 删除、DEL 和 Delete/Backspace 删除共用传播链范围确认、同帧传播链分散 mask 点选联动高亮、传播链自动传播 mask 随 seed/传播结果删除、独立 AI 推理 mask 不被误删、区域合并/去除存在传播帧时弹窗选择当前帧/所有传播帧/按帧范围选择、范围确认前重新开始当前帧布尔操作会取消旧顶栏范围请求、区域合并/去除按帧范围同步到对应传播帧且保留传播 metadata、布尔选择主区域/扣除区域视觉区分和选择顺序提示、内含去除 hole 渲染和 ring 分组保存、合并模式隐藏编辑手柄、工作区顶栏撤销/重做按钮、顶栏撤销/重做图标强调色、撤销/重做快捷键 Ctrl/Cmd+Z、Ctrl/Cmd+Shift+Z、Ctrl/Cmd+Y、物理键码 fallback 和输入框快捷键跳过、撤销/重做历史栈 |
| 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 和起止帧范围自动传播、同类多实例按来源 id 分开传播、当前参考帧无遮罩提示、传播前只保存参考帧 draft/dirty seed mask、传播前独立选择 SAM 2.1 tiny/small/base+/large 权重、自动传播创建 Celery 任务、传播入队权重 id 规范化/拒绝不支持 id、传播 seed 来源 id/签名和历史平滑 metadata 兼容、中空传播 seed 扣除 holes 后注入 SAM 2 且传播结果保留 holes、历史平滑 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 标注、dirty 本地旧 annotationId 预检缺失时直接重新 POST 创建、预检后 PATCH 404 时重新 POST 创建并回显替换、中空 mask 保存为 `polygons` + `holes` 并可回显为 ring 分组、清空删除已保存标注、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 且不显示来源标签、编辑弹窗分类编辑不显示旧 category 来源元信息、编辑后详情页刷新、详情页和编辑弹窗拖拽语义层级顺序、拖拽保存 `zIndex` 且不改变 maskid、JSON 分类导入预览、`[[colors],[names]]` 数组格式、`{colors,names}` 对象格式、带前缀/宽松 keys/中文标点粘贴格式、JSON 错误内联提示、保存错误非阻塞提示、mapping_rules 解包/打包、后端模板 CRUD |
@@ -49,7 +49,7 @@
## 本轮补齐记录
- R5补充 `CanvasArea.test.tsx` 中圆形、画笔新建、画笔触碰选中 mask 仍保持独立和橡皮擦扣除测试,明确验证 metadata、segmentation、bbox/area、选中状态和草稿状态补充 `ToolsPalette.test.tsx` 中画笔/橡皮擦尺寸控制测试,并验证创建点、创建线段入口不再显示。
- R5补充 `CanvasArea.test.tsx` 中圆形、画笔新建、画笔选中 mask 时并入选中 mask、无选中时新建和橡皮擦扣除测试,明确验证 metadata、segmentation、bbox/area、选中状态和草稿状态补充 `ToolsPalette.test.tsx` 中画笔/橡皮擦尺寸控制测试,并验证创建点、创建线段入口不再显示。
- R6补充 `AISegmentation.test.tsx` 中 SAM 2.1 变体选择测试,验证前端不展示 SAM 3 入口、选择 small 后请求携带对应模型,且未放置点提示时不发起推理。
- R6补充 SAM 2 纯文本提示拦截、SAM 2 多候选只保留最高分、SAM 2 engine 单候选请求测试,避免多个重叠候选 mask 被同时叠加。
- R6补充 Canvas 工作区 SAM 2 反向点背景过滤测试,覆盖请求 options 和过滤为空时清除旧候选 mask。
@@ -74,7 +74,7 @@
- R9补充边缘平滑滑杆防抖测试验证连续拖动只触发最后一次后端预览请求降低拖动卡顿。
- R9补充边缘平滑应用到传播链并可撤销/重做的测试,验证平滑后成为新的实际 polygon、强度归零且不再只保存平滑参数。
- R5/R13补充 `CanvasArea.test.tsx``Esc` 交互测试,验证 `Esc` 只取消当前 mask 选中和临时多边形点,不删除已有 mask、不清空 `activeClass`;新增 `doc/11-frontend-interaction-state-machines.md` 记录工作区工具、语义分类树、范围选择、AI 页、模板确认和导入导出状态机。
- R5/R13完成文档一致性回查修正 `doc/02-current-implementation-map.md``doc/08-current-design-freeze.md` 中手工绘制、画笔独立新建、Esc、工具切换保留选区和无选区点击语义分类树的旧描述使实现映射、设计冻结、状态机文档和测试计划保持一致。
- R5/R13完成文档一致性回查修正 `doc/02-current-implementation-map.md``doc/08-current-design-freeze.md` 中手工绘制、画笔有选中时并入/无选中时新建、Esc、工具切换保留选区和无选区点击语义分类树的旧描述使实现映射、设计冻结、状态机文档和测试计划保持一致。
- R5/R13补充左侧工具栏“取消选中”实体按钮测试和 Canvas `clearSelectionSignal` 测试,验证实体按钮与 `Esc` 共享取消选区/临时绘制状态语义。
- R5补充创建后边界点和中空画笔回归测试验证多边形/矩形/圆创建完成后即使仍在创建工具下也显示已选 mask 边界点,并验证画笔闭合成中空区域时保留 `hasHoles/polygonRingCounts`、使用 even-odd 渲染且内外圈顶点可显示。

View File

@@ -17,20 +17,20 @@
| 状态 | 进入事件 | 可用动作 | 退出事件 | 测试 |
|------|----------|----------|----------|------|
| `idle/no-selection` | 初始、切换到创建工具、`Esc`、左侧“取消选中”、切帧无对应传播结果 | 右侧语义树只设置后续新建类别;清空遮罩作用于当前帧全部 mask | 点击 mask、AI 推送、创建新 mask | `CanvasArea.test.tsx``OntologyInspector.test.tsx` |
| `mask-selected` | `move/edit_polygon` 下点击 mask、新建 mask 完成、AI 候选选中 | 右侧语义树给已选 mask 换类Delete/Backspace/DEL 删除;橡皮擦可扣除;顶点可编辑 | `Esc`、左侧“取消选中”、切换到创建工具、删除 mask、切帧无对应传播结果 | `CanvasArea.test.tsx` |
| `polygon-drawing` | `create_polygon` 下点击画布 | 继续加点;三点后 Enter 或点击首点闭合 | Enter/首点创建新独立 mask 并显示边界点;`Esc` 放弃临时点并清选区 | `CanvasArea.test.tsx` |
| `shape-dragging` | `create_rectangle/create_circle` 下按下鼠标 | 拖拽预览形状 | 鼠标释放创建新独立 mask 并显示边界点;切工具取消临时状态 | `CanvasArea.test.tsx` |
| `brush-stroking` | `brush` 且已有 `activeClass` 时按下鼠标 | 采样图像范围内圆形笔触 | 鼠标释放创建新的独立 mask闭合成中空区域时保留内洞 ring图外落笔不创建`Esc` 取消笔触和选区 | `CanvasArea.test.tsx` |
| `idle/no-selection` | 初始、`Esc`、左侧“取消选中”、删除 mask、切帧无对应传播结果 | 右侧语义树只设置后续新建类别;清空遮罩作用于当前帧全部 mask | 点击 mask、AI 推送、创建新 mask | `CanvasArea.test.tsx``OntologyInspector.test.tsx` |
| `mask-selected` | `move/edit_polygon` 下点击 mask、新建 mask 完成、AI 候选选中 | 右侧语义树给已选 mask 换类Delete/Backspace/DEL 删除;橡皮擦可扣除;顶点可编辑;创建工具的新几何会并入当前 mask | `Esc`、左侧“取消选中”、删除 mask、切帧无对应传播结果 | `CanvasArea.test.tsx` |
| `polygon-drawing` | `create_polygon` 下点击画布 | 继续加点;三点后 Enter 或点击首点闭合 | Enter/首点在有选中 mask 时并入选中 mask无选中时创建新 mask 并显示边界点;`Esc` 放弃临时点并清选区 | `CanvasArea.test.tsx` |
| `shape-dragging` | `create_rectangle/create_circle` 下按下鼠标 | 拖拽预览形状 | 鼠标释放时有选中 mask 则并入选中 mask无选中时创建新 mask 并显示边界点;切工具取消临时状态 | `CanvasArea.test.tsx` |
| `brush-stroking` | `brush` 且已有 `activeClass` 或当前选中 mask 时按下鼠标 | 采样图像范围内圆形笔触 | 鼠标释放时有选中 mask 则并入选中 mask无选中时创建新的当前类别 mask闭合成中空区域时保留内洞 ring图外落笔不创建`Esc` 取消笔触和选区 | `CanvasArea.test.tsx` |
| `eraser-stroking` | `eraser` 且已有选中 mask 时按下鼠标 | 采样图像范围内圆形笔触 | 鼠标释放从选中 mask 扣除;扣空则删除该 mask`Esc` 取消笔触和选区 | `CanvasArea.test.tsx` |
| `boolean-selecting` | `area_merge/area_remove` | 选择多个 mask主区域黄色实线参与区域红色虚线 | 当前帧执行、所有传播帧、按帧范围、取消、切换工具 | `CanvasArea.test.tsx``VideoWorkspace.test.tsx` |
### 细节规则
- `Esc` 是取消当前交互状态,不是删除:清空 `selectedMaskIds`、临时多边形点、矩形/圆拖拽状态、画笔/橡皮擦笔触和顶点选择;保留已有 mask、当前 `activeClass` 和当前工具。
- 切换到 `create_polygon``create_rectangle``create_circle`清空旧 mask 选区,避免之后点击语义分类树误改旧 mask
- 多边形、矩形、圆和画笔创建完成后会自动选中新创建的 mask。
- 画笔每次松手都创建新的独立 mask即使与旧 mask 连通或重叠也不自动合并;合并只能通过“区域合并”工具显式执行
- 切换到 `create_polygon``create_rectangle``create_circle`保留旧 mask 选区;用户若想新建独立 mask需要先按 `Esc` 或点击“取消选中”
- 多边形、矩形、圆和画笔创建完成后,有选中 mask 时会并入选中 mask无选中 mask 时会自动选中新创建的 mask。
- 画笔和形状创建遵循同一规则:有选中 mask 时并入选中 mask没有选中 mask 时才新建独立 mask
- 橡皮擦只作用于当前选中 mask不会在无选区时启动。
- 绘制类工具点击已有 mask 时继续绘制,不触发 mask 选择。