元理系院生の新入社員がPythonとJavaで色々頑張るブログ

プログラミングや機械学習について調べた事を書いていきます

【Java】手書き文字を収集するアプリケーションの作成

隠れマルコフモデルによる手書き数字認識を実装する前に、手書き数字データを収集するアプリケーションを作成します。
いきなり余談ですが、手書き文字は採取時のデータの性質によってオンライン手書き文字とオフライン手書き文字に分けることが出来ます。
オフライン手書き文字は文字を見たままの画像として扱い、オンライン手書き文字は筆記時間毎のペンのX,Y座標や筆圧、移動速度や仰角等の時系列として扱います。
今回はHMMによる手書き数寺院式に適用する為、時系列データとして扱えるオンライン特徴量を採取します。
作成した筆跡収集アプリのコードは次のようになります。

HandWriting.java

package emoson.gui.handwriting;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;

public class HandWriting extends JFrame {
	public HandWriting(){
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setBounds(100, 100, 500, 500);
		
		this.setLayout(new FlowLayout());
		
		Note p1 = new Note();
		p1.setPreferredSize(new Dimension(400, 400));
		
		
		JPanel p2 = new JPanel();
		p2.setPreferredSize(new Dimension(400, 50));
		p2.setBackground(Color.BLUE);
		
		JButton ok_button = new JButton("OK");
		ok_button.setBorderPainted(false);
		ok_button.setBackground(Color.WHITE);
		ok_button.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				p1.save(System.currentTimeMillis()+".txt");				
			}});
		JButton cl_button = new JButton("Clear");
		cl_button.setBorderPainted(false);
		cl_button.setBackground(Color.WHITE);
		cl_button.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				p1.clear();
				
			}});
		p2.add(ok_button);
		p2.add(cl_button);
		
		Container cont = this.getContentPane();
		cont.add(p1);
		cont.add(p2);
	}
	
	public static void main(String[] args){
		HandWriting app = new HandWriting();
		app.setVisible(true);
	}
}

Note.java

package emoson.gui.handwriting;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;

public class Note extends JPanel implements MouseMotionListener{
	private static final int size = 5;
	private List<Pos> posList;
	public Note(){
		super();
		this.posList = new ArrayList<Pos>();
		addMouseMotionListener(this);
	}
	public void paintComponent(Graphics g){
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, this.getWidth(), this.getHeight());
		
		g.setColor(Color.BLACK);
		for(Pos pos : this.posList){
			g.fillOval((int)pos.X, (int)pos.Y, size, size);
		
		}
	}

	public void clear(){
		this.posList.clear();
		this.repaint();
	}
	
	public void save(String fileName){
		File file = new File(fileName);
		try {
			FileWriter fw = new FileWriter(file);
			for(Pos p : this.posList){
				fw.write(p.X+","+p.Y+"\n");
			}
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.clear();
	}
	
	@Override
	public void mouseDragged(MouseEvent e) {
		posList.add(new Pos(e.getX(), e.getY()));
		this.repaint();
	}
	@Override
	public void mouseMoved(MouseEvent e) {
		
	}
}

Pos.java

package emoson.gui.handwriting;

public class Pos {
	public float X;
	public float Y;
	public Pos(float X, float Y){
		this.X = X;
		this.Y = Y;
	}
}

実行すると次のようなGUIが起動します。
f:id:emoson:20151108101408p:plain

次のようにマウスで文字を筆記します
f:id:emoson:20151108101438p:plain

書き終えたらOKボタンを押します。
f:id:emoson:20151108101459p:plain

すると、プロジェクトのカレントディレクトリに次のようなファイルが生成されます
f:id:emoson:20151108102201p:plain

このファイルはサンプリング時間毎のマウスのX座標値とY座標値が神間で句切られています。

次回はこのプログラムをを用いて0から9までの手書き数字を採取し、隠れマルコフモデルを用いて手書き数字認識実験を行います。