您的位置:首页 > 运维架构

Opencv2.1中的图像切分grabcut实现

2010-08-03 20:53 399 查看
1.首先要先装上Opencv2.1,注意必须是2.1版本以上的,因为grabcut方法的实现只有在2.1开始才有实现好的函数可以使用。

2.还要装上c-make,用来编译Opencv2.1

以上两个步骤,请参考
http://www.opencv.org.cn/index.php/VC_2008_Express%E4%B8%8B%E5%AE%89%E8%A3%85OpenCV2.0/2.1
这里面非常详细的介绍了Opencv2.1的安装过程,必须注意,这里的编译器是Vs2008.

3在写程序前,要配置几项

打开VC++ 2008 Express,菜单 Tools -> Options -> Projects and Solutions -> VC++ Directories

Show directories for选择include files,加入目录 D:/Program Files/OpenCV2.0/vc2008/include/opencv

Show directories for选择library files,加入目录 D:/Program Files/OpenCV2.0/vc2008/lib

关闭VC++ 2008 Express。





点击看大图





点击看大图

[编辑
]

使用OpenCV 2.1编程

打开VC++ 2008 Express,创建一个空程序grabcut;

选择Solution Explorer里的grabcut项目,点击鼠标右键,选择Properties;

为项目的Debug配置增加依赖的库:cxcore210d.lib cv210d.lib highgui210d.lib

为项目的Release配置增加依赖的库:cxcore210.lib cv210.lib highgui210.lib

编译运行下面的例程(需要将lena.jpg文件放在项目目录下)。

右键工程,点击下面的属性->配置属性->调试->命令参数->D:/图形/Grabcut/Grabcut/lena.jpg,输入图片放置的地方


#include <highgui.h>
#include <cv.h>
#include <iostream>

using namespace std;
using namespace cv;

const string winName = "image";
const Scalar RED = Scalar(0,0,255);
const Scalar BLUE = Scalar(255,0,0);
Mat outImage;

void getBinMask( const Mat& comMask, Mat& binMask )   //comMask 变换成binMask
{
if( comMask.empty() || comMask.type()!=CV_8UC1 )
CV_Error( CV_StsBadArg, "comMask is empty or has incorrect type (not CV_8UC1)" );
if( binMask.empty() || binMask.rows!=comMask.rows || binMask.cols!=comMask.cols ) binMask.create( comMask.size(), CV_8UC1 );
binMask = comMask & 1;
}

void changeMask( Mat& mask, vector<Point> bgdPixels, vector<Point> fgdPixels ) //把mask中的的前景背景改变
{
vector<Point>::const_iterator it = bgdPixels.begin(), itEnd = bgdPixels.end();
for( ; it != itEnd; ++it )
mask.at<uchar>(*it) = GC_BGD;
it = fgdPixels.begin(), itEnd = fgdPixels.end();
for( ; it != itEnd; ++it )
mask.at<uchar>(*it) = GC_FGD;
}

void showImage( Mat& _img, Mat& _mask, vector<Point>& _bgdPxls, vector<Point>& _fgdPxls )  //加载显示图像
{
Mat res;
Mat binMask;
if( _mask.empty() )       //_mask为空,直接拷贝
_img.copyTo( res );   //_img -> res
else                                //_mask不为空,变换后拷贝
{
getBinMask( _mask, binMask );   //bin
_img.copyTo( res, binMask );    //_img - binMask -> res  只拷贝binMask非空时_img的像素
}

vector<Point>::const_iterator it;
for( it = _bgdPxls.begin(); it != _bgdPxls.end(); ++it )  //画出背景信息
circle( res, *it, 1, BLUE );   //(图像,圆心坐标,圆心半径,颜色)
// 函数cvCircle绘制或填充一个给定圆心和半径的圆。
//圆被感兴趣矩形所裁剪。 若指定圆的颜色,可以使用宏 CV_RGB ( r, g, b )。
for( it = _fgdPxls.begin(); it != _fgdPxls.end(); ++it )  //画出前景信息
circle( res, *it, 1, RED );

imshow( winName, res );
res.copyTo(outImage);
}

Mat image;

Mat mask;
Mat bgdModel, fgdModel;
Rect rect;

enum{ NOT_SET = 0, IN_PROCESS = 1, SET = 2 };
uchar rectState = NOT_SET;  //矩形框
uchar lblsState = NOT_SET;

vector<Point> fgdPxls, bgdPxls;
Point p1, p2;
int iterCount;
/*
这个函数的原型应该为  void Foo(int event, int x, int y, int flags, void* param);
其中event是 CV_EVENT_*变量之一,
x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系),
flags是CV_EVENT_FLAG的组合,
param是用户定义的传递到cvSetMouseCallback函数调用的参数。
*/
void on_mouse( int event, int x, int y, int flags, void* param )
{
switch( event )
{
case CV_EVENT_LBUTTONDOWN:  //单击鼠标左键down
{
bool isb = (flags & CV_EVENT_FLAG_ALTKEY) != 0,  //是否选中alt键
isf = (flags & CV_EVENT_FLAG_SHIFTKEY) != 0; //是否选中shift键
if( rectState == NOT_SET && !isb && !isf )    //只点击左键时
{
rectState = IN_PROCESS;   //正在处理矩形框
p1 = Point(x, y);   //起点
}
if ( (isb || isf) && rectState == SET )   //选中alt或shift键,并且矩形框已设置
{
lblsState = IN_PROCESS;   //正在画背景或前景
}
}
break;
case CV_EVENT_LBUTTONUP:   //点击鼠标左键up
if( rectState == IN_PROCESS )     //若是正在处理矩形框时
{
p2 = Point(x, y);        //终点
rect = Rect( p1, p2 );   //矩形框选中
rectState = SET;         //矩形框状态为已设置
grabCut( image, mask, rect, bgdModel, fgdModel, 0, GC_INIT_WITH_RECT );  //grabCut  初始化
assert( bgdPxls.empty() && fgdPxls.empty() );   //判断背景和前景的画笔像素是否为空,为空报错
showImage( image, mask, bgdPxls, fgdPxls );  //刷新
}
if( lblsState == IN_PROCESS )    //若是正在处理背景或前景画笔
{
lblsState = NOT_SET;         //画笔状态为0
showImage( image, mask, bgdPxls, fgdPxls );   //刷新
}
break;
case CV_EVENT_MOUSEMOVE:     //鼠标移动
if( rectState == IN_PROCESS )     //若是正在处理矩形框时
{
Mat res;
image.copyTo(res);            //image->res
rectangle(res, p1, Point(x,y), Scalar(0,255,0), 2);  //图像,矩形的一个顶点,矩形对角线上的另一个顶点,线条颜色,组成矩形的线条的粗细程度
imshow(winName, res);     //显示鼠标移动时矩形框的变化
}
else if( lblsState == IN_PROCESS )  //若是正在处理画笔
{
Point p = Point(x, y);        //当前点的坐标
if( flags & CV_EVENT_FLAG_ALTKEY )   //若是同时按键alt
{
bgdPxls.push_back(p);            //背景画笔记录轨迹
showImage( image, mask, bgdPxls, fgdPxls );  //刷新显示轨迹
}
if( flags & CV_EVENT_FLAG_SHIFTKEY )  //若是同时按键shift
{
fgdPxls.push_back( Point(x, y) );    //前景画笔记录轨迹
showImage( image, mask, bgdPxls, fgdPxls );   //刷新显示轨迹
}
}
break;
}
}

int main( int argc, char** argv )
{
if( argc==1 )
return 1;
string filename = argv[1];
if( filename.empty() )
return 1;
image = imread( filename, 1 );
if( image.empty() )
return 1;

cout << "Hot keys: /n" <<
"/tESC - quit the program/n"
"First, select the rectangular area/n"
"/tr - restore the original image/n"
"/tn - next iteration/n"
"/n/n"
"/tleft mouse button - set rectangle/n"
"/talt+left mouse button - set background pixels/n"
"/tshift+left mouse button - set foreground pixels/n";

cvNamedWindow( winName.c_str(), CV_WINDOW_AUTOSIZE ); //函数cvNamedWindow创建一个可以放置图像和trackbar的窗口。被创建的窗口可以通过它们的名字被引用。
imshow( winName, image );  //显示图像

cvSetMouseCallback( winName.c_str(), on_mouse, 0 );   //跟踪鼠标
//窗口名,指定窗口里每次鼠标事件发生的时候,被调用的函数指针,param是用户定义的传递到cvSetMouseCallback函数调用的参数。
//函数cvSetMouseCallback设定指定窗口鼠标事件发生时的回调函数

rectState = NOT_SET;
lblsState = NOT_SET;
iterCount = 0;
for(;;)
{
int c = cvWaitKey(0); //等待输入
switch( (char) c )
{
case '/x1b':   //退出
cout << "Exiting ..." << endl;
goto exit_main;
case 'r':      //重新加载图像
rectState = NOT_SET;
lblsState = NOT_SET;
iterCount = 0;
bgdPxls.clear();
fgdPxls.clear();
mask.release();
cout << endl;
assert( bgdPxls.empty() && fgdPxls.empty() && mask.empty() );  //检查是否为0,为0报错
showImage( image, mask, bgdPxls, fgdPxls );  //显示图像
break;
case 'n':
cout << "<" << iterCount << "... ";
if( rectState == SET )  //框被选中
{
changeMask( mask, bgdPxls, fgdPxls );  //改变蒙板
bgdPxls.clear(); fgdPxls.clear();
grabCut( image, mask, rect, bgdModel, fgdModel, 1 );  //执行grabCut算法
//grabCut( image, mask, rect, bgdModel, fgdModel, 0, GC_INIT_WITH_RECT );  //grabCut  初始化
showImage( image, mask, bgdPxls, fgdPxls );   //显示图像
cout << iterCount << ">" << endl;
iterCount++;
}
else
cout << "rect is not determined>" << endl;
break;
case 's':  //保存图像
imwrite("save.jpg",outImage);
cout <<"save..."<<endl;
break;
}

}

exit_main:
cvDestroyWindow( winName.c_str() );   //释放窗口
return 0;
}






















内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐