2018-06-12 20:29:09 program_developer 阅读数 1493

“微信公众号”


本文介绍图像处理、计算机视觉、图像前背景分离技术等领域的术语。这里给出若干相关术语及本文对这些术语的解释。

1. 前背景分离(matting):也称抠图,即将图像或视频的某一感兴趣的部分从原始图像或视频中分离出来,主要功能是为了和另一个图像或视频进行合成,形成新的图像或视频。

2. 颜色空间(color space):颜色模型是使用一组值(通常三个、四个值或者颜色成分)表示颜色的抽象数学模型,比如RGB和CMYK都是颜色模型。在颜色模型和一个特定的参照颜色空间之间加入一个特定的映射函数就在参照颜色空间中确定了一个明确的色域,并且与颜色模型一起定义为一个新的颜色空间。

3. 前景蒙版(alpha matte):也称前景透明度或透明度蒙版,是前背景分离的结果,是一个灰度图,每一个像素点的灰度值表示原始图像每个像素属于前景物体的程度,白色代表某一个像素确定属于前景,黑色代表某一个像素确定属于背景。

4. 三值蒙版(trimap):是一些前背景分离方法使用的用户输入和约束条件,用户在原图像上指定哪些像素点是确定的前景,用白色表示;哪些像素点是确定的背景,用黑色表示;哪些像素点是不确定的部分,用某种灰色表示。三值蒙版越精细准确,得到的前背景分离结果越好,但对用户的要求更高,处理时间越长。

5. 简单标记(scribble):是一些前背景分离方法使用的用户输入和约束条件,用户在原图像上以一个或多个白色点或线条标记确定的前景,以一个或多个黑色点或线条标记确定的背景,标记越多、越具有代表性,得到的前背景分离结果越好,对用户的要求也更高。简单标记与三值蒙版相比较,用户输入更简单方便,能大大减少处理时间。

6. 边缘检测算子(edge detection operator):边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化,包括深度上的不连续、表明方向不连续、物质属性变化和场景照明变化。图像边缘检测大幅度地减少了数据量,留下了图像重要的结构属性。边缘检测算子包括:Roberts Cross算子、Prewitt算子、Sobel算子、Canny算子、罗盘算子等。Canny算子是最常用的边缘检测方法。

7. 视差图(disparity map):视差就是从有一定距离的两个点上观察同一个目标所产生的方向差异。从目标看两个点之间的夹角,叫做这两个点的视差,两点之间的距离称作基线。只要知道视差角度和基线长度,就可以计算出目标和观测者之间的距离。视差图是以图像对中任一幅图像为基准,其大小为该基准图像的大小,元素值为视差值的图像。

8. 深度图(depth map):本文中的深度图是黑白二值图,是通过对图像的视差图再处理或视频背景建模后获取深度的结果,作为本文前背景分离方法的约束条件。综合考虑原始图像的颜色信息和深度信息,可以得到更好的前背景分离效果。

9. 前背景分离方程(matting equation):自然图像I可看作由前景图像F和背景图像B组合而成,I中的每个像素点是F和B中对应像素点颜色的线性组合。

  (1)

为像素点的前景透明度,。(1)式中,已知,而未知,是一个缺少条件的方程组。使用RGB颜色空间则有:

  (2)

(2)式有7个未知量,却只有3个方程,如果不加其他条件,(2)式有无穷多解。有人眼来分辨一幅图像哪些部分属于前景,哪些部分属于背景,只有一个或几个可以接受的结果,前背景分离模型为将这一过程自动化,可对前景和背景合理假设,或者增加图像数量,使方程组的解变少,使解与人眼分辨结果尽可能接近。


读论文《图像前背景分离的研究与实现》的笔记。

地址:https://www.docin.com/p-1084120800.html

2016-01-27 19:58:23 u010402786 阅读数 33575

前提

    运动目标的检测是计算机图像处理与图像理解领域里一个重要课题,在机器人导航、智能监控、医学图像分析、视频图像编码及传输等领域有着广泛的应用。
                                      这里写图片描述

目标检测方法分类

  第一,已知目标的先验知识。在这种情况下检测目标有两类方法,第一类方法是用目标的先验知识训练一堆弱分类器,然后这些弱分类器一起投票来检测目标,如boosting, random forest 都是这个思路,大家熟知的adaboost人脸检测也是如此。第二类方法是根据先验知识找到目标和非目标的最佳划分线,如SVM.这两类方法各成一家,各有所长,都有着不错的表现。

  第二,未知目标的先验知识。此时不知道要检测的目标是什么,于是什么是目标就有了不同的定义。一种方法是检测场景中的显著目标,如通过一些特征表达出场景中每个像素的显著性概率,然后找到显著目标。另一种方法就是检测场景当中的运动目标了。

经典目标检测方法

1、背景差分法
  在检测运动目标时,如果背景是静止的,利用当前图像与预存的背景图像作差分,再利用阈值来检测运动区域的一种动态目标识别技术。
  背景差分算法适用于背景已知的情况,但难点是如何自动获得长久的静态背景模型。
  matlab中单纯的背景差分直接是函数imabsdiff(X,Y)就可以。
2、帧差分法
  利用视频序列中连续的两帧或几帧图像的差来进行目标检测和提取。在运动的检测过程中,该方法利用时间信息,通过比较图像中若干连续帧获得对应像素点的灰度差值,如果均大于一定的阈值T2,则可以判断该位置存在运动的目标。
  较适合于动态变化场景。
3、光流场法
  利用相邻两帧中对应像素的灰度保持原理来评估二维图像的变化。能够较好的从背景中检测到相关前景目标,甚至是运动屋里中的部分运动目标,适用于摄像机运动过程中相对运动目标的检测。
  开口问题、光流场约束方程的解的不唯一性问题。不能正确的表示实际的运动场。
        例子如下:
       1.首先在一帧图像内随机均匀选取k个点,并滤除那些邻域纹理太光滑的点,因为这些点不利于计算光流。
这里写图片描述
       2.计算这些点与上一帧图像的光流矢量,如上右图,此时已经可以看出背景运动的大概方向了。
       这里写图片描述
       3.接下来的这一步方法因人而异了。
       2007年cvpr的一篇文章Detection and segmentation of moving objects in highly dynamic scenes的方法是把这些光流点的(x,y,dx,dy,Y,U,V)7个特征通过meanshift聚类来聚合到一起,最后形成运动目标轮廓。

新目标检测方法

       其实写到这里想了想到底能不能叫目标检测,博主认为图像的前背景分离也是目标检测的一种(博主才疏学浅,求赐教)

1、像素点操作
  对每个像素点进行操作,判别为前景或者背景两类。如下面的图片所示:
  这里写图片描述
2、低秩矩阵应用
  背景建模是从拍摄的视频中分离出背景和前景。下面的例子就是将背景与前景分离开。使用的方法是RPCA的方法。
  其网址以及效果如下:
  http://perception.csl.illinois.edu/matrix-rank/introduction.html
  这里写图片描述
3、深度学习
  FCN + denseCRF 精确分割+语义标签。图像中的前景目标检测分割做的很好,下面还能做出语义检测,判断出图中的东西属于什么。This demo is based on our ICCV 2015 paper :Conditional Random Fields as Recurrent Neural Networks,
  测试网址以及测试图像如下:
  http://www.robots.ox.ac.uk/~szheng/crfasrnndemo
  这里写图片描述


推荐另外一篇关于神经网络改进方法的上篇内容:
http://blog.csdn.net/u010402786/article/details/49272757
       另外附上一个深度学习未来发展趋势之一:
       “注意力模型” 在未来的发展,注意力模型的升温。一些系统,但不是全部,开始放到“注意力模型”的背景中,或者说让神经网络在完成任务的过程中试图学习在哪里放置其“注意力”。这些还不是一个正规神经网络流水线中的一部分,但是已经时不时的出现在模型中了。

2015-05-16 08:18:18 u011630458 阅读数 8402

简介

  如题,本篇是在前一篇的基础上进一步讲解的第三个图像背景分离例子。

实例介绍

  这个例子是在上一个加入鼠标操作实例的进一步操作。
  本例:可以在鼠标选框完成之后,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键,
计算背景分离并显示结果。
  运行效果:
      原图像:
      
      
      结果图像:
      
2019-10-15 16:54:17 weixin_44225182 阅读数 291

车牌识别之分离字符

前言
在进行车牌识别时(传统方法),首先是截去车牌区域,分离每个字符串,再利用模式匹配进行匹配字符,得到结果。

分离字符思路
这里利用的是车牌的蓝色特性,在图片中,只有车牌这里蓝色色域最多(作为入门算法,排除蓝色车系),所以利用RGB三通道进行处理,得到只有蓝色色域的图像,然后再二值化,利用闭运算把车牌合成一块白色区域,背景全部处理掉(以黑色显示),然后获得白色区域的位置坐标,矩形的长宽等数据,利用这些数据,对原图进行截图,任何对所截的图像进行二值化等处理,利用同样的方法,获得每个字符串的位置坐标,利用循环分别显示截取图像,并显示出来。

代码

Image = imread ('car2.jpg') ;
Image = imresize (Image, [300 450]) ; %调整图像的大小为300*450

gray = 2*Image (:, :, 3) - Image (:, :, 1) - Image (:, :, 2) ;
figure,imshow(gray),title('保留蓝色色域')

l = graythresh (gray) ; %利用Ostu法获取图像的阈值
bw = im2bw (gray, l) ; %根据Ostu法分割车牌图像
figure,imshow(bw),title('二值化后的图像')

bw1 = bwareaopen (bw, 500) ;%删除面积小于500的区域
figure,imshow (bw1) , title ('删除小面积区域后的图像') ;

se = strel ('cube', 15) ;%创建一个边长为15的正方形
bw2 = imclose (bw1, se) ;%闭运算连使整个车牌区域连接在一起
figure,imshow(bw2),title('进行闭运算后的车牌');

stats = regionprops (bw2, 'BoundingBox', 'Centroid') ; %获取车牌矩形区域, 即二值图中值为1的矩形框
bb = stats (1) .BoundingBox;%获取车牌矩形区域左上角坐标及矩形的长和宽, bb (1) 为矩形框左上角的y坐标, bb (2) 为矩形框左上角的x坐标
Img = Image (floor (bb (2) ) :floor (bb (2) +bb (4) ) ,floor (bb (1) ) :floor (bb (1) +bb (3) ) , :) ;
gray = Img (:, :, 2) ;%突出蓝色车牌的白色字体区域
figure,imshow (gray),title('切割图像 提取蓝色色域后')

l = graythresh (gray) ; %利用Ostu法获取阈值
bw3 = im2bw (gray, l) ; %转换为二值图像
figure,imshow (bw3),title('转换为二值图像')

se = strel ('line', 2, 90) ; %创建一个线条形状
bw4 = imclose (bw3, se) ;%闭运算, 连接各字符之间的缝隙
bw5 = imclearborder (bw4) ; %去除与边界相连的部分
bw6 = bwareaopen (bw5, 30) ; %删除面积小于50的区域
figure,imshow (bw6)

stats = regionprops (bw6, 'BoundingBox', 'Centroid') ; %获取各个字的矩形区域坐标
figure,imshow (Img)

for i = 1:length (stats)
bb = stats (i) .BoundingBox;
I = Img (floor (bb (2) ) :floor (bb (2) +bb (4) ) ,floor (bb (1) ) :floor (bb (1) +bb (3) ) , :) ;
str = ['第', num2str(i), '个字'];
figure,imshow (I) ;%展示每个字符
end

总结
该算法识别能力的确非常低,而且对原图像的要求很高,车辆颜色不能为蓝色、车牌必须正放在图像等要求。但是可以作为入门算法,了解车牌字符分离的简易算法。
实验图
在这里插入图片描述
结果图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2015-05-14 17:46:33 u011630458 阅读数 33116

简介

  如题,本篇就是讲解和使用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
没有更多推荐了,返回首页