上一篇教程: Android 開發入門
下一篇教程: 如何在 Android 裝置上執行深度網路
| |
| 原始作者 | Alexander Panov, Rostislav Vasilikhin |
| 相容性 | OpenCV >= 4.9.0 |
本教程旨在幫助您在 Android 專案中使用 OpenCV 庫。
本指南已在 Ubuntu 上進行檢查,但不包含任何平臺相關的部分,因此應與 Android Studio 和 OpenCV4Android SDK 支援的任何作業系統相容。
本教程假設您已安裝並配置以下各項
如果您在以上任何方面需要幫助,您可以參考我們的 Android 開發入門 指南。
如果在徹底遵循這些步驟後遇到任何錯誤,請隨時透過 OpenCV 論壇 與我們聯絡。 我們將盡最大努力幫助您。
帶有 SDK 的 Hello OpenCV 示例
在本節中,我們將建立一個簡單的應用程式,除了 OpenCV 載入之外什麼也不做。 在下一節中,我們將擴充套件它以支援相機。
除了本說明之外,您還可以使用一些影片指南,例如 這個
- 開啟 Android Studio 並透過選擇Empty Views Activity建立空專案
- 設定專案
- 選擇Java語言
- 選擇Groovy DSL構建配置語言
- 選擇最小 SDK,其版本號不低於 OpenCV 4 Android 構建期間使用的版本
- 如果您不知道它,您可以在檔案
OpenCV-android-sdk/sdk/build.gradle 中的 android -> defaultConfig -> minSdkVersion 找到它
- 單擊File -> New -> Import module...並選擇 OpenCV SDK 路徑
- 將模組名稱設定為
OpenCV 並按 Finish
OpenCV 還提供實驗性的 Kotlin 支援。 請將 Android Kotlin 外掛新增到 MyApplication/OpenCV/build.gradle 檔案
plugins {
id 'org.jetbrains.kotlin.android' version '1.7.10' #版本可能因您的設定而異
}
像這樣: 
如果您不這樣做,可能會收到錯誤
Task failed with an exception.
-----------
* Where
Build file '/home/alexander/AndroidStudioProjects/MyApplication/opencv/build.gradle' line: 4
* What went wrong
A problem occurred evaluating project ':opencv'.
> Plugin with id 'kotlin-android' not found.
解決方案可以在 這裡 找到
OpenCV 專案使用 buildConfig 功能。 請在 MyApplication/OpenCV/build.gradle 檔案中啟用它到 android 塊
buildFeatures{
buildConfig true
}
像這樣: 
如果您不這樣做,可能會收到錯誤
JavaCameraView.java:15: error: cannot find symbol import org.opencv.BuildConfig; ^ symbol: class BuildConfig location: package org.opencv
解決方案可以在 這裡 和 這裡 找到
- 將模組新增到專案
- 單擊File -> Project structure... -> Dependencies -> All modules -> + (Add Dependency button) -> Module dependency
- 在使用任何 OpenCV 函式之前,您必須首先載入庫。 如果您的應用程式包含其他依賴於 OpenCV 的本機庫,您應該在 OpenCV 初始化之後載入它們。 新增以下程式碼以在應用程式啟動時載入庫
if (OpenCVLoader.initLocal()) {
Log.i(TAG, "OpenCV 載入成功");
} else {
Log.e(TAG, "OpenCV 初始化失敗!");
(Toast.makeText(this, "OpenCV 初始化失敗!", Toast.LENGTH_LONG)).show();
return;
}
像這樣: 
- 選擇一個裝置以檢查示例,然後按
run 按鈕執行程式碼
帶有 Maven Central 的 Hello OpenCV 示例
從 OpenCV 4.9.0 開始,OpenCV for Android 包可透過 Maven Central 獲得,並且可以作為 Gradle 依賴項自動安裝。 在本節中,我們將建立一個簡單的應用程式,除了使用 Maven Central 進行 OpenCV 載入之外什麼也不做。
- 開啟 Android Studio 並透過選擇Empty Views Activity建立空專案
- 設定專案
- 選擇Java語言
- 選擇Groovy DSL構建配置語言
- 選擇最小 SDK,其版本號不低於 OpenCV 支援的版本。 對於 4.9.0,最小 SDK 版本為 21。
- 編輯
build.gradle 並將 OpenCV 庫新增到 Dependencies 列表,如下所示dependencies {
implementation 'org.opencv:opencv:4.9.0'
}
4.9.0 可以替換為任何可用的 官方版本。
- 在使用任何 OpenCV 函式之前,您必須首先載入庫。 如果您的應用程式包含其他依賴於 OpenCV 的本機庫,您應該在 OpenCV 初始化之後載入它們。 新增以下程式碼以在應用程式啟動時載入庫
if (OpenCVLoader.initLocal()) {
Log.i(TAG, "OpenCV 載入成功");
} else {
Log.e(TAG, "OpenCV 初始化失敗!");
(Toast.makeText(this, "OpenCV 初始化失敗!", Toast.LENGTH_LONG)).show();
return;
}
像這樣: 
- 選擇一個裝置以檢查示例,然後按
run 按鈕執行程式碼
相機檢視示例
在本節中,我們將擴充套件在上一節中建立的空 OpenCV 應用程式以支援相機。 我們將獲取相機幀並在螢幕上顯示它們。
- 告訴系統我們需要相機許可權。 將以下程式碼新增到檔案
MyApplication/app/src/main/AndroidManifest.xml<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"/>
像這樣: 
- 轉到
activity_main.xml 佈局並刪除帶有文字“Hello World!”的 TextView
也可以透過從 XML 檔案中刪除 TextView 塊在 Code 或 Split 模式下完成此操作。
將相機檢視新增到佈局
- 將方案新增到佈局描述中
xmlns:opencv="http://schemas.android.com/apk/res-auto"
- 將
TextView 替換為 org.opencv.android.JavaCameraView 小部件<org.opencv.android.JavaCameraView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"
android:id="@+id/tutorial1_activity_java_surface_view"
opencv:show_fps="true"
opencv:camera_id="any" />
- 如果收到佈局警告,請將
android:layout_width 和 android:layout_height 屬性的 fill_parent 值替換為 match_parent
您將獲得類似這樣的程式碼
<FrameLayout 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/tutorial1_activity_java_surface_view"
opencv:show_fps="true"
opencv:camera_id="any" />
</FrameLayout>
- 從
org.opencv.android.CameraActivity 繼承主類。 CameraActivity 實現相機許可權請求和 CV 應用程式所需的一些其他實用程式。 我們感興趣要覆蓋的方法是 onCreate, onDestroy, onPause, onResume 和 getCameraViewList
- 實現介面
org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2 onCameraFrame 方法應該返回帶有渲染內容的 Mat 物件。 該示例僅返回相機幀以進行預覽: return inputFrame.rgba();
- 分配
org.opencv.android.CameraBridgeViewBase 物件
- 應該在應用程式啟動時建立它(
onCreate 方法),並且此類應該設定為偵聽器
- 在暫停/恢復時(
onPause, onResume 方法)它應該被停用/啟用
- 應該在應用程式完成時停用它(
onDestroy 方法)
- 應該在
getCameraViewList 中返回
(可選)您可以禁止手機調暗螢幕或鎖定
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
最後,您將獲得類似於這樣的原始碼
package org.opencv.samples.tutorial1;
import org.opencv.android.CameraActivity;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.Toast;
import java.util.Collections;
import java.util.List;
public class Tutorial1Activity extends CameraActivity implements CvCameraViewListener2 {
private static final String TAG = "OCVSample::Activity";
private CameraBridgeViewBase mOpenCvCameraView;
public Tutorial1Activity() {
Log.i(TAG, "例項化新的 " + this.getClass());
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "呼叫 onCreate");
super.onCreate(savedInstanceState);
if (OpenCVLoader.initLocal()) {
Log.i(TAG, "OpenCV 載入成功");
} else {
Log.e(TAG, "OpenCV 初始化失敗!");
(Toast.makeText(this, "OpenCV 初始化失敗!", Toast.LENGTH_LONG)).show();
return;
}
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.tutorial1_surface_view);
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
@Override
public void onPause()
{
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onResume()
{
super.onResume();
if (mOpenCvCameraView != null)
mOpenCvCameraView.enableView();
}
@Override
protected List<? extends CameraBridgeViewBase> getCameraViewList() {
return Collections.singletonList(mOpenCvCameraView);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onCameraViewStarted(int width, int height) {
}
@Override
public void onCameraViewStopped() {
}
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
return inputFrame.rgba();
}
}
就是這樣! 現在您可以在裝置上執行程式碼來檢查它。
讓我們討論一些最重要的步驟
每個帶有 UI 的 Android 應用程式都必須實現 Activity 和 View。 透過第一步,我們建立空白活動和預設檢視佈局。 最簡單的以 OpenCV 為中心的應用程式必須執行 OpenCV 初始化,建立一個檢視來顯示來自相機的預覽,並實現 CvCameraViewListener2 介面以從相機獲取幀並處理它們。
首先,我們使用 XML 佈局建立應用程式檢視。 我們的佈局由類 org.opencv.android.JavaCameraView 的唯一一個全屏元件組成。 此 OpenCV 類繼承自 CameraBridgeViewBase,後者擴充套件了 SurfaceView 並在後臺使用標準 Android 相機 API。
CvCameraViewListener2 介面允許您在從相機抓取幀之後和在螢幕上渲染幀之前新增一些處理步驟。 最重要的方法是 onCameraFrame。 這是一個回撥函式,在從相機檢索幀時呼叫它。 它期望 onCameraFrame 函式返回將在螢幕上繪製的 RGBA 幀。
回撥將來自相機的幀作為 CvCameraViewFrame 類的物件傳遞給我們的類。 此物件具有 rgba() 和 gray() 方法,允許使用者獲取彩色或單通道灰度幀作為 Mat 類物件。
- 注意
- 不要在
onCameraFrame 回撥之外儲存或使用 CvCameraViewFrame 物件。 此物件沒有自己的狀態,並且在回撥之外的行為是不可預測的!