Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9691

C#で英語ゲームのスクリーンショットからOCRと翻訳を行う

$
0
0

はじめに

この記事はゲーム The Elder Scrolls シリーズの1作目である Arena を何とか日本語で遊べるようにしようとする試みの中で、主だった技術部分のコードを備忘録として残すためのものです。
いきさつなどの詳細ははてなブログの記事にて記載しております。
The Elder Scrolls: Arena の日本語化 - 1 - プログラミング・動画編集 備忘録

なお、環境や作成するツールの形態は次の通りです。

Windows 7
Microsoft Visual Studio Community 2019
Version 16.6.3

Windows フォーム アプリケーション(.NET Framework)
.NET Framework 4.7.2

また、現時点での翻訳精度などは同じくはてなブログの次の記事に記載しております。
The Elder Scrolls: Arena の日本語化 - 2 - プログラミング・動画編集 備忘録

主な使用技術

OCR処理

ゲームのスクリーンショットからOCRを行う部分は Tesseract を使用します。
理由は以前調査した事があるため。
【随時更新】Python・OpenCV・Tesseractで参考にした記事などの一覧 - Qiita

翻訳処理

OCRで認識した文字列を翻訳するのは Selenium を使用して、Google翻訳にかける方法を使用します。
なお、以前同じような事を実施しており、その際は標準のWebBrowserコントロールを使用しましたが、スクリプトエラー等が発生しうまくいかないため、もっと行動な操作の行えるSeleniumを使用することにしました。

また、Google翻訳を使うだけであれば、GASを使って自分でAPI化するすばらしい方法が次の記事などでありました。
Google翻訳APIを無料で作る方法 - Qiita

ただ、今回は一応使えるものが出来たらツールは公開するつもりなので、自前のAPIを使う方法は避けるためブラウザを操作してGoogle翻訳を実行させるという方式をとります。

画像補正など

OCRの認識精度を高めるため、画像補正を行うのに OpenCvSharp を使用します。
OpenCvも使い方をほとんど忘れていますが、画像操作するならOpenCvだろうということで選択しています。

Tesseract

NuGet パッケージ マネージャーから Tesseractで検索。
Tesseractとあるのでインストール。バージョンは 3.3.0
サンプルコード内では、jTessBoxEditorにて作成したトレーニングデータを使用しているので、データが無い場合は以下の場所なりからデータを取得して適当な場所に配置してパスを指定する。
GitHub - tesseract-ocr/tessdata: Trained models with support for legacy and LSTM OCR engine

OCR

必要な部分のみ抜粋。

usingTesseract;vartesseract=newTesseractEngine(@"C:\tesseract\training\tessdata","eng01");varimage=newBitmap(@"C:\hoge.png");varpage=tesseract.Process(image);vartext=page.GetText();page.Dispose();

Selenium

NuGet パッケージ マネージャーから Seleniumで検索。
Selenium.WebDriverをインストールする。バージョンは 3.141.0
さらに、個別のブラウザのドライバーが必要なので、ここではChromeを使用する事にする。
Selenium.Chrome.WebDriverをインストール。バージョンは 83.0.0

ChromeにてGoole翻訳させる

SeleniumのChromeのドライバーを使って、文字列を渡して翻訳結果を返すクラスを次のように作成した。
Google翻訳部分の操作は、とりあえずこれで動いたというレベルのもの。もっといい書き方は今後模索する。
注意点としては、Quitを呼ばないと非表示にしているブラウザやコンソールが残ったままとなるので、特にデバッグ起動で強制終了などをすると裏で残されてしまう。

usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;usingOpenQA.Selenium.Support.UI;usingSystem;namespaceRTranslation{publicclassRSeleniumChrome{IWebDriverdriver;WebDriverWaitwait;publicstringTranslationString;publicRSeleniumChrome(){vardriverService=ChromeDriverService.CreateDefaultService();// コマンドプロンプト非表示driverService.HideCommandPromptWindow=true;// ヘッドレス(ブラウザを表示しない)varoptions=newChromeOptions();options.AddArgument("--headless");driver=newChromeDriver(driverService,options);wait=newWebDriverWait(driver,TimeSpan.FromSeconds(10));driver.Navigate().GoToUrl($"https://translate.google.com/?sl=en&tl=ja");}publicvoidClose(){driver.Quit();}publicstringTranslation(stringsrc){try{driver.FindElement(By.ClassName("clear")).Click();wait.Until(condition=>condition.FindElement(By.Id("source")).Text=="");driver.FindElement(By.Id("source")).SendKeys(src);if(wait.Until(condition=>{try{TranslationString=condition.FindElement(By.ClassName("tlid-translation")).Text;returntrue;}catch(Exceptionex){System.Diagnostics.Debug.Print(ex.Message);}returnfalse;})){returnTranslationString;}}catch(Exceptionex){System.Diagnostics.Debug.Print(ex.Message);}returnString.Empty;}}}

OpenCvSharp

こちらは正直どれを選ぶのが良いのかよくわかっていないが次のようにした。
NuGet パッケージ マネージャーから OpenCvSharpで検索。
OpenCvSharp4.Windowsをインストール。バージョンは 4.4.0.20200725
プロジェクトURLは次の通り。
https://github.com/shimat/opencvsharp

2値化

privateBitmapThreshold(stringfilename){varsrc=Cv2.ImRead(filename,ImreadModes.Grayscale);vardst=newMat();Cv2.Threshold(src,dst,100,255,ThresholdTypes.Binary);returndst.ToBitmap();}

クリップボード操作

実際にゲームをプレイしている際は、[Alt]+[PrintScreen]にてゲーム画面のスクリーンショットを取得する。
このため、クリップボードを監視して画像を取得できるようにする。

クリップボードを監視して画像を取得する

publicpartialclassForm1:Form{[DllImport("user32.dll",SetLastError=true)]privateexternstaticvoidAddClipboardFormatListener(IntPtrhwnd);[DllImport("user32.dll",SetLastError=true)]privateexternstaticvoidRemoveClipboardFormatListener(IntPtrhwnd);privatevoidForm1_Load(objectsender,EventArgse){AddClipboardFormatListener(this.Handle);}privatevoidForm1_FormClosed(objectsender,FormClosedEventArgse){RemoveClipboardFormatListener(this.Handle);}protectedoverridevoidWndProc(refMessagem){if(m.Msg==0x31D){GetImage();}else{base.WndProc(refm);}}privatevoidGetImage(){if(!Clipboard.ContainsImage())return;varimg=Clipboard.GetImage()asBitmap;}}

参考にした記事など


Viewing all articles
Browse latest Browse all 9691

Trending Articles