NDK 開發實戰 - 實時人臉檢測和識別

關於人臉檢測和識別,應用的範圍是非常廣的,其實之前的《NDK開發前奏 - 實現支付寶人臉識別功能》 也有提到,只是那時並未具體的去分析算法和實現原理,這裏筆者打算一步一步來分析和實現人臉識別,首先我們得要明確人臉檢測和人臉識別是兩個不同的概念,人臉檢測是檢測有人臉,人臉識別是匹配你是你,他們所採用的算法也是不一樣的,這篇文章是基於人臉檢測來實現人臉識別。我們先來看下已經實現了的人臉檢測效果:
實時人臉檢測

人臉馬賽克大家可以忽略,並不是這裏要關注的內容,是因爲長得太帥了怕大家嫉妒。馬賽克效果實現大家可以參考《圖形圖像處理 - 手寫 QQ 說說圖片處理效果》。首先我們不妨來思考一下,要實現像支付寶的人臉識別和員工刷臉簽到等等,這樣的一些應用功能,我們需要用到哪些知識?需要經過哪些步驟呢?其實這裏分爲兩步,第一步是樣本數據採集,第二步是檢測和匹配。不過我們得先來看幾個概念:均值,標準差,協方差矩陣,特徵值,特徵向量,PCA降維。

1. 均值,標準差,協方差矩陣

這幾個都是概率論中的概念,我們隨便舉一個例子來算下即可,假設我的 Mat 數據如下:

Mat src = (Mat_<int>(3, 3) << 50, 50, 50, 60, 60, 60, 70, 70, 70);

均值:[60]

均值

標準差:[8.164965809277252]

標準差

協方差矩陣:[200, 200, 200; 200, 200, 200; 200, 200, 200]

協方差矩陣

2. 特徵值,特徵向量

關於特徵值與特徵向量這是線性代數的概念,還是老套路拿個例子過來算下,能算出來就可以了,同時大家也可以參考這篇文章:
https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors

圖片來源於百度經驗

圖片來源於百度經驗

圖片來源於百度經驗

3. PCA降維

人臉識別肯定需要採集人臉樣本,也就是相機採集過來的 Mat 數據,那麼大量的數據怎麼處理呢?這裏就需要 PCA 降維了:

  • 把原始數據中每個樣本用一個向量表示,然後把所有樣本組合起來構成一個矩陣。當然了,爲了避免樣本的單位的影響,樣本集需要標準化。
  • 求該矩陣的協方差矩陣
  • 求步驟2中得到的協方差矩陣的特徵值和特徵向量。
  • 將求出的特徵向量按照特徵值的大小進行組合形成一個映射矩陣,並根據指定的 PCA 保留的特徵個數取出映射矩陣的前n行或者前n列作爲最終的映射矩陣。
  • 用步驟4的映射矩陣對原始數據進行映射,達到數據降維的目的。

4. 樣本訓練

接下來就是代碼層面的東西了,代碼是很簡單的就那麼幾句話,但關鍵其實還是在於理解裏面的原理:

FaceDetection_trainingPattern(JNIEnv *env, jobject instance) {
    // 訓練樣本,這一步是在數據採集做的
    // train it
    vector<Mat> faces;
    vector<int> labels;

    // 樣本比較少
    for (int i = 1; i <= 5; ++i) {
        for (int j = 1; j <= 5; ++j) {
            Mat face = imread(format("/storage/emulated/0/s%d/%d.pgm", i, j), 0);
            if (face.empty()) {
                LOGE("face mat is empty");
                continue;
            }
            // 確保大小一致
            resize(face, face, Size(128, 128));
            faces.push_back(face);
            labels.push_back(i);
        }
    }

    for (int i = 1; i <= 8; ++i) {
        Mat face = imread(format("/storage/emulated/0/face_%d.png", i), 0);
        if (face.empty()) {
            LOGE("face mat is empty");
            continue;
        }
        resize(face, face, Size(128, 128));
        faces.push_back(face);
        labels.push_back(11);
    }

    // 訓練方法
    Ptr<BasicFaceRecognizer> model = EigenFaceRecognizer::create();
    // 採集了八張,同一個人 label 一樣
    model->train(faces, labels);
    // 訓練樣本是 xml ,本地
    model->save("/storage/emulated/0/face_darren_pattern.xml");// 存的是處理的特徵數據
    LOGE("樣本訓練成功");
}

4. 匹配識別

FaceDetection_faceDetection(JNIEnv *env, jobject instance,
                                                         jlong nativeObj) {
    Mat *src = reinterpret_cast<Mat *>(nativeObj);

    int width = src->rows;
    int height = src->cols;

    Mat grayMat;
    // 2. 轉成灰度圖,提升運算速度,灰度圖所對應的 CV_8UC1 單顏色通道,信息量少 0-255 1u
    cvtColor(*src, grayMat, COLOR_BGRA2GRAY);

    // 4. 檢測人臉,這是個大問題
    // 參數 1.1 會採取上採樣和降採樣 ,縮放比例
    // 參數 3 檢測多少次
    // 參數 Size(width / 2, height / 2) 最小臉的大小
    std::vector<Rect> faces;
    cascadeClassifier.detectMultiScale(grayMat, faces, 1.1, 3, 0, Size(width / 2, height / 2));

    if (faces.size() != 1) {
        mosaicFace(*src);
        return;
    }

    // 把臉框出來
    Rect faceRect = faces[0];
    rectangle(*src, faceRect, Scalar(255, 0, 0, 255), 4, LINE_AA);

    // 不斷檢測,錄入 10 張,張張嘴巴,眨眨眼睛 ,保證準確率
    // 還需要注意一點,確保人臉大小一致,reSize(128,128) ,確保收集到的人臉眼睛儘量在一條線上
    // 與服務端進行比對,是不是我

    // 用一個計數器,這裏我們做及時的
    Mat face = (*src)(faceRect).clone();
    resize(face, face, Size(128, 128));
    cvtColor(face, face, COLOR_BGRA2GRAY);
    // 直方均衡,harr 檢測人臉
    int label = model->predict(face);
    // 訓練的時候存的是 11
    if (label == 11) {
        // 識別到了自己
        LOGE("識別到了自己");
        putText(*src, "Darren", Point(faceRect.x + 20, faceRect.y - 20),
                HersheyFonts::FONT_HERSHEY_COMPLEX, 1, Scalar(255, 0, 0, 255),2,LINE_AA);
    } else {
        // 不是自己
        LOGE("不是自己");
        putText(*src, "UnKnow", Point(faceRect.x + 20, faceRect.y - 20),
                HersheyFonts::FONT_HERSHEY_COMPLEX, 1, Scalar(255, 0, 0, 255),2,LINE_AA);
    }
    // 速度, 準確率, 人臉儘量正常
    mosaicFace((*src)(faceRect));
}

實時人臉識別

視頻地址:https://pan.baidu.com/s/1lF92ev7_SqVNRNMih9eHkQ
視頻密碼:jc4k

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章