1. 程式人生 > >android OpenCV研究之動態人臉識別

android OpenCV研究之動態人臉識別

轉載自:https://blog.csdn.net/u013895206/article/details/52671550

隨著直播漸漸的火起來,像抱著直播大腿的其他功能也漸漸的火起來了,比如說人臉識別。說起人臉識別用處甚廣,比如說有以這個功能為核心的app:美顏相機、美圖秀秀、SNOW等等,但是美顏相機和美圖秀秀是用的國內SDK《Face++》來做的,這個sdk呢好像是他們自己的後臺進行識別並不是app本身做識別。這樣就跟我們今天要了解的動態識別不是很對路,肯定不能拿到攝像頭的一幀畫面去調一次介面再接回引數吧,這樣效能肯定不行。所以今天就拿SNOW的例子來說,雖然我不知道他是用什麼做的,但是我們可以用openCV也能實現。


我們先看看效果圖:

這裡寫圖片描述


實現步驟如下:

1、首先我們需要去openCV的官網下載sdk,這個是地址:http://opencv.org/downloads.html

2、然後新建個專案我這裡以studio裡為基準,在main目錄裡面新建jniLibs資料夾,為什麼叫jniLibs呢,因為這是呼叫c庫的預設資料夾命名,當然你也可以命名其他的,但是需要在build裡面指定這個資料夾。好了,開啟我們剛才下載的檔案,然後一次開啟sdk\native\libs,最後把libs目錄裡面的所有資料夾拷貝到jniLibs裡面去。請看圖:

這裡寫圖片描述

這裡寫圖片描述

3、加好jniLibs之後呢還需要匯入一個module,在studio裡面點選file->new->import module->匯入module目錄是剛才下載的sdk\java這個目錄。請看圖:

這裡寫圖片描述

這裡寫圖片描述

4、匯入之後呢右鍵專案開啟open module setting選項,在app選項裡點選Dependencies這個,然後點選最右邊的+號把剛剛匯入的module加進去。請看圖:

這裡寫圖片描述

這裡寫圖片描述

5、現在開始寫程式碼了,這裡我把需要寫的程式碼檔案會一一貼出來,下面請看圖:

這裡寫圖片描述


首先是MainActivity的程式碼:

package com.wyw.facedemo;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import
android.util.Log; import android.view.View; import android.view.WindowManager; import android.widget.Button; import android.widget.RelativeLayout; import org.opencv.android.CameraBridgeViewBase; import org.opencv.android.JavaCameraView; import org.opencv.android.OpenCVLoader; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Rect; import org.opencv.core.Scalar; import org.opencv.core.Size; import org.opencv.objdetect.CascadeClassifier; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener { private CameraBridgeViewBase openCvCameraView; private CascadeClassifier cascadeClassifier; //影象人臉小於高度的多少就不檢測 private int absoluteFaceSize; //臨時影象物件 private Mat matLin; //最終影象物件 private Mat mat; //前置攝像頭 public static int CAMERA_FRONT = 0; //後置攝像頭 public static int CAMERA_BACK = 1; private int camera_scene = CAMERA_BACK; private void initializeOpenCVDependencies() { try { // Copy the resource into a temp file so OpenCV can load it 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(); // Load the cascade classifier cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath()); } catch (Exception e) { Log.e("OpenCVActivity", "Error loading cascade", e); } // And we are ready to go openCvCameraView.enableView(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_main); final RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.relative); openCvCameraView = new JavaCameraView(this, CameraBridgeViewBase.CAMERA_ID_FRONT); openCvCameraView.setCvCameraViewListener(this); final Button button = new Button(MainActivity.this); button.setText("切換攝像頭"); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (camera_scene == CAMERA_FRONT) {//如果是前置攝像頭就切換成後置 relativeLayout.removeAllViews(); openCvCameraView.disableView(); openCvCameraView = null; cascadeClassifier = null; openCvCameraView = new JavaCameraView(MainActivity.this, CameraBridgeViewBase.CAMERA_ID_BACK); openCvCameraView.setCvCameraViewListener(MainActivity.this); openCvCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);//後置攝像頭 camera_scene = CAMERA_BACK; relativeLayout.addView(openCvCameraView); relativeLayout.addView(button); initializeOpenCVDependencies(); } else { relativeLayout.removeAllViews(); openCvCameraView.disableView(); openCvCameraView = null; cascadeClassifier = null; openCvCameraView = new JavaCameraView(MainActivity.this, CameraBridgeViewBase.CAMERA_ID_FRONT); openCvCameraView.setCvCameraViewListener(MainActivity.this); openCvCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT);//前置攝像頭 camera_scene = CAMERA_FRONT; relativeLayout.addView(openCvCameraView); relativeLayout.addView(button); initializeOpenCVDependencies(); } } }); relativeLayout.addView(openCvCameraView); relativeLayout.addView(button); if (camera_scene == CAMERA_FRONT) { openCvCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT);//前置攝像頭 } else if (camera_scene == CAMERA_BACK) { openCvCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);//後置攝像頭 } } @Override public void onCameraViewStarted(int width, int height) { matLin = new Mat(height, width, CvType.CV_8UC4);//臨時影象 // 人臉小於高度的百分之30就不檢測 absoluteFaceSize = (int) (height * 0.3); } @Override public void onCameraViewStopped() { } @Override public Mat onCameraFrame(Mat aInputFrame) { //轉置函式,將影象翻轉(順時針90度) Core.transpose(aInputFrame, matLin); if (camera_scene == CAMERA_FRONT) {//前置攝像頭 //轉置函式,將影象翻轉(對換) Core.flip(matLin, aInputFrame, 1); //轉置函式,將影象順時針順轉(對換) Core.flip(aInputFrame, matLin, 0); mat = matLin; } else if (camera_scene == CAMERA_BACK) {//後置攝像頭 //轉置函式,將影象翻轉(對換) Core.flip(matLin, aInputFrame, 1); mat = aInputFrame; } MatOfRect faces = new MatOfRect(); Log.i("123456", "absoluteFaceSize = " + absoluteFaceSize); // Use the classifier to detect faces if (cascadeClassifier != null) { cascadeClassifier.detectMultiScale(mat, faces, 1.1, 1, 1, new Size(absoluteFaceSize, absoluteFaceSize), new Size()); } // 檢測出多少個 Rect[] facesArray = faces.toArray(); for (int i = 0; i < facesArray.length; i++) { Log.i("123456", "facesArray[i].tl()坐上座標 == " + facesArray[i].tl() + " facesArray[i].br() == 右下座標" + facesArray[i].br()); Core.rectangle(mat, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3); } return mat; } @Override public void onResume() { super.onResume(); if (!OpenCVLoader.initDebug()) { Log.e("log_wons", "OpenCV init error"); // Handle initialization error } initializeOpenCVDependencies(); //OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_6, this, mLoaderCallback); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204

然後是layout的xml程式碼:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/relative"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</RelativeLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

現在是raw資料夾裡面的xml(這個xml是圖片解析出來進行對比校驗人臉的模型庫)由於這個檔案有一千多行就不貼了,如有需要請去下載本demo檢視!當然也可以去你下載的openCV的sdk裡面拿,目錄是\samples\face-detection\res\raw。請看圖:

這裡寫圖片描述

最後就是AndroidManifest檔案了:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.wyw.facedemo"
          xmlns:android="http://schemas.android.com/apk/res/android">

    <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"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

做到這一步就趕緊把你的程式碼執行起來吧!!本篇部落格就到這裡,如果有有疑問的歡迎留言討論。同時希望大家多多關注我的部落格,多多支援我。

尊重原創轉載請註明:(http://blog.csdn.net/u013895206) !

下面是地址傳送門:址:http://download.csdn.net/detail/u013895206/9640349