本教程的創(chuàng)建旨在幫助您在Android項目中使用OpenCV庫。
本指南是用Windows 7編寫的,雖然它應該與OpenCV4Android SDK支持的任何其他操作系統(tǒng)配合使用。
本教程假設您已經(jīng)安裝并配置了以下內(nèi)容:
如果您需要上述任何方面的幫助,您可以參考我們的Android開發(fā)入門指南。
本教程還假定您的開發(fā)機器上已經(jīng)安裝了OpenCV4Android SDK,并且相應地在測試設備上安裝了OpenCV Manager。如果您需要任何幫助,可以咨詢我們的OpenCV4Android SDK教程。
如果您在徹底按照這些步驟后遇到任何錯誤,請隨時通過W3Cschool官方或OpenCV Q&A論壇與我們聯(lián)系。我們將竭盡全力幫助您。
在本節(jié)中,我們將介紹如何使一些現(xiàn)有項目使用OpenCV。從Android 2.4.2版本開始,OpenCV Manager用于為應用程序提供最佳可用版本的OpenCV。
使用異步初始化是應用程序開發(fā)的推薦方法。它使用OpenCV Manager來訪問目標系統(tǒng)中外部安裝的OpenCV庫。
1、將OpenCV庫項目添加到您的工作區(qū)。在工作區(qū)中使用菜單File - > Import - > Existing project。
按瀏覽按鈕,找到OpenCV4Android SDK(OpenCV-2.4.9-android-sdk/sdk)。
2、在項目 - >屬性 - > Android - >庫 - >添加選擇OpenCV庫 - 2.4.9中的應用程序項目中添加對OpenCV Java SDK的引用。
在大多數(shù)情況下,OpenCV Manager可能會從Google Play自動安裝。對于這種情況,當Google Play不可用時,即仿真器,開發(fā)板等,您可以使用adb工具手動安裝??碝anager Selection詳情。
有一個非常基礎的代碼片段實現(xiàn)異步初始化。它顯示基本原則。有關詳細信息,請參閱“15拼圖”O(jiān)penCV示例。
public class Sample1Java extends Activity implements CvCameraViewListener {
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
@Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_6, this, mLoaderCallback);
}
...
}
這種情況下,應用程序以OpenCV Manager異步方式運行。當初始化完成時,OnManagerConnected回調(diào)將在UI線程中調(diào)用。請注意,在調(diào)用此回調(diào)之前,不允許使用OpenCV調(diào)用或加載依賴OpenCV的本機庫。在OpenCV成功初始化之后,加載自己的依賴于OpenCV的本地庫。默認BaseLoaderCallback實現(xiàn)將應用程序上下文視為Activity,并在初始化失敗的情況下調(diào)用Activity.finish()方法退出。要覆蓋此行為,您需要覆蓋BaseLoaderCallback類的finish()方法,并實現(xiàn)您自己的finalization方法。
根據(jù)這種方法,所有OpenCV二進制文件都包含在應用程序包中。它主要用于開發(fā)目的。對于生產(chǎn)代碼,不建議使用此方法,因此推薦使用發(fā)行包,通過上述異步初始化與OpenCV Manager進行通信。
1、將OpenCV庫項目添加到工作空間中,與上述異步初始化相同。使用菜單文件 - >導入 - >工作區(qū)中的現(xiàn)有項目,按瀏覽按鈕并選擇OpenCV SDK路徑(OpenCV-2.4.9-android-sdk/sdk
)。
2、在應用程序項目中,在項目 - >屬性 - > Android - >庫 - > Add中添加OpenCV4Android SDK的參考選擇OpenCV Library - 2.4.9;
3、如果您的應用程序項目沒有JNI部分,只需將相應的OpenCV本機庫從<OpenCV-2.4.9-android-sdk>/sdk/native/libs/<target_arch>您的項目目錄復制到文件夾即可libs/<target_arch>。
在具有JNI部分的應用程序項目的情況下,而不是手動庫復制,您需要修改您的Android.mk文件:在“include $(CLEAR_VARS)”之后添加以下兩個代碼行,然后在“include path_to_OpenCV-2.4.9 -Android-SDK / SDK /本地/ JNI / OpenCV.mk”
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
結(jié)果應如下所示:
include $(CLEAR_VARS)
# OpenCV
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
include ../../sdk/native/jni/OpenCV.mk
之后,libs在JNI build.v期間,OpenCV庫將被復制到您的應用程序文件夾
Eclipse將自動將libs文件夾中的所有庫包含到應用程序包(APK)中。
4、在應用程序中啟用OpenCV的最后一步是調(diào)用OpenCV API之前的Java初始化代碼。例如,可以在Activity類的靜態(tài)部分中完成:
static {
if (!OpenCVLoader.initDebug()) {
// Handle initialization error
}
}
如果您的應用程序包含其他基于OpenCV的本機庫,則應在 OpenCV初始化后加載它們:
static {
if (!OpenCVLoader.initDebug()) {
// Handle initialization error
} else {
System.loadLibrary("my_jni_lib1");
System.loadLibrary("my_jni_lib2");
}
}
要構(gòu)建您自己的Android應用程序,使用OpenCV作為本機部分,應采取以下步驟:
include C:\Work\OpenCV4Android\OpenCV-2.4.9-android-sdk\sdk\native\jni\OpenCV.mk
應在此行后插入jni/Android.mk
文件:
include $(CLEAR_VARS)
4、OpenCV Manager 可以使用多個變量來定制OpenCV,但是當您的應用程序通過OpenCV Manager API使用異步初始化時,您無需使用它們。
OPENCV_INSTALL_MODULES:=on
將必要的OpenCV動態(tài)庫復制到項目libs文件夾中,以便將它們包含在APK中。
OPENCV_CAMERA_MODULES:=off
跳過本機OpenCV相機相關的libs復制到項目libs文件夾。
OPENCV_LIB_TYPE:=STATIC
執(zhí)行與OpenCV的靜態(tài)鏈接。默認使用動態(tài)鏈接,項目JNI lib依賴于libopencv_java.so。
5、該文件Application.mk應該存在并應包含行:
APP_STL:= gnustl_static
APP_CPPFLAGS:= -frtti -fexceptions
另外,像這樣的一行:
APP_ABI:= armeabi-v7a
應該指定應用程序目標平臺。
在某些情況下,根據(jù)OpenCV構(gòu)建應用程序JNI庫時,會發(fā)生鏈接錯誤(如“函數(shù)”cv :: toUtf16(std :: basic_string <...> ...未定義的引用“mbstowcs”)以下行Application.mk通常會修復它:
APP_PLATFORM:= android-9
6、或者使用手動的 ndk-build調(diào)用或者設置Eclipse CDT Builder來構(gòu)建本地JNI庫,然后(重新)構(gòu)建Java部分并創(chuàng)建一個APK。
以下是引導您創(chuàng)建簡單的以OpenCV為中心的應用程序的過程的基本步驟。它將能夠訪問攝像機輸出,處理和顯示結(jié)果。
< LinearLayout xmlns:android = “http://schemas.android.com/apk/res/android”
xmlns:tools = “http://schemas.android.com/tools”
xmlns:opencv = “http://schemas.android.com/apk/res-auto”
android:layout_width = “match_parent”
android:layout_height = “match_parent” >
< org.opencv.android.JavaCameraView
android:layout_width = “fill_parent”
android:layout_height = “fill_parent”
android:visibility = “gone”
android:id = “@ + id / HelloOpenCvView”
opencv:show_fps = “true”
opencv:camera_id = “any” />
</ LinearLayout >
AndroidManifest.xml
文件中:</ application >
< uses-permission android:name = “android.permission.CAMERA” />
< uses-feature android:name = “android.hardware.camera” android:required = “false” />
< uses-feature android:name = “android.hardware.camera.autofocus” android:required = “false” />
< uses-feature android:name = “android.hardware.camera.front” android:required = “false” />
< uses-feature android:name = “android.hardware.camera.front.autofocus” android:required = “false” />
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
@Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_6, this, mLoaderCallback);
}
private CameraBridgeViewBase mOpenCvCameraView;
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.HelloOpenCvLayout);
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.HelloOpenCvView);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
@Override
public void onPause()
{
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
public void onCameraViewStarted(int width, int height) {
}
public void onCameraViewStopped() {
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
return inputFrame.rgba();
}
讓我們討論一些最重要的步驟。每個使用UI的Android應用程序都必須實現(xiàn)活動和查看。通過第一步,我們創(chuàng)建空白活動和默認視圖布局。最簡單的以OpenCV為中心的應用程序必須實現(xiàn)OpenCV初始化,創(chuàng)建自己的視圖來顯示來自相機的預覽,并實現(xiàn)CvCameraViewListener2接口從相機獲取幀并處理它。
首先,我們使用xml布局創(chuàng)建我們的應用程序視圖。我們的布局由org.opencv.android.JavaCameraView類中唯一的全屏組件組成。這個類在OpenCV庫中實現(xiàn)。它繼承自CameraBridgeViewBase,它擴展了SurfaceView并使用了標準的Android相機API。
創(chuàng)建布局后,我們需要實現(xiàn)Activity類。OpenCV初始化過程已經(jīng)在上面討論過了。在本例中,我們使用異步初始化。CvCameraViewListener接口的實現(xiàn)允許您在從相機抓取并在屏幕上渲染之前添加處理步驟。最重要的功能是onCameraFrame。它是回調(diào)函數(shù),它在從攝像機檢索幀時被調(diào)用。回調(diào)輸入是表示來自相機的幀的CvCameraViewFrame類的對象。
注意
不要保存或使用CvCameraViewFrame對象從onCameraFrame回調(diào)。這個對象沒有自己的狀態(tài),它的回調(diào)行為是不可預測的!
它具有rgba()和gray()方法,可以分別獲取幀為RGBA和一個通道灰度Mat。它期望onCameraFrame函數(shù)返回將在屏幕上繪制的RGBA幀。
更多建議: