文字領域検出用のERFilterの使い方

これは、**OpenCV Advent Calendar 2015 24日目**の記事で筆者の２回目の投稿になります。前回の話は、[こちら](http://qiita.com/Taro-Yamada/items/5570a52487dd0d6cb1a8)
関連記事は[目次](http://qiita.com/advent-calendar/2015/opencv)にまとめられています。

![text5.PNG](https://qiita-image-store.s3.amazonaws.com/0/105738/169a99cd-cfcb-c822-c8cb-8ca13ce2ab9c.png)

#はじめに
opencv-contrib 3.1.0のtextモジュールには[2種類のアルゴリズム](https://github.com/Itseez/opencv_contrib/tree/master/modules/text)が実装されています。
１つは、文字領域の検出用で、もう一つは、文字の識別用です。


文字識別用**OCRTesseract**クラスは、有名なOCRソフト、tesseract-ocrのインタフェースのクラスであり、**tesseract-ocrが事前にインストールされていないと使用することはできません。**OCRTesseractの使用方法は簡単で、検出対象の言語を指定しOCRTesseract::createを行い、OCRTesseract::runに文字対象領域のmatを与えると、stringと領域とスコアを得ることができます。

もう一方の今回対象としている文字領域の検出用 **ERFilter**は、このOCRTesseract用の前処理に当たるもので、Webカメラやimageファイル内のtext領域を検出するためのクラスです。**こちらは、Contirbをビルドすれば使用することができます。**

cv::text::ERFilterに関する説明は[ここ](http://docs.opencv.org/3.0.0/da/d56/group__text__detect.html)に記載されています。ERFilterの使用方法の説明に使用した、文字検出のサンプルプログラムは、[これ](https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/textdetection.cpp)です。
Visual Studio 2015で新規プロジェクトを作成し、3.1用のpropatyを設定し、上記プログラムの中身をそのままコピーします。
#text検出処理の流れ

文字領域の検出の前処理とし、検出対処の画像を computeNMChannels を使用し、複数の画像を作成します。
` computeNMChannels(src, channels);` 

channelsには、オリジナルのアルゴリズムと異なり、ERFilterではred (R), green (G), blue (B), lightness (L), and gradient magnitude (Grad)の５つの画像が格納されます。

加えて、５つの画像の各画像の値を255から引くことで、各画像の反転画像を作成します
` channels.push_back(255-channels[c]);` 


これにより10画面分の画像が作成されそれれぞれ検出対象として扱われます。

ここでNeumann and Matasの文字領域検出アルゴリズムのベースとなる**ERFilter**の出番となり、第１ステージ、第２ステージのデフォルトの分類器を有する、ERFilterのオブジェクトを作成しています。第１ステージのパラメータは最後に説明します。

```textdetection.cpp
    Ptr<ERFilter> er_filter1 = createERFilterNM1(loadClassifierNM1("trained_classifierNM1.xml"),16,0.00015f,0.13f,0.2f,true,0.1f);
    Ptr<ERFilter> er_filter2 = createERFilterNM2(loadClassifierNM2("trained_classifierNM2.xml"),0.5);
```
上記カスケード分類器で各チャンネルを対象とし検出処理を実行します

```textdetection.cpp
        er_filter1->run(channels[c], regions[c]);
        er_filter2->run(channels[c], regions[c]);
```
検出された領域をerGroupingでまとめます。これにより文字候補の領域がgroups_boxesに格納されています。
` erGrouping(src, channels, regions, region_groups, groups_boxes, ERGROUPING_ORIENTATION_HORIZ);` 

erGroupingｍのパラメータは、ERGROUPING_ORIENTATION_HORIZは、水平に並んだ文字に適したアルゴリズムであり、ほかに任意の方向の文字に適したアルゴリズムERGROUPING_ORIENTATION_ANYがあります。


最後に検出した領域の個数分loop内でrectangleを描画します。
`rectangle(src,groups.at(i).tl(),groups.at(i).br(),Scalar( 0, 255, 255 ), 3, 8 );`

以上で説明は終わりです。
#実行結果のサンプル画像
いくつかの画像で試した結果を掲載します。
![text2.PNG](https://qiita-image-store.s3.amazonaws.com/0/105738/70aeb56b-e086-2c96-a66c-f20aa536c469.png)
1　textのサンプルに含まれていた画像　（看板の文字はだめでした）

![text1.PNG](https://qiita-image-store.s3.amazonaws.com/0/105738/61fc596e-cd4b-6c68-cc6a-e9e7ae9de3fe.png)
2　OpenCVのサンプルで使用されている基盤画像　（左上の文字がまったく検出できていない）

![text4.PNG](https://qiita-image-store.s3.amazonaws.com/0/105738/19966476-519a-19ac-b31e-792be08e08b8.png)
3　映画でこわされたホテル壁　(壁のタイルの誤認識が多すぎる）

![text3.PNG](https://qiita-image-store.s3.amazonaws.com/0/105738/82839dee-92ca-dbb2-02c7-9f7232cb61f8.png)
4　ガソリンスタンドの壁　（足の影響でしょうか）

以上は、サンプルプログラムで設定されたパラメータをそのまま使用したものです。それに対し、冒頭の画像は、4の画像に対して、**createERFilterNM1**検出器のパラメータ 16,0.00015f,0.13f を　修正したものです。

**16**の値は、**thresholdDelta**(Threshold step in subsequent thresholds when extracting the component tree)で小さくすると検出される領域が増えます。
**0.00015f**は、**minArea**(The minimum area (% of image size) allowed for retreived ER’s)で
**0.13f**は、**maxArea**	(The maximum area (% of image size) allowed for retreived ER’s)であり、元の画像に対する検出領域の最小、最大値を指定します。

#結果
期待していたほど文字領域の検出能力はよくないなという感想です。
やはり縦エッジが密集している領域を選択する傾向があるのかと推測しています。

#テスト環境
Windows10 Pro 64bit
OpenCV 3.1.0 + Contrib 3.1.0
Visual Studio 2015

明日はいよいよ今年最後の記事になります。