布局算法篇 - 设计稿生成代码 Imgcook 3.0 系列

文/ 阿里淘系 F(x) Team - 琻中 、民超前端

背景介绍

布局还原是 D2C 整个链路偏核心的部分。在布局部分,imgcook 使用一套布局算法将设计稿图层转换为合理的布局结构,从而生成更加“开发友好”的、拥有层级关系的树状结构(例如 页端的DOM结构 或是 Native 开发的 XML 描述体)。算法

在布局部分以前,插件会将整个视觉稿结构化,获得一份记录了每一个元素的绝对位置、大小、样式的扁平化 JSON。经过这份扁平的 JSON 咱们能精准还原整张视觉稿。可是,在平常开发中,组件与组件之间的关系并不是扁平的绝对定位,而是更加复杂的关系:例如包含与被包含、同一模块的反复使用、同一模块的不一样逻辑状态等等(以下图)。所以,布局算法须要进一步升级,拥有支持这些复杂布局的能力。数组

(“双十一猜你喜欢” 中的循环体)

(“双十一笔笔返“ 中的多态)

问题分析

从如下「UI 信息架构图」来看,一个页面自上而下被细分为 6 层。从设计稿中,咱们只能获得_元件_级别的信息。为了使 imgcook 生成的页面结构更加符合前端开发者的编码逻辑,布局算法须要具有将一些元件组合起来,造成组件、区块或模块的能力。markdown

(UI 信息架构图)

所以,咱们使用了如下几个方案来结构化 schema 的生成:网络

  • 页面分割(把页面分割成不一样的子模块)
  • 成组(决定子模块内组件的包含与被包含关系)
  • 循环(决定子模块内相同组件平铺堆叠的逻辑关系)
  • 多态(决定子模块内同一组件的不一样状态的逻辑关系)

以此为框架,imgcook 致力于推进布局向智能化的方向发展,使最终生成的代码更加符合开发者预期,对开发者更加友好。数据结构

技术方案

在下面几章节中,我将着重介绍「页面分割」、「循环」与「多态」的能力。在 imgcook 的发展历程中,咱们会渐渐使用更加智能化(能力分级更高的阶段)代替以往纯手写纯干预的过程,从而让整个还原链路具有更大的拓展性与泛化能力。可是,鉴于智能化模型在极端的状况不能 100% 精准,咱们仍是会保留低分级阶段的能力以确保主链路的「鲁棒性」。多线程

(布局还原阶段的智能化能力分层)

页面分割

首先是页面分割,当使用 imgcook 对整个页面进行还原时,咱们会对页面进行切割,把一整个页面切分红几个模块来维护。架构

L1 阶段人工辅助生成:设计稿模块协议

在设计稿中,用户能够经过设计稿协议手动将页面分割成指定模块,以此来增强对页面分割的干预。在对应模块的中加入 #module:Name# 的协议,便可将对应的部分转换成模块(以下图)框架

(标注部分)

最终生成(见左边组件树,模块被识别)

L2 阶段规则自动生成:结构化数据分割算法

为了减小人工干预,提升自动识别分割的能力,咱们经过规则匹配相邻的元素,以此来判断这些元素是否属于同一个子模块。算法会查询全部相邻行,并将大型块状结构则合并。具体的效果以下图所示:编辑器


L3 阶段智能辅助生成:CV 边缘检测

不过,基于规则的页面分割缺少泛化能力(只有文字与图片的的边缘才能被识别为同一模块)。在实际的应用过程当中没法取得很是好的效果。所以咱们推出了第二版,经过计算机视觉来智能地分割模块。咱们使用 CV 对设计稿进行像素级别的对比,来加强识别的泛化度。


然而,从上图能够看出:目前基于 CV 的边缘检测虽然比规则具备更强的识别与泛化能力。可是:

  • 像素级别的分割可能会过分分割,将本来不该该被拆开的部分拆成两个模块(例如:标题栏和内容部分);
  • 另外,基于像素级的检测对服务端性能的要求很是严苛。据实验数据,在 8 核多线程环境下,一张页面设计稿须要 2 秒才能完成检测。这对于整个还原链路来讲,耗时仍是很是高的。所以,接下来咱们计划经过将图片降维、池化等方式减小像素数量,从而下降运算的成本,以提升识别的效率。

循环识别

循环布局是界面设计特别经常使用的一种布局模式。好比(卡片)列表、导航tab、轮播组件都用到了循环的结构。在写码的过程当中,合理使用循环可使代码结构更加合理,又能极大地提升代码效率。例如如下案例,咱们只需实现一个子组件,并将子组件垂直循环就能获得一个完整的列表组件(以下图):


生成一个循环布局主要经历了三个阶段:
  • 识别阶段
  • 标注阶段
  • 生成阶段

在识别阶段,咱们经过算法、模型等方法将循环体从整个 schema 中提取出来;在标注阶段,咱们会筛查循环体中的循环元素,并给他们标上序号和循环惟一表示;最后,逻辑库会将全部筛查出循环体绑定上循环变量并批量生成。

在本章节中,咱们着重介绍循环的第一个阶段 —— 识别阶段。

识别方案


循环的识别部分位于整个还原链路的最后部分(以下图所示)。在布局算法进行到最后阶段时,元素与元素之间的嵌套层级关系已经趋于稳定,这时候的 schema 即可用于循环的识别计算。

L1 阶段人工辅助生成:设计稿循环协议

做为基础标注能力,imgcook 提供节点打标的方法,能够强制将某些元素识别成循环。只须要在设计稿软件中将循环元素前加上连续的 #loop# 标签,便可在还原时被识别为循环子元素(以下图)。在以下标注下生成代码,便可获得一个 “5循环节点”。



L2 阶段规则自动生成:循环检测算法

在识别循环以前,首先须要了解为何会有循环布局?前端的循环布局很大程度上由其对应的服务端抽象数据结构有关。在电商行业(尤为是手淘)中,大多数商品都以列表或者feeds流的形式展现,对应到抽象数据结构中就是 ArrayList。所以,类似的数据结构在同一个组件中对应的前端样式也是以循环呈现。


了解了以上背景,不难推出,循环布局通常都具备如下特性:
  • 循环的元素通常都在同一父节点下。
  • 循环的元素通常具备类似的形状、样式属性。

拿营销域下很是常见的卡片式商品举例(以下图),每一张商品卡片都具备相似的布局:正方形头图,大字号标题,描述性文字,清晰可辨的行动点。


所以,咱们推出了初版的循环识别算法:首先遍历全部的父级元素,对全部父元素的直属子节点进行初步的筛选。初步筛选以后,咱们获得了一组内部可能存在循环结构的父元素的集合。接下来,咱们会扫描每个可能存在循环结构的父元素的子元素,并计算它们之间的差别。若是该父元素下的子元素几乎没有布局与样式上的差别,那它极有可能就是循环布局。最后,咱们将全部循环元素打上标记,并交由业务逻辑库作统一的出码处理。

L3 阶段智能辅助生成:循环识别模型算法

L1和L2阶段均是基于规则的一种人为定义的节点遍历算法,基于规则的方法必然不能处理不符合规则的状况。为此D2C把目光移到当前如火如荼的人工智能领域,利用深度学习中的特征提取能力,但愿从海量的数据中找出布局特征,实现端到端的布局识别能力,下降甚至没有人为定义的规则。

经调研,生成对抗网络做为一种新颖的数据生成模型在AI界脱颖而出,在智能布局识别算法中本文引入了当前CV界火热的生成对抗网络,期待生成对抗网络可以找出布局规律特征,将同一布局里全部元素进行风格转换。下面详细介绍本文的工做原理与实践经验。

条件生成对抗网络

大名鼎鼎的谷歌科学家Goodfellow在2014年提出了重量级的深度学习模型:生成对抗网络(Generative Adversarial Networks,GAN),GAN做为一种优秀的图像生成算法成为当前无监督学习中最具前景方法之一。GAN中有两个组件:生成器G(Generative Model)和判别器D(Discriminative Model),生成器负责生成符合真实数据分布的合成数据,判别器负责判别数据的真假,两者互相博弈,互相提高各自的能力。因为深度卷积神经网络能够拟合任意函数,故常被应用于生成器和判别器设计中。GAN的原理框架以下:


上图中,随机噪声z做为生成器G的输入,生成器输出合成数据G(z);判别器判别输入数据是否为真,输入数据为真实数据x时输出为D(x),输入数据为生成器生成的合成数据时输出为D(G(z))。GAN的损失函数数学建模以下:

由上式可知GAN一方面要加强判别器的判别能力,另外一方面要加强生成器生成逼真数据能力,在GAN的训练过程当中二者不断进行对抗进而提高各自的能力,最终二者处于一种动态均衡:生成器可以生成逼真的合成数据;判别器没法将生成器生成的合成数据和真实数据区分开来,即对输入数据判别为真的几率基本为50%。

条件生成对抗网络(Conditional Generative Adversarial Networks,CGAN)技术是GAN技术的一个进化版本,可以根据输入条件生成符合真实数据分布的合成数据,其在原有GAN基础上加入了监督信息。具体为:传统GAN从随机向量z(噪声)中学习到图像y:G:z->y;与传统GAN不一样的是CGAN直接从条件图像中学习到一种映射,即s:G(y,z)->s,式中y为条件图,s为生成器生成的合成图。

模型训练与实践

数据集制做: 首先进行数据集制做,对同一组的布局进行风格转换,对应的标签是一种大白块风格。生成后的一张训练数据展现以下:

模型训练: 接着利用算法pix2pix对模型进行训练,训练过程当中的生成器和判别器loss变化以下图,可知两个网络loss均已收敛,训练完成。


效果展现: 随机从测试集中选取图片进行测试,测试结果证实了模型有效。




(识别效果)

由上图可看出模型将图片里的每组用一块白色区域代替,布局分组成功。

表达方案

当循环在布局算法识别以后,在 schema 的 smart.repeat 字段下,就会被标注循环体信息。信息描述了具体哪些元素是在一个循环体中的,每一个元素分别对应循环体的第几位,等等。

最后在逻辑库中,imgcook 会用 Array.map 的形式将一个数组映射到组件中。在以下的例子中,一个商品列表被循环生成:


多态识别

除循环布局之外,多态(multi-status)也是前端编码中很是重要的一环。一个元素在不一样的状态下可能会有不一样的展现状态与行动状态。例如,在以下物品卡片的案例中,针对是否有货,右下角的“购买”按钮有 3 种不一样的状态:“暂时无货”,“马上预定” 和 “马上下单”。它们有类似的外观,位置和布局,可是,它们也有部分差别:

  • 展现差别(颜色、长短、背景图)
  • 逻辑点差别(点击后执行的逻辑代码不一样)

这样的前端模式被称之为多态,而 imgcook 也在逐渐强化本身识别多态的能力


在 2020 年,imgcook 支持了多态识别的 I1 和 I2 部分能力,可以

识别方案

L1 阶段人工辅助生成:设计稿多态协议

除了算法识别以外,咱们还提供了人工标注的方法,以便在算法未能精准识别时,手动干预生成多态。在 imgcook 的菜单中选择「生成元素多状态」(或者使用快捷键 Ctrl + Shift + M)便可将多个元素绑定为某一个元素的多种状态,从而在布局算法中被识别为多态元素。


L2 阶段规则自动生成:多态检测规则算法

多态识别算法采用了和循环识别相似的逻辑。首先,它位全还原链路的最后一层,它可以将同一个元素的不一样状态提取出来,并进行统一的样式修正与状态的还原和绑定。


  • 首先找到同一个容器的不一样状态,并分析它的子元素
  • 找到布局位置相近的子元素,分别检测他们是否有多种状态
  • 若子元素存在样式差别则,且经过类似度计算得出他们类似但不相同,则标记为多态
  • 最终,将拥有多态的子元素抽离,并合并不一样状态的样式布局

算法的可视化部分能够参考如下动图:


这样,咱们就能从视觉稿中提取出一个元素具备的多种状态,并将它们统一合并在一块儿。对于前端而言,只须要传入对应状态的参数便可控制展现状态,从而实现研发提效。

L3 阶段智能辅助生成:多态识别模型算法

目前,咱们正在推动多态从 I2 到 I3 发展,使用模型的方法来识别设计稿中可能存在的多态。


imgcook 设计了经过 [YOLO](https://en.wikipedia.org/wiki/Object_detection) 提取设计稿中的类似元素,而且分析它们之间的语义相关性来判断这些组件是否构成多态。它的主要流程以下:
  • 将整个设计稿做为图像信息输入;
  • 经过 YOLO 目标检测输出可能存在多态的元素簇;
  • 对各元素簇内的元素进行语义类似度计算。

表达方案

当多态在布局算法识别以后,在 schema 的 smart.layerProtocol.multiStatus 字段下,就会被标注多态信息。信息描述了具体哪些元素是在一个多态簇中的,每一个元素分别对应多态的的第几个状态。

最后在逻辑库中,imgcook 会用 condition 字段将每一个状态的展现条件映射到抽象的逻辑数据中。绑定了 "condition" 字段以后,就能够经过切换不一样的数据来预览不一样状态下模块的样式/逻辑(以下图)。


布局可维护性度量

在不断优化布局算法的同时,咱们须要一套体系来衡量算法对整个还原链路的优化程度:咱们的算法与模型优化对生成的代码到底有多大帮助?这些优化的是否合理?是否真正作到了研发提效?因而咱们推出了 2 种布局可维护性度量方案,来评估布局还原的准确度:

  • UI 还原度量:度量通过布局算法后视觉效果上是否 100% 还原。
  • 布局可维护性度量:根据用户最后保存的 schema 度量生成的布局结构的合理性。

UI 还原准确度

UI 还原度量将设计稿原图片与布局还原后的 schema 通过 DSL 出码后渲染的视图作 CV 对比,以视觉类似度与 DOM 结构复杂程度做为判断标准计算的还原度量。


目前 62,807 次的 UI 布局还原平均分值是 92.1%, 其中 Sketch 设计稿还原平均准确度是 92.45%, PSD 设计稿还原平均准确度是 88.21%。准确度低的主要缘由在于缺少自动判断非 box 类元素的宽高的能力,例如没法判断艺术字的合理宽高而生成错误的 box size,须要手动调整。

可是,UI 还原度量只能衡量渲染出来的 UI 和视觉稿的一致程度,不能确保代码结构的合理性,所以咱们还须要另外一种能够度量布局结构的可维护性的方式:

布局可维护性

在布局可维护性度量中,咱们将布局还原生成的 schema 与用户在编辑器内修改后最后保存的 schema 进行差别对比,经过计算用户改动量来推测还原效果以及可用率。

schema 变动会有 4 种可能:节点变更、位置变更、样式变更、属性变更。其中,后两种为通常能力,对布局影响不大;而前两种,为布局算法的核心能力。因此,在计算可用度时,前者的权重高于后者。以后,只要将变更部分的比例整合,便可计算出总体可用率。

咱们定义了计算布局还原可维护度的公式:



由此能够得出每棵子树的变更率,以及整体变更率。这种可用度度量方式能够更显式地反映用户在使用 Imgcook 时遇到的问题,例如节点名称、样式、DOM 结构的改变。
(可布局变更查看面板)

除了字段绑定、节点属性、样式的变化,在最后保存时还删除了大量循环节点,但这些循环节点并非由人工删除,而是在布局还原阶段识别了循环以后,在后面的业务逻辑生成阶段自动删除。

2020 年双 11 大促会场中,带循环体的模块占新增模块 67.31%,在布局还原阶段循环被识别的模块占比 43%,业务逻辑生成阶段根据布局识别结果自动删除多余的循环体并生成循环结构代码。



F(X)Team 开通 微博 啦!
除文章外还有更多的团队内容等你解锁🔓
相关文章
相关标签/搜索