マウスクリック

cvSetMouseCallbackを使ってウインドウからイベントと座標を引っ張り出す方法。

//引数はイベント、x座標、y座標、フラグ、任意のオプションみたいなの
void Foo(int event, int x, int y, int flags, void* param)


千原研のサンプルを見てみる。

  cvSetMouseCallback(windowName, onMouse); // コールバック関数をセット

(中略)

void onMouse( int event, int x, int y, int flags ) // コールバック関数
{
  switch (event)
  {
  case CV_EVENT_MOUSEMOVE:
    printf("CV_EVENT_MOUSEMOVE: %d, %d\n", x, y);
    break;
  case CV_EVENT_LBUTTONDOWN:
    printf("CV_EVENT_LBUTTONDOWN: %d, %d\n", x, y);
    break;
  case CV_EVENT_RBUTTONDOWN:
    printf("CV_EVENT_RBUTTONDOWN: %d, %d\n", x, y);
    break;

(以下略)

http://chihara.naist.jp/people/2004/kenta-t/OpenCV/pukiwiki/index.php?%A5%DE%A5%A6%A5%B9%C6%FE%CE%CF

と、OnMouseの引数は関数内で参照できるけどどうやって外部の関数から参照というか渡せばいいか分からなかった。
これを持ち出すにはたとえば以下のような構造体でも用意してやればいい。

typedef struct _data{
  int event,x,y,flag;
}Data;


次にコールバック関数を以下のように定義する。

void onMouse( int event, int x, int y, int flags, void* param ){
  Data* data = (Data*)param;
  data->event = event;
  data->x = x;
  data->y = y;
  data->flags = flags;
}


でもってcvSetMouseCallbackのセットのところでこんなふうに引数を指定する。

  Data data;
  IplImage* img;
  int key;

  img = cvLoadImage("filename",1);
  cvSetMouseCallback("window", OnMouse, (void *)&data);  //3つ目の引数のようにする
  cvNamedWindow("window",CV_WINDOW_AUTOSIZE);
  cvMoveWindow("window",50,50);

  for(;;){
    cvShowImage("window",img);
    key = cvWaitKey(10);  //全然待たないとちゃんと表示されない
    if(key==0x1b)break;  //Escで終了
  }

こうすればdataにOnMouseで得た値が入る。はず。実際はfor文の中でそれに対応した操作をさせる。
ちなみにコールバック関数をプロトタイプ宣言したにもかかわらずなぜか呼びだす前に定義を書いてやらんとコンパイルが通らなかった。謎。


参考
「顔を追いかけるカメラのプログラミング入門」 サポートページ 奈良先端科学技術大学 ロボティクス講座 松本 修、松本 吉央
マウス入力 - OpenCV@Chihara-Lab.
OpenCVサンプルプログラム - けんちょの部屋