標籤:屬性 自己 htm tor 版本 ref xxx ado system
本文為作者原創,轉載請註明出處 ——負贔屭 很久以前的筆記了,分享給大家吧。。。OpenCV4Android中用於背景建模的類主要有:BackgroundSubtractor、BackgroundSubtractorMOG、BackgroundSubtractorMOG2、BackgroundSubtractorKNN,主要對使用方法做個總結。 借用OpenCV提供的API,Android編程可以實現比較豐富的視覺處理效果。經過多次嘗試,終於梳理出OpenCV背景建模在Android中的使用方法。BackgroundSubtractor的java API在OpenCV2.x和3.x版本有較大區別,3.x提供了比較豐富的API介面,取消了2.4中的高斯背景建模1(BackgroundSubtractorMOG),保留了高斯背景建模2(BackgroundSubtractorMOG2),引入了KNN背景建模(BackgroundSubtractorKNN)。同時提供了很多訪問BackgroundSubtractor背景模型的屬性方法,例如getBackgroundImage等。廢話不多說,總結如下: 一、通過Java介面實現背景建模 無論在OpenCV2.x還是3.x,BackgroundSubtractor類都必須在幀迴圈處理之前定義,例如:給OpenCV內建的Tutorial2 常式增加一個BackgroundSubtractorMOG2類的前景偵測方法。 1、定義一個BackgroundSubtractorMOG2 對象,Tutorial2 常式對於用到的mat類對象定義為private全域變數,參照給出定義:
public class Tutorial2Activity extends Activity implements CvCameraViewListener2 { …… private Mat mRgba; private Mat mIntermediateMat; private Mat mGray; private BackgroundSubtractorMOG2 mog2;
2、mog2對象初始化,Tutorial2 常式在onCameraViewStarted方法中對mat對象進行初始化,參照執行:
public void onCameraViewStarted(int width, int height) { mRgba = new Mat(height, width, CvType.CV_8UC4); mIntermediateMat = new Mat(height, width, CvType.CV_8UC4); mGray = new Mat(height, width, CvType.CV_8UC1); mog2 = new BackgroundSubtractorMOG2(); //OpenCV2.x初始化方法 //mog2 = video.createBackgroundSubtractorMOG2();//OpenCV3.x初始化方法 }
需要注意的是OpenCV2.x初始化BackgroundSubtractorMOG2對象是通過new來實現,但是在3.x版本中是通過mog2 = Video.createBackgroundSubtractorMOG2()來實現。
3、執行背景建模,直接把常式中的canny方法改成BackgroundSubtractor:
case BUTTON_GETBG: mRgba = inputFrame.rgba(); bg2.apply(inputFrame.gray(),mIntermediateMat,0.01);//前景儲存在mIntermediateMat中 //bg2.getBackgroundImage(mBG); //OpenCV3.x提供擷取背景函數
由於OpenCV2.x沒有提供getBackgroundImage方法,讓我們折騰折騰,通過jni給它實現一下: 二、通過jni實現背景建模 首先你得大致會jni,不在這裡展開講,推薦看一下http://www.cnblogs.com/linguanh/p/4624768.html,做好準備工作。 1、定義GetBGImage類繼承BackgroundSubtractorMOG2類,並定義其中的native方法:
/** * 因為OpenCV2.4中沒有提供BackgroundSubtractorMOG2類getBackgroundImage的API介面, * 所以通過FindBackground類定義擷取背景的方法,FindBackground類的初始化工作和 * BackgroundSubtractorMOG2類一致,必須在Frame迴圈之外完成,擷取背景的方法在幀迴圈體內。 */public class GetBGImage extends BackgroundSubtractorMOG2{ //繼承自BackgroundSubtractorMOG2,其構造方法繼承父類構造方法 public GetBGImage (int history, float varThreshold, boolean bShadowDetection) { super( history, varThreshold, bShadowDetection) ; return; } //FindBackground extends BackgroundSubtractorMOG2 extends BackgroundSubtractor extends Algorithm類 //algorithm類定義了long類型的nativeobj public long getNativeObjAddr() { return nativeObj; } public void FindFeature(Mat mGr, Mat mBG){ FindFeatures(nativeObj, mGr.nativeObj, mBG.nativeObj); return; } public static native void FindFeatures(long nativeObj,long mGr_nativeObj, long mBG_nativeObj);}
2、編寫Java_com_example_Myapplication_GetBGImage.cpp代碼:
#include <jni.h>#include <opencv2/core/core.hpp>#include <opencv2/core/core.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/features2d/features2d.hpp>#include <vector>#include <android/log.h>#include <sys/time.h>#include <opencv2/video/background_segm.hpp>#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "ProjectName", __VA_ARGS__)using namespace std;using namespace cv;//異常處理,可以不要static void throwJavaException(JNIEnv *env, const std::exception *e, const char *method) { std::string what = "unknown exception"; jclass je = 0; if(e) { std::string exception_type = "std::exception"; if(dynamic_cast<const cv::Exception*>(e)) { exception_type = "cv::Exception"; je = env->FindClass("org/opencv/core/CvException"); } what = exception_type + ": " + e->what(); } if(!je) je = env->FindClass("java/lang/Exception"); env->ThrowNew(je, what.c_str()); LOGE("%s caught %s", method, what.c_str()); (void)method; // avoid "unused" warning}//方法主體,一定要以extern "C"{開頭extern "C" {JNIEXPORT void JNICALL Java_com_example_Myapplication_GetBGImage_FindFeatures(JNIEnv* , jobject , jlong self, jlong addrGray, jlong addrBG);//在java native方法中傳入的參數主要有三個,分別對應self、addrGray、addrBG,其中self是自訂的GetBGImage類long類型的nativeobj,它可以作為一個指標指向你定義的GetBGImage類對象。//當對象指標通過jni傳入C++後,你可以通過GetBGImage的父類BackgroundSubtractorMOG2的指標指向這個對象,並在通過指標調用C的介面,從而實現對getBackgroundImage方法的調用。JNIEXPORT void JNICALL Java_com_example_Myapplication _GetBGImage_FindFeatures(JNIEnv* env, jobject , jlong self, jlong addrGray, jlong addrBG) { static const char method_name[] ="FindFeatures->getBackgroundImage()getFrontMaskImage()"; try{ LOGE("%s",method_name); Mat& mGr = *(Mat*)addrGray; Mat& mBG = *(Mat*)addrBG; cv::BackgroundSubtractorMOG2* me = (cv::BackgroundSubtractorMOG2*) self; me->operator()(mGr, mBG,0.001); me->getBackgroundImage(mGr); return; }catch(const std::exception &e) { throwJavaException(env, &e, method_name); } catch (...) { throwJavaException(env, 0, method_name); } return; }}
註:需要調用的C++函數需在native裡聲明,聲明的檔案名稱要與編寫的cpp檔案一致,例如Java_com_example_Myapplication_GetBGImage_FindFeatures對應的FindFeatures。 3、產生.h標頭檔和.so庫檔案 產生.h標頭檔(在as terminal中輸入命令:javah -d &location\app\src\main\jni -classpath &location\app\src\main\java com.example.Myapplication.GetBGImage),如果一切順利則不會報錯,並產生Java_com_example_Myapplication_GetBGImage.h檔案; 編寫Android.mk檔案、application.mk檔案,具體請參照Tutorial2或相關部落格,提示一句:如果需要mk多個cpp檔案(例如1.cpp,2.cpp),請在標記LOCAL_SRC_FILES :=1.cpp LOCAL_SRC_FILES := 2.cpp,當然還有更通用的寫法,可以自己尋找,這裡不再介紹。 編譯.so檔案,as terminal轉入app\src\main\jni目錄下,輸入ndk-build,如果一切順利則會提示產生了一系列.so檔案,同時你的project的main目錄下會產生libs和obj兩個目錄。這就表示編譯成功,在你的mainActivity裡載入這個.so檔案吧,載入方法: BaseLoaderCallback中載入System.loadLibrary("xxxx"); //.so檔案名稱一般為libxxxx.so 這一步很關鍵,也很容易出錯,請耐心調試,如果我的方法不適用可以多搜別人的部落格看看。 4、完成以上步驟,就可以放心使用GetBGImage的FindFeature方法了。步驟可以參考java背景建模,首先預定義GetBGImage類對象
public class Tutorial2Activity extends Activity implements CvCameraViewListener2 { …… private Mat mRgba; private Mat mIntermediateMat; private Mat mGray; private GetBGImage mog2;
在onCameraViewStarted方法中進行初始化,這裡
public void onCameraViewStarted(int width, int height) { mRgba = new Mat(height, width, CvType.CV_8UC4); mIntermediateMat = new Mat(height, width, CvType.CV_8UC1); mGray = new Mat(height, width, CvType.CV_8UC1); //GetBGImage類繼承自BackgroundSubtractorMOG2,其構造方法繼承父類構造方法 bg2 = new GetBGImage(30,16,false);
這裡的參數請參照背景建模的需求進行調試。
在onCameraFrame方法中調用FindFeature
public Mat onCameraFrame(CvCameraViewFrame inputFrame) { mGray = inputFrame.gray(); bg2.FindFeature(mGray,mIntermediateMat );
以上。
OpenCV4Android背景建模(MOG、MOG2)