2012年8月25日土曜日

画像から文字抽出(ImageMagick Tesseractの利用)

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
スクワットのフォームが悪くて、膝を少し痛めてしまった、たなけんです。
本エントリではClojureを用いてシェルを操作し、画像データを加工し、必要となる文字列を抽出する方法を記載します。

事の発端

大学院の授業でシュミレーションゲームを行っており、そのデータをClojureを用いて分析していることを、以前の記事で紹介しました。
その後、あるチームメイトから「このpdfファイルのデータも使えない?」と聞かれ、『pdfなら文字情報を抽出するのも簡単だし、問題ない』と考え、二つ返事でデータの抽出を引き受けたのが、今回の事の発端です。
以前、利用したデータはcvs形式だったので、データ読み取りに何の工夫も必要ありませんでした。今回も、xpdfなど既存のソフトウェアを使えば、文字情報が簡単に取り出せると考えていたのですが、意外な落とし穴がありました。実は
ファイル拡張子はpdfであるものの、実際のデータは画像
だったのです。
(xpdfでテキスト抽出処理をした結果、一文字も抽出されませんでした。不審に思い、その後手動で文字をコピーしようと文字部分をマウスでドラッグしてみて、データが画像であることに気が付きました。。。)
以前より、画像から文字を抽出(OCR)することには関心があったので(※1)、ImageMagickとTesseractを利用して、画像データを抽出することにしました。

実装方針

翌日には結果を渡さないといけないという、時間的制約から、手作業で作業内容を確立し、プログラムでそれを自動化するという方針としました。

  • それぞれの処理(画像加工、OCR)はシェルからコマンドを実行する(作業内容)
  • シェルの起動や、コマンド発行をClojureから行う(自動化)


ImageMagickとTesseractのインストール

どちらもMacPortsからインストールしました。
Tesseractは本体だけではなく、英語バージョンの学習ファイル(辞書)もインストールしました。
特に問題なく、スムーズにインストールすることができました。
(パラメータなどは全てデフォルト値)

作業内容

作業内容および手順は、以下の通り。

  1. 複数ページを含むpdfファイルを、個別の画像ファイルに分割する(同時に解像度も上げる)
  2. 各画像ファイルから抽出対象の文字が含まれる部分を切り取る
  3. 切り取ったファイルの文字情報を読み取る
  4. 読み取った文字情報を整形し、レポートを出力する(本エントリでは記載を省略)


ソースコード

形式変換&ページ分割


ImageMagickのconvertコマンドで複数ページを含むpdfファイルを個別のpngファイルに変換します。(-formatオプションを付けなくてもフォーマット変換出来ました。。。)
解像度指定しなかった場合、画像が荒すぎてOCR精度が落ちるため、-densityオプションで解像度を設定、-unitsオプションで解像度の単位を指定しています。
Clojureで実装した際の注意点としては、clojure.java.shell/sh関数を利用する際、通常(clojure.java.shell/sh コマンド オプション1 オプション2 ...)のように、コマンドのオプションを(リストではなく)第2引数、第3引数...と指定する点があげられます。
今回の実装では、オプションを別関数で生成しているため、apply関数を用い、(apply clojure.java.shell/sh コマンド オプションのリスト)のように実行しました。
またオプションは一続きの文字列ではなく、それぞれのオプション(およびその値)が分割されている必要がある点も注意が必要でした。例えば、"-density 300x300 -units PixelsPerInch"を第2引数に渡すとエラーとなり、正しくは"-density" "300x300" "-units" "PixelsPerInch"をそれぞれ、第2引数、第3引数、第4引数、第5引数として渡さなくてはいけません。
上記の点さえ気をつければ、特に問題なくclojure.java.shell/sh関数を使うことが出来ます。(シェルコマンドをClojureで自動実行できれば、いろいろと便利ですね)

画像切り取り


形式変換&ページ分割と同様、切り取るサイズと位置を指定してconvertコマンドを実行します。ページ毎に切り取り部分が異なるため、ファイル名に応じた切り取りサイズ&位置を渡しています。

文字情報の読み取り


切り取り済みの画像ファイルを順に読み込み、テキストファイルを生成します。
オプションの-psmは画像の中でさらに読み取る部分を指定するオプションです。
画像全体を読み込み対象とするため、-psmに6を指定しています。

捕捉: psm (pagesegmode)一覧


上記のように、一行とみなしたり、円で囲った部分だけ読むなどのオプションがあります。

調査中に見つけたライブラリ

今回は、時間的制約から、プログラムの再利用性(汎用性)よりも、実装の手早さを重視しました。そのため、あまり調査に時間を掛けることはできませんでした。しかし、少しだけ行った調査の過程で、面白そうなライブラリを発見したので、この場を借りて紹介したいと思います。

im4java

ImageMagickのコマンドを網羅したJavaライブラリ。<im4javaのwebサイト>
複雑な処理を自動化するのであれば、使ってみたいといった印象。
学習コスト削減のため、今回は利用しませんでした。

Tess4J

TesseractのJNIラッパー。<Tess4Jのwebサイト>
まだMacでの動作に問題があるようだったので利用を回避。
2012年8月8日にversion 1.0 beta 5がリリースされたばかりの新しいライブラリの様なので、今後の成熟に期待。

今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間2時間(テキスト抽出後の処理は除く))

※1: OCRを組み込んだ、アプリケーション、サービスについての構想は別エントリにて紹介したいと思います。

2012年8月19日日曜日

第3イテレーションの計画

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
『今やる、すぐやる、出来るまでやる』がモットーの、たなけんです。
本エントリでは、第3イテレーションの計画として、仕様および実装方針を記載します。

第3イテレーション(パーシステント(トランザクション)層)の仕様

外部APIを規定の回数以上使用しないよう、検索語と検索日時をデータベースに記録し、規定回数以上のアクセスがあった場合は、外部APIへアクセスせず、画面にメッセージを表示します。
RDBMSでの実装するのであれば、1テーブルのみ、列は単語と日時といったシンプルな構成となるような仕様です。

実装方針

最終的にHerokuにデプロイしてサービスインする予定ですので、無料で利用可能なDBの選択肢として以下の3つが考えられます。

  • PostgreSQL
  • MongoDB
  • その他組み込み系DB

通常のRDBMSについては帳票処理の際に利用し、特に問題なく利用出来たため、
今回のアプリケーションでは、新たなチャレンジとして

  • MongoDB
  • Datomic(組み込みモード)

を用いて、パーシステント層を実装したいと思います。

テスト方針

下記の4ステップを1サイクルとし、継続的にテストが可能な状態を目指します。

  • テストデータの作成
  • 取り込み
  • テスト
  • テストデータの消去


今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間15分)

第2イテレーションの振り返り

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
肩甲骨周辺の筋肉をほぐすと代謝が上がると聞き、日々肩を回している、たなけんです。
本エントリでは、第2イテレーションを振り返ります。

Clojurescriptおよび各種ライブラリを利用した所感

Clojurescriptの利点

Javascriptに馴染めない、という理由からWebクライアントの開発言語にClojureを採用しました。Google Closure Libraryで提供される関数やオブジェクトを利用する感覚が、通常のClojureからJavaのライブラリを利用する感覚に非常に近く、スムーズに開発を進めることができました。また、DOMやイベントの操作についての関数が十分に整備されていたことも、開発効率の向上につながりました。

Clojurescriptの欠点

多少違和感があった点としては、通常のClojureでは副作用を期待する処理にdoマクロを用いるのですが、Clojurescriptではdoマクロを用いずに次々と式を評価していく点があげられます。ライブラリの読み込みや表の描画など、戻り値を利用しない処理が多く、この点は若干の気持ち悪さがありました。

コンパイルとデバッグ

ClojurescriptからJavascriptへのコンパイルなど、導入前は手間が掛かることを想定していたのですが、lein-cljsbuildを用いることで、コンパイルを意識することなく開発を進めることができました。ただし、デバックについてはFirebugを用いてJavascriptのコードにブレイクポイントを設定し、エラーを解析する必要がありました。この点については、HTML 5で提供されるsource mapを利用することで、解決できるのではと考えています。

repl

Clojurescriptのreplは通常のClojureのreplほど洗練されておらず、若干使い勝手が悪かったです。そのため、Clojurescriptで提供されている関数の動作を確認する程度にしか利用しませんでした。この問題は、Emacsとの連携で解決できそうです。(本家サイトのEmacs連携のWikiページ)

Google jsapi (visualization API)

表や図などのオブジェクトが提供されており、自分でtableタグなど書く手間が省け、開発時間を短縮することができました。また、オブジェクトへのidの付与など、今回は利用しなかったものの、通常の利用では必須となるであろう機能も用意されており、また機を見てAPIを調査したいと思います。

Twitter Bootstrap

正直あまりUIに時間を掛けなかったので、なんとも言えません。
動的にCSSを生成するフレームワークとしてlessを採用しているようですので、こちらも機会を見て掘り下げてみたいと思います。

今後利用してみたいツール、フレームワーク

Clojurescriptについて調査を進める中で、気になるツール、フレームワークがあったので、この場を借りて紹介したいと思います。

lein-cljsbuild (複雑なソースのビルド、テストの自動実行)

今回はコンパイル機能のみを利用したのですが、その他にもClojure(.clj)ファイルとClojurescript(.cljs)ファイルを別ディレクトリに保存しておき、ビルド時に1つのJavascriptを生成する機能や、PhantomJSを起動してテストを自動的に実行する機能などをlein-cljsbuildは持っているようです。
特にビルドに関してですが、クライアント側で実行するコードであっても、純粋なClojureで記述できる部分がcljファイルに保存できると、単体テストの仕組みなどをサーバ側と統一できるため、非常に開発効率が上がると思います。
さらに、cljsソースとcljソースが粗結合となるため、Sinon.jsなども絡めることでcljs(ブラウザの操作などを含む不純なClojurescript)コードのテストもより単純化できるのではと感じました。

Clojure one


Clojure oneはサーバ、クライアントの双方をClojure(Clojurescript)で開発可能にした統合Webアプリケーションフレームワークです。単体テストの仕組みなども組み込まれているようで、非常に便利なのではないかという印象です。便利な反面、何かしら制約があるかもしれませんが、次回ClojureでWebアプリケーションを利用する際には、実際に使ってみようと考えています。

Bishop

BishopはClojureで書かれた、HTTPリクエスト処理ライブラリです。Webmachine互換のAPIを持ちRestfulなWebサービスを実現するために利用することができるようです。
クライアントサイドMVCフレームワークについては後述しますが、Webアプリケーションのあり方として、ロジックはサーバーサイド、描画と操作はクライアントサイドにまとめてしまった方が良いのではないかと個人的には考えています。Bishopは多様なリクエスト処理関数を実装しており、ロジックに特化したサーバサイドのライブラリとして、有用なのではと、密かに目をつけています。

クライアントサイドMVCフレームワーク

Bishopの項でも述べた通り、ブラウザでの描画および操作はクライアントサイドで完結させたいと個人的には考えています。そういった要望に応えるのがBackbone.jsやSpine.jsなどクライアントサイドMVCフレームワークです。
Coffeescriptの練習がてらSpine.jsを利用した感想としては、「何故、今までこれを使わなかったのだろう」と思ってしまったくらいに便利でした。(JavascriptではなくCoffeescriptでモデルなど定義できたからかもしれませんが。。。)
今後、クライアントサイドの処理が複雑なアプリケーションを作成する際には、ClojurescriptとこれらのクライアントサイドMVCフレームワークを組み合わせて実装出来ないか、検討したいと考えています。


今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間30分)

Webクライアントのテスト

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
先日、魔女の宅急便を見ました。映画の最後で語られる「おちこんだりもしたけれど、私はげんきです」のメッセージに、とても励まされた、たなけんです。(ダイエットに挫折しそうになっていたため。。。)
本エントリでは、Webクライアントのテストについて記載します。

Webクライアントのテストの位置づけ

Webクライアントのテストの為に、今回テスト手法やテスト用ライブラリなどを調査しました。その結果、いくつかの興味深いフレームワークやライブラリ、ツールを見つけることができました。
しかし、今回のWebクライアントは

  • ソースコードが実質20行程度と非常に短い
  • 条件分岐がなく一本道のロジックである

ことから、それらのライブラリを利用してテストする程ではないと考えました。
本来であれば、クライアントのメソッド単位で、まずは単体テストを実施し、その後ユーザの操作フローに基づいた結合テストを実施します。また、正常系だけではなく、異常系も漏らす事無くテストするのが本来のテストの姿であると考えています。
しかしながら今回は、Webクライアントの機能が十分すぎる程シンプルであるため、テストの目的を、デグレーションの検出に限定して考えたいと思います。

テストプログラム実装方針

正常系の動作を自動実行し、以上が発生しない事を確認する。
ライブラリとしてSeleniumをラップしたclj-webdriverを利用する。

依存ライブラリのダウンロードの問題

project.cljにclj-webdriverを利用するよう記載し、lein depsを実行したところ、bcprov-jdk15on-147.jarおよびbcpkix-jdk15on-147.jarのダウンロード時に、チェックサム例外が発生し、Leiningen経由では上記2ライブラリがインストールできませんでした。
そこで新規Mavenプロジェクトを作成し、Seleniumの依存ライブラリをインストールしたところ、問題なく上記2ライブラリをインストールすることができました。
私の環境ではLeiningenとMavenでライブラリを共有しているため、この方法で解決をすることができました。
また、Maven利用の前にlein-localrepoによるfloating jarのローカルインストール(Mavenの3rd party jarのインストールのようなもの)を試してみましたが、こちらは上手くいきませんでした。

テストコード



  • doマクロ: 手続き型のプログラミング言語のように、以下のS式を順に処理する
  • clj-webdriver.taxi/set-driver!関数: ブラウザを起動し、引数のurlを開く
  • clj-webdriver.taxi/implicit-wait関数: 指定ミリ秒処理を停止する
  • clj-webdriver.taxi/input-text関数: テキストボックスに引数の文字列を入力する
  • clj-webdriver.taxi/click関数: 引数の要素をクリックする
  • clj-webdriver.taxi/find-element関数: 引数で指定された要素を取得する。要素はxpathなどで指定が可能


clj-webdriverの感想

依存ライブラリのダウンロードで問題が発生するなど、アルファバージョンにつきものの不安定さはありました。
その反面、一度インストールしてしまえば、非常に短いコードでSeleniumを用いたテストを記述することができました。
業務ソフトウェアをClojureで書くよう周囲を説得するのは難しいと思います。しかし、clj-webdriverのように、テストツールとしてClojureを導入するのは、非常に現実的な選択肢ではないかと、clj-webdriverを使ってみて強く感じました。
(通常の単体テストも、JUnitの代わりにテストだけClojureで書くことも出来そうですね)

今後利用してみたい、Javascriptテストの技術要素

今回のテスト(そもそもロジックがない)で利用するにはオーバースペックでしたが、Clojurescript (Javascript)のテストに関連する様々なフレームワークやライブラリ、ツールについても多少調査したため、この場を借りて紹介します。

Jasmine

Javascriptテスティングフレームワークの大本命。
Google Closure Library (Closurescriptを影で支えているJavascriptライブラリ)はJsUnitを公式テストフレームワークとして採用しています。しかし今やJsUnitはメンテナンスされておらず、JsUnitのサイトでもJasmineへの以降を推薦していました。
Clojurescriptをテストする方法が、Odyssomayさんのブログに分かりやすく解説されています。(なぜClojurescriptをビルドするためのスクリプトがPythonで書かれているかは追求しません。。。)

Sinon.js

Javascriptの柔軟性を存分に活かした黒魔術のようなライブラリ。単体テストの際、関連オブジェクトを差し替えてテストしたいといった要望は多々あるかと思います。(テストするクラス以外は、単純にある値を返して欲しいなど)
Sinon.jsはオブジェクトのスタブ化、モック化またフェイクサーバやフェイクタイムなどを提供し、オブジェクトを差し替えたいといった要望に応えてくれます。
モックあるいはスタブ化関数で処理することで、テスト対象以外のオブジェクトは、メソッドインタフェースは普遍のまま、振る舞いをテストに都合の良いように変えることができます。
同じ様なコンセプトのライブラリ、是非ともClojureにも欲しいなあと感じました。(JavaでSpring frameworkなど使えば、同様の機能は実現可能ですが、Clojureの持つ柔軟な言語特性を活かしたライブラリがあればもっと手軽に実現できそうなので)

PhantomJS

Javascriptのテストライブラリはブラウザから実行することが多いのですが、ブラウザの起動や動作までサポートするライブラリはあまりありません。
PhantomJSはコマンドラインから起動でき、読み込んだJavascriptを実行することができるブラウザです。(内部で、WebKitエンジンを利用しています)
PhantomJSを利用することで、コマンドラインからJavascriptをテストすることができ、単体テストの自動実行が容易になるかと感じました。

今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間30分)

2012年8月18日土曜日

画面デザインの改善

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
ダイエットを続けて半年、やっと2キロの減量に成功したものの、気がつけば1キロリバウンドしてしまい、意気消沈のたなけんです。
本エントリではTwitter Bootstrapを利用した、Webページのデザイン改善について記載します。

Twitter Bootstrapとは

Twitter社が提供しているCSSフレームワークです。
デザインが苦手なプログラマでも、見栄えの良いWebサイトが作れるとの評判なので、今回作成中のWebアプリケーションに組み込んでみました。

ナビゲーションの追加

今回の要件では、画面そのものがシンプル極まりないため、デザインを取り入れる要素があまりありません。そこで、機能毎に画面遷移するためのナビゲーションを追加することにしました。
実装方法として、ナビゲーションとiframeからなるindex.htmlを作成し、ナビゲーションのクリックイベントをにより、iframe内のベージがそれぞれの機能のページ(例dictionary.html、spelling.html)に切り替わるようにしました。

実装結果


未だ地味な感じは否めませんが、無味乾燥だった画面が、少しまとまった気がします。

ソースコード



  • 6行目: ダウンロードしたBootstrapのCSSを利用
  • 9-10行目: ナビゲーションへのクリックイベントに対応した動作(jQuery使用)
  • 14-30行目: ナビゲーションの描画
  • 32行目: iframeに各機能のページを割り当て(初期値はdictionary.html)


今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間45分)

2012年8月12日日曜日

Clojureで帳票処理(csv読み書き、RDBMS利用、グラフ描画、PDF出力)

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
授業が始まってからグログ更新が滞っていた、たなけんです。
本エントリでは、Clojureを利用した帳票処理について記載します。

事の発端

現在、大学院で会計を専攻しているのですが、任意科目でいくつかのMBA専攻のクラスを受けています。(前期までに、ほぼ会計は履修したため、今期は75%がMBAのクラス)
その履修しているMBAクラスのひとつに、企業戦略を立案するクラスを履修しています。
面白いことに、このクラスの成績は、シュミレーションゲーム上のスコアにより決定されます。(クラスのメンバーを8チームに分け、チーム間で競争することとなります。)
決定すべき項目として、製品開発(高機能戦略や低価格戦略)、マーケティング(世界を4地域に分け競合の出方を伺いながらどのエリアを攻めるか)、生産(工場の人員配置や設備投資など)、財務(株式発行、社債発行など)などがあり、毎週50項目ほどのパラメータを検討して、事業戦略を実装し、他チームと結果を競い合っています。
各チームが決定する50項目のうち、27項目は年度末(実際は毎週日曜日)に結果とともに全チームに公開され、翌年のパラメータ検討の際の参考資料とすることができます。
他チームが見る事のできるパラメータは27項目なのですが、それがチーム毎(8)、地区毎(4)、四半期毎(4)で公開されるため、結果として毎年3,456(=27*8*4*4)項目に目を通すこととなります。また、年間の比較を考えると、1年(1週間)毎にデータが3,456項目ずつ増えることになりますので、数値だけを見て比較するのは困難であると考えられました。
そこで、数値の変化を、各社、各地域で比較出来るようグラフを作成することとなりました。

仕様

入力: 会社、地域ごとに1csvファイル。行は項目、列は四半期ごとの数値が記載されている。
出力:1項目1ページ、1ページに各地域のグラフを縦に配置、1グラフに8社と平均値を表示、横軸は時間、縦軸は値。

出力例
製品販売価格



数値をグラフにすることにより、各チームの意思決定が比較しやすくなっているのが分かると思います。例えば、EA市場ではほとんどのチームが価格を他の地域より高めに設定していること、また、year7に突然ピンクチームがAP、LA、NA市場で価格を高く設定したことなどがこのグラフから読み取れます。

実装

全ソースはtana-kenのGithubにて公開しています。
興味を持たれた方は是非ご覧になって下さい。
以下、ポイントを絞って、実装内容を紹介します。

nsマクロ

https://gist.github.com/3331553
ライブラリとしてclojure.java.io、clojure.data.csv、clojure.java.jdbc、incanter.core、incanter.chartsを利用します。

csvファイル読み書き


ファイルサイズが十分に小さいため、遅延シーケンスとして処理をせず、doallにより全データをメモリ上に読み込んでいます。

行列入れ替え


元ファイルは、列方向にデータが追加される仕様であったため、行方向にデータが追加されるよう、行と列を入れ替える処理を実装しました。

RDBMS利用


組み込みRDBMSとしてH2 Database Engineを採用しました。
csvファイル読み込み同様、想定される取得データが十分小さいため、doallにより全データをメモリ上に読み込んでいます。
また、今回はテーブルを結合する必要がないため、H2 Database Engineのcsvファイル読み込み機能を利用しました。(csvファイル読み込み -> 整形 -> 1ファイルに結合 -> H2 Database Engineにてテーブルとして利用)

グラフ描画


incanterを通じてjfreechartオブジェクトを作成しています。
RDBMSからグラフ描画に必要なデータセットを取り出し、グラフを描画します。

nsマクロ


incanterで利用しているjarと依存関係で不整合があったため、プロジェクトを分けました。ライブラリにはclj-pdfを利用しています。

内容作成


タグ付けされたベクタにて要素を構成しています。
sort-by関数により、ページを制御しています。

PDF描画


pdfマクロにて、与えられた内容をpdfファイルとして出力します。

今回の作業は以上、最後までお読み頂きありがとうございました。
たなけん(作業時間4時間)