opencv移植到Android端

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27063119/article/details/79924750
opencv移植到Android端


一. 说明

    前次的博客说了怎样使用opencv训练识别一些指定的物体,既然有了自己的模型,那么我们是否可以将这个模型用于手机端,结合app进行一些更方便的检测任务呢,回答是肯定的,本篇博客主要记录一下用于物体检测的opencv怎样移植到安卓移动端进行使用的。

二. 准备工作

1. 需要的环境

Android studio(这里使用了2.3.3版本)

opencv-3.4.0-android-sdk

地址:https://jaist.dl.sourceforge.net/project/opencvlibrary/opencv-android/3.4.0/opencv-3.4.0-android-sdk.zip

三. 开始集成

1. 下载opencv-3.4.0-android-sdk并解压缩

2. 新建安卓项目,在项目的根目录新建libraries文件夹,复制 Android SDK 中目录 sdk 下的 java 文件夹到刚刚创建的 libraries 目录中,并将拷贝进去的java文件夹名称修改为 opencv

3. 在重命名的 opencv 文件夹下创建一个 build.gradle 文件,

内容如下图所示:

apply plugin: 'android-library'

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
    }
}

android {
    compileSdkVersion 25
    buildToolsVersion "27.0.3"

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            res.srcDirs = ['res']
            aidl.srcDirs = ['src']
        }
    }
}

 注: minSdkVersion , targetSdkVersion , versionCode , versionName 等可依实际情况而定


4. 编辑安卓项目中的settings.gradle 文件,添加一行代码:include ':libraries:opencv',然后点击右上方的Sync Now进行同步

5. 右键工程, Open Module Settings , 左边选中应用的module名称,右边点击 Dependencies 选项,再点击 + 按钮,添加依赖。选择 Module dependency, 会出现一个含有多个module的列表,选择 :libraries:opencv。





6.   /app/src/main/ 下创建一个 jniLibs 文件夹在,将OpenCV Android SDK 中 sdk/native/libs 下的所有文件夹复制到创建的 jniLibs 目录下,点击右上方的Sync Now进行同步。

至此完成了opencv的基本环境配置。


四. 测试使用

1. 在安卓项目的res文件夹下新建raw文件夹,将我们之前训练好的舌头模型tongue.xml(制作教程链接:https://blog.csdn.net/qq_27063119/article/details/79247266), (如果没有训练,可以使用gopencv自带的人脸模型OpenCV-android-sdk\sdk\etc\haarcascades\haarcascade_frontalface_alt2.xml)

2. 在Activity里面添加初始化opencv的函数

private void initializeOpenCVDependencies() {
        try {
            InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
            File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
//            File mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
//            File mCascadeFile = new File(cascadeDir, "haarcascade_frontalface_alt2.xml");
            File mCascadeFile = new File(cascadeDir, "tongue.xml");
            FileOutputStream os = new FileOutputStream(mCascadeFile);

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            is.close();
            os.close();

            // Load the cascade classifier
            cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());

            if (cascadeClassifier.empty()) {
                Log.e("initializeOpenCVDependencies : ", "Failed to load cascade classifier");
                cascadeDir = null;
            } else{
                Log.i("initializeOpenCVDependencies : ", "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());
            }

        } catch (Exception e) {
            Log.e("OpenCVActivity", "Error loading cascade", e);
        }
//        openCvCameraView.enableView();
    }

使用静态方法进行加载:

/**
     * 此方式配置的opencv必须要静态方式加载
     */
    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                    initializeOpenCVDependencies();
                    break;
                default:
                    super.onManagerConnected(status);
                    break;
            }
        }
    };


接下来就可以对拍照后的图片:Bitmap类型进行 物体检测了:

检测所用的工具类:FaceRtspUtil,添加检测的方法:detectFrame2()

/**
 * 人脸检测工具
 */
public class FaceRtspUtil {

    private static final String TAG = "FaceUtil";
    private Mat grayscaleImage;
    private CascadeClassifier cascadeClassifier = null;

    public FaceRtspUtil(CascadeClassifier cascadeClassifier, int width, int height) {
        this.cascadeClassifier = cascadeClassifier;
        //人脸的宽高最小也要是原图的height的 10%
        grayscaleImage = new Mat(height, width, CvType.CV_8UC4);
    }


    /**
     * 测试有没有人脸
     * @param oldBitmap
     * @return
     */
    public boolean detectFrame2(Bitmap oldBitmap) {
        Mat aInputFrame = new Mat();
        if (oldBitmap == null) {
            return false;
        }
        Utils.bitmapToMat(oldBitmap, aInputFrame);
        if (grayscaleImage == null) {
            Log.i(TAG, "detectFrame: aInputFrame == null || grayscaleImage == null");
            return false;
        }
        Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);

        MatOfRect faces = new MatOfRect();

        // 使用级联分类器 检测物体
        if (cascadeClassifier != null) {
            //不获取60*60以下的物体
            cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2 , new Size(60, 60), new Size());
        }
        //facesArray里保存所有检测到的人脸的位置及大小
        Rect[] facesArray = faces.toArray();
        if (facesArray == null || facesArray.length == 0) {
            //如果没有人脸,直接退出
            Log.i(TAG, "detectFrame: 该图片中没有人脸");
            return false;
        }else{
            Log.i(TAG, "detectFrame: OK ! 检测到人脸");
            return true;
        }
    }

}

最后就是提供一下调用了,拍照后调用方式:

//调用opencv检测物体
        FaceRtspUtil mFaceUtil = new FaceRtspUtil(cascadeClassifier, PIC_WIDTH, PIC_HEIGHT);
        //对保存在本地的图片进行人脸检测,并获取截到的所有人脸
        boolean hasSubstance =  mFaceUtil.detectFrame2(rightBitmap);

如果想自动进行检测到人脸(物体) 自动拍照,可以使用线程进行间断性抓拍,然后将图片递交给opencv检测,如果是检测正确的话就进行存储。


这里放一下android的效果图:

    


android 源码下载地址,8个积分(由于集成opencv后项目太大1.2G, 因此不包含opencv集成的文件,自行去文中给的官方链接下载即可) : 

https://download.csdn.net/download/qq_27063119/10346007




猜你喜欢

转载自blog.csdn.net/qq_27063119/article/details/79924750