読者です 読者をやめる 読者になる 読者になる

OpenCV 2.xでマウスコールバックなGUI

opencv

このエントリーをはてなブックマークに追加

OpenCV 2.x系で、ウィンドウを表示してその上でマウスのクリックイベントを取得するGUIのサンプルです。OpenCV Tutorial 3のコードを大いに参考にしています。ただしC++系の関数に書き換えています。

基本的な流れは以下のようになります。

  • namedWindow()でウィンドウを生成
  • setMouseCallback()でコールバック関数を設定

あとは、マウスによるイベントが起こるたびにコールバック関数が自動的に呼ばれるようになります。

サンプルコード

適当な空画像を生成してウィンドウに表示します。ウィンドウの上で、マウスの左ボタンでエリアを選択すると、矩形が表示されます。終点を定めるまでの間に、仮の矩形が表示されるようになっています。

Windows 7 + Visual Studio Express 2013 + Opencv2.4.8で動作を確認しました。

/**
    @brief マウスコールバックのサンプルプログラム。Original: http://dasl.mem.drexel.edu/~noahKuntz/openCVTut3.html#Step%201
*/

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>


// グローバル変数
cv::Rect box;
bool drawing_box = false;

void draw_box(cv::Mat* img, cv::Rect rect){
    cv::rectangle(*img, cv::Point2d(box.x, box.y), cv::Point2d(box.x + box.width, box.y + box.height),
        cv::Scalar(0xff, 0x00, 0x00));
}

// コールバック関数
void my_mouse_callback(int event, int x, int y, int flags, void* param){
    cv::Mat* image = static_cast<cv::Mat*>(param);

    switch (event){
    case cv::EVENT_MOUSEMOVE:
        if (drawing_box){
            box.width = x - box.x;
            box.height = y - box.y;
        }
        break;

    case cv::EVENT_LBUTTONDOWN:
        drawing_box = true;
        box = cv::Rect(x, y, 0, 0);
        break;

    case cv::EVENT_LBUTTONUP:
        drawing_box = false;
        if (box.width < 0){
            box.x += box.width;
            box.width *= -1;
        }
        if (box.height < 0){
            box.y += box.height;
            box.height *= -1;
        }
        draw_box(image, box);
        break;
    }
}

int main(void)
{
    std::string name = "Box Example";
    box = cv::Rect(-1, -1, 0, 0);

    // 灰色の画像を生成
    cv::Mat image(cv::Size(960, 540), CV_8UC3, cv::Scalar(100, 100, 100));
    cv::Mat temp = image.clone();

    // ウィンドウを生成
    cv::namedWindow(name, CV_WINDOW_AUTOSIZE);

    // コールバックを設定
    cv::setMouseCallback(name, my_mouse_callback, (void *)&image);

    // Main loop
    while (1){
        // imageをtempにコピー
        image.copyTo(temp);

        // マウスの左クリックを離すまでの間、矩形を一時的に描画
        if (drawing_box) {
            draw_box(&temp, box);
        }

        cv::imshow(name, temp);

        // Escで終了
        if (cv::waitKey(15) == 27)
            break;
    }

    return 0;
}

実行例

f:id:minus9d:20140321104101p:plain

参考