プログラミング・動画編集 備忘録

プログラミングや動画編集についての備忘録です

The Elder Scrolls: Arena の日本語化 - 7(テンプレートマッチング)

前回

ゲーム内の決まった内容のテキストについてはあらかじめ翻訳結果を用意するため、OCRで読み取った文字列とその翻訳内容とで、類似度が高いものを表示する仕組みを作成した。
rrryutaro.hatenablog.com

今回

OCRについてはとりあえず全画面のキャプチャに対してそのままOCRしているため、画面内の文字っぽい部分も読み取られてノイズが多い状態となっていた。
また、NPCの会話などは文字列の長さに応じてダイアログウィンドウのサイズが異なるため、PCOTでの固定翻訳も設定しづらい。
このため、翻訳した対象の文字列が表示される領域を特定できるようにしたい。

NPCの会話

NPCの会話は次のように表示される。
f:id:rrryutaro:20220321031144p:plain

ダイアログ部分は特徴的なので、ダイアログのパーツ部分を画像認識にて特定してダイアログのサイズを取得する。
いわゆるテンプレートマッチングを行えばよい。
マッチングするテンプレートはダイアログの四隅のパーツを用意することにする。
矩形の範囲を取得するには対角の2カ所を特定できれば良いので、左上と右下だけでも良いが、場面によってはカーソルが表示されるため、それがかぶさっていると正しく判定できないと思われる。
このため、四隅を確認して、正確に認識されたであろう部分からサイズを判定しようと思う。
パーツは次の部分を用意した。(10倍表示)


上左
f:id:rrryutaro:20220321032032p:plain:w120

上右
f:id:rrryutaro:20220321032057p:plain:w120

下左
f:id:rrryutaro:20220321032107p:plain:w120

下右
f:id:rrryutaro:20220321032041p:plain:w120

右側のパーツの角部分は透過している様で、背景によって色が変わるため、完全一致とはならないため、認識率の調整が必要となりそう。
テンプレートマッチングについてはこちらの記事を参考にさせていただきました。
nomux2.net

なお、現時点(2022/03/21)で OpenCvSharp44.5.5.20211231 が最新だったようなので、こちらを使用した。
また調べていないが OpenCvSharp.ExtensionsについてはOpenCvSharp4.ExtensionsOpenCvSharp4.WpfExtensionsとに分かれていた。
このツールはWindows Form アプリケーションとして作成しているので OpenCvSharp4.Extensions側を追加。

基本的には参考にさせてもらった記事のCvTemplateMatching部分のコードを流用させてもらい、次のような感じで変更した。
まだよくわかっていない部分など一旦結果として保存しているが、おいおい改善していこうと思う。
こんなに簡単にテンプレートマッチングが行えるのは、記事を公開されているノムノムさんのおかげですので感謝です。

class myCV
{
	public class CvTemplateMatchingResult
	{
		public double RateMin { get; set; }
		public double RateMax { get; set; }
		public Rect Rect { get; set; }
		public Mat Mat { get; set; }
	}

	public static CvTemplateMatchingResult CvTemplateMatching(string inputFileName, Mat template)
	{
		var result = new CvTemplateMatchingResult();

		using (Mat target = Cv2.ImRead(inputFileName, ImreadModes.Unchanged))
		using (Mat output = new Mat())
		{
			Cv2.MatchTemplate(target, template, output, TemplateMatchModes.CCorrNormed);

			OpenCvSharp.Point minloc, maxloc;
			double minval, maxval;

			Cv2.MinMaxLoc(output, out minval, out maxval, out minloc, out maxloc);

			result.RateMin = minval;
			result.RateMax = maxval;
			result.Rect = new Rect(maxloc.X, maxloc.Y, template.Width, template.Height);
			result.Mat = output;

			return result;
		}
	}
}

後は、OCR対象のイメージからそれぞれダイアログの四隅の画像を認識させて、NPCの会話のダイアログ部分のみを抜き出せばよい。
これまでは次の画面で認識させていた。
f:id:rrryutaro:20220321035258p:plain

ダイアログ部分がうまく認識できた場合は次のように抜き取った画像でOCRする。
f:id:rrryutaro:20220321035044p:plain

OCRの結果については、このケースではたまたまほとんど正しく読み取れているが、それでも改善前は余計なスペースや改行が含まれているし、背景によってはゴミが含まれるため大分良くなった。
基本的な仕組みは用意できたので、後は各パターン別にテンプレートを用意して、必要な調整を随時追加していこうと思う。
例えばお店では次のような表示となるので、この画面用のテンプレートを用意して読み取れるようにするなど。
f:id:rrryutaro:20220321040145p:plain