おはよう君需要なし

求不得苦な日々

【備忘録】OpenCVのコールバックをうまいこと使いたい

はじめに

OpenCV、ちょこっと簡単なプログラムを組むぐらいだったらグローバル変数でごちゃごちゃやっちゃえば良いんだけど、 いろんな手法を試してみたいだとか、処理が煩雑になってくるとクラスを作ってそれぞれのメンバ変数で完結させたいことがある。

そんなときに弊害になってくるのが、TrackBarなどに代表されるCallback。

あれ、(void *)しか引数に取らないので、クラスのメンバ関数を指定したいときなどには使うことができない。どうしてもクラスのメンバ変数を使いたいときはstaticな関数を定義してやる必要がでてきて、メンバ変数を使用できません。これでは本末転倒ですね。

解決策

公式ドキュメントを見ればわかるのですが、createTrackbar関数は以下のようになっていて、

int cv::createTrackbar  (   const String &     trackbarname,
                const String &     winname,
                int *  value,
                int    count,
                TrackbarCallback    onChange = 0,
                void *     userdata = 0 
)

一方でTrackbarCallBackはこのように宣言されています。

typedef void(*     cv::TrackbarCallback) (int pos, void *userdata)

このuserdata、The optional parameter.としか書かれていませんが、 実際はCallbackが呼ばれるときに渡されるモノのポインタとなっています。

なので・・・

createTrackbar("hoge", "hage", &val, 100, Hoge::trackbar_callback, this);

このように、クラス内でcreateTrackbarをするときの最終引数でthisを指定し、

static void Hoge::trackbar_callback(int pos, void* userdata){
    Hoge *self = (Hoge*)userdata;

とすることで、staticな関数内でselfという形でthisを参照することが可能になります。

たぶんこれ、TrackBarが表示されている状態でthisをdeleteすると落ちる気がしますが、そんな使い方はしないでね。

おわりに

記事にしてから気づいたんだけど、StackOverFlowにも同じコトかかれてました(2番目)

stackoverflow.com