Add new tests and functionality for image processing and geometry handling

- Introduced color_image.py for preparing standalone color images for tests.
- Added hdr_image.py to create HDR textures for testing.
- Implemented test_image_depth_panorama.py to evaluate panorama topology, UVs, and depth discontinuities.
- Created test_shadeless.py to validate the opacity and HDR color endpoints of the Shadeless group.
- Developed moge3_export.py for exporting dynamic MoGe-3 backbone and ONNX graphs.
- Added material.py to inherit material slots onto generated geometry.
- Built image_depth_panorama.py to construct a quad panorama with depth separation and sampling.
This commit is contained in:
2026-09-10 14:42:17 +08:00
parent 27ca25224a
commit 489003c2cc
136 changed files with 5758 additions and 1083 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-10

View File

@@ -0,0 +1,72 @@
## Context
Remove Background 通过 ImageEditTarget 准备输入并提交结果。普通文件按路径校验,packed 图片导出 PNG;后端 BEN2 接收 Pillow RGB,预测 mask 后转换成 8-bit RGBA,Job 写入 PNG。源像素、结果载入和图片替换都涉及 HDR 精度边界。
BEN2 网络输出是 alpha,识别本身可复用既有模型。HDR 支持的关键是分离识别预览与原始 RGB,并让浮点信息贯穿主线程合成、EXR 编码和结果替换。
## Goals / Non-Goals
本次交付为 HDR 静态图去背景:保留源图的场景线性色彩、有效动态范围和尺寸,以模型预测更新透明度。支持 Image Empty 和材质 Image Texture 两种已有入口,以及 Blender 可读取的外部、packed、generated 浮点静态图片。普通媒体沿用既有处理方式;HDR 动画在提交前明确提示首版支持范围。Upscale 的 HDR 适配作为独立能力评估。
## Decisions
### 1. 在 Blender 侧捕获源图和准备预览
以 `Image.is_float` 及真实图片来源判断 HDR 路径,扩展名仅用于来源识别与提示。所有可读浮点静态图片走该路径,包括数值暂时处于 0–1 内的图片。准备时读取当前像素,包含尚未保存的编辑;为本次任务保存独立的 RGBA 数值快照、尺寸、色彩空间和 alpha 解释信息。
Blender 数据仅在主线程准备与提交阶段访问,Job 参数只包含普通字典中的路径、字符串和数值。后端始终读取 PNG 识别预览,因此公共媒体格式校验仍校验实际提交文件。源图与临时文件的所有权由准备阶段和 Job cleanup 明确交接。
### 2. 用固定映射生成可识别的普通 RGB
识别预览从场景线性、非预乘 RGB 生成。Blender 的浮点缓冲已经采用场景线性颜色与预乘 alpha;预览先解关联,再采用按亮度的 Reinhard 映射,以非负亮度 Y 计算 `RGB / (1 + Y)`,执行线性 Rec.709 到 sRGB 编码并限制到可编码范围。负值只在预览中处理;源浮点数值保持原样。全黑图保持有限值。预览按源 alpha 合成到黑底,符合现有 BEN2 输入语义。
映射固定且不读取用户当前 View Transform、Look、Exposure,避免切换显示设置导致 mask 变化。源颜色解码由 Blender 完成。数据图片与 CHANNEL_PACKED 输入在准备时给出明确错误。
该映射是首版确定性基线。用实际高动态范围图片验证高光边缘、暗部与半透明物体;若识别不足,在本变更内调整并固定预览算法和对应行为测试。
### 3. 让 BEN2 推理核心返回数值 alpha
```mermaid
flowchart TD
A[主线程捕获 HDR RGBA 快照] --> B[固定色调映射生成 PNG 预览]
B --> C[BEN2 推理]
C --> D[浮点 alpha 归一化并还原源尺寸]
D --> E[Job 写入 alpha.npy]
A --> F[主线程合成原始 RGB 与新 alpha]
E --> F
F --> G[写入 32-bit float RGBA EXR]
G --> H[验证并提交到原图片目标]
```
将现有推理核心重构为返回原尺寸 float32 alpha 数组。保留既有 mask 归一化语义,缩放过程使用浮点数据并在最后限制到 0–1,检查尺寸与有限值。普通 RGBA 消费者在自身产物边界完成量化与合成,清理旧核心入口并更新真实调用者。
Remove Background Job 增加明确的产物模式,例如 `output_kind: "alpha"`,HDR 静态图产出 `alpha.npy` 并通过结果字段声明。读取使用 `allow_pickle=False`,验证形状、范围和有限值。现有普通图片与动画消费者继续取得对应的 RGBA 结果。
### 4. 主线程合成和 EXR 持久化
在非预乘语义下计算 `A_out = A_source × A_predicted`,保留原始 RGB。Blender 原生浮点缓冲使用预乘 RGB,因此实现直接将 RGBA 乘以预测 alpha,保持解关联后的颜色;解码 STRAIGHT EXR 后同样采用该缓冲语义。零 alpha 像素的不可恢复颜色置零,NONE 模式按不透明源处理。测试分别比较 straight RGB 或重新合成后的可见颜色。
创建 `float_buffer=True` 的结果图片,使用独立临时场景指定 32-bit float RGBA EXR、ZIP 压缩,通过 `save_render` 写出场景线性值。结果采用 Linear Rec.709 与 PREMUL,保存后载入并核对数值,再打包和提交;临时场景及文件在对应阶段结束后释放。
复用 ImageEditTarget 和 common 内的提交、共享引用隔离、图片内容备份与恢复。HDR 的 Empty 提交同时保护材质节点等其他实际使用者。独占源图包含未保存像素或为生成图时,将其当前浮点内容转为内嵌 EXR 并建立撤销基线,保留 Image 身份;一次撤销恢复原始内容,重做恢复处理结果。提交失败时恢复操作前的源状态。先验证候选结果再提交,其他共享使用者保持原状。
### 5. 保持异步编辑事务完整
使用提交时的源快照进行合成,完成前复核原目标及图片绑定。纹理节点保存独立的 `anyimage_identity`,提交时与捕获值核对,避免 Blender 删除重建节点后复用 RNA 地址造成误认。增加对捕获后源像素或色彩解释被修改的冲突检查,发现冲突则提示重新执行并保留当前编辑。
临时预览由输入 cleanup 释放,alpha 由 Job 目录管理,候选 EXR 完成载入和打包后释放临时副本。取消、推理失败、合成失败、提交失败均释放快照与本次临时数据。成功结果支持一次撤销、重做以及保存重开。
## Risks / Trade-offs
- 固定预览映射可能压低极暗部的可辨识度:用代表性 HDR 图片进行真实 BEN2 验收。
- Blender 像素、alpha 模式与 EXR 编码之间存在转换:以已知数值的真实 Blender 保存重开测试约束实现。
- 源快照增加内存占用:仅保留合成和冲突检测所需的数据,所有终止路径释放;大型输入准备失败时提供可读错误。
- 工作区相关公共入口正在修改:实施前核对现有变更,复用最新公共校验和事务接口。
## Migration Plan
先完成数值 alpha 核心与现有消费者回归,再实现 HDR 准备、合成和事务提交。验证普通媒体行为及 HDR round-trip 后完成能力交付。Job 协议由同版本插件与后端一起更新。
## Open Questions
无需要用户决策的前置问题。Blender 像素空间、PREMUL round-trip 与固定预览的识别质量已通过数值测试及实际 BEN2 推理确认。

View File

@@ -0,0 +1,27 @@
## Why
BEN2 通过普通 RGB 图像预测前景透明度。当前去背景流程用 Pillow 合成并保存 PNG,无法保留 HDR 图像的浮点颜色。将识别预览与原始颜色分离,可以让用户对 HDR 图片去背景,同时保留用于渲染的亮度和色彩。
## What Changes
- 为 Remove Background 增加 HDR 静态图处理,覆盖 Blender 已加载的 EXR、Radiance HDR、已打包及生成的浮点图片。
- 从提交时的浮点像素生成经过固定色调映射的 RGB 识别预览,原始颜色留在 Blender 侧。
- BEN2 提供浮点 alpha 结果;主线程将其与源 alpha 相乘,并与原始颜色合成。
- 结果使用 32-bit float RGBA EXR 持久化,支持保存重开、共享图片隔离、撤销和失败恢复。
- 对 HDR 动画输入在准备阶段给出明确提示;普通图片与现有视频、序列沿用当前行为。
## Capabilities
### New Capabilities
- `hdr-background-removal`: HDR 静态图片的识别预览、alpha 预测、浮点结果及生命周期。
### Modified Capabilities
无已发布能力规格需要修改;与现有 ImageEditTarget 的目标提交语义衔接。
## Impact
- Blender:`common/image.py`、`common/image_target.py`、`operators/remove_background.py`;复杂的 HDR 图像处理可独立放入 `common/hdr_image.py`。
- 后端:`server/models/onnx_ben2.py`、`server/models/ben2.py`、`server/jobs/remove_background.py`,以及对应测试。
- 输入仍为普通预览 PNG,新增 Job 的 alpha 产物模式,复用 NumPy 保存数值结果。BEN2 权重与运行依赖保持现有配置。
- 与进行中的 `unify-ai-input-validation` 及图片目标编辑变更共同使用实施时的真实调用链。

View File

@@ -0,0 +1,89 @@
## ADDED Requirements
### Requirement: HDR still image preparation
系统 SHALL 为可读的浮点静态图片提供 Remove Background,覆盖 Image Empty 与材质 Image Texture 的外部、packed 和 generated 图片。输入 SHALL 采用任务开始时的当前像素快照。
#### Scenario: An HDR still is submitted
- **WHEN** 用户对可读的 EXR、HDR 或其他浮点静态图片执行 Remove Background
- **THEN** 系统捕获当前 RGBA、尺寸与颜色解释,并提交普通 RGB 识别预览
#### Scenario: Unsaved pixels are present
- **WHEN** 源浮点图包含未保存的像素编辑
- **THEN** 识别预览与最终 RGB 均使用当前编辑后的快照
#### Scenario: An HDR animation is submitted
- **WHEN** 用户对 HDR 序列或浮点动画执行 Remove Background
- **THEN** 系统在创建推理任务前提示本次 HDR 功能支持静态图,并保持源图状态
### Requirement: Deterministic recognition preview
系统 SHALL 通过确定性的曝光范围压缩及色彩编码生成 BEN2 的普通 RGB 预览,原始 RGB SHALL 独立保留。预览 SHALL 正确解释源 alpha,且不受用户显示变换设置影响。
#### Scenario: Highlights exceed one
- **WHEN** 源图包含多个大于 1 的不同亮度值
- **THEN** 预览先进行色调映射再编码,原始快照保留这些数值
#### Scenario: Display settings change
- **WHEN** 相同源像素分别在不同 View Transform、Look 或 Exposure 下提交
- **THEN** 识别预览一致
#### Scenario: The image is black or contains negative values
- **WHEN** 可读源像素为全黑或包含有限负颜色值
- **THEN** 预览数值有限,源 RGB 不因预览映射改变
### Requirement: Float alpha result
HDR 去背景 Job SHALL 返回原始尺寸的 float32 alpha 数组,数值有限且位于 0–1。系统 SHALL 在使用前验证产物。
#### Scenario: BEN2 predicts a soft edge
- **WHEN** 模型预测连续透明度边缘
- **THEN** alpha 经过浮点缩放返回,合成前不量化为 8-bit
#### Scenario: Alpha is invalid
- **WHEN** alpha 文件损坏、尺寸不符或包含非有限及越界数值
- **THEN** 系统报告结果错误,保持源图片与目标绑定
### Requirement: HDR color and transparency persistence
系统 SHALL 保留源 RGB 的场景线性色彩及动态范围,并以源 alpha 与预测 alpha 的乘积作为结果透明度。结果 SHALL 为同尺寸浮点图像并采用 32-bit float RGBA EXR 持久化,颜色误差 SHALL 限于浮点运算与必要颜色转换的容差。
#### Scenario: Straight alpha is present
- **WHEN** 源图为 straight alpha 且存在大于 1 的 RGB 和部分透明像素
- **THEN** 结果 RGB 保留,alpha 等于源 alpha 乘预测 alpha
#### Scenario: Premultiplied alpha is present
- **WHEN** 源图采用 PREMUL 且包含部分透明及完全透明像素
- **THEN** 系统按 alpha 关联语义合成,边缘颜色正确且结果没有 NaN 或 Inf
#### Scenario: The project is saved and reopened
- **WHEN** 用户保存含处理结果的 blend 文件后重新打开
- **THEN** 结果尺寸、HDR 数值、颜色解释和透明度保持一致
### Requirement: Transactional target update
系统 SHALL 复用既有图片目标提交规则,保护共享使用者并支持撤销、重做与错误恢复。Blender 数据访问 SHALL 发生于主线程,任务通信 SHALL 使用可序列化普通参数。
#### Scenario: Another owner shares the image
- **WHEN** 源图片存在其他实际使用者
- **THEN** 仅发起操作的目标取得独立 HDR 结果,其他使用者仍引用原图
#### Scenario: The source changes during inference
- **WHEN** 原目标失效、改绑图片或源像素与颜色解释发生修改
- **THEN** 系统拒绝覆盖当前状态,提示重新执行并清理本次临时资源
#### Scenario: The operation is cancelled or fails
- **WHEN** 准备、推理、合成或提交取消或失败
- **THEN** 系统保持或恢复源图及目标绑定,释放本次快照和临时数据
#### Scenario: The user undoes and redoes
- **WHEN** 用户撤销并重做一次成功的 HDR 去背景
- **THEN** 原始和处理后的浮点内容及绑定正确恢复,重做无需重新推理
### Requirement: Existing media behavior
系统 SHALL 保留普通图片、视频和普通序列的现有去背景行为,所有 BEN2 消费者 SHALL 适配统一的数值 alpha 核心。
#### Scenario: An existing regular image or animation is processed
- **WHEN** 用户提交现有支持的普通图片或动画
- **THEN** 系统按既有帧选择、透明度合成和输出规则完成操作

View File

@@ -0,0 +1,31 @@
## 1. 验证浮点图片基础行为
- [x] 1.1 核对最新输入校验、BEN2 消费者与图片提交调用链,保留工作区已有修改。
- [x] 1.2 在真实 Blender 中验证已知 HDR 数值、straight/PREMUL alpha、色彩空间及 32-bit EXR 保存载入行为,确定可用颜色转换与数值容差。
- [x] 1.3 检查图片内容备份、原位替换、打包及撤销对 float buffer 的支持,定位需要修改的公共边界。
## 2. 分离 BEN2 alpha 核心
- [x] 2.1 将推理核心改为返回原尺寸 float32 alpha,保留归一化行为,使用浮点缩放并校验有限值。
- [x] 2.2 更新所有真实 BEN2 消费者及相关测试,在各自输出边界合成 RGBA,移除旧核心入口。
- [x] 2.3 为 Remove Background Job 增加静态 alpha 产物模式、结果字段及安全的 NumPy 读写校验,覆盖错误与取消路径。
## 3. 准备 HDR 识别输入
- [x] 3.1 在主线程识别浮点静态图并捕获当前 RGBA 快照,覆盖外部、packed、generated 和未保存像素。
- [x] 3.2 实现固定色调映射及 sRGB 预览编码,覆盖 alpha、负值、全黑及显示设置独立性。
- [x] 3.3 接入 Remove Background 的准备与普通参数提交,明确拒绝 HDR 动画并验证临时输入清理。
## 4. 合成与提交 HDR 结果
- [x] 4.1 校验 float alpha 并按 straight/PREMUL 语义合成,保留源 HDR RGB 和尺寸。
- [x] 4.2 创建浮点结果并写入无损 32-bit RGBA EXR,完成载入、打包及临时文件释放。
- [x] 4.3 复用并补全 ImageEditTarget 的浮点提交与恢复行为,覆盖共享隔离、独占 Image 身份、源修改冲突、撤销和重做。
- [x] 4.4 验证取消、失败、目标失效各路径的资源释放和源状态恢复。
## 5. 验收
- [x] 5.1 更新并运行相关后端、common 和 Operator 测试,覆盖浮点 alpha 精度与现有普通媒体行为。
- [x] 5.2 用已知 RGB 大于 1、有限负值、软 alpha 的图片进行真实 Blender 两种入口及保存重开验证;记录数值误差。
- [x] 5.3 用代表性 HDR 实图运行 BEN2,检查高光、暗部、半透明边缘与黑底预览效果,必要时调整固定映射并补齐验证。
- [x] 5.4 运行全量 `uv run pytest` 并确认正常退出,检查最终差异及旧入口引用,记录验证结果。

View File

@@ -0,0 +1,32 @@
## 验证环境
2026-09-10,Windows,项目 uv 环境,Blender Python 4.5.3 LTS,BEN2 本地 `models/BEN2-ONNX/onnx/model_fp16.onnx`,ONNX Runtime CPU。
## 浮点与编辑事务
- 真实 Blender 验证外部 EXR、packed、generated、未保存像素,覆盖 Image Empty 与材质 Image Texture,以及共享和独占图片。
- RGBA 样本包含大于 1 的颜色、有限负值、零 alpha 与部分透明像素;32-bit ZIP EXR 保存、打包、载入和 blend 保存重开均通过数值检查。
- 单独验证 STRAIGHT EXR 解码后的预乘缓冲语义,处理后解关联颜色在 `rtol=1e-6` 内保持一致。
- 已验证 Radiance `.hdr` 实际文件读取与识别预览生成,源浮点像素保持不变。
- 原生 Operator 的撤销、重做、取消、提交异常和资源释放通过测试;未保存的独占浮点源图采用内嵌 EXR 撤销基线。
- 纹理节点删除重建测试覆盖独立身份字段,防止 RNA 地址复用造成异步目标误认。
## 实际 BEN2 推理
Cycles 渲染 320×320 金属 Suzanne,16 samples,两盏面光源,原始 RGB 峰值约 112.432。用渲染 alpha 作为轮廓参考,构造三档曝光的灰底 HDR 图,以及保留原始软 alpha 的透明图。四组均执行真实 BEN2 Job、浮点 alpha 读回、Blender 合成及 EXR 持久化。
| 输入 | 原始 RGB 峰值 | 输出预乘 RGB 峰值 | 轮廓 IoU |
| --- | ---: | ---: | ---: |
| 正常亮度 | 112.4321 | 112.4235 | 0.9822 |
| 16 倍亮度 | 1798.9137 | 1796.3881 | 0.9874 |
| 0.05 倍亮度 | 5.6216 | 5.6176 | 0.9757 |
| 原始透明度 | 112.4321 | 112.4292 | 0.9656 |
IoU 使用预测 alpha 与渲染 alpha 的 0.5 阈值轮廓计算。四组 EXR 读回值相对于 `source_rgba × predicted_alpha` 的最大绝对误差均为 0。已目视检查高亮预览、低亮度预览与预测轮廓。该结果验证当前渲染样例的识别效果;不同实图的抠图质量取决于模型预测。
## 自动检查
- OpenSpec 严格校验通过。
- BEN2 的旧 `infer` 入口及旧节点使用者检查名称已清理,相关调用者和测试已更新。
- 最终 `uv run pytest -q`:1074 passed、2 xfailed、52 subtests passed,175.71 秒,退出码 0。两项 xfail 为已有的浮点图片显示色彩空间适配测试。
- `git diff --check` 通过。