使用 Canvas 进行图像连通域标记

图像识别本来并不是我擅长的领域,无奈最近业务上有一个需求,要求从一个 PNG 上识别出透明区域的位置,再进行一些图层处理,自动生成一张图片。

查了一些资料后,最终实现了功能,感谢以下两篇文章的作者,本文的实现大部分参考自第一篇文章。

图像分析:二值图像连通域标记

几种联通区域标记的算法介绍

算法描述

本文的实现使用的是「基于行程的标记」,该算法的描述如下,由于需求比较简单,联通域都是规则形状的,所以并没有实现算法步骤的等价对计算。

  1. 逐行扫描图像,我们把每一行中连续的白色像素组成一个序列称为一个团(run),并记下它的起点start、它的终点end以及它所在的行号。

  2. 对于除了第一行外的所有行里的团,如果它与前一行中的所有团都没有重合区域,则给它一个新的标号;如果它仅与上一行中一个团有重合区域,则将上一行的那个团的标号赋给它;如果它与上一行的2个以上的团有重叠区域,则给当前团赋一个相连团的最小标号,并将上一行的这几个团的标记写入等价对,说明它们属于一类。

  3. 将等价对转换为等价序列,每一个序列需要给一相同的标号,因为它们都是等价的。从1开始,给每个等价序列一个标号。

  4. 遍历开始团的标记,查找等价序列,给予它们新的标记。

  5. 将每个团的标号填入标记图像中。

  6. 结束。

结合一个三行的图像说明,上面的这些操作。 第一行,我们得到两个团:[2,6]和[10,13],同时给它们标记1和2。

第二行,我们又得到两个团:[6,7]和[9,10],但是它们都和上一行的团有重叠区域,所以用上一行的团标记,即1和2。

第三行,两个:[2,4]和[7,8]。[2,4]这个团与上一行没有重叠的团,所以给它一个新的记号为3;而[2,4]这个团与上一行的两个团都有重叠,所以给它一个两者中最小的标号,即1,然后将(1,2)写入等价对。

全部图像遍历结束,我们得到了很多个团的起始坐标,终止坐标,它们所在的行以及它们的标号。同时我们还得到了一个等价对的列表。

等价对列表的处理可以查看原文,关键就是让等价对标记的所有标号区域合成一个。

得到所有的团后,将团按照标记序号分成几组,然后在组内取 x、y 方向上的最大及最小值,即可获得左上角订单坐标及宽高数值,用以定义图层信息。

JS 代码实现

图片太大时可能会卡住,可以增加缩放比例减小 canvas 的尺寸