背景

2017 年,一篇关于图像转代码的 Pix2Code 论文掀起了业内激烈讨论的波澜,讲述如何从设计原型直接生成源代码。随后社区也不断涌现出基于此思想的类似 Screenshot2Code 的作品,2018 年微软 AI Lab 开源了草图转代码 工具 Sketch2Code,同年年底,设计稿智能生成前端代码的新秀 Yotako 也初露锋芒, 机器学习首次以不可小觑的姿态正式进入了前端开发者的视野。

最近,阿里的imgcook工具,吸引了人们的眼球,基本实现了从设计稿到各种前端代码的自动生成。前面那些项目,使我们对智能生成代码还是保持观望态度,而这个项目的上线,让我们确定了D2C的可行性。

应用

线上页面生成

目前阿里imgcook已经上线,我们整理了使用介绍文档: 设计稿生成前端业务代码。对于不需要经常修改的活动页,可以尝试使用并生成代码。对于imgcook是否始终保持免费 或者 是否能开源,我们保持观望的态度,即使做到开源,相关的模型和组件其实也无法直接使用。不过目前没有自主搭建这方面的强烈需求,可以先用着这个服务。而且短时间很难自主实现这个繁杂的工程。

CRM后台页面生成

不过,相对于复杂的线上页面,CRM后台的页面相对简单,组件基本固定,没有大量的不确定组件识别问题。在前端智能化领域,特别是中后台智能方向上,表单表格的识别是非常重要的一环。因为表单表格的开发工作,占据了中后台前端开发工作量中的绝大部分,如果能够通过智能的手段,从设计稿图片秒级生成表单表格代码,那么将会是巨大的生产力提升。目前imgcook没有开放出这部分,而雪球有大量的CRM,这个是我们目前可以做的方向。

目标


对于CRM后台需求,实现从原型稿截图生成antd前端代码,目标如下图(来自imgcook的博客,只是个动图,功能没有对外开放):

整体方案

  • 1.检测出所有的组件类型及其坐标。

  • 2.通过文字识别技术和自动翻译技术识别出所有文字及其坐标并翻译为英文。

  • 3.通过代码转换器从上述组件信息和文字信息中提取表单/表格的布局、label、type 、字段等各种属性。

组件检测方案

方案1.机器学习目标识别

样本集生成

机器学习的最重要的是数据集的收集和处理,HTML元素如果采用人工标注来收集处理,会浪费大量人力与时间。因此编写了个代码来自动生成HTML UI 组件数据集。

HTML-COCO-datasets-generate

https://github.com/yuxizhe/HTML-COCO-datasets-generate

可批量自动生成图片,每张图上包括25个 HTML 元素,相应的标注为coco数据格式,放都在 json中。

实现方式:

  • react 项目负责生成网页

  • puppeteer 负责生成图片并js生成coco格式标注信息

我们批量生成100张训练图片,10张验证图片,10张测试图片。

每个生成的图片示意如下面两

目标检测

目标检测框架可以理解成是把目标检测算法整合在一起的一个库。其实TensorFlow 不是一个目标检测框架,但它提供目标检测的 API: Object Detection API。

目标检测框架主要有:Detectron、maskrcnn-benchmark、mmdetection、Detectron2。目前使用较广的是Facebook AI 研究院于 2019 年 10 月 10 日开源的 Detectron2 目标检测框架。效果不错。

我们使用 Detectron2。

Detectron2目标检测

在官方例子上修改,在谷歌colab上进行训练,显卡为 NVIDIA® Tesla® P100 16G。模型选择及参数如下,显卡内存占用约5G,5分钟训练完成

1
2
3
4
5
6
7
8
9
10
11
cfg = get_cfg()
cfg.merge_from_file(model_zoo.get_config_file("COCO-Detection/faster_rcnn_R_50_C4_1x.yaml"))
cfg.DATASETS.TRAIN = ("my_dataset_train","my_dataset_valid")
cfg.DATASETS.TEST = ()
cfg.DATALOADER.NUM_WORKERS = 2
cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url("COCO-Detection/faster_rcnn_R_50_C4_1x.yaml")
cfg.SOLVER.IMS_PER_BATCH = 2
cfg.SOLVER.BASE_LR = 0.00025
cfg.SOLVER.MAX_ITER = 500
cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 128
cfg.MODEL.ROI_HEADS.NUM_CLASSES = 4

完整训练程序及结果如下

https://github.com/yuxizhe/HTML-COCO-datasets-generate/blob/master/detectron2_html.ipynb

能正确识别出训练目标

通过不断改进和训练,对于自身生成的组件能识别的不错,但是对于真实原型图识别效果有错误出现,如下图所示。后续可改为在真实原型图上标注的方式,获得样本数据集,提高训练结果准确性。

方案2.openCV 识别矩形 + 机器学习图像分类

用机器学习需要大量的训练样本和人力投入,观察上述检测结果,发现其对组件矩形边框这个必要条件都忽略了。因为我们的对象是CRM原型图,所有组件基本都是矩形,所以直接用openCV 提取出所有的矩形,再进行分类。会比上面的机器学习快。

分类问题的复杂度比目标检测容易很多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import cv2
import numpy as np
from google.colab.patches import cv2_imshow
for i in range(8):
img = cv2.imread('/content/pic/crm/'+str(i + 1)+'.png')
# img resize to 700
img = cv2.resize(img, (700,int(700/img.shape[1]*img.shape[0])), interpolation=cv2.INTER_AREA)
#cv2_imshow(img)
# 转为灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 边缘检测
binary = cv2.Canny(gray,50,100)
#ret,binary = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY)

cv2_imshow(binary)

#检测轮廓
# RETR_EXTERNAL 表示只检测最外层轮廓
#print(cv2.MinAreaRect2(binary))
contours, hier = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#print(contours)
trueBoxes = []
for c in contours: #遍历轮廓
rect = cv2.minAreaRect(c) #生成最小外接矩形
box_ = cv2.boxPoints(rect)
h = abs(box_[3, 1] - box_[1, 1])
w = abs(box_[3, 0] - box_[1, 0])
#print("宽,高",w,h)
#只保留需要的轮廓
if (h > 500 or w > 600):
continue
if (h < 10 or w < 50):
continue
#print("宽,高",w,h)
trueBoxes.append(box_)
box = cv2.boxPoints(rect) # 计算最小面积矩形的坐标
box = np.int0(box) # 将坐标规范化为整数
# 绘制矩形
cv2.drawContours(img, [box], 0, (255, 0, 255), 3)
cv2_imshow(img)
print("矩形元素个数", len(trueBoxes))
#print(trueBoxes)

使用opencv 识别效果如下

分离出矩形后,再进行图像分类即可,TensorFlow可以很方便实现。

文字识别方案

可以调用收费api或者开源库来识别,这里分别使用开源库 cnocr 和 tesseract 对我们的原型图识别测试,代码及结果如下

cnocr: https://github.com/yuxizhe/OCR/blob/master/cnocr.ipynb

tesseract: https://github.com/yuxizhe/OCR/blob/master/tesseract.ipynb

使用 tesseract 的效果好很多,所以采用 tesseract。