DRYな備忘録

Don't Repeat Yourself.

個人開発程度のOCRサーバならHerokuに立てればいいじゃない

追記 2018/07/26

このプロジェクトはDocker on Herokuに移行したので、一時的に「Deploy to Heroku」ボタンは動かなくなってます。Dockerでデプロイ可能なので、以下をご参考ください。

github.com

以下原文


このエントリはGo (その2) Advent Calendar 2016 - Qiitaの5日目です。
WETな方でもお世話になっております、otiai10です。

とある個人開発が、もうかれこれ3年ぐらい続いているんですが、ブラウザ上に描画されたちょっとしたテキストをOCR(文字認識)する要件があって、それをずっとさくらVPSPythonでやってましたが、3年もやってると、他の個人開発だったりとか、副業だったりとかでサーバリソースを一緒にしたくないなあ、っていうことが発生してきて、しかもべつに広告とかアフィとかで報酬が発生するタイプの個人開発でもないので、なんで俺が身を削って維持せなあかんねんという気持ちにもなったので、いいかげん、無料でOCRサーバ立てるのをやりました。Goで。Go好きなので。

tl;dr

Deploy

これ押したらもう立ちます。

特徴

  1. Google Cloud Vision API のように自由画像から文字座標を検出したりしない
    • 位置と矩形が確定している場合の文字認識に適してます
  2. Google Cloud Vision API では指定できないchar_whitelist(検出文字制限)ができる
    • 想定される文字が限られている場合に適しています
  3. 無料 ← つよい

みなさんバンバン自分のOCRサーバインスタンスを立てて、レシートを読むなり、アイドルのスタミナ回復時間を読むなりしてください。

やったことその1: GoでC++のライブラリを叩く

Goはcgoっていうのがあって、GoからC/C++C/C++からGoを呼べたりするんですけど、これを使って既存の光学文字認識ライブラリであるTesseract-OCRを呼んでます。

GitHub - otiai10/gosseract: Go package for OCR (Optical Character Recognition), by using Tesseract C++ library

例。includeしているtess.hは自作のヘッダファイルで、cppファイルが実際にTesseract-OCRを叩いてます。このGoファイルをビルドすると、C/C++のライブラリにリンクされた実行ファイルが手に入る、という寸法です。

package tesseract

/*
#cgo LDFLAGS: -llept -ltesseract
#include "tess.h"
*/
import "C"

// Simple executes tesseract only with source image file path.
func Simple(imgPath string, whitelist string,languages string) string {
    p := C.CString(imgPath)
    w := C.CString(whitelist)
    l := C.CString(languages)

    s := C.simple(p, w,l)
    return C.GoString(s)
}

やったことその2: せっかくなのでWAFっぽいものをつくる

僕がGoの好きなところのひとつは、DIY(Do It Yourself)感がすごいところで、始めやすいし、Write&Runが手軽だし、標準ライブラリが簡潔かつ充実してるし、釘一本からチェーンソーまであって、隅にはペットコーナーすらある的な、ホームセンターみたいな雰囲気が好きです。

ということで、最低限よくやるルーティングと、あとHTTPのフィルタリングあたりをやる小さなツールキットをつくりました。

GitHub - otiai10/marmoset: The very minimum web toolkit, less than frame work

func main() {
    router := marmoset.NewRouter()
    router.GET("/hello", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hello!"))
    })
    http.ListenAndServe(":8080", router)
}

Viewのレンダリングもやるんですけど、なんかHerokuで動かなくて、アドベントカレンダー的に合わなかったのでocrserver側ではdirty hackしてます...

やったことその3: 1と2を、Uh...!合わせる

PPAPの画像をコラって貼りたいと思ったんだけど、ライセンスフィルタ付きで画像検索したら1個も無えの。

marmosetで小さいサーバをつくって、gosseractでOCRするところをやったのが、こちらになります。

github.com

やったことその4: Herokuデプロイできるようにする

なんかHerokuはbuildpackっていうのがあって、言うなればUbuntuベースのCedarっていうイメージをベースに、自分で好きな拡張をしていけるようになってるっぽい。

上記のgoseractは当然、GoのコンパイルにはTesseract-OCRのヘッダファイル/共有オブジェクトファイルが必要なので、これをHerokuインスタンスに配置して、サーバアプリケーションが立つときに参照できるようにしてやらないといけないんだけど、どうしようかな、と思ってたら直でaptitudeが使えるマジ神なbuildpackがあったので一発解決しました。

これがたぶん今回のミソでした。Tesseract-OCR叩くパッケージにも、webのツールキットにも、OCRサーバのUIにもまだまだTODOが多いので、使いながらブラシアップしていきたいです。

まとめ

Deploy ← これ押したらあなたのOCRサーバがもう立ちます。無料で。

個人開発、いいですよね。知らない技術に触れるチャンスになるので。

追記

現場からは以上です。