簡介
如題,本篇是在前一篇的基礎上進一步講解的第三個圖像背景分離例子。
執行個體介紹
這個例子是在上一個加入滑鼠操作執行個體的進一步操作。
本例:可以在滑鼠選框完成之後,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鍵,
計算背景分離并顯示結果。
運作效果:
原圖像:
opencv實作圖像分割,分離前景和背景(2)
結果圖像:
opencv實作圖像分割,分離前景和背景(2)