かくすけのいろいろ作るブログ

かくすけの開発者ブログです。開発の他いろいろなモノづくりについて書きます。

【CapTra】Windows 10 OCR 利用までの手順

この記事について

この記事ではWindows画面翻訳ツール「CapTra」の文字認識エンジン「Windows 10 OCR」を使うための設定手順をまとめています。

CapTraでは3種類の文字認識エンジンを使用できます。
それぞれの特徴は次のようになっております。
本記事ではこの中のWindows 10 OCRの設定手順を説明します。

※ 2020/06/22 時点での筆者PCでの表示画面です。OSのアップデートなどにより変更されている可能性があります。

デフォルト準備なしで使用できます。
高速で準備が必要ないことが強みですが、他のエンジンに比べ文字認識の精度は高くありません。
オープンソースOCRエンジン Tesseract OCR を使用しています。
Windows 10 OCR使用するためにはWindows側の設定が必要です。
(本記事ではこの設定手順を説明します。)
高速で安定した精度の文字認識が可能です。
Google OCR有料で使用できる文字認識エンジンです。
無料版・テスト版ではご利用いただけません。
認識に時間がかかりますが、高い精度での文字認識が可能です。

目次

  • Windows 10 OCR を使えるようにするための設定手順
  • 普段のPC利用に影響を出さないための追加設定手順

Windows 10 OCR を使えるようにするための設定手順

CapTraでWindows10 OCRを使うために必要な最低限の設定手順を説明します。


1. すでにCapTraを起動している場合は「×」ボタンを押してCapTraを終了させます。
f:id:kakusuke98:20200319233155p:plain

2. 画面左下にあるWindowsのスタートボタンを右クリックします。
f:id:kakusuke98:20200316125833p:plain
するとメニューが表示されます。

3. 表示されたメニューの「設定」をクリックします。
f:id:kakusuke98:20200316125915p:plain
Windowsの設定」ウィンドウが表示されます。

4. 表示された「Windowsの設定」ウィンドウのにある「時刻と言語」をクリックします。
f:id:kakusuke98:20200316130032p:plain
「日付と時刻の設定」ウィンドウが表示されます。

5. 表示された「日付と時刻の設定」ウィンドウの左側に表示されている「言語」をクリックします。
※ウィンドウの左側にメニューが表示されていない場合はウィンドウの幅を広げると表示されます。
f:id:kakusuke98:20200316130051p:plain
「言語」の設定画面が開きます。

6. 「言語」の設定画面にある「優先する言語を追加する」をクリックします。
f:id:kakusuke98:20200319150524p:plain
「インストールする言語を選択してください」ウィンドウが表示されます。

7. 「インストールする言語を選択してください」ウィンドウで
「English (United States)」をクリックして選択し、「次へ」ボタンを押します。
f:id:kakusuke98:20200319150543p:plain
「言語機能のインストール」ウィンドウが表示されます。

8. 「言語機能のインストール」ウィンドウで外せるすべてのチェックを外して「インストール」ボタンを押します。
※CapTra以外で必要であればチェックを入れたままインストールしても構いません。
f:id:kakusuke98:20200319150601p:plain
「言語機能のインストール」ウィンドウが閉じられ、言語パックのインストールがはじまります。

9. 言語パックのインストールが終わるのを待ちます。
f:id:kakusuke98:20200319150620p:plain

10. 「言語パックをインストールしました」と表示されれば設定完了です!
f:id:kakusuke98:20200319150713p:plain

CapTraを起動し、文字認識エンジンの「Windows10 OCR」を選択しても赤文字の注意文が表示されないようになりました。
「Windows10 OCR」をご使用いただけます。
f:id:kakusuke98:20200319153940p:plain

普段のPC利用に影響を出さないための追加設定手順

CapTraを利用する上では前項目の設定のみでも問題なく使えるのですが、
このままだと普段PCを使っている時に、操作ミスによって突然英語キーボードに変わってしまう恐れがあります。
本項目ではその問題を回避するための設定方法を説明します。
普段から英語キーボードを使用されている方はこちらの設定を行わなくて結構です。


1. 前項目の1~5を行い、「言語」の設定画面を開きます。

2. 「言語」の設定画面にある「常に規定として使用する入力方式を選択する」という文字をクリックします。
f:id:kakusuke98:20200319150735p:plain
「キーボードの詳細設定」画面が開きます。

3. 「キーボードの詳細設定」画面にある「言語バーのオプション」という文字をクリックします。
f:id:kakusuke98:20200319150749p:plain
「テキスト サービスと入力言語」ウィンドウが開きます。

4. 「テキスト サービスと入力言語」ウィンドウの上部にある「キーの詳細設定」タブを選択し、
表示された入力言語ホットキー内の「入力言語を切り替える」をクリックして選択します。
選択されたことを確認し、「キー シーケンスの変更」ボタンを押します
f:id:kakusuke98:20200319231312p:plain
すると、「キー シーケンスの変更」ウィンドウが開きます。

5. 「キー シーケンスの変更」ウィンドウで以下を選択します。
 入力言語の切り替え:割り当てなし
 キーボード レイアウトの切り替え:割り当てなし
両方選択した後に「OK」ボタンを押します。
f:id:kakusuke98:20200319150822p:plain
「キー シーケンスの変更」ウィンドウが閉じられます。

6. 「テキスト サービスと入力言語」ウィンドウの内容を確認し、「入力言語を切り替える」のキー シーケンスが「(なし)」になっていることを確認してください。
f:id:kakusuke98:20200319150840p:plain

7. 「テキスト サービスと入力言語」ウィンドウの「英語(米国) - US へ」の設定も4~6の手順と同じように行ってください。
「英語(米国) - US へ」についても キー シーケンスが「(なし)」になっていることが確認できたら「OK」ボタンを押してください。
すると「テキスト サービスと入力言語」ウィンドウが閉じられます。

8. 以上で設定は完了です!お疲れさまでした!

ブログ更新についてのお知らせとテスト版配布の予告

こんにちは。かくすけです。
今回はお知らせが2件あります!

お知らせ

今後しばらく、開発中のシステムのマニュアル記事をいくつか投稿します!

更新通知を受け取っている方の邪魔になってしまうかもしれないのでお知らせでした。

CapTraテスト版配布の予告

このシステムなのですが
kakusuke98.hatenablog.com

CapTra (キャプトラ)
という名称で近いうちにテスト版を配布する予定です!!
(できるだけ今月中に配布したい)
ついにここまで漕ぎ着けました。
みなさまの応援のおかげです。残りも頑張って開発します!

テスト版の配布は以下の方々に行う予定です

  • Youtubeチャンネルメンバーの方
  • 私と通話したことのある実況者さん
  • その他先着5名ほど、Steamのフレンドになれる方 (募集はまだです。開始時にお知らせしますね!)

こちらの事情でテスト版は大人数が同時に利用できないため、このような制限を設けさせていただきます。
この問題も含め、正式版までには機能拡張しますのでお待ちくださいませ!

それではお知らせでした!
お読みくださりありがとうございましたー!

Google Apps Scriptで作成した翻訳APIを使用する

こんにちは。かくすけです。
今回は翻訳用APIを作成する方法をまとめていきます。
ちなみに私はGASを使うのは初めてです。こんなに便利なものがあるなんて!

目次

  • GAS使用を決めた経緯
  • GASを使った翻訳APIの作成
  • おわりに

GAS使用を決めた経緯

ひとことでいうと「無料でつかえるから」です!

現在OCRと翻訳を使った↓のWindows Formアプリを開発しています。
kakusuke98.hatenablog.com

そして、このアプリにはすでに Google Transflation API を使った翻訳の仕組みを実装しています。
しかし問題点が。Google Translation API は使用するたびに課金される従量課金制です。
このアプリを公開・配布してしまうと、使われれば使われるほど私のお財布からお金が飛んでいくという悲しい状態になってしまうのです。
私はそんなにお金持ちじゃないのでできる限りお金が飛ばないようにできないものか・・・と考えてこの方法を見つけました。

GASは基本的に無料で使えるサービスで、ブラウザ上でjavascriptをベースとしたプログラムをかけるサービスです。
今回Googleの翻訳を使うように、GoogleカレンダーGmailなどのGoogleのサービスと連携させることもできます。API化もできるんですから、使い方は無限大ですね!

今まではAWSのサービスを使うことが多かったのですが、どうしても金銭面の問題があったので・・・今後はGASのお世話になることが増えるかもしれません!!

script.google.com

GASを使った翻訳APIの作成

コードの内容は次のページで紹介されているものをまるっと使わせていただきましたので、内容が気になる方はこちらのページを参考にされて下さい。
ありがとうございます!!
xn--pckzexbx21r8q9b.net

私の場合は一箇所だけ設定を変更しました。
参考ページの項目"APIを公開"の部分。
こちらのページではGoogle ChromeからのAPI呼び出しを想定されているのだと思います。

今回の私のパターンでは

  • Windows Form AppからAPIを呼び出す
  • 不特定多数の利用を許可する

ということで、次のような設定にしました
f:id:kakusuke98:20200213224105p:plain

"Execute the app as"では自分を選択します。
これにより、こちらのScriptは私のアカウントを使って処理を行います。
でもみんな使えるようにしたいんでしょ?と思われるかもしれませんが、この設定はあくまで"どのアカウントを使って処理を走らせるか?"の設定であって、"だれが使えるか?"ではありません。
その設定は次の選択です。

"Who has accecc to the app"で"Anyone, even anonymous"を選択することで誰でも使えるAPIとすることができます。
"全ユーザー"と"Anyone, even anonymous"の違いがわかりづらいですが、Googleへのログインが必要かどうかの差だと思います。多分。
今回はGoogleへのログインなしで使えるAPIにするので"Anyone, even anonymous"を選択しました。

おわりに

これでもう翻訳APIの作成が完了です!!
とっても簡単!!

ただし、無料ということでAPIの呼び出し可能回数には制限があります。
ログインしたアカウントでの制限のようでした!今回は誰でもアクセスできるログインなしの方法だから問題ない?

developers.google.com

制限はありますが、これによってとりあえず限定人数に向けたテスト公開は結構近いうちにできる気がしてきました!!
制限の内容はしっかりとは確認できていないのですが、スクリプトの実行アカウント(上の設定でいう"Execute the app as")によって制限回数が設定されているのであれば、Googleへのログインの仕組みを作ることで制限回数は気にしなくてよくなる気がします。

はやくテスト公開できるようにがんばるぞー!!

【C#】JSONテキストとして設定値を保持する

Visual Studio 2019
C#

こんにちは。かくすけです。
前回まではOCR関連の記事を書いていましたがそこはいったん置いといて、今回は設定した翻訳範囲の保持をできるようにしていきます。

開発中のシステム説明記事はこちら
kakusuke98.hatenablog.com

現時点で

  • 翻訳範囲指定
  • 文字認識
  • 翻訳
  • 翻訳結果表示

の一連の流れはできるようになっています。
ただし、いまは一度アプリを終了してしまうと指定した翻訳範囲は初期化されてしまうため、起動するたびに翻訳範囲を指定する必要があります。
ちょっとした手間ですね。今回はこのちょっとした手間を省けるよう、指定した翻訳範囲をアプリ再起動時にも指定したままにできるような仕組みを作っていきます。

目次

  • 概要
  • 設定値の読み込み・書き込み
  • JSONテキスト⇔オブジェクトの変換
  • 実際の動作

概要

翻訳範囲を変更したタイミングで設定値を保存し、起動時にはその値を読み込むようにします。

  1. アプリ起動
  2. 設定値取得
  3. JSONテキスト⇒クラスオブジェクト変換
  4. 翻訳動作など
  5. クラスオブジェクト⇒JSONテキスト変換
  6. JSONテキストを設定値として保存
  7. アプリ停止

という流れになります。

↓のページで紹介されているようにC#JSONを扱うにはいくつか方法があります。
dev.classmethod.jp

シンプルで軽量という理由でDynamicJsonを使おうかと思い、試してみたのですが私がJSONにしたいオブジェクトが複雑すぎてだめっぽかったのでDataContractJsonSerializerを使うことにしました。

設定値の読み込み・書き込み

次のページの通り、Visual Studio 2005 以降であればデフォルトで設定値保存機能があるようです。
dobon.net

こちらの方法を使ってアプリを閉じても値を保存できるようにしていきます。
私はVisual Studio 2019 を使用しています。

ページに書いてある通りなのですが、プロジェクト⇒〇〇のプロパティ⇒リソース の順番で選択し、設定一覧画面を表示します。
名前を入力し、データの種類を選択します。JSONテキストは文字列なのでstringを選択しました。
スコープはユーザーにしました。ユーザーにすることで同じPCであってもログインするユーザーが違えば別の設定値を使うことになります。

これで設定値の枠組みが準備できました!
しかし枠組みだけあっても仕方ありません。書き込みと読み込みを行います。
プロジェクト名部分や設定名部分は自分の環境に合わせて読みかえてくださいね。

設定値書き込み

// CaptureTransformApp:プロジェクト名 CaptureSettingSets: 設定名
CaptureTransformApp.Properties.Settings.Default.CaptureSettingSets = 'test';
CaptureTransformApp.Properties.Settings.Default.Save();

これで設定名"CaptureSettingSets"に"test"という文字列が設定できました。
設定値をセットした後はSaveしないと意味がないのでお忘れなく。
複数の設定値をセットしたい場合は複数セットして、最後に1度SaveすればOK。
私はメインウィンドウが閉じられる直前に呼ばれる「MainWindow_FormClosing」メソッドにこの処理を入れています。

設定値読み込み

// CaptureTransformApp:プロジェクト名 CaptureSettingSets: 設定名
CaptureTransformApp.Properties.Settings.Default.Reload();
string load_string= CaptureTransformApp.Properties.Settings.Default.CaptureSettingSets;

これで設定名"CaptureSettingSets"に設定されている値が取得できます。
セット後にSaveが必要なのと同様に、読み込み前にReloadをしましょう。
私はこの処理を起動時に行うようにしています。

JSONテキスト⇔オブジェクトの変換

前項目では"設定値の読み込み・書き込み"を紹介しました。
そこでは"test"という値をセットしていましたが、実際はJSONテキストを設定したいので

  • クラスオブジェクト⇒JSONテキスト変換
  • JSONテキスト⇒クラスオブジェクト変換

の方法を紹介します。

クラスオブジェクト⇒JSONテキスト変換

using System.Runtime.Serialization.Json;  // 最初に読み込む必要あり
...

using (var ms = new MemoryStream())
using (var sr = new StreamReader(ms))
{
    var serializer = new DataContractJsonSerializer(typeof(SetValues));  // SetValues: オリジナルクラス名
    serializer.WriteObject(ms, setValues);  // setValues: JSON変換したいオブジェクト
    ms.Position = 0;

    var json = sr.ReadToEnd();  // jsonにJSONテキストが代入される
}

今回は SetValues というオリジナルクラスのオブジェクトをJSONテキストに変換しています。
ここで変換したJSONテキストを設定値書き込みで書き込んであげれば、複雑なクラスでも設定値を保持することができます!
そしてオリジナルクラスを使う場合は[Serializable]をクラス定義部分の直前に入れてあげる必要があります

こんな感じ。

[Serializable]
internal class SetValues
{
    public List<CaptureSettingSet> CaptureSettingSets;
    // オブジェクト生成
    public SetValues(List<CaptureSettingSet> captureSettingSets)
    {
        CaptureSettingSets = captureSettingSets;
    }
}

また、この例のようにオリジナルクラス内に別のオリジナルクラスが含まれる場合、含まれる方のクラス定義部分にも入れる必要があります。

JSONテキスト⇒クラスオブジェクト変換

// jsonString: JSONテキスト
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
{
    var serializer = new DataContractJsonSerializer(typeof(SetValues)); // SetValues: オリジナルクラス名
    SetValues testObject = (SetValues)serializer.ReadObject(ms); // SetValues: オリジナルクラス名
}

JSONテキスト⇒クラスオブジェクト変換は逆より簡単。
変換後のクラスを指定してあげる必要があるので、例のごとく SetValues の部分は読みかえてくださいね。

実際の動作

今回紹介した方法を使ったシステムのGIF動作です。
f:id:kakusuke98:20200205230308g:plain 「Shift + F2」と設定されていたものを「A」に変更した後、一度アプリを閉じて開きなおしても設定値が「A」のままになっています。

多くの Windows Form App で設定値の保存は必要になると思います。
是非ご活用ください!
そして、他に良い方法をご存知の方は教えていただけると嬉しいです。

【C#】【Tesseract OCR】画像処理を行ってOCRの精度を向上させる

こんにちは。かくすけです
前回はTesseract OCRを開発中の「画面翻訳ソフト」に導入し、デフォルト状態での精度を他のOCRエンジンと比較してみました。

kakusuke98.hatenablog.com

「画面翻訳ソフト」開発の発端と仕組みの説明記事はこちら

kakusuke98.hatenablog.com

その結果、使えそうだと判断したので今回はTesseract OCRの精度向上を目指して色々やってみます。
Tesseract OCR以外のOCRでも画像の変換処理は有効だと思いますが、一番結果がはっきりでそうだったのでTesseract OCRで確認しています。

そして、今回は前回の精度確認でTesseract OCRの認識精度が低かった以下のような
吹き出し無しでゲーム画面に白文字が表示されているパターン」
をうまく認識させられるようにすることを目的とします。
f:id:kakusuke98:20191113235320p:plain

こういうゲームは結構多いですからね。そしてこの場合大抵白文字なので白文字特化で対応させます!!

方法

精度向上の方法は

  • Tesseract OCRの学習
  • Tesseract OCRに渡す画像の加工

といったものがあると思います。

Tesseract OCRの学習

Tesseractには学習させるためのツールが準備されており、こちらの公式GitHubページではその方法が細かく紹介されています(英語)

github.com

しかし学習というのは基本的に"特定の特徴をもつ画像内の文字を認識する精度を上げる"ためのものであると考えています。
つまり、いろんなタイプの画像に含まれる文字を認識させたい、つまり特徴がバラバラな画像を認識させる場合はあまり精度向上が見込めないか、むしろ精度が落ちる可能性が高いと考えました。
私のシステムではいろんなゲーム画面を読み込ませるつもりなので、このパターンに当たります。ですのでひとまず学習は無視します。
(いつかその人のプレイしているゲームにあわせて学習するようにできたら最高ですね。遠い遠いお話だけど)

ただ、学習とは違って使えそうな機能があるとどこかの記事で目にしました。
それは認識する文字の種類(アルファベットだけ認識するとか、どの記号を使うとか)を設定できるというもの。
それはぜひ使いたいと思っていたのですが、どうやらバージョン4では使えないようです(2019/12/05現在)
Tesseract OCR v4 を使うつもりでいたのですが、この理由でやはりv3にするかもしれません!が、それはまた今度のお話。今回はv4で検証していきます。

画像の加工手法

学習をさせないということで、私のシステムでは画像の加工を行うことで精度向上を図ります。
効果のある画像加工の手法も公式のGitHubページで紹介してあります。

github.com

これはありがたい!!
紹介されている画像加工の手法は以下の7つ。

  • 色反転
  • サイズ変更
  • 二値化
  • ノイズ除去
  • 傾き補正
  • ボーダー除去
  • アルファチャネル除去

色反転

Tesseractの公式のページには「バージョン3系までは暗い背景に明るい文字も認識するけど、バージョン4系は明るい背景に暗い文字しか認識しないよ」と書いてあります。
その割には前回↓の画像とかいい感じに認識してたけどね。

f:id:kakusuke98:20191205134541p:plain

できなくはないけど、得意ではないよということなんでしょうかね。
そんな難しいものでもないので対応します!

サイズ変更

公式の以下FAQページによると、Tesseractでは小文字のxが8ピクセル以上で解像度が300dpi以上の画像であれば文字認識し、8px以下の文字はノイズとして扱われるようです。

github.com

私のアプリでは切り抜き画像の高さが低い場合は拡大することににします。

二値化

二値化というのは画像を"真っ白"と"真っ黒"の2つの色だけで表現されることです。
ぼんやりとした画像は認識しづらいから白黒はっきりさせた画像にしな!ということですね。
とはいえこれは諸刃の剣。下手したら文字がつぶれちゃってまったく認識できないなんてことになりかねません。
私のアプリでは二値化ではなく中間のグレーも含むように変換します。

ノイズ除去

これはそのまま。ノイズは削除せいという話。
ゲーム画像はそりゃあノイズ多いのですが…私の力量では厳しいところがあります。とりあえず今回は見送り。

傾き補正

これも難しいですね!
文字そのものが傾いてたらちゃんと横並びになるように画像を回転させてね。というものです。
自動変換は難しいし、傾いてる文字自体ゲームの重要な文章には少ないと思うのでスルー。ゲームによってはそういう演出もあると思うけどね。
多分これはスキャン画像の認識などを想定した内容なんじゃないかな。

ボーダー除去

無駄な線は消してくださいという内容です。
これも多分スキャン画像で折り目の線が入っちゃったりしてる場合にはそれを取り除いた方が良いという話だと思います。
しかし同じ項目に気になる一文が。
"If you OCR just text area without any border, tesseract could have problems with it."
境界線の無いテキスト部分のみの画像を読み込ませたらエラーが発生するかもという内容だと思います。
ボーダーは消さないといけないけど境界線は必要・・・?
画像処理の最後に画像全体を細い白線で囲った方がいいのかも。やってみます。

アルファチャネル除去

アルファチャネルとは透明部分を表す情報。
今回はもともと透明色なんてないのでスルーします!

全項目について書いていきましたが、今回私がすることをまとめると

  • 色反転
  • 画像拡大
  • 4値化か5値化あたり
  • 境界線追加

となります!
ちなみに後ほど紹介しますが"4値化か5値化あたり"の処理ではちょっと特殊な変換をします。
細かいところは秘密ですが。

変換処理コード紹介

いよいよ実践です!
今回は実況動画をとっていた中で認識できなかった、ゲーム"Skylar & Plux Adventure On Clover Island"のこの画像を使用します。
f:id:kakusuke98:20191205151231p:plain

色反転

色反転は次のページのソースコードをほぼそのまま使わせていただきました。

参考にしたページ dobon.net

ColorMatrixを使って赤、青、緑の値を画像すべてのピクセルで反転(-1)させてありますね。
画像を色反転させた結果はこちらです!
f:id:kakusuke98:20191205151531p:plain ちゃんと反転されていますね!ちょっとホラーチックに。

しかしこれだけではOCR結果は相変わらず空のままでした。

画像拡大

今回の画像は文字大きいから拡大の必要なんてないんだろうけども。
できる仕組みだけ作っておきます。

こちらのページを参考にさせていただきます!
dobon.net

拡大にも色々な手法があるようですが、今回は高品質補間を使ってみました。
小さい画像のみ拡大する予定なのでそこまで処理に時間はかからないはず。
でもそれぞれの違いによる認識の結果を比較していないので、このあたりの検証もしないといけませんね!

ほぼ参考にさせていただいたページそのままですが次のようなメソッドを作成しました。

        //--------------------------------------
        // 画像をリサイズする
        // 引数: snap リサイズしたいBitmap
        //       width リサイズ後の幅
        //       height リサイズ後の高さ
        // 戻り値: リサイズ結果Bitmap
        //--------------------------------------
        private Bitmap ResizeBitmap(Bitmap snap, int width, int height)
        {
            // 描画先とするImageオブジェクトを作成する
            Bitmap canvas = new Bitmap(width, height);
            // ImageオブジェクトのGraphicsオブジェクトを作成する
            Graphics g = Graphics.FromImage(canvas);

            // 補間方法として高品質補間を指定する
            g.InterpolationMode =
                System.Drawing.Drawing2D.InterpolationMode.High;
            // 画像をリサイズする
            g.DrawImage(snap, 0, 0, width, height);

            // 不要なオブジェクトを破棄
            snap.Dispose();
            g.Dispose();

            return canvas;
        }

そして結果はこちら!
f:id:kakusuke98:20191205155516p:plain

ブログ側の処理で自動リサイズされてたらほぼ同じ画像を載せてるだけになりますねw
もともと文字のサイズが原因で読み取れない画像ではないため当然のごとく認識結果は空のままです。
今回のこれはただの仕組みづくりですもん!

4値化か5値化あたり

まずは単純にグレースケール画像にしてみます。
こちらのソースコードをそのまままるっと使わせていただきました!

dobon.net

結果はこちら。ちゃんとモノクロ画像になってますね!
f:id:kakusuke98:20191205160205p:plain

認識結果は相変わらず。
ここで、自分でいままで使ってみて「Tesseractは原色に近い色と白文字の組み合わせに弱い」と感じていたので独自の画像変換値を準備することにしました。

参考にさせていただいたのはこちらの2値化のソースコードです。
dobon.net

ページ内こちらのコードでピクセル1つ1つの明るさをとって、白にするか黒にするかを決定しているようです。

    //新しい画像のピクセルデータを作成する
    byte[] pixels = new byte[bmpDate.Stride * bmpDate.Height];
    for (int y = 0; y < bmpDate.Height; y++)
    {
        for (int x = 0; x < bmpDate.Width; x++)
        {
            //明るさが0.5以上の時は白くする
            if (0.5f <= img.GetPixel(x, y).GetBrightness())
            {
                //ピクセルデータの位置
                int pos = (x >> 3) + bmpDate.Stride * y;
                //白くする
                pixels[pos] |= (byte)(0x80 >> (x & 0x7));
            }
        }
    }

私はここで明るさ「img.GetPixel(x, y).GetBrightness()」だけでなく色相「img.GetPixel(x, y).GetHue()」も使って計算するようにしました。
その結果はこちら!

f:id:kakusuke98:20191205161734p:plain

そして認識結果がついに空以外になりました!!
「v Wm“ ( , I // , \ /Mhat? w' 'e‘ll that’mat’... \」 まあボロボロではありますが…空よりはマシ!

境界線追加

ここまでやって私は感じ始めました。
「これって空で返ってきてるのは実は認識できていないわけではなく、それ以前に噂の"境界線がないエラー"が発生しているのではないか…」と

やってみればわかりますね!
もとの画像にただ白い枠線を入れただけの画像を生成して認識させてみます。
下のコードは雑なのであまりマネしないでくださいね。

        // Bitmapに枠線を追加する
        private Bitmap AddBorder(Bitmap snap)
        {
            // 描画先とするImageオブジェクトを作成する
            Bitmap canvas = new Bitmap(snap.Width + (1 * 2), snap.Height + (1 * 2));
            // ImageオブジェクトのGraphicsオブジェクトを作成する
            Graphics g = Graphics.FromImage(canvas);

            // 枠付き画像の生成
            g.DrawImage(snap, 1, 1, snap.Width + 1, snap.Height + 1);
            g.DrawRectangle(new Pen(Color.White, 1), new Rectangle(0, 0, canvas.Width - 1, canvas.Height - 1));

            // 不要なオブジェクトを破棄
            snap.Dispose();
            g.Dispose();

            return canvas;
        }

生成された画像がこちら!
f:id:kakusuke98:20191205170351p:plain

そして認識結果は空!!
良かった…いままでの努力は無駄じゃなかった…!

全部合わせた処理結果

前の項目で使用する画像処理を紹介しました。
ひとつひとつの効果は薄かったですが、組み合わせると・・・?

  1. 画像拡大
  2. 4値化か5値化あたり
  3. 色反転
  4. 境界線追加

の順番で変換処理をかけた結果はこちらです

これが f:id:kakusuke98:20191205151231p:plain

こう f:id:kakusuke98:20191205171427p:plain

ずいぶん変わりました!

そして、OCRの結果は・・・
「\ / \IIV // /\V / Plux: What? Well that’s just great... \」

まだまだゴミは残っていますが、ちゃんと文字が取得できるようになりました!!
無駄な部分はテキストを取得した後に取り除いたり、Tesseract OCR v3の認識する文字の種類設定機能を使うことで除去できる気がします!!

問題点

上の結果で良さそうに感じる結果が出たのですが、逆に悪いこともあります。
もともと認識できていたこの画像が
f:id:kakusuke98:20191205173136p:plain

こうなってしまい
f:id:kakusuke98:20191205173156p:plain

全然認識できなくなってしまいました。
今回の目的は吹き出し無しの白文字を取得できるようにすること(別モードとして切り替えられるようにする)だったから良いっちゃ良いんだけど…
それにしても文字がつぶれすぎじゃありません!?

きっと4値化か5値化あたりの変換時に白が正しく取得できていないのが原因ですね。
今後も解像度いじったり、閾値を変更したり、ピクセル単位の動作を確認しつつ修正したりする必要がありそうです。

とはいえいままで認識できなかった文字が認識できたんです!
大きな一歩ということで、今回はここまで!
読んでくださってありがとうございましたー!

【Tesseract OCR】【C#】Tesseract OCR をWindows Form Appで使ってみる

こんばんは。かくすけです!
相変わらずかめの速度ですが以下のWindows Form アプリケーションを継続して開発しています!

kakusuke98.hatenablog.com

今回はオープンソースOCRエンジン "Tesseract OCR" を導入し、その精度を "Google Translation API" "Windows10 のOCRエンジン" と比較してみました!

【注意】
私が開発しているのはゲーム内の英文をOCRで認識するものです。
日本語の精度確認はしておりません。

導入のきっかけ

まず、前回↓の記事でWindows 10のOCRエンジンを試してみて納得していたのになぜ Tesseract OCR に手を出したかというと、Windows10のOCRエンジンを使用する場合、利用する方に事前準備をしていただく必要があるからです。

kakusuke98.hatenablog.com

アプリ上でその準備をできるようにしたかったのですが、厳しそうだったので別のOCRエンジンを探したところ、Tesseract OCRを見つけました。

これであればアプリ内に必要データを入れこむことができるはず!!

アプリへの実装

C#での実装はこちらのページの内容ほぼそのまま使わせていただきました!

qiita.com

私はv3とv4の両方を使ってみたのですが、上の参考ページの方法はv3の方法です。
v4を使う場合は

Tesseract.Page page = tesseract.Process(img);

の部分を

Pix pix = PixConverter.ToPix(img);
Tesseract.Page page = tesseract.Process(pix);

みたいにしてTesseract専用のPixクラスに変換してあげる必要があります。
また、Pixクラスを使用するため最初に"using Tesseract;"での読み込みも必要です!

ちなみにv4はまだテスト段階です(2019/11/13 時点)

精度確認

さて、メインの精度検証に入ります。
Windows10のOCRを導入した際の以下記事での動作確認ではソースコードを読ませるという、精度確認とは絶対に言えないものだったので、Google, Windowsの精度確認も兼ねてます。

kakusuke98.hatenablog.com

今回は開発中のアプリの利用を想定し、ちゃんとゲーム画面で検証しましたよ!!

【ポイント】

  • 改行位置は開発中システムでいじっていたりするので気にしないこと
  • 実際の利用を想定して画面の切り抜き範囲(赤枠部分)は広めに設定している
  • 画面画像→認識結果表 の順番で載せていきます
  • 認識結果表の赤文字は誤字部分黄色ハイライトは問題のある脱字部分青文字は評価除外部分です。記号など、認識できなくても仕方ない部分は無視しています。
  • 認識結果表の赤文字と黄色ハイライトは私が手作業で付けてます。ちょっとくらい間違ってても許してくださいw
  • 誤認識率といった数字での結果は出していません。全部所感です。
  • Tesseract OCR v4 だけは切り抜き範囲を手動で指定しなおしたので若干元画像が違います。v3と同時に動作させることができなかったためです。精度にも少し影響あるかも…

使用した画面画像は11枚、画面画像を使わせていただいたゲームは

  • Remnant From the Ashes
  • The Wolf's Bite
  • Pyre

の3本です!どれも日本語がなくて自分自身悲しんでいるゲームです。自分のシステム使って遊ぶぞ!

画像1(Remnant From the Ashes)

f:id:kakusuke98:20191113234720p:plain

f:id:kakusuke98:20191113235251p:plain

画像2(Remnant From the Ashes)

f:id:kakusuke98:20191113235320p:plain

f:id:kakusuke98:20191113235342p:plain

画像3(The Wolf's Bite)

f:id:kakusuke98:20191113235553p:plain

f:id:kakusuke98:20191113235620p:plain

画像4(The Wolf's Bite)

f:id:kakusuke98:20191113235944p:plain

f:id:kakusuke98:20191113235704p:plain

画像5(The Wolf's Bite)

f:id:kakusuke98:20191114000108p:plain

f:id:kakusuke98:20191113235712p:plain

画像6(The Wolf's Bite)

f:id:kakusuke98:20191114000017p:plain

f:id:kakusuke98:20191113235724p:plain

画像7(Pyre)

f:id:kakusuke98:20191114000153p:plain

f:id:kakusuke98:20191113235817p:plain

画像8(Pyre)

f:id:kakusuke98:20191114000208p:plain

f:id:kakusuke98:20191113235825p:plain

画像9(Pyre)

f:id:kakusuke98:20191114000243p:plain

f:id:kakusuke98:20191113235836p:plain

画像10(Pyre)

f:id:kakusuke98:20191114000310p:plain

f:id:kakusuke98:20191113235843p:plain

画像11(Pyre)

f:id:kakusuke98:20191114000326p:plain

f:id:kakusuke98:20191113235852p:plain

感想

"考察"なんてタイトル付けられるほどの考察はできないので"感想"でw

私での所感での大雑把な精度の高さは
Google Translation API > Windows10 OCRエンジン > Tesseract OCR v4 > Tesseract OCR v3
ですね

やはりGoogleの認識精度はとんでもないですね!
Remnant From the Ashes のような"ゲーム画面に直接文字が表示されている"パターンでもばっちり。
選択肢部分をまとめて切り抜いた場合もしっかり認識してくれます。

Windows 10OCRエンジンは目立った問題はなく、たまに謎の誤認識があります。

そして今回のメイン、Tesseract OCR ! Tesseract OCRは背景の影響を強く受けてしまっていますね。文字以外の部分がごちゃっとしていると余計な文字が認識結果に含まれてしまいます。
画像4の↓の部分が全く認識できていませんでしたが、
f:id:kakusuke98:20191114002420p:plain ここの部分だけを指定してあげればちゃんと認識してくれました。やはり背景の影響を受けているみたいですね。画像全体の色味を元に画像変換処理がされているとかかもしれません。

また、文字が小さいものも苦手なようです。
画像8の認識結果は散々でしたが、切り抜き部分を拡大した状態で切り抜き、認識させてあげることでちゃんと認識されました。
システムで拡大させるだけで精度を上げることができるのであればここはそんなに問題ありませんね!
v3とv4は大きな差はこれだけではわかりませんが、やはり精度が上がっているような気がします。

Tesseract OCRGoogleWindowsには劣りますが、オープンソースですから。十分な精度を出してくれていると思います!
普通に吹き出しの内容だけを認識させてあげた場合にはちゃんと認識していますからね。

今後の方針

精度確認の結果から、私のアプリの方針が決まりました。

  1. デフォルトで使えるのは"Tesseract OCR"
  2. ちょっとした手間をかけて設定してくれる人は"Windows 10 のOCR"を使える
  3. 課金で"Google Translation API"の使用回数を購入できる

こんな感じ!
課金までしてGoogleを使う人は少ないと思いますが、それでコール回数分の使用量はまかなえます。

やっぱりこういう比較をするのは楽しいですね!
最後までお読みくださりありがとうございました!!

WindowsFormアプリをUWPに移行しようとして諦めた話

こんにちは。かくすけです。
今回は残念ながらWindowsFormアプリをUWPに移行しようとして諦めたことの報告になります…

UWPに移行をしようと思った経緯

私は次のようなWindows Formアプリを開発中です。
kakusuke98.hatenablog.com

WindowsFormでの開発は順調に進んでおり、基本的な翻訳動作はちゃんとするようになりました!
ゲームによっては正しく動作しなかったり、Google翻訳自体の誤翻訳があったりはしますが、自分や仲の良い人の間ではテストで使ってもらえるレベルにはなったと思います。

しかし公開するとなるとまた別。
翻訳処理を動かすたびに私のお財布からお金が飛んでいく仕様なので、そこを補う戦略が必要になります。
使ってもらいながら収入を得るためには、広告収入が良いと考えていたのですが、WindowsFormに広告を載せることはできず、最新のUWPを使用する必要がありました。

そこで、今までWindowsFormアプリとして開発していたものをUWPに移行しようとしたのですが…諦めたというのが今回の記事の内容になります。
とはいっても、絶対に無理!ってわけではありません。ただ、人に使ってもらう上での難易度的に現実的ではないなと… WindowsFormに広告載せられないの先に調べておけって話ですね!
使い慣れてるものを使って楽しようとした罰が下りました。

具体的にどの処理が移行できなかったのか?

UWPへの移行を諦めたといっても、もちろんすべての機能が移行できないわけではありません。
移行できなかったのは"画面の一部をキャプチャする機能"の部分です。

ここで、画面の"一部"というのがポイントです。
私の開発しているアプリではゲーム画面の一部を画像として切り出し、翻訳します。
しかし、UWPはWindowsFormにくらべてセキュリティががちがちになってしまったため、他のアプリや画面全体に影響のある処理は普通にはできなくなっています。

ですが、画面のキャプチャをとる方法は準備されてはいますし、実際に自分でコードを組んでみました。
UWPで画面のキャプチャを取得するには「Windows.Graphics.Capture」というものを使います。

参考
www.kinakomotitti.net

docs.microsoft.com

動作としてはキャプチャさせるウィンドウまたは画面をユーザーが選択することで、画面のキャプチャを許可できるというもの。
f:id:kakusuke98:20191104174416p:plain

これで許可して、画面のキャプチャをできるようにするところまではできました。
内容は参考にさせていただいたページほぼそのままなので割愛。

しかし問題はここから。そのウィンドウや画面から一部を切り出すという部分。

問題1. ユーザーがウィンドウを選択した場合

ここでユーザーがウィンドウを選択した場合はどうしようもありません。
できそうでできないんですよ。おしいんです。次の画像みたいな感じ。
f:id:kakusuke98:20191104175856p:plain

開発中のアプリでは、画面内のキャプチャしたい箇所をドラッグアンドドロップで指定します。
ここで、ユーザーが選択してキャプチャを許可したウィンドウの左端の座標さえわかれば、キャプチャしたい箇所の座標といい感じに演算して、キャプチャしたい箇所の画像を取得することができます。

  1. ユーザーがキャプチャするウィンドウを選択
  2. ユーザーがキャプチャする箇所を設定
  3. システムがウィンドウ全体画像を取得
  4. ウィンドウ左端の座標とユーザーが設定した箇所の座標をつかって、3で取得した画像の一部をトリミング

という手順でなんとかできるのです。できるのですが、左上の座標そのものを取得できないという仕様なのでどうしようもありませんでした。

問題2. ユーザーが画面を選択した場合

では、ユーザーが画面を選択した場合はどうでしょう?
たぶん大丈夫です。特に"すべてのディスプレイ"を選択してもらえたら安心です。
しかしなぜ諦めたのか?というと、ユーザーに対して「すべてのディスプレイを選択してね!」といちいち言うのはあまりよろしくないと思うからです。
世の中ちゃんと説明を読む人ばかりじゃありませんからね。
できる限りユーザーが何も考えずにやっても何とかなる仕様にしたいのでそれはボツにしました。

ここで、ユーザーが画面を選択するときの表示を"すべてのディスプレイ"だけにできるのであればよかったのですが、資料を読んだ感じだと無理そうでした。

UWPへの移行を諦めて今後どうするか?

上に書いたように、惜しいところまで行ったけど無理だった。という状況です。
では今後どうするかというと、ひとまずはこのままWindowsFormアプリとして開発を進めます。
で、お金の部分は寄付をいただくのと、拡張機能使用のための課金を準備することで賄いたいと考えています。
どうか、アプリを公開した際には"がんばって!"の寄付をいただけますと幸いです。
どうしてもマイナスが大きくなってしまった場合にはシステム停止ですね…

しかし、UWPへの移行を完全に諦めたわけではありません。
Microsoftさんは結構開発者の意見を取り入れていただけるので(多分このキャプチャ機能自体がそうやって追加された機能)

  • ウィンドウの一部をキャプチャできる機能の追加
  • 選択されたウィンドウの左上の座標を取得する機能の追加
  • ウィンドウと画面の選択肢を絞り込めるオプションの追加

を要望として出すことにします。
もし、この希望を聞いていただけたときには、今度こそUWPに移行したいですね!!
あ、私が気づいてないだけですでにこれらの機能が準備されていたら、コメントで教えていただけるとありがたいです!!

さて、今回はあきらめるという結果に至ったわけですが、UWP開発に挑戦する良い機会になりました。
クセはありそうですが、そこまでWindowsFormとの差は大きくないので、次にもうちょっと単純なWindowsアプリを開発する場合はUWPを使ってみようかな。

自分用に作りたいYoutubeの管理アプリとか Oculus Rift の一時的なデバイス無効化アプリとか、各種SNSの管理アプリとか作ってみたいんですよね。
夢がひろがるぞ~