简介
如题,本篇是在前一篇的基础上进一步讲解的第三个图像背景分离例子。
实例介绍
这个例子是在上一个加入鼠标操作实例的进一步操作。 本例:可以在鼠标选框完成之后,1、通过shift+鼠标右键来选择设置图像对应位置为前景。 2、通过ctrl +鼠标右键来选择设置图像对应位置为背景景。 3、按下键值‘n’,进行图像背景分离计算,并显示结果。 4、按下键值‘esc’,退出程序。
实例讲解
具体代码
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "stdio.h" #include <iostream> using namespace std; using namespace cv; string filename; char filename_tmp[10] = "tmp.jpg"; Mat image; string winName = "show"; enum{NOT_SET = 0, IN_PROCESS = 1, SET = 2}; enum{LS_LEFT = 0, LS_RIGHT = 1, LS_NONE = 2}; uchar rectState, mouse_flag; Rect rect; Mat mask; const Scalar GREEN = Scalar(0,255,0); const Scalar RED = Scalar(0,0,255); const Scalar BLUE = Scalar(255,0,0); Mat bgdModel, fgdModel; int line_count[4]; const int BGD_KEY = CV_EVENT_FLAG_CTRLKEY; const int FGD_KEY = CV_EVENT_FLAG_SHIFTKEY; int i, j; void setRectInMask(){ rect.x = max(0, rect.x); rect.y = max(0, rect.y); rect.width = min(rect.width, image.cols-rect.x); rect.height = min(rect.height, image.rows-rect.y); } static void getBinMask( const Mat& comMask, Mat& binMask ){ binMask.create( comMask.size(), CV_8UC1 ); binMask = comMask & 1; } void on_mouse( int event, int x, int y, int flags, void* ) { switch( event ){ case CV_EVENT_LBUTTONDOWN: mouse_flag = LS_LEFT; if( rectState == NOT_SET){ rectState = IN_PROCESS; rect = Rect( x, y, 1, 1 ); } break; case CV_EVENT_LBUTTONUP: if( rectState == IN_PROCESS ){ rect = Rect( Point(rect.x, rect.y), Point(x,y) ); rectState = SET; (mask(rect)).setTo( Scalar(GC_PR_FGD)); } break; case CV_EVENT_RBUTTONDOWN: mouse_flag = LS_RIGHT; line_count[0] = x; line_count[1] = y; break; case CV_EVENT_RBUTTONUP: mouse_flag = LS_NONE; line_count[0] = 0; line_count[1] = 0; line_count[2] = 0; line_count[3] = 0; imwrite(filename_tmp,image); break; case CV_EVENT_MOUSEMOVE: if(mouse_flag == LS_LEFT){ if( rectState == IN_PROCESS ){ rect = Rect( Point(rect.x, rect.y), Point(x,y) ); image = imread(filename_tmp, 1 ); rectangle(image, Point( rect.x, rect.y ), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2); imshow(winName, image); } }else if(mouse_flag == LS_RIGHT){ IplImage pI = image; IplImage pI_2 = mask; line_count[2] = x; line_count[3] = y; if((flags & BGD_KEY) != 0){ cvLine(&pI, Point(line_count[0], line_count[1]), Point(line_count[2], line_count[3]), RED, 5); cvLine(&pI_2, Point(line_count[0], line_count[1]), Point(line_count[2], line_count[3]), cvScalar(0,0,0), 5); }else if((flags & FGD_KEY) != 0){ cvLine(&pI, Point(line_count[0], line_count[1]), Point(line_count[2], line_count[3]), BLUE, 5); cvLine(&pI_2, Point(line_count[0], line_count[1]), Point(line_count[2], line_count[3]), cvScalar(1,0,0), 5); } line_count[0] = x; line_count[1] = y; imshow(winName, image); } break; } } int main(int argc, char* argv[]){ Mat res; Mat binMask; filename = argv[1]; image = imread( filename, 1 ); imshow(winName, image); imwrite(filename_tmp,image); mask.create(image.size(), CV_8UC1); rectState = NOT_SET; mask.setTo(GC_BGD); setMouseCallback(winName, on_mouse, 0); while(1){ int c = waitKey(0); if(c == ‘\x1b‘){ break; }else if(c == ‘n‘){ image = imread(filename, 1 ); grabCut(image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_MASK); getBinMask( mask, binMask ); image.copyTo(res, binMask ); imshow("11", res); } } return 0; }
代码讲解
和前面实例1和实例2相同的代码部分,不在做讲解。只讲在之基础上新加入的部分。
鼠标右键响应
加入了鼠标右键+键值ctrl、shift的组合操作。
1、鼠标左键按下时候,记录下当前坐标,并且设置当前模式为LS_RIGHT(前景背景设置模式)
case CV_EVENT_RBUTTONDOWN: mouse_flag = LS_RIGHT; line_count[0] = x; line_count[1] = y; break;
2、当鼠标右键+shift按下,并拖动鼠标的时候,在图像上绘制出鼠标移动的蓝色线条轨迹,同时在掩码mask上,对应轨迹位置标注为前景(GC_FGD)。 当鼠标右键+Ctrl 按下,并拖动鼠标的时候,在图像上绘制出鼠标移动的红色线条轨迹,同时在掩码mask上,对应轨迹位置标注为前景(GC_BGD)。
case CV_EVENT_MOUSEMOVE: ........ }else if(mouse_flag == LS_RIGHT){ IplImage pI = image; IplImage pI_2 = mask; line_count[2] = x; line_count[3] = y; if((flags & BGD_KEY) != 0){ cvLine(&pI, Point(line_count[0], line_count[1]), Point(line_count[2], line_count[3]), RED, 5); cvLine(&pI_2, Point(line_count[0], line_count[1]), Point(line_count[2], line_count[3]), cvScalar(0,0,0), 5); }else if((flags & FGD_KEY) != 0){ cvLine(&pI, Point(line_count[0], line_count[1]), Point(line_count[2], line_count[3]), BLUE, 5); cvLine(&pI_2, Point(line_count[0], line_count[1]), Point(line_count[2], line_count[3]), cvScalar(1,0,0), 5); } line_count[0] = x; line_count[1] = y; imshow(winName, image); } break;
3、当鼠标右键抬起的时候,清除掉一些前景背景操作中的临时变量。 case CV_EVENT_RBUTTONUP: mouse_flag = LS_NONE; line_count[0] = 0; line_count[1] = 0; line_count[2] = 0; line_count[3] = 0; imwrite(filename_tmp,image); break;
键盘响应
加入了两个键值的响应操作:1、esc:直接退出程序。 2、‘n’:进行图像背景分离计算,并显示结果。
while(1){ int c = waitKey(0); if(c == ‘\x1b‘){ break; }else if(c == ‘n‘){ image = imread(filename, 1 ); grabCut(image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_MASK); getBinMask( mask, binMask ); image.copyTo(res, binMask ); imshow("11", res); } }
效果演示
特别注意:本实例使用时候,需要首先鼠标左键画出背景分离矩形框,然后鼠标右键选择的自定义前景背景才能正常时候。之后按下n键, 计算背景分离并显示结果。 运行效果: 原图像: 结果图像:
时间: 2024-10-07 06:29:07