Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
7
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

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

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のサンプルコードを多少変えただけのモデルで学習を行いたいと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
7
Help us understand the problem. What are the problem?