OpenSiv3Dで文字認識

この記事は、OpenSiv3D Challenge 2021 Challenge 09 | 手書き数字・英字の認識の一環として書いたものです。OpenSiv3Dで文字認識を行うために必要な手順をまとめました。
# 準備
使用するもの
- OpenSiv3D v0.6
- OpenCV(4.5.1)
- OpenCV_contrib(4.5.1)
- Tesseract(4.1)

この記事ではWindows10(64bit)でVisual Studio 2019, Cmakeを使うものとします。また、事前にVisual Studioインストーラーから英語の言語パックを追加しておく必要があります。


# OpenSiv3Dのインストール
現在、OepnSiv3D v0.6を使うには自分でビルドする必要があります。まずOpenSiv3Dのソースコードをダウンロードします。
詳しい手順は[OpenSiv3D | ライブラリの自前ビルド](https://zenn.dev/reputeless/articles/article-build-siv3d)を参考にしてください。

# Tesseractのインストール
1. Visual StudioインストーラーからVisual Studioに英語の言語パックを追加します。（追加していない場合）
1. Tesseractはvcpkgからインストールすることができます。まず[vcpkg](https://github.com/microsoft/vcpkg)をGitHubからダウンロードし、中にある「bootstrap-vcpkg.bat」を実行します。
2. vcpkgのある場所で管理者権限でコマンドプロンプトを開き`vcpkg install tesseract:x64-windows`というコマンドを実行します。
3. しばらく待つとインストールが完了します。

# OpenCV, OpenCV_contribのインストール
1. GitHubから[OpenCV](https://github.com/opencv/opencv)と[OpenCV_contrib](https://github.com/opencv/opencv_contrib)のソースコードをダウンロードします。


2. Cmake-GUIを開きます。「Where is the source code:」のところにOpenCVのsourceを指定します。「Where to build the binaries」にはビルドしたファイルを置く場所を指定します。この場所は後で使うので、できるだけ分かりやすい場所がお勧めです。今回は`opencv_build`というフォルダを新しく作りそこに保存することにしました。
3. 「Configure」をクリックし、出てくるウィンドウでは「Visual Studio 16 2019 Win64」を選択して「finish」をクリックします。
4. Name「OPENCV_EXTRA_MODULES_PATH」のValueに「opencv_contrib」を展開した先の「/modules」を設定します。もう一度「Configure」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659015/a1c7f200-d1cc-dd32-6ae2-bd9c5d81a32b.png)

5. Name「Tesseract_DIR」には「C:/.../vcpkg-master/x64-windows/share/tesseract」を、「Leptonica_DIR」には「C:/.../vcpkg-master/x64-windows/share/tesseract」を指定します。その他のオプションは自由です。ただし、**「BUILD_opencv_world」は必ずOFFにしてください。**これをOFFにしないと後で必要になるファイルが生成されなくなります。
6. もう一度「Configure」をクリックし、次に「Generate」をクリック。さらに、「Open Project」をクリックしてVisual Studio 2019を開きます。 

7. ビルドからバッチビルドを選択し、ALL_BUILDとINSTALLのDebug, Releaseの両方にチェックを入れ、ビルドをクリックします。
![batchbuild (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659015/d8514c3e-3f9e-32a6-ff1d-9a70f22e5920.png)




8. ビルドはPCのスペックによりますが1時間ほどかかります。これでOpenCVの準備は完了です。[^1]

# Visual Studioの設定
OpenSiv3DのソースコードをVisual Studioで開くと`Siv3D-Test` というプロジェクトが同梱されており、それを使うことでOpenSiv3Dのサンプルを動かすことができるようになっています。今回はそのプロジェクトのプロパティを書き換えることでOpenCVを利用できるようにしていきます。
1.まず、プロジェクトからプロパティを開き、VC++ディレクトリのインクルードディレクトリに
C:\ ...\opencv_build\install\include
を追加します。また、ライブラリディレクトリに
C:\ ...\opencv_build\install\x64\vc16\lib
C:\ ...\vcpkg-master\installed\x64-windows\lib
C:\ ...\vcpkg-master\installed\x64-windows\debug\lib
の3つを追加します。
1. プロパティのリンカーから入力を選び、その中の追加の依存ファイルに
C:\ ...\opencv_build\install\x64\vc16\lib\opencv_text451d.lib
C:\ ...\opencv_build\install\x64\vc16\lib\opencv_dnn451d.lib
C:\ ...\opencv_build\install\x64\vc16\lib\opencv_highgui451d.lib
C:\ ...\opencv_build\install\x64\vc16\lib\opencv_features2d451d.lib
C:\ ...\vcpkg-master\installed\x64-windows\debug\lib\tesseract41d.lib
の5つを追加します。
2. C:\...\vcpkg-master\installed\x64-windows\debug\binにある全てのファイルを、実行ファイルがあるフォルダ（ここからは `App` フォルダにあるものとします）にコピーします。
3. https://github.com/tesseract-ocr/tessdata_fast からjpn.traineddata（縦書きの文章を認識したい場合はjpn_vert.traineddata）をダウンロードします。ダウンロードしたファイルは、`App` フォルダに新しくフォルダを作り、その中に置いてください。(ここでは`data`というフォルダを作ったものとします。）[^2]
4. 認識させたい画像を用意します[^3]。読み込みたい画像ファイルのパスは、 App フォルダを基準とする相対パスか、絶対パスを使用してください。
5. Main.cppに文字認識を行うためのコードを書きます。ここでは[opencvで文字認識その１　Tesseractラッパ](http://whoopsidaisies.hatenablog.com/entry/2014/11/12/003100) を参考にしました。

```c++:Main.cpp
# include <Siv3D.hpp> // OpenSiv3D v0.6
# include <Siv3D/OpenCV_Bridge.hpp>
# include <opencv2/opencv.hpp>
# include <opencv2/text.hpp>

SIV3D_SET(EngineOption::Renderer::Direct3D11)
//SIV3D_SET(EngineOption::Renderer::OpenGL)
//SIV3D_SET(EngineOption::D3D11Driver::WARP)

void Main()
{
	// Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
	Scene::SetBackground(Palette::Black);
	Scene::SetResizeMode(ResizeMode::Keep);
	Window::SetStyle(WindowStyle::Sizable);
	// Window::Resize(1280, 720);

	// 画像読み込み
	cv::Mat image = cv::imread("example\\hayakuchi.png");
	Print << image.size().width;

	// グレースケール化
	cv::Mat gray;
	cv::cvtColor(image, gray, cv::COLOR_RGB2GRAY);
	// 文字認識クラスのインスタンス生成
	auto ocr = cv::text::OCRTesseract::create("data\\", "jpn");

	// ホワイトリストを消す
	// これを書かないとアルファベットと数字しか認識しない
	ocr->setWhiteList("");

	std::string text;
	std::vector<cv::Rect> boxes;
	std::vector<std::string> words;
	std::vector<float> confidences;
	// 文字認識の実行
	ocr->run(gray, text, &boxes, &words, &confidences);

	// 結果出力
	String s;
	if (boxes.size() > 0) {
		// 文字コードを変換
		s = Unicode::FromUTF8(text);
	}
	Print << s;
	
	
	while (System::Update())
	{	
	
	}
}
```

6.　Ctrl + F5を押して実行してください。
7.　ビルドエラーが発生した場合は、インクルードディレクトリやライブラリディレクトリが正しく設定されているか確認してください。ビルドが成功して実行する段階でエラーが発生した場合は、画像やtraineddataファイル、dllファイルがAppフォルダにあるかを確認してみてください。

# 実行結果
今回、認識に使った画像と認識結果は以下の通りです。

|![Siv3D App (Debug Build) _ D3D11 _ 61 FPS _ F 1200x900 _ V 800x600 _ S 800x600 2021_03_20 1_24_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659015/92e801b7-c73c-e1ef-ed0c-c0f7b2b61a7d.png)|![_無題 - メモ帳 2021_03_18 17_26_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659015/f61f55fd-109c-b8a8-4bba-b0bf46deb646.png)|
|---|---|
|認識結果|元の画像|
手書き文字での認識結果は以下の通りです。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659015/e83c1e21-373e-f93d-9928-4bd46a024832.png)|![hand.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659015/44488c4e-dbd6-7920-8767-be52b4c064ff.png)|
|---|---|
|認識結果|元の画像|

デジタルな文字については十分な精度で認識ができますが、手書き文字についてはまだ工夫が必要なようです。

# 参考資料
https://qiita.com/lilac0011/items/9fe6e061c3a036689a36
http://whoopsidaisies.hatenablog.com/entry/2014/11/12/003100
https://zenn.dev/reputeless/articles/article-build-siv3d
https://siv3d.github.io/ja-jp/tutorial/texture/#56




[^1]: ビルドには時間だけでなく、20GB ~ 30GBのストレージの空き容量が必要です。
[^2]: この認識用データは自作することもできるようですが、ここではリポジトリで公開されているデータを使いました。
[^3]: 余白の多い画像では文字の大きさを分析できないためか、失敗することがあります。