Linux52:ROCKX+RV1126实现1->N人脸识别功能

1.Rockx+Rv1126实现1->N 人脸识别功能大体流程

上图是实现1->N人脸识别流程,首先要初始化RV1126模块初始化,包括VI模块、VENC模块、人脸检测rockx模块、人脸识别rockx模块,初始化模块之后,就要分两个线程做处理。

主流程是先读取单张图片的图像并提取人脸特征值,然后死循环获取VI的码流数据,然后用rockx的人脸检测模块RV1126的VI数据是否有人脸,如果有人脸则调用rockx的人脸识别模块识别出RV1126视频流的人脸数据并且提取出来。然后对比两个人脸的阈值,如果<=1.0,则认定单张人脸图片和RV1126检测的人脸是同一个,否则就不是同一个人,并把数据通过Opencv显示到VI数据,最后把识别后的VI数据传输到VENC编码器里面

get_rockx_face_recg_venc_thread线程主要是获取每一帧的VENC码流数据,并且保存起来。

2.Rockx+Rv1126实现1->N 人脸识别功能代码截图

2.1. RV1126 模块的初始化并启动 VI 工作

上图是RV1126模块的初始化,这里需要初始化RV1126的VI模块、VENC模块、并调用RK_MPI_VI_StartStream启动VI模块采集摄像头数据。具体的API不讲解了,因为之前已经讲了很多次。

2.1. 初始化人脸检测和人脸识别的 rockx 模块

上图是rockx模块的初始化,这里我们要初始化两个rockx模块,分别是人脸检测rockx模块和人脸识别rockx模块。首先要使用rockx_create_config 分配rockx_config_t结构体,并使用rockx_add_config 把对应的rockx路径配置进去,在我们的板子里面在**/userdata/rockx_data**里面。

使用rockx_create创建人脸检测rockx_handle_t句柄。rockx_create的传参第一个参数rockx_handle_t结构体指针、 第二个参数rockx_module_t是ROCKX_MODULE_FACE_DETECTION_V2 ROCKX_MODULE_FACE_DETECTION_V2是人脸检测的Version2模块、第三个参数是rockx_config_t结构体指针、第四个参数默认是0。

使用rockx_create创建人脸识别rockx_handle_t句柄。rockx_create的传参第一个参数rockx_handle_t结构体指针、 第二个参数rockx_module_t是ROCKX_MODULE_FACE_RECOGNIZE ROCKX_MODULE_FACE_RECOGNIZE是人脸识别模块、第三个参数是rockx_config_t结构体指针、第四个参数默认是0。

2.2. 读取单张人脸的图像并提取特征值

rockx_image_read 读取单张人脸图像,face_02.jpg这张图片是我上节课拍照的图片,并且用rockx_face_recognize 提取单张图片的人脸特征值,第一个参数传值:人脸识别的句柄(face_reco_handle ),第二个参数传值:单张人脸的rockx_image_t数据地址(&single_face_image ),第三个参数传值:获取单张人脸的人脸特征(&single_face_feature )

2.3. 获取每一帧 VI 视频数据并提取 VI 数据的人脸特征值

首先初始化rockx_image_t结构体,包括

width(WIDTH=1920),height(HEIGHT=1080),pixel_format(ROCKX_PIXEL_FORMAT_YUV420SP_NV12)。使用RK_MPI_SYS_GetMediaBuffer 获取每一帧VI数据,并且把每一帧VI数据赋值到rockx_image_t **,**这里关键要赋值的是data(data =(uint8_t *)RK_MPI_MB_GetPtr(mb) )和size(size = RK_MPI_MB_GetSize(mb))。

赋值后,就调用rockx_face_detect 对每一帧的视频数据进行人脸检测,如果rockx_object_array_t 的count大于0**(face_detect_array.count)** 则说明检测到人脸。若检测到人脸则调用rockx_face_recognize提取VI摄像头的人脸特征值,第一个参数传值:人脸识别的句柄(face_reco_handle ),第二个参数传值:rv1126的图像数据地址(&rv1126_video_image ),第三个参数传值:获取rv1126视频流的人脸特征(&rv1126_face_feature)

2.4. 对比单张图片的人脸特征值和 VI 数据的人脸特征值

提取完单张图片特征值和RV1126视频流的人脸特征值后就要对比两个特征值的相似度了,在rockx框架提供了rockx_face_feature_similarity 去对比两个脸特征值。第一个参数传值:单张人脸的特征结构体指针(&single_face_feature ), 第二个参数:rv1126视频流人脸特征结构体指针(&rv1126_face_feature ),第三个参数:两个人脸对比输出的相似度阈值similarity(&similarity)。

如果输出的人脸相似度值<=1.0(1.0是rockx比较经典的人脸识别阈值, 值越小相似度越高),则说明单张人脸和视频流的人脸是同一个人,然后把"Harry"输出到string , 否则就不输出。

2.5. 把识别的人脸名称输出到 opencv Text

上述步骤已经得到了对比的人脸名称,这一步则需要把人脸的名称输出到OPENCV里面,并显示到视频上。首先要创建OPENCV的矩阵Mat rv1126_mat = Mat(HEIGHT,WIDTH,CV_8UC1,rv1126_video_image.data), 第一个参数: HEIGHT(1080), 第二个参数 HEIGHT(1920), 第三个参数: CV_8UC1( 单通道 ), 第四个参数: rv1126_video_image.data( 每一帧的 rv1126 VI 数据 ).

创建完矩阵后,则需要调用OPENCV的putText把人脸名称输出到Mat矩阵里面。具体的如下:putText(rv1126_mat,reco_name,text_point,FONT_HERSHEY_COMPLEX,1.0,Scalar(255,0,255),1) ,第一个参数: rv1126_mat(Mat 矩阵数据 ) ,第二个参数: reco_name( 人脸名称的 string 字符串 ) ,第三个参数: text_point( 坐标信息 ,x =300,y -300), 第四个参数: FONT_HERSHEY_COMPLEX( 字体类型 ) ,第五个参数: 1.0( 字体大小是 1.0) ,第六个参数: Scalar(255,0,255)( 颜色标量 ) ,第七个参数: 1( 粗细程度是 1)

2.6. 把处理后的数据传输到 VENC 编码器

上述识别工作完成之后,就需要把VI数据传输到VENC编码器里面。这里直接调用**RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, VENC_CHN, mb)**去发送。

2.7. 开启 get_rockx_face_recg_venc_thread 线程获取每一帧 VENC 数据并且保存到 H264

上图是创建一个get_rockx_face_recg_venc_thread 线程,在这个线程里面通过**RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, VENC_CHN, -1)**获取每一帧VENC码流,并且用fwrite写到face_reco.h264文件里面。

最终的运行效果:

上图就是程序运行的效果,在这个H264里面,可以识别到我的人脸名称,并且显示出来。

3.代码

cs 复制代码
/****************************************************************************
 *
 *    Copyright (c) 2017 - 2019 by Rockchip Corp.  All rights reserved.
 *
 *    The material in this file is confidential and contains trade secrets
 *    of Rockchip Corporation. This is proprietary information owned by
 *    Rockchip Corporation. No part of this work may be disclosed,
 *    reproduced, copied, transmitted, or used in any way for any purpose,
 *    without the express written permission of Rockchip Corporation.
 *
 *****************************************************************************/
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <opencv2/core/hal/interface.h>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/imgproc_c.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string>

// #include "common/sample_common.h"
#include "rkmedia_api.h"
#include "rockx.h"
#include <opencv2/core.hpp>
// #include <opencv2/imgoroc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>

#define CAMERA_PATH "rkispp_scale0"
#define CAMERA_ID 0
#define CAMERA_CHN 0
#define VENC_CHN 0
#define WIDTH 1920
#define HEIGHT 1080

using namespace std;
using namespace cv;

string reco_name;

void * get_rockx_face_recg_venc_thread(void * args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb = NULL;

    FILE * face_reco_venc_h264 = fopen("face_reco.h264", "w+");

    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, VENC_CHN, -1);
        if(!mb)
        {
            printf("Get Venc Stream break...\n");
            break;
        }

        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, face_reco_venc_h264);
        RK_MPI_MB_ReleaseBuffer(mb);
    }

    return NULL;
}



int main(int argc, char **argv)
{
    int ret;
    VI_CHN_ATTR_S vi_chn_attr;
    vi_chn_attr.pcVideoNode = CAMERA_PATH;        // Path
    vi_chn_attr.u32Width = 1920;                  // Width
    vi_chn_attr.u32Height = 1080;                 // Height
    vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;       // ImageType
    vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP; // BufType
    vi_chn_attr.u32BufCnt = 3;                    // Cnt
    vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL; // Mode
    ret = RK_MPI_VI_SetChnAttr(CAMERA_ID, CAMERA_CHN, &vi_chn_attr);
    if (ret)
    {
        printf("Vi Set Attr Failed.....\n");
        return 0;
    }
    else
    {
        printf("Vi Set Attr Success.....\n");
    }

    ret = RK_MPI_VI_EnableChn(CAMERA_ID, CAMERA_CHN);
    if (ret)
    {
        printf("Vi Enable Attr Failed.....\n");
        return 0;
    }
    else
    {
        printf("Vi Enable Attr Success.....\n");
    }

    VENC_CHN_ATTR_S venc_chn_attr;
    memset(&venc_chn_attr, 0, sizeof(VENC_CHN_ATTR_S));
    venc_chn_attr.stVencAttr.u32PicWidth = 1920;
    venc_chn_attr.stVencAttr.u32PicHeight = 1080;
    venc_chn_attr.stVencAttr.u32VirWidth = 1920;
    venc_chn_attr.stVencAttr.u32VirHeight = 1080;
    venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;
    venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;
    venc_chn_attr.stVencAttr.u32Profile = 66;
    venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 25;
    venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = 1920 * 1080 * 3;
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;
    ret = RK_MPI_VENC_CreateChn(0, &venc_chn_attr);
    if (ret)
    {
        printf("ERROR: Create venc failed!\n");
        exit(0);
    }

    ret = RK_MPI_VI_StartStream(CAMERA_ID, CAMERA_CHN);
    if (ret)
    {
        printf("ERROR: RK_MPI_VI_StartStream failed!\n");
        exit(0);
    }

    

    rockx_config_t * face_config = rockx_create_config();
    rockx_add_config(face_config, ROCKX_CONFIG_DATA_PATH, "/userdata/rockx_data");

    rockx_handle_t face_det_handle;
    rockx_module_t face_det_module = ROCKX_MODULE_FACE_DETECTION_V2;
    rockx_ret_t face_det_ret;
    face_det_ret = rockx_create(&face_det_handle, face_det_module, face_config, 0);
    if(face_det_ret != ROCKX_RET_SUCCESS)
    {
        printf("rockx_create face_detect_handle failed!\n");
        return -1;
    }

    rockx_handle_t face_reco_handle;
    rockx_module_t face_reco_module = ROCKX_MODULE_FACE_RECOGNIZE;
    rockx_ret_t face_recg_ret;
    face_recg_ret = rockx_create(&face_reco_handle, face_reco_module, face_config, 0);
    if(face_recg_ret != ROCKX_RET_SUCCESS)
    {
        printf("rockx_create face_recognize_handle failed!\n");
        return -1;
    }
    

    char * image_path = "face_02.jpg";
    rockx_image_t single_face_image;
    rockx_image_read(image_path, &single_face_image, 1);
    rockx_face_feature_t single_face_feature;
    rockx_face_recognize(face_reco_handle, &single_face_image,&single_face_feature);

    pthread_t pid;
    pthread_create(&pid, NULL, get_rockx_face_recg_venc_thread, NULL);


    MEDIA_BUFFER mb = NULL;
    rockx_image_t rv1126_video_image;
    rv1126_video_image.width = WIDTH;
    rv1126_video_image.height = HEIGHT;
    rv1126_video_image.pixel_format = ROCKX_PIXEL_FORMAT_YUV420SP_NV12;

    rockx_ret_t sim_ret;
    Point text_point;
    text_point.x = 300;
    text_point.y = 300;

    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VI, CAMERA_CHN, -1);
        if(!mb)
        {
            printf("Get vi data break....\n");
            break;
        }

        rv1126_video_image.data = (uint8_t  *)RK_MPI_MB_GetPtr(mb);
        rv1126_video_image.size = RK_MPI_MB_GetSize(mb);

        Mat rv1126_mat = Mat(HEIGHT,WIDTH,CV_8UC1,rv1126_video_image.data);

        rockx_object_array_t face_detect_array;
        face_det_ret = rockx_face_detect(face_det_handle,&rv1126_video_image,&face_detect_array,NULL);
        if(face_det_ret != ROCKX_RET_SUCCESS)
        {
            printf("rockx_face_detect failed!.....\n");
        }

        rockx_face_feature_t rv1126_face_feature;

        if(face_detect_array.count > 0)
        {
            face_recg_ret =  rockx_face_recognize(face_reco_handle,&rv1126_video_image,&rv1126_face_feature);
            if(face_recg_ret != ROCKX_RET_SUCCESS)
            {
                printf("rockx_face_recognize failed....\n");
            }

            float similarity;
            sim_ret = rockx_face_feature_similarity(&single_face_feature, &rv1126_face_feature, &similarity);
            if(sim_ret != ROCKX_RET_SUCCESS)
            {
                printf("rockx_face_feature_similarity failed....\n");
            }

            if(similarity <= 1.0)
            {
                reco_name = "Harry";
                printf("This is Harry...\n");
            }
            else
            {
                reco_name = "";
                printf("Can not recognize...\n");
            }

            putText(rv1126_mat,reco_name,text_point,FONT_HERSHEY_COMPLEX,1.0,Scalar(255,0,255),1);
        }

        RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, VENC_CHN, mb);
        RK_MPI_MB_ReleaseBuffer(mb);
    }

    RK_MPI_VI_DisableChn(CAMERA_ID,CAMERA_CHN);
    RK_MPI_VENC_DestroyChn(VENC_CHN);
    
    return 0;
}
相关推荐
ZPC82103 小时前
CPU 核心隔离 + 线程绑核 + 实时优先级 SCHED_FIFO
人工智能·算法·计算机视觉·机器人
隐士Xbox4 小时前
c++ 指针的用法
开发语言·c++·计算机视觉
weixin_413063215 小时前
c++ opencv 复现 halcon算子 derivate_gauss
opencv·计算机视觉·derivate_gauss
新新学长搞科研6 小时前
【最新】2026年能源方向学术会议征稿/交流资讯
人工智能·功能测试·计算机视觉·自动化·能源·新能源·材料工程
Hua-Jay6 小时前
OpenCV联合C++/Qt 学习笔记(十五)----形态学操作及应用
c++·笔记·qt·opencv·学习·计算机视觉
Coovally AI模型快速验证6 小时前
多校联合提出LLM-as-Judge:大模型评判无人机电力线分割,无真值场景下守护安全
人工智能·计算机视觉·电力巡检
Hua-Jay7 小时前
OpenCV联合C++/Qt 学习笔记(十六)----图像细化、轮廓检测、轮廓信息统计及轮廓外接多边形
c++·笔记·qt·opencv·学习·计算机视觉
sali-tec7 小时前
C# 基于OpenCv的视觉工作流-章69-圆弧测量
图像处理·人工智能·opencv·算法·计算机视觉
人工智能培训7 小时前
集中式与分布式智能:单个复杂智能体 vs. 多个简单智能体协同
大数据·人工智能·机器学习·计算机视觉·知识图谱