• Android—基于OpenCV+Android实现人脸检测


    导读

    OpenCV 是一个开源的跨平台计算机视觉库, 采C++语言编写,实现了图像处理和计算机视觉方面的很多通用算法,同时也提供对Python,Java,Android等的支持,这里利用Android下的接口,实现一个简单的人脸检测;

    首先需要说清楚这里是人脸检测,不是人脸识别,网上很多资料说实现人脸识别,最后一看明明是人脸检测。
    人脸检测:是找出人脸,并标记出人脸。
    人脸识别:检测出人脸,并能够通过学习,给出人脸信息,比如,给定一个人脸A,通过学习,在之后的众多检测中能够找出人脸A,这才是人脸识别;

    准备工作

    首先到http://opencv.org/releases.html下载相应的开发工具,我下载时latest version是3.4.1,选择Android pack。开发包比较大,我下载时已经300多M。下载后解压缩,得到如下目录结构;

    新建AS项目,OpenCVDemo,然后File > New > New Module,选择Import Eclipse ADT Project;
    把下载下来的目录下sdk/java 下的项目导入到项目里。此时生产的Module名称为openCVLibrary2411,版本不同这里名字会不同,后面添加依赖时,需要注意!

    然后将刚新建的这个modules 添加依赖到 app modules里,
    直接在 app 目录下build.gradle 文件里dependencies 下添加:

    compile project(':openCVLibrary2411')
    

    然后在 app/src/main 目录下创建一个jniLibs 目录,然后把sdk/native/libs 下全部文件 copy到jniLibs下,编译通过。

    修改新建模块下 build.gradle 文件,把 compileSdkVersion 与 targetSdkVersion修改成你最新的SDK版本,如我的:

    apply plugin: 'com.android.library'
    
    android {
        compileSdkVersion 27
        buildToolsVersion "26.0.2"
    
        defaultConfig {
            minSdkVersion 21
            targetSdkVersion 27
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            }
        }
    }
    

    我app下的build.gradle文件如下:

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 27
        defaultConfig {
            applicationId "com.jiajia.opencvdemo"
            minSdkVersion 21
            targetSdkVersion 27
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:27.1.1'
        implementation 'com.android.support.constraint:constraint-layout:1.1.0'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    
        implementation project(':openCVLibrary2411')
    }
    

    OK, 上面就是所有的准备工作;

    实现人脸检测

    只需要有一个MainActivity即可,首先申请相应的权限

        <uses-permission android:name="android.permission.CAMERA"/>
        <uses-feature android:name="android.hardware.camera" android:required="false"/>
        <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
        <uses-feature android:name="android.hardware.camera.front" android:required="false"/>
        <uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>
    

    如果是Android是6.0以上,调用相机需要动态申请权限(小Demo,我直接在设置中为应用赋予了权限);

    修改MainActivity代码如下:

    public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener{
    
        private CameraBridgeViewBase openCvCameraView;
        private CascadeClassifier cascadeClassifier;
        private Mat grayscaleImage;
        private int absoluteFaceSize;
        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");
                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();
                cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
            } catch (Exception e) {
                Log.e("OpenCVActivity", "Error loading cascade", e);
            }
            openCvCameraView.enableView();
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    
            openCvCameraView = new JavaCameraView(this, -1);    // 新建一个布局文件
            setContentView(openCvCameraView);   // 为该活动设置布局
            openCvCameraView.setCvCameraViewListener(this);
    
        }
        @Override
        public void onCameraViewStarted(int width, int height) {
            grayscaleImage = new Mat(height, width, CvType.CV_8UC4);
            absoluteFaceSize = (int) (height * 0.2);
        }
    
        @Override
        public void onCameraViewStopped() {
        }
    
        @Override
        public Mat onCameraFrame(Mat aInputFrame) {
            Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);
            MatOfRect faces = new MatOfRect();
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2,
                        new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }
            Rect[] facesArray = faces.toArray();
            for (int i = 0; i <facesArray.length; i++)
                Core.rectangle(aInputFrame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
            return aInputFrame;
        }
        @Override
        public void onResume() {
            super.onResume();
    
            if (!OpenCVLoader.initDebug()) {
            }
            initializeOpenCVDependencies();
        }
    }
    
    

    简单分析:

    首先onCreate方法中设置屏幕常亮.

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

    然后新建了一个布局openCvCameraView,这个布局文件是OpenCV封装好了,不需要我们重写布局文件,因为请看setContentView方法,这和平时我们写Activity是不一样的。

    openCvCameraView = new JavaCameraView(this, -1);    // 新建一个布局文件
    setContentView(openCvCameraView);   // 为该活动设置布局
    

    然后为这个布局类设置了回调监听, 因为我们的MainActivity实现了CameraBridgeViewBase.CvCameraViewListener,所以监听器就是本身;

    openCvCameraView.setCvCameraViewListener(this);
    

    实现了该监听器,就需要实现onCameraViewStarted onCameraViewStopped onCameraFrame这三个方法,具体实现的逻辑就在这三个方法中,涉及到很多数据知识,就不多说了(我也不是很懂!!!)

    参考资料

    1. Android 接入 OpenCV库的三种方式

    最后

    • 本文内容个人拙见,若有出入,欢迎指正。
    • 欢迎赏脸关注:家佳Talk

    欢迎赏脸关注:家佳Talk

  • 相关阅读:
    C# OCR 文字识别[初级]
    首次试用 NeoSwiff ,用C#开发FLASH版的多国语言翻译
    星期天上午买了个nokia 的NGage QD手机
    高兴,今天总算鸟枪换炮了~
    3年前的小程序:破解需要delphi IDE 环境的vcl 控件
    基于Ajax的五子棋演示
    学习API HOOK,编写了一个winsock 的封包抓取程序,可免费使用;
    我得小猫爱摔交
    老是不中,算了算“双色球”和“3D”,全买到底要多少¥¥。。(C 代码)
    总算忙完了,大家'晚秋快乐'!
  • 原文地址:https://www.cnblogs.com/numen-fan/p/10009425.html
Copyright © 2020-2023  润新知