将C++源码封装为dll,并提供接口给调用
2017-12-30 12:00
435 查看
一、前言
本文主要记录将某个cpp函数在vs上封装为dll ,并在另一cpp中调用该dll 接口。
二、欲封装的源码
三、将源码封装为dll过程
在VS2010中新建一个win32->dll工程。建立的工程名为 MogBg3Dll,接着添加上述头文件和cpp文件如下,由于使用了opencv库,故要先把opencv和vs配置好
头文件为:
cpp 文件开头增加一行:
四、调用封装的lib 和 dll
新建一工程win32控制台项目,配置好opencv,将 MOG_BGS3.h 头文件添加到工程中,然后将lib 和 dll 文件拷贝至项目的可执行目录,并在 Properties->Linker->Input-> Additional Dependecies 中添加MogBg3Dll.lib
可以在mian中使用了
五、参考资料
多个类封装为dll :http://blog.csdn.net/GarfieldEr007/article/details/50499178
本文主要记录将某个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.csdn.net/GarfieldEr007/article/details/50499178
相关文章推荐
- 转载_Linux C调用C++库(用C封装C++接口)
- C#调用C++Dll封装时遇到的一系列问题
- 将c++封装成dll库及vs调用dll
- Linux C调用C++库(用C封装C++接口)
- C#调用C++Dll封装时遇到的一系列问题
- C# 如何调用 C++ DLL中的函数接口和回调函数
- C# 调用C++dll中接口,返回const char*
- 【C++】多个类的DLL封装及调用
- C++在windows下直接调用dll文件中的函数--封装
- C# wpf 封装成dll供C++调用
- C++调用C#接口dll,对dll进行注册
- C# 发中调用一个采用C++封装好的dll, 其结构体中的二维数转换
- C#调用C++封装的DLL调试方法小结
- C#调用C++Dll封装时遇到的一系列问题
- 【C++】多个类的DLL封装及调用
- Linux C调用C++库(用C封装C++接口)
- 【C++】多个类的DLL封装及调用
- java调用c++封装的dll
- PY++ 自动将你的C++程序接口封装供python调用
- 关于C++调用C#封装的dll后,获取C#中string返回值的问题