用LLM自动识别UI设计稿并批量切图:坐标映射与Python脚本全实践

用LLM自动识别UI设计稿并批量切图:坐标映射与Python脚本全实践 周五下午设计扔过来一版新的商城详情页Figma里两百多个图层嘴里说着“今晚能出吧”。我看着那些嵌套了三层的自动布局、加了特殊阴影的按钮、一个渐变背景拆成四个图层的小卡片心里清楚今晚大概率又要熬夜手动切图标了。当晚我顺手做了个实验让手里的大模型直接对着设计稿截图返回所有可切图区域的坐标和命名再写脚本批量切出来。这轮实验的成果很有意思单纯靠LLM的图像理解能力确实能识别UI图层的边界、类型和层次切小图标和卡片区域的效果远超预期但在坐标精度和重叠图层判断上又确实够不着生产标准。这篇文章会把我的思路、完整Prompt、坐标转换方案、Python切图脚本以及踩过的坑全部拆开来讲给同样在做AI提效探索的设计师和前端同学做个参考。实验思路不一定能直接落地到你的工作流但它足够展示LLM在处理UI视觉结构任务时能力和边界分别在哪儿。1. 项目背景与实验动机1.1 切图这个活为什么让人头疼做过UI交付的人都清楚切图从来不是“把图层拖出来导出”这么简单。设计师交付的设计稿里光是一个按钮可能就拆了背景、描边、文字、阴影四五个图层一套完整的电商详情页里有商品图、价格文字、标签、按钮、底部栏每一个区域都得单独切出来给开发用。过去我的流程是打开设计稿手动隐藏不需要的图层框选区域导出2x和3x两套尺寸命名成类似btn_buy_now_normal.png的格式再拖进标注工具里圈出位置。一次完整的页面切图耗掉两三个小时是常态。更麻烦的是命名规范。不同设计师习惯完全不一样有人喜欢叫“矩形1”有人叫“icon-购物车-48”前端拿到的资源命名乱七八糟还要自己猜到底是什么。手动切图本质上是一件高度重复、低创造性、又特别容易出错的机械劳动但这件活儿对准确率的要求还特别高切错一个坐标前端还原页面时就会糊。1.2 LLM带来的新变量是什么传统自动化工具解决的是“已经知道要切什么但不想手动做”的问题所以要人工先把要切的区域圈出来工具只负责执行导出动作。但LLM解决的是完全不同的一个问题它能不能直接看懂设计稿的视觉结构自主判断哪些区域应该成为独立的切片并且把切片的语义、尺寸、层级关系一起给出来。这在两年前是想都不敢想的。过去的图像识别模型擅长的任务是“图里有什么”给它一张UI截图它能识别出里面有个按钮、有商品图、有导航栏但没办法把每个元素的位置和大小精确框出来当作切图坐标。现在的多模态大模型视觉理解能力和结构化输出能力都上了一个台阶理论上它能看到整个页面理解层次关系然后把坐标、尺寸、类型、命名全部结构化输出。这个能力一旦成立等于把“看图理解结构”这一步自动化了切图这个环节的人力和时间成本会大幅下降。1.3 查了一圈资料之后的判断正式动手之前我先花了一个晚上调研目前已有的方案和资料。当时翻了不少关于大模型原理的讨论和实验笔记留意到几个有意思的点一是大模型的图像理解本质是“语义空间里的推测”它不是像人眼一样通过像素去精确定位而是更像“理解了一个页面大概长什么样再按语义去猜位置”这种模式决定了它在粗粒度识别上很强但在像素级精确上天然偏弱。二是结构化输出对大模型来说属于强项只要Prompt写清楚要求的JSON格式它就能稳定返回组织良好的数据。基于这些信息我对实验做了一个预判用LLM直接切图标和色块这种大区域应该可行但切尺寸严格、需要像素级精确的资产大概率会有偏移。实验目标定在不追求一步到位做生产工具而是先跑通流程、量化能力边界摸清楚哪些环节可以留给LLM哪些环节必须靠脚本校正。这个定位让整个实验的路径变得非常清晰。2. 方案设计与技术选型2.1 核心设计让模型输出结构而不是让它直接裁图实验最开始我有过一个想法直接把设计稿截图丢给模型让它返回一张切好的图片压缩包。试了一次就放弃了大模型确实可以返回图片但那是生成的“新图”不是从原图里切出来的精确像素区域对于生产来说毫无意义。后来我把方案改成了一个更务实的架构模型只负责“理解和规划”脚本负责“执行”。具体来说LLM需要输出一份结构化的JSON里面有每个切片的名称、类型、边界框、缩放建议和层级关系然后由Python脚本读取这份JSON把边界坐标映射回原始设计稿用图像处理库完成裁切、导出。设计稿截图 - LLM理解和规划 - 结构化JSON切片坐标类型命名 | v 原始高清图 —— 坐标映射与缩放补偿 —— Python脚本批量裁切这样设计的核心考虑是让每一步都做它最擅长的事。LLM的强项是语义理解和判断它知道这块区域应该叫product_image还是price_text知道哪些图层应该合并成一个卡片而裁切需要的是像素级精度这件事交给图像处理库做再可靠不过。模型在虚拟坐标系里输出相对位置脚本再换算成真实像素误差控制在自己手里。2.2 模型选型三类视觉模型的对比实测实验里我同时测了三类模型分别是闭源商业模型、开源社区模型、以及针对视觉任务微调的专用模型。要说明的是这里的测试结果只是我基于当时API服务的实际表现不构成权威评测但方向上对选型有参考价值。模型类型视觉理解能力结构化输出稳定性单次调用成本坐标偏差情况闭源旗舰多模态模型最强能理解复杂布局嵌套稳定很少多字段漏出较高粗粒度准确像素级常有2%~5%偏移开源7B级别视觉模型能识别图标和区块复杂卡片结构吃力一般需要多次解析修正低偏移较明显卡片内部元素容易混专用视觉定位模型识别精度高但语义理解弱好中定位表现好但命名和分类基本靠规则补实际跑完一轮后我的选择是主模型用闭源旗舰模型做语义规划因为它的命名质量和对复杂结构的判断远超其他两类坐标精度靠后续脚本补偿。开源模型很适合批量处理海量设计稿的初筛阶段成本低但命名和分类结果基本不能直接用。专用模型在这个场景里的定位比较特殊适合对位置要求高但结构简单的场景比如单独切图标。2.3 为什么不能让模型直接返回像素坐标这里有个非常重要的设计决策我不让模型在原图纸素坐标系里返回坐标而是让它在一个0到1000的虚拟坐标系统里工作。原因很简单模型看到的输入图通常是经过缩放的。我把1440像素宽的设计稿截图压缩到1024像素甚至更小喂给模型如果让模型直接返回“x356, y728”它返回的数字是基于缩放后图像的直接映射回原图会有偏差。更麻烦的是不同模型对同一张图的内部表示方式不一样有的模型视觉编码器会把图切成固定网格像素坐标本身就带上了网格偏差。干脆让模型在虚拟坐标里框选再由脚本按比例映射反而更稳定。原图宽度1440输入模型时缩放为900。 模型在虚拟坐标系0~1000内返回某个图标的bbox为 { x_min: 235, y_min: 600, x_max: 302, y_max: 667 } 映射回原图的公式 真实x 虚拟x / 1000 * 1440 235 / 1000 * 1440 338.4 真实y 虚拟y / 1000 * 设计稿高度假设2560 600 / 1000 * 2560 1536这个换算简单到不能再简单但它规避了所有因图像缩放和模型内部预处理带来的坐标漂移问题。后面实验数据的偏差控制很大程度归功于这个“虚拟坐标系”的设计。3. 实验过程与核心实现3.1 测试素材准备怎么挑设计稿最能测出水平素材选择直接决定实验结论是否可信我特意准备了四种类型的UI页面一张PC端数据后台Dashboard特点是卡片多、表格多、信息密度高顶部还有侧边导航和多级筛选器适合测试复杂结构的拆解能力。一张移动端设置页元素密集但类型单一有大量的开关、列表项、头像和分组标题适合测细粒度图标的识别。一张电商详情页有大图、价格区、促销标签、规格选择、底部固定购物栏元素大小跨度极大适合测多尺度场景。一张我故意做了嵌套阴影和半透明叠加层的设计稿很多图层视觉上是重叠的适合测试模型对图层物理边界的判断。这四类页面基本覆盖了日常切图的典型场景。为了让结果对比更有说服力我还同时准备了一份“标准答案”所有目标切片区域都是我在Figma里手动框选导出的坐标用像素级工具标注出来作为脚本跑分的Ground Truth。3.2 Prompt模板把要求写清楚比什么都重要Prompt是整个实验里性价比最高的优化点同一个模型Prompt写不写清楚输出的可用率能差出三倍。我最终的Prompt模板是反复迭代出来的核心诉求有四个输出格式必须严丝合缝、切片类型必须语义化、坐标必须按虚拟坐标系返回、每个切片必须给出置信度。你是资深UI切图专家。下面会给出一张完整的UI设计稿截图。 请你把这张界面中所有需要单独导出给前端使用的图片资源列出来 包括但不限于图标、图片、按钮背景、卡片背景、logo、插画、装饰元素。 要求 1. 只输出JSON数组不要输出任何解释性文字。 2. 每一项结构如下 { name: 英文小写语义化命名比如product_image、icon_cart_48、btn_bg_primary, type: icon | image | button | card | logo | illustration | decoration, bbox: {x_min: 0, y_min: 0, x_max: 0, y_max: 0}, scale_suggest: 1x或2x或3x, confidence: 0到1之间的小数 } 3. bbox坐标系为0~1000的绝对虚拟坐标左上角是(0,0)右下角是(1000,1000)。 请严格按视觉边界框选不要包含外间距。 4. 对视觉上嵌套的元素只要它在界面上能看见、能独立使用就单独列出来。 5. 对于纯文字、分割线、纯背景色块不需要切图不要输出。 6. 同一类型、同一尺寸的图标如果出现三次以上只输出一次并在name里加后缀批量标记。 现在请开始分析这张设计稿。几个细节值得展开说一下。第三点“不要包含外间距”很关键模型默认会把元素的外边距甚至阴影区域一起框进去加上这句话后框选结果明显干净很多。第四点解决了嵌套切图的问题比如一个卡片背景里有张商品图和一个标签设计上它们可能是同一个父图层组但切图时卡片背景、商品图、标签要各自独立切片这句要求就是让模型把嵌套内部的可见元素拆出来。第五点是减少无效输出裸文字和分割线在CSS里可以实现不需要图片资源。第六点则是偷懒神器很多后台界面有几十个同尺寸图标让模型只输出一个代表再加批量标记脚本里就能自动生成整批图标。3.3 坐标补偿与可视化校验先画出来看再决定要不要切拿到模型返回的JSON之后我不会直接拿去切图而是先做一次可视化校验。脚本会把模型返回的每个bbox画在原图上生成一张红色矩形框的标注图我用眼睛快速扫一遍框的位置准不准、有没有漏掉关键元素、有没有把两块区域合并成一个框基本一眼就能看出来。这个环节帮了大忙。第一轮跑完Dashboard的顶部导航和侧边栏被模型识别得很干净但页面中间几个卡片明明视觉边界很清楚模型的框却明显偏了右边界多框了一大截把相邻卡片的边缘也圈进去了。后来排查发现这几个卡片在虚拟坐标系里的边界本身没问题问题出在截图压缩后几个卡片之间的留白区域太小模型在低分辨率下把两个卡片的视觉边界混在一起了。解决办法分两层。第一层是把截图按区域切块每块放大后再单独让模型识别小区域内的相对坐标精度会明显提升第二层是在JSON里增加了一个padding字段允许脚本在裁切时做边缘收缩把模型框选时可能多包含的外边界统一裁掉。# 可视化校验脚本核心片段 import json import cv2 from PIL import Image, ImageDraw image Image.open(design_preview.png) draw ImageDraw.Draw(image) with open(llm_output.json, r, encodingutf-8) as f: items json.load(f) scale_x 1440 / 1000 # 原图宽/虚拟坐标 scale_y 2560 / 1000 # 原图高/虚拟坐标 for item in items: box item[bbox] x1 box[x_min] * scale_x y1 box[y_min] * scale_y x2 box[x_max] * scale_x y2 box[y_max] * scale_y draw.rectangle([x1, y1, x2, y2], outlinered, width3) draw.text((x1, y1 - 12), item[name], fillred) image.save(visual_check.png)可视化产出之后我还会跑一个比对脚本把模型坐标和Figma里手动框的标准坐标求IoU交并比。IoU超过0.85的视为优秀0.7到0.85的视为可用低于0.7基本就要靠后处理去修了。统计下来第一轮优秀率只有四成左右低得可怜但这也是整个实验最有价值的起点。3.4 批量裁切脚本从JSON到PNG的最后一步可视化校验通过之后就进入真正的裁切环节。我写了一个Python脚本完成整条流水线读取JSON、换算坐标、执行裁切、按命名规则保存、输出2x和3x两套尺寸。import json import os from PIL import Image output_dir ./slices os.makedirs(output_dir, exist_okTrue) image Image.open(design_fullhd.png) img_width, img_height image.size scale_x img_width / 1000 scale_y img_height / 1000 with open(llm_output.json, r, encodingutf-8) as f: items json.load(f) for item in items: box item[bbox] left int(box[x_min] * scale_x) top int(box[y_min] * scale_y) right int(box[x_max] * scale_x) bottom int(box[y_max] * scale_y) # 边缘收缩修正 shrink 4 left, top left shrink, top shrink right, bottom right - shrink, bottom - shrink cropped image.crop((left, top, right, bottom)) base_name item[name] # 1x切图 cropped.save(os.path.join(output_dir, f{base_name}.png)) # 2x切图特殊处理 w, h cropped.size if item.get(type) in (icon, logo): cropped_2x cropped.resize((w * 2, h * 2), Image.LANCZOS) cropped_2x.save(os.path.join(output_dir, f{base_name}2x.png))这里有一个值得注意的细节脚本里只对icon和logo类型做了2x放大其他类型直接导出1x。原因是UI切片里只有图标和Logo这种矢量类元素需要2x甚至3x的尺寸来适配不同分辨率的屏幕图片类的切片本身就是位图设计稿给多大就用多大强行放大只会糊。这个判断来自Prompt里给模型定义的scale_suggest字段模型对每个切片都给出了缩放建议脚本再根据建议决定导出策略。3.5 首轮跑分结果看完数据我沉默了第一轮完整实验一共处理了4张设计稿模型返回了127个切片项和人工标准答案对齐后的统计结果如下指标PC后台Dashboard移动端设置页电商详情页复杂叠加设计稿人工标准切片数34513822模型输出切片数41474417命中率识别到且类型正确79.4%82.4%73.7%59.1%平均IoU0.720.830.680.51命名直接可用率61.8%64.7%55.3%45.5%数据能说明几个问题。移动端设置页的表现最好因为结构规律、元素排列整齐、图标边界清晰识别率和坐标精度都高。电商详情页差一些主要坑在商品大图区域模型经常把一整块商品展示区拆成好几个不存在的切片或者把促销标签和价格文字合并成一个切片。复杂叠加设计稿直接翻车IoU只有0.51说明当图层有阴影、半透明、视觉重叠时模型的边界判断能力明显不够用。4. 常见问题与排查心得4.1 坐标偏移为什么这么顽固坐标偏移是整个实验里最折磨人的问题。我把每次裁切结果和人工标准坐标叠加后发现偏移不是随机分布的而是有系统性的规律模型框选的位置整体偏向元素中心靠拢特别是对面积较大的卡片区域框会“内缩”而对尺寸较小的图标框又会“外扩”一点。这个现象背后的原因后来我理解为是模型的视觉编码器在处理图像时天然带有注意力中心化的倾向它“看到”一个元素时会优先聚焦在语义最突出的部分。像一个卡片模型关注的是里面的大标题和主要图片对卡片边缘这类低语义密度的区域就不敏感导致框选范围偏保守。文字和图标这种独立语义元素注意力集中模型就会把周围的留白也一起算进去造成外扩。应对方式我总结出三招。第一招是区域切块放大。把一张1440宽的设计稿横向切成三段每段单独送进模型识别相当于让模型在更高分辨率下“看”局部框选精度能提升两到三个百分点。第二招是锚点校对让模型先识别页面四个角落的标志性元素用它们的坐标反推虚拟坐标系和原图的映射关系再做一次线性回归校正。第三招最简单也最暴力针对某一种固定版式的页面先跑一批数据统计出平均偏移量直接在脚本里做反向补偿。4.2 图层命名混乱模型给的名字能不能直接用模型返回的命名第一眼看过去挺像那么回事但细看问题很多。比如它会给同一页面里的多个商品图都命名成product_image不会自动加序号给图标命名时会出现icon_search_blue_large这种把视觉特征全塞进去的长命名最头疼的是同一个元素在不同轮次实验里可能被命名成完全不同的词btn_bg_primary和button_background_normal指的根本是同一个东西。命名问题是这个方案能不能进入生产环境的关键因为切图资产最终是给前端用的命名不稳定比切歪几张图更致命。我的解决方案是给模型加了一层“命名词表约束”在Prompt里附上一份规范化的命名清单包含动词和名词的可选范围比如图标必须用icon_开头、按钮类必须用btn_开头、商品图统一叫product_image_序号。加了词表约束之后命名的稳定率从六成左右提升到了八成以上虽然还不能完全替代人工审核但已经减少了大量来回沟通的成本。4.3 成本与超时一次完整切图到底花了多少钱和时间成本问题在实验里无法回避。旗舰模型的单次调用要同时处理设计稿图像和输出一大段JSON尤其设计稿信息密度很高的时候输出token数量会暴涨。统计下来处理一张密集的Dashboard设计稿单次调用大约消耗1万到1.5万输入token和3000到5000输出token按当时的API计价一张图切图过程的视觉理解成本大概在几毛钱到一块钱人民币之间。四张设计稿做完总花销不到五块钱。时间上更可控。模型从收到截图到输出完整JSON平均耗时在10秒到25秒之间比人工框选快得多。把脚本裁切、可视化校验的时间加起来一张设计稿全流程大约能在1分钟内跑完即使加上人工过一遍标注图的时间也比从零开始手动切快上一个数量级。不过这里有个大坑模型对超长JSON的输出容易在中途截断特别是页面元素特别多的时候输出到一半断了整个JSON无法解析。我踩过这个坑后给脚本加了重试机制检测到JSON解析失败就自动重发一次请求并且把Prompt里多加了“继续输出上一轮未完成的List”的指令勉强把成功率拉回到了九成以上。4.4 识别幻觉模型会切出根本不存在的图层实验里最让设计师崩溃的问题是幻觉。有一次模型对着一张没有底部栏的设计稿硬是生成了一个bottom_nav_bar坐标还有模有样地框在页面最底部。还有一次它把深色页面里的一个装饰性背景纹理识别成了图片资源但实际上那是CSS渐变就能实现的效果。这类幻觉有两个主要来源。一是模型对常见UI模式有强先验它“知道”电商页面应该有底部导航于是即使截图里没有它也会“脑补”出来二是模型对装饰性元素和功能性元素的边界判断不清它看到一块有纹理的区域就会默认这是资源图片。我的解决方案是在Prompt的负向清单里明确写了“不需要切图的内容”把纯文字、分割线、背景色块、阴影、线性渐变这些通通列为禁止输出项。效果立竿见影幻觉产生的无效切片数量下降了将近一半。另外我也学到一个调参技巧可以把返回字段里的confidence用起来设定一个0.55的阈值低于这个置信度的切片直接丢弃。代价是有时候会误伤真实切片但比起让前端拿到错资源来说宁可少切一点后续人工补也不能多给一堆幻觉资产污染资源目录。5. 可行性结论与扩展思路5.1 这套流程的真实能力边界所有实验数据收完之后我对“用LLM直接做UI图层切图”的判断是粗粒度可用细粒度不可用内部工具可用对外交付不可用辅助可大幅提效全自动替代还差一条鸿沟。具体拆开说边界大概在四种场景里显得特别分明。小尺寸独立元素比如图标、小按钮、段落的背景块模型识别率和坐标精度都很好结合脚本修正后基本能直接用。中等尺寸的语义区域比如卡片区域、图片占位区、弹窗容器模型的命中率可观输出可以作为草稿给人工筛一遍。大尺寸复杂区域和多层叠加的场景目前能力不足识别结果即使修了坐标也难以保证切出来的视觉还原度。最后一类严格规范场景比如需要逐层叠加阴影、一个按钮切成多层背景资源、或者设计系统里有明确切图规范的LLM目前完全无法胜任建议直接放弃。我自己的判断是这个方案现阶段最适合的场景是“快速把设计稿变成可用的前端资产草稿”它能把最烦人的体力活先干完把设计师从重复劳动里解放出来让设计师把精力花在整理、规范和校验上而不是花在框选、命名的原始操作上。5.2 能落地的三条路径实验做完后我认真想过落地路径目前最可行的是三个方向。第一个方向是Figma插件。在Figma里直接读取设计稿的图层信息和位图数据调用LLM API生成切图规划再调用Figma的导出接口把切片输出到本地。这个路径能让设计师完全不离开设计工具交互最顺滑。严格来说Figma本身有图层数据接口既可以把图层树结构发给模型辅助判断也可以用位图做视觉识别双通道输入理论上效果比只用截图更好。第二个方向是UI自动化测试断言生成。切图规划和组件识别能力实际上也是在识别UI结构这个能力在UI自动化测试里同样成立模型能帮测试工程师批量判断页面结构是否符合设计稿自动化测试脚本从“手动写断言”进化成“比对模型结构输出”。实验里的JSON结构化输出天然就是一份可解析的UI组件清单。第三个方向是前端代码生成的前置环节。LLM返回的切片不仅包含坐标还包含类型、层次和命名这些东西揉在一起就是一份半成品的页面结构描述。让模型在切图的同时输出每个区块的CSS建议前端拿到切图的同时也拿到布局草图开发效率可以再往前提一截。5.3 后续还能怎么玩把设计规范喂进去如果要把这个实验继续深化我最想做的改进是把RAG接进来。现在的模型完全依赖通用知识做判断它对“哪些元素该切”的理解是来自海量网页的通用经验而不是你团队的设计规范。如果把公司设计规范文档、历史切图资产清单、组件库命名规则提前切好块灌进知识库再让模型在生成切图方案时先检索匹配的规范条目输出的命名和分类会更贴合团队习惯。我在实验里用简单的方式验证过这个方向的有效性。我在Prompt里直接粘贴了一段简短的命名规范和必须切图的元素清单模型的命名可用率立刻提升了十几个百分点。这说明模型不是不理解规范而是之前没人告诉它规范是什么。RAG把这件事从手工粘贴提升成了自动检索效果理论上会更好。再往后一步想这类能力还可以和设计稿版本管理结合起来。每次设计稿更新模型只对比新旧版本的切片差异只重新切变化的区域形成增量切图那效率还能再上一个台阶。这些都是后话但方向已经通过实验验证了是通的。跑完这轮实验我最大的感受是LLM做UI切图最强的不是“切图”这个动作本身而是在切图过程中暴露出来的对页面结构语义的理解能力。它能告诉你这张图里什么重要、什么可忽略、元素之间怎么组织信息密度远高于一张导出好的PNG。所以就算切图这个任务最终被传统工具或其他方式替代让模型参与UI结构理解的思路也不会过时。我最后给自己留下了一个习惯每跑完一批设计稿把模型识别失败的案例截图存档把它们当作下一轮实验Prompt里的反面例子。这比调什么参数都管用。