freetype対応したまとめを(Harfbuzzも足したい！）

OpenCV Advent Calendar 2016、12月10日の記事です。

#はじめに
cv::matに日本語も描画したい！って人向けのガイダンスになります。
- 
# 何ができるのか
OpenCVのcv::matに直接フォントファイル使って日本語が書けるよ！！:smile:
![image](https://qiita-image-store.s3.amazonaws.com/0/89434/b3379629-f8cb-a2d0-3ebc-a64a86aeb78c.png)

``` a.cpp
#include <opencv2/opencv.hpp>
#include <opencv2/freetype.hpp>
#include <string>
#include <cstring>

int main(int argc, char **argv)
{
    std::string fontlist[] = {
"NotoSansCJKjp-Black.otf",
"NotoSansCJKjp-Bold.otf",
"NotoSansCJKjp-DemiLight.otf",
"NotoSansCJKjp-Light.otf",
"NotoSansCJKjp-Medium.otf",
"NotoSansCJKjp-Regular.otf",
"NotoSansCJKjp-Thin.otf",
"NotoSansMonoCJKjp-Bold.otf",
"NotoSansMonoCJKjp-Regular.otf",
"mplus-1c-black.ttf",
"mplus-1c-bold.ttf",
"mplus-1c-heavy.ttf",
"mplus-1c-light.ttf",
"mplus-1c-medium.ttf",
"mplus-1c-regular.ttf",
"mplus-1c-thin.ttf"
};

  int i;
  cv::freetype::FreeType2 ft2;
  ft2.setSplitNumber( 4 );
  cv::Scalar col ( 255,255,255 );

  cv::Mat src = cv::Mat::ones(800, 900, CV_8UC3) * 255;

  for(i=0;i<sizeof(fontlist)/sizeof(fontlist[0]);i++){
    ft2.loadFontData(fontlist[i], 0);

    ft2.putText(src, fontlist[i] + "これはharfbuzzのテストです",
      cv::Point(10 , 10 + i * 40), 30, col, -1, 16, false );
  }
  cv::imwrite("a.png", src);
}
```

## hint
線幅 に -1を指定するとbitmapでの描画モードになります。それ以外ならばpathでの描画モードになります。
bitmapモードで、lineStyleに16を指定すると、8bit画像でのマージモードになります。


# インストール手順
ここでは、Ubuntuでの作業手順を提示します。適宜、各自の環境に読み直してください。

1. 必要なライブラリをインストールする
` $ sudo apt install libfreetype6-dev libharfbuzz-dev `

2.フォントデータをダウンロードして、ワークフォルダに置く。

例えば、M+FONTSさん
http://mplus-fonts.osdn.jp/about.html#download
https://ja.osdn.net/projects/mplus-fonts/releases/62344

例えば、Google Noto Fontsさん
https://www.google.com/get/noto/

3. OpenCVとcontribをダウンロード

```
$ cd ~ && mkdir opencv2 && cd opencv2
$ git clone https://github.com/Itseez/opencv.git
$ git clone https://github.com/Kumataro/opencv_contrib.git
```

改造版contribについては、最新レポジトリとってきてもいいけど、 https://github.com/Kumataro/opencv_contrib/tree/freetype2 の右上でダウンロードしてもよいかもしれません。一番良いのは、オリジナルのopencv_contribにマージする事ですけどね（ちらっちらっ）。

4 contrib付きでMakefileを作成する
```
$ cd opencv
$ mkdir build && cd build
$ cmake -D OPENCV_EXTRA_MODULES_PATH=~/opencv2/opencv_contrib/modules .
```

そうするとこんな感じになる。（ただし、なんかマージしたコードでコンパイル通らない！詳しくは最後の暫定対応で）

```
  OpenCV modules:
    To be built:                 core flann imgproc ml photo reg surface_matching video dnn freetype fuzzy imgcodecs shape videoio highgui objdetect plot superres ts xobjdetect xphoto bgsegm bioinspired dpm face features2d line_descriptor saliency text calib3d ccalib datasets rgbd stereo tracking videostab xfeatures2d ximgproc aruco optflow phase_unwrapping stitching structured_light
```

再実行すると、コンパイルするモジュール一覧に"freetype"が追加されていることを確認できるはず。出来ない場合、freetype2とharfbuzzのどちらかの存在が確認できていないかも？

5 コンパイルを実行する
`sudo make install -j 8 install && ldconfig` 

6 サンプルコードを動かしてみる（前述）

``` Makefile
a.out : a.cpp
        g++ a.cpp -O2 -o a.out `pkg-config opencv freetype2 harfbuzz --cflags --libs`
```

# まとめ
- これでもう日本語を描画するためだけに、convertをがりがり呼び出す必要はありません！
- PRしたいけど（ほかのモジュールで）コンパイル通らないのは誰のせいかな？私？
- Happy OpenCV life !!

明日(2016/12/11)は、 [dandelion1124](http://qiita.com/dandelion1124) さんの「OpenCVとNPPの連携」です。

以上、よろしくお願いいたします。

# 技術的な説明
## bitmap描画の場合
harfbuzzにUTF-8文字列を渡すと、gid(Glyph id)の配列が戻ってくる。各gidを基にfreetype library側でグリフをレンダリング→cv::matに合成をしています。

![image](https://qiita-image-store.s3.amazonaws.com/0/89434/f03f40bc-8a03-a76d-3f7a-d20babc0dfcd.png)

＜path描画の場合＞
path描画用のcallback関数を登録しておきます。freetype library側がmoveやline,cubic,conicなどのパス描画コールバック関数を呼び出してきます。ただし、OpenCVでは直接ベジェ曲線を描画できないので、仕方がなくn分割の直線に変換して描画しています。

![image](https://qiita-image-store.s3.amazonaws.com/0/89434/e64df0cb-3664-eacc-eebe-1617924a37f1.png)

## harfbuzzは何のための使っているのか？

単純にUTF-8から、unicodeを取り出すのは容易である。これだけならばharfbuzzを使う必然性は低い。だが、harfbuzzを使うとunicodeの正規化処理も実行してくれる。これにより、例えば「か」＋「濁点」が、「が」として描画されるようになる。

なお、harfbuzz側で計算した座標情報は今回は使っていない。全部、freetype側が計算した座標情報に従っている。

## 暫定対応
- 2016/12/10 最新版のopencvトランク使うと問題なかったので、下記コメントは削除。

2016/12/9現在ためしたらエラーがでたので当該エラー箇所を削除。

```CMake Error at /home/kumataro/opencv2/opencv_contrib/modules/text/CMakeLists.txt:22 (ocv_add_testdata):
  Unknown CMake command "ocv_add_testdata".```

- TEST付きでコンパイルすると、これもコンパイルエラーが発生する。

``` cmake-gui .. ``` なんかで、TESTモジュールコンパイルを外す。

~~