柯受良,[图像处理] OpenCV系列26——图形输出功能的详细说明-ope电竞平台-ope电竞竞猜官方网站

暖心故事 238℃ 0

上一节咱们学习了间隔改换算法,信任咱们学习之后,对间隔改换算法现已有了根本的知道,本节呢,咱们对学习图画切割,对grabCut函数详解!

一、函数详解

1、函数原型

void grabCut(InputArray img,

InputOutputArray mask,

Rect rect,

InputOutputArray bgdModel,

InputOutputArray fgdModel,

int iterCount,

int mode = GC_EVAL)

2、函数功用

首要完成对图画布景的切割!

3、参数详解

  • 第一个参数,InputArray img,输入图画,一个8位3通道的图画;
  • 第二个参数,InputOutputA柯受良,[图画处理] OpenCV系列26——图形输出功用的具体阐明-ope电竞渠道-ope电竞竞猜官方网站rray mask,输入/输出一个8位单通道的掩码图画;当函数的参数mode设置为GC_INIT_WITH_RECT,掩码由函数进行初始化;它的元素可能是GrabCutClasses中的一个;

掩码的类型

(1) GC_BGD,表明是布景;

(2) GC_FGD,表明是远景;

(3) GC_PR_BGD, 表明可能是布景;

(4) GC_PR_FGD, 表明可能是远景;

  • 第三个参数,Rect rect,要切割目标的ROI,ROI外部的像素被符号为“显着的布景”;只有当函数的参数mode设置为GC_INIT_WITH_RECT时,才运用该参数;
  • 第四个参数,InputOutputArray bgdModel,布景模型的暂时数组;在处理同一图画时,不要修正它;
  • 第五个参数,InputOutputArray fgdModel,远景模型的暂时数组;在处理同一图画时,不要修正它;
  • 第六个参数,int iterCount,在回来成果之前,算法应该进行的迭代次数;

Note:

能够将函数中的参数mode设置为GC_INIT_WITH_MASK或许GC_EVAL进一步骤用来细化成果;

  • 第七个参数,int mode = GC_EVAL,操作的形式;

操作的形式有以下几种

(1) GC_INIT_WITH_RECT,函数运用供给的矩形来初始化状况和掩码;之后,它运转算法iterCount次迭代。

(2) GC_INIT_WITH_MASK,函数运用供给的掩码初始化状况;

Note:

能够组合运用GC_INIT_WITH_RECT和GC_INIT_WITH_MASK;

(3) GC_EVAL,该值意味着该算法只需康复;

(4) GC_EVAL_FREEZE_MODEL,该值意味着该算法应该只运转具有固定模型的GrabCut算法(一次迭代);

二、归纳实例

1、亚洲情色图片试验事例

完成对人物的图画进行抠图

辅佐信息

#include 
#include
#include
#inclu日子麻辣烫陈小伟de

using namespace std;
using namespace cv;

static void help()
{
cout << "\n在图画中挑选一块区域,然后用grabCut测验将其切割出来.\n"
"\鱼头汤的做法n在图画中挑选一块你要切割的矩形区域\n" <<
"\nHot keys: \n"
"\tESC - 退出程序\n"
"\tr - 回复原始图画\n"
"\tn - 下一次迭代\n"
"\n"
"\t左键移动,设置要切割的矩形\n"
"\n"
"\tCTRL+left 鼠标按键 - 设置 GC_BGD 布景\n"
"\tSHIFT+left 鼠标按键 - 设置 GC_FGD 远景\n"
"\n"
"\tCTRL+right 鼠标按键 - 设置 GC_PR_BGD 可能是布景\n"
"\tSHIFT+right 鼠标按键 - 设置 GC_PR_FGD 可能是远景\n" << endl;
}

// 赤色
const Scalar RED = Scalar(0,0,255);

// 粉红
const Scalar PINK = Scalar(230,130,255);

// 蓝色
const Scalar BLUE = Scalar(255,0,0);

// 微蓝
const Scalar LIGHTBLUE = Scalar(255柯受良,[图画处理] OpenCV系列26——图形输出功用的具体阐明-ope电竞渠道-ope电竞竞猜官方网站,255,160);

// 绿色
const Scalar GREEN = Scalar(0,255,0);

// 布景模型按键 Ctrl键
const int BGD_KEY = EVENT_FL达美航空AG_CTRLKEY;

// 远景模型按键 shift键
const int FGD_KEY = EVENT_FLAG_SHIFTKEY;

// 获取二值化的掩码
static void getBinMask( const Mat& comMask, Mat& binMask )
{
if( co柯受良,[图画处理] OpenCV系列26——图形输出功用的具体阐明-ope电竞渠道-ope电竞竞猜官方网站mMask.empty() || comMask.type()!=CV_8UC1 )
CV_Error( Error::StsBadArg,
"comMask is empty or has incorrect type (not CV_8UC1)" );

// 进行判别,假如为false,则从头创立binMask掩码
if( binMask.empty() ||
binMask.rows!=comMask.rows
|| binMask.cols!=玛卡的成效与效果comMask.cols )
binMask.create( comMask.size(), CV_8UC1 );

binMask = comMask & 1; // 一切的像素&1
}


// 应用程序类
class GCApplication
{
public:
enum
{
NOT_SET = 0, // 未设置状况
IN_PROCESS = 1, // 正在处理状况
SET = 2 // 设置状况
};

// 圆的半径
static const int radius = 2;

// 字体的巨细
static const int thickness = -1;

// 重置
void reset();

// 设置图片和窗口称号
void冰雪奇缘主题曲 setImageAndWinName( const Mat& _image, const string& _winName );

// 显现图片
void showImage() const;

// 鼠标点击
void mouseClick( int even尚文祁t, int x, int y, int flags, void* param );

// 下一次迭代
int nextIter();

// 获取迭代次数
int getIterCount() const { return iterCount; }

private:
// 在掩码中设置Rect
void setRectInMask();

// 左键
void setLblsInMask( int flags, Point p, bool isPr );

// 窗口称号
const stri柯受良,[图画处理] OpenCV系列26——图形输出功用的具体阐明-ope电竞渠道-ope电竞竞猜官方网站ng* winName;

// 图画
const Mat* image;

// 掩码
Mat mask;

// 远景模型与布景模型
Mat bgdModel, fgdModel;

// 制作矩形的状况,左键按下的状况,右键按下的状况
uchar rectState, lblsState, prLblsState;

// 是否初始化
bool isInitialized;

// 要切割的矩形
Rect rect;

// 左键前/布景制作点集,右键前/布景制作点集
vector fgdPxls, bgdPxls, prFgdPxls, prBgdPxls;

// 迭代的次数
int iterCount;
};


// 重置参数信息的函数
void GCApplication::reset()
{
// 掩码不为空,则重置掩码
if( !mask.empty() )
mask.setTo(Scalar::all(GC_BGD));

// 清空点集
bgdPxls.clear();
fgdPxls.clear();

pr漫画头像BgdPxls.clear();
prFgdPxls.clear();

// 初始化设置为false
isInitialized = false;

// 矩形,左键,右键三个状况设置为NOT_SET
rectState = NOT_SET;
lblsState = NOT_SET;
prLblsState = NOT_SET;

// 迭代次数设置为0
iterCount = 0;
}


// 设置窗口的称号
void GCApplication::setImageAndWinName( const Mat& _image, const string& _winName )
{
// 对函数参数的信息进行判别
if( _image.empty() || _winName.empty() )
return;

// 参数列表中的值,赋值到全局变量中
image = &_image;
winName = &_winName;

// 掩码图画从头创立
mask.create( image->size(), CV_8UC1);

// 重置状况
reset();
}


// 显现图画
void GCApplication::showImage() const
{
// 对图画和窗口称号进行判别
if( image->empty() || winName->empty() )
return;

// 成果图画
Mat res;

// 二值化掩码图画
Mat binMask;

// 假如没有初始化
if( !isInitialized )
// 直接进行复制
image->copyTo( res );
else
{
// 获取二值化的掩码
getBinMask( mask, binMask );

// 复制带掩码
image->copyTo( res, binMask );
}

// 鼠标通过的点,用不同的色彩制作出来,默许原点
vector::const_iterator it;
for( it = bgdPxls.begin(); it != bgdPxls.end(); ++it )
circle( res, *it, radius, BLUE, thickness );

for( it = fgdPxls.begin(); it != fgdPxls.end(); ++it )
circle( res, *it, radius, RED, thickness );

for( it = prBgdPxls.begin(); it != prBgdPxls.end(); ++it )
circle( res, *it, radius, LIGHTBLUE, thickness );

for( it = prFgdPxls.begin(); it != prFgdPxls.end(); ++it )
circle( res, *it, radius, PINK, thickness );

// 制作矩形
if( rectState == IN_PROCESS || rectState == SET )
rectangle( res, Point( rect.x, rect.y ), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2);

// 显现图画
imshow( *winName, res );
}


// 设置要切割的Rect
void GCApplication::setRectInMask()
{
CV_Assert( !mask.empty() );柯受良,[图画处理] OpenCV系列26——图形输出功用的具体阐明-ope电竞渠道-ope电竞竞猜官方网站

// 掩码设置为布景
mask.setTo( GC_BGD );

// 矩形的巨细
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);

// 掩码区域设置为可能是远景
(mask(rect)).setTo( Scalar(GC_PR_FGD) );
}


// 设置状况
void GCApplication::setLblsInMask( int flags, Point p, bool isPr )
{
// 布景,远景点集
vector *bpxls, *fpxls;

uchar bvalue, fvalue;

// 远景,布景
if( !isPr柯受良,[图画处理] OpenCV系列26——图形输出功用的具体阐明-ope电竞渠道-ope电竞竞猜官方网站 )
{
bpxls = &bgdPxls;
fpxls = &fgdPxls;
bvalue = GC_BGD;
fvalue = GC_FGD;
}
// 可能是远景,布景
else
{
bpxls = &prBgdPxls;
fpxls = &prFgdPxls;
bvalue = GC_PR_BGD;
fvalue = GC_PR_FGD;
}

// 布景+Ctrl键
if( flags & BGD_KEY )
{
// 点集压栈
bpxls->push_back(p);

// 制作圆
circle( mask, p, radius, bvalue, thickness );
}

// 远景+shift键
if( flags & FGD_KEY )
{
// 点集压栈
fpxls->push_back(p);

// 制作圆
circle( mask, p, radius, fvalue, thickness );
}
}


// 鼠标点击事情
void GCApplication::mouseClick( int 心跳event, int x, int y, int flags, void* )
{
switch( event )
{
// set rect or GC_BGD(GC_FGD) labels 左键按下
case EVENT_LBUTTONDOWN:
{
bool isb = 梭(flags & BGD_KEY) != 0,
isf = (flags & FGD_KEY) != 0;

if( rectState == NOT_SET && !isb && !isf )
{
// 制作矩形正在被占用
rectState = IN_PROCESS;

// 制作的矩形
rect = Rect( x, y, 1, 1 );
}
if ( (isb || isf) && rectState == SET )
// 符号左键正在占用
lblsState = IN_PROCESS;
}
break;
// set GC_PR_BGD(GC_PR_FGD) labels 右键按下
case EVENT_RBUTTONDOWN:
{
bool isb = (flags & BGD_KEY) != 0,
isf = (flags & FGD_KEY) != 0;

if ( (isb || isf) && re凤凰卫视资讯台c柯受良,[图画处理] OpenCV系列26——图形输出功用的具体阐明-ope电竞渠道-ope电竞竞猜官方网站tState == SET )
// 符号右键正在被占用
prLblsState = IN_PROCESS;
}
break;

// 左键松起
case EVENT_LBUTTONUP:
// 假如制作矩形状况被占用
if( rectState == IN_PROCESS )
{
// 制作的矩形
rect = Rect( Point(rect.x, rect.y), Point(x,y) );

// 制作矩形的状况标示为设置
re小萝卜头ctState = SET;

// 设置掩码
setRectInMask();

// 对一些参数进行判别
CV_Assert( bgdPxls.empty() &&
fgdPxls.em简伯承pty() &&
prBgdPxl刮脂藻s.empty() &&
prFgdPxls.empty() );

// 显现图画
showImage();
}

// 假如左键被占用
if( lblsState == IN_PROCESS )
安德的游戏{
// 键盘加鼠标按下,画圆
setLblsInMask(flags, Point(x,y), false);

// 左键状况改为设置
lblsState = SET;

// 显现图画
showImage();
}
break;

// 右键松起
case EVENT_RBUTTONUP:

// 假如右键正在被占用
if( prLblsState == IN_PROCESS )
{
// 键盘加鼠标按下,画圆
setLblsInMask(flags, Point(x,y), true);

// 右键状况改为设置
prLblsState = SET;

// 显现图画
showImage();
}
break;

// 鼠标移动
case EVENT_MOUSEMOVE:

// 假如制作矩形的状况正在被占用
if( rectState == IN_PROCESS )
{
// 实时改写矩形的巨细
rect = Rect( Point(rect.x, rect.y), Point(x,y) );

// 对点集的参数进行判别
CV_Assert( bgdPxls.empty() &&
fgdPxls.empty()双瞳 &&
prBgdPxls.empty() &&
prFgdPxls.empty() );

// 实时显现图画
showImage();
}

// 假如左键被占用
else if( lblsState == IN_PROCESS )
{
// 键盘加鼠标按下,画圆
setLblsInMask(flags, Point(x,y), false);

// 显现图画
showImage();
}

// 假如右键正在被占用
else if( prLblsState == IN_PROCESS )
{
// 键盘加鼠标按下,画圆
setLblsInMask(flags, Point(x,y), true);

// 实时显现图画
showImage();
}
break;
}
}


// 下一次迭代
int GCApplication::nextIter()
{
// 假如现已初始化,直接进行切割图画
if( isInitialized )
// 切割图画
grabCut( *image, mask, rect, bgdModel, fgdModel, 1 );

else
{
// 对图画进行初始化
if( rectState != SET )
return iterCount;

if( lblsState == SET || prLblsState == SET )
// 切割图画
grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_MASK );

else
// 切割图画
grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_RE支付宝敬业福CT );

// 设置图画现已初始化符号
isInitialized = true;
}

// 迭代次数加1
iterCount++;

// 数据点清空
bgdPxls.clear(); fgdPxls.clear();
prBgdPxls.clear(); prFgdPxls.clear();

// 回来迭代的次数
return iterCount;
}


// 类变量声明
GCApplication gcapp;


// 鼠标移动事情
static void on_mouse( int event, int x, int y, int flags, void* param )
{
gcapp.mouseClick( event, x, y, flags, param );
}


// mian函数
int main( int argc, char** argv )
{
// 辅佐信息
help();

// 载入图画
Mat image = imread("lena.png", IMREAD_COLOR);

// 判别图画是否为空
if( image.empty() )
{
cout << "\n image error!" << endl;
return -1;
}

const string winName = "image";
namedWindow( winName, WINDOW_AUTOSIZE );

// 设置鼠标调用事情
setMouseCallback( winName, on_mouse, 0 );

// 设置窗口称号
gcapp.setImageAndWinName( image, winName );

// 显现图画
gcapp.showImage();

for(;;)
{
// 从键盘接纳输入
char c = (char)waitKey(0);
switch( c )
{
// 退出程序
case '\\x1b':
cout << "Exiting ..." << endl;
goto exit_main;

// 康复为原始图画
case 'r':
cout << endl;
gcapp.reset();
gcapp.showImage();
break;

// 进行迭代
case 'n':
// 获取当时迭代的次数
int iterCount = gcapp.getIterCount();

cout << "<" << iterCount << "... ";

// 进行下一次迭代
int newIterCount = gcapp.nextIter();

if( newIterCount > iterCount )
{
/amber/ 显现图画
gc缺钙的症状有哪些app.showImage();
cout << iterCount << ">" << endl;
}
else
cout << "rect must be determined>" << endl;
break;
}
}

// 退出程序,毁掉窗口
exit_main:
destroyWindow( winName );
return 0;
}

2、试验成果

原图


抠图的成果

我是奕双,现在现已结业将近两年了,从大学开端学编程,期间学习了C言语编程,C++言语编程,Win32编程,MFC编程,结业之后进入一家图画处理相关范畴的公司,把握了用OpenCV对图画进行处理,假如咱们对相关范畴感兴趣的话,能够重视我,我这边会为咱们进行回答哦!假如咱们需求相关学习材料的话,能够私聊我哦!

标签: pokeman