insightface进行视频中人脸识别

包含针对视频的简单人脸识别,后续需增加阈值确定视频中的具体人,防止跳振,还需增加相关的release和接口等操作

cpp 复制代码
#include <iostream>
#include <thread>
#include <vector>
#include <condition_variable>
#include <mutex>
#include <atomic>
#include <opencv4/opencv2/opencv.hpp>

#include "inspireface.h"

std::mutex mtx;
std::condition_variable face_cv;
std::atomic<bool> face_cv_flag(false);


struct FrameTokenPair{
    cv::Mat frame;
    std::vector<HFFaceFeatureIdentity> queryFeatureIdentitys;
    std::vector<HFFaceFeature> queryFeatures;

};

class ThreadSafeTokenQueue{
    private:
        std::queue<FrameTokenPair> pairQueue;
        std::mutex mtx_;
        std::condition_variable cv_;
        std::atomic<bool> stop_flag_{false};
        const int max_queue_size = 50;

    public:
        bool addFrameToken(cv::Mat& frame, std::vector<HFFaceFeature>& queryFeatures){

            std::lock_guard<std::mutex> lock(mtx_);

            if (pairQueue.size() >= max_queue_size){
                std::cerr << "queue is full, drop frame token" << std::endl;
                return false;
            }
            FrameTokenPair pair;
            pair.frame = frame.clone();
            pair.queryFeatures = queryFeatures;
            pairQueue.push(pair);
            cv_.notify_one();

            return true;
        }

        FrameTokenPair getToken(){
            std::unique_lock<std::mutex> lock(mtx_);
            cv_.wait(lock,[this](){
                return !pairQueue.empty();
            });
            if (pairQueue.empty()){
                std::cerr << "pairQueue为空,gettoken失败" << std::endl;
                return {};
            }
            FrameTokenPair pair = std::move(pairQueue.front());
            pairQueue.pop();
            return pair;
        }

};

bool cvMatToImageBitmap(const cv::Mat& mat, HFImageBitmap& bitmap){

    if (mat.empty()){
        std::cerr << "empty frame" << std::endl;
        return false;
    }
    cv::Mat bgr_mat;
    if (mat.channels() == 1){
        cv::cvtColor(mat, bgr_mat, cv::COLOR_GRAY2BGR);
    }else if(mat.channels() == 4){
        cv::cvtColor(mat, bgr_mat, cv::COLOR_RGBA2BGR);
    }else{
        bgr_mat = mat;
    }

    HFImageBitmapData bitmapData = {0};
    bitmapData.width = bgr_mat.cols;
    bitmapData.height = bgr_mat.rows;
    bitmapData.channels = bgr_mat.channels();
    bitmapData.data = bgr_mat.data;

    HResult ret = HFCreateImageBitmap(&bitmapData, &bitmap);
    if (ret != HSUCCEED){
        return false;
    }

    return true;

}

int videoDetectThread(ThreadSafeTokenQueue& threadSafeTokenQueue,
                       const std::string video_path){

    std::cout << "人脸检测线程开始" << std::endl;

    HResult ret;
    HPath packPath = "/home/yfzx/project/insightface/insightface/cpp-package/inspireface/test_res/pack/Megatron";
    ret = HFLaunchInspireFace(packPath);     // 模型文件路径
    if (ret != HSUCCEED) {
        HFLogPrint(HF_LOG_ERROR, "Load Resource error: %d", ret);
        return ret;
    }

    HOption option = HF_ENABLE_QUALITY | HF_ENABLE_FACE_RECOGNITION;

    HFDetectMode detMode = HF_DETECT_MODE_ALWAYS_DETECT; // 每次都重新检测所有人脸,不追踪,视频流有额外的模式
    HInt32 maxDetectNum = 20;
    HInt32 detectPixelLevel = 160;
    HFSession session;
    ret = HFCreateInspireFaceSessionOptional(option, detMode, maxDetectNum, detectPixelLevel, -1, &session);
    if (ret != HSUCCEED) {
        HFLogPrint(HF_LOG_ERROR, "Create FaceContext error: %d", ret);
        return ret;
    }


    cv::VideoCapture cap(video_path);
    if (!cap.isOpened()){
        std::cerr << "failed to open video file" << video_path <<std::endl;
        return -1;
    }

    int frame_width = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
    int frame_height = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
    int total_frames = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_COUNT));
    double fps = cap.get(cv::CAP_PROP_FPS);

    std::cout << "Video info: " << frame_width << "x" << frame_height
              << ", FPS: " << fps << ", Total frames: " << total_frames << std::endl;

    int frame_count = 0;
    cv::Mat frame;
    while(cap.read(frame)){

        // 1. 将opencv帧转为inspire face的image bitmap
        HFImageBitmap bitmap = {0};
        if (!cvMatToImageBitmap(frame, bitmap)){
            frame_count++;
            continue;
        }

        // 2. 创建图像流
        HFImageStream stream = {0};
        ret = HFCreateImageStreamFromImageBitmap(bitmap, HF_CAMERA_ROTATION_0, &stream);
        if (ret != HSUCCEED){
            std::cerr << "failed to create image stream frame" << frame_count << std::endl;
            frame_count++;
            continue;
        }

        // 3. 执行人脸识别
//        HFSession session = {0};
        HFMultipleFaceData multipleFaceData = {0};
        ret = HFExecuteFaceTrack(session, stream, &multipleFaceData);
        if (ret != HSUCCEED){
            std::cerr << "检测人脸出错,error code:" << ret << std::endl;
        }
        std::vector<HFFaceFeature> queryFeatures;
        if (multipleFaceData.detectedNum > 0){
            for (int i = 0; i < multipleFaceData.detectedNum; ++i) {
//                HFFaceFeature queryFeature;
                HFFaceFeature feature;
                ret = HFCreateFaceFeature(&feature);
                if (ret != HSUCCEED){
                    std::cout << "创建 face feature error :" << ret << std::endl;
                }
                ret = HFFaceFeatureExtractTo(session, stream, multipleFaceData.tokens[i], feature);
                if (ret != HSUCCEED) {
                    HFLogPrint(HF_LOG_ERROR, "Extract feature error: %d", ret);
                    return ret;
                }
//                queryFeature.feature = &feature;
//                queryFeature.id = -1;
                queryFeatures.push_back(feature);
            }
            threadSafeTokenQueue.addFrameToken(frame, queryFeatures);


        }else{
            continue; // 未检测到人脸
        }
    }
    std::cout << "读取frame完成" << std::endl;

    return 1;


}

int faceRecognitionThread(ThreadSafeTokenQueue& threadSafeTokenQueue,
                            char *db_path = "../database/case_crud.db"){

    HResult ret;
    // The resource file must be loaded before it can be used
    ret = HFLaunchInspireFace("/home/yfzx/project/insightface/insightface/cpp-package/inspireface/test_res/pack/Megatron");     // 模型文件路径

    if (ret != HSUCCEED) {
        HFLogPrint(HF_LOG_ERROR, "Load Resource error: %d", ret);
        return ret;
    }

    HFFeatureHubConfiguration featureHubConfig;
    featureHubConfig.primaryKeyMode = HF_PK_AUTO_INCREMENT;    //  自增ID
    featureHubConfig.enablePersistence = 1;                    //  持久化到DB
    featureHubConfig.persistenceDbPath = db_path;              //  db路径
    featureHubConfig.searchMode = HF_SEARCH_MODE_EXHAUSTIVE;   //  全量检索
    featureHubConfig.searchThreshold = 0.48f;                  //  匹配阈值
    ret = HFFeatureHubDataEnable(featureHubConfig);
    if (ret != HSUCCEED) {
        HFLogPrint(HF_LOG_ERROR, "Enable feature hub error: %d", ret);
        return ret;
    }
    HInt32 faceCount;
    ret = HFFeatureHubGetFaceCount(&faceCount);
    std::cout<<"人脸数据库中人脸数量为:" << faceCount<< std::endl;

    HFloat confidence;
    while (true){
        FrameTokenPair tokenPair = threadSafeTokenQueue.getToken();

        for (int i = 0; i < tokenPair.queryFeatures.size(); ++i) {
            HFFaceFeatureIdentity searchedIdentity = {0};
//            searchedIdentity.feature = &tokenPair.queryFeatures[i];
//            searchedIdentity.id = -1;
            std::cout << tokenPair.queryFeatures[i].size << std::endl << tokenPair.queryFeatures.data() << std::endl;
            ret = HFFeatureHubFaceSearch(tokenPair.queryFeatures[i], &confidence, &searchedIdentity);
            if (ret != HSUCCEED){
                std::cerr << "查询数据库失败" << std::endl;
                continue;
            }
            std::cout << "查询到人脸,人脸id为:" << searchedIdentity.id << std::endl;

        }



    }

}

int main(){

    ThreadSafeTokenQueue threadSafeTokenQueue;
    std::string videopath = "../testdata/wyr.mp4";
    char *db_path = "../database/case_crud.db";

    std::thread t1(videoDetectThread,std::ref(threadSafeTokenQueue),videopath);
    std::thread t2(faceRecognitionThread, std::ref(threadSafeTokenQueue), db_path);

    t1.join();
    t2.join();


    return 1;
}
相关推荐
小樱花的樱花2 小时前
C++权限对继承的影响
开发语言·c++
Q741_1472 小时前
每日一题 力扣 3661. 可以被机器人摧毁的最大墙壁数目 双指针 动态规划 C++ 题解
c++·算法·leetcode·机器人·动态规划
ai产品老杨2 小时前
源码级开放与二次开发:基于 Spring Boot 的 AI 视频管理平台架构与 API 深度解析
spring boot·架构·音视频
Fleshy数模2 小时前
基于 dlib 与 OpenCV 的人脸检测实战:图片与视频场景全解析
人工智能·opencv·音视频
一定要AK8 小时前
刷题时的学习笔记
c++·笔记·学习
小彭努力中10 小时前
199.Vue3 + OpenLayers 实现:点击 / 拖动地图播放音频
前端·vue.js·音视频·openlayers·animate
小樱花的樱花12 小时前
C++ new和delete用法详解
linux·开发语言·c++
努力的章鱼bro14 小时前
操作系统-FileSystem
c++·操作系统·risc-v·filesystem
967714 小时前
cURL curl
c++