埼玉系社内SEの日記

埼玉県内の物流会社に勤務する社内SEが適当に書込む日記です。

会社にきたFAXをOCR処理のうえ担当者別にSlackに通知してみるテスト

会社に複合機がありFAXやらスキャンやらプリンタとして使っているのですが、ふと「OCR(写真とかに写っている字を読み取る技術)処理して検索出来るようにしたら便利だよね」と思った。

調べてみたらその複合機自体にOCRの機能が付いていて早速試してみたのですが、数字とアルファベットは結構読み取るのですが、漢字に関しては無茶苦茶な内容になってしまいとても使えたものではありませんでした。

はい終了!と思ったその時思いだしました!みんな大好き!Google Driveの名を!

検索すると沢山教えてくれるページが出てくるのですが、GoogleDriveに写真をおくって「ドキュメントで開く」と、写真の中をOCR処理してテキスト化してくれるのです。

しかも処理結果が素晴らしい!もちろん誤字もあるけど、今まで見たことない精度で文字を読み取ってくれます。(手書き文字はやっぱり駄目ですが)

でもいちいち手動で写真を右クリックしてドキュメント化するんだったらFAXめくって探した方が早いので、GAS(Google Apps Script)を使って自動化のうえ、弊社の担当者の名前が書いてあったら、最近社内に導入したビジネスチャットソフトの「Slack」に通知を出すところまで作成してみました。

そして早速下記の適当な内容をFAXで流してみた

f:id:lincle-imai:20190419181219j:plain


すると

f:id:lincle-imai:20190419181525j:plain

キター!(リンクをクリックするとFAXをPDF化したものが見れる)

当初の目的の検索はSlackから出来るし、いい感じ。

ただ担当者に通知機能は送信元の担当者さんの名前が書いてあって弊社側の担当者と同じ苗字でも反応してしまうし、誤字で違う字になってしまうと通知が送られないので

逆に「FAX来てないやー」って思ってたら来てたなんてトラブルも考えられるので

今回は自己満足で終了!

 

FileMakerでシリアル入力

最近FileMakerが楽すぎて社内系は全部FileMaker使ってる今井です。

FileMakerばっかりやってるんで他の言語忘れそうです(笑)。

 

さて、今回は社内にあったシリアルポート接続タイプのバーコードリーダーをFileMakerで使いたいと思います。

バーコードリーダーでよくあるタイプとして、USBで繋いでキーボードエミュレーションする製品ってお手軽でいいのですが、フォーカスが当たってないと期待した動作にならないので、画面をモーダル表示にしてテキストボックスからフォーカス外れたら戻すとかしないといけないのですが、シリアル入力だとフォーカス外れようが、画面が裏側になっていようが関係なく処理できるので、個人的にシリアル入力タイプお勧めです。

 

でもですね

そんなお勧めのシリアルさんはFileMakerでは取り扱いしてないのです(悲)

MSのAccessですらできるのに....

 

そんな訳でなんとかしてみました。(Windows限定です)

C#(VisualStudio2012)でシリアル通信するフォームアプリケーション作って、入力受け取ったらFMPプロトコルFileMaker側に渡すようにしてみました。

f:id:lincle-imai:20171024153933j:plain

微妙なアイコン付きですが、ポイントとしては下記

1.SerialPortコンポーネントを使います。

  (バッファリングとかしてくれて便利)

2.DataReceivedイベントでReadExistingしてFMPプロトコルに流します

      ReadExistingはバッファ内の読み取り可能なデータを全部持ってきてくれます。

      今回は単純なデータなのでReadExistingで簡単に済ませます。

      FMPスクリプトの呼び出しには外部起動でよく使う、System.Diagnostics.Process

      を使用します。

3.FileMaker側にはFMPプロトコルで呼ばれるスクリプトを用意しておく

      

      かなりざっくりですが、下記C#コードです。


private void sp_Barcode_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string receivedData;
    receivedData = this.sp_Barcode.ReadExisting();

    using (System.Diagnostics.Process p = new System.Diagnostics.Process())
    {
        p.StartInfo.FileName = "fmp://{アドレス}/{FMファイル名}?script={FMスクリプト名}&param=" + receivedData;
        p.Start();
    }
}

 これでバーコード読み込むとFileMaker側のスクリプトが呼ばれて、パラメータに渡したバーコードデータを元にゴニョゴニョできます。

今回はざっくり作りましたが、多分近い時期に社内で必要になるのでしっかり版作ります。

欲しい人は連絡下さいっていねーか(笑)

プログラムの内容は英語なので、翻訳機にかけてみた

こんにちは

「焼き肉行きましょう」って言われると、断る言葉を知らない今井です。

ちなみに最初はカルビです。

 

たまにですが、プログラミング始めたいって人に言われるのが「英語わかんないから難しそう」です。難しいのはそこじゃないけど。

世の中にはプログラミングをするための「言語」というのが沢山あります。

人が使う言葉に近い言語の事を「高級言語」といい、これらは殆どが英語ベースになっています。

例えば、「条件分岐」といわれる記法ですが、「if 」(もし)とか「switch case」(この場合は〜)ってかんじです。

いくつか日本語で書ける言語も存在しますが、メジャーにはなってません。(ぴゅー太の日本語BASIC懐かしい)

 

さて、以前から気になっていたのですが、「プログラムが英語ならば翻訳機にかけたら訳せるんじゃない?しかも変な感じで」です。

 そしたら、英語が苦手な人でも何が書いてあるか分かって「こんな感じなんだー」となるかと思うと同時に面白翻訳期待してやってみました。

 

今回使うのは、CakePHPというフレームワークでBakeという機能を使い自動生成されたソースコード(プログラム)です。

内容は入力画面で入力された内容をデータベースに追加して、成功したら指定したページに移動するというものです。


    public function add()
    {
        $place = $this->Places->newEntity();
        if ($this->request->is('post')) {
            $place = $this->Places->patchEntity($place, $this->request->data);
            if ($this->Places->save($place)) {
                $this->Flash->success(__('The place has been saved.'));

                return $this->redirect(['action' => 'index']);
            } else {
                $this->Flash->error(__('The place could not be saved. Please, try again.'));
            }
        }
        $this->set(compact('place'));
        $this->set('_serialize', ['place']);
    }

 英語がさっぱり分からないという人には、なんの事か分からないと思いますので、

早速エキサイト翻訳にかけてみます。

 


    公的な機能加算()
    {
        $place = $this->Places->newEntity();
        ならば($this->request->is(ポスト'))
            $place = $this->Places->patchEntity($place、$this->request->data);
            ならば($this->Places->save($place))
                $this->Flash->success(__(『場所は救われた。』));

                帰りの$this->redirect([『行動』 => 『インデックス』 ]);
            他に
                $this->Flash->error(__(『場所はsaved.であるはずがない 再びトライする 。』));
            }
        }
        $this->set(コンパクト(『場所』));
        $this->set(『_serialize』、[『場所』]);
    }

 んー。肝心な箇所は訳されてないですね。プログラム的な書かれ方だとスキップしちゃうのかな。

「場所は救われた」はふふってなりました。

ちょっと期待外れだったので、次はgoogle翻訳してみます。

 


パブリック関数add()
     {
         $ place = $ this-> Places-> newEntity();
         if($ this-> request-> is( 'post')){
             $ place = $ this-> Places-> patchEntity($ place、$ this-> request-> data);
             if($ this-> Places-> save($ place)){
                 $ this-> Flash-> success(__( '場所が保存されました。'));

                 $ this-> redirect(['action' => 'index'])を返します。
             } else {
                 $ this-> Flash-> error(__( '場所を保存できませんでした。もう一度やり直してください。'));
             }
         }
         $ this-> set(compact( 'place'));
         $ this-> set( '_ serialize'、['place']);
     } 

 

プログラム的な箇所は綺麗に残りましたね。

「パブリック関数add」と出力するあたりは翻訳する文章の分類分けがきちんと出来てる印象です。

さすがgoogle先生

 

でも、期待していたような面白翻訳してくれないので、次に行きます

Yahooさんにお願いしてみました。

 


公的な機能は、加わります()
{
= $this-場所-newEntity()を出してください;
もしも($this-request-is(『ポスト』)){
= $this-場所-patchEntity(出します、$this-要請-データ)を出してください;
もしも($this-場所-保存(出します)){
$this-フラッシュ-成功(__(『場所は保存されました』。));
$this再直接尋問の([=が『インデックスを付ける』『行動』])復帰;
}他に{
$this-フラッシュ-エラー(__(『場所は、保存されることができませんでした。もう一度ためします』。));
}
}
$this-セット(コンパクトな(『場所』));
$this-セット(『_serialize』[『場所』]);
}

 ちょっと期待値に近づきました(笑)

何故か変数$placeがなくなってます。「を出して下さい」に置き換わった?

「置く」的な解釈なのかな

redirect(このページに飛んでね)が「再直接尋問」は良いですね(笑)

というか、むしろ解り辛くなった感があります。

 

なんだか全体的に「だから何?」的な感じになってしまいましたが

まぁ、あれです。これからプログラムを始めたいけど「英語が...」って人は、そんなに気にしないでとにかく初めてみてください。むしろ難しいのは文字的な物ではなく構造的な方です。

何事も最初の一歩を踏み出すことが大事です。

どーんと行っちゃって下さい。

OCR機能付きペンスキャナーで商品チェックするぞ(3)

前回はOCRペンスキャナーをFileMakerで作ったアプリケーションで使用しようとしたら、うんともすんとも言わなかったで終わりましたが、今回は解決編です。

ちなみに解決方法の一つにPowerShellというWindows特有の機能を使いますのでWindows限定の解決方法になります。

 

今回とる解決手段は「ペンスキャナで読むときにFileMakerにフォーカスを当てない」です。

 

前回にも書いたように、FileMaker以外の例えば標準のテキストエディタとかだと普通にOCR読みした内容が流れてくるしクリップボードにも内容がコピーされるのを確認しているので、ペン型スキャナで読み込むときだけ別のウィンドウにフォーカスを当てればクリップボードに欲しい内容が残るので、その後FileMaker側でクリップボードの内容を取得すればOK的な処理を加えます。

 

まず、フォーカスを当てるべきウィンドウを何で作るかですが、今回はWindows7以降でOS標準搭載となっている「PowerShell」を使います。(私の使っているのはWindows10です)

またFileMaker側でクリップボードの内容を取得する際に、読み込みが終わった事を検出する必要があるのですが、どうやら外部のプログラムを起動してから終了するまで処理を待ってくれるオプションは無いようなので、PowerShell側からFileMakerに通知させるようにします。

これを可能にするのが「FMPプロトコル」です。とは言っても初めて使うのでちょっとドキドキですが実装してみましょう。

その前にクリップボードから内容を取得するスクリプトを作成します。名前は「clip_board」です。

f:id:lincle-imai:20170428162630p:plain

クリップボードからitem_cdに内容を貼り付けし、前回作った品名を探すためのスクリプト「item_search」を実行します。

 

次にPowerShell呼び出しとFileMakerへの通知を行う部分です。

 

 FileMakerで外部プログラムである「PowerShell」を使うには、スクリプトの「Eventを送信」を使い下記のように記述し、名前は「input_proc」とします。

f:id:lincle-imai:20170428155822p:plain

何を書いているかというと

powershell -WindowStyle Hidden


PowerShellを呼び出して、呼び出しオプションとしてPowerShellの画面は隠します。

add-type -AssemblyName "Microsoft.VisualBasic"


VisualBasicの機能を使いますよとPowerShellに教えてあげます。

[Microsoft.VisualBasic.Intetaction]::InputBox('読み込んでください','OcrPen',''); -Wait

ではフォーカスの当たるインプットボックスを表示します。WaitオプションはInputBoxが閉じるまで次に処理が行かないように待たせます。

最後にFMPプロトコルFileMakerアプリケーション内の「clip_board」スクリプトを呼び出します。

start 'fmp://$/OcrPen?script=clip_board';

 startはPowerShell上では「Start-Process」のエイリアスです。

fmp://~の部分がFMPプロトコルです。今回のように起動するスクリプトを指定する場合は「?script=~」とクエリ文字で指定します。

 

そして最後に上記のスクリプトを編集ボックスの「OnObjectKeystroke」に貼り付けて終わりです。

ペンスキャナにはボタンが付いていて、このボタンを押すとEnterのキーが送信されるので、読み込み前はスキャナのボタンを押してから読み込みになるようになります。

(ちょっと雑とはおもいますが...)

f:id:lincle-imai:20170428165401p:plain

さてでは動かしてみましょう。前回作成した「input」フォームを開き、「item_cd」編集ボックスにフォーカスを当ててからペン型スキャナのボタンを押します。 

f:id:lincle-imai:20170428171052j:plain

するとPoserShellのInputBoxが出てきて

f:id:lincle-imai:20170428171326p:plain

前回登録した「ラスパイマガジン」の数字表記コードを読み込みます。

f:id:lincle-imai:20170428172438j:plain

f:id:lincle-imai:20170428172802p:plain

そしてもう一回ペン型スキャナのボタンを押すと

f:id:lincle-imai:20170428173016p:plain

やっときたーーー!!

 

何とか成功しましたが、PowerShellの画面「Hidden」オプションつけたのに一瞬出ちゃうのね...

まぁ当初の目的「ペン型スキャナで商品の文字で書かれているコード読んだらFileMakerで作ったアプリケーションで商品名を表示する」は達成できました。

問題は色々ありましたが、FileMakerで意地になる必要あったのかな

ただこの状態では仕事で使うとなるとまだ問題はあると思います

例えば、途中まで同じ商品コードがあったら、どっちの商品なのかわからないとか

(A-1234という商品とA-12345という商品が存在するとか)

最低限コードの文字数は決まってないと不安ですね。

今回はまぁ、あくまで「技術検証」という事で(笑)

OCR機能付きペンスキャナーで商品チェックシリーズ」はこれにて終わりです。

「僕の備忘録」的なブログですが、誰かの役にたてば幸いです。

これからもFileMakerに限らずいろいろやっていきますので、興味のある方は今後もよろしくお願いします。

OCR機能付きペンスキャナーで商品チェックするぞ(2)

前回「WorldPenScan USB」なるペン型スキャナを購入したところまででしたが

今回は検証用としてペンスキャナで読み取った商品コードから商品名を表示するアプリケーションを作成します。

 

まずペン型スキャナから取得できる内容ですが

1.OCR(画像から文字を認識する機能)処理されたテキストデータ

2.読み込んだ画像データ

上記2点が取れます。今回は1のOCR処理済のテキストデータを使います。

 

ざっくりですが仕様を決めます。

1.商品マスタに登録されている「商品コード」がOCR処理されたテキスト上に

 存在するかをチェックする。

2.1で存在が確認された「商品コード」に対する「商品名」を画面上に表示する

上記2点のみです。

1は通常バーコードリーダーを使う場合はリーダーで読まれた「商品コード」を「商品マスタ」の中から探すのが通常のアプローチですが、OCR処理済のテキストは「商品コード」のみではなく、「読み取った範囲の文字を読んだもの」になるため余計な情報が入ってくることが予想されます。カタログなどでは文字で表記されている「商品コード」のすぐ近くに説明文が入っていたりすることは珍しくないので、殆どの場合一緒に読まれてしまうでしょう。通常のやり方で永遠にマッチングしない物になってしまうので、逆のアプローチをとります。

 

さて、開発環境ですが今回は「FileMaker」で作っていきます。

去年会社で導入して、ちょこっとした物は凄く早くできそうなのですが

私自身がまだあまり慣れてないので、勉強がてらやってみますね。

 

FileMakerを開いて「ファイル」→「新規ソリューション」でソリューション名を決め

保存したら作成開始です。

 

まず初めに「テーブル」を作成していきます。

f:id:lincle-imai:20170417111403p:plain

今回作るテーブルは2つ

1.「items」は商品の情報を格納する為の商品マスタです。

2.「input」は入力用のテーブルになります。ペンスキャナからの情報を受け付ける

 為の物です。

 

次にフィールドを追加していきます。まずはitems

f:id:lincle-imai:20170417111639p:plain

1.「item_cd」は商品コードを表します。スキャナで読み取った商品コードとマッチングをさせます。

2.「item_name」は商品名です。1でマッチングした場合に対となる「商品名」を表示させるための項目です。

 

次は「input」のフィールドです。

f:id:lincle-imai:20170417112011p:plain

「items」と変わらないですね(笑)。ただし重要な違いとして「オプション」でグローバルを設定しています。グローバル設定の詳細はグローバルフィールド(グローバル格納を使用するフィールド)の定義を参照願います。

今回グローバルを使っている理由は入力を受け付ける為だけで使用しています。

他の開発環境で作る場合では、なんのフィールドにも関連付けられていないテキストボックスとかに入力値をいれて判定とかやればいいのですが、FileMakerでは殆どのオブジェクトはフィールドに関連付けしないといけないので、入力用のテーブルをグローバル設定にして使用しています。

 

次に通常であればFileMakerの肝となるリレーションを設定するのですが、今回は設定しません。f:id:lincle-imai:20170417114219p:plain

 

次は画面の作成です。itemsの画面は登録と検索に使います。

f:id:lincle-imai:20170417130053p:plain

特におしゃれもせず単純に並べます。

 

次はペンスキャナからの入力を受け付けるinputの画面です。

f:id:lincle-imai:20170417130423p:plain

入力の項目は「item_cd」のみ、item_cdにOCR処理された「商品コードを含んだテキスト」が入力され、一致する商品コードがあれば隣のitem_Name(商品名)に表示されます。

 

最後はスクリプトの作成です。

item_cd編集ボックスのスクリプトトリガの「OnObjectSave」(入力内容が保存されるとき)に下記のスクリプトを発動するようにします。

f:id:lincle-imai:20170417132050p:plain

何をしているかといえば、最初の仕様で書いたように

OCR処理されたテキストは商品コード以外を含んでいる可能性が高い為通常と逆のアプローチをとります。

OCR処理済テキストのテキストの中に、「マスタ登録された商品コード」が入っているかをチェックする為、商品マスタテーブルの「item_cd」を一行ずつループで回し、

Position関数を使って0以上の値が帰ってくれば現在処理中の行の商品コードが存在する事になるので「input」の商品名に該当した行のitem_nameをコピーします。

 

これで完成のはず!

 

まずは商品マスタにそこらへんにあった「ラスパイマガジン2月号」を登録します。

f:id:lincle-imai:20170417132413j:plain

そして手入力でテスト

item_cd編集ボックスに写真にも写っている「66996-42」と入力しEnter

f:id:lincle-imai:20170417132721p:plain

おぉー。ちゃんと「ラスパイマガジン」と表示されました。

ちなみに一致しない内容を入力すると

f:id:lincle-imai:20170417132957p:plain

となります。

では、商品コード以外の内容も入力してみましょう。

「ABCD66996-42aaa」と入力してみました。

f:id:lincle-imai:20170417132721p:plain

おぉー。ちゃんと認識しました。さっきのラスパイの結果と同じ写真ですが、スクリプトで商品コード以外の文字はいらないので、マッチした場合は商品マスタの商品CDをコピーして表示しています。

 

一個だけではテストにもならないので、他にもいくつか登録をしてテスト。

ちゃんと動くのを確認して、いよいよペン型スキャナ「WorldPenScan  USB」を使ってのテストです!。

ちなみにこのペン型スキャナは読み込むとそのまま現在フォーカスの当たっているところに読み込んだ内容を書き込んでくれます(さらにクリップボードにも残る)。USBバーコードリーダーでよくある「キーボードエミュレーション」なんでしょうね。ということは、先ほど作ったinput画面のitem_cdのところにフォーカスを当てておいて、そのままスキャナで読み込めば動くはず!

 

あれ?

スキャナはちゃんと読み込んでいるのに画面に変化が無い。

まったく画面に変化無し。

何回やっても変化無し。

念の為クリップボードに残ってないかテキストファイルを作って貼ってみましたが何も無し。

 

原因が掴めないので、FileMakerのUI周りを確認。VisualStudioについてくる「spy++」でウィンドウハンドルの状態を確認してみると...

肝心の作成した画面まわりのハンドルが取れません。

FileMaker独自のUIを使ってるのかな?

とはいえキーボードの入力は受け付けるので、キーボードエミュレーションっぽいペン型スキャナのアプリケーション(使う時は「WorldPenScan」っていうアプリケーションを起動します)側の問題?

多分ですが、スキャナ側のアプリケーションで入力可能な属性かどうかチェックしてからOCR処理後のテキスト出力を行っているんじゃないだろうか?

クリップボードの方も相変わらず取れないし....

んー諦めるしかないのか!?

いや!私もしょぼいとはいえエンジニアの端くれ!足掻いてやるぜ!

 

大分長くなってしまったので今日はここまでです。

次回力技で解決します。こうご期待(見てる人いるのかな?)

OCR機能付きペンスキャナーで商品チェックするぞ(1)

ご覧いただいている皆様初めまして

物流会社で社内(たまに社外)向けシステムとか作ってる今井と申します。

 

さて、皆さん物流システムとかってバーコードリーダー使ってピッピピッピばかりしてると思ってる方も多いと思うのですが、その通りです。それだけじゃないけどバーコードはよく使います。

 

扱う商品が多かったり似た商品が多かったりする場合、人だけを頼りに作業をすると商品を間違えて発送してしまうなんて事故も起こりやすくなります。

そこで商品に付いているバーコードをバーコードリーダーで読取って、納品書の商品とマッチングさせる事で間違いを防止する事が出来ます。

 

バーコード万歳!!

 

なのですが、世の中の全ての商品にバーコードが付いている訳ではなく

「商品名」だけとか「数字とアルファベット表記の商品コード」だけなんて物も沢山あります。

例えばカタログとかチラシなんて、まず間違いなくバーコード付いてないです。

私の所属する物流会社では、上記のような物も多く扱っていて1日に何千何万と作業をしていくのですが、中には送り先によってカタログの組合せが違うなんてのも当然あるので、以前から「バーコードが付いてたらなぁ」という事が沢山ありました。

 

最近仕事中に色々検索してましたら、「ペン型スキャナ」なる物を見つけて、

「ひょっとして、これで商品コードの部分の画像取り込んでOCRにかけたら、数字とかアルファベットの商品コードも読めるんじゃない?」と思いまして、早速社長にお願いして買ってもらいました。

買ったのは「サンワサプライ」が販売している「WorldPenScan USB」という商品です。

f:id:lincle-imai:20170412132810j:plain

 

左側に読取部分。右側はローラーになっていて回っている時だけ読取を行う。

f:id:lincle-imai:20170412141832j:plain

商品が届いて気付いたのですが、この商品「OCR機能」が付いていたのですね

(買う前にちゃんと調べない無能っぷり)

 

っで実際にこのペンスキャナを使って、現場のバーコードが付いていない商品(数字のみの商品コードが印刷されている)を読み取ってみたら、これが結構正確に数字の商品コードをテキスト化してくれます。

その証拠写真を載せたいところですが、お客様の商品を勝手にアップするわけにもいかないので、次回別の物を用意して紹介しますね。

今回はとりあえずここまでです。次回は読み込んだテキスト(商品コード)を使って簡単な商品判定ツールを作ってみます。