feat: Implement cutout tool and depth generation features

- Added a new cutout tool for selecting regions in images, allowing users to choose mesh shapes based on selected areas.
- Introduced depth generation capabilities for rasterized images, including normal data extraction.
- Created jobs for generating depth planes and region data, enhancing the AI data generation workflow.
- Developed a selection refinement process for cutout regions, improving accuracy in generated outputs.
- Established a new region module for handling rasterized image regions and their associated AI generation tasks.
- Enhanced node graph builders for asset generation, facilitating smoother integration of new features.
This commit is contained in:
2026-08-30 23:09:13 +08:00
parent 32bcd45d7b
commit 08309f719d
88 changed files with 4145 additions and 5639 deletions

View File

@@ -21,7 +21,7 @@ Cutout 用套索从一张 Image Empty 中选择区域,再生成 Surface、Ball
四种结果都保留源 Image Empty,并在同一位置创建新网格。它们共享选区轮廓、UV、材质和基础三角网格,因此可以从同一张图多次生成不同 Shape 进行比较。
无论是否启用 Refine Selection,套索超出图片的部分都不会生成网格,源图中 `Alpha <= 0.1` 的像素也始终从几何中排除。双击选择完整画面时同样只为 `Alpha > 0.1` 的区域生成网格。
无论是否启用 Refine Selection,套索超出图片的部分都不会生成网格,源图中 `Alpha <= 0.1` 的像素也始终从 Region 中排除。双击使用完整画面时同样只为 `Alpha > 0.1` 的 Region 生成网格。
## 工具设置
@@ -38,19 +38,19 @@ Point Spacing 先按完整源图换算基础密度;选区裁切后的长边若
四个 Shape 都使用同一个 `O Image Cutout` Geometry Nodes 修改器。创建时 Shape 菜单已经设为饼菜单所选类型;切换 Shape 后,Blender 只显示该类型实际使用的输入。常用参数包括:
- **Thickness**:Surface / Depth Surface 使用场景距离;Balloon / Depth Balloon 使用鼓起高度倍率。
- **Cleanup**:绝对面积阈值;创建时根据 Point Spacing 和图片平面尺寸自动写入,面积小于该值的 Mesh Island 会在生成任意 Shape 前移除。
- **Cleanup**:碎岛面积阈值;创建时根据 Point Spacing 和图片平面尺寸自动写入。为便于在修改器中调节,显示值放大了 `100` 倍,节点内部会还原为实际面积,因此这次显示缩放不会改变默认清理效果。
- **Smooth Iterations**:位于外层,控制平滑次数,默认 `0`;**Smooth** 位于 Options 中,控制每次平滑的混合强度。四种 Shape 都可使用。
- **Depth Scale**:Depth Shape 的深度强度;`0` 回到基础平面或 Balloon。
两个 Depth Shape 共用 **Reference Depth**;Depth Balloon 还提供 **Depth Direction**。插件自动写入的 Depth Image 与 Uniform Scale 位于折叠的 Data 面板,一般无需手动修改。
两个 Depth Shape 共用 **Base Plane Depth**;Depth Balloon 还提供 **Depth Direction**。生成前会检查最终 Region 输入的 Alpha:`Alpha < 0.1` 的像素达到 `5%` 时,根据有效 Region 自适应 Base Plane Depth,并为 Depth Balloon 拟合 Direction;不足 `5%` 时使用稳定的固定基准。这个判断不依赖双击全图或 Refine Selection。插件自动写入的 Depth Image 与 Uniform Scale 位于折叠的 Data 面板,一般无需手动修改。
Balloon 的轮廓高度算法由扩展 Preferences 中的 **Balloon Profile** 控制:Poisson 更平滑,Teddy 更强调轮廓骨架。修改默认值只影响之后创建的 Shape。
## Refine 与 Normal
Refine Selection 只在“套索与源图可见 Alpha 的交集”内收紧用于建网格的最终选择,不把 AI 生成的颜色写回原图。材质继续使用当前 Image Empty 的源颜色和原 Alpha。
Refine Selection 只在“套索与源图可见 Alpha 的交集”内收紧最终 Region,不把 AI 生成的颜色写回原图。材质继续使用当前 Image Empty 的源颜色和原 Alpha。
Normal 关闭时使用几何法线;开启后,Surface、Balloon 与 Depth Balloon 使用适配成品网格的 Tangent Space 法线,Depth Surface 使用 Object Space 法线。Cutout 始终使用 MoGe-2;Depth 与 Normal 同时需要时共享同一次 Prediction,不会重复运行模型。
Normal 设为 **None** 时使用几何法线;**Tangent** 把 MoGe-2 结果作为基于完整图片平面的浮雕细节,**Object** 则直接编码到 Cutout 对象局部轴。两种模式都不根据 Geometry Nodes 的成品网格再次烘焙。Normal 保持模型分析分辨率,Color Image 仍保留原始裁切分辨率;Depth 与 Normal 同时需要时共享同一次 Prediction,不会重复运行模型。
## 当前范围

View File

@@ -20,7 +20,7 @@ AnyImage 把运行环境、模型和任务结果放在 Blender 之外,多个 B
## 全局 AI 输入尺寸
Environment 区的 **Maximum AI Input Size** 控制 Upscale、Depth 与 Normal 分析输入的最大长边,默认 `2048 px`,可在 `256–8192 px` 之间调整。超过上限的输入会保持宽高比缩小;颜色贴图仍使用原始分辨率。Cutout 在完成套索裁切后再应用上限,因此整张原图很大但选区较小时不会被无谓缩小。
Environment 区的 **Maximum AI Input Size** 默认 `2048 px`,可在 `256–8192 px` 之间调整。它既是允许执行 Upscale 的当前图片长边上限,也是 Depth 与 Normal 分析输入的最大长边;Upscale 在达到上限时置灰,Depth 与 Normal 则保持宽高比缩小分析输入。颜色贴图仍使用当前图片的原始分辨率。Cutout 在完成套索裁切后再应用上限,因此整张图片很大但选区较小时不会被无谓缩小。
## Device
扩展偏好设置中的 **Device** 控制 Depth Plane、Cutout 的 AI 增强、Remove Background 和 Upscale 等正式任务。

View File

@@ -1,6 +1,6 @@
# 高清放大
Upscale 用 ONNX 模型把 Image Empty 的图片放大 4 倍,不创建网格。它支持单图、Movie 和 Image Sequence,并保留源 Alpha。
Upscale 用 ONNX 模型把 Image Empty 的 RGB 放大 4 倍,不创建网格。它支持单图、Movie 和 Image Sequence,并以 Lanczos 独立放大源 Alpha 后重新合并。
## 使用
@@ -8,7 +8,7 @@ Upscale 用 ONNX 模型把 Image Empty 的图片放大 4 倍,不创建网格
2. 按需要设置 Environment 区的 **Maximum AI Input Size**;默认 `2048 px`,最高 `8192 px`。
3. 选中 Image Empty,在右键 **AnyImage** 菜单中点击 **Upscale**。
输入长边超过全局上限时,会先保持宽高比缩小,再执行 4× 放大。因此默认设置下结果长边最多为 `8192 px`。完成后,当前 Empty 会改用名称以 `_upscale.png` 结尾的结果图片。
菜单项只显示本次操作预计生成的 4× 尺寸。当前图片长边必须小于全局上限;达到上限后 Upscale 会置灰,因此默认设置下单次结果长边小于 `8192 px`。完成后,当前 Empty 会直接使用放大结果;原 Image 没有其他引用时沿用原名并移除旧数据,存在其他引用时则为当前 Empty 保留独立结果。
## 模型选择
@@ -18,10 +18,10 @@ Upscale 用 ONNX 模型把 Image Empty 的图片放大 4 倍,不创建网格
后两项可在扩展偏好设置中按需下载。
对高清结果再次执行 Upscale 时,AnyImage 会从最初的原图重新生成并替换当前结果,不会连续放大已有高清图。
AnyImage 不追踪高清结果的原图引用,Upscale 始终处理当前 Image。只要当前长边仍小于全局上限,就可以再次放大;达到上限后不能继续执行。
把高清结果继续转换为 Depth Plane 时,颜色材质可以继续使用当前高清图,分析输入则遵守全局上限;Cutout 同样只缩放裁切后的分析输入,不会把限制后的临时图用作 Color。
把高清结果继续转换为 Depth Plane 时,颜色材质和分析都以当前 Image 为来源,分析输入仍遵守全局上限;Cutout 同样只缩放裁切后的分析输入,不会把限制后的临时图用作 Color。
如果显存或内存不足,请降低 **Maximum AI Input Size**,或改用 CPU。
分块推理、Alpha 合并与原图引用见 [Upscale 实现原理](../internals/operators/upscale.md)。
分块推理、Alpha 合并与输入限制见 [Upscale 实现原理](../internals/operators/upscale.md)。

View File

@@ -37,7 +37,7 @@ flowchart TD
Menu --> Runtime["注册 JobRuntime"]
```
`__init__.py` 按依赖顺序注册,并在注销时逆序清理。扩展级设置统一由 `preferences.addon_preferences()` 读取;`runtime.py` 只消费 `configured_storage_root` 回调,不持有 Blender 偏好设置的定位逻辑。交互中的临时状态和 Debug 参数保存在 `Scene.anyimage_settings`,Upscale 的原图引用保存在 `Image.anyimage_upscale_source`。 全局 `max_ai_input_size` 也在 `preferences.py` 定义与读取,由 Operator 冻结到每次 Job 请求。
`__init__.py` 按依赖顺序注册,并在注销时逆序清理。扩展级设置统一由 `preferences.addon_preferences()` 读取;`runtime.py` 只消费 `configured_storage_root` 回调,不持有 Blender 偏好设置的定位逻辑。交互中的临时状态和 Debug 参数保存在 `Scene.anyimage_settings`。全局 `max_ai_input_size` 在 `preferences.py` 定义与读取,由 Operator 冻结到每次 Job 请求;Upscale 还用它判断当前 Image 是否允许执行。
## 同步与异步路径
@@ -60,6 +60,10 @@ sequenceDiagram
这条边界也决定了模块依赖方向:`server/` 不导入 `bpy` 或 `operators/`;Blender 侧可以读取 Server 产物,但不会复用 Server 中的 Blender 无关算法来创建 RNA 数据。
## 共享能力
## 共享能力 { #shared-capabilities }
`operators/common/` 保存多个功能真实复用的能力:图片输入与命名、像素写回、手势状态、Mask 运算、Image Empty 坐标、材质、节点资产、法线烘焙和 Job 参数辅助。共享模块只承载跨功能概念;完整工作流仍留在各自功能包中,以便从用户入口追踪到实现。
`operators/common/` 只保存多个生产功能真实复用的稳定原子能力;完整工作流、功能参数和专用算法留在所属模块。公共层不保留旧路径转发函数,也不为了测试或资产工具建立入口。
全部可由功能模块调用的函数见[Common 公共函数](common.md)。该索引只列 `common/` 外部的生产调用,不重复列出公共模块内部辅助函数;创建新功能前先核对该页,避免重新实现 Image 引用分流、像素方向、Job 输入生命周期、数据块命名、节点资产加载和对象激活逻辑。
新增公共函数前应确认至少有两个真实消费者,或它是两个公共流程共同依赖的原子能力。只有单一功能使用的逻辑应留在所属模块;删除或移动能力时同步清理注册、测试、工具脚本和文档,不保留兼容胶水。

102
docs/internals/common.md Normal file
View File

@@ -0,0 +1,102 @@
# Common 公共函数
`src/anyimage/operators/common/` 集中已经被多个功能复用的 Blender 侧原子能力,目的是让开发新功能时能够先查找并复用现有实现,避免重复造轮子。
本页只列功能模块直接调用的公共函数,不列 `common/` 内部辅助函数、测试或资产工具专用函数,也不列公共类型。
## Image 数据块
`image_data.py` 处理 Blender `Image` 数据块及其在 Image Empty 上的使用方式,包括像素读取、动画帧、Job 输入、结果 Image 创建和 Empty 引用替换。它不处理 Viewport 手势或选区算法。
| 函数 | 职责 |
| --- | --- |
| `image_data.is_image_empty()` | 判断对象是否为带有效 Image 数据的 Empty。 |
| `image_data.require_image_empty()` | 按名称取得 Image Empty;对象已失效时抛错。 |
| `image_data.image_pixels()` | 以 Blender 原始顺序读取一维 float32 像素。 |
| `image_data.image_rgba()` | 读取为 Top-down RGBA float32 数组。 |
| `image_data.video_total_frames()` | 返回 Movie 或 Sequence 总帧数,静态图返回 1。 |
| `image_data.image_user_settings()` | 读取 Image Empty 的帧起点、偏移、时长和循环设置。 |
| `image_data.default_extract_frames()` | 取得当前 Empty 默认应处理的帧数。 |
| `image_data.source_start_frame()` | 从源 Image Empty 取得 Job 应处理的起始帧。 |
| `image_data.prepare_image_input()` | 将 Packed、Dirty、Sequence 等输入准备为 Job 可读路径,并返回临时标记。 |
| `image_data.prepare_region_input()` | 将 `RegionMask` 裁切为带 Mask Alpha 的临时 RGBA Job 输入。 |
| `image_data.cleanup_image_input()` | 按临时标记清理由 `prepare_image_input()` 创建的文件或目录。 |
| `image_data.image_base_name()` | 去除图片或视频扩展名和 Blender 数字后缀,得到数据块基础名。 |
| `image_data.depth_data_name()` | 生成 Depth 结果数据块文件名。 |
| `image_data.color_data_name()` | 生成 Color 结果数据块文件名。 |
| `image_data.load_color_result_image()` | 加载、命名、Pack 并配置 Job 的 Color 或 Sequence 结果;不修改 Empty。 |
| `image_data.load_normal_result_image()` | 加载、命名、设为 Non-Color 并 Pack Normal 结果。 |
| `image_data.create_pixel_result_image()` | 从本地编辑后的 RGBA 像素创建 Packed Image;不修改 Empty。 |
| `image_data.replace_empty_image()` | 执行 Image Empty 结果替换、共享引用分流、旧数据清理、帧设置继承和可选画布对齐。 |
| `image_data.image_empty_bounds()` | 计算 Image Empty 在对象局部坐标中的实际显示边界。 |
`load_*_result_image()` 和 `create_pixel_result_image()` 只创建结果 Image;`replace_empty_image()` 负责把结果提交给当前 Empty。两者分别表达“创建产物”和“替换引用”。
## Image Region 与视图交互
这组公共能力使用固定术语:
- Region 是用户在图片空间圈定的业务范围;`RegionPath` 保存路径点、反选状态和填充规则。
- `RegionMask` 是 Region 的栅格化结果,只包含局部像素权重 `values` 和源图 `bounds`。
- Mask 只表示二维像素权重或 Alpha 运算,不作为手势、协议或业务范围的别名。
- Selection 只用于 Blender 对象选择和界面动作 Refine Selection,不表示中间数据。
`image_interaction.py` 处理 3D Viewport 中的点击、坐标投影、`ImageRegionGesture`、工具设置和预览绘制;`image_region.py` 负责图片空间 Region 的值、栅格化和 Alpha 裁切。前者负责用户如何圈定 Region,后者负责 Region 如何变成 Mask。
### Viewport 交互
| 函数 | 职责 |
| --- | --- |
| `image_interaction.report_image_edit_exception()` | 将可预期的图片编辑警告和异常映射为 Operator Report。 |
| `image_interaction.image_edit_poll()` | 判断当前上下文是否允许启动 Image 编辑工具。 |
| `image_interaction.resolve_image_edit_click()` | 解析点击到 Image Empty,并保持或恢复选择状态。 |
| `image_interaction.active_view3d_tool_id()` | 取得当前 View3D Workspace Tool ID。 |
| `image_interaction.apply_region_settings()` | 将当前 Region 工具的 Refine 设置同步到手势 Operator。 |
| `image_interaction.draw_region_settings()` | 绘制 Region 工具的公共 Refine 设置。 |
| `image_interaction.draw_dashed_line()` | 绘制手势或透视框虚线。 |
| `image_interaction.draw_polygon_fill()` | 绘制手势或透视框填充预览。 |
| `image_interaction.gesture_property()` | 声明统一的 Box、Lasso、Line 和 Polyline RNA 属性。 |
| `image_interaction.screen_path_to_image_pixels()` | 将屏幕路径投影为 Image Empty 像素坐标。 |
| `image_interaction.serialize_matrix()` | 将 4×4 Matrix 序列化为 Operator 可保存的字符串。 |
| `image_interaction.deserialize_matrix()` | 恢复已序列化的 4×4 Matrix。 |
| `image_interaction.drawing_in_region()` | 判断 Modal 绘制是否仍位于启动时的 Area 和 Region。 |
### Region 栅格化
| 函数 | 职责 |
| --- | --- |
| `image_region.region_path_bounds()` | 校验 Region Path 并返回整数像素包围框。 |
| `image_region.rasterize_region_path()` | 把 `RegionPath` 栅格化为 `RegionMask`,并可与源 Alpha 相交。 |
| `image_region.crop_pixels_to_alpha()` | 按 Alpha 非零区域紧裁切 RGBA 像素。 |
## Mesh 结果构建
`mesh_result.py` 集中 Convert to Plane 与 Cutout 共同使用的结果构建能力:读取图片几何产物、创建材质、加载节点资产、设置修改器输入,并完成结果对象替换。
`ImageGeometry` 表示按图片像素组织的三维点、相机内参、有效区域、参考深度和选区统计;`load_image_geometry()` 从 `image_geometry.npz` 读取并校验这组数据。
| 函数 | 职责 |
| --- | --- |
| `mesh_result.load_image_geometry()` | 读取并校验 `image_geometry.npz`,返回用于构建 Mesh 的 `ImageGeometry`。 |
| `mesh_result.create_image_material()` | 从 Image Empty 创建包含颜色、位移、Normal、Alpha 和动画设置的完整材质。 |
| `mesh_result.load_asset_node_group()` | 从随扩展分发的 Blend 资产加载指定 Node Group。 |
| `mesh_result.modifier_input_identifier()` | 按接口名称解析 Geometry Nodes Modifier 输入 Identifier。 |
| `mesh_result.set_modifier_input()` | 跨受支持 Blender RNA 形式设置 Modifier 输入。 |
| `mesh_result.finalize_object_result()` | 激活结果对象,并按需替换或保留源 Empty。 |
节点资产构建和验证专用函数位于 `tools/node_assets/`,不属于运行时公共能力。
## AI 任务准备
`ai_job.py` 处理多个 AI 功能共同使用的任务准备,包括输入路径校验、Environment 与模型检查、Device 选择,以及 DA3 和 MoGe-2 请求参数组装。它不包含业务 Operator、结果导入或 Undo 操作。
| 函数 | 职责 |
| --- | --- |
| `ai_job.require_input_path()` | 解析 Blender 路径并要求其为现存文件或目录。 |
| `ai_job.require_background_input_path()` | 在通用路径校验之外限制 BEN2 支持的媒体类型。 |
| `ai_job.production_device()` | 读取正式任务使用的计算设备。 |
| `ai_job.require_environment()` | 要求 AnyImage AI Environment 已就绪。 |
| `ai_job.invoke_ai_setup_if_needed()` | Environment 未就绪时启动安装交互。 |
| `ai_job.require_model()` | 校验模型标识和下载状态,并返回模型记录。 |
| `ai_job.da3_parameters()` | 组装 DA3 正式任务与 Debug 共用参数。 |
| `ai_job.moge2_parameters()` | 组装 MoGe-2 正式任务与 Debug 共用参数。 |

View File

@@ -39,10 +39,11 @@ flowchart TD
## 文档分层
- [程序架构](architecture.md):注册、配置、线程和模块边界。
- [Common 公共函数](common.md):仅列生产功能从 `operators/common/` 外部调用的函数。
- [Job Runtime 与 Server](runtime.md):任务生命周期、媒体输入和模型 Session。
- [Operator 实现索引](operators/index.md):按 `src/anyimage/operators/` 中的完整功能拆分实现页。
- [Job 产物](outputs.md):文件用途和 Blender 导入关系。
- [开发与发布](development.md):本地环境、测试、打包和 CI。
- [节点资产](node-assets.md):Geometry Nodes 的构建、加载与验证。
内部实现文档描述模块之间的职责和主要数据流。函数级分支、参数校验与异常处理以源码和测试为准,避免文档重复实现细节。
内部实现文档描述模块之间的职责和主要数据流。[Common 公共函数](common.md)按真实外部调用列出开发新功能时应优先复用的稳定入口;函数级分支、参数校验与异常处理仍以源码和测试为准。

View File

@@ -7,12 +7,12 @@ AnyImage 将稳定、可复用的 Geometry Nodes 和 Shader 节点组构建到 `
```text
src/anyimage/
├── assets/O_AnyImage.blend
└── operators/common/
├── node_asset.py # 资产路径、加载与 Modifier 输入
└── node_graph.py # 共享节点图构造函数
├── operators/common/mesh_result.py # 运行时资产加载与 Modifier 输入
└── operators/convert_to_plane/nodes.py # Depth Plane 运行时节点图
tools/node_assets/
├── build.py # 统一构建入口
├── node_graph.py # Cutout 资产构建专用节点图函数
├── build_mesh_plane.py
├── build_shadeless.py
├── build_cutout.py
@@ -27,7 +27,7 @@ tools/node_assets/
flowchart TD
Scripts["tools/node_assets/build_*.py"] --> Build["Blender 后台构建"]
Build --> Blend["assets/O_AnyImage.blend"]
Blend --> Loader["operators/common/node_asset.py"]
Blend --> Loader["operators/common/mesh_result.py"]
Loader --> Modifier["运行时 Node Group / Modifier"]
```

View File

@@ -1,6 +1,6 @@
# Plane 转换
Plane 转换包含两条路径:普通 Plane 在 Blender 内同步完成;Depth Plane 先通过 `prepare-geometry-data` Job 取得深度场,再回到 Blender 构建面片。两者共享图片命名、材质与基础四边形能力,但使用不同的 Geometry Nodes。
Plane 转换包含两条路径:普通 Plane 在 Blender 内同步完成;Depth Plane 先通过 `generate-depth-plane` Job 取得深度场,再回到 Blender 构建面片。两者共享图片命名、材质与基础四边形能力,但使用不同的 Geometry Nodes。
## 对应文件
@@ -13,7 +13,8 @@ operators/convert_to_plane/
└── nodes.py # 运行时 O Image Depth Plane 节点图
server/
├── jobs/prepare_geometry_data.py
├── jobs/generate_depth_plane.py
├── geometry/generate_depth.py
├── models/da3.py
├── models/moge2.py
└── geometry/projection.py
@@ -27,8 +28,8 @@ flowchart TD
Kind -- "Plane" --> Copy["复制 Image 与材质"]
Copy --> Quad["创建四边形 + O Mesh Plane"]
Kind -- "Depth Plane" --> Input["准备颜色与分析输入"]
Input --> Job["prepare-geometry-data"]
Job --> Field["image.0001 + field.npz"]
Input --> Job["generate-depth-plane"]
Job --> Field["image.0001 + image_geometry.npz"]
Field --> Anchor["按 Empty 范围锚定相机点"]
Anchor --> Depth["创建深度 Image + 材质 + 节点修改器"]
Quad --> Replace["替换源 Empty"]
@@ -45,7 +46,7 @@ flowchart TD
`ConvertToDepthPlane` 当前只接受静态图片。深度模型和分辨率来自扩展 Preferences:MoGe-2 使用 Resolution Level,DA3 使用按原图尺寸换算并对齐到模型 Patch 的处理分辨率。
`GenerateDepthPlane` 把颜色输入、分析输入和模型参数提交给 `prepare-geometry-data`。Server 将模型结果统一为 `GeometryFrame`,写出包含相机点、深度、内参、有效区域和参考深度的 `field.npz`。这一步不创建网格。 `max_input_size` 同时传入 Job;Server 通过 `media/resolution.py` 在模型推理前限制分析图长边,默认 `2048`。颜色输入仍由未缩放的原图复制,受限分析图不会成为材质 Color。
`GenerateDepthPlane` 把当前 Image 随模型参数提交给 `generate-depth-plane`。`jobs/generate_depth_plane.py` 负责单图协议,`geometry/generate_depth.py` 负责 AI 深度生成;Server 将模型结果统一为 `GeometryFrame`,写出包含相机点、深度、内参、有效区域和参考深度的 `image_geometry.npz`。Blender 侧通过公共 `load_image_geometry()` 读取为 `ImageGeometry`,与 Cutout 使用同一协议校验。这一步不创建网格。`max_input_size` 同时传入 Job;Server 通过 `media/resolution.py` 在模型推理前限制分析图长边,默认 `2048`。颜色输入仍按当前 Image 的未缩放分辨率复制,受限分析图不会成为材质 Color。
Blender 响应阶段执行三件事:
@@ -56,3 +57,5 @@ Blender 响应阶段执行三件事:
Depth 节点组先复用 `O Mesh Plane` 完成细分与材质,再生成背面厚度、限制正面向内穿透,最后在 Thickness 为零时删除背面和侧面。`Depth Amount` 控制位移强度;`Depth Image` 与 `Material` 是由插件填入的内部输入。
与 Cutout 的 Depth Surface 不同,Depth Plane 只使用锚定后的 Z 高度,不在 Geometry Nodes 中重建完整相机空间 XYZ。它强调一张图上的可编辑浮雕,而不是局部透视表面。
颜色材质、Normal 导入和结果对象激活分别复用 `create_image_material()`、`load_normal_result_image()` 与 `finalize_object_result()`;普通 Plane 和 Depth Plane 不再各自维护对象替换步骤。

View File

@@ -1,80 +1,76 @@
# Cutout
# Cutout Tool
Cutout 从一条图片空间套索生成规则三角基础面,再交给统一的 `O Image Cutout` Geometry Nodes 修改器形成 Surface、Balloon、Depth Balloon 或 Depth Surface。公开节点组用 Shape 菜单路由到四个原有内部节点组;轮廓和 Mesh 始终由 Blender 主线程创建,Server 只在需要时准备 Refine、深度或法线数据。
Cutout 由两个核心 Operator 组成:
## 对应文件
- `SelectCutoutRegion`(`select_region.py`)把 Viewport 手势转换为图片空间 Region,并弹出 Shape 菜单。
- `CutoutRegionToShape`(`region_to_shape.py`)准备所需数据,再构建并创建 Shape。
```text
operators/cutout_tool/
├── selection_tool.py # 套索交互、设置与 Shape 饼菜单
├── shape_conversion.py # 本地 / Job 路径选择和任务参数
├── build_shapes.py # 裁切贴图、Mesh、材质与修改器
├── shape_types.py # Shape 与节点组映射
├── mask_regions.py # Alpha 外轮廓与孔洞
├── planar_mesh.py # 规则采样与约束三角化
├── balloon_profile.py # Poisson / Teddy profile
├── depth_calibration.py # Reference 与 Direction
└── node_assets.py # Cutout 节点资产加载
路径约定:Blender 侧文件相对 `src/anyimage/operators/cutout_tool/`,Server 侧文件相对 `src/anyimage/server/`。
server/
├── jobs/prepare_geometry_data.py # Cutout / Depth Plane 数据编排
├── selection/
│ ├── polygon_mask.py # Polygon 栅格化与选区裁切
│ └── cutout_images.py # Refine 与 Cutout 局部图片
└── geometry/normal_texture.py # 相机轴法线编码
```
## 路径选择
## 执行路径
```mermaid
flowchart TD
Lasso["套索 + Shape"] --> Refine{"Refine Selection?"}
Refine -- "是" --> Ben2["BEN2 × 1"]
Refine -- "否" --> Selection["套索 Selection"]
Ben2 --> Selection
Selection --> NeedMoge{"需要 Depth 或 Normal?"}
NeedMoge -- "否" --> Mesh["轮廓 → 规则点 → 约束三角化"]
NeedMoge -- "是" --> Moge["MoGe-2 × 1\\n同一 Prediction"]
Moge --> Data["Depth Field / Camera Normal"]
Data --> Mesh
Mesh --> Profile["计算 o_balloon"]
Profile --> Nodes["加载 O Image Cutout 并设置 Shape"]
Nodes --> Bake["按需烘焙最终 Tangent Normal"]
Select["圈定 Cutout Region<br/>选择 Shape"]
Raster["栅格化 Region"]
Route{"需要 AI 数据?"}
Local["使用本地 Region 数据"]
AI["生成 Refine / Depth / Normal"]
Ready["汇总 Shape 输入"]
Build["构建基础 Shape"]
Create["创建 Blender 对象"]
Select --> Raster
Raster --> Route
Route -- "否" --> Local --> Ready
Route -- "是" --> AI --> Ready
Ready --> Build --> Create
```
Cutout 只接受静态图片。Refine Selection 是网格生成前唯一可选的选区分析:开启时执行一次 BEN2,关闭时直接使用套索 Selection。Surface 与 Balloon 在不需要 Normal 时不运行 MoGe-2;两个 Depth Shape 和任意开启 Normal 的 Shape 都统一使用 MoGe-2。Depth 与 Normal 同时启用时只执行一次推理,同一个 Prediction 同时提供相机点、深度和图片空间法线。
## 节点说明
Cutout 不使用 DA3。若全局 Depth Model 当前选择 DA3,Cutout 会回退到默认 MoGe-2;选择 MoGe-2 档位时则沿用该档位和 Resolution Level。DA3 仍可用于独立的 Depth Plane 流程。
### 圈定 Cutout Region
## 选择与局部数据
`SelectCutoutRegion` 将 Lasso 路径投射到图片像素坐标,形成 `RegionPath`,然后把 Region 和用户选择的 Shape 交给 `CutoutRegionToShape`。双击图片时,Region 使用完整图片范围。
Cutout 复用 `ImageMaskGesture` 的采点和屏幕预览,并复用 `operators/common/image_mask.py` 的可见选区语义:最终几何范围始终是套索、图片边界与源图 `Alpha > 0.1` 区域的交集。套索采用 NONZERO 填充规则,使反向内环可以表达孔洞。`Point Spacing` 先根据完整源图最长边换算为基础 `mesh_detail`;获得裁切 Selection 后,再按 `min(1, max_input_size / crop_long_edge)` 缩放有效 `mesh_detail`。因此只有裁切图超过全局上限时网格才会变稀,Color Image 仍使用原始裁切尺寸。
`RegionPath` 定义在 `operators/common/image_region.py`,包含图片空间路径点、反选状态和填充规则。它既供 Cutout 使用,也供 Image Tool 使用。
Job 路径将数据拆成三层:源颜色、最终选择和只供模型分析的 RGBA。写出最终选择前会再次以 `Alpha > 0.1` 与源图求交,因此未 Refine、Refine 和双击全图遵循相同边界。`bounds.json` 把可见选区的局部矩形映射回源图,Blender 据此恢复局部平面范围和 UV。未走 Job 时,`build_shapes.py` 在内存中完成相同的求交、裁切与坐标换算。
### 栅格化 Region
## 基础网格
`CutoutRegionToShape` 把 `RegionPath` 栅格化为 `RegionMask`。`RegionMask` 只包含局部像素权重 `values` 和它在源图中的 `bounds`,后续几何、颜色裁切和 AI 输入都以它为范围。
最终 Alpha 先转为带包含关系的外轮廓与孔洞。`planar_mesh.py` 在内部生成近似六角排列的规则点,并用轮廓作为约束进行 Delaunay 三角化。边界按目标间距重采样,短轮廓会提高边界采样密度,内部点仍保持用户设置的间距。
Surface 或 Balloon 在未启用 Refine 与 Normal 时直接使用本地 Region 数据;选择 Depth Shape,或启用 Refine、Normal 时进入 AI 路径。两条路径最终都调用 `region_to_shape()`。
四种 Shape 共享同一张单面基础网格、UV 和 `o_balloon` 点属性。创建阶段以目标 Point Spacing 的平方作为一个采样单元面积,再除以 Image Empty 图片平面从局部到世界的面积缩放,得到修改器局部坐标中的 Cleanup 阈值。这个值只取决于工具分辨率和图片尺寸/变换,不受碎片数量或碎面面积分布影响。Balloon Profile 由 Preferences 选择 Poisson 或 Teddy;节点组只消费计算后的属性,不再重复推导轮廓。
### 生成 AI 数据
## 统一修改器与四种 Shape
`generate-region-data` Job(`jobs/generate_region_data.py`)根据请求生成所需数据:
创建结果时始终添加 `O Image Cutout`,并按饼菜单选择写入 Shape。节点组先统一执行 Cleanup,再由 Menu Switch 仅求值当前 Shape 的内部节点组,最后统一执行 Smooth;因此四种 Shape 都可使用 Cleanup、Smooth 和 Smooth Iterations。各分支独有输入直接连接到对应内部组,Blender 4.5 会在修改器中隐藏当前 Shape 不使用的输入。Cleanup 直接比较 Mesh Island 总面积与创建时写入的绝对面积阈值,不再统计当前网格面的中位面积。
- `generate_selection()`(`region/generate_selection.py`)使用 BEN2 收紧 Region;
- `generate_depth(..., normal_mode=...)`(`geometry/generate_depth.py`)使用 MoGe-2 生成 Depth,并可从同一次 Prediction 派生 Tangent 或 Object Normal。
| Shape | 内部节点组 | 主要几何来源 |
Blender 传入的已是带 Region Alpha 的局部 RGBA。Depth 与 Normal 同时启用时只运行一次 MoGe-2,颜色贴图仍使用 Region 的原始裁切分辨率。
### 构建基础 Shape
`region_to_shape()` 汇总 Region、Depth 和 Normal 输入,再依次执行几何构建与 Blender 数据创建。
`build_base_shape()` 从 `RegionMask` 构建纯内存 `BaseShape`:先由 `region_contours.py` 提取包含外轮廓与孔洞的 `RegionContours`,再由 `triangulation.py` 按 Point Spacing 采样并约束三角化,最后使用 `balloon.py` 计算 `o_balloon`。`depth_calibration.py` 负责把 AI Depth 标定为 Blender 中使用的深度基准与方向。四种 Shape 共用这张单面基础网格。
### 创建 Blender 对象
`create_shape_object()` 创建裁切后的 Color Image、Material、Mesh Object 和统一的 `O Image Cutout` Modifier。Shape 的差异由 Modifier 中对应的几何分支表达:
| Shape | 形成方式 | Shape 自身所需 AI 数据 |
| --- | --- | --- |
| Surface | `O Image Surface` | 基础薄片与可调 Thickness |
| Balloon | `O Image Balloon` | `o_balloon` 鼓起高度 |
| Depth Balloon | `O Image Depth Balloon` | Balloon profile + 相对基准面的非负深度高度 |
| Depth Surface | `O Image Depth Surface` | MoGe-2 相机点的完整投影 |
| Surface | 保持基础 Shape 的平面轮廓,并可增加真实厚度 | 无 |
| Balloon | 使用 `o_balloon` 从轮廓向内部平滑鼓起 | 无 |
| Depth Balloon | 在 Balloon 上叠加相对基准面的图片深度,并沿 Depth Direction 形成浮雕 | MoGe-2 Depth |
| Depth Surface | 使用完整相机点 XYZ 重建带透视位移的表面,并可增加厚度 | MoGe-2 Camera Points |
四个内部节点组不再标记为 Modifier,也不再各自执行 Cleanup。原本只在 `O Image Depth Surface` 内的 Smooth 后处理已移到公开节点组;统一节点组的 Smooth 默认值为 `1`;外层 `Smooth Iterations` 默认值为 `0`,只有用户增加迭代次数后才执行平滑。两个 Depth 内部节点组也统一使用 `Reference Depth`,总节点组只暴露一个共用输入。
四种 Shape 共用 Region、基础三角面、UV、材质、Cleanup 和 Smooth。Cleanup 的 UI 数值放大 `100` 倍,节点内部乘以 `0.01` 还原,因此显示尺度不会改变实际清理阈值。
两个 Depth 形状把相机点 RGB 写入 Packed 浮点 `_depth.exr`,并以隐藏的 `Uniform Scale` 匹配 Image Empty 尺寸。未启用 Refine 时 Reference 使用固定值,Depth Balloon Direction 使用默认轴向;启用 Refine 后,`calibration_valid` 限制在模型有效区域与最终选择的交集,Reference 使用其深度第 95 百分位,Depth Balloon 还拟合局部基准方向。
### Depth 与 Normal
Depth Balloon 保留图片平面 XY,只使用相机 Z 形成向外高度;Depth Surface 将完整 XYZ 映射到 Cutout 局部轴,因此能表达透视位移。两者都只采样深度 Image 的 RGB,Alpha 仅保存有效性和深度跳变信息。
Depth Shape 根据最终 Region Alpha 选择基准:透明像素比例达到 `5%` 时从有效内容自适应计算 Base Plane Depth;不足 `5%` 时使用固定基准。Depth Balloon 还会在自适应路径中拟合 Depth Direction。
## 法线空间
MoGe-2 在 Job 阶段输出图片空间的相机轴法线预测;这一步不依赖 Blender 网格。Depth Surface 在导入时将它重排到 Cutout 对象轴并以 Object Space 使用;Surface、Balloon 与 Depth Balloon 则先创建基础网格并完成 Geometry Nodes 求值,再根据成品网格 UV、法线和切线基底烘成 Tangent Space。也就是说,网格前产生的是模型 Prediction,最终法线贴图的空间转换仍发生在网格生成之后。
Normal 是材质层的浮雕细节,与四种 Shape 都可组合。None 使用几何法线;Tangent 以完整图片平面为切线基准;Object 直接编码到 Cutout 对象局部轴。Geometry Nodes 负责大轮廓和深度,Normal 负责表面细节。

View File

@@ -1,6 +1,6 @@
# Image Tool
`operators/image_tool/` 对应工具栏中的 Box、Lasso、Line 与 Polyline。四个 WorkspaceTool 共用一个 `EditImageMask` Operator,把屏幕手势转换为图片 Alpha;只有 Box 与 Lasso 可以用 BEN2 细化选择。
`operators/image_tool/` 对应工具栏中的 Box、Lasso、Line 与 Polyline。四个 WorkspaceTool 共用一个 `EditImageMask` Operator:手势先形成图片空间 Region,Region 栅格化为 Mask 后才修改图片 Alpha;只有 Box 与 Lasso 可以用 BEN2 执行 Refine Selection。
## 对应文件
@@ -20,20 +20,22 @@ operators/image_tool/
```mermaid
flowchart TD
Tool["Box / Lasso / Line / Polyline"] --> Gesture["ImageMaskGesture"]
Gesture --> Polygon["图片像素 Polygon"]
Polygon --> Refine{"Refine Selection?"}
Refine -- "否" --> Mask["本地几何 Mask"]
Refine -- "是" --> Job["refine-image-mask"]
Tool["Box / Lasso / Line / Polyline"] --> Gesture["ImageRegionGesture"]
Gesture --> Region["RegionPath"]
Region --> Raster["栅格化 Region"]
Raster --> Data["RegionMask"]
Data --> Refine{"Refine Selection?"}
Refine -- "否" --> Mask["Region Mask"]
Refine -- "是" --> Input["带 Region Alpha 的裁切 RGBA"]
Input --> Job["refine-image-mask"]
Job --> Mask
Mask --> Invert["可选反选"]
Invert --> Alpha["源 Alpha × 最终 Mask"]
Mask --> Alpha["源 Alpha × Mask"]
Alpha --> Crop["紧裁切并写回 Empty"]
```
`EditImageMask` 只接受静态图片。未启用 Refine 时,Polygon 在 Blender 侧直接栅格化;启用后,Operator 准备单图输入并提交 Job,响应阶段读取局部 Alpha 与源图 `bounds`,再映射回完整画布。反选始终在最终 Mask 上执行。
`EditImageMask` 只接受静态图片。`ImageRegionGesture` 把屏幕路径投射为 `RegionPath`;`rasterize_region_path()` 再生成 `RegionMask`。未启用 Refine 时直接把 Region Mask 乘入源 Alpha;启用后,Operator 将 `RegionMask` 写成局部 RGBA 并提交 Job,响应阶段读取细化后的 Alpha 与 `bounds`,再映射回完整画布。
Box 和 Lasso 分别保存自己的 Refine 状态。Line 与 Polyline 强制关闭 Refine,只使用几何 Mask;Line 将有向线扩展为半平面,Polyline 显式闭合用户确认的顶点。
Box 和 Lasso 分别保存自己的 Refine Selection 状态。Line 与 Polyline 强制关闭 Refine,只使用本地 Region Mask;Line 将有向线扩展为半平面 Path,Polyline 显式闭合用户确认的 Path。
## 手势与预览
@@ -43,4 +45,4 @@ Box 和 Lasso 分别保存自己的 Refine 状态。Line 与 Polyline 强制关
## 写回结果
最终像素保留源 RGB,只修改 Alpha,再按非零 Alpha 紧裁切。公共写回函数只替换当前 Empty 的 Image,并更新 `empty_display_size` 与 `empty_image_offset`,因此剩余像素继续对齐原图片平面,对象 `matrix_world` 不变。
最终像素通过公共 `image_pixels()` / `image_rgba()` 读取,保留源 RGB,只修改 Alpha,再按非零 Alpha 紧裁切。公共像素写回函数创建结果后,通过统一的 Image Empty 替换入口处理共享引用,并更新 `empty_display_size` 与 `empty_image_offset`,因此剩余像素继续对齐原图片平面,对象 `matrix_world` 不变。

View File

@@ -1,6 +1,6 @@
# Operator 实现索引
`src/anyimage/operators/` 负责 Blender 侧交互、Job 请求组装和结果导入。内部实现按完整功能包或顶层业务模块拆页;只提供共享能力的 `common/` 不单独成页,其职责统一放在[程序架构](../architecture.md)中说明。
`src/anyimage/operators/` 负责 Blender 侧交互、Job 请求组装和结果导入。内部实现按完整功能包或顶层业务模块拆页;`common/` 的边界见[程序架构](../architecture.md),实际公开入口见[Common 公共函数](../common.md)。
| Operator 路径 | 实现页 | 主要职责 |
| --- | --- | --- |
@@ -8,11 +8,11 @@
| `operators/ai_setup.py` | [AI 环境管理](ai-setup.md) | 环境安装、模型下载与缓存释放 |
| `operators/clipboard_image/` | [Clipboard Image](clipboard-image.md) | 系统剪贴板读取、粘贴与快捷键 |
| `operators/convert_to_plane/` | [Convert to Plane](convert-to-plane.md) | Mesh Plane 与 Depth Plane 创建 |
| `operators/cutout_tool/` | [Cutout Tool](cutout-tool.md) | 区域选择、轮廓生成与 Shape 构建 |
| `operators/cutout_tool/` | [Cutout Tool](cutout-tool.md) | Region 选择、基础 Shape 构建与 Blender 对象创建 |
| `operators/debug.py` | [Debug Operator](debug.md) | 模型接口与原始产物验证 |
| `operators/image_tool/` | [Image Tool](image-tool.md) | Box、Lasso、Line 与 Polyline 编辑 |
| `operators/perspective_tool/` | [Perspective Tool](perspective-tool.md) | 四点透视框与透视校正 |
| `operators/remove_background.py` | [Remove Background](remove-background.md) | BEN2 去背与结果替换 |
| `operators/upscale.py` | [Upscale](upscale.md) | 4× 高清与原图引用维护 |
| `operators/upscale.py` | [Upscale](upscale.md) | 当前 Image 的 4× 高清与输入长边检查 |
`operators/__init__.py` 只聚合注册类,不承载独立业务流程。具体类的注册和逆序注销由扩展入口统一管理,整体边界见[程序架构](../architecture.md)。

View File

@@ -10,7 +10,7 @@ operators/perspective_tool/
└── edit_perspective.py # 四点交互、预览、Homography 与写回
```
图片选择、裁切和 Empty 写回复用 `operators/common/` 的基础能力,不与 Image Mask Operator 共享业务状态。
图片坐标投射、Alpha 裁切和 Empty 写回复用 `operators/common/` 的基础能力;四点数据始终称为 Quad,不与 Image Region 或 Image Mask Operator 共享业务状态。
## 矫正流程
@@ -29,4 +29,4 @@ flowchart TD
Homography 使用预乘 Alpha 插值,避免透明边缘混入黑色。输出最长边限制为 8192 px,总像素限制为 16,777,216,并按 256 行分块计算,控制中间数组大小。
Perspective 是 deform 工具,不提供 Refine 或反选。结果比例可能不同于原四边形的轴对齐范围,因此 Empty 写回保持中心和覆盖尺度近似一致,而不是假设当前 3D View 相机等于图片拍摄相机。
Perspective 是 deform 工具,不提供 Refine 或反选。它通过公共 `image_pixels()` 读取供预览与最终 Warp 共用的源像素,并与 Image Mask 共用像素结果创建和 Image Empty 替换入口。结果比例可能不同于原四边形的轴对齐范围,因此 Empty 写回保持中心和覆盖尺度近似一致,而不是假设当前 3D View 相机等于图片拍摄相机。

View File

@@ -8,7 +8,7 @@
src/anyimage/
├── operators/
│ ├── remove_background.py # Blender 入口、任务参数与结果替换
│ └── common/image.py # 媒体输入准备与结果 Image 创建
│ └── common/image_data.py # 媒体输入准备与结果 Image 创建
└── server/
├── jobs/remove_background.py # 单图与多帧任务编排
└── models/ben2.py # BEN2 前景适配
@@ -28,4 +28,4 @@ flowchart TD
Packed 图片或内存中修改过的单图会先导出为临时输入;文件图片、视频和序列则沿用可读取的源路径。多帧输入由统一媒体层展开,结果保持连续帧命名,导入后继续沿用源 Image User 的帧起点、偏移与循环设置。
BEN2 推理前使用输入 Alpha 屏蔽透明区域,模型输出的前景 Alpha 再与源 Alpha 合成,RGB 保持为源图内容。响应阶段只替换当前 Empty 的 Image 数据;当旧 Image 没有其他用户和 Fake User 时,旧数据块会被清理并由结果继承名称。
BEN2 推理前使用输入 Alpha 屏蔽透明区域,模型输出的前景 Alpha 再与源 Alpha 合成,RGB 保持为源图内容。响应阶段通过公共 Image Empty 替换入口导入结果;当旧 Image 没有其他用户和 Fake User 时,旧数据块会被清理并由结果继承名称。

View File

@@ -1,6 +1,6 @@
# Upscale
本页对应 `src/anyimage/operators/upscale.py`。该模块读取扩展首选项中的模型与全局 AI 输入长边上限,提交 4× 高清任务,并维护高清结果到原始 Image 的引用。
本页对应 `src/anyimage/operators/upscale.py`。该模块读取扩展首选项中的模型与全局 AI 输入长边上限,检查当前 Image 是否可处理,再提交 4× 高清任务。
## 对应文件
@@ -8,7 +8,7 @@
src/anyimage/
├── operators/
│ ├── upscale.py # Blender 入口、任务参数与结果替换
│ └── common/image.py # 媒体输入准备与结果 Image 创建
│ └── common/image_data.py # 媒体输入准备与结果 Image 创建
└── server/
├── jobs/upscale.py # 单图与多帧任务编排
├── media/resolution.py # 共用长边限制与等比缩放
@@ -20,17 +20,18 @@ src/anyimage/
```mermaid
flowchart TD
Empty["Image Empty"] --> Source["解析原始 Image"]
Source --> Prepare["准备媒体输入"]
Empty["Image Empty"] --> Source["读取当前 Image"]
Source --> Gate{"当前长边小于全局上限?"}
Gate -- "否" --> Disabled["Upscale 置灰"]
Gate -- "是" --> Prepare["准备媒体输入"]
Prepare --> Job["upscale-image Job"]
Job --> Limit["按全局输入长边上限等比缩放"]
Limit --> RGB["分块执行 4× RGB 推理"]
Limit --> Alpha["独立缩放 Alpha"]
Job --> RGB["分块执行 4× RGB 推理"]
Job --> Alpha["独立缩放 Alpha"]
RGB --> Merge["合并 RGBA 结果"]
Alpha --> Merge
Merge --> Replace["导入并替换当前 Image"]
```
模型以 256×256 分块处理 RGB,并带入相邻上下文以减弱块边界;Alpha 按同一受限输入尺寸单独缩放,最后合并为 RGBA。`max_input_size` 来自全局 **Maximum AI Input Size**,默认 `2048`,只约束送入模型的长边;4× 输出长边因此默认为最多 `8192`。输入尺寸不超过上限时不会发生预缩放。
模型以 256×256 分块处理 RGB,并带入相邻上下文以减弱块边界;Alpha 不进入模型,使用 Lanczos 独立放大后合并为 RGBA。`max_input_size` 来自全局 **Maximum AI Input Size**,默认 `2048`。Operator 只允许当前 Image 长边小于该值时执行,因此正式流程不会预缩放输入,4× 输出长边小于上限的四倍。Server 仍保留相同上限作为任务边界。
结果以 `_upscale.png` 结尾,并通过 `Image.anyimage_upscale_source` 保存原图引用。再次对高清结果执行时,Operator 会从原图重新生成,而不是继续放大上一次输出。模型与全局输入上限在每次执行时从 Preferences 读取,再写入可序列化的隐藏属性交给 Job。Provider 资源错误会释放当前 Upscale Session,并提示降低全局输入上限或改用 CPU。
菜单根据当前尺寸只显示预计的 4× 结果尺寸。结果通过与 Remove Background、Image Mask 和 Perspective 相同的 Image Empty 替换入口处理:原 Image 没有其他用户且未启用 Fake User 时,移除旧数据并让结果沿用原名;存在其他用户时保留原 Image,并只让当前 Empty 使用独立结果。结果不增加 Upscale 专属后缀,也不保存来源引用。后续 Upscale 与 Depth Plane 都读取当前 Image。模型与全局输入上限在每次执行时从 Preferences 读取,再写入可序列化的隐藏属性交给 Job。Provider 资源错误会释放当前 Upscale Session,并提示降低全局输入上限或改用 CPU。

View File

@@ -21,16 +21,16 @@ flowchart TD
| Job | 主要文件 | 消费方 |
| --- | --- | --- |
| `remove-background` | `image.0001.png` 起 | 替换 Image Empty 的颜色数据 |
| `upscale-image` | `upscale.0001.png` 起 | 创建 `_upscale.png` Image 并记录原图引用 |
| `refine-image-mask` | `selection-input.png`、`image.png`、`bounds.json` | Image Box / Lasso 读取 Alpha 与原图坐标 |
| `prepare-geometry-data`:Depth Plane | `image.0001.*`、`field.npz` | 创建颜色图、深度图、材质和 Plane |
| `prepare-geometry-data`:Cutout | `image.0001.png`、`selection.png`、`analysis.png`、`bounds.json`,以及按形状生成的 `field.npz` / `normal.png` | Blender 主线程构建局部网格与贴图 |
| `upscale-image` | `upscale.0001.png` 起 | 按共享引用情况替换当前 Image Empty 的颜色数据,并沿用原 Image 命名语义 |
| `refine-image-mask` | `image.png`、`bounds.json` | Image Box / Lasso 读取细化 Alpha 与原图坐标 |
| `generate-depth-plane` | `image.0001.*`、`image_geometry.npz` | 创建颜色图、深度图、材质和 Plane |
| `generate-region-data` | 可选的 `region.png`、`region_bounds.json`、`image_geometry.npz`、`normal.png` | Blender 主线程构建 Cutout Shape 与贴图 |
`prepare-geometry-data` 不输出 Blender 网格。它只准备颜色、选区和模型数组;轮廓提取、约束三角化、Geometry Nodes Modifier 与法线烘焙都在 Blender 响应阶段完成。
两个几何 Job 都不输出 Blender 网格。`generate-depth-plane` 生成完整图片的颜色副本与深度场;`generate-region-data` 只生成请求的 AI 产物。轮廓提取、约束三角化以及 Mesh、Material 和 Geometry Nodes 创建都在 Blender 主线程完成。
## 深度场
`field.npz` 是 Depth Plane、Depth Balloon 与 Depth Surface 共用的模型中间结果:
`image_geometry.npz` 是 Depth Plane、Depth Balloon 与 Depth Surface 共用的模型中间结果。Blender 侧统一通过 `operators/common/mesh_result.py` 的 `load_image_geometry()` 读取为 `ImageGeometry`,功能模块不分别解释字段:
| 字段 | 含义 |
| --- | --- |
@@ -38,21 +38,21 @@ flowchart TD
| `depth` | 相机深度 |
| `intrinsics` | 像素坐标下的 3×3 相机内参 |
| `valid` | 模型与数值检查后的有效区域 |
| `calibration_valid` | 用于结果定位或深度基准的区域;Cutout 时与选择相交 |
| `calibration_valid` | 用于结果定位或深度基准的区域;Cutout 时与 Region 相交 |
| `image_size` | 深度场宽高 |
| `reference_depth` | 校准区域中的参考深度 |
Server 保留模型空间数据,不提前换算 Blender 单位。Depth Plane 在导入时根据 Image Empty 平面范围和相机内参锚定点场;Cutout 深度形状则计算 `Uniform Scale` 和局部坐标,再把相机点写入 Packed 浮点 Image 供 Geometry Nodes 采样。
## Cutout 三类图片
## Cutout Region 产物
Cutout 把“显示内容”“几何范围”和“模型分析”分开:
Blender 侧先把 `RegionPath` 栅格化为 `RegionMask`,再将 Region 裁切为带有效 Alpha 的临时 RGBA 输入。Server 不接收路径或 Mask 协议,只按需产生 AI 数据:
- `image.0001.png` 保存裁切矩形中的源颜色与原 Alpha,用作材质。
- `selection.png` 保存最终选择 Alpha,用于轮廓与网格。
- `analysis.png` 只保留选择内的有效 RGBA,供深度或法线模型分析。
- 启用 Refine 时,`region.png` 保存细化后的局部 RGBA,`region_bounds.json` 保存它在输入裁切图中的范围;
- Depth Shape 使用 `image_geometry.npz`;
- Tangent 或 Object Normal 使用 `normal.png`。
`bounds.json` 把裁切矩形映射回源图像素坐标。这样 Server 可以只处理局部数据,Blender 仍能恢复局部平面范围、UV 和世界位置。
Blender 将局部范围与原始 `RegionMask.bounds` 合成回源图坐标,并直接从源 Image 创建最终 Color Image。未启用 Refine、Depth 或 Normal 时不提交 Job。
## Debug 产物
@@ -65,7 +65,7 @@ Debug Job 保留模型适配层的直接输出,不执行正式功能的 Blende
| `debug-ben2` | `foreground*.png` |
| `debug-upscale` | `prediction*.png` |
这些文件用于验证模型、Device 和适配层。正式 Job 会继续派生选择、Alpha、深度场或可导入图片,因此两者的文件结构有意不同。
这些文件用于验证模型、Device 和适配层。正式 Job 会继续派生 Region、Alpha、深度场或可导入图片,因此两者的文件结构有意不同。
## 单图与序列

View File

@@ -14,7 +14,7 @@ src/anyimage/
├── model_manager.py # 模型目录与 Session 缓存
├── media/input.py # 图片、视频和序列输入
├── jobs/ # app.py 可提交的公开任务
├── selection/ # 选区栅格化与 Cutout 图片准备
├── region/ # BEN2 Region 细化
├── models/ # 模型适配与 ONNX 推理
├── geometry/ # 深度反投影与法线纹理编码
└── outputs/ # Debug Prediction 序列化
@@ -41,17 +41,18 @@ Runtime 在首次任务或显式启动时拉起 Server。任务在队列中串
| `download-model`、`download-required-models` | 准备模型文件 |
| `remove-background` | BEN2 透明前景 |
| `upscale-image` | 4× 图片或帧序列 |
| `refine-image-mask` | 为 Image Box / Lasso 细化选区 |
| `prepare-geometry-data` | 为 Depth Plane 或 Cutout 准备颜色、选区、深度和法线数据 |
| `refine-image-mask` | 为 Image Box / Lasso 细化 Region |
| `generate-depth-plane` | 为 Depth Plane 生成颜色副本与深度场 |
| `generate-region-data` | 按需为 Cutout Region 生成 Refine、Depth 或 Normal |
| `debug-*` | 保存模型适配层的直接输出 |
## 媒体输入
`server/media/input.py` 把单图、视频和图片目录统一为有序帧路径,并用上下文管理器负责临时帧目录的生命周期。它还支持将颜色输入与分析输入分开:例如 Upscale 结果可以作为颜色来源,同时使用它保存的原图引用进行 Depth Plane 分析。帧展开是媒体输入的内部能力,不再暴露没有业务消费者的独立 Job。 `server/media/resolution.py` 提供默认 `2048` 的共用输入长边限制;Upscale 直接限制每帧,`prepare-geometry-data` 则在 Cutout 裁切和分析输入选择完成后限制 Depth / Normal 模型输入。该临时缩放图不参与颜色产物写入。
`server/media/input.py` 把单图、视频和图片目录统一为有序帧路径,并用上下文管理器负责临时帧目录的生命周期。帧展开是媒体输入的内部能力,不再暴露没有业务消费者的独立 Job。`server/media/resolution.py` 提供默认 `2048` 的共用输入长边限制;Upscale Operator 只允许长边小于该值的当前 Image 进入正式任务,Depth Plane 与 Cutout 则只限制模型分析输入,不降低颜色贴图分辨率。
当前 `prepare-geometry-data` 只接受一帧,因此 Depth Plane 与 Cutout 都是静态图工作流。Remove Background 与 Upscale 通过同一媒体入口处理单图、视频和序列帧。
`generate-depth-plane` 与 `generate-region-data` 只接受一帧,因此 Depth Plane 与 Cutout 都是静态图工作流。Remove Background 与 Upscale 通过同一媒体入口处理单图、视频和序列帧。
公开 Job 不与 Operator 一一对应:Depth Plane 和 Cutout 共享 `prepare-geometry-data`,四个 Debug Job 共享 `jobs/debug_predictions.py`。Job 只负责协议和编排;可复用的输入、选区、模型与几何数据能力分别位于 `media/`、`selection/`、`models/` 和 `geometry/`,Job 之间不互相导入实现。
公开 Job 按稳定的计算边界划分,不按界面入口机械映射。Depth Plane 使用 `jobs/generate_depth_plane.py`,Cutout 使用 `jobs/generate_region_data.py`,四个 Debug Job 共享 `jobs/debug_predictions.py`。Job 只负责协议和编排;可复用的输入、AI Region、模型与几何数据能力分别位于 `media/`、`region/`、`models/` 和 `geometry/`,Job 之间不互相导入实现。
## 模型层

View File

@@ -34,11 +34,11 @@ Cutout 提供四种结果:
| Depth Balloon | `O Image Depth Balloon` | MoGe-2 高度 |
| Depth Surface | `O Image Depth Surface` | MoGe-2 相机点 |
四种 Shape 共用 `O Image Cutout` 修改器、规则三角基础面、UV 和 `o_balloon` 属性。Shape 菜单选择内部几何分支,Cleanup 在分支前执行,Smooth 在分支后执行;Point Spacing 控制网格密度,Normal 与 Refine Selection 按需启用 MoGe-2 和 BEN2。
四种 Shape 共用 `O Image Cutout` 修改器、规则三角基础面、UV 和 `o_balloon` 属性。Shape 菜单选择内部几何分支,Cleanup 在分支前执行且使用便于调节的百倍显示值,Smooth 在分支后执行;Depth Shape 根据 Region 透明比例选择固定或自适应 Base Plane Depth,Normal 可选 None、Tangent 或 Object,Refine Selection 按需启用 BEN2。
### 图片结果
Image Mask 和 Perspective 直接更新当前 Empty 的图片并 Pack。Remove Background 输出透明颜色图或序列。Upscale 通过三档 ONNX 模型输出 4× RGBA,并保存原图引用,重复执行时从原图重新生成。
Image Mask 和 Perspective 直接更新当前 Empty 的图片并 Pack。Remove Background 输出透明颜色图或序列。Upscale 通过三档 ONNX 模型把当前 Image 输出为 4× RGBA;当前长边达到全局输入上限时不可执行。
## 模型