Add image extraction functionality with background removal

- Implemented ExtractImageRegion operator for extracting image regions using box or lasso selection.
- Added RemoveImageRegionBackground job for background removal from selected image regions.
- Created utility functions for polygon bounds, selection canvas creation, and applying selection masks.
- Integrated image processing using PIL and numpy for efficient pixel manipulation.
- Enhanced user experience with modal drawing and status updates during extraction.
This commit is contained in:
2026-08-22 15:47:34 +08:00
parent 988332548e
commit f42cba1932
27 changed files with 2513 additions and 761 deletions

View File

@@ -37,7 +37,7 @@ Mesh Plane、Depth Plane、Surface、Background 和 Balloon 按功能组织。
Server 的模型模块返回 Prediction,几何模块处理数组与网格,输出模块写文件。Blender 数据只在 Operator Response 的主线程阶段创建。
Image Lasso 的基础像素裁切在 Blender 主线程完成;启用 Contour 时,Server Job 计算 BEN2 Alpha,并按最终非零 Alpha 范围与像素 Padding 输出图片,Operator Response 负责 Pack 新图、可选复制源 Empty 并更新结果对象的空间范围。
Image Box、Lasso 与 Perspective 位于 `operators/image_extract/` 功能包。模块职责、交互状态、像素管线、背景清理和 Empty 定位见 [Image 工具技术实现](image-tools-technical.md)。
## 项目结构

View File

@@ -12,6 +12,7 @@
| Surface | 从单张图片恢复透视空间 | 单图 | 相机空间网格、材质与可选匹配相机 |
| Remove Background | 提取透明前景 | 单图、视频、序列帧 | 透明图片或透明序列 |
| Image Lasso | 手绘提取并原位更新图片 | 静态 Image Empty | Pack 的透明裁切图 |
| Image Perspective | 四点透视矫正裁切 | 静态 Image Empty | Pack 的矩形裁切图 |
| Balloon | 沿轮廓绘制鼓起造型 | 静态 Image Empty | 带原图 UV 的封闭网格 |
| Debug | 检查模型原始输出 | 模型支持的图片或帧序列 | 保存在 Job 目录中的原始 Prediction |
@@ -29,7 +30,9 @@ Balloon 作为不依赖 AI 的基础工具单独排列;三个 AI 功能在缺
转换任务完成后,AnyImage 在一个 Undo 步骤中创建网格、图片、材质和修改器。源 Image Empty 是否保留由转换选项决定。
Image Box 与 Image Lasso 合并为一个工具组,分别使用 Sculpt Mode 的 Box Mask 与 Lasso Mask 图标;默认显示 Box,长按按钮可切换 Lasso。绘制时使用默认鼠标光标,并以类似 Select Tool 的白色虚线显示选区。该工具组与 Balloon Lasso 相邻,并通过一个工具栏间隔与前方的 Add Cube 分开;两组工具只位于 3D Viewport 左侧工具栏,不显示在右键 AnyImage 子菜单。它们将选区外 RGBA 清为透明黑,再以最终 Alpha 大于 0 的最小 bounding box 作为输出画布;Padding 使用整数像素向四周扩展透明边距,默认 0 px。结果会 Pack 到 .blend,同一个 Empty 的原点移动到新画布中心,显示尺寸同步调整,使裁切内容在世界空间保持重合。Keep Original 默认关闭;开启后保留源 Empty 的 Active 与选择状态,并创建未选中的裁切副本。可选 Contour 使用 BEN2 的软 Alpha 进一步收紧选区,并在分析后计算最终画布范围。
Image Box、Image Lasso 与 Image Perspective 组成一个工具组,共用源图选择、`Remove Background`、`Continuous` 和 `Padding`。Box 提取矩形,Lasso 提取自由轮廓,Perspective 将任意顺序输入的四个角矫正为指定比例的矩形。结果都是 Pack 的 Image Empty,并沿用源图朝向与深度。
操作步骤见 [Image Box、Lasso 与 Perspective](image-tools.md);处理管线与模块职责见 [Image 工具技术实现](image-tools-technical.md)。
Balloon 默认在 Blender 内部生成,无需 Environment 或模型。Tool Settings 提供模式、厚度、采样距离、材质复用、`Contour`、`Depth` 与 MoGe-2 `Depth Model`;AI 未就绪时只禁用这三个控件,并在 Tool Settings 中显示安装按钮。Depth 会把物理距离相对化并稳健拟合初始基面,保留未截断的正负起伏。Base Plane 子 Empty 的旋转定义基面朝向,沿自身局部 Z 移动定义 middle level。

View File

@@ -0,0 +1,77 @@
# Image 工具技术实现
Image Box、Lasso 与 Perspective 位于 `operators/image_extract/`。三者共享源图选择、设置、图片写回、空间定位、Continuous 分层和可选背景清理。
## 模块职责
```mermaid
flowchart LR
Box["box.py\nWorkspaceTool"] --> Region["region.py\nBox / Lasso Operator"]
Lasso["lasso.py\nWorkspaceTool"] --> Region
Perspective["perspective.py\n四点与透视矫正"]
Region --> Common["common.py\n共享选择、设置与结果写回"]
Perspective --> Common
Common --> Job["extract-image-background\n可选 BEN2 Job"]
```
`box.py` 与 `lasso.py` 只声明 WorkspaceTool。两者通过 `selection_shape` 复用 `ExtractImageRegion`;Perspective 保留独立 Operator,因为它还有四点输入、比例预览和 Homography。
## 首次点击
`resolve_image_extract_click()` 将首次点击归为两种结果:
| 点击目标 | 结果 |
| --- | --- |
| 另一张 Image Empty | 只选择并设为 Active |
| 当前 Active 图片、空白或非图片对象 | 使用当前 Active 图片开始取区 |
这段逻辑由三个工具共用。点击非图片对象后会恢复原选择,避免触发对象移动或更换源图。
## 处理管线
```mermaid
flowchart TD
Input["屏幕选区"] --> Pixels["转换到源图片像素坐标"]
Pixels --> Background{"Remove Background?"}
Background -- 否 --> Local["Blender 内处理 RGBA"]
Background -- 是 --> Server["选区画布 → BEN2 → 局部图片"]
Local --> Tool{"工具类型"}
Server --> Tool
Tool -- Box / Lasso --> Crop["Alpha bounds + Padding"]
Tool -- Perspective --> Warp["预乘 Alpha Homography"]
Warp --> Crop
Crop --> Result["创建并 Pack Image\n定位 Empty"]
```
Box 与 Lasso 将选区外 RGBA 清为透明黑,再按非零 Alpha 的最小范围裁切。Perspective 先将四点规范为沿源图 X/Y 方向的凸四边形,再按确认的宽高比重采样;点击顺序不参与输出旋转。
透视预览固定生成一次 512 × 512 临时 Image。鼠标移动只改变屏幕上的预览比例;确认后才执行全分辨率重采样。
## 背景清理
`extract-image-background` 与标准 `remove-background` Job 共用 `remove_image_background()`。图片工具的 Job 只增加三项选区语义:
- polygon mask;
- 局部图片在源图中的 bounds;
- Box / Lasso 使用的透明 Padding。
Perspective 请求的 Job Padding 固定为 0。局部结果回到 Blender 后先换算为源图坐标,再执行透视矫正和最终 Padding。
## Empty 定位与 Continuous
Box 与 Lasso 根据裁切前后的像素 bounds 换算 Empty 的中心和显示尺寸。Perspective 使用源四边形的轴对齐 bounds 近似放置结果。三者都沿用源 Empty 的矩阵,因此朝向与深度不变。
Continuous 关闭时直接更新源 Empty;开启时复制对象,并沿操作开始时捕获的 View 方向偏移:
```text
offset = display_size × world_scale × 0.001 × layer
```
`layer` 记录在源对象的 `_anyimage_extract_layer` Custom Property 中,使连续结果依次靠近当前 View。
## 维护约束
- WorkspaceTool 的显示设置放在 `box.py`、`lasso.py`、`perspective.py`。
- Box / Lasso 的共享交互放在 `region.py`,跨三个工具的行为放在 `common.py`。
- Blender 数据只在主线程 Operator 中读写;Server 参数保持为可序列化字典。
- 普通裁切不启动 Job Server;只有 Remove Background 需要 Environment 与 BEN2。

85
docs/image-tools.md Normal file
View File

@@ -0,0 +1,85 @@
# Image Box、Lasso 与 Perspective
这三个工具用于从 Image Empty 中提取局部图片。结果仍是 Image Empty,并自动 Pack 到 `.blend`。
它们只处理静态图片。视频和序列帧请使用其他转换工具。
## 选择工具
| 工具 | 适合 |
| --- | --- |
| **Image Box** | 提取矩形区域,操作最快 |
| **Image Lasso** | 沿物体或不规则边界自由绘制 |
| **Image Perspective** | 将海报、屏幕、门窗等四边形内容矫正为矩形 |
在 3D Viewport 左侧工具栏找到 Image 工具组。长按当前图标可以切换三个工具;设置位于 Tool Settings。
<div class="screenshot-placeholder" markdown>
**截图占位:工具组与 Tool Settings**
建议同时显示三个工具入口,以及 Remove Background、Continuous、Padding。
目标文件:`images/image-tools/tool-group.png`
</div>
## 选择源图片
如果当前 Active 已是目标图片,可以直接开始取区。
如果要处理另一张图片,先点击它。这一次点击只负责选择;下一次点击或拖动才开始取区。点击空白处或其他类型的对象时,工具继续使用当前 Active 图片。
!!! tip
最简单的习惯是:先点一下目标图片确认 Active,再开始绘制。
## 使用 Box 或 Lasso
=== "Image Box"
1. 按住左键,从区域一角拖到另一角。
2. 松开左键,立即生成结果。
=== "Image Lasso"
1. 按住左键,沿需要保留的区域绘制。
2. 松开左键,立即生成结果。
选区可以越过图片边缘。只要范围内仍有可见像素,工具就会按实际内容裁切。
<div class="screenshot-placeholder" markdown>
**截图占位:Box 与 Lasso 取区**
建议用一张并排图展示矩形拖拽和自由轮廓,不需要额外结果图。
目标文件:`images/image-tools/box-lasso.png`
</div>
## 使用 Perspective
1. 依次点击内容的四个角,顺序不限。
2. 第四点完成后,Viewport 中央会显示矫正预览。
3. 左右移动鼠标调整宽高比。
4. 单击左键确认并生成结果。
调整比例时按住 `Ctrl`,可以吸附到 `1:1`、`4:3`、`3:4`、`16:9` 和 `9:16`。`Backspace` 返回上一个角点;右键或 `Esc` 取消。
<div class="screenshot-placeholder" markdown>
**截图占位:Perspective 比例确认**
建议截取中央图片预览、蓝色边框、比例文字和底部操作提示。
目标文件:`images/image-tools/perspective-aspect.png`
</div>
## 结果设置
- **Remove Background**:使用 BEN2 删除选区内的背景,再按可见内容裁切。首次使用需要先完成 AI Environment 与 BEN2 配置。
- **Continuous**:保留源图片,连续创建新结果。新图片会向当前 View 稍微靠近,减少重叠闪烁。
- **Padding**:在可见内容四周增加透明像素,单位为 px。
Continuous 关闭时,结果会原位替换当前 Image Empty;开启时,源图片保持 Active,便于继续提取其他区域。
## Perspective 的结果位置
Perspective 会矫正图片内容,但不会尝试还原真实相机或空间平面。结果沿用源图片的朝向和深度,并大致放在原四边形覆盖的区域。
需要了解交互状态、像素处理和模块职责时,请阅读 [Image 工具技术实现](image-tools-technical.md)。

View File

@@ -9,6 +9,7 @@ AnyImage 是一款 Blender 扩展,可以把照片、视频或序列帧转换
- 用 **Depth Plane** 快速得到可调节的浮雕式面片
- 用 **Surface** 从单张图片生成透视纹理网格
- 用 **Remove Background** 一键获得透明前景
- 用 **Image Perspective** 将四点选区矫正为沿用源 Empty 朝向的矩形裁切图
- 处理视频和序列帧,生成可随时间播放的 Depth Plane
- 使用 Geometry Nodes 继续调整深度、细分、重拓扑与平滑效果

View File

@@ -9,6 +9,7 @@
| `generate-depth` | `results.npz`、深度与颜色序列 | Depth Plane 所需深度、相机和贴图 |
| `generate-surface` | `mesh.npz`、`normal.png`、颜色层 | Surface 网格、相机与材质输入 |
| `remove-background` | `color.0001.png` 起 | 带 Alpha 的颜色层 |
| `extract-image-background` | `selection-input.png`、`image.png`、`bounds.json` | 图片工具选区内去背景后的局部图片与原图坐标 bounds |
| `analyze-balloon` | `lasso-input.png`,按选项输出 `foreground.png`、`contour.json`、`depth.npz`、`normal.png` | 套索约束输入、BEN2 轮廓与 MoGe-2 深度、法线 |
| `debug-da3` | `prediction.npz` | DA3 API 返回 |
| `debug-moge2` | `prediction*.npz` | MoGe-2 API 返回 |

View File

@@ -59,6 +59,8 @@ Environment 使用 Python 3.12、ONNX Runtime、NumPy、Pillow、PyAV、trimesh
Balloon 的 `analyze-balloon` Job 会裁切套索输入并清零选区外 RGBA。`Contour` 用 BEN2 回传最大连通轮廓;`Depth` 用 MoGe-2 对有效相机距离稳健拟合二维基面,并把物理距离换算为不受绝对拍摄距离影响、未截断的相对深度信号。Job 同时把 MoGe normal 转换为 tangent-space 纹理,铺回原图尺寸并以中性法线填充无效区域。Blender 主线程负责采样深度属性、创建 Base Plane Empty、组装 `O Balloon Shape` 修改器与 `O Balloon Layer` 材质。
图片 Box、Lasso 与 Perspective 的可选 `Remove Background` 使用 `extract-image-background` Job。它与标准 `remove-background` Job 共用单图 BEN2 去背景函数,再叠加图片工具专属的 polygon mask、局部 bounds 与透明 Padding。
正式功能支持:
- MoGe-2 ViT-S、ViT-B、ViT-L Normal

View File

@@ -11,3 +11,17 @@
.md-typeset .grid.cards > ul > li {
border-radius: 0.5rem;
}
.md-typeset .screenshot-placeholder {
margin: 1rem 0;
padding: 2.5rem 1.25rem;
border: 2px dashed var(--md-default-fg-color--lighter);
border-radius: 0.5rem;
color: var(--md-default-fg-color--light);
text-align: center;
background: var(--md-code-bg-color);
}
.md-typeset .screenshot-placeholder p {
margin: 0.35rem 0;
}

View File

@@ -8,7 +8,8 @@ AnyImage 提供多种日常工作流。选择结果时,先考虑你需要的
| Depth Plane | 人物、产品、插画、动态背景、快速场景搭建 | 图片、视频、序列帧 | 带深度位移的平面 | 快速、可动画、Geometry Nodes 参数直观 |
| Surface | 建筑、室内、街景、需要匹配视角的单图 | 单张图片 | 透视纹理网格 | 空间感更强,可创建匹配相机 |
| Remove Background | 抠出人物或物体,继续作为 Image Empty 使用 | 图片、视频、序列帧 | 带透明 Alpha 的颜色图 | 不创建网格,保留 Empty 的位置和显示设置 |
| Image Box / Lasso | 矩形或手绘提取局部内容并按 Alpha 范围裁切 | 静态图片 | Pack 的透明裁切图 | 工具组切换,支持像素 Padding 与 Keep Original,不创建网格 |
| Image Box / Lasso | 矩形或手绘提取局部内容并按 Alpha 范围裁切 | 静态图片 | Pack 的透明裁切图 | 支持 Padding 与 Continuous,不创建网格 |
| Image Perspective | 海报、屏幕、门窗等四边形内容的透视矫正裁切 | 静态图片 | Pack 的矩形图片 | 四点任意顺序,共用 Remove Background、Padding 与 Continuous |
## 什么时候选择 Mesh Plane
@@ -33,3 +34,7 @@ Surface 会根据模型估算的相机和深度构建透视网格。相较 Depth
如果只想把 Image Empty 换成透明前景图,不需要任何几何结构,直接选择 **Remove Background**。对象的 Transform、显示尺寸和 Offset 会保留。
[阅读去除背景指南](remove-background.md)
## 什么时候使用 Image Perspective
当图片中的矩形物体因为透视变成四边形,并且希望得到一张正视矩形裁切图时,使用 3D Viewport 工具栏中的 **Image Perspective**。它只把四点当作图片裁切与 Homography 输入,不假设当前 View 的焦距与原图拍摄相机一致。四点顺序不影响输出方向;结果 Empty 保持源图朝向和深度,并按源图中的选区范围近似放置。需要持续提取多个区域时,可开启与 Image Box / Lasso 共用的 Continuous。