android studio使用jni调用opencv的人脸检测

android studio使用jni调用opencv的人脸检测

我的环境

  • Android Studio 3.1.3
  • opencv-3.4.2-android-sdk

环境配置

Android Studio安装配置(略)

下载安装opencv-3.4.2-android-sdk

  1. 官网下载 打开官网 Android - OpenCV library, avatar

打开新手教程,找到sdk的下载地址 avatar

当前最新版本是3.4.2 avatar

下载即可 avatar

  1. 下载完成后解压到指定位置

工程创建和配置

  1. 新建一个工程,勾选C++支持 avatar

2.勾选C++14支持和其他两个选项 avatar

3.等待初始化完成

4.配置NDK和CMAKE支持 打开File->Settings..., 在SDK Tools下方勾选CMAKE和NDK, Android Studio会自动下载CMAKE和NDK avatar

5.引入opencv

  • 打开File->Project Structure... 点击 Import Module avatar

  • 选择opencv安装目录的sdk/java的目录 avatar

  • 修改Compile Sdk Version 与app 一致, 打开File->Project Structure... app的版本是 API 28 avatar

opencv的版本也需要设置为 API 28 avatar

app添加opencv module avataravataravatar

  • 拷贝opencv的so文件和jni用到的头文件到工程目录

拷贝opencv安装目录下的sdk\native\jni\include文件夹到工程目录下面的app/src/main/cpp目录下

拷贝opencv安装目录下的sdk\native\libs文件夹到工程目录下面的app/src/main/jniLibs目录下

avatar

  • 修改app/build.gradle

在android节点下面添加

    sourceSets{
        main{
            jniLibs.srcDirs = ['src/main/jniLibs/libs']
        }
    }

修改androiddefaultConfigcmake/externalNativeBuild/cmake节点

    externalNativeBuild {
        cmake {
            cppFlags "-std=c++14 -frtti -fexceptions "
            arguments '-DANDROID_STL=gnustl_static'
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }
    }
  • 修改app/CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)下方插入

# 添加opencv的头文件目录
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)

# 导入opencv的so
add_library(libopencv_java3 SHARED IMPORTED)
set_target_properties(libopencv_java3 PROPERTIES IMPORTED_LOCATION
            ${CMAKE_SOURCE_DIR}/src/main/jniLibs/libs/${ANDROID_ABI}/libopencv_java3.so)

修改target_link_libraries

target_link_libraries( # Specifies the target library.
                       native-lib

                       libopencv_java3 # 链接opencv的so

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )
  • 测试是否配置成功

修改class MainActivityonCreate函数末尾添加如下代码,需要先import org.opencv.core.Mat;

    Mat mImg = new Mat();
    mImg.release();

如果app能够在手机上正常运行说明配置成功

实现人脸检测并画出人脸所在位置

拷贝默认分类器配置文件

首先得拷贝opencv安装目录下的sdk\etc\haarcascades\haarcascade_frontalface_default.xml文件到工程目录app\src\main\res\raw

native-lib.cpp

#include <jni.h>
#include <string>
#include <opencv2/opencv.hpp>

static cv::CascadeClassifier* face_detecter = nullptr;

// 初始化分类器
extern "C" JNIEXPORT void JNICALL
Java_com_xiong_dalton_cvcamerafacedetection_MainActivity_FaceDetecterInit(
        JNIEnv  *jenv,
        jobject /* this */,
        jstring cascadeFileName
){
    const char* cascade_file_name = jenv->GetStringUTFChars(cascadeFileName, NULL);
    if( face_detecter == nullptr){
        face_detecter = new cv::CascadeClassifier(cascade_file_name);
    }
}

// 找出人脸所在位置并标记出来
extern "C" JNIEXPORT void JNICALL
Java_com_xiong_dalton_cvcamerafacedetection_MainActivity_DetectFaces(
        JNIEnv  /* *env */,
        jobject /* this */,
        jlong addrInputRgbaImage
) {
    cv::Mat& image_input = *(cv::Mat*)addrInputRgbaImage;

    cv::Mat image_gray;
    cv::cvtColor(image_input, image_gray, cv::COLOR_RGBA2GRAY);

    auto width = image_input.size().width;
    auto height = image_input.size().height;
    if(face_detecter != nullptr){
        std::vector<cv::Rect> faces;
        face_detecter->detectMultiScale( image_gray, faces, 1.1, 2, 0|cv::CASCADE_SCALE_IMAGE, cv::Size(width/10, height/5));

        for(auto face_rect: faces){
            cv::rectangle(image_input, face_rect, cv::Scalar(255, 0, 0), 3);
        }
    }
}

MainActivity.java

package com.xiong.dalton.cvcamerafacedetection;

import android.app.Activity;
import android.content.Context;
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.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class MainActivity extends Activity implements CameraBridgeViewBase.CvCameraViewListener2 {
    static final String TAG = "MainActivity";

    CameraBridgeViewBase mOpenCvCameraView;
    File mCascadeFile;
    Mat mRgba;

    static {
        System.loadLibrary("native-lib");
    }


    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {

        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS: {
                    Log.i(TAG, "OpenCV loaded successfully");

                    // 使用opencv自带的分类器文件初始化
                    try{
                        InputStream is = getResources().openRawResource(R.raw.haarcascade_frontalface_default);
                        File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
                        mCascadeFile = new File(cascadeDir, "haarcascade_frontalface_default.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();

                        FaceDetecterInit(mCascadeFile.getAbsolutePath());  //调用jni的初始化接口

                        cascadeDir.delete();
                    } catch (IOException e){
                        e.printStackTrace();
                        Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
                    }

                    mOpenCvCameraView.enableView();
                }

                break;
                default: {
                    super.onManagerConnected(status);
                }
            }
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.activity_main);

        mOpenCvCameraView = findViewById(R.id.cameraView);
        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
        mOpenCvCameraView.setCvCameraViewListener(this);
        mOpenCvCameraView.enableFpsMeter();  //显示fps信息
    }

    @Override
    public void onPause() {
        super.onPause();
        disableCamera();
    }

    @Override
    public void onResume() {
        super.onResume();
        if (!OpenCVLoader.initDebug()) {
            Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
        } else {
            Log.d(TAG, "OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }
    }

    public void onDestroy() {
        super.onDestroy();
        disableCamera();
    }

    public void disableCamera() {
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    public void onCameraViewStarted(int width, int height) {

    }

    public void onCameraViewStopped() {

    }

    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
        mRgba = inputFrame.rgba();

        DetectFaces(mRgba.getNativeObjAddr());
        return mRgba;
    }

    public native long FaceDetecterInit(String cascadeFileName);
    public native long DetectFaces(long addrInputRgbaImage);
}

最终效果

avatar

转载于:https://my.oschina.net/u/111188/blog/1921187

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值