设计稿生成代码核心技术揭秘:获取图片中前端组件的位置信息

简介: 快来学习前端智能化!

作者 | 缺月

image.png
为了让大家更好地学习 Pipcook 和机器学习,我们准备了实战系列教程,会分别从前端组件识别、图片风格迁移、AI 作诗以及博客自动分类,这几个具体示例来讲解如何在我们日常开发中使用 Pipcook,如果需要了解 Pipcook 1.0,请阅读文章 AI ❤️ JavaScript, Pipcook 1.0

开源地址:https://github.com/alibaba/pipcook

背景

您是否在前端业务中遇到过这样的场景:手中有一些图片,您想有一种自动的方式来识别这些图片这个图片里都包含哪些组件,这些组件都在图片的什么位置,属于哪种类型的组件,这种类型的任务一般在深度学习领域称为目标检测。

目标检测与识别是指从一幅场景(图片)中找出目标,包括检测(where) 和识别(what) 两个过程

这种检测是非常有用的,例如,在图片生成代码的研究里,前端代码主要就是由 div, img, span 组成的,我们可以识别图片里的形状,位图,和文本的位置,然后直接生成相应的描述代码即可。

这篇教程将会教你如何训练出一个模型来做这样一个检测任务。

场景示例

举个例子,如下图所示,这个图片包含着多个组件,包括按钮,开关,输入框等,我们想要识别出他们的位置和类型:
image.png
对于训练好的模型来说,在输入这张图片之后,模型会输出如下的预测结果:

{
  boxes: [
    [83, 31, 146, 71],  // xmin, ymin, xmax, ymax
    [210, 48, 256, 78],
    [403, 30, 653, 72],
    [717, 41, 966, 83]
  ],
  classes: [
    0, 1, 2, 2  // class index
  ],
  scores: [
    0.95, 0.93, 0.96, 0.99 // scores
  ]
}

同时,我们会在训练的时候生成 labelmap,labelmap 是一个序号和实际类型的一个映射关系,这个的生成主要是由于现实世界我们的分类名是文本的,但是在进入模型之前,我们需要将文本转成数字。下面就是一个 labelmap:

{
  "button": 0,
  "switch": 1,
  "input": 2
}

我们对上面的预测结果做一个解释:

  • boxes:这个字段描述的是识别出来的每一个组件的位置,按照左上角和右下角的顺序展示,如 [83, 31, 146, 71],说明这个组件左上角坐标为 (83, 13), 右下角坐标为 (146, 71)
  • classes: 这个字段描述的是每一个组件的类别,结合 labelmap,我们可以看出识别出来的组件分别为按钮,开关,输入框和输入框
  • scores: 识别出来的每一个组建的置信度,置信度是模型对于自己识别出来的结果有多大的信息,一般我们会设置一个阈值,我们只取置信度大于这个阈值的结果

数据准备

当我们想要做这样一个目标检测的任务时,我们需要按照一定规范制作,收集和存储我们的数据集,当今业界主要有两种目标检测的数据集格式,分别是 Coco 数据集 和 Pascal Voc 数据集, 我们也分别提供了相应的数据收集插件来收集这两种格式的数据,下面我们以 Pascal voc 格式举例,文件目录为:

  • train

    • 1.jpg
    • 1.xml
    • 2.jpg
    • 2.xml
    • ...
  • validation

    • 1.jpg
    • 1.xml
    • 2.jpg
    • 2.xml
    • ...
  • test

    • 1.jpg
    • 1.xml
    • 2.jpg
    • 2.xml
    • ...

我们需要按照一定比例把我们的数据集分成训练集 (train),验证集 (validation) 和测试集 (test),其中,训练集主要用来训练模型,验证集和测试集用来评估模型。验证集主要用来在训练过程中评估模型,以方便查看模型过拟合和收敛情况,测试集是在全部训练结束之后用来对模型进行一个总体的评估的。

对于每一张图片,Pascal Voc 都指定有一个 xml 注解文件来记录这个图片里有哪些组件和每个组件的位置,一个典型的 xml 文件内容为:

<?xml version="1.0" encoding="UTF-8"?>
<annotation>
   <folder>less_selected</folder>
   <filename>0a3b6b38-fb11-451c-8a0d-b5503bc351e6.jpg</filename>
   <size>
      <width>987</width>
      <height>103</height>
   </size>
   <segmented>0</segmented>
   <object>
      <name>buttons</name>
      <pose>Unspecified</pose>
      <truncated>0</truncated>
      <difficult>0</difficult>
      <bndbox>
         <xmin>83</xmin>
         <ymin>31.90625</ymin>
         <xmax>146</xmax>
         <ymax>71.40625</ymax>
      </bndbox>
   </object>
   <object>
      <name>switch</name>
      <pose>Unspecified</pose>
      <truncated>0</truncated>
      <difficult>0</difficult>
      <bndbox>
         <xmin>210.453125</xmin>
         <ymin>48.65625</ymin>
         <xmax>256.453125</xmax>
         <ymax>78.65625</ymax>
      </bndbox>
   </object>
   <object>
      <name>input</name>
      <pose>Unspecified</pose>
      <truncated>0</truncated>
      <difficult>0</difficult>
      <bndbox>
         <xmin>403.515625</xmin>
         <ymin>30.90625</ymin>
         <xmax>653.015625</xmax>
         <ymax>72.40625</ymax>
      </bndbox>
   </object>
   <object>
      <name>input</name>
      <pose>Unspecified</pose>
      <truncated>0</truncated>
      <difficult>0</difficult>
      <bndbox>
         <xmin>717.46875</xmin>
         <ymin>41.828125</ymin>
         <xmax>966.96875</xmax>
         <ymax>83.328125</ymax>
      </bndbox>
   </object>
</annotation>

这个 xml 注解文件主要由以下几个部分组成:

  • folder / filename: 这两个字段主要定义了注解对应的图片位置和名称
  • size: 图片的宽高
  • object:

    • name: 组件的类别名
    • bndbox: 组件的位置

我们已经准备好了一个这样的数据集,您可以下载下来查看一下:下载地址

开始训练

在准备好数据集之后,我们就可以开始训练了,使用 Pipcook 可以很方便的进行目标检测的训练,您只需搭建下面这样的 pipeline,

{
  "plugins": {
    "dataCollect": {
      "package": "@pipcook/plugins-object-detection-pascalvoc-data-collect",
      "params": {
        "url": "http://ai-sample.oss-cn-hangzhou.aliyuncs.com/pipcook/datasets/component-recognition-detection/component-recognition-detection.zip"
      }
    },
    "dataAccess": {
      "package": "@pipcook/plugins-coco-data-access"
    },
    "modelDefine": {
      "package": "@pipcook/plugins-detectron-fasterrcnn-model-define"
    },
    "modelTrain": {
      "package": "@pipcook/plugins-detectron-model-train",
      "params": {
        "steps": 100000
      }
    },
    "modelEvaluate": {
      "package": "@pipcook/plugins-detectron-model-evaluate"
    }
  }
}

通过上面的插件,我们可以看到分别使用了:

  1. @pipcook/plugins-object-detection-pascalvoc-data-collect 这个插件用于下载 Pascal Voc 格式的数据集,主要,我们需要提供 url 参数,我们提供了上面我们准备好的数据集地址
  2. @pipcook/plugins-coco-data-access 我们现在已经下载好了数据集,我们需要将数据集接入成后续模型需要的格式,由于我们模型采用的 detectron2 框架需要 coco 数据集格式,所以我们采用此插件
  3. @pipcook/plugins-detectron-fasterrcnn-model-define 我们基于 detectron2 框架构建了 faster rcnn 模型,这个模型在目标检测的精准度方面有着非常不错的表现
  4. @pipcook/plugins-detectron-model-train 这个插件用于启动所有基于 detectron2 构建的模型的训练,我们设置了 iteration 为 100000,如果您的数据集非常复杂,则需要调高迭代次数
  5. @pipcook/plugins-detectron-model-evaluate 我们使用此插件来进行模型训练效果的评估,只有提供了 test 测试集,此插件才会有效,最终给出的是各个类别的 average precision

由于目标监测模型,尤其是 rcnn 家族的模型非常大,需要在有 nvidia gpu 并且 cuda 10.2 环境预备好的机器上进行训练:

pipcook run object-detection.json --verbose --tuna

模型在训练的过程中会实时打印出每个迭代的 loss,请注意查看日志确定模型收敛情况:

[06/28 10:26:57 d2.data.build]: Distribution of instances among all 14 categories:
|   category   | #instances   |  category   | #instances   |  category  | #instances   |
|:------------:|:-------------|:-----------:|:-------------|:----------:|:-------------|
|     tags     | 3114         |    input    | 2756         |  buttons   | 3075         |
| imagesUpload | 316          |    links    | 3055         |   select   | 2861         |
|    radio     | 317          |  textarea   | 292          | datePicker | 316          |
|     rate     | 292          | rangePicker | 315          |   switch   | 303          |
|  timePicker  | 293          |  checkbox   | 293          |            |              |
|    total     | 17598        |             |              |            |              |

[06/28 10:28:32 d2.utils.events]:  iter: 0  total_loss: 4.649  loss_cls: 2.798  loss_box_reg: 0.056  loss_rpn_cls: 0.711  loss_rpn_loc: 1.084  data_time: 0.1073  lr: 0.000000  
[06/28 10:29:32 d2.utils.events]:  iter: 0  total_loss: 4.249  loss_cls: 2.198  loss_box_reg: 0.056  loss_rpn_cls: 0.711  loss_rpn_loc: 1.084  data_time: 0.1073  lr: 0.000000  
...
[06/28 12:28:32 d2.utils.events]:  iter: 100000  total_loss: 0.032 loss_cls: 0.122  loss_box_reg: 0.056  loss_rpn_cls: 0.711  loss_rpn_loc: 1.084  data_time: 0.1073  lr: 0.000000  

训练完成后,会在当前目录生成 output,这是一个全新的 npm 包,那么我们首先安装依赖:

cd output
BOA_TUNA=1 npm install

安装好环境之后,我们就可以开始预测了:

const predict = require('./output');
(async () => {
  const v1 = await predict('./test.jpg');
  console.log(v1); 
  // {
  //   boxes: [
  //     [83, 31, 146, 71],  // xmin, ymin, xmax, ymax
  //     [210, 48, 256, 78],
  //     [403, 30, 653, 72],
  //     [717, 41, 966, 83]
  //   ],
  //   classes: [
  //     0, 1, 2, 2  // class index
  //   ],
  //   scores: [
  //     0.95, 0.93, 0.96, 0.99 // scores
  //   ]
  // }
})();

注意,给出的结果包含三个部分:

  • boxes: 此属性是一个数组,每个元素是另一个包含四个元素的数组,分别是 xmin, xmax, ymin, ymax
  • scores:此属性是一个数组,每个元素是对应的预测结果的置信度
  • classes:此属性是一个数组,每个元素是对应的预测出来的类别

制作自己的数据集

看完上面的描述,你是否已经迫不及待想要用目标检测解决自己的问题了呢,要想制作自己的数据集,主要有以下几步

收集图片

这一步比较好理解,要想有自己的训练数据,您需要先想办法收集到足够的训练图片,这一步,您不需要让您自己的图片有相应的标注,只需要原始的图片进行标注就好

标注

现在市面上有很多的标注工具,您可以使用这些标注工具在您原始的图片上标注出有哪些组件,每个组件的位置和类型是什么,下面我们拿 labelimg 为例,详细的介绍一下
image.png
您可以先从上面的 labelimg 官网上安装软件,然后按照以下步骤操作:

  • 按照官网的说明进行构建和启动。
  • 在菜单/文件中单击“更改默认保存的注释文件夹”
  • 点击“打开目录”
  • 点击“创建RectBox”
  • 单击并释放鼠标左键以选择一个区域来标注矩形框
  • 您可以使用鼠标右键拖动矩形框来复制或移动它

训练

在制作好上面的数据集之后,根据之前的章节中的介绍组织文件结构,之后,就可以启动 pipeline 进行训练了,赶快开始吧。

总结

读者到这里已经学会如识别一张图片中的多个前端组件了,可以适用于一些更加通用的场景了。那么在一篇,我们会介绍一个更有趣的例子,就是如何使用 Pipcook 实现图片风格迁移,比如将图片中的橘子都替换称苹果,或者将写实的照片风格替换为油画风格等。


🎉Pipcook 1.0 系列专题 🎉

AI (爱) JavaScript , Pipcook 1.0 正式发布

Pipcook 团队有话说

使用Pipcook对图片中的前端组件进行分类,饼图、折线图还是柱状图?

👉设计稿生成代码核心技术揭秘:获取图片中前端组件的位置信息

未完待续...

❤️欢迎大家关注 Alibaba F2E 微信公众号前端智能化技术分享周(6.29-7.3)❤️


image.png
关注「Alibaba F2E」
把握阿里巴巴前端新动向

相关文章
|
7天前
|
前端开发 JavaScript 测试技术
前端测试技术中,如何提高集成测试的效率?
前端测试技术中,如何提高集成测试的效率?
|
14天前
|
前端开发 JavaScript API
惊呆了!这些前端技术竟然能让你的网站实现无缝滚动效果!
【10月更文挑战第30天】本文介绍了几种实现网页无缝滚动的技术,包括CSS3的`scroll-snap`属性、JavaScript的Intersection Observer API以及现代前端框架如React和Vue的动画库。通过示例代码展示了如何使用这些技术,帮助开发者轻松实现流畅的滚动效果,提升用户体验。
84 29
|
7天前
|
移动开发 前端开发 JavaScript
惊!这些前端技术竟然能让你的网站在移动端大放异彩!
随着互联网技术的发展,移动设备成为主要的上网工具。本文介绍了几种关键的前端技术,包括响应式设计、图片优化、字体选择、HTML5和CSS3的应用、性能优化及手势操作设计,帮助开发者提升网站在移动端的显示效果和用户体验。示例代码展示了如何实现简单的双向绑定功能。
17 3
|
7天前
|
数据采集 前端开发 安全
前端测试技术
前端测试是确保前端应用程序质量和性能的重要环节,涵盖了多种技术和方法
|
7天前
|
前端开发 JavaScript
前端界的革命:掌握这些新技术,让你的代码简洁到让人惊叹!
前端技术的快速发展带来了许多令人惊叹的新特性。ES6及其后续版本引入了箭头函数、模板字符串等简洁语法,极大减少了代码冗余。React通过虚拟DOM和组件化思想,提高了代码的可维护性和效率。Webpack等构建工具通过模块化和代码分割,优化了应用性能和加载速度。这些新技术正引领前端开发的革命,使代码更加简洁、高效、可维护。
12 2
|
7天前
|
前端开发 JavaScript 测试技术
前端工程师的必修课:如何写出优雅、可维护的代码?
前端工程作为数字世界的门面,编写优雅、可维护的代码至关重要。本文从命名规范、模块化设计、注释与文档、遵循最佳实践四个方面,提供了提升代码质量的方法。通过清晰的命名、合理的模块划分、详细的注释和持续的学习,前端工程师可以写出高效且易于维护的代码,为项目的成功打下坚实基础。
16 2
|
13天前
|
监控 前端开发 JavaScript
前端开发的终极奥义:如何让你的代码既快又美,还不易出错?
【10月更文挑战第31天】前端开发是一个充满挑战与机遇的领域,本文从性能优化、代码美化和错误处理三个方面,探讨了如何提升代码的效率、可读性和健壮性。通过减少DOM操作、懒加载、使用Web Workers等方法提升性能;遵循命名规范、保持一致的缩进与空行、添加注释与文档,让代码更易读;通过输入验证、try-catch捕获异常、日志与监控,增强代码的健壮性。追求代码的“快、美、稳”,是每个前端开发者的目标。
30 3
|
13天前
|
编解码 前端开发 JavaScript
前端界的黑科技:掌握这些技术,让你的网站秒变未来感十足!
【10月更文挑战第31天】前端技术日新月异,黑科技层出不穷,让网页更加美观、交互更加丰富。本文通过响应式布局与媒体查询、前端框架与组件化开发等案例,展示这些技术如何让网站充满未来感。响应式布局使网站适应不同设备,前端框架如React、Vue则提高开发效率和代码质量。
26 3
|
15天前
|
JSON 前端开发 搜索推荐
惊!这些前端技术竟然能让你的网站实现个性化推荐功能!
【10月更文挑战第30天】随着互联网技术的发展,个性化推荐已成为提升用户体验的重要手段。前端技术如JavaScript通过捕获用户行为数据、实时更新推荐结果等方式,在实现个性化推荐中扮演关键角色。本文将深入解析这些技术,并通过示例代码展示其实际应用。
45 4
|
15天前
|
前端开发 JavaScript 测试技术
前端小白逆袭之路:如何快速掌握前端测试技术,确保代码质量无忧!
【10月更文挑战第30天】前端开发技术迭代迅速,新手如何快速掌握前端测试以确保代码质量?本文将介绍前端测试的基础知识,包括单元测试、集成测试和端到端测试,以及常用的测试工具如Jest、Mocha、Cypress等。通过实践和学习,你也能成为前端测试高手。
33 4