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
时间: 2024-11-07 18:30:08

opencv实现图像分割,分离前景和背景的相关文章

opencv之通道分离和合并

opencv之通道分离和合并 通道分离 void split(const Mat& src, Mat* mvbegin); void split(InputArray m, OutputArrayOfArrays mv); 通道合并 void merge(const Mat* mv, size_t count, OutputArray dst); void merge(InputArrayOfArrays mv, OutputArray dst); 实例 #include <opencv2/

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

简介 如题,本篇是在前一篇的基础上进一步讲解的第三个图像背景分离例子. 实例介绍 这个例子是在上一个加入鼠标操作实例的进一步操作. 本例:可以在鼠标选框完成之后,1.通过shift+鼠标右键来选择设置图像对应位置为前景. 2.通过ctrl +鼠标右键来选择设置图像对应位置为背景景. 3.按下键值'n',进行图像背景分离计算,并显示结果. 4.按下键值'esc',退出程序. 实例讲解 具体代码 #include "opencv2/highgui/highgui.hpp" #include

via OpenCv 提取分离前景和背景

1 #include <opencv2/highgui/highgui.hpp> 2 #include <opencv2/core/core.hpp> 3 #include <vector> 4 #include <iostream> 5 #include <opencv2/imgproc/imgproc.hpp> 6 //#include "../../../../../Downloads/colourhistogram.h"

OpenCV 之 图像分割 (一)

1  基于阈值 1.1  基本原理 灰度阈值化,是最简单也是速度最快的一种图像分割方法,广泛应用在硬件图像处理领域 (例如,基于 FPGA 的实时图像处理). 假设输入图像为 f,输出图像为 g,则经过阈值化处理的公式如下: $\quad g(i, j) = \begin{cases} 1 & \text{当 f(i, j) ≥ T 时} \\0 & \text{当 f(i, j) < T 时} \\ \end{cases} $ 也即,遍历图像中的所有像素,当像素值 f (i, j)

opencv 金字塔图像分割

我所知的opencv中分割函数:watershed(只是看看效果,不能返回每类pixel类属),cvsegmentImage,cvPyrSegmentation(返回pixel类属) 金字塔分割原理篇在这里,本文只提供代码. Segment函数: [cpp] view plain copy #include<cv.h> #include <cvaux.h> #include <opencv\cxcore.hpp> #include <opencv.hpp>

OpenCV运动目标检测——帧间差,混合高斯模型方法

一.简单的帧间差方法 帧差法是在连续的图像序列中两个或三个相邻帧间采用基于像素的时间差分并且闽值化来提取图像中的运动区域. 代码: int _tmain(int argc, _TCHAR* argv[]) { VideoCapture capture("bike.avi"); if(!capture.isOpened()) return -1; double rate = capture.get(CV_CAP_PROP_FPS); int delay = 1000/rate; Mat

图像金字塔及其在 OpenCV 中的应用范例(下)

前言 本文将主要讲解如何使用 OpenCV 实现图像分割,这也是图像金字塔在 OpenCV 中的一个重要应用. 关于图像分割 在计算机视觉领域,图像分割(Segmentation)指的是将数字图像细分为多个图像子区域(像素的集合)(也被称作超像素)的过程.图像分割的目的是简化或改变图像的表示形式,使得图像更容易理解和分析.[1]图像分割通常用于定位图像中的物体和边界(线,曲线等).更精确的,图像分割是对图像中的每个像素加标签的一个过程,这一过程使得具有相同标签的像素具有某种共同视觉特性. 图像分

大津法(Python实现)

在计算机视觉和图像处理中,大津法被用于自动获取图像的阈值,或者将灰度图像转换为二值化图像.该算法假设图像包含两个类别的像素(前景像素和背景像素),然后它计算一个最优的阈值用于分离前景和背景,使得前景和背景的类间方差最小. 下面定义类间方差的计算公式: 假设我们使用阈值T将灰度图像分割为前景和背景 size:图像总像素个数 u:图像的平均灰度 w0:前景像素点占整幅图像大小的比例 u0:前景像素点的平均值 w1:背景像素点占整幅图像大小的比例 u0:背景像素点的平均值 g:类间方差 u = w0

GMM+Kalman Filter+Blob 目标跟踪

转 http://www.cnblogs.com/YangQiaoblog/p/5462453.html ==========图片版============================================================================== ===================================================================================== 最近学习了一下多目标跟踪,看了看Mat