摘要: UI2CODE项目是闲鱼技术团队研发的一款通过机器视觉理解+AI人工智能将UI视觉图片转化为端侧代码的工具。

背景:

随着移动互联网时代的到来,人类的科学技术突飞猛进。然而软件工程师们依旧需要花费大量精力在重复的还原UI视觉稿的工作。
UI视觉研发拥有明显的特征:组件,位置和布局,符合机器学习处理范畴。能否通过机器视觉和深度学习等手段自动生成UI界面代码,来解放重复劳动力,成为我们关注的方向。

UI2CODE简单介绍:

UI2CODE项目是闲鱼技术团队研发的一款通过机器视觉理解+AI人工智能将UI视觉图片转化为端侧代码的工具。

2018年3月UI2CODE开始启动技术可行性预研工作,到目前为止,经历了3次整体方案的重构(或者重写)。我们参考了大量的利用机器学习生成代码的方案,但都无法达到商用指标,UI2CODE的主要思想是将UI研发特征分而治之,避免鸡蛋放在一个篮子里。我们着重关注以下3个问题的解法:

  1. 视觉稿还原精度:我们的设计师甚至无法容忍1像素的位置偏差;
  2. 准确率:机器学习还处于概率学范畴,但我们需要100%的准确率;
  3. 易维护性:工程师们看的懂,改的动是起点,合理的布局结构才能保障界面流畅运行。

UI2CODE运行效果:

UI2CODE插件化运行效果,如下视频:进过几轮重构,最终我们定义UI2CODE主要解决feeds流的卡片自动生成,当然它也可以对页面级自动生成。

视频地址:https://yunqivedio.alicdn.com/od/mm4Te1551157852340.mov

架构设计:

简化分析下UI2CODE的流程:

大体分为4个步骤:

  1. 1.通过机器视觉技术,从视觉稿提取GUI元素
  2. 2.通过深度学习技术,识别GUI元素类型
  3. 3.通过递归神经网络技术,生成DSL
  4. 4.通过语法树模板匹配,生成flutter代码

版面分析

版面分析只做一件事:切图。

图片切割效果直接决定UI2CODE输出结果的准确率。我们拿白色背景的简单UI来举例:

上图是一个白色背景的UI,我们将图片读入内存,进行二值化处理:

  1. def image_to_matrix(filename):
  2. im = Image.open(filename)
  3. width, height = im.size
  4. im = im.convert("L")
  5. matrix = np.asarray(im)
  6. return matrix, width, height

得到一个二维矩阵:将白色背景的值转化为0.

像切西瓜一样,我们只需要5刀,就可以将GUI元素分离,切隔方法多种多样:(下面是横切的代码片段,实际切割逻辑稍微复杂些,基本是递归过程)

  1. def cut_by_col(cut_num, _im_mask):
  2. zero_start = None
  3. zero_end = None
  4. end_range = len(_im_mask)
  5. for x in range(0, end_range):
  6. im = _im_mask[x]
  7. if len(np.where(im==0)[0]) == len(im):
  8. if zero_start == None:
  9. zero_start = x
  10. elif zero_start != None and zero_end == None:
  11. zero_end = x
  12. if zero_start != None and zero_end != None:
  13. start = zero_start
  14. if start > 0:
  15. cut_num.append(start)
  16. zero_start = None
  17. zero_end = None
  18. if x == end_range-1 and zero_start != None and zero_end == None and zero_start > 0:
  19. zero_end = x
  20. start = zero_start
  21. if start > 0:
  22. cut_num.append(start)
  23. zero_start = None
  24. zero_end = None

客户端的UI基本都是纵向流式布局,我们可以先横切在纵切。

将切割点的x,y轴坐标记录下来,它将是处理组件位置关系的核心。切割完成后,我们获取到2组数据:6个GUI元素图片和对应的坐标系记录。后续步骤通过分类神经网络进行组件识别。

在实际生产过程中,版面分析会复杂些,主要是在处理复杂背景方面。

关注我们的技术公众号,我们后续会详细分解。

组件识别:

进行组件识别前我们需要收集一些组件样本进行训练,使用Tensorflow提供的CNN模型和SSD模型等进行增量训练。

UI2CODE对GUI进行了几十种类型分类:IMAGE, TEXT,SHAP/BUTTON,ICON,PRICE等等,分别归类为UI组件,CI组件和BI组件。

  1. UI组件,主要针对flutter原生的组件进行分类。
  2. CI组件,主要针对闲鱼自定义UIKIT进行分类。
  3. BI组件,主要针对具备一定业务意义的feed卡片进行分类。

组件的识别需要反复的通过全局特征反馈来纠正,通常会采用SSD+CNN协同工作,比如下图的红色“全新“shape,这该图例中是richtext的部分,同样的shape样式可能属于button或者icon。

属性提取:

这块的技术点比较杂,归纳起来需要处理3部分内容:shape轮廓, 字体属性和组件的宽高。

完成属性提取,基本上我们完成所有GUI信息的提取。生成的GUI DSL如下图:

通过这些数据我们就可以进行布局分析了。
其中文字属性的提取最为复杂,后续我们会专门介绍。

布局分析:

前期我们采用4层LSTM网络进行训练学习,由于样本量比较小,我们改为规则实现。规则实现也比较简单,我们在第一步切图时5刀切割的顺序就是row和col。缺点是布局比较死板,需要结合RNN进行前置反馈。

视频地址:https://yunqivedio.alicdn.com/od/7DD7w1551157938106.mp4

视频中展示的是通过4层LSTM预测布局结构的效果,UI的布局结构就像房屋的框架,建造完成后通过GUI的属性进行精装修就完成了一个UI图层的代码还原工作。

代码生成及插件化:

机器学习本质上来说还属于概率学范畴,自动生成的代码需要非常高的还原度和100%的准确率,概率注定UI2CODE很难达到100%的准确率,所以我们需要提供一个可编辑工具,由开发者通过工具能够快速理解UI的布局结构和修改布局结构。

我们将UI2CODE生成的DSL TREE进行代码模板化匹配,代码模板的内容由资深的flutter技术专家来定义,它代表目前我们发现的最优代码实现方案。

代码模板中会引入一些标签,由Intellij plugin来检索flutter工程中是否存在对应的自定义UIKIT,并进行替换,提高代码的复用度。

整个插件化工程需要提供自定义UIKIT的检索,替换和校验工作,以及DSL Tree的创建,修改,图示等工作,总体来说,更像ERP系统,花费一些时间能够做的更加完美。

小结:

本篇我们简单介绍了UI2CODE的设计思路,我们将整个工程结构分为5个部分,其中4块内容核心处理机器视觉的问题,通过机器学习将它们链接起来。代码的线上发布是非常严格的事情,而单纯的机器学习方式,很难达到我们要求,所以我们选择以机器视觉理解为主,机器学习为辅的方式,构建整个UI2CODE工程体系。我们将持续关注AI技术,来打造一个完美的UI2CODE工具。

原文链接
更多技术干货 请关注阿里云云栖社区微信号 :yunqiinsight

UI2Code智能生成Flutter代码--整体设计篇的更多相关文章

  1. UI2CODE智能生成代码——组件识别篇

    1.背景 在<UI2CODE——整体设计篇>中,我们介绍了UI2CODE工程的整体流程: 在组件识别这个环节,需要有一种处理布局信息的方法,来解析和计算控件间的布局关系(比如识别业务组件( ...

  2. 借Adobe XD之力,自动生成Flutter代码

    概述 今天,我们来聊聊一个专门为"懒人程序员"准备的工具--Adobe XD.使用它可以快速将原型设计图转换为可执行的Flutter代码, 而由于Flutter自身跨平台的特性,因 ...

  3. MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

    前言 经过前面EF的<第一篇>与<第二篇>,我们的数据层功能已经较为完善了,但有不少代码相似度较高,比如负责实体映射的 EntityConfiguration,负责仓储操作的I ...

  4. [转]MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

    本文转自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html 〇.目录 一.前言 二.工具准备 三.T4代码生成预热 (一) 单文件生成:Hello ...

  5. 我所理解的RESTful Web API [设计篇]

    <我所理解的RESTful Web API [Web标准篇]>Web服务已经成为了异质系统之间的互联与集成的主要手段,在过去一段不短的时间里,Web服务几乎清一水地采用SOAP来构建.构建 ...

  6. RecyclerView源码分析(一)--整体设计

    RecyclerView这个控件出来已经有一段时间了,如果看这篇文章的你,还没有使用过这个控件.那请先去学习怎样使用.不然看也白看.这里奉上一些关于介绍RecyclerView使用方法的优秀博客: 鸿 ...

  7. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

  8. 基于语义感知SBST的API场景测试智能生成

    摘要:面对庞大服务接口群,完备的接口测试覆盖和业务上下文场景测试看护才有可能保障产品服务的质量和可信.如果你想低成本实现产品和服务的测试高覆盖和高质量看护,这篇文章将为你提供你想要的. 本文分享自华为 ...

  9. jQuery2.x源码解析(设计篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 这一篇笔者主要以设计的角度探索jQuery的源代 ...

随机推荐

  1. 解决asp.net web api时间datetime自动带上带上的T和毫秒的问题

    今天用asp.net web api写微信小程序的接口时遇到一个问题. 返回的model中的datetime类型的字段自动转换成了“2014-11-08T01:50:06:234”这样的字符串,带上的 ...

  2. openssl操作公私钥和加解密的一些常用命令

    生成公私钥实践: 生成私钥,这里以椭圆曲线secp256k1为例: openssl ecparam -name secp256k1 -genkey -out secp256k1-priv.pem #带 ...

  3. Python xlwt模块

    Examples Generating Excel Documents Using Python’s xlwt Here are some simple examples using Python’s ...

  4. flask请求上下文源码分析

    一.什么是上下文 每一段程序都有很多外部变量,只有像add这种简单的函数才是没有外部变量的,一旦你的一段程序有了外部变量,这段程序就不完整了,不能独立运行,你为了使他们能运行,就要给所有的外部变量一个 ...

  5. Docker系列(十一):Kubernetes集群集群部署实践

    Kubernetes分布式集群架构 服务注册和服务发现问题怎么解决的? 分布式通讯的核心就是ip加端口 每个服务分配一个不变的虚拟IP+端口 系统env环境变量里有每个服务的服务名称到IP的映射 如下 ...

  6. 《DSP using MATLAB》Problem 8.18

    代码: %% ------------------------------------------------------------------------ %% Output Info about ...

  7. 04_Hibernate检索方式

    一.Hibernate检索方式概述 OID检索方式:按照对象的OID来检索对象(get/load) HQL检索方式:使用面向对象的HQL查询语言 QBC检索方式:使用QBC(Query By Crit ...

  8. HDU--2126 Buy the souvenirs(二维01背包)

    题目http://acm.hdu.edu.cn/showproblem.php?pid=2126 分析:有两个要求,一是计算最多可以选多少中纪念品:而是计算选最多纪念品的方案有多少种, 即统计最优方案 ...

  9. Python2 Python3 urllib方法对应

    Python2 name Python3 nameurllib.urlopen() urllib.request.urlopen()urllib2.urlopen() urllib.request.u ...

  10. 2019-2-18-VisualStudio-给项目添加特殊的-Nuget-的链接

    title author date CreateTime categories VisualStudio 给项目添加特殊的 Nuget 的链接 lindexi 2019-02-18 15:56:48 ...