Created
May 26, 2017 06:26
-
-
Save zhanghuimeng/f2ff34b0c532ccf6ba1d7ca415db78b9 to your computer and use it in GitHub Desktop.
opencv鼠标笔刷标记区域
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1. 一些基本定义 | |
typedef cv::Vec3b Color; | |
typedef cv::Mat_<Color> Image; | |
Image img; // 要处理的那张图 | |
struct MouseArgs // 用于和回调函数交互,至于为什么要特意攒一个struct后面会讲~ | |
{ | |
Image &img; // 显示在窗口中的那张图 | |
std::vector<std::vector<int>> &mask; // 用户绘制的选区(删除/保留) | |
Color color; // 用来高亮选区的颜色 | |
MouseArgs(Image &img, std::vector<std::vector<int>> &mask, const Color color) | |
: img(img), mask(mask), color(color) {} | |
}; | |
// 2. 创建一个可交互的窗口 | |
Image showImg = img.clone(); // 拷贝一张图用于显示(因为需要在显示的图上面高亮标注,从而造成修改) | |
cv::namedWindow("Draw ROI", CV_WINDOW_AUTOSIZE); // 新建一个窗口 | |
// 3. 定义一个回调函数,这里主要实现2个功能: | |
// 1) 用半透明颜色高亮选区 | |
// 2) 将选区存到数组中 | |
// 这个回调函数有一个固定的格式(函数名随意): | |
void onMouse(int event, int x, int y, int flags, void *param); | |
/** | |
* event: 触发回调函数的鼠标事件(如移动/点击/松开等) | |
* (x, y): 鼠标事件发生的位置 | |
* flags: 貌似是用位运算的方式表示左/中/右三个键是否被按下 | |
* param: 传给回调函数的参数,可以在回调函数内部被读/写【我们将从这里获取数据】 | |
* | |
* 以上这堆参数只有param需要自行在外部准备,其余的opencv都搞定了,咱们不用管直接用就行了 | |
*/ | |
void onMouse(int event, int x, int y, int flags, void *param) | |
{ | |
// C++没有类似Java的单根继承机制,为了支持多类型的交互数据这里只能传入void *再强制转换 | |
// 为什么必须定义一个MouseArgs结构体:不然没法同时给回调函数传入多个数据 | |
MouseArgs *args = (MouseArgs *)param; | |
// 按下鼠标左键拖动时 | |
if ((event == CV_EVENT_MOUSEMOVE || event == CV_EVENT_LBUTTONDOWN) | |
&& (flags & CV_EVENT_FLAG_LBUTTON)) | |
{ | |
int brushRadius = 10; // 笔刷半径 | |
int rows = args->img.rows, cols = args->img.cols; | |
// 以下的双重for循环遍历的是半径为10的圆形区域,实现笔刷效果 | |
// 注意传回给回调函数的x, y是【窗口坐标】下的,所以y是行,x是列 | |
for (int i = max(0, y - brushRadius); i < min(rows, y + brushRadius); i++) | |
{ | |
int halfChord = sqrt(pow(brushRadius, 2) - pow(i - y, 2)); // 半弦长 | |
for (int j = max(0, x - halfChord); j < min(cols, x + halfChord); j++) | |
if (args->mask[i][j] == 0) | |
{ | |
// 高亮这一笔 | |
args->img(i, j) = args->img(i, j) * 0.7 + args->color * 0.3; | |
// 将这一笔添加到选区 | |
args->mask[i][j] = 1; | |
} | |
} | |
} | |
} | |
vector<vector<int>> maskRemove(rows, vector<int>(cols, 0)); // 希望获取的待删除选区 | |
MouseArgs *args = new MouseArgs(showImg, maskRemove, Color(0, 0, 255)); // 攒一个MouseArgs结构体用于交互 | |
cv::setMouseCallback("Draw ROI", onMouse, (void*)args); // 给窗口设置回调函数 | |
// 拖动鼠标作画 | |
while (1) | |
{ | |
cv::imshow("Draw ROI", args->img); | |
// 按 esc 键退出绘图模式,获得选区 | |
if (cv::waitKey(100) == 27) | |
break; | |
} | |
// 4. 垃圾回收 | |
cv::setMouseCallback("Draw ROI", NULL, NULL); // 取消回调函数 | |
delete args; args = NULL; // 垃圾回收 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
mask
用一个cv::Mat1b
就好了,不需要嵌套vector