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;
}
相关推荐
2601_957884846 小时前
面向内容合规性的短视频矩阵分发机制:感知哈希去重与语义检索优化实践
矩阵·音视频·哈希算法
小欣加油9 小时前
leetcode3751 范围内总波动值I
java·数据结构·c++·算法·leetcode
代码中介商9 小时前
C++左值与右值:核心判断法则详解
开发语言·c++
玖玥拾9 小时前
C/C++ 基础笔记(七)
c语言·c++
珊瑚里的鱼10 小时前
手撕单例模式中的饿汉模式和懒汉模式,懒汉模式还要再多加一个C++11版本的
开发语言·c++·单例模式
zh路西法10 小时前
【Linux 串口通信】基于 C++ 多线程的同步/异步串口实现
linux·运维·c++·python
不会C语言的男孩11 小时前
C++ Primer 第12章:动态内存
开发语言·c++
thisiszdy11 小时前
<C++> 浅拷贝与深拷贝
c++
2023自学中11 小时前
Linux虚拟机 CMakeLists.txt:x86 与 ARM 双架构编译脚本
linux·c语言·c++·嵌入式
眠りたいです11 小时前
现代C++:C++17中的新库特性
开发语言·c++·c++20·c++17