您好,欢迎来到二三四教育网。
搜索
您的当前位置:首页NDK 开发实战 - 实时人脸检测和识别

NDK 开发实战 - 实时人脸检测和识别

来源:二三四教育网
实时人脸检测

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. 特征值,特征向量

图片来源于百度经验 图片来源于百度经验 图片来源于百度经验

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));
}
实时人脸识别

Copyright © 2019- how234.cn 版权所有 赣ICP备2023008801号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务