search
LoginSignup
4
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

OpenCV Advent Calendar 2020 Day 3

posted at

updated at

はじめてのG-API(文字描画編)

はじめに

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

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でサポート
 ↓ ↓
 ↓ (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"を有効にすること。そうしないと実行時に非サポートであることを怒られる。

image.png

コード

当該コード中にも記載されていますが、OpenCV 4.5.0のgapiでは、FText primitiveで" "を含む文字列は描画できません。

test.cpp
#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;
}

出力結果

image.png

おまけ

ft_render.cppにパッチを当てると、4.5.0でも空白を使えるようになります。

ft_render.cpp
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の並列化フレームワークの謎挙動」です!!謎・・・謎!?いったい何だろう・・・とワクワクしつつ、ご精読ありがとうございました!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4
Help us understand the problem. What are the problem?