#76 スクリーンショットから文字を抽出する
ある Facebook グループに寄せられていた、以下のような悩み。
具体的なサービス名は明記されていませんが、「寿司打」の成績を報告する 「Google フォーム+ Google スプレッドシート」についての悩みのようです。
成績を Google フォームで回収して、成績は児童生徒が手入力させるものの、その証拠データとして添付するスクリーンショットとの整合性を手作業でチェックするのはとても面倒ですよね…
処理対象の画面
「寿司打」の成績をスクリーンショットした画像ファイルの実例については、↓ で言及されているように、注意が必要なように感じられます。
引用の範囲であれば記事中に掲載してもいいように思うのですが、微妙な感じがしないでもないので、具体例は掲載しません。
具体例がなくても、イメージは伝わると思います… 実際にどんな画面が表示されるのかは、「寿司打」をプレイしてみてください。
画像ファイルには、以下の情報が文字として記録されているので、これらの情報がテキスト化できれば、処理が自動化できそうです。
何円分のお寿司をゲットしたか?
正しく打ったキーの数
平均キータイプ数
ミスタイプ数
作成したプログラム
(1)参考にしたサイト
以下のサイトで紹介されていた方法を参考にして、Google フォームからアップロードされた画像ファイルをテキスト化することにしました。
↑ のサンプルでは、指定したフォルダの中にあるファイルを対象に処理するようになっていましたが、指定したファイルのみを処理するようにするなど、プログラムの変更を行っていますが、根本的なテキスト化(OCR)の部分は変わっていません。
(2)作成したプログラム
今回作成したプログラムは、Google フォームで「ファイルのアップロード」によってアップロードした画像ファイル(スクリーンショット)を対象に処理を行います。
「ファイルのアップロード」による回答が、Google フォームの何番目の質問なのかについては、URL と思われる回答を回答の中から探すので、フォーム側で意識する必要はありません。 ※後述の「B:回答をまとめて処理する場合」で説明していますが、プログラムの使い方によっては変更しなければならない場合があります。
作成したプログラムを埋め込んだ Google スプレッドシートは、以下の URL にアクセスすることで、自身の Google ドライブにコピーを作成できます。
https://docs.google.com/spreadsheets/d/1Lm-UiBSC51TuLpy6z2HOaWnQqR2qfGNOTlRTzYeWk70/copy
このスプレッドシートには、シート「解析結果」とフォームからの回答を処理するための GAS のプログラムが保存されています。
プログラムは、後述するような 2種類の使い方ができ、それぞれの使い方での処理で共通化できる部分を関数にしてあるため、4つの関数を作成しました。
onFormSubmit
→ 後述の「A:トリガー関数で処理する場合」currentRowProc
→ 後述の「B:回答をまとめて処理する場合」procRowData
→ 与えられた行データをもとにして処理を行うimageReadOCR
→ 画像ファイルから「平均キータイプ数」「ミスタイプ数」を抽出
今回、上述のような構成で、サンプルとして用意した画像をテキスト化したら、「平均キータイプ数」と「ミスタイプ数」をうまく切り出すことができました。 ※はじめに公開したプログラムから、切り出すアルゴリズムを改良しました。
テキスト化した内容をそのまま出力するか、単位を付けずに出力するかは、プログラム中に定義されている OUTPUT_VALUE で設定できます。
配布したままの状態では OUTPUT_VALUE に 0 が設定されており、そのまま出力します。単位を付けずに出力する場合には 2 を設定してください。
以下が、実際のプログラムです。
上記のプログラムでは、うまく動作しなかったときに、挙動を確認できるように console.log() でデバッグ表示を残したままにしてあります。
スプレッドシートには結果しか表示されませんが、うまく動作しなかったときにログを確認してください。
(3)プログラムのカスタマイズ
今回のプログラムで、肝となる部分は以下の部分です。
75~80行目の部分で、画像ファイル中のテキスト情報を、変数 text に格納しています。
その後、81行目で「改行」「空白」によって区切って配列に格納して、目的のデータを探索しています。さらに別のデータを表示させたい場合には、81行目のあとに、変数 strSplit の内容を console.log() で表示させるなどして、画像ファイルからどのようなテキスト情報が得られたかを確認するといいでしょう。
使い方
作成したプログラムは、処理の対象となるデータによって 2種類の使い方ができるようにしてみました。
A:トリガー関数で処理する場合
→ フォームからの回答を処理対象とする。
関数 onFormSubmitB:回答をまとめて処理する場合
→ 既にスプレッドシートに記録されているデータを処理対象とする。
関数 currentRowProc
いずれの場合も、プログラムの内部的では同じ関数 procRowData を呼び出して処理を行っています。
補足:
処理の過程で、Google ドキュメントの作業ファイルを作成していますので、マイドライブのゴミ箱には、Google ドキュメントで作成された tmp というファイルが、処理した分だけ存在しているはずです。
A:トリガー関数で処理する場合
まずは、このスプレッドシートに、Google フォームの回答が保存されるように、Google フォーム側で設定を行ってください。
Google フォームから得られた回答を、トリガー関数でその都度処理する場合には、トリガー関数を設定します。
メニューから「拡張機能」→「Apps Script」と選択します。
画面左側の「トリガー」をクリックします。
更に、画面右下の「+ トリガーを追加」をクリックします。
トリガー関数として、下図のように設定します。
設定する内容としては、以下の 2項目に注意してください。
「実行する関数を選択」で「onFormSubmit」を選択。
「イベントの種類を選択」の項目を「フォーム送信時」に変更。
トリガー関数を設定しようとすると、実行するアカウントによる確認作業が必要になります。詳しくは以下の投稿をご覧ください。
トリガー関数を設定したら、スプレッドシートでの設定は完了です。
ここまでの設定が終われば、Google フォームから回答があると、添付された画像ファイルから抽出された内容を付加したデータが、シート「抽出結果」に書き出されます。
Google フォームからの元のデータ(下図のシート「フォームの回答 1」)には、加工を行っていません。
シート「解析結果」に書き出されるのは、Google フォームからの回答に加えて、「平均キータイプ数」「ミスタイプ数」を追加したもの。 ※Google フォームでの質問数に関係なく処理できるようにしてあります。
書き出し先のシート「解析結果」には、フォームの回答が追加されていきますが、1行目の見出し行は出力されていません。手作業でコピーするなりしてください。
書き出し先のシート「解析結果」のシート名は、プログラム中で固定となっています。存在チェックを行っていないので、プログラムが実行される前に作成されていなければなりません。
B:回答をまとめて処理する場合
既にスプレッドシートに保存されているデータを対象に処理を行う場合には、こちらの方法を使います。
処理対象となる行にカーソルを合わせて、関数 currentRowProc を実行すると、その行のデータに対して処理が行われます。
配布しているファイルでは、Google スプレッドシートの当該行を先頭から 10列分(READ_COLUMNS)読み込み、「平均キータイプ数」を 5列目(WRITE_COLUMN1)、「ミスタイプ数」を 6列目(WRITE_COLUMN2)、に書き出すようにしています。 ※Google フォームの質問数に応じて、プログラム中に定義された定数を変更しなければなりません。
画像ファイルの URL が READ_COLUMNS で指定された列までに存在していなければなりません。
WRITE_COLUMN1 と WRITE_COLUMN2 で指定された列に、処理結果を書き出します。
関数を実行する場合には、
「挿入」→「図形描画」で適当なボタンを作成して、作成したボタンに「スクリプトを割り当て」で、関数 currentRowProc を割り当てる。
「拡張機能」→「マクロ」→「マクロをインポート」と選択して、関数 currentRowProc をインポートして、「拡張機能」→「マクロ」→「マクロを管理」でショートカットキーを割り当てる。
最後に
今回のプログラムは、画像ファイルを Google ドキュメントへ変換することで、画像中の文字をテキストデータとして抽出する、OCR 機能を実現しています。画像ファイルを目視確認して、一つずつチェックするよりも格段スムーズに処理できるようになるのではないか、と思います。
スクリーンショットから文字が抽出できるテクニックは、別のケースでも利用できると思います!
最後に、お決まりのフレーズなどを書いておきます。
一応の動作確認は行っているものの、不慮のトラブルによって損害等が生じても、責任はとれませんので予めご了承ください。
コメントを含めても 130行くらいのスクリプトであり、実行に際して目的外の場所への書き出しや収集などは行っていません。
特別なエラー処理は行っていないので、意図しないケースでエラーが発生してしまうかもしれません。どうにもならない場合には、ご連絡ください。
わたし自身にしてみると、このような「スクリプトを作ること」が目的になっているような感じですが、このスクリプトが何かの役に立てば幸いです。
この記事が気に入ったらサポートをしてみませんか?