Initial public release
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2026-09-19 21:31:36 +08:00
commit 198fcbf55b
837 changed files with 67239 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
# 程序架构
| 模块 | 职责 |
| --- | --- |
| `__init__.py` | 注册类型、工具、菜单、快捷键与 Runtime |
| `menu.py`、`panel.py` | Image Empty 与 Shader Image Texture 上下文菜单与 Job Server 面板 |
| `preferences.py` | 扩展设置及读取入口 |
| `properties.py` | Scene 手势状态、模型状态查询、枚举与 Operator 属性构造 |
| `common/` | Blender 侧公共能力 |
| `operators/` | 交互、任务参数、结果导入和 Undo |
| `server/` | 独立环境内的媒体处理、推理和产物写出 |
## 注册与配置
注销先关闭 Runtime、快捷键与工具,再移除菜单和 Scene 属性,按 `CLASSES` 逆序注销类型。设备、存储目录、模型、材质显示适配和功能上限统一通过 `preferences.py` 读取。
**Maximum AI Input Size** 限制模型分析输入和 Upscale 可提交源图的长边;**Maximum Frame Resolution** 限制 Frame 输出长边;**Minimum Relative Edge Length** 与 **Boundary Padding** 控制 Cutout 的网格密度和轮廓边界采样。
## 执行边界
```mermaid
flowchart TD
A[Operator 在主线程读取 Blender 数据] --> B[准备输入文件]
B --> C[request 返回普通字典]
C --> D[BlendJob 队列执行 Server Job]
D --> E[模型与媒体处理写入 Job 目录]
E --> F[主线程 response 加载结果]
F --> G[提交 Image 或 Object 修改及 Undo]
G --> H[清理临时输入]
```
Plane、Frame、Mask、Rectify 和无需 AI 的 Cutout 在 Blender 内执行。Server 的 `jobs/` 编排任务,`models/` 负责模型适配,`geometry/` 处理深度与法线产物。Server 模块通过内部相对导入共享能力,Blender 侧通过 `common/` 复用。
MoGe-2 与 MoGe-3 输出统一为 `GeometryFrame`:包含 Depth、Validity、Intrinsics,以及按需提供的 Normal 和 Points。产物写入器消费同一个 Frame,保持深度、法线和相机数据一致。参见 [Runtime](runtime.md) 与 [产物协议](outputs.md)。

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

@@ -0,0 +1,44 @@
# Blender 公共能力
`src/anyimage/common/` 按业务职责提供公共函数,调用方从对应模块直接导入。
| 模块 | 职责与主要入口 |
| --- | --- |
| `ai.py` | 环境和模型就绪检查、输入路径校验、`production_device()`、`moge2_parameters()` 与安装 UI |
| `image.py` | `image_rgba()`、Image User 帧设置读取、Job 输入准备、像素采样、结果 Image 和 `replace_empty_image()` |
| `color_image.py` | 材质颜色与 AI 分析输入的准备和清理 |
| `hdr_image.py` | HDR 去背景分析输入及浮点颜色保留 |
| `image_target.py` | Image Empty 与 Shader Image Texture 编辑目标 |
| `selection.py` | `SelectionPath`、`SelectionMask`、non-zero winding 栅格化与 Alpha 修整 |
| `viewport.py` | 原生点选、屏幕投影、`ImageGesture`、Lasso / Brush / Polyline 与 Overlay |
| `depth.py` | 深度图片和元数据加载、相机坐标与显示范围的尺度换算 |
| `material.py` | Image Layer、Normal、Alpha、Shadeless 与 Depth 材质 |
| `object.py` | Modifier 输入设置与结果对象激活、源对象替换 |
| `node.py` | `node_asset_path()` 与 `load_node_group()` |
## 图像生命周期
业务像素采用 Top-down RGBA,`image_pixels()` 使用 Blender 像素顺序。预乘采样用于投影插值;文件或 Packed 图像的业务读取保留隐藏 RGB。`ImageEditTarget` 校验目标身份后经 `replace_empty_image()` 或 `replace_texture_image()` 提交:未共享的 Image 原地替换内容,共享时改用新的 Image 数据块,失败时回滚源数据。
`prepare_image_input()` 返回路径及临时标记;`cleanup_image_input()` 与创建方配对。`color_image.py` 的 `prepare_material_color_input()` 准备材质颜色,`material_analysis_input()` 提供分析输入;Cutout 按几何 bounds 裁切。
## 手势与 Selection
```mermaid
flowchart TD
A[原生对象点选] --> B[ImageGesture 冻结源图与交互状态]
B --> C[屏幕路径与 Overlay]
C --> D[提交时投影到图片空间]
D --> E[SelectionPath]
E --> F[局部 non-zero winding 栅格化]
F --> G[SelectionMask values 与 bounds]
G --> H[Mask Alpha 运算或 Cutout 内容轮廓]
```
Brush 的圆形印记和连接条由 `brush_footprint_polygons()` 生成,供预览与提交共用。拖动时维护屏幕路径与局部 Overlay,提交时生成覆盖值。Mask、Rectify 与 Cutout 的空命中保留 active Image Empty;点中另一对象时完成原生选择。
## 材质、节点与对象
`create_image_material()` 按 Shadeless、Normal 和 Depth 组合节点、连接颜色与 Alpha;材质显示适配读取当前 Preferences。`set_modifier_input()` 按实际 RNA 输入形式设置值,`finalize_object_result()` 完成结果对象激活和源对象处理。Image 替换路径保留 Empty 的矩阵、显示尺寸、偏移和 Image User 帧设置。
Geometry Nodes 从 `src/anyimage/assets/O_AnyImage.blend` 按公开名称加载。构建与布局职责见[节点资产](node-assets.md),深度字段见[Job 产物](outputs.md)。

View File

@@ -0,0 +1,48 @@
# 开发与发布
仓库使用 CPython 3.11 与 `bpy==4.5.3` 测试 Blender 代码;AI Server 使用 `runtime.py` 声明的独立 Python 3.12 Environment。
```bash
uv sync
uv run pytest
```
## 测试组织
| 测试范围 | 文件 |
| --- | --- |
| 扩展注册、设置、安装和 Job 交互 | `test_addon_registration.py`、`test_preferences.py`、`test_ai_setup.py`、`test_job_operator.py` |
| Frame、Mask、Rectify、Plane、Cutout | 对应 `test_*_tool.py`、`test_*_operators.py` 与对象、投影、网格测试 |
| 图像身份、Alpha、材质与 Undo | 图像编辑集成、共享替换、材质适配与 Undo 测试 |
| Server | `test_job_server.py`、`test_server_jobs.py`、`test_input_validation.py`、`test_geometry_artifacts.py` |
| 模型 | `test_model_manager.py`、下载、推理与各 ONNX 模型测试 |
| 节点资产 | 布局与接口等价、几何求值、Cutout 与临时属性清理 |
| 工具与包协议 | 扩展 Manifest、打包、模型同步与节点启动器 |
Blender Stub 共用 `tests/support/blender.py`;Server 和实际 Blender 几何 fixture 按使用范围存放在对应 support 模块。测试命名描述功能、触发条件与可观察结果。
## 发布命令
| 命令 | 职责 |
| --- | --- |
| `uv run pack` | 生成 Windows、macOS arm64、Linux 扩展包 |
| `uv run pack --prepare` | 为本机同步扩展 wheel 与 Manifest |
| `uv run --group blender node-group build` | 构建、验证节点资产并运行节点测试 |
| `uv run model sync` | 准备、校验并上传模型声明的文件 |
| `uv run docs -dev` | 本地预览文档 |
| `uv run docs` | 通过 Mike 发布项目版本并更新 latest |
`tools/pack.py` 从 `pyproject.toml` 读取依赖,按平台与 Blender Python 版本解析 wheel,使用 Blender 提供的 NumPy。产物命名为 `AnyImage.v<version>.<platform>.zip`,写入 `dist/`。本地 BlendJob wheel 内容变化后运行 `uv lock --refresh`,并核对锁文件、Manifest 与打包测试。
`tools/models/cli.py` 根据模型目录选择上游 ONNX 或本地导出流程;`tools/models/exports.py` 处理对应 PyTorch 权重导出。文件校验依据声明大小和 SHA-256,上传使用逐文件复制。`uv run model prepare` 用于本地准备。
## CI 与文档导航
```mermaid
flowchart TD
A[main push、Pull Request 或手动触发] --> B[test.yml 运行测试]
C[v 前缀 Tag] --> D[build.yml 测试、打包并发布 ZIP]
E[main 文档路径变化或手动触发] --> F[docs.yml 构建站点并部署到 Cloudflare Workers]
```
站点导航由 `mkdocs.yml` 显式维护,页面移动时同步导航和相对链接。节点资产的脚本职责及检查入口见[节点资产](node-assets.md)。

15
docs/internals/index.md Normal file
View File

@@ -0,0 +1,15 @@
# 内部实现总览
AnyImage 在 Blender 主线程处理交互、像素编辑和数据创建,通过 BlendJob 把模型推理交给独立 Job Server。
| 主题 | 对应职责 |
| --- | --- |
| [程序架构](architecture.md) | 进程、注册、配置与主线程边界 |
| [Common](common.md) | Blender 侧图像、手势、几何与 AI 公共能力 |
| [Runtime 与 Server](runtime.md) | Environment、Job、模型下载与 Session 生命周期 |
| [Job 产物](outputs.md) | 文件协议、相机坐标和 Blender 消费方式 |
| [Operator 索引](operators/index.md) | 按实际用户功能查找实现 |
| [节点资产](node-assets.md) | 资产、源码职责、构建和验证 |
| [开发与发布](development.md) | 测试组织、工具命令与发布流程 |
源码位于 `src/anyimage/`,开发工具位于 `tools/`,自动化测试位于 `tests/`。扩展级设置由 `preferences.py` 定义,运行时资源由 `runtime.py` 接入 BlendJob。

View File

@@ -0,0 +1,50 @@
# 节点资产
## 资产清单
节点组由 `nodes/groups/` 中的构建模块定义,共用构建逻辑位于 `nodes/common/`。
| 节点组 | 构建模块 |
| ------------------------- | --------------------------- |
| `O Image Plane` | `image_plane.py` |
| `O Image Depth Plane` | `image_depth_plane.py` |
| `O Image Relief Plane` | `image_relief_plane.py` |
| `O Image Cutout` | `image_cutout.py` |
| `O Image Depth Cutout` | `image_depth_cutout.py` |
| `O Image Cutout Symmetry` | `image_cutout_symmetry.py` |
| `O Image Layer` | `image_layer.py` |
| `O Image Depth Layer` | `image_depth_layer.py` |
| `O Shadeless` | `shadeless.py` |
| `O Image Depth Panorama` | `image_depth_panorama.py` |
## 构建节点资产
生产节点组由 `uv run --group blender node-group build` 构建到 `src/anyimage/assets/O_AnyImage.blend`。该文件是 Git 忽略的发布构建产物;CI 与本地发布都从节点源码重新生成。
节点组规则:
- 字段默认直接连接,多个消费者可复用同一输出;按消费位置的几何、域、类型和输入属性版本验证求值等价性
- 所有几何节点、嵌套组及测试辅助图禁止使用 Capture Attribute;构建定义和保存资产递归检查 Capture 为零
- 域转换使用 Evaluate on Domain 或明确域的采样节点表达;跨几何变化优先调整消费顺序或在源几何上采样,明确索引对应关系
- Store Named Attribute 用于实际命名协议或仍需跨几何变化保存的最少数据,逐项明确名称、类型、域、Selection、写入阶段、消费者及必要性;内部临时属性使用 `_o_` 前缀,在最后消费者之后用通配符 `_o_*` 清理,保留 UV、用户属性和外部协议属性。清理必须走 `remove_attribute_pattern`:按精确名称删除时,若某个几何分支从未写入该属性,Remove Named Attribute 会报出缺失警告
- Group Input 按区域重复放置,通过字段排列和必要的 Reroute 保持连线可读,隐藏未使用输出;存储须有数据生命周期依据
- 构建阶段通过明确的节点或 socket 引用接线
- 保留节点默认 `name` 和标题,不用 `label` 覆盖,不用 String 节点注解。Frame 仅用于确有包裹语义的区域
- 全接线的简单数学运算可折叠;需要阅读的常数、运算域和模式保持可见
- 比较统一用 Compare 节点并按操作数数据类型选择输入,布尔运算统一用 Boolean Math,不用 Math 节点做比较、也不用数值乘法代替布尔运算;材质树不支持这两个节点,仍用 Math
- 修改器 Geometry Nodes 的输入 socket 默认使用 `SINGLE`
- socket `subtype` 按业务语义设置:长度用 `DISTANCE`,`0–1` 比例用 `FACTOR`,`0–100` 用 `PERCENTAGE`;无对应范围语义时保留默认
- 接口或布局变更须验证 socket 顺序与结构、未使用输出隐藏及几何求值;纯布局变更比较运算、默认值和实际连接,确认功能不变
## 构建资产脚本
`tools/nodes/build.py` 按依赖顺序加载 `nodes/groups/` 的定义,调用 `arrangement/` 统一排列几何节点组后保存。`nodes/common/` 提供共用构建函数:`nodes.py` 创建接口与节点,`depth_surface.py`、`cutout.py` 等组装几何,`shader.py` 构建材质着色节点,`material_slots.py` 继承几何材质槽;`tools/nodes/preview/` 导出交互预览。
命令通过当前 uv Python 的独立子进程执行构建、检查和预览,`bpy` 由 `blender` dependency group 提供。保存后,`check.py` 重新加载资产并做基本几何求值;`tests/nodes/` 覆盖节点定义行为,`tests/tools/nodes/` 覆盖工具行为。CI 使用同一入口先生成资产,再运行常规测试和打包。
```bash
uv run --group blender node-group build
uv run --group blender node-group build --skip-tests
uv run --group blender node-group check
uv run --group blender node-group preview
```

View File

@@ -0,0 +1,42 @@
# AI 环境管理
AI 环境管理从当前安装状态出发,补齐独立运行环境和必需模型,并提供设置入口与模型缓存释放操作。
## 执行过程
```mermaid
flowchart TD
Entry["Set Up AI Server"] --> Status["读取环境与必需模型状态"]
Status --> Ready{"是否全部就绪?"}
Ready -- "是" --> Done["结束"]
Ready -- "否" --> Environment{"运行环境是否就绪?"}
Environment -- "否" --> Install["安装隔离 Python 环境"]
Environment -- "是" --> Download["下载缺失的必需模型"]
Install --> Download --> Done
```
`SetupAIEnvironment` 是统一入口。首次使用时先安装运行环境,再下载默认模型;环境已经存在时,只补齐缺失模型。环境安装由 Blender Operator 启动,模型下载通过 Job Server 执行。
## 节点说明
### 读取状态,选择下一步
入口位于 `src/anyimage/operators/ai_setup.py`。`SetupAIEnvironment` 通过 `properties.py` 中的 `ai_status()` 读取环境和模型状态,并根据结果结束、安装环境或调用 `DownloadRequiredModels`。对话框同时显示预计下载量和缺失模型名称。
`runtime.py` 提供当前 Environment 与 Server 状态;Server 正忙时不会启动新的安装流程。`OpenAIEnvironmentSettings` 打开 AnyImage 的扩展首选项。
### 安装独立环境
环境尚未就绪时,`SetupAIEnvironment` 调用 Runtime 注册的安装 Operator。`use_mirror` 决定 uv、Python 和安装包的下载源,模型使用模型目录中声明的来源。
安装完成后通过 `post_install()` 下载默认模型,模型依赖加载于独立 Server 环境。
### 下载模型
`ai_setup.py` 中的 `DownloadModel` 处理单个模型,`DownloadRequiredModels` 处理默认必需模型集合。两者先检查 Environment、Blender Online Access 和模型记录,再提交 `download-model` 或 `download-required-models` Job。
Job 在 `server/app.py` 注册;`server/model_catalog.py` 保存模型名称、文件和来源,`server/model_download.py` 下载并校验文件,`server/model_manager.py` 管理模型目录与已加载 Session。下载进度和错误通过同一套 BlendJob Runtime 返回 Blender。
### 释放模型缓存
`ai_setup.py` 中的 `ClearModels` 调用 `runtime.clear_resource("model_manager")`,释放 Server 中已加载的模型 Session。下次推理从模型目录重新加载 Session。

View File

@@ -0,0 +1,41 @@
# 剪贴板图片
剪贴板图片从 `Ctrl/Cmd + V` 开始,把操作系统中的图片变成 Packed Blender Image,并放到当前编辑器支持的位置。
## 执行过程
```mermaid
flowchart TD
Paste["Ctrl/Cmd + V"] --> Priority{"刚执行过 Blender Copy?"}
Priority -- "是" --> Native["交回原生 Paste"]
Priority -- "否" --> Read["读取系统图片"]
Read --> Image["复用或创建 Packed Image"]
Image --> Target{"当前编辑器"}
Target --> View["Reference / Plane"]
Target --> Node["Image Node"]
Target --> Paint["Brush Texture"]
```
Windows 快捷键优先处理 Blender 自己的 Copy/Paste,系统剪贴板出现新的图片内容时 AnyImage 接管粘贴;macOS 和 Linux 没有系统剪贴板序列号,始终由 AnyImage 处理粘贴。
## 节点说明
### 判断是否交给 Blender
`operators/clipboard_image/operators.py` 定义 `TrackNativeCopy`、`PasteClipboardImage` 和 3D View、Node Editor 快捷键。`TrackNativeCopy` 记录 Blender Copy 时的系统剪贴板序列号;粘贴时若序列号没有变化,`PasteClipboardImage` 返回 `PASS_THROUGH`,让 Blender 继续处理对象或节点粘贴。
同一文件随后调用 `actions.target_for_context()` 判断当前编辑器是否支持图片落点。
### 读取系统图片
`clipboard.py` 负责平台差异。Windows 依次尝试 PNG、DIBV5 和 DIB,DIB 补成 BMP;macOS 通过 `osascript` 导出 PNG;Linux 依次尝试 `wl-paste` 和 `xclip` 提供的图片格式。各平台输出统一为图片字节和扩展名,再交给后续步骤。
### 创建或复用 Packed Image
`actions.py` 对图片内容计算 SHA-256。相同内容已经粘贴过时会复用现有 Packed Image,否则创建新 Image 并 Pack 到当前 `.blend`,避免依赖临时剪贴板文件。
### 放到当前编辑器
落点仍在 `actions.py` 中完成:3D View 创建 Reference 或 Plane,Node Editor 创建与当前节点树匹配的 Image 节点,绘制模式把 Image 配置为当前画笔的 Texture。鼠标位置和视图位置也在这里换算。
Plane 路径调用 `convert_to_plane/image_plane.py` 创建中心原点基础网格,并从节点资产加载 `O Image Plane`。`actions.py` 创建图像材质并放入 Mesh 第 `0` 个材质槽,节点组只生成几何。

View File

@@ -0,0 +1,14 @@
# Panorama 转换
`operators/convert_to_panorama/` 将静态等距柱状 Image Empty 转换为径向深度表面,提交前裁剪出最大居中 2:1 区域。`operators.py` 提交任务,`object.py` 导入对象,`__init__.py` 汇总导出与注册清单。
```mermaid
flowchart TD
A[准备颜色与分析图] --> B[generate-panorama-geometry]
B --> C[采样 12 个透视视图并推理]
C --> D[融合径向距离与有效性]
D --> E[写出 depth.exr 与 depth.json]
E --> F[创建材质与 O Image Depth Panorama]
```
任务使用 Preferences 选择的几何模型。源颜色由 Blender 侧保存,Server 的 `geometry/panorama.py` 负责视图采样与距离融合,`jobs/panorama.py` 编排推理和产物写入。

View File

@@ -0,0 +1,21 @@
# Plane 转换
`operators/convert_to_plane/operators.py` 提供 `ConvertToPlane`、`ConvertToDepthPlane`、`ConvertToReliefPlane` 与 `GenerateDepthPlane`。`object.py` 导入对象和材质,`image_plane.py` 构建基础矩形网格,`__init__.py` 汇总导出与注册清单。
```mermaid
flowchart TD
A[Image Empty] --> B[准备材质颜色]
B --> C{转换类型}
C -- Plane --> D[四边形与 O Image Plane]
C -- Depth 或 Relief --> E[静态图提交几何 Job]
E --> F[加载深度、元数据与法线]
F --> G[对应节点修改器与材质]
D --> H[创建对象并替换源 Empty]
G --> H
```
三种转换都只接受静态图片。基础网格以局部中心为原点,对象矩阵补偿源 Empty 的显示范围。
Depth 与 Relief 从 Preferences 读取几何模型、分辨率级别和 AI 输入上限。`create_depth_plane_from_result()` 导入产物并创建修改器。`O Image Depth Plane` 使用相机 XYZ 与对象空间法线构建深度表面;`O Image Relief Plane` 使用深度 Z 与切线空间法线构建浮雕。
节点构建见[节点资产](../node-assets.md),文件协议见[Job 产物](../outputs.md)。

View File

@@ -0,0 +1,43 @@
# Cutout
Cutout 在静态 Image Empty 上圈定 Selection,按轮廓创建 Flat、Solid、Depth Symmetry 或 Depth Solid。入口位于 `operators/cutout_tool/operators.py`,Shape 菜单位于 `interaction.py`,预设标识与节点组对应关系位于 `shape.py`。
```mermaid
flowchart TD
A[Lasso 或 Polyline 提交 SelectionPath] --> B[选择 Shape]
B --> C[栅格化 SelectionMask 并读取源 RGBA]
C --> D{需要 Depth 或 Normal?}
D -- 是 --> E[准备 bounds 矩形 RGBA]
E --> F[generate-cutout-artifacts]
F --> G[加载 Depth、Metadata 与 Normal]
D -- 否 --> H[源 Alpha 与 SelectionMask 组合]
G --> H
H --> I[边界映射、轮廓提取与质量三角化]
I --> J[BaseShape 与 o_balloon]
J --> K[创建材质、对象与对应节点修改器]
```
| 预设 | 节点组 | AI 产物 |
| --- | --- | --- |
| Flat | `O Image Cutout`,Thickness 0 | 可选切线空间法线 |
| Solid | `O Image Cutout`,Thickness 1 | 可选切线空间法线 |
| Depth Symmetry | `O Image Depth Cutout` 与 `O Image Cutout Symmetry` | 深度与对象空间法线 |
| Depth Solid | `O Image Depth Cutout` | 深度与对象空间法线 |
Flat 与 Solid 可以不带 AI 产物生成;Depth 预设和 Normal Map 需要就绪的几何模型,Shape 菜单按该状态提供选项。
## 轮廓与网格
`geometry.py` 从内容 Alpha 提取连通轮廓与孔洞,按 Edge Length 生成 `BaseShape`。Edge Length 是世界空间的网格目标边长,Minimum Relative Edge Length 会按内容范围提高其下界。
`mesh.py` 负责轮廓分离、孔洞处理、质量三角化和边界支撑,`polygon.py` 提供轮廓简化,`tangle.py` 是随包分发的 Delaunay 三角化核心。Fine Outline 展开时保留小孔与细节轮廓,关闭时填洞并简化。
`balloon.py` 负责 Balloon Profile,按 Preferences 选择 Poisson 或 Teddy,生成所有预设共用的 POINT 属性 `o_balloon`。`boundary_padding.py` 按 Boundary Padding 沿结构内法线重采样轮廓附近的颜色与深度。
## AI 与对象创建
Server 接收 Selection bounds 内保留源 Alpha 的 RGBA,一次 MoGe 推理按 `generate_depth` 与 `normal_mode` 返回产物。深度参考区域使用所选 Alpha Threshold,Normal 使用原预测;Maximum AI Input Size 只影响分析分辨率。
`object.py` 的 `create_shape_object()` 消费 BaseShape、Color、Depth 和 Normal,加载对应节点组。基础网格位于局部 XZ 平面,厚度沿 Y 展开;对象矩阵把网格放入 Image Empty 的图片平面,Depth Symmetry 额外叠加对称节点组与方向参数。Object Normal 随方向同步转换。
材质使用 IOR 1.2,颜色与法线接入 Image Layer,法线按切线或对象空间解释。节点计算见[节点资产](../node-assets.md)。

View File

@@ -0,0 +1,21 @@
# Frame 多图合成
`operators/frame_tool/operators.py` 定义 `FrameImages` 和 `FrameTool`。`projection.py` 负责视图投影、交叠和结果平面定位,`compositing.py` 负责像素深度排序与边界覆盖采样,`__init__.py` 导出类型及注册清单。Frame 将选中的静态 Image Empty 按当前视图合成为一张图片。
```mermaid
flowchart TD
A[拖出屏幕矩形] --> B[冻结视图矩阵并收集选中静态图片]
B --> C[检查矩形与 active 图片的有效投射交集]
C --> D[按 Region 与 Maximum Frame Resolution 计算输出尺寸]
D --> E[观察射线投影到各图片平面]
E --> F[按样本深度从远到近合成,等深度 active 优先]
F --> G[边界覆盖采样与独立 Alpha]
G --> H[创建 Packed Image 并复用 active Object]
H --> I[删除其他参与图片对象并提交 Undo]
```
正交视图接受有限深度,透视视图采样观察方向前方的交点。交叠检查采用连续投影范围;输出尺寸受 Region、最长边上限和总像素上限约束。
RGB 与 Alpha 分别累计,保留被 Mask 隐藏的有效颜色。边界使用覆盖采样,内部复用直接采样,避免黑边和不必要的模糊。结果平面朝向观察者,位置由 active 图片的有效深度确定。
Frame 保留 active 对象身份、名称和 Collection;图像替换复用 [Common](../common.md) 的共享数据与失败恢复逻辑。

View File

@@ -0,0 +1,16 @@
# Operator 实现索引
| 源码(相对 `src/anyimage/`) | 功能 |
| --- | --- |
| `operators/ai_setup.py` | [AI 环境管理](ai-setup.md) |
| `operators/clipboard_image/` | [剪贴板图片](clipboard-image.md) |
| `operators/convert_to_plane/` | [Plane 与 Depth Plane](convert-to-plane.md) |
| `operators/convert_to_panorama/` | [Panorama](convert-to-panorama.md) |
| `operators/cutout_tool/` | [Cutout](cutout-tool.md) |
| `operators/frame_tool/operators.py` | [Frame 多图合成](frame.md) |
| `operators/mask_tool.py` | [Mask Alpha 编辑](mask.md) |
| `operators/rectify_tool/operators.py` | [Rectify 透视校正](rectify.md) |
| `operators/remove_background.py` | [Remove Background](remove-background.md) |
| `operators/upscale.py` | [Upscale](upscale.md) |
单文件功能按业务命名;复杂功能包在 `operators.py` 定义 Operator 和入口协调逻辑,交互式工具同时定义 WorkSpaceTool,其余模块承载具体实现。包的 `__init__.py` 汇总导出与 `CLASSES` 注册清单,类型在 `operators/__init__.py` 和扩展 `__init__.py` 汇总注册。AI Operator 使用普通字典提交任务,并在主线程响应中读取文件和修改 Blender 数据。

View File

@@ -0,0 +1,23 @@
# Mask Alpha 编辑
`operators/mask_tool.py` 定义 `EditImageAlpha` 和 `MaskTool`,使用 `common/viewport.py` 的 `ImageGesture` 管理 Lasso、Brush 与 Polyline。
```mermaid
flowchart TD
A[冻结 Scene 的 Gesture、Mode、Radius] --> B[屏幕手势与 Overlay]
B --> C[完成后投影并生成覆盖 M]
C --> D[读取源 RGBA]
D --> E[按模式计算 Alpha]
E --> F[保留 RGB 和源画布尺寸]
F --> G[替换 Packed Image 并提交一个 Undo]
```
| 模式 | 源 Alpha A 与覆盖 M 的结果 |
| --- | --- |
| Set | `A × M` |
| Extend | `max(A, M)` |
| Subtract | `A × (1 − M)` |
Brush 拖动时维护简化屏幕路径、圆形印记与连接条的并集预览;释放时一次生成图片覆盖。Polyline 使用逐点路径,至少三个点后通过闭合圈、双击或 Enter 完成,Backspace 删除末点。
结果保留 Empty 的身份、矩阵、显示尺寸和偏移。全透明结果有效,取消或切换工具清理未提交的 Overlay;共享 Image 通过统一替换入口分流。

View File

@@ -0,0 +1,17 @@
# Rectify 透视校正
`operators/rectify_tool/operators.py` 定义 `RectifyImagePerspective` 与 `RectifyTool`,将图片内的四角区域校正为矩形。`geometry.py` 负责四角验证与像素校正,`preview.py` 负责预览图、Overlay 和宽高比控制,`__init__.py` 导出类型及注册清单。
```mermaid
flowchart TD
A[点选四角] --> B[规范为凸 Quad 并检查图片交叠]
B --> C[512×512 预览与宽高比调整]
C --> D[按像素密度和输出上限确定尺寸]
D --> E[分块 Homography 与预乘 Alpha 插值]
E --> F[按可见 Alpha 裁剪]
F --> G[映射 placement bounds 并替换 Packed Image]
```
四角允许任意点击顺序,退化或非凸输入在提交前校验。预览根据源颜色空间配置显示,像素重采样复用 `common/image.py`。输出最长边上限 8192,总像素上限 16,777,216。
`replace_empty_image()` 根据校正区域的 placement bounds 调整画框,保留源 Image 名称、对象身份和共享引用语义。

View File

@@ -0,0 +1,19 @@
# Remove Background
`operators/remove_background.py` 从 Image Empty 或当前 Shader Image Texture 准备输入。`RemoveImageBackground` 协调设置与输入,`RunBackgroundRemoval` 提交 Job 并应用结果。
```mermaid
flowchart TD
A[ImageEditTarget 取得编辑目标] --> B[准备图像输入]
B --> C[remove-background Job]
C --> D[所选背景模型生成前景 Alpha]
D --> E{输入类型}
E -- 普通图片 --> F[透明 PNG 前景]
E -- HDR --> G[alpha.npy]
F --> H[应用结果与 Undo]
G --> H
```
`server/jobs/remove_background.py` 读取单张输入并调用 `server/models/background.py`,支持 BiRefNet 和 BEN2。模型前景 Alpha 与源 Alpha 合成。
普通结果通过 `ImageEditTarget` 保留共享图像引用与帧设置。HDR 使用 `common/hdr_image.py` 的 `HdrBackgroundInput` 准备分析输入,并将返回 Alpha 应用于原浮点 RGB。Operator 负责临时输入清理。

View File

@@ -0,0 +1,15 @@
# Upscale
`operators/upscale.py` 从 Image Empty 或当前 Shader Image Texture 生成 2× 结果,源图长边必须小于 Maximum AI Input Size。
```mermaid
flowchart TD
A[检查源图尺寸并冻结模型设置] --> B[准备图片输入]
B --> C[upscale-image 单张处理]
C --> D[分块执行 4× RGB 推理]
D --> E[统一缩放为源图 2×]
E --> F[原 Alpha 独立 Lanczos 缩放]
F --> G[ImageEditTarget 应用结果并提交 Undo]
```
`server/models/upscale.py` 处理输入上限和最终尺寸,`onnx_upscale.py` 执行 Real-ESRGAN 与 HAT 模型。ModelManager 管理 Session;Provider 资源错误会释放当前 Session 并返回处理建议。

40
docs/internals/outputs.md Normal file
View File

@@ -0,0 +1,40 @@
# Job 产物
Server 将结果写入 Job 目录,返回以相对文件名为值的字典。Blender 主线程通过 JobResult 读取文件,创建或更新 Image、Mesh、Material 和 Object。
| Job | 文件 | 消费方 |
| --- | --- | --- |
| `remove-background` | `foreground.png` 或 `alpha.npy` | ImageEditTarget 或 HDR Alpha 编辑 |
| `upscale-image` | `upscale.png` | 图像替换 |
| `generate-depth-plane-geometry` | `depth.exr`、`depth.json` 和法线 | Depth / Relief Plane |
| `generate-cutout-artifacts` | 按请求提供深度、元数据和法线 | Cutout |
| `generate-panorama-geometry` | `depth.exr`、`depth.json` | Panorama |
## 深度与法线协议
| 返回字段 | 内容 |
| --- | --- |
| `depth` | float32 EXR,透视产物 RGB 保存相机空间 XYZ,Alpha 保存源 Alpha × 模型有效性 |
| `depth_metadata` | JSON,包含 `image_size` 与 3×3 `intrinsics` |
| `tangent_normal` | `tangent-normal.png`,切线空间法线 |
| `object_normal` | `object-normal.png`,对象空间法线 |
```mermaid
flowchart TD
A[源 RGB 与 Alpha] --> B[限尺寸 RGB 推理]
B --> C[GeometryFrame]
C --> D[写出深度与法线]
A --> E[源 Alpha 写入有效通道]
E --> D
D --> F[Blender 加载并 Pack]
```
参考深度由 `common/depth.py` 从产物计算:先按 Alpha 阈值和有限正深度筛选样本,剔除超过样本中位数 1.1 倍的远处背景,再取 95 分位数;无可用样本时返回基准值。加载后设置 Non-Color 和 CHANNEL_PACKED。Depth Plane 使用对象空间法线,Relief Plane 使用切线空间法线。
Panorama 的 EXR RGB 保存径向距离,Alpha 保存源 Alpha 与融合有效性;元数据包含 `projection: equirectangular` 和 `image_size`。
## 颜色与图像编辑
`common/color_image.py` 为 Plane、Panorama 和 Cutout 准备独立的材质颜色与 AI 分析输入。Cutout 使用 Selection bounds 内的源图;网格创建时组合源 Alpha 与 SelectionMask。颜色分辨率与分析尺寸分别处理。
`ImageEditTarget` 统一 Image Empty 和 Shader Image Texture 的编辑目标及共享引用。HDR 去背景通过 `HdrBackgroundInput` 保留 Blender 浮点 RGB,并应用 Server 返回的连续 Alpha。

36
docs/internals/runtime.md Normal file
View File

@@ -0,0 +1,36 @@
# Job Runtime 与 Server
`runtime.py` 配置 BlendJob `JobRuntime` 和独立 Python 3.12 Environment。`server/app.py` 注册 Job,`model_manager.py` 管理模型文件与缓存 Session。
```mermaid
flowchart TD
A[Operator request] --> B[JobRuntime 队列]
B --> C[Server Job 调用媒体与模型模块]
C --> D[写入 Job 目录]
D --> E[主线程 response 导入结果]
```
| Job | 实现与用途 |
| --- | --- |
| `download-model`、`download-required-models` | `app.py` 下载单个或缺失模型 |
| `remove-background` | `jobs/remove_background.py` 生成透明前景或连续 Alpha |
| `upscale-image` | `jobs/upscale.py` 生成 2× 图像 |
| `generate-depth-plane-geometry` | `jobs/depth_plane.py` 生成深度、元数据和法线 |
| `generate-cutout-artifacts` | `jobs/cutout.py` 按请求生成深度和法线 |
| `generate-panorama-geometry` | `jobs/panorama.py` 生成全景径向深度 |
`media/` 校验输入图片并限制分析尺寸,Server 只处理静态图片。Job 在阶段边界检查取消,通过 `context.progress()` 返回进度,Operator 清理 Blender 导出的临时输入。
`geometry/prediction_artifacts.py` 缩放源 RGB 后运行一次 MoGe,将同一预测交给深度、法线和元数据写入器;源 Alpha 写入深度与法线产物的有效通道。参考深度由 Blender 侧按产物 Alpha 计算,文件协议见 [Job 产物](outputs.md)。
## 模型与缓存
| 用途 | 模型 | Session 分类 |
| --- | --- | --- |
| Depth 与 Normal | MoGe-2 ViT-S / ViT-B Normal、MoGe-3 ViT-L | geometry |
| Remove Background | BiRefNet Lite、BEN2、BiRefNet HR Matting | background |
| Upscale | Real-ESRGAN WDN、Real-ESRGAN x4plus、HAT Sharper | upscale |
`model_catalog.py` 声明文件来源、许可、大小和 SHA-256;`model_download.py` 下载并校验。ModelManager 按模型路径和设备缓存 Session,切换模型或设备时释放对应类别。Clear Models 或关闭 Server 时释放已加载资源。
首次安装通过 `post_install()` 下载默认 MoGe-2 ViT-S Normal、BiRefNet Lite 与 Real-ESRGAN General WDN x4v3。Storage Root 默认 `~/.anyimage`,保存环境、模型、Job 产物和日志。设置入口见 [AI 环境管理](operators/ai-setup.md)。