Android通过NDk使用OpenCV4.1--人脸检查与模板训练

一、前言

某天,领导突然来问,可不可以在项目登录时,绑定手机的人脸开屏功能使用人脸登录。然后就搜索了很多文章,发现并没有提供相应的功能接口(也许是我搜索的姿势不对,如果有大神知道希望可以指点一下)。后来突发奇想,可不可以使用不健康样本(只是登录本人的人脸样本)训练的模型进行检测,来实现指定人员人脸检测。在此记录下学习过程。也希望能有大神之纠其不正,补其不足。

二、OpenCV4.1.0环境搭建

详细步骤见文章:https://cloud.tencent.com/developer/article/1472652

此处只是从文章中挑出关键步骤:

1、NDK搭建和OpenCV下载

  • NDK搭建:

    在Android studio中,settings->Appearance&Behavior->system settings->Android SDK->SDK Tools中,选择LLDBCMakeNDK这三个下载。

  • OpenCv下载地址:https://opencv.org/releases/ 选择Android下载

    此处是使用的是4.1.0,目前更新到4.1.1。之后的搭建方式目测通用,未实测。

2、创建项目

  • 创建Android项目时,选择Native C++

  • 此处在C++ Standard中选择的是C++11
    在这里插入图片描述

3、修改app下build.gradle文件

androidandroid->defaultConfig下添加如下配置

android {
   
    compileSdkVersion 28
    defaultConfig {
   
        ....
        externalNativeBuild {
   
            cmake {
   
                cppFlags "-std=c++11"
                //添加上的
                //APP要支持的CPU架构,此处只支持armeabi v7    
                abiFilters "armeabi-v7a"
            }
            //添加上的
            ndk {
   
                // 设置支持的SO库架构
                abiFilters 'armeabi-v7a'
            }
        }
    }
    //添加上的
    sourceSets{
   
        main{
       
            //此处设置的目录为上面下载的OpenCv-android-sdk的保存目录
            //中的so库,也就是libopencv_java4.so
            //当前这个目录下的库文件会被调用并且被打包进apk中
            jniLibs.srcDirs = ['E:/tools/OpenCV-android-sdk/sdk/native/libs']
        }
    }
    ......
}

4、修改CMakeLists.txt文件

cmake_minimum_required(VERSION 3.4.1)

#------以下为添加的内容------------
#该变量为真时会创建完整版本的Makefile
set(CMAKE_VERBOSE_MAKEFILE on)
#定义变量ocvlibs使后面的命令可以使用定位具体的库文件
set(opencvlibs "E:/tools/OpenCV-android-sdk/sdk/native/libs")
#调用头文件的具体路径
#此处和上边的路径都是OpenCv-android-sdk下载保存路径
include_directories(E:/tools/OpenCV-android-sdk/sdk/native/jni/include)
#增加我们的动态库
add_library(libopencv_java4 SHARED IMPORTED)
#建立链接
set_target_properties(libopencv_java4 PROPERTIES IMPORTED_LOCATION
        "${opencvlibs}/${ANDROID_ABI}/libopencv_java4.so")
#---------------------------------------------

add_library(native-lib SHARED native-lib.cpp)

find_library( log-lib log)
        
target_link_libraries( native-lib
        #添加这两个
        libopencv_java4
        android
        ${log-lib})

5、点击build下刷新C++工程

  • 点击build->Refresh Linked C++ Projects;

  • 查看搭建是否完成,

    在左侧项目目录中选择Android视图

    在此视图下找到app->cpp->includes->opencv2,即搭建完成即可开发。
    在这里插入图片描述

三、NDK实现人脸检测

1、对camera的封装

封装一个camera的工具类,提供切换摄像头,开始预览,停止预览和对预览换面的回调方法

public class CameraHelper implements Camera.PreviewCallback {
   

    private static final String TAG = "CameraHelper";
    //摄像头宽和高,有固定对的值
    public static final int WIDTH = 640;
    public static final int HEIGHT = 480;
    //摄像头id   区分前后摄像头的
    private int mCameraId;
    private Camera mCamera;
    //图片数组
    private byte[] buffer;
    //摄像头预览回调
    private Camera.PreviewCallback mPreviewCallback;

    public CameraHelper(int cameraId) {
   
        this.mCameraId = cameraId;
    }

    /**
     * 切换摄像头
     */
    public void switchCamera() {
   
        if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
   
            mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
        } else {
   
            mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
        }
        stopPreview();
        startPreview();
    }

    /**
     * 开始预览
     */
    public void startPreview() {
   
        try {
   
            //获取摄像头Camera实例,并打开前置摄像头
            mCamera = Camera.open(mCameraId);
            //配置Camera属性,首先获取属性列表
            Camera.Parameters parameters = mCamera.getParameters();
            Camera.Size pictureSize = parameters.getPictureSize();
            //设置预览数据格式为nv21
            parameters.setPreviewFormat(ImageFormat.NV21);
            //设置摄像头的宽和高
            parameters.setPreviewSize(WIDTH, HEIGHT);
            mCamera.setParameters(parameters);
            //初始化图片数组
            buffer = new byte[WIDTH * HEIGHT * 3 / 2];
            //添加数据缓存区并设置监听
            mCamera.addCallbackBuffer(buffer);
            mCamera.setPreviewCallbackWithBuffer(this);
            //设置预览画面
            SurfaceTexture surfaceTexture = new SurfaceTexture(11);
            //离屏渲染
            mCamera.setPreviewTexture(surfaceTexture);
            //打开预览
            mCamera.startPreview();
        } catch (IOException e) {
   
            e.printStackTrace();
        }
    }

    /**
     * 停止预览
     */
    public void stopPreview() {
   
        if (mCamera != null) {
   
            //预览回调方法值为null
            mCamera.setPreviewCallback(null);
            //停止预览
            mCamera.stopPreview();
            //释放摄像头
            mCamera.release();
            //摄像头实例置null,方便被GC回收
            mCamera = null;
        }
    }

    /**
     * 获取摄像头id
     */
    public int getCameraId() {
   
        return mCameraId;
    }
    
    /**
     * 预览画面的回调
     * @param previewCallback
     */
    public void setPreviewCallback(Camera.PreviewCallback previewCallback) {
   
        this.mPreviewCallback = previewCallback;
    }

    /**
     * 预览画面
     * @param data   预览的图片数据
     * @param camera 摄像头实例
     */
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
   
        //data数据是倒的
        mPreviewCallback.onPreviewFrame(data, camera);
        camera.addCallbackBuffer(buffer);
    }
}

2、MainActivity

  • 动态申请摄像头和读写权限
  • 在布局中只提供三个按钮,一个跳转到采集模型界面,一个挑战到检查人脸界面,一个上传人脸模型按钮
  • 在上传之前进行压缩,
@Override
protected void onCreate(Bundle savedInstanceState) {
   
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (Build.VERSION.SDK_INT >= 23) {
   
        int REQUEST_CODE_CONTACT = 101;
        String[] permissions = {
   Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
        //验证是否许可权限
        for (String str : permissions) {
   
            if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
   
                //申请权限
                this.requestPermissions(permissions, REQUEST_CODE_CONTACT);
            }
        }
    }
    //采集
    findViewById(R.id.btn_face_collect).setOnClickListener(new View.OnClickListener() {
   
        @Override
        public void onClick(View v) {
   
            Intent intent = new Intent(MainActivity.this, FaceDetectionActivity.class);
            intent.putExtra("isCollect", true);
            startActivity(intent);
        }
    });
    //检查
    findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
   
        @Override
        public void onClick(View v) {
   
            Intent intent = new Intent(MainActivity.this, FaceDetectionActivity.class);
            intent.putExtra("isCollect", false);
            startActivity(intent)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值