2026-05-20-02-32-47 支持NII导出包与分割类别范围

This commit is contained in:
2026-05-20 02:40:50 +08:00
parent 66ad99f996
commit 68fb0cb564
7 changed files with 469 additions and 29 deletions

View File

@@ -0,0 +1,68 @@
# 实现方案-2026-05-20-02-32-47
## 实现方案文档路径
`工程分析/实现方案-2026-05-20-02-32-47.md`
## 修改目标
将顶部“导出全部 NII.GZ”改为一次性下载 `.tar.gz` 导出包;分割影像导出时自动附带 label/category 映射 JSON并支持“所有类别/可见类别”范围选择。
## 涉及路径
- `WebSite/server.ts`
- `WebSite/src/lib/api.ts`
- `WebSite/src/components/ReverseWorkspace.tsx`
- `工程分析/需求分析-2026-05-20-02-32-47.md`
- `工程分析/实现方案-2026-05-20-02-32-47.md`
- `工程分析/测试方案-2026-05-20-02-32-47.md`
- `工程分析/经验记录.md`
## 技术路线
1. 后端扩展分割生成参数:
- 增加 `SegmentationExportScope = all | visible`
- `createSegmentationData` 按 scope 决定是否跳过隐藏构件。
2. 后端新增类别映射 JSON
- 根据 `project.stlFiles``project.moduleStyles` 生成 label/name/fileName/color/opacity/visible。
- scope 为 visible 时只包含可见构件。
3. 后端新增导出包接口:
- `GET /api/projects/:projectId/export-bundle`
- 参数:`targets=dicom,segmentation,pose``format=nii.gz``pose=...``segmentationScope=visible|all`
- 使用现有 tar header 工具封装为 `.tar.gz`
4. 前端 API
- 新增 `downloadProjectExportBundle`
- 保留单个分割 NII/NII.GZ 下载兼容。
5. 前端菜单:
- “导出所选”改为下载单个压缩包。
- 增加分割类别范围的 segmented control。
- 仅选中分割影像时显示类别范围选项。
## 执行步骤
- 新增后端 tar entry 通用函数和 bundle 生成函数。
- 修改 NIfTI 分割生成函数支持 scope。
- 新增 label map JSON 生成逻辑。
- 调整前端 API 和导出菜单。
- 执行 `npm run lint``npm run build`
- 用临时/正式服务验证 bundle 接口返回 `.tar.gz`,并检查包内文件名。
- 追加经验记录、commit、push、部署。
## 兼容性与回滚方案
- `/export-nifti``/export-mask` 保持可用。
- 单独分割导出默认沿用 visible scope。
- 若 bundle 导出异常,可回滚到多文件直链下载。
## 预计文件变更
- `server.ts`:新增 bundle、分割 scope、类别映射 JSON。
- `api.ts`:新增 bundle 下载 API。
- `ReverseWorkspace.tsx`:导出菜单增加 scope 选择并调用 bundle。
- 工程分析文档:新增本次文档,更新经验记录。
## 提交与部署策略
- Commit message`2026-05-20-02-32-47 支持NII导出包与分割类别范围`
- 显式暂存本次相关文件,避免提交历史删除状态。
- 推送到 Gitea `origin/main`,并使用 `tmux` 会话 `revoxelseg-dicom` 重新部署。

View File

@@ -0,0 +1,62 @@
# 测试方案-2026-05-20-02-32-47
## 测试方案文档路径
`工程分析/测试方案-2026-05-20-02-32-47.md`
## 静态检查
-`WebSite/` 下执行 `npm run lint`
## 构建检查
-`WebSite/` 下执行 `npm run build`
## 关键业务场景验证
- 顶部“导出全部 NII.GZ”选择多个内容后只触发一个压缩包下载。
- 选中分割影像时,菜单显示“导出可见类别/导出所有类别”选项。
- bundle 中包含所选 DICOM NIfTI、分割 NIfTI、位姿 JSON。
- 若包含分割影像bundle 中同时包含 `segmentation-labels.json`
- 类别 JSON 中 label/partId/name/fileName/color/opacity/visible 与项目构件层级一致。
## 医学影像数据相关边界验证
- DICOM NIfTI 仍为真实 DICOM 体数据同维同距。
- 分割 NIfTI 仍使用当前模型位姿。
- visible scope 下隐藏构件不进入分割图和类别 JSON。
- all scope 下隐藏构件仍进入分割图和类别 JSON。
## 部署验证
- 重启 `tmux` 会话 `revoxelseg-dicom`
- 验证:
- `curl http://127.0.0.1:4000/api/health`
- `curl -I http://127.0.0.1:4000/`
## Git/Gitea 备份验证
- 显式暂存本次相关代码和文档。
- 创建包含时间戳和描述的 commit。
- 推送到 Gitea `origin/main`
## 实测结果
- `npm run lint`:通过。
- `npm run build`:通过;仅保留 Vite chunk size 提醒。
- 临时服务 `127.0.0.1:4100` 验证 `targets=segmentation,pose&segmentationScope=visible`HTTP 200返回 `.tar.gz`
- visible bundle 包内包含:
- `head-ct-demo-segmentation-label.nii.gz`
- `head-ct-demo-segmentation-labels.json`
- `head-ct-demo-pose-data.json`
- `segmentation-labels.json` 验证包含 `segmentationScope=visible``label/partId/name/categoryName/className/fileName/color/opacity/visible` 字段。
- 临时服务验证 `targets=dicom,segmentation,pose&segmentationScope=all`HTTP 200返回约 75.90 MB `.tar.gz`
- all bundle 包内包含 DICOM NIfTI、分割 NIfTI、分割 labels JSON、位姿 JSON。
- all labels JSON 验证包含隐藏构件,隐藏项 `visible=false` 仍保留。
- bundle 内分割 NIfTI 头验证:`512x512x300`datatype `2`bitpix `8`,最大标签 `9`
## 风险与回归关注点
- 避免重新引入 `URL.createObjectURL(blob)` 下载。
- 避免提交历史工程文档删除状态。
- 大体数据打包接口要捕获异常并返回明确错误。

View File

@@ -1099,3 +1099,21 @@ C. 解决问题方案
D. 后续如何避免问题
凡是三维视图中的方向、法向、切面或平移提示,都应从 Three.js 真实对象矩阵或统一坐标变换链路推导,不能手写静态示意。若该提示会随拖拽视角变化,还必须包含场景根节点和相机投影。
## 2026-05-20-02-32-47 分割影像与类别元数据必须同包同源
A. 具体问题
用户要求“导出全部 NII.GZ”改成压缩包形式同时分割影像必须附带不同类别 ID 与名称的对应 JSON并且分割范围可选所有类别或可见类别。如果 NIfTI 和 JSON 分开下载,或二者使用不同筛选条件,后续在 ITK-SNAP 查看时容易无法追溯标签语义。
B. 产生问题原因
旧前端对多个导出目标采用连续触发多个直链下载,缺少一个原子化导出包;旧分割生成逻辑默认跳过隐藏构件,也没有把实际参与导出的 label/partId/name/fileName/color 等元数据写入侧车文件。
C. 解决问题方案
新增 `/api/projects/:projectId/export-bundle`,将 DICOM NIfTI、分割 NIfTI、位姿 JSON 和分割 labels JSON 放入同一个 `.tar.gz`。分割生成函数和 labels JSON 生成函数共用 `segmentationScope=visible|all`,确保可见/全量筛选逻辑一致labels JSON 中记录 label、partId、name、categoryName、className、fileName、color、opacity、visible 和 activePose。
D. 后续如何避免问题
任何分割影像导出都应同时考虑语义侧车文件,并保证侧车元数据与实际 mask 标签来自同一批样式和筛选条件。多文件导出优先做成一个后端归档包,避免浏览器多下载顺序、丢文件或元数据错配。

View File

@@ -0,0 +1,56 @@
# 需求分析-2026-05-20-02-32-47
## 开始时间
2026-05-20-02-32-47
## 原始需求摘要
用户要求优化“导出全部 NII.GZ”
- 选择导出全部时,改为压缩包形式一次导出。
- 如果选择分割影像,需要同时导出不同类别 ID 与名称/类别名对应的 JSON 文件。
- 分割影像导出范围可选择“所有类别”或“可见类别”。
## 业务目标
- 避免多文件连续触发下载,形成一个可归档、可转移的导出包。
- 让分割影像与类别语义元数据成对导出,便于 ITK-SNAP 查看后再对照系统内 STL 构件层级。
- 保留“只导出当前可见构件”的轻量检查场景,同时支持“导出全部构件”的完整交付场景。
## 输入与输出
- 输入:
- 导出内容选择DICOM 原始影像、分割影像、位姿数据。
- 分割类别范围:所有类别或可见类别。
- 当前模型位姿。
- 输出:
- 一个 `.tar.gz` 导出包。
- 包内按选择包含 DICOM NIfTI、分割 NIfTI、位姿 JSON。
- 若包含分割影像,同时包含类别映射 JSON。
## 影响范围
- `WebSite/server.ts`
- `WebSite/src/lib/api.ts`
- `WebSite/src/components/ReverseWorkspace.tsx`
- 本次工程分析文档和经验记录。
## 关键约束
- NIfTI 导出仍必须使用真实 DICOM 维度、spacing 和当前模型位姿。
- 分割类别范围不能影响 DICOM 原始影像和位姿数据导出。
- 类别 JSON 必须与实际导出的分割标签值一致。
- 前端仍使用后端直链下载,避免重新引入 blob URL。
## 风险点
- DICOM NIfTI 和分割 NIfTI 都可能较大,包生成会有一定耗时。
- 当前项目已有 tar.gz 归档工具,若强行实现 zip 可能引入额外复杂度;本轮默认使用 `.tar.gz` 压缩包。
- “可见类别”需要读取项目持久化的 `moduleStyles.visible`,不能只看前端临时状态。
## 默认假设
- “压缩包形式”按项目现有归档方式实现为 `.tar.gz`
- 顶部“导出全部 NII.GZ”使用压缩包右侧单独 NII/NII.GZ 导出按钮继续导出单个分割 NIfTI。
- 分割类别范围默认为“可见类别”,符合当前右侧映射视图的显示语义。