Files
AnyImage/openspec/changes/normalize-moge-alpha-depth/design.md
nan c97b4a3e41 Add image selection refinement functionality with BEN2 integration
- Implemented viewport.py for handling 3D view projections, gestures, and overlay drawing.
- Created refine_image_selection.py to manage the refinement of gesture masks and output image bounds.
- Added selection module with refine_selection.py to process and crop images based on alpha channel visibility.
- Introduced __init__.py for selection module to expose refine_selection function.
2026-08-31 22:10:05 +08:00

94 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Context
Cutout Job 会把最终 Region 图像交给 MoGe-2。Remove Background 路径会清除全透明像素下的 RGB,Fit to Foreground 路径则可能保留隐藏 RGB;MoGe-2 只读取 RGB,因此两条业务路径当前并不等价。
几何预测的另一处边界也不统一:MoGe-2 先返回专用 `Prediction`,Normal Writer 直接读取它,Depth Writer 才临时转换为 `GeometryFrame`;DA3 则有另一套转换入口。这样 `GeometryFrame` 没有真正成为模型预测与几何产物之间的稳定协议。
MoGe-2 返回连续的 Depth/Points Field 和原始 Mask。当前 Depth Writer 会按有效性 Mask 清零 RGB,而 Depth Surface 线性采样 RGB、不读取 Alpha,因此 Mask 边界的零坐标会把网格拉向相机原点。
## Goals / Non-Goals
**Goals:**
- 以 MoGe-2 单帧预测的数据类型重建 `GeometryFrame`,并让 MoGe-2 与 DA3 都通过模型适配器产出该类型。
- 让 Depth EXR、Normal Texture 和 `depth.json` 只消费 `GeometryFrame`,不直接依赖模型专用预测结构。
- 让所有 MoGe-2 调用在同一个 Server 边界获得确定的黑底 RGB 输入。
- 让 Depth EXR 分别表达连续数值场与原始模型 Mask,两者互不改写。
- 保留严格的 Metadata 校准筛选,并阻止非有限数值进入 Blender。
**Non-Goals:**
- 不修改 BEN2、MoGe-2 或 DA3 模型实现及其推理分辨率。
- 不改变 Depth EXR 文件名、尺寸、RGBA 通道布局或节点组接口。
- 不用输入 Alpha 覆盖模型 Mask,也不在本次变更中让 Geometry Nodes 按 Alpha 丢弃点。
- 不把 DA3 恢复为当前生产路径;仅保持其适配器与统一协议可用、可测试。
## Decisions
### 1. `GeometryFrame` 是单帧几何预测协议
`GeometryFrame` 按 MoGe-2 单帧结果定义:
- `depth: ndarray[H, W]`,必需的 `float32` 深度场;
- `normal: ndarray[H, W, 3] | None`,MoGe-2 提供,DA3 可为空;
- `validity: ndarray[H, W]`,必需的 `float32` 模型有效性信号;MoGe-2 的原始 Mask 转换为 `0/1`,DA3 保存原始连续 Confidence;
- `intrinsics: ndarray[3, 3]`,必需的 `float32` 像素坐标内参;
- `points: ndarray[H, W, 3] | None`,可选的 `float32` 相机空间点场;
构造时校验 dtype、维度和同帧空间尺寸,但不在容器内改写预测值。`validity` 是唯一存储的模型有效性信号;不再同时保存 `mask`、`confidence` 和派生的 `valid_mask`,避免相同职责出现多个可漂移来源。
MoGe-2 的生产推理入口直接返回一组 `GeometryFrame`,在适配器内完成 batch 拆分、Mask 到 Validity 的转换和内参像素化。用于调试 NPZ 的原始单次推理入口继续返回模型原始字典,因为它不是 Artifact 生产边界。DA3 保留原始调试推理,并提供同样的逐帧适配器:`normal=None`,从深度和内参生成 Points,并把 Confidence 作为连续 Validity。
不选择在通用层保留 MoGe-2 `Prediction` 再二次转换,因为这会继续允许 Writer 绕过统一协议。也不把 `GeometryFrame` 限定为 MoGe-2 类型,避免 DA3 和后续模型各自复制 Artifact 逻辑。
### 2. 所有几何 Artifact Writer 只消费 `GeometryFrame`
Vector Depth Writer 从 `frame.points` 和 `frame.validity` 写 EXR;Z Depth Writer 从 `frame.depth` 和 `frame.validity` 写 EXR;Normal Writer 从 `frame.normal` 生成贴图;Metadata Writer 从 `frame.depth`、`frame.intrinsics` 和调用方提供的业务 Region Mask 计算 `depth.json`。
Writer 只依赖通用 `GeometryFrame`,不导入 `moge2` 或 `da3`。缺少所需可选字段时明确失败,例如没有 `points` 不能写 Vector Depth,没有 `normal` 不能写 Normal Texture。Artifact 编排层从 MoGe-2 取得一帧 `GeometryFrame` 后,把同一对象传给各 Writer,不再读取模型专用属性。
Metadata 所需的校准有效性按使用点计算:正的 `frame.validity`、有限且为正的 Depth,以及业务 Region Mask 的交集。它不是 `GeometryFrame` 的第二个持久字段,也不反向影响 EXR Alpha 或 RGB。
### 3. 在最终 MoGe-2 输入边界统一黑底合成
读取最终 `region_image_path` 为 RGBA,按输入上限缩放,然后使用 `output_rgb = source_rgb * alpha` 合成到黑底,并始终写为 Job 内的 RGB PNG。即使无需缩放,也经过相同规范化步骤。
这会让半透明像素保留按 Alpha 衰减后的颜色,并彻底消除 Alpha 为零时隐藏 RGB 的差异。Metadata 和 Normal 输出所需的业务 Alpha 仍从原始 Region 图读取,不从已移除 Alpha 的模型输入读取。
不在 Blender 的 `prepare_region_input()` 提前处理,因为该入口还服务其他 Job,而且 Fit to Foreground 会在 Server 端重新生成 RGBA,无法形成唯一收口点。
### 4. Depth RGB 保留连续 Field,Alpha 只记录 `frame.validity`
Vector/Z Depth Writer 无条件把完整 Points/Depth Field 写入 RGB,并仅把 `frame.validity` 写入 Alpha。零 Validity 不再导致 RGB 清零,使 Depth Surface 在边缘线性采样时仍能得到连续坐标。
Writer 在创建文件前要求所需 Field 全部有限。Mask 为假不豁免该检查,因为 Geometry Nodes 仍会读取 Mask 外 RGB;NaN/Inf 会传播到网格。有限但非正的 Depth 仍忠实写入,正值条件只属于 Metadata 校准。
不把非有限值替换为零或最近有效值:前者会重新引入相机原点尖刺,后者不再忠实于模型结果。
### 5. 测试固定协议、工作流等价与连续性
测试分为四层:
1. `GeometryFrame` 校验,以及 MoGe-2/DA3 适配器的字段、形状、dtype、Validity 映射和批次拆分。
2. 模型输入验证 Alpha 为 `0`、`0.5`、`1` 的黑底合成,并验证不同隐藏 RGB 得到相同透明区输入。
3. Writer 验证只接收 `GeometryFrame`、Validity 为零时 RGB 保留原值、Alpha 等于 `frame.validity`、缺字段与 NaN/Inf 明确失败;Normal 和 Metadata 不再读取 MoGe-2 专用结果。
4. Depth Surface 使用边缘 Mask 为假但 XYZ 连续的 Vector Depth,验证求值网格不会聚集到相机原点。
## Risks / Trade-offs
- [MoGe-2 返回类型变化会影响调用方] → 生产调用集中在 Artifact 编排层;一次性迁移并删除旧 `Prediction`/转换入口,不保留兼容层。
- [GeometryFrame 严格 dtype 会暴露模型适配错误] → 在适配器边界显式转换并用模型级测试固定协议。
- [黑底输入会改变当前 Fit to Foreground 的预测] → 这是统一语义的预期行为,用像素级测试固定合成规则。
- [零 Validity 区域的有限 Field 可能精度较低] → Alpha 完整保留模型判断供消费者解释;连续 Field 用于避免几何塌缩。
- [完整 Field 中一个非有限值会使 Job 失败] → 失败优于生成被 NaN/Inf 污染的网格,错误信息区分 Depth、Point 和 Normal Field。
## Migration Plan
1. 重建 `GeometryFrame` 与两种模型适配器,迁移 MoGe-2 生产推理返回值并删除旧专用中间结构。
2. 将 Depth、Normal 和 Metadata Writer 改为只消费 `GeometryFrame`,再迁移 Artifact 编排层。
3. 建立统一的 MoGe-2 黑底输入准备,并补充像素与工作流等价测试。
4. 调整 EXR 通道写入与数值检查,增加 Depth Surface 回归测试。
5. 更新 GeometryFrame、Artifact 和 Cutout 内部文档并运行全量测试。
现有 Job 目录中的旧 EXR 不迁移;重新运行对应功能即可生成新语义 Artifact。回退时必须同时回退协议、适配器、Writer 与测试。