Android Studio 3.2.1 配置 OpenCV 详解(2019年2月)

目录

OpenCV

OpenCV的下载

配置SDK manager

配置OpenCV

导入动态库

示例代码

测试效果

参考博客:


近期课题需要用Android实时处理视频,所以做了一些这方面的工作

本文示例代码地址:https://github.com/nikolajohn/OpenCVtest

推荐一个基于Android OpenCV的目标检测项目:https://github.com/nikolajohn/OpenCVForAndroid


OpenCV

OpenCV全称Open Source Computer VisoVision Library,是一个基于BSD开源协议的跨平台计算机视觉库。OpenCV实现了多种实时且高效的计算机视觉和图像处理通用算法,并且可以利用计算机底层硬件平台进行硬件加速。


OpenCV的下载

打开OpenCV主页:https://opencv.org/

并选择发行的Release版本

这里可以选择我们需要的OpenCV版本

以OpenCV 3.4.1为例

点击这里下载OpenCV 3.4.1 for Android

下载完成后,打开压缩包

我们可以先看一下,这里面都有什么

选择SDK文件夹

然后选择java

可以发现,这和我们自己新建的Android工程目录下的文件很像

待会儿会提到,这个目录将以Module的形式加载到我们自己新建的Android项目中

至此,OpenCV 3.4.1 for Android下载完成


配置SDK manager

首先打开桌面上的Android Studio

点击configure,进入配置选项

选择SDK manager

打开后,在右边选择SDK Tools

SDK Tools的页面是这样的

我们选择CMake和NDK

CMake是一个跨平台的编译工具,能够输出各种各样的makefile文件,这个在之后OpenCV编译阶段需要用到

NDK是Android平台下的一个开发工具包,使用NDK可以快速地开发C、C++的以.so为后缀的动态库,并自动将.so动态库与应用打包成.apk文件,这也是后面需要用到的

选择好后,点击Apply应用,即可开始下载

下载之前,会提醒你要下载的版本,点击确定即可

稍微等待一下,速度还是挺快的

最好翻一下墙

接下来新建Android工程

填写项目名称,记得勾选上支持C++,因为我们用到的OpenCV是用C、C++编写的

SDK版本我们选择默认即可,一般来说是API 15

接下来的默认Activity,名字可以直接用默认的MainActivity,也可以修改一下

接下来是选择C++支持相关的一些选项,记得和下图选择一样即可

至此,配置好NDK和C++支持的Android工程新建完成

 


配置OpenCV

进入刚刚新建好的工程中

选择Import Module导入模块

选一下路径,就是我们下载好OpenCV 3.4.1 for Android后提到的那个文件夹

选择确定即可

点击Finish后遇到这个报错

这是我们的项目API版本和刚导入模块的API版本不一致导致的

我们的项目API版本要求在这里打开

API版本要求如下:

刚导入的Module的API版本要求如下:

API版本要求如下:

把Module里面的API版本要求根据我们自己新建项目的API版本要求修改即可

这时候可能还会有其他的报错,但是先不用管,把下面的配置工作先做完

接下来导入模块,首先打开Project Structure

选择右边的Dependencies

选择右边的小加号,添加Module Dependency

选择OpenCVLibrary341,就是我们刚刚导入的Module

导入成功

点击运行,就没有报错了


导入动态库

笔者曾看过一些其他教程,里面需要我们先在手机上下载OpenCV Manager

然后才能运行我们自己的Android应用程序

这显然是没有必要的

OpenCV Manager是OpenCV 用于管理Android下的OpenCV动态链接库的

通过OpenCV Manager这个东西,可以实现只要在同一个设备上,都可以共享OpenCV的动态链接库

什么意思呢?

就是说我现在用Android去调用OpenCV

其实我是不能直接用java调用C++的,我的java代码只能Import其他的java包

也就是说,我的java代码只能去调刚导入的那个Module里面的包

而Module里面的java代码也是不能直接调用C++的,而是需要以动态链接库的形式,间接地调用C++

那么这些动态链接库怎么来的呢?

第一种方法比较简单,其实我们之前下载的OpenCV 3.4.1 for Android里面就已经包含了这些动态链接库

我们只需要把它放进我们的项目里面来就好了

第二种方法就是使用所谓的OpenCV Manager

我先要下载一个OpenCV Manager应用程序,这个OpenCV Manager里面是带有这些动态链接库的

然后只要我现在的手机上有这个OpenCV Manager,那么我自己写应用程序时不需要添加那些动态链接库,也可以调用之前下载好的那个应用程序里面的动态链接库了

我比较推荐第一种方法,做法如下:

选择Directory,新建一个目录,命名为jniLibs

回到我们刚刚下载的OpenCV 3.4.1 for Android

选择native

这里面有两个文件夹

libs里面放的是动态链接库,文件以.so结尾

staticlibs里面放的是静态库,文件以.a结尾

动态链接库和静态链接库的区别可以我的另一篇文章:

https://blog.csdn.net/qq_24118527/article/details/78569578

我们用的是动态链接库,因此选择libs文件夹打开

把这个目录下的所有文件复制一下

这些文件夹的名字表示不同的处理器架构

回到Android Studio

直接在刚刚新建好的目录下粘贴即可

点击运行即可

至此,动态链接库的导入完成


示例代码

一个简单的示例程序,测试我们写的代码能否调用OpenCV

JavaActivity

package cn.edu.zju.myopencv;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;

import java.io.InputStream;

public class JavaActivity extends AppCompatActivity {



    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }


    private double max_size = 1024;
    private int PICK_IMAGE_REQUEST = 1;
    private ImageView myImageView;
    private Bitmap selectbp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_java);
        staticLoadCVLibraries();
        myImageView = (ImageView)findViewById(R.id.imageView);
        myImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
        Button selectImageBtn = (Button)findViewById(R.id.select_btn);
        selectImageBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // makeText(MainActivity.this.getApplicationContext(), "start to browser image", Toast.LENGTH_SHORT).show();
                selectImage();
            }

            private void selectImage() {
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent,"选择图像..."), PICK_IMAGE_REQUEST);
            }
        });

        Button processBtn = (Button)findViewById(R.id.process_btn);
        processBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // makeText(MainActivity.this.getApplicationContext(), "hello, image process", Toast.LENGTH_SHORT).show();
                convertGray();
            }
        });

    }

    private void staticLoadCVLibraries() {
        boolean load = OpenCVLoader.initDebug();
        if(load) {
            Log.i("CV", "Open CV Libraries loaded...");
        }

    }

    private void convertGray() {
        Mat src = new Mat();
        Mat temp = new Mat();
        Mat dst = new Mat();
        Utils.bitmapToMat(selectbp, src);
        Imgproc.cvtColor(src, temp, Imgproc.COLOR_BGRA2BGR);
        Log.i("CV", "image type:" + (temp.type() == CvType.CV_8UC3));
        Imgproc.cvtColor(temp, dst, Imgproc.COLOR_BGR2GRAY);
        Utils.matToBitmap(dst, selectbp);
        myImageView.setImageBitmap(selectbp);
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
            Uri uri = data.getData();
            try {
                Log.d("image-tag", "start to decode selected image now...");
                InputStream input = getContentResolver().openInputStream(uri);
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(input, null, options);
                int raw_width = options.outWidth;
                int raw_height = options.outHeight;
                int max = Math.max(raw_width, raw_height);
                int newWidth = raw_width;
                int newHeight = raw_height;
                int inSampleSize = 1;
                if(max > max_size) {
                    newWidth = raw_width / 2;
                    newHeight = raw_height / 2;
                    while((newWidth/inSampleSize) > max_size || (newHeight/inSampleSize) > max_size) {
                        inSampleSize *=2;
                    }
                }

                options.inSampleSize = inSampleSize;
                options.inJustDecodeBounds = false;
                options.inPreferredConfig = Bitmap.Config.ARGB_8888;
                selectbp = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);

                myImageView.setImageBitmap(selectbp);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


相应的layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_java"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cn.edu.zju.myopencv.JavaActivity"
    android:orientation="vertical"
    >

    <Button
        android:id="@+id/select_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="选择图片" />

    <Button
        android:id="@+id/process_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="处理" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

这里都是些很简单的代码,主要为了测试功能

大家不用自己打了,直接去github下载即可

地址:https://github.com/nikolajohn/OpenCVtest


测试效果


参考博客:

https://blog.csdn.net/qq_36992688/article/details/79214273

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: SQLitestudio 3.2.1是一个用于管理和编辑SQLite数据库的开源工具。它是基于图形用户界面的应用程序,旨在使用户能够更轻松地操作和管理SQLite数据库。 SQLitestudio 3.2.1具有直观的用户界面,使用户可以轻松地执行各种数据库管理任务。它提供了许多功能,包括创建、编辑和删除数据库表、索引和触发器,执行SQL查询和脚本,导入和导出数据等等。 使用SQLitestudio 3.2.1,用户可以通过简单的拖放操作创建数据库表,并使用可视化界面定义表的结构和属性。用户也可以通过直接输入SQL语句来执行查询和脚本。 此外,SQLitestudio 3.2.1还支持导入和导出数据。用户可以从各种格式的数据源中导入数据到SQLite数据库,包括CSV文件、Excel文件和其他数据库。用户还可以将数据库中的数据导出到不同的文件格式,如CSV、Excel和SQL脚本。 SQLitestudio 3.2.1还提供了一个强大的SQL编辑器,用户可以在其中编写和执行SQL查询和脚本。它具有语法高亮和自动完成功能,使用户能够更轻松地编写复杂的SQL语句。 总之,SQLitestudio 3.2.1是一个功能强大且易于使用的SQLite数据库管理工具。它使用户能够更轻松地管理和操作SQLite数据库,并提供了许多便捷的功能来提高工作效率。 ### 回答2: SQLiteStudio 3.2.1是一个免费的开源数据库管理工具,用来管理SQLite数据库。它提供了一个图形界面,使得使用和管理SQLite数据库变得更加方便。 SQLiteStudio的主要功能包括创建、编辑和管理数据库对象(如表、视图和索引)、执行SQL查询、导入和导出数据等。它支持多个标签页,可以同时打开多个数据库,并在它们之间进行切换和操作。用户可以通过复制和粘贴SQL代码,或者使用可视化的工具创建和修改表结构,然后通过SQL查询来检索和操作数据。 在SQLiteStudio中,用户可以方便地浏览数据库对象的属性和内容。它提供了一个数据浏览器,可以查看表中的数据,支持排序、过滤和搜索功能。用户也可以快速通过右键菜单进行常见的操作,如添加、删除和修改数据行。 此外,SQLiteStudio还提供了一个强大的SQL编辑器,可以自动完成SQL代码,有语法高亮显示、自定义颜色方案、语法检查和代码折叠等功能,提高了编写和调试SQL语句的效率。 总之,SQLiteStudio 3.2.1是一个功能强大、易于使用的数据库管理工具,适用于SQLite数据库的管理和开发工作。它提供了丰富的功能和友好的界面,帮助用户轻松地创建、编辑和管理数据库对象,执行和调试SQL查询,使得SQLite数据库的管理变得更加高效和便捷。 ### 回答3: SQLiteStudio 3.2.1是一款免费且开源的SQLite数据库管理工具。它提供了一个直观且用户友好的图形界面,可以用于连接、创建、编辑和管理SQLite数据库。 SQLitestudio 3.2.1具有许多功能,包括表的创建和编辑、索引的管理、SQL查询的执行和调试、数据导入和导出等。它还支持自定义数据类型,可以轻松地在数据库中创建复杂的表结构。 该工具还具有强大的数据浏览和编辑功能。您可以通过简单的点击和拖放操作,直观地修改和删除表中的数据。此外,您还可以使用内置的查询编辑器编写和执行自定义SQL查询。 SQLitestudio还提供了一个功能强大的导入和导出工具,可以从各种格式的文件中导入数据,例如CSV、XML和JSON。导入时,您可以选择要导入的表以及数据映射规则。 对于开发人员来说,SQLitestudio是一个非常有用的工具,它提供了一个实用的调试器来调试自定义的SQL查询。您可以逐步跟踪SQL语句的执行过程,并在需要时检查和修改变量的值。 总之,SQLitestudio 3.2.1是一个功能丰富且易于使用的SQLite数据库管理工具。它适用于初学者和专业人士,并提供了许多有用的功能来简化SQLite数据库的管理。无论您是开发人员还是数据库管理员,都可以使用SQLitestudio轻松管理和查询SQLite数据库。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值