码迷,mamicode.com
首页 > 其他好文 > 详细

opencv实现图像分割,分离前景和背景

时间:2015-05-14 18:42:41      阅读:487      评论:0      收藏:0      [点我收藏+]

标签:opencv   图像处理   

简介

  如题,本篇就是讲解和使用opencv函数grabcut,来实现图像前景与背景的分离。

函数原型

  1、opencv官方介绍:opencv官方grabcut介绍
  2、网上童鞋翻译解释:学习OpenCV——学习grabcut算法
  3、大致内容如下:
         函数原型:
              void grabCut(InputArray img, InputOutputArray mask, Rect rect, 
                             InputOutputArray bgdModel, InputOutputArray fgdModel, 
                             int iterCount, int mode=GC_EVAL )
              img:待分割的源图像,必须是8位3通道(CV_8UC3)图像,在处理的过程中不会被修改;
              mask:掩码图像,大小和原图像一致。可以有如下几种取值:
                        GC_BGD(=0),背景;
                        GC_FGD(=1),前景;
                        GC_PR_BGD(=2),可能的背景;
                        GC_PR_FGD(=3),可能的前景。
                rect:用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理;
                bgdModel:背景模型,如果为null,函数内部会自动创建一个bgdModel;
                fgdModel:前景模型,如果为null,函数内部会自动创建一个fgdModel;
                iterCount:迭代次数,必须大于0;
                mode:用于指示grabCut函数进行什么操作。可以有如下几种选择:
                    GC_INIT_WITH_RECT(=0),用矩形窗初始化GrabCut;
                    GC_INIT_WITH_MASK(=1),用掩码图像初始化GrabCut;
                    GC_EVAL(=2),执行分割。
   4、基本原理:
          首先用户在图片上画一个方框,grabCut默认方框内部为前景,设置掩码为2,方框外部都是背景,设置掩码为0。然后根据算法,
       将方框内部检查出来是背景的位置,掩码由2改为0。最后,经过算法处理,方框中掩码依然为2的,就是检查出来的前景,其他为背景。

实例讲解1

  这些例子都主要是根据opencv自带的例子:opencv\samples\cpp\grabcut.cpp 简化修改而来。

源代码

代码如下:
#include "opencv2/highgui/highgui.hpp"                                                                                               
#include "opencv2/imgproc/imgproc.hpp"
 
#include <iostream>
 
using namespace std;
using namespace cv; 
 
string filename;
Mat image;
string winName = "show";
Rect rect;
Mat mask;
const Scalar GREEN = Scalar(0,255,0);
Mat bgdModel, fgdModel;
 
void setRectInMask(){
	rect.x = 110;
	rect.y = 220;
	rect.width = 100;
	rect.height = 100;
}
 
static void getBinMask( const Mat& comMask, Mat& binMask ){
	binMask.create( comMask.size(), CV_8UC1 );
	binMask = comMask & 1;
}
 
int main(int argc, char* argv[]){
	Mat binMask, res;
	filename = argv[1];
	image = imread( filename, 1 );
	mask.create(image.size(), CV_8UC1);
	mask.setTo(GC_BGD);
	setRectInMask();
	(mask(rect)).setTo(Scalar(GC_PR_FGD));
	rectangle(image, Point(rect.x, rect.y), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2);
	imshow(winName, image);
	image = imread( filename, 1 );
	grabCut(image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_RECT);
	getBinMask(mask, binMask);
	image.copyTo(res, binMask);
	imshow("result", res);
 
	waitKey(0);
 
	return 0;
}

代码讲解

  1、首先是装载需要处理的源图片。
        filename = argv[1];
	image = imread( filename, 1 );
  2、设置掩码,首先创建了一个和源图片一样大小的掩码空间。接着将整个掩码空间设置为背景:GC_BGD。接着创建了一个rect,对应左上角坐标为:
(110,220),长宽都为100。接着在掩码空间mask对应左边位置的掩码设置为GC_PR_FGD(疑似为前景)。这个rect就是需要分离前景背景的空间。同时
在源图像上,rect对应的需要被处理位置画出绿色方框框选。接着将画了绿色方框之后的源图片显示出来。
	mask.create(image.size(), CV_8UC1);
	mask.setTo(GC_BGD);
	setRectInMask();
	(mask(rect)).setTo(Scalar(GC_PR_FGD));
	rectangle(image, Point(rect.x, rect.y), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2);
	imshow(winName, image);
  3、之前的源图像被画了绿色方框,所以需要重新装载一遍源图像。接着使用函数grabCut,根据传入的相关参数,进行前景背景分离操作。最后在生成的
结果保存在mask中,背景被置为0,前景被置为1。接着将mask结果筛选到binMask中。最后使用image.copyTo(res, binMask);将原图像根据binMask作为掩码,
将筛选出来的前景复制到目标图像res中。并将目标图像显示出来。

效果演示

  原图像:
              技术分享
  目标图像:
              技术分享


实例讲解2

  继续这个例子中加入了鼠标的操作。

源代码

#include "opencv2/highgui/highgui.hpp"                                                                                               
#include "opencv2/imgproc/imgproc.hpp"
 
#include <iostream>
 
using namespace std;
using namespace cv; 
 
string filename;
Mat image;
string winName = "show";
enum{NOT_SET = 0, IN_PROCESS = 1, SET = 2};
uchar rectState;
Rect rect;
Mat mask;
const Scalar GREEN = Scalar(0,255,0);
Mat bgdModel, fgdModel;
 
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* )
{
	Mat res;
	Mat binMask;
 
	switch( event ){
		case CV_EVENT_LBUTTONDOWN:
			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));
				image = imread( filename, 1 );
				grabCut(image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_RECT);
				getBinMask( mask, binMask );
				image.copyTo(res, binMask );
				imshow("11", res);
			}
			break;
		case CV_EVENT_MOUSEMOVE:
			if( rectState == IN_PROCESS ){
				rect = Rect( Point(rect.x, rect.y), Point(x,y) );
				image = imread( filename, 1 );
				rectangle(image, Point( rect.x, rect.y ), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2);
				imshow(winName, image);
			}
			break;
	}
}
 
int main(int argc, char* argv[]){
	filename = argv[1];
	image = imread( filename, 1 );
	imshow(winName, image);
	mask.create(image.size(), CV_8UC1);
	rectState = NOT_SET;
	mask.setTo(GC_BGD);
 
	setMouseCallback(winName, on_mouse, 0);
	waitKey(0);
 
	return 0;
}

代码讲解

  这一步中,主要也就是加入了鼠标响应。通过鼠标左键按下拖动,来框选之前提到的绿色目标框,当释放掉鼠标左键之后,便会将框选的位置进行
背景分离。
代码下载路径:http://download.csdn.net/detail/u011630458/8700335

opencv实现图像分割,分离前景和背景

标签:opencv   图像处理   

原文地址:http://blog.csdn.net/u011630458/article/details/45723895

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!