はじめに
dandelion先生( @dandelion1124 ) ならば、はじめてのG-API(前編)の続き、はじめてのG-API(後編)を執筆してくれる、と信じて!! (2020/11/08 20:32)
この記事はOpenCV Advent Calendar 2020の3日目の記事です.
TL;DR
- OpenCV 4.5.0 G-APIのFText Primitiveは、結構制約厳しい。
- 「文字が出ればよし!」で割り切って使いましょう。
- リガチャできないよ!
- フォント種別指定が一種類しかできないよ!
- パス描画できないよ!(いるかなあ・・・)
- 2値描画できないよ!
Motivation
あっ,freetype2モジュールネタで書いてくれそうな人だ!あと,OpenCVのテキスト描画周りはちょっと進展あったみたいです.https://t.co/c89KwQge7M
— dandelion (@dandelion1124) November 3, 2020
Another round with truetype font suppport. Made use of STB_truetype (tiny, 4Kloc single-file ttf parser and renderer), patched it to support variable fonts, almost refactored previous patch to use STB_truetype instead of freetype. Patch size went down from several megabytes to ~300Kb.
なるほど…
よし、G-APIで文字描画するところだけ書こう!!!
OpenCV関係の文字描画の歴史
これまでのOpenCVの文字描画は歴史を非常に簡単にまとめると、以下の通り。今回は、(3)の話。
(1) imgproc putText (A-Za-z0-9とかぐらいのシンプルなサポートしかない)
↓ ↓ ↓ 詳細はcv::putText()周り、ちと見てみるに昔書きました。
↓ ↓ ↓
↓ ↓ (2) freetype2 wrapper (contrib) ※流行らずメンテナンス不備状態に
↓ ↓
↓ (3) [G-API freetype2 APIでサポート] (https://github.com/opencv/opencv/tree/63b154396a9941e2cf24e42045b9f82eeed83824 )
↓ ↓
↓ (3.1) freetype2 libraryを3rd party libraryとして抱え込みたい
↓ ↓
↓ (4) G-API freetype2 backend
↓
(5) imgproc STB_truetype これによって、putText()関数で、truetype fontでの文字描画ができるようになる!!!上のはこの話です!
※ あ、あれ?(5)でSTB_truetypeを搭載すると、(3.1)でfreetype2 library抱え込む検討は要らなくなる…… よし見なかったことにしよう。
※ あ、あれ?(5)でSTB_truetypeを搭載すると、(2)でfreetype2 wrapper対応も要らなくなる…… は、削除していい?って確認中。
実際にG-APIで文字描画してみよう
実験環境
- ubuntu 20.10
- OpenCV 4.5.0
- GCC10
kmtr@ubuntu2010:~/work/opencv-4.5.0/build$ gcc --version
gcc (Ubuntu 10.2.0-13ubuntu1) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
kmtr@ubuntu2010:~/work/opencv-4.5.0/build$ pkg-config --version
0.29.2
情報源
https://docs.opencv.org/master/df/de4/group__gapi__draw.html
https://docs.opencv.org/master/d6/d69/structcv_1_1gapi_1_1wip_1_1draw_1_1FText.html
コンパイル時の諸注意
CMakeで、"WITH_FREETYPE"を有効にすること。そうしないと実行時に非サポートであることを怒られる。
コード
当該コード中にも記載されていますが、OpenCV 4.5.0のgapiでは、FText primitiveで" "を含む文字列は描画できません。
#include <opencv2/imgproc.hpp> // cv::FONT*, cv::LINE*, cv::FILLED
#include <opencv2/highgui.hpp> // imwrite
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/render.hpp>
int main(int argc, char *argv[])
{
if (argc < 2) {
std::cerr << "Filename required" << std::endl;
return 1;
}
const auto white = cv::Scalar{ 255,255,255};
const auto red = cv::Scalar{ 0, 0,255};
const auto black = cv::Scalar{ 0, 0, 0};
cv::Mat img(cv::Size(480, 160), CV_8UC3, white );
namespace draw = cv::gapi::wip::draw;
std::vector<draw::Prim> prims;
// Notice!!
// In OpenCV 4.5.0, FText doesn't support " "(white space)".
// Freetype module returns 0x0 bitmap.
// OpenCV received, but cannot create roi.
// Exception is happend as
// "Can't reallocate empty Mat with locked layout (probably due to misused 'const' modifier)
prims.emplace_back(draw::FText{ // FTEXT primitive
L"Hello,world", // Text
{68,100}, // Position (a cv::Point)
50, // Font Height
black // Color
});
prims.emplace_back(draw::FText{ // FTEXT primitive
L"Hello,world", // Text
{64,96}, // Position (a cv::Point)
50, // Font Height
red // Color
});
draw::render(
img,
prims,
cv::compile_args(
cv::gapi::wip::draw::freetype_font{"/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf"})
);
cv::imwrite(argv[1], img);
return 0;
}
出力結果
おまけ
ft_render.cppにパッチを当てると、4.5.0でも空白を使えるようになります。
void cv::gapi::wip::draw::FTTextRender::Priv::putText(cv::Mat& mat,
const std::wstring& text,
const cv::Point& org,
int fh)
{
GAPI_Assert(!FT_Set_Pixel_Sizes(m_face, fh, fh) &&
"Failed to set pixel size");
cv::Point pen = org;
for (const auto& wc : text)
{
GAPI_Assert(!FT_Load_Char(m_face, wc, FT_LOAD_RENDER) &&
"Failed to load char");
FT_Bitmap *bitmap = &(m_face->glyph->bitmap);
+ // FIXME: Skip glyph, if size is 0
+ if (bitmap->rows == 0 || bitmap->width == 0) {
+ int advance = (m_face->glyph->advance.x >> 6);
+ pen.x += advance;
+ continue;
+ }
比較
描画機能それぞれをまとめてみるとこうなる……
あのその、本当に「文字が描画できるだけ」なんですけど…だ、大丈夫なんですかね(心配)
(1) putText | (2)freetype2 wrapper | (3)G-API FTEXT primitive | |
---|---|---|---|
入力データ | ASCII | UTF-8 | UTF-16 |
リガチャ対応 | Not supported | OK | Not supported |
描画色指定 | OK | OK | OK |
描画線幅指定 | OK | OK | Not supported |
背景色マージ | OK | OK | OK |
内部フォント指定 | OK | Not supported | Not supported |
外部フォント指定 | Not supported | OK | OK |
複数外部フォント | Not supported | OK | Not supported |
二値ビットマップ描画 | Not supported | OK | Not supported |
多値ビットマップ描画 | Not supported | OK | OK |
パス描画(二値/多値) | OK | OK | Not supported |
8UC1 | OK | Not supported | OK(Maybe) |
8UC3 | OK | OK | OK(Maybe) |
8UC4 | OK | Not supported | OK(Maybe) |
まとめ(再掲)
- OpenCV 4.5.0 G-APIのFText Primitiveは、結構制約厳しい。
- 「文字が出ればよし!」で割り切って使いましょう。
- リガチャできないよ!
- フォント種別指定が一種類しかできないよ!
- パス描画できないよ!(いるかなあ・・・)
- 2値描画できないよ!
oh.... 夢も希望もない・・・?
大丈夫だ、問題ない!!
STB_truetypeは(OpenCVで文字描画をしたい)人々にとって、新しい希望になる、はず!!
こちらについては、19日に記事を投稿させていただきます!
さて、明日の記事は…
@fukushima1981 さんの「OpenCVの並列化フレームワークの謎挙動」です!!謎・・・謎!?いったい何だろう・・・とワクワクしつつ、ご精読ありがとうございました!