将C++源码封装为dll,并提供接口给调用

本文介绍如何将OpenCV中的混合高斯背景建模算法封装成DLL,并在另一个C++项目中调用该DLL。包括源码修改、DLL创建步骤及调用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

       本文主要记录将某个cpp函数在vs上封装为dll ,并在另一cpp中调用该dll 接口。

二、欲封装的源码

//MOG_BGS3.h
#include "opencv2/core/core.hpp"
#include <list>
#include"cv.h"
#include <iostream>
using namespace cv;

namespace OurMogBgs{

	class CV_EXPORTS_W BackgroundSubtractor : public Algorithm
	{
	public:

		virtual ~BackgroundSubtractor();
		CV_WRAP_AS(apply) virtual void operator()(InputArray image, OutputArray fgmask,
			double learningRate = 0);
		virtual void getBackgroundImage(OutputArray backgroundImage) const;
	};
	class CV_EXPORTS_W BackgroundSubtractorMOG3 : public BackgroundSubtractor
	{
	public:
		CV_WRAP BackgroundSubtractorMOG3();
		CV_WRAP BackgroundSubtractorMOG3(int history, float varThreshold, bool bShadowDetection = true);
		virtual ~BackgroundSubtractorMOG3();
		virtual void operator()(InputArray image, OutputArray fgmask, double learningRate = -1);
		virtual void getBackgroundImage(OutputArray backgroundImage) const;
		virtual void initialize(Size frameSize, int frameType);


	protected:
		Size frameSize;
		int frameType;
		Mat bgmodel;
		Mat bgmodelUsedModes;
		int nframes;
		int history;
		int nmixtures;
		double varThreshold;
		float backgroundRatio;
		float varThresholdGen;
		float fVarInit;
		float fVarMin;
		float fVarMax;
		float fCT;
		bool bShadowDetection;
		unsigned char nShadowDetection; 
			float fTau;

	};

}
相应的cpp 文件
//MOG_BGS3.cpp

#include "MOG_BGS3.h"
#include <list>


using namespace cv;

namespace OurMogBgs{
	/*
	Interface of Gaussian mixture algorithm from:

	"Improved adaptive Gausian mixture model for background subtraction"
	Z.Zivkovic
	International Conference Pattern Recognition, UK, August, 2004
	http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf

	Advantages:
	-fast - number of Gausssian components is constantly adapted per pixel.
	-performs also shadow detection (see bgfg_segm_test.cpp example)

	*/
	BackgroundSubtractor::~BackgroundSubtractor() {}
	void BackgroundSubtractor::operator()(InputArray _image, OutputArray _fgmask, double learningRate)
	{
	}
	void BackgroundSubtractor::getBackgroundImage(OutputArray backgroundImage) const
	{
	}

	// default parameters of gaussian background detection algorithm
	static const int defaultHistory3 = 500; // Learning rate; alpha = 1/defaultHistory2
	static const float defaultVarThreshold3 = 4.0f*4.0f;  //表示马氏平方距离上使用的来判断是否为背景的阈值
	static const int defaultNMixtures3 = 3; // maximal number of Gaussians in mixture
	static const float defaultBackgroundRatio3 = 0.9f; // threshold sum of weights for background test
	static const float defaultVarThresholdGen3 = 2.5f*2.5f;  //判断是否匹配的那个函数
	static const float defaultVarInit3 = 30.0f; // initial variance for new components  初始化的方差
	static const float defaultVarMax3 = 5 * defaultVarInit3;
	static const float defaultVarMin3 = 4.0f;

	// additional parameters
	static const float defaultfCT3 = 0.05f; // complexity reduction prior constant 0 - no reduction of number of components
	static const unsigned char defaultnShadowDetection3 = (unsigned char)127; // value to use in the segmentation mask for shadows, set 0 not to do shadow detection
	static const float defaultfTau = 0.5f; // Tau - shadow threshold, see the paper for explanation

	struct GaussBGStatModel3Params
	{
		//image info
		int nWidth;
		int nHeight;
		int nND;//number of data dimensions (image channels)

		bool bPostFiltering;//defult 1 - do postfiltering - will make shadow detection results also give value 255
		double  minArea; // for postfiltering

		bool bInit;//default 1, faster updates at start

		/////////////////////////
		//very important parameters - things you will change
		////////////////////////
		float fAlphaT;
		//alpha - speed of update - if the time interval you want to average over is T
		//set alpha=1/T. It is also usefull at start to make T slowly increase
		//from 1 until the desired T
		float fTb;
		//Tb - threshold on the squared Mahalan. dist. to decide if it is well described
		//by the background model or not. Related to Cthr from the paper.
		//This does not influence the update of the background. A typical value could be 4 sigma
		//and that is Tb=4*4=16;

		/////////////////////////
		//less important parameters - things you might change but be carefull
		////////////////////////
		float fTg;
		//Tg - threshold on the squared Mahalan. dist. to decide
		//when a sample is close to the existing components. If it is not close
		//to any a new component will be generated. I use 3 sigma => Tg=3*3=9.
		//Smaller Tg leads to more generated components and higher Tg might make
		//lead to small number of components but they can grow too large
		float fTB;//1-cf from the paper
		//TB - threshold when the component becomes significant enough to be included into
		//the background model. It is the TB=1-cf from the paper. So I use cf=0.1 => TB=0.
		//For alpha=0.001 it means that the mode should exist for approximately 105 frames before
		//it is considered foreground
		float fVarInit;
		float fVarMax;
		float fVarMin;
		//initial standard deviation  for the newly generated components.
		//It will will influence the speed of adaptation. A good guess should be made.
		//A simple way is to estimate the typical standard deviation from the images.
		//I used here 10 as a reasonable value
		float fCT;//CT - complexity reduction prior
		//this is related to the number of samples needed to accept that a component
		//actually exists. We use CT=0.05 of all the samples. By setting CT=0 you get
		//the standard Stauffer&Grimson algorithm (maybe not exact but very similar)

		//even less important parameters
		int nM;//max number of modes - const - 4 is usually enough

		//shadow detection parameters
		bool bShadowDetection;//default 1 - do shadow detection
		unsigned char nShadowDetection;//do shadow detection - insert this value as the detection result
		float fTau;
		// Tau - shadow threshold. The shadow is detected if the pixel is darker
		//version of the background. Tau is a threshold on how much darker the shadow can be.
		//Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow
		//See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
	};

	struct GMM
	{
		float weight;
		float variance;
	};

	// shadow detection performed per pixel
	// should work for rgb data, could be usefull for gray scale and depth data as well
	// See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
	static CV_INLINE bool
		detectShadowGMM(const float* data, int nchannels, int nmodes,
		const GMM* gmm, const float* mean,
		float Tb, float TB, float tau)
	{
			float tWeight = 0;

			// check all the components  marked as background:
			for (int mode = 0; mode < nmodes; mode++, mean += nchannels)
			{
				GMM g = gmm[mode];

				float numerator = 0.0f;
				float denominator = 0.0f;
				for (int c = 0; c < nchannels; c++)
				{
					numerator += data[c] * mean[c];
					denominator += mean[c] * mean[c];
				}

				// no division by zero allowed
				if (denominator == 0)
					return false;

				// if tau < a < 1 then also check the color distortion
				if (numerator <= denominator && numerator >= tau*denominator)
				{
					float a = numerator / denominator;
					float dist2a = 0.0f;

					for (int c = 0; c < nchannels; c++)
					{
						float dD = a*mean[c] - data[c];
						dist2a += dD*dD;
					}

					if (dist2a < Tb*g.variance*a*a)
						return true;
				};

				tWeight += g.weight;
				if (tWeight > TB)
					return false;
			};
			return false;
		}

	//update GMM - the base update function performed per pixel
	//
	//"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
	//Z.Zivkovic, F. van der Heijden
	//Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
	//
	//The algorithm similar to the standard Stauffer&Grimson algorithm with
	//additional selection of the number of the Gaussian components based on:
	//
	//"Recursive unsupervised learning of finite mixture models "
	//Z.Zivkovic, F.van der Heijden
	//IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
	//http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf

	struct MOG3Invoker : ParallelLoopBody
	{
		MOG3Invoker(const Mat& _src, Mat& _dst,
		GMM* _gmm, float* _mean,
		uchar* _modesUsed,
		int _nmixtures, float _alphaT,
		float _Tb, float _TB, float _Tg,
		float _varInit, float _varMin, float _varMax,
		float _prune, float _tau, bool _detectShadows,
		uchar _shadowVal)
		{
			src = &_src;
			dst = &_dst;
			gmm0 = _gmm;
			mean0 = _mean;
			modesUsed0 = _modesUsed;
			nmixtures = _nmixtures;
			alphaT = _alphaT;
			Tb = _Tb;
			TB = _TB;
			Tg = _Tg;
			varInit = _varInit;
			varMin = MIN(_varMin, _varMax);
			varMax = MAX(_varMin, _varMax);
			prune = _prune;
			tau = _tau;
			detectShadows = _detectShadows;
			shadowVal = _shadowVal;

			cvtfunc = src->depth() != CV_32F ? getConvertFunc(src->depth(), CV_32F) : 0;
		}

		void operator()(const Range& range) const
		{
			int y0 = range.start, y1 = range.end;
			int ncols = src->cols, nchannels = src->channels();
			AutoBuffer<float> buf(src->cols*nchannels);
			float alpha1 = 1.f - alphaT;
			float dData[CV_CN_MAX];

			for (int y = y0; y < y1; y++)
			{
				const float* data = buf;
				if (cvtfunc)
					cvtfunc(src->ptr(y), src->step, 0, 0, (uchar*)data, 0, Size(ncols*nchannels, 1), 0);
				else
					data = src->ptr<float>(y);

				float* mean = mean0 + ncols*nmixtures*nchannels*y;
				GMM* gmm = gmm0 + ncols*nmixtures*y;
				uchar* modesUsed = modesUsed0 + ncols*y;
				uchar* mask = dst->ptr(y);

				for (int x = 0; x < ncols; x++, data += nchannels, gmm += nmixtures, mean += nmixtures*nchannels)
				{
					//calculate distances to the modes (+ sort)
					//here we need to go in descending order!!!
					bool background = false;//return value -> true - the pixel classified as background

					//internal:
					bool fitsPDF = false;//if it remains zero a new GMM mode will be added
					int nmodes = modesUsed[x], nNewModes = nmodes;//current number of modes in GMM
				
					float totalWeight = 0.f;

					float* mean_m = mean;

					//////
					//go through all modes
					for (int mode = 0; mode < nmodes; mode++, mean_m += nchannels)
					{
						float weight = alpha1*gmm[mode].weight + prune;//need only weight if fit is found
						int swap_count = 0;
						////
						//fit not found yet
						if (!fitsPDF)
						{
							//check if it belongs to some of the remaining modes
							float var = gmm[mode].variance;  //高斯混合模型的方差

							//calculate difference and distance
							float dist2;

							if (nchannels == 3)
							{
								dData[0] = mean_m[0] - data[0];
								dData[1] = mean_m[1] - data[1];
								dData[2] = mean_m[2] - data[2];
								dist2 = dData[0] * dData[0] + dData[1] * dData[1] + dData[2] * dData[2];
							}
							else
							{
								dist2 = 0.f;
								for (int c = 0; c < nchannels; c++)
								{
									dData[c] = mean_m[c] - data[c];
									dist2 += dData[c] * dData[c];
								}
							}

							//background? - Tb - usually larger than Tg
							if (totalWeight < TB && dist2 < Tb*var)
								background = true;

							//check fit
							if (dist2 < Tg*var)
							{
								/////
								//belongs to the mode
								fitsPDF = true;

								//update distribution

								//update weight
								weight += alphaT;
								float k = alphaT / weight;

								//update mean
								for (int c = 0; c < nchannels; c++)
									mean_m[c] -= k*dData[c];

								//update variance
								float varnew = var + k*(dist2 - var);
								//limit the variance
								varnew = MAX(varnew, varMin);
								varnew = MIN(varnew, varMax);
								gmm[mode].variance = varnew;

								//sort
								//all other weights are at the same place and
								//only the matched (iModes) is higher -> just find the new place for it
								for (int i = mode; i > 0; i--)
								{
									//check one up
									if (weight < gmm[i - 1].weight)
										break;

									swap_count++;
									//swap one up
									std::swap(gmm[i], gmm[i - 1]);
									for (int c = 0; c < nchannels; c++)
										std::swap(mean[i*nchannels + c], mean[(i - 1)*nchannels + c]);
								}
								//belongs to the mode - bFitsPDF becomes 1
								/////
							}
						}//!bFitsPDF)

						//check prune
						if (weight < -prune)
						{
							weight = 0.0;
							nmodes--;
						}

						gmm[mode - swap_count].weight = weight;//update weight by the calculated value
						totalWeight += weight;
					}
					//go through all modes
					//////

					//renormalize weights
					totalWeight = 1.f / totalWeight;
					for (int mode = 0; mode < nmodes; mode++)
					{
						gmm[mode].weight *= totalWeight;
					}

					nmodes = nNewModes;

					//make new mode if needed and exit
					if (!fitsPDF)
					{
						// replace the weakest or add a new one
						int mode = nmodes == nmixtures ? nmixtures - 1 : nmodes++;

						if (nmodes == 1)
							gmm[mode].weight = 1.f;
						else
						{
							gmm[mode].weight = alphaT;

							// renormalize all other weights
							for (int i = 0; i < nmodes - 1; i++)
								gmm[i].weight *= alpha1;
						}

						// init
						for (int c = 0; c < nchannels; c++)
							mean[mode*nchannels + c] = data[c];

						gmm[mode].variance = varInit;

						//sort
						//find the new place for it
						for (int i = nmodes - 1; i > 0; i--)
						{
							// check one up
							if (alphaT < gmm[i - 1].weight)
								break;

							// swap one up
							std::swap(gmm[i], gmm[i - 1]);
							for (int c = 0; c < nchannels; c++)
								std::swap(mean[i*nchannels + c], mean[(i - 1)*nchannels + c]);
						}
					}

					//set the number of modes
					modesUsed[x] = uchar(nmodes);
					mask[x] = background ? 0 :
						detectShadows && detectShadowGMM(data, nchannels, nmodes, gmm, mean, Tb, TB, tau) ?
					shadowVal : 255;
				}
			}
		}

		const Mat* src;
		Mat* dst;
		GMM* gmm0;
		float* mean0;
		uchar* modesUsed0;

		int nmixtures;
		float alphaT, Tb, TB, Tg;
		float varInit, varMin, varMax, prune, tau;

		bool detectShadows;
		uchar shadowVal;

		BinaryFunc cvtfunc;
	};

	BackgroundSubtractorMOG3::BackgroundSubtractorMOG3()
	{
		frameSize = Size(0, 0);
		frameType = 0;

		nframes = 0;
		history = defaultHistory3;
		varThreshold = defaultVarThreshold3;
		bShadowDetection = 1;

		nmixtures = defaultNMixtures3;
		backgroundRatio = defaultBackgroundRatio3;
		fVarInit = defaultVarInit3;
		fVarMax = defaultVarMax3;
		fVarMin = defaultVarMin3;

		varThresholdGen = defaultVarThresholdGen3;
		fCT = defaultfCT3;
		nShadowDetection = defaultnShadowDetection3;
		fTau = defaultfTau;
	}

	BackgroundSubtractorMOG3::BackgroundSubtractorMOG3(int _history, float _varThreshold, bool _bShadowDetection)
	{
		frameSize = Size(0, 0);
		frameType = 0;

		nframes = 0;
		history = _history > 0 ? _history : defaultHistory3;
		varThreshold = (_varThreshold>0) ? _varThreshold : defaultVarThreshold3;
		bShadowDetection = _bShadowDetection;

		nmixtures = defaultNMixtures3;
		backgroundRatio = defaultBackgroundRatio3;
		fVarInit = defaultVarInit3;
		fVarMax = defaultVarMax3;
		fVarMin = defaultVarMin3;

		varThresholdGen = defaultVarThresholdGen3;
		fCT = defaultfCT3;
		nShadowDetection = defaultnShadowDetection3;
		fTau = defaultfTau;
	}

	BackgroundSubtractorMOG3::~BackgroundSubtractorMOG3()
	{
	}


	void BackgroundSubtractorMOG3::initialize(Size _frameSize, int _frameType)
	{
		frameSize = _frameSize;
		frameType = _frameType;
		nframes = 0;

		int nchannels = CV_MAT_CN(frameType);
		CV_Assert(nchannels <= CV_CN_MAX);

		// for each gaussian mixture of each pixel bg model we store ...
		// the mixture weight (w),
		// the mean (nchannels values) and
		// the covariance
		bgmodel.create(1, frameSize.height*frameSize.width*nmixtures*(2 + nchannels), CV_32F);
		//make the array for keeping track of the used modes per pixel - all zeros at start
		bgmodelUsedModes.create(frameSize, CV_8U);
		bgmodelUsedModes = Scalar::all(0);
	}

	void BackgroundSubtractorMOG3::operator()(InputArray _image, OutputArray _fgmask, double learningRate)
	{
		Mat image = _image.getMat();
		bool needToInitialize = nframes == 0 || learningRate >= 1 || image.size() != frameSize || image.type() != frameType;

		if (needToInitialize)
			initialize(image.size(), image.type());

		_fgmask.create(image.size(), CV_8U);
		Mat fgmask = _fgmask.getMat();

		++nframes;
		learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1. / min(2 * nframes, history);
		CV_Assert(learningRate >= 0);

		parallel_for_(Range(0, image.rows),
			MOG3Invoker(image, fgmask,
			(GMM*)bgmodel.data,
			(float*)(bgmodel.data + sizeof(GMM)*nmixtures*image.rows*image.cols),
			bgmodelUsedModes.data, nmixtures, (float)learningRate,
			(float)varThreshold,
			backgroundRatio, varThresholdGen,
			fVarInit, fVarMin, fVarMax, float(-learningRate*fCT), fTau,
			bShadowDetection, nShadowDetection));
	}

	void BackgroundSubtractorMOG3::getBackgroundImage(OutputArray backgroundImage) const
	{
		int nchannels = CV_MAT_CN(frameType);
		CV_Assert(nchannels == 3);
		Mat meanBackground(frameSize, CV_8UC3, Scalar::all(0));

		int firstGaussianIdx = 0;
		const GMM* gmm = (GMM*)bgmodel.data;
		const Vec3f* mean = reinterpret_cast<const Vec3f*>(gmm + frameSize.width*frameSize.height*nmixtures);
		for (int row = 0; row<meanBackground.rows; row++)
		{
			for (int col = 0; col<meanBackground.cols; col++)
			{
				int nmodes = bgmodelUsedModes.at<uchar>(row, col);
				Vec3f meanVal;
				float totalWeight = 0.f;
				for (int gaussianIdx = firstGaussianIdx; gaussianIdx < firstGaussianIdx + nmodes; gaussianIdx++)
				{
					GMM gaussian = gmm[gaussianIdx];
					meanVal += gaussian.weight * mean[gaussianIdx];
					totalWeight += gaussian.weight;

					if (totalWeight > backgroundRatio)
						break;
				}

				meanVal *= (1.f / totalWeight);
				meanBackground.at<Vec3b>(row, col) = Vec3b(meanVal);
				firstGaussianIdx += nmixtures;
			}
		}

		switch (CV_MAT_CN(frameType))
		{
		case 1:
		{
				  vector<Mat> channels;
				  split(meanBackground, channels);
				  channels[0].copyTo(backgroundImage);
				  break;
		}

		case 3:
		{
				  meanBackground.copyTo(backgroundImage);
				  break;
		}

		default:
			CV_Error(CV_StsUnsupportedFormat, "");
		}
	}
}
         所封装的函数实际为opencv中的混合高斯背景建模算法,源码中包含了opencv的core.h 、cv.h头文件等,所使用的主要类和方法如下:

BackgroundSubtractorMOG3 mog(20, 16, false);

//参数为:输入图像、输出图像、学习速率
mog(frame, foreground, 0.005); //

三、将源码封装为dll过程

         在VS2010中新建一个win32->dll工程。建立的工程名为 MogBg3Dll,接着添加上述头文件和cpp文件如下,由于使用了opencv库,故要先把opencv和vs配置好

         头文件为:

#pragma once   //新增部分
#ifdef MogBg3LibDll  
#define Mog3API _declspec(dllexport)  
#else  
#define Mog3API  _declspec(dllimport)  
#endif  

#include "opencv2/core/core.hpp"
#include <list>
#include"cv.h"
#include <iostream>
using namespace cv;

namespace OurMogBgs{

	class Mog3API CV_EXPORTS_W BackgroundSubtractor : public Algorithm //多了 Mog3API
	{
	public:

		virtual ~BackgroundSubtractor();
		CV_WRAP_AS(apply) virtual void operator()(InputArray image, OutputArray fgmask,
			double learningRate = 0);
		virtual void getBackgroundImage(OutputArray backgroundImage) const;
	};
	class Mog3API CV_EXPORTS_W BackgroundSubtractorMOG3 : public BackgroundSubtractor  //多了 Mog3API
	{
	public:
		CV_WRAP BackgroundSubtractorMOG3();
		CV_WRAP BackgroundSubtractorMOG3(int history, float varThreshold, bool bShadowDetection = true);
		virtual ~BackgroundSubtractorMOG3();
		virtual void operator()(InputArray image, OutputArray fgmask, double learningRate = -1);
		virtual void getBackgroundImage(OutputArray backgroundImage) const;
		virtual void initialize(Size frameSize, int frameType);


	protected:
		Size frameSize;
		int frameType;
		Mat bgmodel;
		Mat bgmodelUsedModes;
		int nframes;
		int history;
		int nmixtures;
		double varThreshold;
		float backgroundRatio;
		float varThresholdGen;
		float fVarInit;
		float fVarMin;
		float fVarMax;
		float fCT;
		bool bShadowDetection;
		unsigned char nShadowDetection; 
			float fTau;

	};

}

cpp 文件开头增加一行:

#define MogBg3LibDll 
        编译生成后,在debug文件夹生成相应的lib和dll 文件

    

四、调用封装的lib 和 dll

       新建一工程win32控制台项目,配置好opencv,将 MOG_BGS3.h 头文件添加到工程中,然后将lib 和 dll 文件拷贝至项目的可执行目录,并在 Properties->Linker->Input->  Additional Dependecies 中添加MogBg3Dll.lib

       可以在mian中使用了

       

#include <stdio.h>
#include <iostream>
#include <cv.h>
#include "opencv2/core/core.hpp"
#include < opencv2/highgui/highgui.hpp >
#include "MOG_BGS3.h"
using namespace cv;
using namespace std;
using namespace OurMogBgs;

int main()
{
	VideoCapture capture("F:\\研二资料\\视频资料\\UMN Dataset\\Crowd-Activity-All.avi");
	if (!capture.isOpened())
	{
		cout << "读取视频失败" << endl;
		return -1;
	}
	//获取整个帧数
	long totalframenumber = capture.get(CV_CAP_PROP_FRAME_COUNT);
	cout << "整个视频共" << totalframenumber << "帧" << endl;

	//设置开始帧()
	long frametostart = 0;
	capture.set(CV_CAP_PROP_FRAME_COUNT, frametostart);
	cout << "从第" << frametostart << "帧开始读" << endl;

	//设置结束帧
	int frametostop = totalframenumber;

	if (frametostop < frametostart)
	{
		cout << "结束帧小于开始帧,程序错误,即将退出!" << endl;
		return -1;
	}
	else
	{
		cout << "结束帧为:第" << frametostop << "帧" << endl;
	}

	double rate = capture.get(CV_CAP_PROP_FPS);
	int delay = 100 / rate;

	Mat frame;
	//前景图片
	Mat foreground;
	//背景图片
	Mat background;

	BackgroundSubtractorMOG3 mog(20, 16, false);
	bool stop(false);
	long currentframe = frametostart;
	while (!stop)
	{
		if (!capture.read(frame))
		{
			cout << "从视频中读取图像失败或者读完整个视频" << endl;
			return -2;
		}

		//从某一帧开始背景建模
		currentframe++;
		if (currentframe < 1454) continue;

		//中值滤波去噪
		//medianBlur(frame, frame,3);

		imshow("输入视频", frame);
		//参数为:输入图像、输出图像、学习速率
		mog(frame, foreground, 0.005); //

		mog.getBackgroundImage(background);   // 返回当前背景图像   


		imshow("前景", foreground);
		imshow("背景", background);

		//按esc键退出,按其他键会停止在当前帧

		int c = waitKey(delay);

		if ((char)c == 27 || currentframe >= frametostop)
		{
			stop = true;
		}
		if (c >= 0)
		{
			waitKey(0);
		}

		if (currentframe == 3004)
		{
			//imwrite("3004.png", foreground);
		}

		//cout << "\ncurrentframe:" << currentframe;

	}

	waitKey(0);
}

运行结果:

        


五、参考资料

多个类封装为dll :http://blog.youkuaiyun.com/GarfieldEr007/article/details/50499178






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值