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

简介

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

实例介绍

  这个例子是在上一个加入鼠标操作实例的进一步操作。
  本例:可以在鼠标选框完成之后,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键,
计算背景分离并显示结果。
  运行效果:
      原图像:
      Opencv wt 25 1.jpg
      
      结果图像:
      Opencv wt 25 2.jpg

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。

Android Monkey的用法 - 2015-05-27 06:05:03

Android Monkey Monkey 简介 Monkey官方文档(需要翻墙) Monkey源码 Monkey是一个命令行工具,可以运行在Android模拟器里或真实设备中。它可以向系统发送 伪随机(pseudo-random) 的用户事件流(如按键输入、触摸屏输入、手势输入等),可以对待测的目标应用或整个Android系统进行压力测试。因此Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法 基本语法: $ adb shell monkey [options] event -count
PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN。因为CSDN也支持MarkDown语法了,牛逼啊! 【工匠若水 http://blog.csdn.net/yanbober 】 背景 之所以要谈这个话题是因为你在开发App时可能会发现,Activity担负的责任非常之重,如果站在MVC框架角度看自己开发的App,一般xml布局文件科Activity的setContentView等充当了View角色,Activity其他代码充当了Controller角色,其他数据来源(数据库
Android中自定义下拉样式Spinner 本文继续介绍android自定义控件系列,自定义 Spinner 控件的 使用 。 实现思路 1.定义下拉控件布局(ListView及子控件布局) 2.自定义SpinerPopWindow类 3.定义填充数据的Adapter 效果图 一、定义控件布局 ?xml version="1.0" encoding="utf-8"?RelativeLayout xmlns:android="http://schemas.android.com/apk/res/andro
这个问题造成的原因 其实是加载ListView之后  ScrollView 的焦点异常   然后看上去被顶上去的 其实有两个方法可以解决 这个问题  一个是 scrollView .smoothScrollTo(0,20); 顾名思义  这个是让屏幕滚动到顶端的意思。  可有的时候 必须用TabHost  等页面切换Fragment的时候  这个方法找不到合适的地方加    写在生命周期里  也可能不调用  所有就有了第二种方法 在XML文件里   让listView失去焦点    只需要在父容器中加入这
变态需求 Textview只能显示10个英文字符 多的换行显示  默认android 的Textview只能这是宽度强制换行,要不就是在字符串里面有换行符"/n" 但要是给String 无换行符呢? 这里就需要自己判断的修改下   // 设置名称 String test = "abcdefg12345678" TextView textView =(TextView) findViewById(R.id.tv_test); textView.setText(toMultiLine(test, 3));  
Android项目中使用自定义进度加载Dialog 效果图一:    项目中使用的效果图二: 1.首先定义动画文件 ?xml version="1.0" encoding="utf-8"?animated-rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/loading2" android:fromDegrees="0.0" android:pivotX="50.0%"
        最近花了几天时间梳理了一下新游戏的客户端框架,虽然本身就有相对明确的方向,但是在一开始写的时候还是有些混乱,不过最终梳理完成后,个人感觉代码清爽很多。         这篇文章不是设计模式的教学,而是自己的一些想法和实践,我把代码梳理成自己喜欢的结构,保证逻辑和结构的清晰,但是这并不意味者它是符合所有人习惯的。         我之前有写过一两篇文章讨论客户端的结构,也吐槽过一些其他人的设计。可以说我在写代码之初就有一个相对明确的方向,多年的经验也可以告诉我什么样的代码是漂亮的,什么样的代
猫猫分享,必须精品 原创文章,欢迎转载。转载请注明:翟乃玉的博客 地址: http://blog.csdn.net/u013357243?viewmode=contents CALayer 在iOS中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮、一个文本标签、一个文本输入框、一个图标等等,这些都是UIView。 其实UIView之所以能显示在屏幕上,完全是因为它内部的一个图层。 在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的laye
Wire简介 轻量级的protocol buffers,针对移动设备的java库 (和protoc产生的代码相比较)由Wire生成的代码方法数量将大大减少,这将有助于android应用避免方法数65k的限制 使用方法 下载最近的wire jar包,目前最新的版本是wire-compiler-1.7.0-jar-with-dependencies.jar, github上有下载链接 编写 .proto 文件,这里直接采用 上一篇 介绍pb时用到的例子 编译 .proto 文件,用wrie生成java类, 命
     在开发过程中,我们经常需要用到NSLog输出一些信息,甚至有的开发过程,必须在控制台查看输出,有经验的程序员通过控制台输出就能知道整个数据交互的一个流程。但是一个发布的程序,里面带有太多的NSLog输出,肯定对于App性能有所影响,这时候我们可以使用一个宏定义来处理,在开发的时候使用DEBUG模式,在发布的时候使用RELEASE模式。这样,发布的App就不会在程序内部做大量的NSLog输出了。 简单的代码如下, ? 1 2 3 4 #if defined(DEBUG)||defined(_DEB