AI拼UI的图层拆分算法小突破
传统的游戏UI方案是美术出PSD图,程序去拼。随着生图模型的发展,如今策划、美术会用AI生成图片,但AI生成的界面图是一张平面,需要人工拆图。我们对拆图算法做了大量研究,包括生图模型去生成图集(网上大部分工具采用的方法)等等,但总归不尽如意。
见到magic layers后,我很有启发,它的拆图算法又快又准,因此就一直很想去复现它,但时隔几个月,网上没有关于它实现细节的文章,也没有相关论文,使得有一度停滞。在经过多项试验之后,我们研究出合适的算法,并开发出内部产品。本文将会从效果展示、算法原理等方面进行详解。
一、效果展示
如下动图展示了对一张UI预览图的拆图效果,可见,拆分效果还挺准确,各个部件都拆了出来,被遮挡的元素(背景框)也做了修补。程序运行速度较快,处理一张图片大概1分钟时间。

下图中,左侧是原始的预览图,中间是经过修补后的背景,而右边则是拆分素材后回拼的图像,可见,准确率较高。图中的文字是经过ocr后重新渲染的,因此字体、字号上会有一点偏差,但分离文字是游戏界面开发所需的步骤。

下图展示拆分出来的素材,准确率也还不错。

虽然有些素材稍有瑕疵(如左上第一张图),但我们的目标是尽可能做到85%的准确度,剩下的会提供一些界面交互,让用户能手动修。在界面交互上,如下图,会提供素材的二次拆分、通过prompt重新修补素材、手动通过画笔修补素材等功能。

下图展示处理图像各阶段所耗费的时间,其中涉及两个本地模型调用,分别花费4.1秒和19.8秒,这两部分可以云端GPU处理,从而进一步压缩时间,后续有望将处理时间压缩到30秒左右。

二、算法解析
整个拆图算法经过如下几个步骤,包括OCR、文字清理 、LLM规划、图像分割、图层构建、元素修补、背景修补、层级组合等,有些步骤会根据不同图像走不同的分支,包括美术字的处理、素材修补算法等等。

接下来会对每个步骤做详细的说明。
2.1 文字处理
2.1.1 OCR文字提取
输入一张图像,会先使用RapidOCR做文字识别,设置最低置信度 0.35,同时低于 0.85 的单个拉丁字母会被视为图标误识别;低置信度且高宽比 ≥2.4 的竖排装饰候选也会会被剔除。下图展示OCR阶段提取的文字Mask。

2.1.2 预览图去除文字
有了文字mask,接下来会执行一次修补算法,将原图的文字去掉,下图展示执行了修补泛后的预览图,可见,效果挺好。

具体的修补算法如下:
1.限定候选范围:对每个 OCR 结果取其 bbox 裁片,并把 OCR 四边形转换为局部 allowed mask;后续像素判断不会越出该四边形。
2.估计底色:在裁片四周取宽度为 clamp(min(h,w)/4, 1, 3) 像素的边带,只保留 allowed 内像素,计算 RGB 中位数 B,作为该文字区域的局部底色。

3.提取实际字形:对 allowed 内每个像素计算 RGB 欧氏距离 d(p)=||I(p)-B||₂,将 3d 截断到 0–255,再用 Otsu 自动阈值 T;最终条件为 3d ≥ max(12, 0.65T)。所得二值图再做一次 3×3 闭运算,连接笔画内的小裂缝。
- 质量约束:若字形面积占 OCR 四边形面积不足 1.5% 或超过 68%,说明颜色分离不可信,此区域改用完整 OCR 四边形作为 mask,并在记录中标记 mask_mode=coarse;否则标记 estimated_glyphs。
- 覆盖抗锯齿、描边和阴影:按 OCR 框高 h 对字形 mask 做椭圆膨胀。单个中文字符半径为 clamp(round(0.16h),3,8);其他文字为 clamp(round(0.09h),2,6)。所有区域取并集,得到报告中的硬 mask。

6.补空缺:将原图转为 BGR,调用 OpenCV cv2.inpaint(..., radius=5, INPAINT_TELEA)。Telea 方法从 mask 边界向内推进,根据已知邻域像素与待补点的距离、边界法线方向和等照度线方向进行加权传播;因此它延续的是文字附近的局部颜色/低频纹理。修复后再转回 RGB。

2.1.3 文字提取
OCR提取文字后,虽然可以得到文本、位置的信息,但算法还需要判断文字的字体、字号、颜色等内容,因此还需要运行一次文字样式的估计算法,各项的计算如下。
- 文字前景色。取字形 mask 内像素,将每个 RGB 通道按 32 级宽量化到桶中心(16、48、…、240)。每个颜色桶的得分为 像素数 × (24 + 与局部背景的 RGB 欧氏距离),取最高分桶;这样兼顾主色占比与背景对比度。
2.字体族。文本中包含 CJK 字符时选 Microsoft YaHei,否则选 Arial。
3.字号。以 OCR 框高 h 为基准:单个中文字符取 round(0.88h),其余取 round(0.82h),下限 8px。实际渲染时用 PIL 测量含描边文本包围盒;只要超过 OCR 框宽或框高,就逐像素减小字号,直到完整放入。
4.粗体。计算字形覆盖率 coverage = mask像素数/(框宽×框高);coverage ≥ 0.17 记为 700,否则记为 600,区分半粗/粗两档。
5.描边颜色。分别按 Rec.709 系数 0.2126R+0.7152G+0.0722B 计算前景与背景亮度。前景不暗于背景时使用深色 #1e2322,否则使用浅色 #f0f4f1,确保文字边缘保持对比。
6.描边宽度。若 coverage > 0.12,取 round(0.045h);否则取 round(0.03h);最后限制在 0–2px。
以示例图中左上角的“金币:100”为例,处理结果如图。

2.1.4 美术字处理
游戏中常用美术字,如下图中的logo“精灵大作战”就是美术字,它应是像素素材,不应该处理成文字。然而OCR并不能区分它是不是美术字,会统一对待。因此,需要特殊处理。

算法会在LLM阶段交由LLM去判断文字的类型,如果是普通文字,则走去除流程,而如果判定为美术字,则删去对应的mask。下图展现存在美术字logo的图像在LLM步骤之后的去字结果。

另一张示意图:

2.2 素材分割
接下来是本算法最核心的部分,图像分割,目标就是将预览图中的各个元素给分离出来。为了实现这一步,我们做了大量实验,尝试了多种分割模型和不同的组合算法。

2.2.1 LLM图层规划
为了有效指引分割模型,先使用LLM对图像做规划,使用Gemini 3.7 Flash,该模型是经过多项对比后,目前认为在视觉能力、响应速度、推理能力等方面都比较符合我的需要。该阶段会让LLM圈出界面中的元素,同时也对元素的类型(面板/按钮/图标 等),美术字,修补类型,层级关系等需要决策的内容作出判断。
LLM的输入包括:原图、初次全 OCR 去字图,以及一段精心调教的prompt,输入图像示意如下。

具体的提示词:
Analyze a game UI and return a compact executable layer plan.Two images are provided in this order: (1) the original image, (2) an OCR-cleaned working image.OCR regions are listed with stable ids below. First classify their rendering mode:- ordinary readable UI copy (labels, values, hints, button captions) remains editable text;- a logo, wordmark or decorative display lettering whose irregular shape, multicolor fill, thick custom outline, embedded mascot/icon or hand-drawn geometry is part of its identity must remain a raster image asset. Put only those OCR ids in raster_text_ids.Do not classify text as raster merely because it is bold, outlined or placed on a button. A normal font that can be acceptably recreated as text must stay editable. This is a rendering decision, not an OCR-confidence decision.The cleaned image initially has all OCR glyphs removed. For each raster_text_id, also emit exactly one non-text query (prefer kind=logo, role=foreground) using its location in the original image. The pipeline will restore that artwork before segmentation. Never emit ordinary text as a query.Find all visible non-text assets that should be independently editable:- large panels, boards, frames and dialogs whose exposed material/boundary is visible;- every repeated card, slot, tab or row surface as a separate geometry hint;- complete action/navigation buttons as one object, including any integrated icon shape;- independent icons, item artwork, portraits, silhouettes and framed illustrations;- badges, ribbons, locks, counters and grouped status markers with their own visible shape.Do not emit the full-screen background, ordinary text, shadows, gaps, separators, speculative objects, duplicate composite descriptions, or people/props inside one framed illustration. A parent surface and its foreground child must be separate only when both are real editable assets. Repeated instancesshare one query but each instance needs its own hint.Every hint is passed directly to segmentation:- bbox_norm=[x0,y0,x1,y1] tightly encloses exactly one instance, normalized to 0..1;- positive_points_norm has 1-3 points on solid target pixels, not edges, holes or background;- negative_points_norm is empty unless a real competing object is near/inside the box; when used, put 1-2 points on that competitor, never on an overlaid child of an underlying surface;- inspect each repeated instance separately. Do not mechanically copy relative point positions.- z_order is back-to-front. Parent surfaces must have a lower z_order than their children.- parent_query_id is required for every element visually carried by another exported element. Use the nearest direct material parent, not merely the largest outer panel: artwork, silhouette, badge or label inside a card belongs to that card; the card belongs to its panel. Leave it null only for true root elements. This parent chain is exported and also controls occlusion repair.For every query choose one element_repair_mode:- "image" for a textured, patterned, illustrated, translucent or gradient-bearing parent material whose child elements must later be removed and reconstructed by the image model;- "surface" only for a nearly uniform flat-colour material that can be reconstructed from measured neighbouring pixels;- "none" for a topmost foreground object or an object with no meaningful material behind children. This is a material decision. A panel/card/frame with artwork, glow or visible texture is "image".Choose one background_repair.mode for the pixels hidden by the extracted UI:- "scene": the hidden area is a real textured/illustrated scene and should be reconstructed from the visible scene boundary. The repair image will contain only a black diagnostic hole plus a very narrow softened edge; do not rely on a generated prefill.- "surface": the hidden area is visually close to a uniform or translucent colour/material. Use measured boundary colour/low-frequency continuation only; do not invent scenery or texture.- "none": do not synthesize hidden pixels; preserve the current cleaned background. Select from the image evidence, not from the number of detected layers.Return JSON only, with no prose and no fields outside this schema. The original image is providedonly for the text audit; the text-cleaned image is the source for non-text layer planning.{ "scene_summary": "short description", "background_repair": {"mode": "scene|surface|none", "reason": "short evidence-based reason"}, "text_corrections": [{ "text": "visible text missed by OCR", "bbox_norm": [0.1,0.1,0.2,0.2], "confidence": 0.8 }], "raster_text_ids": ["text_001"], "queries": [{ "id": "snake_case_id", "name": "short user-facing name", "kind": "panel|card|button|icon|illustration|badge|decoration|logo", "role": "container|surface|button|foreground|decoration", "element_repair_mode": "image|surface|none", "parent_query_id": null, "z_order": 0, "geometry_hints": [{ "bbox_norm": [0.1,0.1,0.2,0.2], "positive_points_norm": [[0.15,0.15]], "negative_points_norm": [] }] }]}由于提示词比较长,为了容易阅读,我翻译了一个中文版本。
分析游戏 UI,并返回一份紧凑、可执行的图层规划。系统将按以下顺序提供两张图片: 1. 原始图片 2. 经 OCR 清理后的工作图片下面会列出带有稳定 ID 的 OCR 区域。首先,请判断它们的渲染方式: 1. 普通且可读的 UI 文本(如标签、数值、提示语、按钮文字)应保留为可编辑文本; 2. 如果某段文字属于 Logo、字标或装饰性展示字体,并且其不规则造型、多色填充、粗重的定制描边、嵌入式吉祥物/图标或手绘几何形状构成了其身份特征,则必须保留为栅格图像资产。只有这类 OCR ID 才能放入 raster_text_ids。不要仅仅因为文字使用了粗体、描边或位于按钮上,就将其归类为栅格图像。如果能使用普通字体以可接受的效果重新制作,它就必须保留为可编辑文本。这里判断的是渲染方式,而不是 OCR 识别置信度。清理后的图片在初始状态下已移除所有 OCR 字形。对于每个 raster_text_id,还必须基于它在原始图片中的位置,输出且仅输出一个非文本查询;优先使用 kind=logo、role=foreground。流水线会在图像分割之前恢复这些图形。绝不能为普通文本创建查询。找出所有可见且应当独立编辑的非文本资产,包括: 1. 暴露的材质或边界清晰可见的大型面板、板块、边框和对话框; 2. 每个重复出现的卡片、槽位、标签页或行表面;每个实例都要分别提供几何提示; 3. 完整的操作按钮或导航按钮,将按钮及其集成的图标形状视为一个整体对象; 4. 独立图标、物品插画、肖像、剪影和带框插画; 5. 具有自身可见形状的徽章、缎带、锁、计数器和成组状态标记。不要输出以下内容: 1. 全屏背景; 2. 普通文本; 3. 阴影; 4. 空隙; 5. 分隔线; 6. 推测出来但不可确认的对象; 7. 重复的复合描述; 8. 一幅带框插画内部的人物或道具。只有当父级表面与其前景子元素都是真实且可编辑的资产时,才应将二者分别导出。对于重复实例,应共用同一个查询,但每个实例都必须拥有自己的几何提示。每条几何提示都会被直接传入图像分割流程: 1. bbox_norm=[x0,y0,x1,y1]:必须紧密包围且仅包围一个实例,坐标归一化到 0..1; 2. positive_points_norm:包含 1~3 个位于目标实体像素上的点,不能位于边缘、孔洞或背景上; 3. negative_points_norm:除非边界框附近或内部确实存在竞争对象,否则应为空。需要使用时,在竞争对象上放置 1~2 个点;绝不能将点放在底层表面所承载的叠加子元素上; 4. 必须逐个检查每个重复实例。不要机械地复制相同的相对点位; 5. z_order 按从后到前的顺序排列。父级表面的 z_order 必须低于其子元素; 6. 所有被另一个已导出元素承载的元素,都必须设置 parent_query_id。应指定最近的直接材质父级,而不是仅仅指定最大的外层面板: 6.1 卡片内部的插画、剪影、徽章或标签属于该卡片; 6.2 卡片属于其所在面板。 7. 只有真正的根元素才能将其设为 null。这条父子链会被导出,同时也会控制遮挡修复。每个查询都必须选择一个 element_repair_mode: 1. "image":适用于带纹理、图案、插画、半透明效果或渐变的父级材质;移除其子元素后,必须由图像模型重建该材质; 2. "surface":仅适用于近似均匀的纯色平面材质,可通过测量周边像素进行重建; 3. "none":适用于最上层的前景对象,或其子元素后方不存在有意义材质的对象。这是对材质的判断。任何带有插画、光晕或明显纹理的面板、卡片或边框,都应使用 "image"。为被提取 UI 遮挡的像素选择一个 background_repair.mode: 1. "scene":被遮挡区域属于真实的纹理化或插画式场景,应依据可见场景边界进行重建。修复图中只会包含一个黑色诊断孔洞和极窄的柔化边缘;不要依赖生成式预填充; 2. "surface":被遮挡区域在视觉上接近均匀或半透明的颜色/材质。仅使用测得的边界颜色或低频延续进行修复;不要虚构场景或纹理; 3. "none":不合成被遮挡的像素,保留当前清理后的背景。必须根据图像证据进行选择,而不能根据检测到的图层数量决定。返回JSON格式部分略。下表整理并展示了LLM的部分返回结果。

将其中元素的bbox框图可视化,会得到下图,可见LLM的分析结果准确度非常高,使得能用它来指引图像分割模型。

2.2.2 图像分割
有了LLM的指引,分割操作便简单了许多。算法使用Segment Anything SAM1 ViT-B模型,整张任务图只编码一次,随后按 LLM 实例逐一执行提示分割。
2.2.3 候选提取
对于每个实例,SAM模型会给出三套候选方案,算法会使用一套自定义的评分机制,选出最合适的分割实例。以main_panel为例,三个候选分割方案如下。

算法采用的评分公式如下,正点命中率衡量候选是否覆盖目标锚点;负点命中率衡量是否误吞竞争物;框内包含度是 mask 像素位于提示框内的比例;外接框 IoU 衡量候选范围与提示框的一致性。
总分 = SAM模型分 + 0.22×正点命中率 − 0.38×负点命中率 + 0.10×框内包含度 + 0.06×外接框IoU
按照该评分规则,main_panel三个候选的得分如下,因此,第一个候选框被选中,其他两个候选框则被丢弃。

2.2.4 修补和连通域筛选
SAM模型分割的图像往往会有一些“破漏”的点,本算法会执行连通域修补的算法,让分割出来的元素更加自然。连通域修补算法分为如下两个步骤。
- 3×3 闭运算修补。对二值 mask 使用一个 3×3 全 1 核,先膨胀 1 像素再腐蚀 1 像素。它会连接约 1–2px 的断裂并填掉细小针孔,但不会把明显的大洞补成矩形,也不会扩张成整个 bbox。
- 连通域筛选。闭运算后按 8 邻域把 mask 划分为组件。① 所有包含正点的组件必保留;② 若没有任何组件命中正点,保留最大组件;③ 另外保留面积至少为最大组件 8% 的组件。小于阈值且不含正点的孤立碎屑被删除。

重复进行该过程,即可提取所有界面元素。
2.3 遮挡修补
在完成界面元素分割后,顶层(没有被遮挡的,如下图)元素便可直接提取使用,但底层的元素由于被遮挡,需要进行修补流程。

下图展示“非顶层”的元素,由于扣去顶层的元素,它是镂空的,需要有算法进行修补。

此处会根据LLM的决策,分为大模型修补和传统算法修补两条路径。
2.3.1 大模型生图修补
将需要修补的元素拼成图集,再送入生图模型进行修补,使用的prompt如下:
Image inpainting task. The first image is the Atlas to be repaired, and the second image is a binary mask of exactly the same dimensions.All white regions in the mask must be inpainted, while all black regions in the mask must remain unchanged. Black areas in the first image also represent missing content. The repaired content must seamlessly continue the surrounding background material of the same element.The black regions are not black content to preserve, nor are they text to be redrawn.Repair only the black regions in the first image. Do not introduce any text, numbers, letters, icons, buttons, characters, objects, logos, lighting effects, or additional UI elements.Use only the immediately adjacent background of the same element as reference. Fill the missing regions with continuous colors, gradients, translucent materials, and textures. Do not reference other elements.All non-black content, element positions, dimensions, shapes, outer contours, boundaries, gray spacing, and the overall layout must remain completely unchanged.Even if a black region has the shape of text, treat it solely as a gap in the parent layer’s background. Do not restore it as text or as a rectangle.Output a complete image with exactly the same dimensions as the input.对应的中文翻译。
图像修补任务。第一张图是待修补的 Atlas,第二张图是与它尺寸一致的二值 mask。mask 中白色区域必须修补,黑色区域必须保持不动。第一张图中黑色也代表缺失内容,修补后的内容必须是同一个元素周围连续的背景材质。黑色区域不是要保留的黑色,也不是要重新绘制的文字。只修补黑色区域;不要出现文字、数字、字母、图标、按钮、角色、物体、logo、光效或任何额外 UI 元素。只参考黑色区域紧邻的同一元素背景,补成连续的颜色、渐变、半透明材质和纹理,不要参考其它元素。所有非黑色内容、元素位置、大小、形状、外轮廓、边界、灰色间隔和整张图布局都必须保持不动。黑色区域即使是文字形状,也只是父层背景的空缺,不要把它还原成文字或矩形。输出与输入完全相同尺寸的完整图像。下图展示修补的结果,可见,效果还可以。

当然,大模型不是万能的,对于一些较简单的情形,使用传统算法能达到更好的效果与稳定性。
2.3.2 传统算法修补
该部分与文字清除的修补相似,获取mask周围的元素像素来填补,这对于颜色单一的区域有着很好的效果。
2.3.3 背景修补
UI图中的背景因为被遮挡了大部分,因此使用大模型生图来进行修补,prompt如下:
Fill the black missing region in this image so the surrounding scene continues naturally.Keep visible characters and objects, and naturally continue anything that reaches the black region.Do not add UI, text, logos, or unrelated objects. Return one complete image at the same size.对应的中文翻译:
填充图像中的黑色缺失区域,使周围场景自然连续。保留可见的人物和物体,并自然延续进入黑洞的内容。不要添加 UI、文字、Logo 或无关物体。返回一张尺寸完全相同的完整图像。修补的结果如下图所示,可见取得较好的效果。

2.4 组合
根据切出来的素材图及其坐标,结合LLM推理得到的辅助关系和遮挡层级关系,对素材做重新的组合,即可得到有层次结构的复原图,也模拟了在游戏引擎中拼出来的界面效果。

三、对比实验
UI拆图游戏UI还原至关重要,本算法具备一定的竞争力。
下图展示qwen-image-layered的拆图结果,它需要手动指定层数,若指定不对,查出来的结果就很差,而且它所需的显存很多,运行速度也比较慢。

虽说设置合理的层数后,qwen-image-layered的拆图效果能有所提升,也能通过后处理来继续拆分,但它拆图的逻辑合理性欠佳,且对于更复杂的背景和其他很多测试图,其效果都没有很好。

对于canva的magic layers,下图展示magic layers的切图效果,它不支持批量元素下载(下图都是通过特殊手段获取的全部元素图),本算法具备较高的竞争力。

四、后续改进
目前还有不少改进的思路。
其一是根据LLM的决策,对应不同图像采用不同的提示词,以提升算法的泛化性。
其二是通过图像相似度匹配,召回参考图,使得切分和补图更精准。
综上,本算法解决了AI拼UI方案中的拆图问题,具备一定的实用性,也为上层的工具产品提供了核心内容。
