作者
郑楠
链接提供
陈榆
听项目组员说,Android上也能撸OpenCV,而且还是纯Java。还在寝室的等发霉我立马关掉了屁股开始尝试。闲话就说到这,开始正事。主要步骤还是按照官方文档来,嘛,不过也遇到了几个坑,下面会一一列出。
致谢
https://www.youtube.com/watch?v=JIHfqzTdOcQ
http://stackoverflow.com/questions/27470313/opencv-service-intent-must-be-explicit-android-5-0-lolipop#
http://opencv.org/
准备
IDE | Gradle | OpenCV SDK |
---|---|---|
Android Studio 2.1.2 | com.android.tools.build:gradle:2.1.2 | OpenCV-2.4.9-android-sdk |
配置
解压SDK包,里面的文件如下
使用 Android Studio 建立一个新项目,选择 Empty Activity 。 右键项目,按如图所示操作。
然后进入 OpenCV-2.4.9-android-sdk\sdk\native\libs 把目录复制到新建立的JNI目录中
第一个坑
注意,这里要根据你手机的CPU指令集来复制,如果一次性全都复制过去的话,运行的时候可能会在Logout中输出 Cannot load library “opencv_java”。 我的手机是 Nexus 6 CPU APQ8084AB 指令集是 ARMv7,因此仅仅将 armeabi-v7a 这个目录复制到 app\src\main\jniLibs 目录下即可
导入官方 SDK Module,按如图所示操作
这里要根据实际路径设置
导入之后可能会报SDK错误,这时候需要进入导入的 Model 中修改的 build.gradle 文件,把targetSdkVersion 修改成和你的App一样的版本。修改完的截图如下
右键 app,依次选择 Open Model Settings, Dependencies, 选择 加号, Module dependency, openCVLibrary249, OK 这样就成功导入 JavaSDK 了。
Demo
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.ubibots.opencvchess">
<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:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<activity
android:name=".MainActivity"
android:screenOrientation="landscape">
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:opencv="http://schemas.android.com/apk/res-auto"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="org.ubibots.opencvchess.MainActivity">
<org.opencv.android.JavaCameraView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:id="@+id/HelloOpenCvView"
opencv:show_fps="true"
opencv:camera_id="any"/>
</RelativeLayout>
MainActivity.java
package org.ubibots.opencvchess;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceView;
import android.view.WindowManager;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;
public class MainActivity extends Activity implements CvCameraViewListener2 {
private static final String TAG = "MainActivity";
static {
if(!OpenCVLoader.initDebug()){
Log.d(TAG, "OpenCV not loaded!");
}else {
Log.d(TAG, "OpenCV loaded!");
}
}
private CameraBridgeViewBase openCvCameraView;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
openCvCameraView = (CameraBridgeViewBase) findViewById(R.id.HelloOpenCvView);
openCvCameraView.setVisibility(SurfaceView.VISIBLE);
openCvCameraView.setCvCameraViewListener(this);
}
private BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS: {
Log.i(TAG, "OpenCV loaded successfully");
openCvCameraView.enableView();
}
break;
default: {
super.onManagerConnected(status);
}
break;
}
}
};
@Override
public void onResume() {
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_9, this, baseLoaderCallback);
}
@Override
public void onPause() {
super.onPause();
if(openCvCameraView != null){
openCvCameraView.disableView();
}
}
public void onDestroy(){
super.onDestroy();
if(openCvCameraView != null){
openCvCameraView.disableView();
}
}
public void onCameraViewStarted(int width, int height){
}
public void onCameraViewStopped(){
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame){
return inputFrame.rgba();
}
}
第二个坑
由于我的手机系统是 Android6.0 因此运行的时候会报错
java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=org.opencv.engine.BIND }
这个是由于系统 5.0 开始安卓的机制更改,需要修改 SDK Module 中 src\main\java\org\opencv\android\AsyncServiceHelper 文件 修改后如图