- Updated the naming convention for upscaled images to include underscores and file extensions. - Renamed properties related to cutout pixel size to point spacing for clarity. - Adjusted alpha region calculations to use a half-alpha threshold for better accuracy. - Enhanced the handling of foreground mesh masks to consider half-alpha values. - Introduced new functions for unbounded selections and cutout images, ensuring proper handling of source and selection images. - Improved test coverage for cutout functionalities, including bounds mapping and alpha preservation. - Updated tests to reflect changes in naming conventions and functionality adjustments.
6.1 KiB
Image 工具技术实现
Image 工具位于 operators/image_edit/。Box、Lasso、Line 与 Polyline 共享直接编辑管线;Perspective 在工具栏中独立显示并处理 Homography,但复用源图选择、绘制和 Empty 写回。
模块职责
flowchart LR
Tools["box / lasso / line / polyline\nWorkspaceTool"] --> Mask["mask.py\n手势、Refine、Invert"]
Perspective["perspective.py\n四点、比例、Homography"]
Mask --> Common["common.py\n选择、绘制、裁切、Empty 写回"]
Perspective --> Common
Mask --> Job["refine-image-mask\nBEN2 内容 mask"]
box.py、lasso.py、line.py、polyline.py只声明 WorkspaceTool。mask.py用EditImageMask统一四种手势;RefineImageMask负责异步 BEN2 响应。perspective.py维护四点输入、比例预览和全分辨率重采样。common.py只放跨两条管线实际共用的逻辑。
首次点击
resolve_image_edit_click() 临时调用 Viewport Select 判断点击目标:
| 点击目标 | 行为 |
|---|---|
| 另一张 Image Empty | 选择并设为 Active,本次不编辑 |
| 当前 Active 图片、空白或非图片对象 | 恢复原选择并开始编辑当前图片 |
这避免工具在无有效源图时退化为对象移动,也让用户无需切回 Select Tool。
Mask 管线
flowchart TD
Gesture["屏幕手势"] --> Polygon["源图片像素 polygon / mask"]
Polygon --> Refine{"Refine Selection?"}
Refine -- 否 --> Content["几何 mask"]
Refine -- 是 --> Server["选区外 RGBA 清零 → BEN2"]
Server --> Content2["BEN2 Alpha × 几何 mask"]
Content --> Invert{"Invert?"}
Content2 --> Invert
Invert -- 否 --> Final["final mask"]
Invert -- 是 --> Reverse["1 - final mask"]
Final --> Apply["源 Alpha × mask"]
Reverse --> Apply
Apply --> Crop["按非零 Alpha 紧裁切\n保留源 RGB"]
Crop --> Write["替换 Image 并更新 Empty 显示"]
Box / Lasso 的顺序固定为 Refine → Invert。BEN2 只提供内容 Alpha;最终 RGB 始终来自源图。Blender 侧只修改 Alpha,不清理透明区 RGB,以避免 Viewport 纹理过滤产生黑边。Line / Polyline 强制关闭 Refine,只执行几何 mask 与 Invert。
未形成有效区域的单击直接返回 CANCELLED,不报告消息;最终 Alpha 全空时,Operator 报告 WARNING 并保持源图不变。其他数据、状态或运行时异常仍报告 ERROR。
Box、Lasso、Line 与 Polyline 的屏幕预览统一绘制白色虚线轮廓和淡灰半透明填充。简单选区使用 Blender 的凹多边形三角剖分,不使用从首点展开的 Triangle Fan;通过屏幕网格快速检测到自交后改用 2 px 扫描填充,并读取 Operator 的最终填充规则。Image Mask 使用偶奇规则,Cutout 使用与最终几何一致的非零环绕规则。Lasso 只在游标相对末点移动至少 2 px 时采点,停留产生的重复 MOUSEMOVE 不增加轨迹;新点与前一线段的偏差不超过 0.75 px 时直接替换末点,在线消除近似共线点。填充三角形和闭合虚线段都按当前屏幕 polygon 缓存,额外重绘不重复计算。松开鼠标后使用这条已简化的闭合 polygon 生成几何 mask。
Line 的屏幕坐标 Y 轴与图片坐标 Y 轴方向相反,因此像素阶段会反转线段端点,使半透明预览侧与实际保留侧一致;Ctrl 只影响屏幕端点的 5° 吸附。零长度点击在投影前直接取消,投影结果不足两个点时也会安全终止。Polyline 接近起点时绘制闭合圆环,并支持单击起点或 Enter 完成;完成时显式闭合,不把当前游标位置作为额外顶点。
Perspective 管线
四点先按源图片 X/Y 方向规范为凸四边形,输入顺序不参与输出方向。第四点后只生成一次 512 × 512 临时纹理;移动鼠标改变 UI 比例,确认时才进行全分辨率 Homography。
预览引用在删除前先从 Operator 清空;若 Undo 或 Blender 已移除临时 Image,清理会忽略失效的 RNA 引用,因此切换工具和重复结束都安全。
透视重采样使用预乘 Alpha 插值,随后恢复 RGB、清理透明像素并紧裁切。输出最长边限制为 8192 px,总像素限制约 16 MP。
Perspective 不调用 BEN2,也不支持 Invert。它是 deform 工具,不属于 mask 清理语义。
Empty 写回
replace_empty_image_pixels() 先创建并验证完整结果,再根据引用源 Image 的 Image Empty 数量选择提交方式:只有一个引用时,把原 Image 的用户重映射到结果、删除旧 datablock 并恢复原名,最终不留下额外图片;两个或更多引用时,只替换当前 Empty 的 data,其他 Empty 继续使用原图。共享图片的新结果沿用源 Image 基础名,不附加 .mask、.perspective 或其他工具后缀;同名冲突交给 Blender 自动添加 .001。两种方式都不复制对象,也不修改 matrix_world。
empty_display_alignment() 在写入像素前,根据源画布、旧 plane_bounds、结果尺寸和放置 bounds 计算显示参数;写回函数随后更新:
empty_display_size;empty_image_offset。
Box、Lasso、Line 与 Polyline 的放置 bounds 等于最终裁切范围,因此像素与原图片平面严格对齐。Perspective 的结果比例可能不同于四边形轴对齐范围,因此只保持中心和覆盖尺度近似一致。
Server 边界
普通 Mask 和 Perspective 完全在 Blender 侧执行。只有 Box / Lasso 的 Refine Selection 提交 refine-image-mask:
- 根据 polygon 创建局部透明画布;
- 清空选区外 RGBA;BEN2 公共入口再以输入 Alpha 遮住透明 RGB;
- 使用共享的
remove_image_background()运行 BEN2; - 再乘几何 selection mask;
- 返回紧裁切的
image.png与源图坐标bounds.json。
Blender 只读取返回图片的 Alpha,并把它应用到原图 RGB。相同的 BEN2 输入清理规则也用于 Remove Background、Depth Plane、Surface 和 Balloon;正式输出使用源 RGB 与 BEN2 Alpha。Blender 数据只在主线程 Operator 中读写,Job 参数保持为可序列化字典。