android studio mat插件安装,OpenCV On Android最佳环境配置指南(Android Studio篇)

简介

本文是《OpenCV On Android最佳环境配置指南》系列教程第二篇,也是配置教程的最后一篇。通过对Android Studio里OpenCV环境配置讲解,快速帮新人解决入门配置问题。

本文内容是本人经过多次踩坑,并参考网上众多OpenCV On Android的配置教程总结而来,尽希望能帮助学习移动图像处理的朋友们少走弯路,OpenCV On Android最佳环境配置指南(Eclipse篇)。

环境

电脑:Windows10

Java:jdk1.8.0_172

Android Studio:Version 3.6.1

SDK:Android Studio 3.6.1自带的最新SDK(请不要与Eclipse同用一SDK,以免出错)。

NDK:Android Studio 3.6.1自带的最新NDK

OpenCV:V4.2.0

注:以上配置向上兼容,读者可使用更新的版本,但低版本可能出现错误

(更新时间:2020-6-22)

配置前说明:

本次配置不像上篇介绍Eclipse配置环境那样编写多个Demo,本次将使用一个Demo,将OpenCV Java和NDK配置方式完全包含,尽可能帮助大家去理解,请大家不要跳跃式地阅读。

同时OpenCV Java库和NDK库的优缺点在上篇文章里面已经提及,本文就不再赘述。

一、安装必要组件

1、打开Android Studio。如果是欢迎界面,选择Configure->SDK Manager。如果是项目界面,选择Tools->Android->SDK Manager。

2、将选项条切换到SDK Tools,勾上左下角的Show Package Details,然后勾选以下四项,然后OK,开始下载。

1

下载完后,就可以开始创建项目了。

二、创建Android Studio工程

Create New Projec,开始选择模板,这时选择最后一项Native C++,然后进入配置界面。

2

这一步需要注意两个地方

1、包名,请尽量与我保持一致,否则新手容易出错。

2、最小SDK:OpenCV 4.2.0要求最小SDK必须大于21。

下一步直接Finish,项目创建成功!

项目创建完成后,最好运行一下,确保基本环境没问题

三、OpenCV Java库使用指南

3.1、环境配置:

第一步、将OpenCV Java库作为Module导入。具体步骤为:File->New->Import Module,然后将OpenCV-android-sdk\sdk\java目录导入,最好顺便将模块名从java改成opencv。如下图,然后Next->Finish。

3

第二步、将导入的opencv模块从application改成library,步骤如下:

4

1、将文件预览方式切换至Android。

2、打开opencv的build.gradle文件。

3、将apply plugin: 'com.android.application'修改成apply plugin: 'com.android.library'。

4、删除(或注释)掉defaultConfig内容

5、将Run/Debug Configurations从opencv切换到app

6、点击Sync Now使修改生效。

第三步、给项目添加opencv依赖

菜单File->Project Structure,在Dependencies中选择app,点击+,选择Module dependency,如下图:

5

勾选上opencv模块,点击OK即可!

3.2、代码编写:

在AndroidManifest.xml文件中添加权限:

....

android:name="android.hardware.camera"

android:required="true" />

android:name="android.hardware.camera.autofocus"

android:required="false" />

....

将activity_main.xml内容修改为以下内容:

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/javaCameraView"

android:layout_width="match_parent"

android:layout_height="match_parent"

app:camera_id="back"

app:show_fps="true" />

将MainActivity.java改为以下内容:

public class MainActivity extends CameraActivity implements CameraBridgeViewBase.CvCameraViewListener2 {

private JavaCameraView javaCameraView;

private BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(this) {

@Override

public void onManagerConnected(int status) {

switch (status) {

case LoaderCallbackInterface.SUCCESS: {

javaCameraView.enableView();

}

break;

default:

super.onManagerConnected(status);

break;

}

}

};

@Override

protected List extends CameraBridgeViewBase> getCameraViewList() {

List list = new ArrayList<>();

list.add(javaCameraView);

return list;

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

javaCameraView = findViewById(R.id.javaCameraView);

javaCameraView.setVisibility(SurfaceView.VISIBLE);

javaCameraView.setCvCameraViewListener(this);

}

@Override

public void onPause() {

super.onPause();

if (javaCameraView != null)

javaCameraView.disableView();

}

@Override

public void onResume() {

super.onResume();

if (!OpenCVLoader.initDebug()) {

OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, this, baseLoaderCallback);

} else {

baseLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);

}

}

@Override

public void onCameraViewStarted(int width, int height) {

}

@Override

public void onCameraViewStopped() {

}

@Override

public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {

return inputFrame.gray();

}

}

这里注意一下,让我们自己的Activity继承至opencv的CameraActivity,是一个十分不好的做法,请读者务必看懂CameraActivity源码,做到活学活用。

做到这一步,我们已经能够编译出一个app,但是它并不能正常运行,这是因为我们只是将opencv的api模块导入,但具体代码没包含在apk中。

我们现在可通过以下两种方式来解决这个问题:

1、在手机中安装OpenCV Manager.apk

这种方式及其不好,原因有以下几点:

1、用户需要单独安装这个apk,且不同CPU架构的手机,apk也不一样。

2、Android高版本中,即使安装了这个apk,我们的程序也可能不会正常运行。这是因为一些手机厂商,为了防止应用通过相互唤醒来实现应用保活,所以对不同应用进程间调用进行了限制。比如华为手机管家中的启动管理。

3、OpenCV高版本现已不再提供OpenCV Manager.apk

2、将libopencv_java4.so导入到apk中

这种方式的缺点就是:麻烦!!!

如果我们已经确定了目标机型,这种方式无疑是比较好的。通常来说,如果是真机,导入armeabi或armeabi-v7a架构的so文件;如果是虚拟机,则一般选择x86架构的so文件。

方法2实现步骤如下:

1、将OpenCV库中的OpenCV-android-sdk\sdk\native\libs目录下4个子目录,copy到我们项目的libs目录下。

2、修改build.gradle文件,添加以下内容:

sourceSets{

main{

jniLibs.srcDirs = ["libs"];

}

}

如图所示:

6

做完这一步,libopencv_java4.so将被自动打包进apk中,但是依旧不能正常运行,提示缺少c++_shared,这需要我们再次修改build.gradle文件,添加arguments:

android {

//......

defaultConfig {

//......

externalNativeBuild {

cmake {

cppFlags ""

arguments "-DANDROID_STL=c++_shared"

}

}

}

}

做完以上内容,基本上就OK了。

其实这里还有一个坑,由于我们从一开始就创建的是一个Native C++项目,所以通过在build.gradle文件中添加arguments参数,就能将c++_shared.so打包进apk,但是如果创建的是普通项目,此方式将无效,需要手动将c++_shared.so添加到libs对应的目录下

四、OpenCV NDK库使用指南

4.1、环境配置:

Android Studio配置OpenCV环境灰常简单(是的,没错),只需修改一个文件便能成功配置环境,什么Android.mk啊、Application.mk啊,全部滚蛋。

配置方式:打开CMakeLists.txt,内容修改如下,(将OpenCV_DIR设置为你的路径,注意分隔符,使用'/'或'\\'):

cmake_minimum_required(VERSION 3.4.1)

# ##################### OpenCV 环境 ############################

#设置OpenCV-android-sdk路径

set( OpenCV_DIR D:\\OpenCV\\OpenCV-android-sdk\\sdk\\native\\jni )

find_package(OpenCV REQUIRED )

if(OpenCV_FOUND)

include_directories(${OpenCV_INCLUDE_DIRS})

message(STATUS "OpenCV library status:")

message(STATUS " version: ${OpenCV_VERSION}")

message(STATUS " libraries: ${OpenCV_LIBS}")

message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")

else(OpenCV_FOUND)

message(FATAL_ERROR "OpenCV library not found")

endif(OpenCV_FOUND)

# ###################### 项目原生模块 ###########################

add_library( native-lib

SHARED

src/main/cpp/native-lib.cpp)

target_link_libraries( native-lib

${OpenCV_LIBS}

log

jnigraphics)

OK,环境配置好了,嘿嘿嘿,接下来开始代码编写。

4.2、代码编写:

菜单File->New->Activity->Empty Activity,创建一个新的Activity,其命名下如图,并设置为启动页,Finish。

7

为了分清楚桌面上两个程序入口,请在AndroidManifest.xml文件中给两个Activity指定label,如下图:

8

下面开始编写布局文件activity_native.xml,内容如下:

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/imageView"

android:layout_width="match_parent"

android:layout_height="match_parent" />

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

android:orientation="horizontal">

android:id="@+id/show"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_weight="1"

android:text="show" />

android:id="@+id/process"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_weight="1"

android:text="process" />

NativeActivity.java内容如下:

public class NativeActivity extends AppCompatActivity implements View.OnClickListener {

private ImageView imageView;

static {//加载so库

System.loadLibrary("native-lib");

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_native);

imageView = findViewById(R.id.imageView);

findViewById(R.id.show).setOnClickListener(this);

findViewById(R.id.process).setOnClickListener(this);

}

@Override

public void onClick(View v) {

if (v.getId() == R.id.show) {

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);

imageView.setImageBitmap(bitmap);

} else {

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);

getEdge(bitmap);

imageView.setImageBitmap(bitmap);

}

}

//获得Canny边缘

native void getEdge(Object bitmap);

}

将一张名为test.jpg的图片放置在drawable目录下,嘿嘿嘿!

9

应用层写好了,现在开始原生层操作:

第一步:生成头文件

打开Android Studio下方Terminal栏,输入cd app\src\main\java(所有应用都一样),回车。然后输入javah -encoding UTF-8 包名.类名(我们这里输入的是javah -encoding UTF-8 com.demo.opencv.NativeActivity),回车后,将在app\src\main\java目录下生成一个头文件,将该头文件移动到app\src\main\cpp目录下。

10

第二步:编写NDK代码

native-lib.cpp内容修改为:

#include "com_demo_opencv_NativeActivity.h"

#include

#include

using namespace cv;

extern "C" JNIEXPORT void

JNICALL Java_com_demo_opencv_NativeActivity_getEdge

(JNIEnv *env, jobject obj, jobject bitmap) {

AndroidBitmapInfo info;

void *pixels;

CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);

CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||

info.format == ANDROID_BITMAP_FORMAT_RGB_565);

CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);

CV_Assert(pixels);

if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {

Mat temp(info.height, info.width, CV_8UC4, pixels);

Mat gray;

cvtColor(temp, gray, COLOR_RGBA2GRAY);

Canny(gray, gray, 45, 75);

cvtColor(gray, temp, COLOR_GRAY2RGBA);

} else {

Mat temp(info.height, info.width, CV_8UC2, pixels);

Mat gray;

cvtColor(temp, gray, COLOR_RGB2GRAY);

Canny(gray, gray, 45, 75);

cvtColor(gray, temp, COLOR_GRAY2RGB);

}

AndroidBitmap_unlockPixels(env, bitmap);

}

注意,naive-lib.cpp中只有一个函数,这个函数名必须与生成的头文件中定义的一致

运行程序,点击SHOW按钮,效果如下:

11

点击PROCESS,效果如下:

12

完美,收工,回家吃饭!

五、总结

OpenCV On Android 系列配置教程就到此为止,写这两篇文章确实也不容易,修改了很多遍,尤其是这篇Android Studio,算是百忙之中抽空完成的吧,也拖了很久。自己在配置的过程中踩了无数的坑,希望我的经验能够帮助到大家少走弯路,同时也虚心接受大家的批评与指正。移动端图像处理的路还长,我也将不断去学习充实自己,这两篇文章算是了却我的一个心愿,下面是我创的学习群,我也将不定期帮助大家解决问题,请加群的人保持一个和善的心,分享经验,共同进步,记住:别人帮助你不是必须的。

OpenCV On Android学习群.png

你可能感兴趣的:(android,studio,mat插件安装)