利⽤matlab将位图转为SVG⽮量图
利⽤matlab将位图转为SVG⽮量图
惯例声明:本⼈没有相关的⼯程应⽤经验,只是纯粹对相关算法感兴趣才写此博客。所以如果有错误,欢迎在评论区指正,不胜感激。本⽂主要关注于算法的实现,对于实际应⽤等问题本⼈没有任何经验,所以也不再涉及。
0 前⾔
位图转⽮量图的⽅法有很多,有的是利⽤线条特征转换,有的是利⽤颜⾊特征转换。根据⽬的来说,各有优缺点。
线条特征转换主要根据线条的⾛势,利⽤直线或贝塞尔曲线之类的线条拟合原位图,多⽤于线框⽂字类的位图图⽚。基于颜⾊特征的则关注位图的颜⾊分布,利⽤多边形或曲线围成的图形来拟合各个⾊块组成的图像。
本⽂主要算法为利⽤颜⾊特征进⾏转换。
算法思路为:1图⽚中值滤波,减少噪声。2将图⽚的颜⾊提取,并减少图形的颜⾊。3将不同颜⾊代表的图层进⾏图形分割,分割为若⼲个独⽴的多边形。4将这些多边形转换为⽮量图的多边形,赋予颜⾊。
1 算法思路
1.1 读取图⽚
以matlab⾃带图⽚peppersvg图
1.2 中值滤波
滤掉噪声,去除某些零星的颜⾊分布,使得⽣成的颜⾊能够代表整个图形。
因此,采⽤中值滤波。滤波效果如下:
1.3 中值滤波
利⽤rgb2ind函数,将图⽚的颜⾊数量减少到指定的数量。此时⽣成⼀个X索引矩阵,和RGB格式的map地图。X中每⼀个值代表⼀个颜⾊,具体颜⾊可以根据索引在map⾥到。使得之后多边形的数量和颜⾊为⼀个有限值。
1.4 去除孤⽴的像素
可以看到1.3背景还有很多噪点形状的像素块,⽐如图⽚上⽅的绒布和图⽚下⽅的绒布。
这些像素块是由于颜⾊介于两者之间,导致分布极为零星破碎。
因此,为了减少多边形数量,我们到这些孤⽴的像素,使得它的颜⾊等于周边像素的颜⾊。
⽅法为遍历每⼀个像素,如果该像素与周边8个像素中少于2个相同,则代表该像素⽐较孤⽴,应该同化为周围的像素。
去除之后的结果如下,可以看到幕布的的颜⾊变为了⼏个整颜⾊。⽔果上的某些噪点类似的颜⾊也被剔除。
1.5 提取单独的颜⾊
将1.4得到的新的X索引进⾏单独的颜⾊提取。以BW=(X==1)为例,此时提取出来了⼀个只有0和1的图像。根据1.4的结果对⽐,可以看到是深红⾊的图形被提取了出来。
这也可以看做是图像分割。
1.6 出⼆值图像中所有的连接体
将上⾯的图形区域分割,把每⼀个连通区域都到,并进⾏边缘的记录。
当然,matlab有专门的函数来处理这个问题,分别为bwconncomp进⾏分割,boundary进⾏边缘的提取。
然⽽boundary提取边缘的时候,只能进⾏凸包提取,中间的孔洞和凹陷很容易忽略掉。
所以为了将这种影响减少到最⼩,我们把⾯积⼤的图形先绘制,⾯积⼩的图形后绘制。这样如果出现孔洞没有被算作边缘时,先画⼤图当背景,之后⾯积⼩的孔洞在后⾯绘制时,就会显⽰在这个⼤图图层的上⽅,不被影响。
之后boundary提取边缘得到的就是最终绘制⽮量图所需的多边形了。
1.7 将提取出来的每个多边形膨胀
之后,按照多边形⾯积⼤⼩依次绘制多边形,并填充颜⾊。
可以发现,每个多边形之间会出现缝隙。这是因为在提取多边形的时候,是按照像素点中⼼处的坐标提取,和实际位图像素的边界相差约0.5个像素。相邻的多边形每个都相差0.5个像素,就会导致最终出现⼤约1个像素左右宽的缝隙。
如下图所⽰:
因此,需要对每⼀个多边形进⾏膨胀,在不改变图形的外形条件下,向四周均匀膨胀1个像素左右的距离。
原理采⽤基于多边形顶点来进⾏膨胀,如下图所⽰:
把图形⾔逆时针依次标号,蓝⾊向量为沿着标号⽅向,指向下⼀个点的向量。红⾊向量为上⼀个蓝⾊向量平移过来的向量,也就是说,红⾊向量2等由蓝⾊向量1平移得到,红⾊向量3等由蓝⾊向量2平移得到。
我们规定膨胀的⽅向为,向着红⾊向量⽅向⾛⼀步,再向着蓝⾊向量⽅向相反的⽅向⾛⼀步,如点4处的⽰意。
如果遇到图形凹陷,膨胀的⽅向与凸点相反。判断凹陷点和凸出点的⽅法为,计算红⾊向量与蓝⾊向量之间的夹⾓(逆时针),超过180°则为凹点。这⾥可以⽤叉乘来间接计算出sin值,来进⾏判断。
当然最终结果不能保证边缘与原图像平⾏。如果想要平⾏,需要在最终合成的向量那⾥除以sin值。但是后来发现实际效果并不好,它会把某些特别尖的尖点过于放⼤。
matlab中实际效果⼤致如下: