导语:前端智能化,就是通过AI/CV技术,使前端工具链具备理解能力,进而辅助开发提升研发效率,比如实现基于设计稿智能布局和组件智能识别等。
本文要介绍的是前端智能化的一类实践:通过计算机视觉和机器学习实现自动提取图片中的UI样式的能力。
具体效果如上图,当用户框选图片中包含组件的区域,算法能准确定位组件位置,并有效识别组件的UI样式。
样式提取方案
对图像的样式检测涉及计算机视觉领域知识,本文基于OpenCV进行代码实现,主要分为三步:
- 从图片检测并分离组件区域;
- 基于组件区域进行形状检测;
- 对符合规则形状的组件进行样式计算。
1. 从图片分离组件区域
组件区域分离主要是通过图像分割算法,识别组件区域(前景)和背景区域,本文主要从用户框选操作上考虑,采用了可交互可迭代的Grab Cut算法。
Grab cut 算法允许用户框选作为前景输入,利用混合高斯模型GMM,找到前景和背景的最佳分割路径,具体可参考文章:图像分割——Grab Cut算法
如上图,通过调用OpenCV的cv2.grabCut
方法时,我们将组件前景框(x, y, width, height)作为方法入参,识别出的组件像素被存储在mask遮罩。
代码实现
1 | def extract(img, rect): |
通过这一步,我们从背景分离出目标遮罩,它是包含了N个组件区域的二值图。
2. 形状检测
接下来,我们需要通过形状检测从遮罩区筛选出多个可用样式还原的组件,比如矩形、带圆角矩形和圆形。
具体分为两步:1) 提取组件外轮廓 2) 霍夫检测识别轮廓形状
2.1 外轮廓提取
第一步是通过前面图割遮罩进行外轮廓提取,排除组件内部其它线条带来的影响。轮廓提取主要使用Suzuki85轮廓跟踪算法),该算法基于二值图像拓补,能确定连通域的包含关系。
这里采用的是Canny边缘检测来得到图像边缘图,再通过Suzuki85算法cv2.findContours
从图像边缘提取外轮廓。
代码实现
1 | def separate(img, th=5): |
这一步我们得到了图像中所有组件的外轮廓以及具体的坐标x,y
和宽高w,h
。
2.2 组件的形状检测
第二步则是对每个组件外轮廓进行图形类型识别,其中除了矩形、圆形是样式可还原图形,其它都不可还原,我们的目标就是检测出这两种基本图形。
这里运用霍夫变换(Hough Transform)
)方法,它是一种识别几何形状的算法,主要采用投票机制从多个特征点拟合图像中线段和曲线的参数方程。
2.2.1 矩形检测
检测矩形主要分两步:1)通过霍夫直线变换检测外轮廓的边;2)根据边(线段)集合判断是否符合矩形特征。
OpenCV提供线段检测方法cv2.HoughLinesP
,输入外轮廓,输出检测到的线段,具体代码实现如下:
1 | # 检测矩形 |
取到线段集合后,我们再判断是否满足矩形边的特征:
- 存在两条水平方向线段和两条垂直方向线段
- 上线段到下线段距离≈组件高度,左线段到右线段距离≈组件宽度
代码实现
1 | """判断是否为矩形""" |
2.2.2 圆形检测
圆形检测可使用霍夫圆环检测法,对应OpenCV的HoughCircles
方法,输入二值图,如果存在圆形,则返回圆形和半径。代码实现如下:
1 | # 检测圆形 |
通过这一步,我们筛选出属于矩形或圆形的组件,以及组件的宽高、圆形以及对应的半径,下一步,我们将针对这两种基本图形进行样式检测。
3. 组件的样式计算
组件样式计算主要对边框、圆角、背景三种常用样式分别计算。
3.1 圆角计算
在样式定义中,圆角被限制在矩形的四个顶点处,圆角弧度取决于它的半径,因此圆角计算的主要目标就是识别圆角的半径。
根据圆角的4个方位,我们将组件区域划分为4块进行逐块分析。
一开始,我们采用直接对圆弧点进行圆的曲线拟合,但由于圆角点的数据过于集中,拟合圆的误差很大,如图:
我们知道,圆角经过十字对称后能构造出一个圆形,因此,只要我们确定了“圆角”的候选区域,构造十字轴对称图,就可以根据圆形拟合准确判断是否为满足圆角特征了。具体步骤如下:
- 假设存在圆角,用面积推算圆角半径,确定“候选区域”
- 构造“候选区域”水平-竖直轴对称图形,对图形进行霍夫圆环检测,验证是否为圆角
3.1.1 圆角半径推算
我们假设存在圆角,半径为R,如下图黄色色块区域,是组件框与填充组件的差集。
同时,黄色块也是以边长R为正方形与半径R为1/4圆的差集,即s = R² - π × R² × ¼
,于是联立方程,可求解圆角半径R,代码如下:
这一步我们根据面积差集计算出半径R,通过R,我们裁剪出“候选区域”,进行下一步验证。
3.1.2 候选区域验证
这一步先构造轴对称图像,主要是在水平和竖直方向依次做翻转+拼接操作。
如图,得到对称图形后,我们沿用上文的霍夫圆环变换来检测是否存在圆形,如果存在,则圆角也存在,反之亦然。
代码实现
1 | # 推算可能的圆角半径 |
3.2 边框计算
对于边框的计算,我们同样是先确定边框的描述特征:A. 边框内的颜色连续与相近;B. 外轮廓和内轮廓是形状相似的。基于这个特征,我制定了以下步骤:
- 色块分离:对图像基于颜色聚类,相近色区聚类同一色块
- 遍历不同色块,提取每个色块内外轮廓,并计算其相似度
3.2.1 色块分离
边框具有颜色相近的特征,我们通过聚类算法对目标图像让颜色相近的区域归类,这里采用k-means
算法聚类,聚类特征基于图像的HSV色彩空间。
代码实现
1 | """k-means聚类""" |
3.2.2 候选区域验证
这一步是遍历k个候选色块,对色块分别进行外轮廓和内轮廓提取,再判断色块内外轮廓是否形状相似。
其中外轮廓的提取直接复用前面的cv2.findContours
方法,输入色块,输出外轮廓填充图。
内轮廓则需要分两步,首先对外轮廓填充图与色块填充图进行差运算得到“内域”,再对内域进行cv2.findContours
。
拿到内外轮廓后,我使用感知哈希pHash + 汉明距离进行相似度计算,它主要通过颜色低采样将图片统一缩小到32×32尺寸并输出图像签名,很好地解决相似形状中大小不一致带来的误差。
代码实现
1 | """验证每个色块是否存在边框特征B""" |
总结
本文通过OpenCV系列算法分别实现简单组件区域的分离和样式的检测,对于组件的区域检测,目前是通过手工框选的手段确定组件区域,如果要完全自动化实现Pixels to Code,还需要借助深度卷积网络进行组件检测与识别。
最后,本人将于9月5号参与2020腾讯live开发者大会,介绍更多前端智能化内容,欢迎有兴趣童鞋前来观摩👇
腾讯Live开发者大会:https://2020.tlc.ivweb.io/detail/?number=8
更多文章欢迎关注:https://zhuanlan.zhihu.com/webxr
相关资料
最全综述 | 图像分割算法:https://zhuanlan.zhihu.com/p/70758906
pHash图像相似度比较算法汇总:https://blog.csdn.net/mago2015/article/details/81137089
机器学习算法实践——K-Means算法与图像分割:https://blog.csdn.net/google19890102/article/details/52911835
霍夫变换:https://en.wikipedia.org/wiki/Hough_transform
Suzuki85轮廓跟踪算法:https://blog.csdn.net/yiqiudream/article/details/76864722