OpenCV Advent Calendar 2016、12月10日の記事です。
#はじめに
cv::matに日本語も描画したい!って人向けのガイダンスになります。
何ができるのか
OpenCVのcv::matに直接フォントファイル使って日本語が書けるよ!!
#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での作業手順を提示します。適宜、各自の環境に読み直してください。
- 必要なライブラリをインストールする
$ 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/
- 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 サンプルコードを動かしてみる(前述)
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 さんの「OpenCVとNPPの連携」です。
以上、よろしくお願いいたします。
技術的な説明
bitmap描画の場合
harfbuzzにUTF-8文字列を渡すと、gid(Glyph id)の配列が戻ってくる。各gidを基にfreetype library側でグリフをレンダリング→cv::matに合成をしています。
<path描画の場合>
path描画用のcallback関数を登録しておきます。freetype library側がmoveやline,cubic,conicなどのパス描画コールバック関数を呼び出してきます。ただし、OpenCVでは直接ベジェ曲線を描画できないので、仕方がなくn分割の直線に変換して描画しています。
harfbuzzは何のための使っているのか?
単純にUTF-8から、unicodeを取り出すのは容易である。これだけならばharfbuzzを使う必然性は低い。だが、harfbuzzを使うとunicodeの正規化処理も実行してくれる。これにより、例えば「か」+「濁点」が、「が」として描画されるようになる。
なお、harfbuzz側で計算した座標情報は今回は使っていない。全部、freetype側が計算した座標情報に従っている。
暫定対応
- 2016/12/10 最新版のopencvトランク使うと問題なかったので、下記コメントは削除。
2016/12/9現在ためしたらエラーがでたので当該エラー箇所を削除。
Unknown CMake command "ocv_add_testdata".```
- TEST付きでコンパイルすると、これもコンパイルエラーが発生する。
``` cmake-gui .. ``` なんかで、TESTモジュールコンパイルを外す。
~~