【OpenCV】選擇ROI區域

一點心青發表於2013-08-07

問題描述:在測試目標跟蹤演算法時,需要選擇不同區域作為目標,進行目標跟蹤,測試目標跟蹤的效果。

解決思路:

1.OpenCV中提供了滑鼠互動控制,利用setMouseCallback()給固定的視窗設定滑鼠回撥函式。

2.在滑鼠回撥函式中,選擇感興趣區域。

程式碼實現如下,將感興趣區域封裝在MouseSelect類中,提供選擇點和矩形框兩種模式。

 1 #pragma once
 2 #ifndef __MOUSESELECT_H__
 3 #define __MOUSESELECT_H__
 4 
 5 #include <opencv2/opencv.hpp>
 6 #include <iostream>
 7 
 8 #define MAX_OBJECTS    10
 9 using namespace cv;
10 using namespace std;
11 typedef struct MouseSelectParams
12 {
13     vector<Point> pts;        //Points of selected
14     char        *win_name;
15     Mat            *image;        
16     unsigned int mode;        //1 Point,2 Rect
17     int             n;            // selected object number
18 }MouseSelectParams;
19 
20 void on_mouse(int event,int x,int y,int flags,void *param);
21 class MouseSelect
22 {
23 public:
24     MouseSelect();
25     ~MouseSelect();
26 
27     void select_rect(Mat &frame);
28     void select_point(Mat &frame);
29 
30     vector<Point> vPoints;
31     vector<Rect> vRects;
32     unsigned int obj_selected;
33 private:
34     int get_rects(Mat &frame);
35     int get_points(Mat &frame);
36 
37 };
38 #endif
View Code
  1 #include "MouseSelect.h"
  2 
  3 MouseSelectParams *g_mousep;
  4 MouseSelect::MouseSelect() {}
  5 
  6 MouseSelect::~MouseSelect() {}
  7 
  8 void MouseSelect::select_rect(Mat &frame)
  9 {
 10     obj_selected = 0;
 11     while(0 == obj_selected)
 12     {
 13         obj_selected = get_rects(frame);
 14         if (obj_selected == 0)
 15         {
 16             cout<<"You haven't selected any rectangles. "<<endl;
 17         }
 18     }
 19 }
 20 
 21 void MouseSelect::select_point(Mat &frame)
 22 {
 23     obj_selected = 0;
 24     while(0 == obj_selected)
 25     {
 26         obj_selected = get_points(frame);
 27         if (obj_selected == 0)
 28         {
 29             cout<<"You haven't selected any points."<<endl;
 30         }
 31     }
 32 }
 33 
 34 int MouseSelect::get_rects(Mat &frame)
 35 {
 36     char *win_name = "Init Frame";
 37     MouseSelectParams params;
 38     params.win_name = win_name;
 39     params.image = &frame;
 40     params.n = 0;
 41     params.mode = 2;
 42     namedWindow(win_name,WINDOW_AUTOSIZE);
 43     imshow(win_name,frame);
 44     
 45     g_mousep = &params;
 46     setMouseCallback(win_name,on_mouse,0);
 47     waitKey(0);
 48     destroyWindow(win_name);
 49     
 50     int x1,x2,y1,y2,w,h;
 51     Rect rt;
 52     Point pt1,pt2;
 53     cout<<"Point Num: "<<params.pts.size()<<" Object Num: "<<params.n<<" Object Type: Rect."<<endl;
 54     for(int i = 0;i < params.pts.size();i += 2)
 55     {
 56         pt1 = params.pts[i];
 57         pt2 = params.pts[i + 1];
 58         x1 = min(pt1.x,pt2.x);
 59         x2 = max(pt1.x,pt2.x);
 60         y1 = min(pt1.y,pt2.y);
 61         y2 = max(pt1.y,pt2.y);
 62         w = x2 - x1;
 63         h = y2 - y1;
 64         w = (w % 2)? w:w+1;
 65         h = (h % 2)? h:h+1;
 66         rt.x = x1;
 67         rt.y = y1;
 68         rt.width = w;
 69         rt.height = h;
 70         vRects.push_back(rt);
 71     }
 72     return params.n;
 73 }
 74 
 75 int MouseSelect::get_points(Mat &frame)
 76 {
 77     char    *win_name = "Init Frame";
 78     MouseSelectParams params;
 79     params.win_name = win_name;
 80     params.image = &frame;
 81     params.n = 0;
 82     params.mode = 1;
 83 
 84     namedWindow(win_name,1);
 85     imshow(win_name,frame);
 86 
 87     g_mousep = &params;
 88     setMouseCallback(win_name,on_mouse,0);
 89     waitKey(0);
 90 
 91     destroyWindow(win_name);
 92     
 93     cout<<"Point Num: "<<params.pts.size()<<" Object Num: "<<params.n<<" Object Type: Point."<<endl;
 94     for (int i = 0;i < params.n;i++)
 95     {
 96         vPoints.push_back(params.pts[i]);
 97     }
 98     return params.n;
 99 }
100 
101 void on_mouse(int event,int x,int y,int flags,void *param)
102 {
103     int        n;
104     static bool pressed = false;
105     static Point cur_pt;
106     static Point prev_pt;
107     /* on left button press, remember first corner of rectangle around object */
108     if (event == CV_EVENT_LBUTTONDOWN)
109     {
110         n = g_mousep->n;
111         if (n == MAX_OBJECTS)
112         {
113             return;
114         }
115         prev_pt.x = x;
116         prev_pt.y = y;
117         //cout<<prev_pt.x <<","<<prev_pt.y<<" "<<cur_pt.x<<","<<cur_pt.y<<endl;
118         pressed = true;
119     }
120     /* on left button up, finalise the rectangle and draw it in black */
121     else if(event == CV_EVENT_LBUTTONUP && pressed)
122     {
123         /* 1 == mode for selecting points */
124         if (1 == g_mousep->mode)
125         {
126             n = g_mousep->n;
127             if (n == MAX_OBJECTS)
128             {
129                 return;
130             }
131             cur_pt.x = x;
132             cur_pt.y = y;
133             g_mousep->pts.push_back(cur_pt);
134             int radius = 3;
135             circle(*g_mousep->image,cur_pt,radius,CV_RGB(255,0,0));
136             imshow(g_mousep->win_name,*g_mousep->image);
137             pressed = false;
138             g_mousep->n++;
139         }
140         /* 2 == mode for selecting rectangles */
141         else if (2 == g_mousep->mode)
142         {
143             n = g_mousep->n;
144             if (n == MAX_OBJECTS)
145             {
146                 return;
147             }
148             cur_pt.x = x;
149             cur_pt.y = y;
150             g_mousep->pts.push_back(prev_pt);
151             g_mousep->pts.push_back(cur_pt);
152         //    cout<<prev_pt.x <<","<<prev_pt.y<<" "<<cur_pt.x<<","<<cur_pt.y<<endl;
153             rectangle(*g_mousep->image,prev_pt,cur_pt,CV_RGB(0,0,255));
154             imshow(g_mousep->win_name,*g_mousep->image);
155             pressed = false;
156             g_mousep->n++;
157         }
158         else if (3 == g_mousep->mode)
159         {
160             n = g_mousep->n;
161 
162         }
163     }
164     else if (event == CV_EVENT_MOUSEMOVE && pressed && CV_EVENT_FLAG_LBUTTON)
165     {
166         if (2 == g_mousep->mode)
167         {
168             n = g_mousep->n;
169             if (n == MAX_OBJECTS)
170             {
171                 return;
172             }
173             cur_pt.x = x;
174             cur_pt.y = y;
175             Mat tmp = (*g_mousep->image).clone();
176             //cout<<prev_pt.x <<","<<prev_pt.y<<" "<<cur_pt.x<<","<<cur_pt.y<<endl;
177             rectangle(tmp,prev_pt,cur_pt,CV_RGB(0,255,0));
178             imshow(g_mousep->win_name,tmp);
179         }
180     }
181 }
View Code

 程式碼分析:

on_mouse()回撥函式,對應於一個顯示視窗。

在回撥函式處理滑鼠事件,要理解一個滑鼠點選過程,會產生多個事件。

例如:滑鼠左擊,對應著CV_EVENT_LBUTTONDOWN和CV_EVENT_LBUTTONUP。 

在選擇矩形框區域時,CV_EVENT_LBUTTONDOWN記錄一個對角點;CV_EVENT_MOUSEMOVE記錄選對矩形框的中間過程,並顯示出來,便於使用者調整選擇的區域;CV_EVENT_LBUTTONUP記錄另一個對角點,CV_EVENT_LBUTTONUP響應後,完成一個矩形框的選擇。

在選擇點時,只需記錄CV_EVENT_LBUTTONUP事件響應的座標。

相關文章