ざこ文字認識の話

文字認識システムを作りました。開発速度重視で具体的な手法については全く調べていません。

実行してみて動いたらそれを使うくらいの勢いなので、かなり間違ってると思うので、生暖かく見てやってください。

1. 文字の写真を撮影

テスト時はカメラで取ってました。

f:id:naxatoko:20171207103526j:plain

この画像は、テストに使った写真です。

2. 写真からエッジ検出

OpenCVさんのちからを借りて、Canny法を使いました。

import cv2
imgpath = "/path/to/img"
img = cv2.imread("/path/to/img", 0)

# lowより下は、エッジにはならない、highより上はエッジになるというしきい値を指定
cv2.Canny(img, low, high)  # => エッジ検出された画像データ

以下が、エッジを検出した結果の画像です。

f:id:naxatoko:20171207103543p:plain

3. 文字領域を抽出

文字領域とは、ある画像内で、文字が写っている一部分を抽出することです。

パッと見、隣接しているエッジ(白)ピクセルで、一文字と見ることができそうと感じたので、隣接する白ピクセルを走査し、 それで見つけたピクセルの最大のx,yと最少のx,yを抽出し、その座標を通る四角で囲われる部分を文字領域として認識しています。

実際には、見てもわかる通り、エッジは色が変わる境界線なので、Bや0のように、外側と内側が隣接しない場合があります。なので、少しだけ離れていても(間に黒ピクセルを含んでも)隣接していると判断する必要があり、調節が必要です。

以下は、その四角を画像に表示したものです。

f:id:naxatoko:20171207103613p:plain

4. 抽出した領域情報から写真内の文字領域を実際に抽出

f:id:naxatoko:20171207175349p:plainf:id:naxatoko:20171207175351p:plainf:id:naxatoko:20171207175356p:plain........

四角に沿って、画像を切り分けて抽出します。

5. 抽出した画像をうまい具合にリサイズ

今のままだと文字の画像のサイズが、それぞれ違うため、そのまま学習機に突っ込むわけには行きません。 全ての画像を等倍(縦横のピクセルの数が全て同じ)にしなければ次の学習したり認識したりする時に支障がでるので、リサイズします。 全て同じサイズならどんなサイズでも問題ありません。とりあえず、今回使った32x32にするために行った手順を紹介したいと思います。

まず、縦横の長い方を32に合わせて比率を保持したままリサイズします。

f:id:naxatoko:20171207175349p:plainf:id:naxatoko:20171207211155p:plain

元画像の比を保存しつつサイズを合わせたいので、短い方は両はじに黒ピクセルを追加します。ただし、元画像が中心に来るように追加する黒ピクセルの幅は両はじとも均等になるようにします。

f:id:naxatoko:20171207211155p:plainf:id:naxatoko:20171207211423p:plain わかりづらいかもしれませんが、左右に黒い空間ができていると思います。

6. リサイズした文字画像を機械学習を使って文字認識

trainデータはラボのメンバーに作成をお願いしました(一文字30文字づつで、全部で350文字ほど)。 そのtrainデータを上記の加工を施して学習機に学習させました。

modelはKNNとSVMで、グリッドサーチを行いパラメータ探索をして生成しました。

7. 結果

cross validationの結果を載せておきます。

  • KNN (K=1)
    • accuracy : 0.730
  • SVM
    • accuracy : 0.765

正直、このままでは使い物に成りませんが、ここから先は精度上げであって、実装ではないので、とりあえず良いかなと思います。

まとめ

2週間ほどの突貫作業でしたが、精度は置いておいて、意外とものに成りました。

実は、角度を変えた画像でtrainデータをかさ増ししたり、学習時に使うデータを加工してみたりした結果、accuracy 0.9くらいになったりしていたり、スマホで写真を取ると自動で認識を開始したりする機能も付けたりしてますが、それはそれでもう一記事くらいかけそうなのでここであえては書きません。

機械学習に入門してからかれこれ1年ほど立ちますが、こういった形でアウトプットできる機会がなかったので、非常に良い機会でした。また、自分のスキルアップを直に感じることができたのでモチベーションにもうまい具合に響いてくれると良いなと感じました。

以上です。ご読了ありがとうございます。

My Favorite Musics

弊ラボのAdvent Calendarができたので参加してみようと思います。 目的としては、弊ラボのAdvent Calendarは技術指向オンリーではなく、幅広く拾っていきたいという意思があるらしいのでそのへんを考慮して試しに技術以外のことを書いてみようかなと言う感じです。あと、めっちゃリンクが多いので注意してください。

好きなジャンル

適当に好きなジャンルと、そのジャンルで好きな曲(youtubeとかにあったらリンクも)を紹介していきます。

Club Jazz(NuJazz)

Jazzというと、静かなバーとか、ちょっと古くさいイメージを受けるかもしれませんが、Club Jazzはそんなことはありません。 普通Jazzというと、サックスがとか、トランペットがと言うような金管楽器と生演奏みたいに傾向が結構ありますが、Club Jazzはそのへんには余りこだわっておらず、他のジャンル(Hip Hop、Bossa novaなど)と融合して新たな方向性を切り開いています。なので、一口にClub Jazzと言っても、その幅は多岐に渡ります。なので、Club Jazzで気に入った曲を探すのも楽しいのではないかなと思います。 今回紹介しているのは、ぶっちゃけJazzかどうかも怪しいやつも含んでます。まぁ、TUTAYAの邦楽ジャズに入ってたし大目に見てください。

好きな曲

  • Toconoma - L. S. L

www.youtube.com

  • Jazz'in park - JOY

www.youtube.com

Easy Listening

ぶっちゃけ細かいことはよくわかんないです。テンポがゆっくりで高音がきれいなイメージがありますが、とりあえず、のんびりとした軽音楽のことくらいに考えてます。調べていくと、New Ageというジャンルがありそのwikiに、ジャンル区分が難しいらいしいようなことが書いてありました。

好きな曲

https://www.youtube.com/watch?v=qSxq8ePIiskwww.youtube.com

www.youtube.com

www.youtube.com

洋楽Rock

細かい説明はいらないと思います。洋楽のRockです。

好きな曲

www.youtube.com

www.youtube.com

www.youtube.com

www.youtube.com

Sound Track

Sound Trackは、wikiによると、映画および映画音楽の用語で、映画のフィルム上における音声が収録されている部分を指すとのことですが、ここでは、映画、アニメ、ゲームのOST(Original Sound Track)として販売されているもので個人的に好きなものを紹介したいと思います。

好きな作品のOST

Sound Trackは、元になる作品にかなり影響されますので、この曲というよりも、この作品といったような紹介のほうが正しいと思いますので、好きな作品を紹介しようと思います。あ、曲もあります。

映画

なんか、個人的に音楽で気に入る作品は、古くてB級という傾向がありますので個人差あるかもしれないです。

  • Midnight Run

  • Blues Brothers

ゲーム

  • UNDERTALE

http://cdn.edgecast.steamstatic.com/steam/apps/391540/header.jpg?t=1503525486

  • Hyper Light Drifter

https://images-3.gog.com/fdc6ee70ba6aee36a86086a9391fbea1ac146ff15cfef037f19ea42046ffa1ca.jpg

https://vignette.wikia.nocookie.net/silent/images/3/30/Silent_Hill_The_Room.JPG/revision/latest?cb=20130421201358

www.youtube.com

  • Portal1,2のED

www.youtube.com

www.youtube.com

アニメ

  • LAST EXILIE

まとめ

いろいろ描いてきましたが、ジャンルの説明もどんどん適当になってますね。最初はやる気あったんですけど... まぁ、こんな感じで、好きな曲を紹介させて頂きました。あまりに多すぎて当初の予定だった曲ごとの感想は諦めました。 もし、この中に気に入ったものとか、知ってるやつあった人で、もし、これとかいいよ!みたいのがありましたら是非コメントなどをください! 最後に、My Favorite Musicsということで

www.youtube.com

Elixirでチャットサーバを作ってみた

動機

Elixirを使ってスクレイピングとか、そんなことをやっていたのですが、ふとあんまりElixirらしい使い方では無いなと思いました。 それで、ElixirらしいといえばOTPなんかを使ったサーバサイドプログラミングだと思っているので、そんな感じのことをすればElixirのなんたるかが見えてくるのではないかと思ったので、軽めにチャットサーバなんかを作ってみようと思いました。

目的

  • チャットサーバの作成
  • チャンネル機能の実装
  • 各種チャットの情報を取得するコマンドの実装
  • OTPの学習(最初はホントに名前くらいしか知らなかった)注: 今回全く使いこなせてません。

OTP(Behavior)

とりあえずわかったこと

Behaviorとは、振る舞いという意味で、ここでは、サーバの振る舞いという意味。この振る舞いというのは、サーバを構築する上でよくでてくる実装をサーバのBehaviorとしていて、その振る舞いをテンプレート化しようっていうやつがらしい。なので、やってることは、簡単で細かいフレームワーク群を用意しているみたいな感じだった。

GenServer Behavior

  • Erlang VM上でプロセス間通信を行う際に行う処理のBehaviorの一つ
  • コールバック何かを使って、プロセス間通信の処理を隠蔽している

Supervisor Behavior

  • Supervisorが監視しているプロセスがクラッシュした場合、指定した戦略に基づいてプロセスを再起動する。
  • Supervisor Treeといった形で、プロセスをSuperviseして、更にそれをSuperviseして、Tree状にして管理するらしい

できていない点

  1. Behaviorを使って、他のVM上のプログラムとの通信を行うこと。
  2. クライアント/サーバシステムとして設計したが、クライアントとサーバを物理的に別のプログラムにした(同じVM上じゃなくした)ためGenServerのようなBehaviorで通信を行うことができなかった。
  3. プロセス化したクライアントアクセプタがうまく機能しなかったうえ、Superviseもうまく行かなった。

改善のアイディア

  • とりあえず、設計をもっとElixir(Erlang)に合わせて考える。
    • すごいErlangゆかいに学ぼう!を読め
  • Supervisor Treeの設計も念頭において設計をする
    • まず、Supervisorを使いこなせ
  • サンプルを見ているとサーバとクライアントを同じVM上に実装していたので、真似する。

    • どうやって、サーバとクライアントを物理的に離して接続してるのか全く想像がつかない
    • ElixirのNodeという機能を使うことで実現できるみたいです。Nodeについては、これから勉強します。
  • Elixirむずくね?

というわけで、チャットシステムの概要

f:id:naxatoko:20170721231808p:plain こんな感じで、サーバとクライアントを分けてます。 Processとかいうよくわかんない部分がありますが、実は、Reciverの部分に取り込まれており、実は、明確には分割されていません。 当初はchannelシステムなしで行こうと考えていたのでstate lessなシステムになると思っていたのですが、途中でchannelシステムを追加したため、思ったよりも状態が複雑になってしまい、そのへんがグダグダになってしまっいました。

システムの流れ

  1. クライアントから何らかのeventが送信される
  2. サーバがそのイベントを受信し、それに対応した処理を行う
  3. その結果、クライアントへ送信する必要があれば、eventを送信する
  4. クライアントは、eventを受け取ったらそれに応じた処理を行う

機能の解説

発言する以外の機能を用いる際は、:hogehogeといったようにすると、存在する機能の場合、hogehoge機能に対する処理が実行されます。

  1. channel機能

    • :channel_list
      • 現在サーバが管理しているチャンネル一覧を表示する
    • :now_channel
      • 現在、クライアントが所属しているチャンネルを表示する
    • :user_list
      • 現在所属しているチャンネルのユーザ一覧を表示する
    • :move arg1
      • arg1で指定したチャンネルに所属チャンネルを移動する
    • :create arg1
      • arg1で指定した名前のチャンネルを作成する
    • :delete arg1
      • arg1で指定した名前のチャンネルを削除する
  2. whisper機能

    • :whisper arg1 arg2
      • arg1で指定したユーザに対してarg2をメッセージとして送信
  3. say機能

    • arg1
      • 先頭にコマンドを指定しないで、入力すると、現在所属しているチャンネルにarg1を発言する

反省

  • Nodeの存在を知らなかったばっかりに、クライアントとのコネクションを:gen_tcpで持ってきてた。
    • Nodeの勉強します
  • Behaivior,OTPについて取っ掛かりをしっかりつかめたので、発展させていきたい
  • Supervisoruで管理できるプロセスは、基本的に何らかのBehaiviorに則ったプロセスのみなので、注意したい
  • すごいE本を読む

Source

Nodeの仕組みを知らなかったため、サーバとクライアントのソースが別れている;;

Rust で MPDクライアント作成

背景

私は、音楽再生にMPDを使っていて、クライアントはncmpcppを使っている。

でも、これはLinux機の話でwindows機だとiTunesを使っている。

個人的には、ncmpcppはキーボードだけで操作できるの良い点で、iTunesは、Albumで音楽を探せるのが非常に良いと思っている。

なので、その両方を兼ね備えた最強に見えるクライアントを作ろうと考えた。

開発環境

  • rust : 1.15.1
  • cargo : 0.16.0 - nightly
  • GUIライブラリ
    • GTK+3
    • gtk-rs : 0.1.2 feature : v3_16

 メインに考えている機能

1 それぞれの画面でのCUI操作

  • 音楽を選択して ‘a’ を押すと playlist に追加
  • playlist 画面で 選択した音楽を ’d' で plylist から削除
  • キーバインドの設定
  • GUIでの操作も可能

2 Album 画面

  • MPD内のアルバム全てをリストアップしてそのカバーアートを表示
  • 選択すると、そのアルバムの音楽リストを表示
  • カバーアートを音楽データから、あるいはネットから取得

現在の状況

  • 表示できるウィンドウ
    • playlist window( TreeView ) f:id:naxatoko:20170327222402p:plain
      • 現在再生している playlist の音楽データ(title, artist, album)を表示
      • 音楽を選択して ’d' を押すと playlist から音楽を削除
    • album window ( FlowBox ) f:id:naxatoko:20170327222410p:plain
      • アルバムのリストを表示
    • music directory window(mpd 内の音楽ディレクトリをそのまま表示) ( TreeView ) f:id:naxatoko:20170327222423p:plain
    • seek bar
      • 再生中の音楽の再生時間に応じて変化
      • 停止、再生などのボタンはあるが、何の動作もしない。

問題点

1 MPDのアルバム名取得(list album)で、アルバム名だけしか取得できないので、アルバムから音楽の取得がしにくい。

2 list album でアルバム名がかぶると一つにまとめられて表示されるので同じ名前のアルバムを表示できない。

3 album window でアルバムを選択すると、iTunes みたいに下の行に音楽リストを表示したいが、FlowBoxの特性上難しそう。

4 music directory window でMPDから音楽を取得するために、音楽のタイトルをファイル名にしている。

5 シークバーに gtk の Scale が ダサいのでProgressBarを使っているが、クリックなどのイベントがないので、時間操作ができない。

その他