5
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SVGとPNGのデータセット ① (塩尻MLもくもく会#09)

Last updated at Posted at 2018-09-24

#SVGとPNGのデータセット ① (塩尻MLもくもく会#09)

ラスタ形式からベクタ形式を推論する研究が、様々な分野で行われているようです。

ラスタからベクタへの学習が簡単に試せるデータセットがあったら面白いので、MNISTのサンプルを少し弄るだけで使えそうなものを作りたいと思います。

###PythonでSVGを出力する
参考 : SVGをお手軽に出力するならQtが最強のライブラリではないか?
こちらを参考にさせて頂きました。
PythonでのSVG描画はsvgwriteが有名ですが今回はこちらの方法を利用しました。

まずSVGを描画するための要素をnumpy.randomでランダムに生成します。
今回は、
 0から9までの数字
 14から84までのサイズ
 15種類のフォント
でランダムに2つ選び、
上下左右に位置をずらして、横に2枚並べて描画します。

gen_svg.py
from __future__ import unicode_literals, print_function, absolute_import
import os
import sys
import numpy as np
import PySide
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtSvg import *
from PIL import Image

app = QApplication(sys.argv)
fontlist = ['Axis', 'Arial', 'Bahnscrift', 'Cambria', 'Century', 'Consolas', 'Courier', 'Georgia', 'Lucida', 'Myriad', 'Rockwell', 'Segoe', 'Symbol', 'Tahoma', 'TimesNewRoman']

def random_elements(n):
    rd_text = np.random.randint(0, 9, (n, 2))
    rd_size = np.random.randint(14, 84, (n, 2))
    rd_font = np.random.choice(fontlist, n*2).reshape(n, 2)
    rd_posi_x1 = np.random.randint(7, 35, (n, 1))
    rd_posi_y1 = np.random.randint(14, 63, (n, 1))
    rd_posi_w1 = np.random.randint(16, 56, (n, 1))
    rd_posi_h1 = np.random.randint(16, 56, (n, 1))
    rd_posi_x2 = np.random.randint(49, 70, (n, 1))
    rd_posi_y2 = np.random.randint(14, 63, (n, 1))
    rd_posi_w2 = np.random.randint(16, 56, (n, 1))
    rd_posi_h2 = np.random.randint(16, 56, (n, 1))
    rd_stack = np.concatenate((rd_text, rd_size, rd_font, rd_posi_x1, rd_posi_y1, rd_posi_w1, rd_posi_h1, rd_posi_x2, rd_posi_y2, rd_posi_w2, rd_posi_h2), axis=1)
    return rd_stack

このパラメーターをPySideに渡してSVGを描画・保存をします。

gen_svg.py
def draw_svg(rd, n, width, dir_svg):
    for i in range(n):
        svg_gen = QSvgGenerator()
        svg_gen.setFileName(dir_svg + str(i) + ".svg")
        svg_gen.setSize(QSize(width, width))
        svg_gen.setViewBox(QRect(0, 0, width, width))

        painter = QPainter()
        painter.begin(svg_gen)

        text1 = str(rd[i,0])
        text2 = str(rd[i,1])
        size1 = int(rd[i,2])
        size2 = int(rd[i,3])
        font1 = str(rd[i,4])
        font2 = str(rd[i,5])
        posi1 = np.array(rd[i,6:10], dtype=int)
        posi2 = np.array(rd[i,10:14], dtype=int)

        x1, y1, w1, h1 = posi1
        x2, y2, w2, h2 = posi2

        rect1 = QRect(x1, y1, w1, h1)
        painter.setPen(Qt.green)
        painter.setFont(QFont(font1, size1))
        painter.drawText(rect1, Qt.AlignCenter, text1)

        rect2 = QRect(x2, y2, w2, h2)
        painter.setPen(Qt.blue)
        painter.setFont(QFont(font2, size2))
        painter.drawText(rect2, Qt.AlignCenter, text2)
        painter.end()

###SVGをPNGに変換する
参考 : PythonでSVGをPNGに変換する
こちらにあるPySideを用いてPNGへ変換する方法を参考にしました。
SVGの変換ライブラリはCairoSVGが有名ですが、インストールが上手くいかなかったためPySideの機能を使いました。

gen_svg.py
def svg2png(n, width, dir_svg, dir_png):
    for i in range(n):
        file_svg = dir_svg + str(i) + ".svg"
        file_png = dir_png + str(i) + ".png"
        r = QSvgRenderer(file_svg)
        i = QImage(width, width, QImage.Format_ARGB32)
        p = QPainter(i)
        p.fillRect(0, 0, width, width, QColor(0, 0, 0))
        #p.eraseRect(0, 0, width, width)    
        r.render(p)
        i.save(file_png)
        p.end()

###PNGをnumpy配列に変換する
PILでPNGを読み込んで、numpy.asarrayでnumpy配列に変換します。

gen_svg.py
def png2numpy(n, dir_png):
    image_list = []
    for i in range(n):
        file_png = dir_png + str(i) + ".png"
        pil = Image.open(file_png)
        num = np.asarray(pil)
        image_list.append(num)
    image_numpy = np.array(image_list)
    return image_numpy

###1つの関数にまとめる
random_elements
draw_svg
svg2png
png2numpy
以上の4つをまとめて、generate_datasetsという関数にします。

gen_svg.py
def generate_datasets(n, width, dir_svg, dir_png):
    rd = random_elements(n)
    draw_svg(rd, n, width, dir_svg)
    svg2png(n, width, dir_svg, dir_png)
    image_numpy = png2numpy(n, dir_png)
    return image_numpy, rd

###訓練用データセット
訓練用に600枚のデータセットを作成します。
同じディレクトリにtrainフォルダ、その下のsvgフォルダとpngフォルダをos.mkdir()で作ります。
そこを作業ディレクトリにしてSVGとPNGが生成されます。
PNGはnumpy配列に変換されtrain_imageに代入されます。
train_signalはSVGの描画に用いたパラメーターです。これを教師データにします。
widthは画像サイズを決めるパラメーターです。

gen_svg.py
n = 600
width = 112
os.mkdir("./train")
os.mkdir("./train/svg")
os.mkdir("./train/png")
dir_svg = "train/svg/"
dir_png = "train/png/"
train_image, train_signal = generate_datasets(n, width, dir_svg, dir_png)

###テスト用データセット
テストデータセットをtestフォルダに100枚作成します。
test_image test_signalに生成されたnumpy配列を代入します。

gen_svg.py
n = 100
width = 112
os.mkdir("./test")
os.mkdir("./test/svg")
os.mkdir("./test/png")
dir_svg = "test/svg/"
dir_png = "test/png/"
test_image, test_signal = generate_datasets(n, width, dir_svg, dir_png)

###numpy配列の保存
numpy.save("ファイル名", 配列名).npyの拡張子に保存します。

gen_svg.py
np.save("train_image", train_image)
np.save("train_signal", train_signal)
np.save("test_image", test_image)
np.save("test_image", test_signal)

pngフォルダに以下のようなpngファイルが生成されました。
svg01.png


今回は以上になります。
次回では、このnumpy配列を使ってMNISTのサンプルコードを多少変えただけのモデルで学習を行いたいと思います。

5
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?