04-28 14:02
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[OpenCV] 이미지 윈도우 상에서 마우스 이벤트 감지하기 본문

Programming/OpenCV

[OpenCV] 이미지 윈도우 상에서 마우스 이벤트 감지하기

cinema4dr12 2015. 9. 23. 00:08

이번 포스팅에서는 OpenCV의 마우스 콜백(Callback) 함수를 이용하여 이미지 윈도우 상에서 마우스 이벤트를 감지하는 방법에 대하여 알아보도록 하겠습니다.


OpenCV의 마우스 콜백함수는 setMouseCall 이며, 함수의 프로토타입은 다음과 같습니다:


void cv::setMouseCallback (
    const String &  winname,
    MouseCallback   onMouse,
    void *  userdata = 0 
)

파라미터들:

winname 윈도우의 이름

onMouse 마우스 콜백 함수 이름

userdata         콜백에 전달되는 옵션 파라미터


onMouse는 마우스 콜백 함수 이름인데 파라미터들은 다음과 같이 정의됩니다:


void onMouse(
    int event,
    int x,
    int y,
    int flags,
    void* userdata
)


 Parameter

Description 

event

 마우스 이벤트 타입.

 EVENT_MOUSEMOVE
 EVENT_LBUTTONDOWN
 EVENT_RBUTTONDOWN
 EVENT_MBUTTONDOWN
 EVENT_LBUTTONUP
 EVENT_RBUTTONUP
 EVENT_MBUTTONUP
 EVENT_LBUTTONDBLCLK
 EVENT_RBUTTONDBLCLK
 EVENT_MBUTTONDBLCLK

x

 마우스 이벤트의 x좌표

y

 마우스 이벤트의 y좌표

flags

 마우스 이벤트가 발생할 때의 특정 조건.

 EVENT_FLAG_LBUTTON
 EVENT_FLAG_RBUTTON
 EVENT_FLAG_MBUTTON
 EVENT_FLAG_CTRLKEY
 EVENT_FLAG_SHIFTKEY
 EVENT_FLAG_ALTKEY

userdata

 setMouseCallback 함수로 전달되는 포인터

Example 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
 
using namespace std;
using namespace cv;
 
 
/*/////////////////////////////////////
@ function: CallBackFunc
*//////////////////////////////////////
void CallBackFunc( int event, int x, int y, int flags, void* userdata )
{
    if ( event == EVENT_LBUTTONDOWN )
    {
        std::cout << "Left button of the mouse is clicked - position (" << x << ", " << y << ")" << std::endl;
    }
    else if ( event == EVENT_RBUTTONDOWN )
    {
        std::cout << "Right button of the mouse is clicked - position (" << x << ", " << y << ")" << std::endl;
    }
    else if ( event == EVENT_MBUTTONDOWN )
    {
        std::cout << "Middle button of the mouse is clicked - position (" << x << ", " << y << ")" << std::endl;
    }
    else if ( event == EVENT_MOUSEMOVE )
    {
        std::cout << "Mouse move over the window - position (" << x << ", " << y << ")" << std::endl;
    }
    else if ( event == EVENT_LBUTTONUP )
    {
        std::cout << "Left button of the mouse is released - position (" << x << ", " << y << ")" << std::endl;
    }
    else if ( event == EVENT_RBUTTONUP )
    {
        std::cout << "Right button of the mouse is released - position (" << x << ", " << y << ")" << std::endl;
    }
    else if ( event == EVENT_MBUTTONUP )
    {
        std::cout << "Middle button of the mouse is released - position (" << x << ", " << y << ")" << std::endl;
    }
    else if ( event == EVENT_LBUTTONDBLCLK )
    {
        std::cout << "Left button of the mouse is double-clicked - position (" << x << ", " << y << ")" << std::endl;
    }
    else if ( event == EVENT_RBUTTONDBLCLK )
    {
        std::cout << "Right button of the mouse is double-clicked - position (" << x << ", " << y << ")" << std::endl;
    }
    else if ( event == EVENT_MBUTTONDBLCLK )
    {
        std::cout << "Middle button of the mouse is double-clicked - position (" << x << ", " << y << ")" << std::endl;
    }
 
    if ( flags & CV_EVENT_FLAG_LBUTTON )
    {
        std::cout << "\tCV_EVENT_FLAG_LBUTTON" << std::endl;
    }
    if ( flags & CV_EVENT_FLAG_RBUTTON )
    {
        std::cout << "\tCV_EVENT_FLAG_RBUTTON" << std::endl;
    }
    if ( flags & CV_EVENT_FLAG_MBUTTON )
    {
        std::cout << "\tCV_EVENT_FLAG_MBUTTON" << std::endl;
    }
    if ( flags & CV_EVENT_FLAG_CTRLKEY )
    {
        std::cout << "\tCV_EVENT_FLAG_CTRLKEY" << std::endl;
    }
    if ( flags & CV_EVENT_FLAG_SHIFTKEY )
    {
        std::cout << "\tCV_EVENT_FLAG_SHIFTKEY" << std::endl;
    }
    if ( flags & CV_EVENT_FLAG_ALTKEY )
    {
        std::cout << "\tCV_EVENT_FLAG_ALTKEY" << std::endl;
    }
 
}
 
 
/*/////////////////////////////////////
@ function: main
*//////////////////////////////////////
int main()
{
    /// Read image from file
    cv::Mat img = cv::imread( {YOUR_IMAGE_PATH} );
  
    /// if fail to read the image
    if ( img.empty() )
    {
        std::cout << "Error loading the image" << std::endl;
        return -1;
    }
  
    /// Create a window
    cv::namedWindow( "ImageDisplay"1 );
  
    /// set the callback function for any mouse event
    cv::setMouseCallback( "ImageDisplay", CallBackFunc, NULL );
  
    /// show the image
    cv::imshow( "ImageDisplay", img );
  
    /// Wait until user press some key
    waitKey( 0 );
     
    return 0;
}
cs 

Example 2 - FILL DEMO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/videoio/videoio.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
 
using namespace std;
using namespace cv;
 
 
// Global
cv::Mat image0, image, gray, mask;
int ffillMode = 1;
int loDiff = 20, upDiff = 20;
int connectivity = 4;
int isColor = true;
bool useMask = false;
int newMaskVal = 255;
 
 
/*/////////////////////////////////////
@ function: help
*//////////////////////////////////////
static void help()
{
    cout << "\nThis program demonstrated the floodFill() function\n"
            "Call:\n"
            "./ffilldemo [image_name -- Default: ../data/fruits.jpg]\n" << endl;
 
    cout << "Hot keys: \n"
            "\tESC - quit the program\n"
            "\tc - switch color/grayscale mode\n"
            "\tm - switch mask mode\n"
            "\tr - restore the original image\n"
            "\ts - use null-range floodfill\n"
            "\tf - use gradient floodfill with fixed(absolute) range\n"
            "\tg - use gradient floodfill with floating(relative) range\n"
            "\t4 - use 4-connectivity mode\n"
            "\t8 - use 8-connectivity mode\n" << endl;
}
 
 
/*/////////////////////////////////////
@ function: onMouse
*//////////////////////////////////////
static void onMouse( int event, int x, int y, intvoid* )
{
    if( event != EVENT_LBUTTONDOWN )
        return;
 
    Point seed = Point(x,y);
    int lo = ffillMode == 0 ? 0 : loDiff;
    int up = ffillMode == 0 ? 0 : upDiff;
    int flags = connectivity + (newMaskVal << 8+
                (ffillMode == 1 ? FLOODFILL_FIXED_RANGE : 0);
    int b = (unsigned)theRNG() & 255;
    int g = (unsigned)theRNG() & 255;
    int r = (unsigned)theRNG() & 255;
    Rect ccomp;
 
    cv::Scalar newVal = isColor ? cv::Scalar( b, g, r ) : cv::Scalar( r*0.299 + g*0.587 + b*0.114 );
    cv::Mat dst = isColor ? image : gray;
    int area;
 
    if( useMask )
    {
        cv::threshold( mask, mask, 1128, THRESH_BINARY );
        area = cv::floodFill( dst, mask, seed, newVal, &ccomp, cv::Scalar( lo, lo, lo ), cv::Scalar( up, up, up ), flags );
        cv::imshow( "mask", mask );
    }
    else
    {
        area = cv::floodFill( dst, seed, newVal, &ccomp, cv::Scalar( lo, lo, lo ), cv::Scalar( up, up, up ), flags );
    }
 
    cv::imshow( "image", dst );
    std::cout << area << " pixels were repainted\n";
}
 
 
 
/*/////////////////////////////////////
@ function: main
*//////////////////////////////////////
int main()
{
    cv::Mat image0 = imread( {YOUR_IMAGE_PATH}, 1 );
 
    if( image0.empty() )
    {
        cout << "Image empty. Usage: ffilldemo <image_name>\n";
        return 0;
    }
 
    help();
 
    image0.copyTo(image);
    cv::cvtColor(image0, gray, COLOR_BGR2GRAY);
    mask.create(image0.rows+2, image0.cols+2, CV_8UC1);
 
    namedWindow( "image"0 );
    createTrackbar( "lo_diff""image"&loDiff, 2550 );
    createTrackbar( "up_diff""image"&upDiff, 2550 );
 
    setMouseCallback( "image", onMouse, 0 );
 
    for(;;)
    {
        imshow( "image", isColor ? image : gray );
 
        int c = waitKey( 0 );
 
        if( (c & 255== 27 )
        {
            cout << "Exiting ...\n";
            break;
        }
 
        switch( (char)c )
        {
        case 'c':
            if( isColor )
            {
                std::cout << "Grayscale mode is set\n";
                cv::cvtColor(image0, gray, COLOR_BGR2GRAY);
                mask = Scalar::all(0);
                isColor = false;
            }
            else
            {
                std::cout << "Color mode is set\n";
                image0.copyTo(image);
                mask = Scalar::all(0);
                isColor = true;
            }
            break;
 
        case 'm':
            if( useMask )
            {
                cv::destroyWindow( "mask" );
                useMask = false;
            }
            else
            {
                cv::namedWindow( "mask"0 );
                mask = Scalar::all( 0 );
                cv::imshow( "mask", mask );
                useMask = true;
            }
            break;
 
        case 'r':
            std::cout << "Original image is restored\n";
            image0.copyTo( image );
            cv::cvtColor( image, gray, COLOR_BGR2GRAY );
            mask = Scalar::all( 0 );
            break;
 
        case 's':
            std::cout << "Simple floodfill mode is set\n";
            ffillMode = 0;
            break;
 
        case 'f':
            std::cout << "Fixed Range floodfill mode is set\n";
            ffillMode = 1;
            break;
 
        case 'g':
            std::cout << "Gradient (floating range) floodfill mode is set\n";
            ffillMode = 2;
            break;
 
        case '4':
            std::cout << "4-connectivity mode is set\n";
            connectivity = 4;
            break;
 
        case '8':
            std::cout << "8-connectivity mode is set\n";
            connectivity = 8;
            break;
        }
    }
     
    return 0;
}
cs


Result


 Original

Ffill 


 


 

Example 3 - ExtractColor

마우스를 클릭한 위치의 컬러 정보를 얻는 예제.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
 
using namespace std;
using namespace cv;
 
 
/*/////////////////////////////////////
@ function: mouseEvent
*//////////////////////////////////////
void mouseEvent( int evt, int x, int y, int flags, void* param ) 
{                    
    cv::Mat* rgb = (cv::Mat*) param;
    if ( evt == CV_EVENT_LBUTTONDOWN )
    { 
        printf("%d %d: %d, %d, %d\n"
        x, y, 
        (int)(*rgb).at<Vec3b>(y, x)[0], 
        (int)(*rgb).at<Vec3b>(y, x)[1], 
        (int)(*rgb).at<Vec3b>(y, x)[2]); 
    }         
}
 
 
/*/////////////////////////////////////
@ function: main
*//////////////////////////////////////
int main()
{
    /// Read image from file
    cv::Mat img = cv::imread( {YOUR_IMAGE_PATH} );
  
    /// if fail to read the image
    if ( img.empty() )
    {
        std::cout << "Error loading the image" << std::endl;
        return -1;
    }
  
    /// Create a window
    cv::namedWindow( "My Window"1 );
  
    /// set the callback function for any mouse event
    cv::setMouseCallback( "My Window", mouseEvent, &img );
  
    /// show the image
    cv::imshow( "My Window", img );
  
    /// Wait until user press some key
    cv::waitKey(0);
     
    return 0;
}
cs


Comments