[OCR]情景文字認識(Scene Text Detection) pythonライブラリー

## 概要

今回はあるSTD(scene text detection)ライブラリーを使う感想を記録したいんです。

[github](https://github.com/breezedeus/cnstd)

>CnSTD 是 Python 3 下的场景文字检测（Scene Text Detection，简称STD）工具包，支持中文、英文等语言的文字检测，自带了多个训练好的检测模型

`CnSTD`ライブラリーの実行環境は`Python 3`で、中国語、英語など言語も文字認識もできます。中身は学習済の`machine learning`モデルも含まれています。


## インストール

docker環境以下実行し、CnSTDは`openCV`を使い、まずは`libgl1-mesa-dev`をインストールする必要があります。

```
apt-get install -y libgl1-mesa-dev
```

cnstdをインストール(デフォルトのmachine learningモデルも含まれているので、ちょっと重いかもしれません。)


```
pip install cnstd
```

cnocrをインストールします

```
pip install cnocr
```


## 使ってみた(OCR)

事前にテスト用の写真を用意しておく必要があり、今回は下記の`./test_ocr.jpg`という写真を用意しました。

![test_ocr.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1184340/b89b5801-f604-3973-de44-6773d782d03f.jpeg)


```python
from cnstd import CnStd
from cnocr import CnOcr

std = CnStd()
cn_ocr = CnOcr()

box_infos = std.detect('./test_ocr.jpg')

for box_info in box_infos['detected_texts']:
    cropped_img = box_info['cropped_img']
    ocr_res = cn_ocr.ocr_for_single_line(cropped_img)
    print('ocr result: %s' % str(ocr_res))
```

実行結果

```
ocr result: {'text': '新品', 'score': 0.9792218804359436}
ocr result: {'text': '两件套裙子', 'score': 0.980034351348877}
ocr result: {'text': '免费试穿', 'score': 0.9957491159439087}
ocr result: {'text': '不显肚子', 'score': 0.9964652061462402}
ocr result: {'text': '全国包邮', 'score': 0.9838100671768188}
ocr result: {'text': '赠运费险', 'score': 0.9975008368492126}
```

中国語の場合、scoreは`90%`以上となっているます。

日本語も試してみました。

![test_oo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1184340/f7650181-5a5f-2f95-9505-aab71672bba6.jpeg)



```
ocr result: {'text': '(C巾3', 'score': 0.29352283477783203}
ocr result: {'text': '毛', 'score': 0.3482152819633484}
ocr result: {'text': '列色X上', 'score': 0.21150672435760498}
ocr result: {'text': '大門', 'score': 0.7463467717170715}
ocr result: {'text': '日本语て', 'score': 0.9831153750419617}
ocr result: {'text': '岳子于', 'score': 0.39043349027633667}
ocr result: {'text': '中老U', 'score': 0.27085861563682556}
ocr result: {'text': '', 'score': 0.8908950686454773}
ocr result: {'text': '话', 'score': 0.5065010190010071}
ocr result: {'text': '日本帮', 'score': 0.25354406237602234}
ocr result: {'text': 'A', 'score': 0.24818772077560425}
ocr result: {'text': '吉南章', 'score': 0.4098373353481293}
ocr result: {'text': 'L', 'score': 0.19635368883609772}
ocr result: {'text': '百苯E住七', 'score': 0.1374766230583191}
ocr result: {'text': '百苯E住心', 'score': 0.20808185636997223}
ocr result: {'text': '外国人の一专', 'score': 0.16933318972587585}
ocr result: {'text': '外面人の一右', 'score': 0.1487574279308319}
ocr result: {'text': '英悟水て名人', 'score': 0.2745394706726074}
ocr result: {'text': '日本语水て83', 'score': 0.39503467082977295}
ocr result: {'text': '44%', 'score': 0.7512996196746826}
ocr result: {'text': '钛9人', 'score': 0.09978510439395905}
ocr result: {'text': '63%', 'score': 0.9509661197662354}
ocr result: {'text': '凳见!', 'score': 0.5658078789710999}
ocr result: {'text': '「白本汇住办外国人献、英语力て老子人占b', 'score': 0.2715124487876892}
ocr result: {'text': '日本语力て吉子人の方力多\\o」(苯颖出D)', 'score': 0.2607419490814209}
```


日本語も学習済モデルはないので、精度はに低いんですが(`score`は`10%`以下)、カスタマイズモデルを導入することもできますので、日本語文字に対応する必要がある場合、カスタマイズモデルを使った方が良いらしいです。但し、モデルを`ONNX`化にする必要があるらしいです。

> CnSTD 从 V1.2 开始，可直接使用的模型包含两类：1）CnSTD 自己训练的模型，通常会包含 PyTorch 和 ONNX 版本；2）从其他ocr引擎搬运过来的训练好的外部模型，ONNX化后用于 CnSTD 中。


linux環境なら、モデルの置き場は:`~/.cnstd`の配下となるそうです。

> Linux/Mac下默认值为 ~/.cnstd，表示模型文件所处文件夹类似


`CnStd`クラスは↓となるので、`std = CnStd(model_name = {カスタマイズモデル名})`にするなら、自分でトレーニングしたモデルも使えるようになりそう。(詳細はgithubを読んだ方が良いです。)

```python
class CnStd(object):
    """
    场景文字检测器（Scene Text Detection）。虽然名字中有个"Cn"（Chinese），但其实也可以轻松识别英文的。
    """

    def __init__(
        self,
        model_name: str = 'ch_PP-OCRv3_det',
        *,
        auto_rotate_whole_image: bool = False,
        rotated_bbox: bool = True,
        context: str = 'cpu',
        model_fp: Optional[str] = None,
        model_backend: str = 'onnx',  # ['pytorch', 'onnx']
        root: Union[str, Path] = data_dir(),
        use_angle_clf: bool = False,
        angle_clf_configs: Optional[dict] = None,
        **kwargs,
    ):
```