5/01/2014

(OpenCV Study) setMouseCallback function example source code, get rectangle coordinate of mouse drag on image.

This  source code is useful when you need retangle coordinate of mouse drag.
The rectangle coordinate is applied initial region for tracking.

refer to video and source code.

#include < stdio.h>
#include < iostream>

#include < opencv2\opencv.hpp>
//#include < opencv2/core/core.hpp>
//#include < opencv2/highgui/highgui.hpp>
//#include < opencv2/video/background_segm.hpp>
//#include < opencv2\gpu\gpu.hpp>
//#include < opencv2\legacy\legacy.hpp>

#ifdef _DEBUG        
#pragma comment(lib, "opencv_core247d.lib")
//#pragma comment(lib, "opencv_imgproc247d.lib")   //MAT processing
//#pragma comment(lib, "opencv_objdetect247d.lib") //HOGDescriptor
//#pragma comment(lib, "opencv_gpu247d.lib")
//#pragma comment(lib, "opencv_features2d247d.lib")
#pragma comment(lib, "opencv_highgui247d.lib")
//#pragma comment(lib, "opencv_ml247d.lib")
//#pragma comment(lib, "opencv_stitching247d.lib");
//#pragma comment(lib, "opencv_nonfree247d.lib");
//#pragma comment(lib, "opencv_video247d.lib")
//#pragma comment(lib, "opencv_legacy247d.lib")
#else
#pragma comment(lib, "opencv_core247.lib")
//#pragma comment(lib, "opencv_imgproc247.lib")
//#pragma comment(lib, "opencv_objdetect247.lib")
//#pragma comment(lib, "opencv_gpu247.lib")
//#pragma comment(lib, "opencv_features2d247.lib")
#pragma comment(lib, "opencv_highgui247.lib")
//#pragma comment(lib, "opencv_ml247.lib")
//#pragma comment(lib, "opencv_stitching247.lib");
//#pragma comment(lib, "opencv_nonfree247.lib");
//#pragma comment(lib, "opencv_video247.lib")
//#pragma comment(lib, "opencv_legacy247.lib")
#endif 

using namespace std;
using namespace cv;

bool selectObject = false;
Rect selection;
Point origin;
int trackObject = 0;
Mat image;


static void onMouse( int event, int x, int y, int, void* )
{
    if( selectObject )
    {
        selection.x = MIN(x, origin.x);
        selection.y = MIN(y, origin.y);
        selection.width = std::abs(x - origin.x);
        selection.height = std::abs(y - origin.y);

        selection &= Rect(0, 0, image.cols, image.rows);
    }

    switch( event )
    {
    case CV_EVENT_LBUTTONDOWN:
        origin = Point(x,y);
        selection = Rect(x,y,0,0);
        selectObject = true;
        break;
    case CV_EVENT_LBUTTONUP:
        selectObject = false;
        if( selection.width > 0 && selection.height > 0 )
            trackObject = -1;
        break;
    }
}


int main (void)  
{  
 

 VideoCapture cap(0);
 Mat frame;
 namedWindow( "Demo", 0 );
 setMouseCallback( "Demo", onMouse, 0 );

    for(;;)
    {
        
  cap >> frame;
        if( frame.empty() )
   break;

        frame.copyTo(image);
  

  if( selectObject && selection.width > 0 && selection.height > 0 )
        {
            Mat roi(image, selection);
            bitwise_not(roi, roi);
   printf("%d %d %d %d\n", selection.x, selection.y, selection.width, selection.height);
        }

  imshow( "Demo", image );

  if( waitKey(10) > 10 )
   break;
 }

 return 0;  
}  



3 comments:

  1. Hello, I have the following code, can you please help me with an advice.
    I have an error at SetMousecallback, more exacly at parameer onMouse (a pointer to member is not valid for a managed class) . I remain grateful.
    private: System::Void button5_Click(System::Object^ sender, System::EventArgs^ e) {

    src = mOriginalImagesAf.clone();
    namedWindow(winName, WINDOW_NORMAL);
    setMouseCallback(winName, onMouse, NULL);
    imshow(winName, src);

    }



    void checkBoundary(){
    //check croping rectangle exceed image boundary
    if (cropRect.width>img.cols - cropRect.x)
    cropRect.width = img.cols - cropRect.x;

    if (cropRect.height>img.rows - cropRect.y)
    cropRect.height = img.rows - cropRect.y;

    if (cropRect.x<0)
    cropRect.x = 0;

    if (cropRect.y<0)
    cropRect.height = 0;
    }

    void showImage(){
    img = src.clone();
    checkBoundary();
    if (cropRect.width>0 && cropRect.height>0){
    ROI = src(cropRect);
    imshow("cropped", ROI);
    }

    rectangle(img, cropRect, Scalar(0, 255, 0), 1, 8, 0);
    imshow(winName, img);
    }


    void onMouse(int event, int x, int y, int f, void*){


    switch (event){

    case CV_EVENT_LBUTTONDOWN:
    clicked = true;

    P1.x = x;
    P1.y = y;
    P2.x = x;
    P2.y = y;
    break;

    case CV_EVENT_LBUTTONUP:
    P2.x = x;
    P2.y = y;
    clicked = false;
    break;

    case CV_EVENT_MOUSEMOVE:
    if (clicked){
    P2.x = x;
    P2.y = y;
    }
    break;

    default: break;


    }


    if (clicked){
    if (P1.x>P2.x){
    cropRect.x = P2.x;
    cropRect.width = P1.x - P2.x;
    }
    else {
    cropRect.x = P1.x;
    cropRect.width = P2.x - P1.x;
    }

    if (P1.y>P2.y){
    cropRect.y = P2.y;
    cropRect.height = P1.y - P2.y;
    }
    else {
    cropRect.y = P1.y;
    cropRect.height = P2.y - P1.y;
    }

    }


    showImage();


    }

    ReplyDelete
  2. 안녕하세요 자꾸 질문 올려드려 죄송합니다.
    onMouse 함수에서 selection &= Rect(0,0,image.cols, image.rows)는 왜 해주는 것인가요?? x,y 좌표를 날리고 width와 height 값만 남기려고 하는것인가요???
    답변해주시면 감사하겠습니다.

    ReplyDelete
    Replies
    1. 네 안녕하세요.
      답변이 늦어서 죄송합니다.
      Rect & Rect 를 한 이유는 선택한 rect의 크기가 이미지보다 크지 않게 하기 위해서 입니다.
      여기서는 심각하진 않지만, rect 크기로 어떤 영상 처리 연산을 할때 이미지를 벗어나게 되는 값이 있을때 오류를 발생 시킬 수 있습니다.
      RectA & RectB 이렇게 하면 중복되는 영역의 rect값이 계산됩니다.
      그러니깐 제일 inbound 한 rect가 만들어 지는데요..
      여기를 참고하세요.
      http://study.marearts.com/2014/09/opencv-tip-rect-bounding.html
      감사합니다.

      Delete