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键,
计算背景分离并显示结果。
  运行效果:
      原图像:
      
      
      结果图像:
      
2015-05-14 17:46:33 u011630458 阅读数 33114

简介

  如题,本篇就是讲解和使用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
2017-04-06 17:38:07 oHanTanYanYing 阅读数 3343

在图像处理中,常常需要通过去除图像的背景来获得图像中的人或者其他一些物体等前景对象。
传统的算法是先拍一张背景图像,然后将之后拍摄到的图像减去这张背景图像再做一些滤波处理以取得前景对象。这种方法的好处是简单,但简单之余,一旦背景发生了变化,变化的部分就会被识别为前景,以致算法失效,因此背景一有变动则需重新拍摄背景图像,非常麻烦。
混合高斯模型去除背景法则没有这个问题,其在加入的图像中不断学习,分离出前景和背景,并不断的改善背景模型,因此能比较好的对背景和前景进行分离。这套算法OpenCV已经实现了,下面贴出代码,后面如本人自行实现,会再贴出详细的分析。

#include <opencv2/opencv.hpp>    
using namespace cv;

void main()
{
    cv::Mat frame;
    cv::Mat back;
    cv::Mat fore;
    cv::Ptr<BackgroundSubtractorMOG2> bg = createBackgroundSubtractorMOG2();//第一个参数为参考历史帧数
    char path[100];
    for (int i=3;i<242;) 
    {
        sprintf_s(path, "前景调整\\%d.jpg", i++);//读入图像
        frame = imread(path,0);
        int begin = clock();
        bg->apply(frame, fore, 0.001);
        //cv::erode(fore, fore, cv::Mat());//腐蚀
        //cv::dilate(fore, fore, cv::Mat());//膨胀
        //threshold(fore, fore, 80, 250, CV_THRESH_BINARY_INV);
        printf("花费时间:%dms\n", clock() - begin);
        cv::imshow("", fore);
        waitKey(30);
    }
}
2014-11-30 20:35:04 xiayang1023 阅读数 3900

废话不多说,先上图。

原图


圆形的清晰区域


竖直的清晰区域


水平的清晰区域


嘿嘿,看上去还可以哈~~我们这里说的背景虚化呢,自然没有能力做到自动识别背景与前景的,所以只能算是一个半自动的过程:由用户来指定哪片区域是清晰的,哪片区域是模糊的,然后在清晰的区域与模糊的区域之间做一个简单的过渡。

我们在这里提供了三张模式,分别是圆形的清晰区域,竖直的清晰区域和水平的清晰区域。示意图如下所示

圆形


横向


纵向


如果你还想折腾出其他的形状,可以参考我后面的代码自己折腾一下。

这里不打算讲高斯模糊之类的东西,相信现有的博客写高斯模糊早已写烂了。我也只是借用了图像模糊里面的一个思想而已:使用周围像素的平均值来代替当前像素。高斯模糊里面对像素点周围不同位置的像素点还赋予了不同的权重,我为了简单,索性让所有的权重都一样。产生的效果也还行。

下面就把全部代码都奉上。


package algorithm.blur;

import java.awt.Color;
import java.awt.image.BufferedImage;

public class InteractiveBlur
{

	// 掩码最小值
	public static final int MIN_MASK_SIZE = 3;

	// 掩码最大值
	public static final int MAX_MASK_SIZE = 15;
	
	//掩码最大值的一半
	public static final int HALF_MAX_MASK_SIZE = 7;

	// 最小值与最大值的差
	public static final int DIFF_MASK_SIZE = MAX_MASK_SIZE - MIN_MASK_SIZE;

	// 点在模糊区域中
	public static final int AREA_BLUR = 1;

	// 点在清晰区域中
	public static final int AREA_CLEAR = 2;

	// 点在过渡区域中
	public static final int AREA_TRAN = 3;

	// 圆形的清晰区域
	public static final int TYPE_CIRCLE = 1;

	// 垂直的清晰区域
	public static final int TYPE_VERTCIAL = 2;

	// 水平的清晰区域
	public static final int TYPE_HORIZONTAL = 3;

	//外部区域以外的都是模糊的
	private static int outSize;
	
	//内部区域以内的都是清晰的
	private static int innerSize;

	//区域
	private static int area;

	
	private static Color[][] colorMatrix;




	/**
	 * 获取图像
	 * 
	 * @param image
	 *            源图像
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param size
	 *            作用范围
	 * @param type
	 *            类型
	 * */
	public static BufferedImage getImage(BufferedImage image, int x, int y, int size, int type)
	{
		InteractiveBlur.innerSize = size;
		InteractiveBlur.outSize = (int) (size * 1.5);
		// 获取rgb矩阵
		colorMatrix = getColorMatrix(image);

		switch (type)
		{
		case TYPE_VERTCIAL:
			return getVecticalImage(image, x, size);
		case TYPE_HORIZONTAL:
			return getHozizontalImage(image, y, size);
		default:
			return getCircleImage(image, x, y, size);
		}
	}

	/**
	 * 获取圆形的清晰区域
	 * 
	 * @param image
	 *            源图像
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param size
	 *            作用范围
	 * */
	private static BufferedImage getCircleImage(BufferedImage image, int centerX, int centerY, int size)
	{
		int width = image.getWidth();
		int height = image.getHeight();

		BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

		for (int y = HALF_MAX_MASK_SIZE; y < height - HALF_MAX_MASK_SIZE; y++)
		{
			for (int x = HALF_MAX_MASK_SIZE; x < width - HALF_MAX_MASK_SIZE; x++)
			{
				int distance = getDistance(x, y, centerX, centerY);
				area = getArea(distance);
				outputImage.setRGB(x, y, getRGBValue(image, x, y,distance));
			}
		}
		return outputImage;
	}

	/**
	 * 获取纵向的背景虚化图像
	 * 
	 * @param image
	 *            源图像
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param size
	 *            作用范围
	 * */
	public static BufferedImage getVecticalImage(BufferedImage image, int centerX, int size)
	{
		int width = image.getWidth();
		int height = image.getHeight();

		BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

		for (int x = HALF_MAX_MASK_SIZE; x < width - HALF_MAX_MASK_SIZE; x++)
		{
			int distance  = Math.abs(x - centerX);
			area = getArea(Math.abs(x - centerX));

			for (int y = HALF_MAX_MASK_SIZE; y < height - HALF_MAX_MASK_SIZE; y++)
			{
				outputImage.setRGB(x, y, getRGBValue(image, x, y,distance));

			}
		}
		return outputImage;
	}

	/**
	 * 获取水平的背景虚化图像
	 * 
	 * @param image
	 *            源图像
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param size
	 *            作用范围
	 * */
	public static BufferedImage getHozizontalImage(BufferedImage image, int centerY, int size)
	{
		int width = image.getWidth();
		int height = image.getHeight();
		BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

		for (int y = HALF_MAX_MASK_SIZE; y < height - HALF_MAX_MASK_SIZE; y++)
		{
			int distance = Math.abs(y - centerY);
			area = getArea(distance);
			
			for (int x = HALF_MAX_MASK_SIZE; x < width - HALF_MAX_MASK_SIZE; x++)
			{
				outputImage.setRGB(x, y, getRGBValue(image, x, y,distance));

			}
		}
		return outputImage;
	}

	
	private static int getRGBValue(BufferedImage image, int x, int y,int distance)
	{
		if (area == AREA_BLUR)
		{
			return getBlurRGBValue(x, y, MAX_MASK_SIZE);
		}
		else if (area == AREA_TRAN)
		{
			// 过渡区间
			int maskSize = MIN_MASK_SIZE + DIFF_MASK_SIZE * (distance - innerSize) / (outSize - innerSize);
			// 将masksize变为奇数
			maskSize = (maskSize / 2) * 2 + 1;

			return getBlurRGBValue(x, y, maskSize);
		}
		else
		{
			return image.getRGB(x, y);
		}
	}

	/**
	 * 获取模糊后的图像的rgb值
	 * 
	 * @param colorMatrix
	 * @param x
	 * @param y
	 * @param maskSize
	 * */
	private static int getBlurRGBValue(int x, int y, int maskSize)
	{
		int sum = maskSize * maskSize;
		int halfMaskSize = maskSize / 2;

		int sumR = 0, sumG = 0, sumB = 0;
		for (int i = -halfMaskSize; i <= halfMaskSize; i++)
		{
			for (int j = -halfMaskSize; j <= halfMaskSize; j++)
			{
				sumR += colorMatrix[x + i][y + j].getRed();
				sumG += colorMatrix[x + i][y + j].getGreen();
				sumB += colorMatrix[x + i][y + j].getBlue();
			}
		}
		sumR /= sum;
		sumG /= sum;
		sumB /= sum;

		sumR = sumR << 16;
		sumG = sumG << 8;

		return sumR|sumG|sumB;
	}

	// 判断点在那个区域
	private static int getArea(int distance)
	{
		int area;
		if (distance > outSize)
		{
			area = AREA_BLUR;
		}
		else if (distance < innerSize)
		{
			area = AREA_CLEAR;
		}
		else
		{
			area = AREA_TRAN;
		}
		return area;
	}

	/**
	 * 获取两点之间的距离
	 * 
	 * @param x1
	 *            第一个点的X坐标
	 * @param y1
	 *            第一个点的y坐标
	 * @param x2
	 *            第二个点的X坐标
	 * @param y2
	 *            第二个点的y坐标
	 * */
	private static int getDistance(int x1, int y1, int x2, int y2)
	{
		int x = x1 - x2;
		int y = y1 - y2;
		return (int) Math.sqrt(x * x + y * y);
	}
	
	
	/**
	 * 获取图像的color矩阵
	 * 
	 * @param image
	 * */
	private static Color[][] getColorMatrix(BufferedImage image)
	{
		int width = image.getWidth();
		int height = image.getHeight();
		Color[][] matrix = new Color[width][height];
		for (int y = 0; y < height; y++)
		{
			for (int x = 0; x < width; x++)
			{
				matrix[x][y]  = new Color(image.getRGB(x, y));
			}
		}
		return matrix;
	}
}


                                
2017-10-17 16:21:17 LeasonQ 阅读数 2747

背景减除法基本思想:利用当前帧图像与背景图像对应像素点的灰度差值来检测目标物体。如果当前图像的像素点和背景图像的像素点灰度值差别很大,就认为此像素点为前景像素点;相反,如果当前图像的像素点和背景图像的像素点灰度值差别较小,在一定的阈值范围内,我们就认为此像素点为背景像素点。


具体halcon代码如下:

*背景减除法

dev_clear_window()
dev_close_window()
*读取背景图像
read_image (BKImage, 'C:/Users/背景减除法/TEST/background.bmp')
get_image_size (BKImage, Width, Height)
dev_open_window_fit_image (BKImage, 0, 0, Width, Width, WindowHandle)
dev_display (BKImage)
*依次读取当前帧图像
for i := 37 to 80 by 1
    read_image(Image,'C:/Users/背景减除法/TEST/'+i+'.bmp')
    sub_image (Image,BKImage, ImageSub, 1, 128)
    *使用灰度直方图自适应选择阈值
    auto_threshold (ImageSub, Regions, 2)
    reduce_domain (ImageSub, Regions, ImageReduced)
    connection (Regions, ConnectedRegions)
    select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 1000, 99999)
    connection (SelectedRegions, ConnectedRegions1)
    dev_clear_window()
    
    region_to_bin (ConnectedRegions1, BinImage, 255, 0, Width, Height)
    dev_display (BinImage)
    dump_window_image (DImage, WindowHandle)
    
    FilePath:='C:/Users/背景减除法/前景提取图像/'+i+'.bmp'
    write_image (DImage, 'bmp', 0, FilePath)
    dev_display (BKImage)

endfor


具体运行结果如下:

1、背景图片



2、测试图片



3、结果图像




图像处理之分割图像

阅读数 20425

形态学图像处理

阅读数 431

没有更多推荐了,返回首页