整个项目的代码在我的 GitHub 上面: https://github.com/yongyehuang/svg_parser ,直接 download 后可以使用。
首先需要安装的一些 python 库:
pip install svgwrite
pip install svgpathtools
pip install wand
1. svg 生成 png
refer: http://docs.wand-py.org/en/0.4.4/
网上找的一些 svg 生成 png 的方式貌似很复杂,后来发现 wand 库直接读入 svg 图片后可以保存为 png.暂时还没有测试效率,但是对于小样本的话应该没什么问题。
from wand.image import Image
from wand.display import display
# 导入 svg 图片并存成 png 格式
input_file = 'data/airplane/1.svg'
output_file = 'data/1.png'
with Image(filename=input_file) as img:
img.resize(224, 224)
img.save(filename=output_file)
查看生成的图片
import PIL.Image as pimg
import numpy as np
img = pimg.open(output_file)
# img = img.resize((224,224))
_img = np.asarray(img)
print(_img.shape)
img
(224, 224, 2)
这里生成的 png 是 2通道的,不过从输出来的 png 图形来看应该没有什么问题。
2. 解析 svg 笔画路径序列
svg 笔画路径解析比较复杂,这里只解释一下 svg_to_np 函数,至于 svg 文件夹中一些辅助函数太复杂了,其实也没有去认真研究的必要。
简单的使用例子见: https://github.com/yongyehuang/svg_parser/blob/master/example.py
from svg.path import parse_path
import numpy as np
from xml.dom import minidom
import time
下面贴出两个笔画的代码如下,关于 svg 代码的理解请参考 Sketch Learning - SVG 是什么?
<path id="0" d="M167 268 C167 268 169.3665 263.4813 172 262 C175.9896 259.7559 177.6387 259.2365 183 259 C210.4512 257.7889 216.727 256.0078 240 259 C245.7803 259.7432 247.6027 262.8186 253 268 C259.5845 274.3211 265 283 265 283 "/>
<path id="1" d="M171 264 C171 264 156.0157 299.1415 149 333 C144.9744 352.4277 146.294 356.9169 148 375 C148.4708 379.991 151.6471 385.2605 154 386 C161.2152 388.2676 172.6028 390.1283 183 386 C200.8261 378.922 205.9707 374.266 222 359 C235.7293 345.9245 235.8428 342.9286 246 326 C251.8714 316.2143 249.7558 314.4885 255 304 C260.64 292.72 268 282 268 282 "/>
整个函数如下,其中 original_flag 设置为 True 的话将会解析原本 svg 的点的坐标。最后每个曲线只得到一个起始点和一个终点,但是曲线中间的一些点就不考虑了,这样得到的结果其实是不够准确的。
比如 C167 268 169.3665 263.4813 172 262
曲线,解析出来就只有一个终点(172 262)
所以我们需要对曲线中间的一些点进行采样,此时,通过 sample_len 来进行控制采样频率。
另外,不同数据集中解析出来的序列长度可能会相差较大,如果我们要用同一个模型进行学习的话,最好控制样本序列长度分布大概一致,这样就可以通过采样来控制了。
sample_len 是控制采样的参数,sample_len=20 表示每 20 个原始坐标采一个点。 sample_len 设置越大,那么最后得到的序列就会越短。
def svg_to_np(svg_file_name, sample_len=20, original_flag=False):
"""Parse the svg file to coordinate sequence.
Args:
svg_file_name: The path of the svg file.
sample_len: dot sample parameter, the larger sample_len is, the less dot will get. Only works when original_flag is Fasle.
original_flag: If True, get the original coordinates. If False, get the sampled coordinates.
Returns:
image_coord: numpy.ndarray with shape [n_dot, 3], coordinate sequence. Each line denotes the location for a dot [x, y, is_end]
if is_end == 1, the dot is the end of a stroke.
"""