在Windows下运行Felzenszwalb的star-cascade DPM(Deformable Part Models)目标检测Matlab源码

文章转自:http://blog.csdn.net/masibuaa/article/details/20651005

        可变形部件模型Deformable Part Models(DPM)是非常经典的目标检测算法,由Felzenszwalb提出,本文介绍如何在windows下运行Felzenszwalb给出的DPM算法的star-cascade版本voc-release4.01-star-cascade,相比于基本版本voc-release4.01,star-cascade版本增加了PCA降维,检测速度可提高十几倍。

       有关Deformable Part Model参见论文

       A Discriminatively Trained, Multiscale,Deformable Part Model[CVPR 2008]的中文翻译

       Object Detection with Discriminatively Trained Part Based Models[PAMI 2010]的中文翻译 

       及 有关可变形部件模型(Deformable Part Model)的一些说明

       Deformable Part Model 相关网页(其中有源码下载):http://www.cs.berkeley.edu/~rbg/latent/index.html

       star-cascade版本相关网页(其中有源码下载):http://people.cs.uchicago.edu/~rbg/star-cascade/

       Pedro Felzenszwalb的个人主页:http://cs.brown.edu/~pff/

       PASCAL VOC 目标检测挑战:http://pascallin.ecs.soton.ac.uk/challenges/VOC/


同样,Felzenszwalb给出的star-cascade DPM也只能在Linux或Mac系统上运行,我们可以对其进行一些修改,使之可以在Windows的Matlab上跑起来。


 我的环境:Win7 + Matlab R2012b(其中配置VS2010中的c++编译器)


首先,在作者的网站上下载源码,由于star-cascade必须在DPM的基本版本之上运行,所以还需要下载对应的DPM源码,我这里用的都是第4版,即voc-release4.01 和 voc-release4.01-star-cascade。下载完成后首先要在Windows上把voc-release4.01跑起来,详见这篇文章:

在Windows下运行Felzenszwalb的Deformable Part Models(voc-release4.01)目标检测matlab源码


下载完voc-release4.01-star-cascade后,将star-cascade文件夹解压到voc-release4.01文件夹中(因为要在DPM之上运行)。发现其中有很多“._”开头的文件,这些是Linux或Mac系统上使用的(具体我也不是很懂),全部删掉,windows下用不到。其子文件夹data中的._开头的文件也可以删掉。

然后用notepad++或其他编辑器打开README,看看说明。README中说先进入star-cascade文件夹,编译源码,然后退回到voc-release4目录运行。在Linux下可以直接运行作者写好的Makefile文件进行编译,在windows上我们需要手动编译。打开Makefile文件,大体上看一看,发现需要编译cascade.cc,model.cc和fconv_var_dim.cc三个文件,接下来尝试用mex进行编译,看看会遇到什么错误。


步骤1 编译cascade.cpp和model.cpp

首先将cascade.cc,model.cc,fconv_var_dim.cc这三个文件的扩展名都改为.cpp,否则windows中无法识别cc文件。然后将matlab的工作目录定位到star-cascade文件夹。cascade.cpp和model.cpp需要同时编译,在matlab命令行中输入:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. >> mex cascade.cpp model.cpp  
出现错误提示:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. \voc-release4.01-star-cascade\star-cascade\timer.h(6) : fatal error C1083: Cannot open include file: 'sys/time.h': No such file or directory   
  2.   D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'cascade.cpp' failed.   
  3. Error using mex (line 206)  
  4. Unable to complete successfully.  
是说找不到timer.h中的sys/time.h头文件,网上查了查,这是linux中的文件,将“sys/”去掉,直接include time.h,因为windows中也有time.h。再次输入上面的编译命令,结果为:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. voc-release4.01-star-cascade\star-cascade\timer.h(21) : error C2079: 'tv' uses undefined struct 'timer::tic::timeval'   
  2. voc-release4.01-star-cascade\star-cascade\timer.h(22) : error C3861: 'gettimeofday': identifier not found   
  3. voc-release4.01-star-cascade\star-cascade\timer.h(23) : error C2228: left of '.tv_sec' must have class/struct/union type is 'int'   
  4. voc-release4.01-star-cascade\star-cascade\timer.h(23) : error C2228: left of '.tv_usec' must have class/struct/union type is 'int'   
  5. voc-release4.01-star-cascade\star-cascade\timer.h(28) : error C2079: 'tv' uses undefined struct 'timer::toc::timeval'   
  6. voc-release4.01-star-cascade\star-cascade\timer.h(29) : error C3861: 'gettimeofday': identifier not found   
  7. voc-release4.01-star-cascade\star-cascade\timer.h(30) : error C2228: left of '.tv_sec' must have class/struct/union type is 'int'   
  8. voc-release4.01-star-cascade\star-cascade\timer.h(30) : error C2228: left of '.tv_usec' must have class/struct/union type is 'int'   
说明windows中的time.h和linux中的不一样,没有结构体timeval的定义,也没有gettimeofday函数,网上找了一段替代linux中的 gettimeofday函数的代码,加到timer.h文件中,同时再加两个头文件,修改完的timer.h文件如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #ifndef _TIMER_H_  
  2. #define _TIMER_H_  
  3.   
  4. #include <string>  
  5. #include <sstream>  
  6. //#include <sys/time.h> //windows下的time.h中没有timeval定义  
  7. #include<windows.h> //windows下代替<sys/time.h>  
  8. #include<time.h> //windows下代替<sys/time.h>  
  9.   
  10.   
  11. using namespace std;  
  12.   
  13. //windows下没有gettimeofday函数,从网上找的一个替代函数  
  14. int gettimeofday(struct timeval *tp, void *tzp)  
  15. {  
  16.     time_t clock;  
  17.     struct tm tm;  
  18.     SYSTEMTIME wtm;  
  19.     GetLocalTime(&wtm);  
  20.     tm.tm_year     = wtm.wYear - 1900;  
  21.     tm.tm_mon     = wtm.wMonth - 1;  
  22.     tm.tm_mday     = wtm.wDay;  
  23.     tm.tm_hour     = wtm.wHour;  
  24.     tm.tm_min     = wtm.wMinute;  
  25.     tm.tm_sec     = wtm.wSecond;  
  26.     tm. tm_isdst    = -1;  
  27.     clock = mktime(&tm);  
  28.     tp->tv_sec = clock;  
  29.     tp->tv_usec = wtm.wMilliseconds * 1000;  
  30.     return (0);  
  31. }  
  32.   
  33.   
  34. class timer {  
  35. public:  
  36.   timer(string timer_name) {  
  37.     name = timer_name;  
  38.     total_time = 0;  
  39.     calls = 0;  
  40.   };  
  41.   
  42.   ~timer() {};  
  43.   
  44.   void tic() {  
  45.     struct timeval tv;  
  46.     gettimeofday(&tv, NULL);  
  47.     last_time = (double)tv.tv_sec + 1e-6*(double)tv.tv_usec;  
  48.     calls++;  
  49.   };  
  50.   
  51.   void toc() {  
  52.     struct timeval tv;  
  53.     gettimeofday(&tv, NULL);  
  54.     double cur_time = (double)tv.tv_sec + 1e-6*(double)tv.tv_usec;  
  55.     total_time += cur_time - last_time;  
  56.   };  
  57.   
  58.   const char *msg() {  
  59.     ostringstream oss;  
  60.     oss << "timer '" << name   
  61.         << "' = " << total_time << " sec in "   
  62.         << calls << " call(s)";  
  63.     return oss.str().c_str();  
  64.   };  
  65.   
  66.   void mexPrintTimer() {  
  67.     mexPrintf("timer '%s' = %f sec in %d call(s)\n", name.c_str(), total_time, calls);  
  68.   };  
  69.   
  70.   double getTotalTime() {  
  71.     return total_time;  
  72.   };  
  73.   
  74. private:  
  75.   string name;  
  76.   int calls;  
  77.   double last_time;  
  78.   double total_time;  
  79. };  
  80.   
  81. #endif  
改完timer.h后,再次编译,错误提示为:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. cascade.cpp(116) : error C2065: 'INFINITY' : undeclared identifier   
  2. cascade.cpp(130) : error C2065: 'INFINITY' : undeclared identifier   
  3. cascade.cpp(170) : error C2065: 'INFINITY' : undeclared identifier   
  4. cascade.cpp(216) : error C2065: 'INFINITY' : undeclared identifier   
  5. cascade.cpp(217) : error C2065: 'INFINITY' : undeclared identifier   
  6. cascade.cpp(218) : error C2065: 'INFINITY' : undeclared identifier   
  7. cascade.cpp(219) : error C2065: 'INFINITY' : undeclared identifier   
INFINITY是linux中的无穷大,windows下没有,可以自己定义一个,在cascade.cpp中增加下面的语句:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //INFINITY是Linux下的无穷大标志,windows下没有,自己定义一个  
  2. #define INFINITY 0xFFFFFFFFF  
然后继续mex cascade.cpp model.cpp,没有错误了。


步骤2 编译fconv_var_dim.cpp

在matlab命令行中输入:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. >> mex fconv_var_dim.cpp  
提示为:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. fconv_var_dim.cpp(2) : fatal error C1083: Cannot open include file: 'pthread.h': No such file or directory   
  2.   D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'fconv_var_dim.cpp' failed.   
  3. Error using mex (line 206)  
  4. Unable to complete successfully.  
找不到pthread.h,可以从 这个网站 下载Pthreads的win32版本,下载整个pthreads-w32-2-9-1-release压缩包,我们要用到其中两个头文件。

将pthread.h的目录添加到环境变量,嫌麻烦的话直接把pthread.h放到VS2010安装目录的include文件夹中。再次编译,提示:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\pthread.h(299) : fatal error C1083: Cannot open include file: 'sched.h': No such file or directory   
  2.   D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'fconv_var_dim.cpp' failed.   
  3. Error using mex (line 206)  
  4. Unable to complete successfully.  
sched.h就是我们需要的第二个文件,也在 pthreads-w32-2-9-1-release中,把它也复制到VS2010的include文件夹中,再次编译,提示:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. \voc-release4.01-star-cascade\star-cascade\fconv_var_dim.cpp(77) : error C4716: 'process' : must return a value   
  2.   D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'fconv_var_dim.cpp' failed.   
  3. Error using mex (line 206)  
  4. Unable to complete successfully.  
打开fconv_var_dim.cpp文件,看process函数的定义,函数类型是void *,但函数体中没有return,在 windows中运行voc-release4.01的文章 中说过,可以通过将process函数的类型改为void来解决没有返回值的错误,但这里如果还这样改的话会出现下面的错误:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. fconv_var_dim.cpp(128) : error C2664: 'pthread_create' : cannot convert parameter 3 from 'void (__cdecl *)(void *)' to 'void *(__cdecl *)(void *)'   
  2.         None of the functions with this name in scope match the target type   
  3.   D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'fconv_var_dim.cpp' failed.   
  4. Error using mex (line 206)  
  5. Unable to complete successfully.  
因为后面有个用process函数做参数的地方:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (pthread_create(&ts[i], NULL, process, (void *)&td[i]))  
改变process函数的类型会导致参数类型不匹配而无法传参。

怎么办呢,到这里我也没辙了。

翻墙去google上查,偶然发现一个大牛的个人主页,他做了star-cascade DPM算法的改进,网页上有源码下载,使用说明里有句话:

The distribution comes with precomputed mex files for 64-bit windows, linux and mac systems.也就是说他为64位的windows、linux和mac系统编译好了文件,那么他的源码会不会是win32上的呢,赶紧下载下来一看,果真,他提供了win32版本的和MacOSX版本的源码,而且也是基于voc-release4进行改进的。所以,我们可以下载 http://vision.mas.ecp.fr/Personnel/iasonas/dpms.html 上的dtbb_1.zip源码,解压后,进入star-cascade目录,可以看到几个cc文件都为64位系统mex编译好了,真是良心啊。


.mexa64是给linux-64编译好的,.mexmaci64是给Mac-64编译好的,.mexw64是为win-x64编译好的。所以,如果你是64位系统,就不用编译了,人家已经给弄好啦。我们编译完成后,会生成一个后缀为.mexw32的文件,这个文件可以看做c++和matlab之间的一个接口,可以在matlab中调用,实现matlab和c++混合编程。

再仔细看看,发现他写了个makefile_windows.m文件,方便windows用户快速编译,其实里面也就两句话:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. mex cascade.cc model.cpp  
  2. mex fconv_var_dim.cpp  
不用说,几个需要编译的cpp文件肯定也已经针对win32系统做了修改,我们可以挨个看看,cascade.cpp中,他直接将include timer.h注释掉了,所以timer.h中不兼容windows的都不用管了,更简单,加入了INFINITY的定义 #define INFINITY 1e5。再看看fconv_var_dim.cpp,也就是我不会改的地方,他是在process函数的末尾加上:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #ifdef MThread  
  2. thread_exit(NULL);  
  3. #else  
  4. eturn NULL;  
  5. #endif  
然后将用到process函数的地方改为:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #ifdef MThread  
  2.  (pthread_create(&ts[i], NULL, process, (void *)&td[i]))  
  3.         mexErrMsgTxt("Error creating thread");    
  4. #else  
  5.     process((void *)&td[i]);  
  6.     mxSetCell(plhs[0], i, td[i].mxC);  
  7. #endif  
我们直接用他的 fconv_var_dim.cpp文件替换原来的,再次mex fconv_var_dim.cpp,无错误提示,成功了。


步骤3 运行star-cascade

将matlab的工作目录返回到voc-release4.01,先输入命令:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. addpath star-cascade  

将star-cascade加入搜索目录,然后调用cascade_demo,就可以看到检测结果啦。






最后再提一下,这个网站 http://vision.mas.ecp.fr/Personnel/iasonas/dpms.html 上的DPM算法改进应该很不错,以前没接触到,以后要好好看看。最想说的是,此网站提供的源码真心不错。


猜你喜欢

转载自blog.csdn.net/kezunhai/article/details/50008347