在Windows下執行Felzenszwalb的star-cascade DPM(Deformable Part Models)目標檢測Matlab原始碼
可變形部件模型Deformable Part Models(DPM)是非常經典的目標檢測演算法,由Felzenszwalb提出,本文介紹如何在windows下執行Felzenszwalb給出的DPM演算法的star-cascade版本voc-release4.01-star-cascade,相比於基本版本voc-release4.01,star-cascade版本增加了PCA降維,檢測速度可提高十幾倍。
有關Deformable Part Model參見論文
同樣,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跑起來,詳見這篇文章:
下載完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命令列中輸入:
- >> mex cascade.cpp model.cpp
- \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
- D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'cascade.cpp' failed.
- Error using mex (line 206)
- Unable to complete successfully.
- voc-release4.01-star-cascade\star-cascade\timer.h(21) : error C2079: 'tv' uses undefined struct 'timer::tic::timeval'
- voc-release4.01-star-cascade\star-cascade\timer.h(22) : error C3861: 'gettimeofday': identifier not found
- voc-release4.01-star-cascade\star-cascade\timer.h(23) : error C2228: left of '.tv_sec' must have class/struct/union type is 'int'
- voc-release4.01-star-cascade\star-cascade\timer.h(23) : error C2228: left of '.tv_usec' must have class/struct/union type is 'int'
- voc-release4.01-star-cascade\star-cascade\timer.h(28) : error C2079: 'tv' uses undefined struct 'timer::toc::timeval'
- voc-release4.01-star-cascade\star-cascade\timer.h(29) : error C3861: 'gettimeofday': identifier not found
- voc-release4.01-star-cascade\star-cascade\timer.h(30) : error C2228: left of '.tv_sec' must have class/struct/union type is 'int'
- voc-release4.01-star-cascade\star-cascade\timer.h(30) : error C2228: left of '.tv_usec' must have class/struct/union type is 'int'
- #ifndef _TIMER_H_
- #define _TIMER_H_
- #include <string>
- #include <sstream>
- //#include <sys/time.h> //windows下的time.h中沒有timeval定義
- #include<windows.h> //windows下代替<sys/time.h>
- #include<time.h> //windows下代替<sys/time.h>
- usingnamespace std;
- //windows下沒有gettimeofday函式,從網上找的一個替代函式
- int gettimeofday(struct timeval *tp, void *tzp)
- {
- time_t clock;
- structtmtm;
- SYSTEMTIME wtm;
- GetLocalTime(&wtm);
- tm.tm_year = wtm.wYear - 1900;
- tm.tm_mon = wtm.wMonth - 1;
- tm.tm_mday = wtm.wDay;
- tm.tm_hour = wtm.wHour;
- tm.tm_min = wtm.wMinute;
- tm.tm_sec = wtm.wSecond;
- tm. tm_isdst = -1;
- clock = mktime(&tm);
- tp->tv_sec = clock;
- tp->tv_usec = wtm.wMilliseconds * 1000;
- return (0);
- }
- class timer {
- public:
- timer(string timer_name) {
- name = timer_name;
- total_time = 0;
- calls = 0;
- };
- ~timer() {};
- void tic() {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- last_time = (double)tv.tv_sec + 1e-6*(double)tv.tv_usec;
- calls++;
- };
- void toc() {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- double cur_time = (double)tv.tv_sec + 1e-6*(double)tv.tv_usec;
- total_time += cur_time - last_time;
- };
- constchar *msg() {
- ostringstream oss;
- oss << "timer '" << name
- << "' = " << total_time << " sec in "
- << calls << " call(s)";
- return oss.str().c_str();
- };
- void mexPrintTimer() {
- mexPrintf("timer '%s' = %f sec in %d call(s)\n", name.c_str(), total_time, calls);
- };
- double getTotalTime() {
- return total_time;
- };
- private:
- string name;
- int calls;
- double last_time;
- double total_time;
- };
- #endif
- cascade.cpp(116) : error C2065: 'INFINITY' : undeclared identifier
- cascade.cpp(130) : error C2065: 'INFINITY' : undeclared identifier
- cascade.cpp(170) : error C2065: 'INFINITY' : undeclared identifier
- cascade.cpp(216) : error C2065: 'INFINITY' : undeclared identifier
- cascade.cpp(217) : error C2065: 'INFINITY' : undeclared identifier
- cascade.cpp(218) : error C2065: 'INFINITY' : undeclared identifier
- cascade.cpp(219) : error C2065: 'INFINITY' : undeclared identifier
- //INFINITY是Linux下的無窮大標誌,windows下沒有,自己定義一個
- #define INFINITY 0xFFFFFFFFF
步驟2 編譯fconv_var_dim.cpp
在matlab命令列中輸入:
- >> mex fconv_var_dim.cpp
- fconv_var_dim.cpp(2) : fatal error C1083: Cannot open include file: 'pthread.h': No such file or directory
- D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'fconv_var_dim.cpp' failed.
- Error using mex (line 206)
- Unable to complete successfully.
將pthread.h的目錄新增到環境變數,嫌麻煩的話直接把pthread.h放到VS2010安裝目錄的include資料夾中。再次編譯,提示:
- 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
- D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'fconv_var_dim.cpp' failed.
- Error using mex (line 206)
- Unable to complete successfully.
- \voc-release4.01-star-cascade\star-cascade\fconv_var_dim.cpp(77) : error C4716: 'process' : must return a value
- D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'fconv_var_dim.cpp' failed.
- Error using mex (line 206)
- Unable to complete successfully.
- fconv_var_dim.cpp(128) : error C2664: 'pthread_create' : cannot convert parameter 3 from 'void (__cdecl *)(void *)' to 'void *(__cdecl *)(void *)'
- None of the functions with this name in scope match the target type
- D:\PROGRA~1\MATLAB\R2012B\BIN\MEX.PL: Error: Compile of 'fconv_var_dim.cpp' failed.
- Error using mex (line 206)
- Unable to complete successfully.
- if (pthread_create(&ts[i], NULL, process, (void *)&td[i]))
怎麼辦呢,到這裡我也沒轍了。
翻牆去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進行改進的。所以,我們可以下載 上的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使用者快速編譯,其實裡面也就兩句話:
- mex cascade.cc model.cpp
- mex fconv_var_dim.cpp
- #ifdef MThread
- thread_exit(NULL);
- #else
- eturn NULL;
- #endif
- #ifdef MThread
- (pthread_create(&ts[i], NULL, process, (void *)&td[i]))
- mexErrMsgTxt("Error creating thread");
- #else
- process((void *)&td[i]);
- mxSetCell(plhs[0], i, td[i].mxC);
- #endif
步驟3 執行star-cascade
將matlab的工作目錄返回到voc-release4.01,先輸入命令:
- addpath star-cascade
將star-cascade加入搜尋目錄,然後呼叫cascade_demo,就可以看到檢測結果啦。