一.ROCKX的API
1.ROCKX的作用
ROCKX的AI组件可以快速搭建 AI的应用,这些应用可以是车牌识别、人脸识别、目标识别,人体骨骼识别等等。主要用于各种检测识别。例如下图:

2.ROCKX人脸识别的API
- rockx_ret_t rockx_create(rockx_handle_t *handle, rockx_module_t m, void *config, size_t config_size);
函数解释: rockx_create 创建 rockx 的句柄 rockx_handle_t 。rockx_handle_t 也是管理整个 rockx 人脸检测、人脸识别的最重要结构体
第一个参数: rockx_handle_t 的结构体指针
**第二个参数:**rockx_module_t 的结构体,rockx_module_t 是一个枚举类型,设置当前 rockx 的处理类型。具体的如下:

ROCKX_MODULE_FACE_DETECTION:人脸检测模块
ROCKX_MODULE_FACE_LANDMARK_68:人脸 68 个特征点检测
ROCKX_MODULE_FACE_RECOGNIZE:人脸识别模块
ROCKX_MODULE_FACE_ANALYZE: 人脸分析模块
ROCKX_MODULE_OBJECT_DETECTION:目标检测模块
ROCKX_MODULE_POSE_BODY: 人体姿态检测模块,14 个关键点
ROCKX_MODULE_POSE_FINGER_21:手指检测模块,21 个关键点
ROCKX_MODULE_FACE_LANDMARK_5:人脸 5 个特征点检测
ROCKX_MODULE_HEAD_DETECTION: 人体头部检测模块
ROCKX_MODULE_CARPLATE_DETECTION: 车牌检测模块
ROCKX_MODULE_CARPLATE_ALIGN:车牌对齐模块
ROCKX_MODULE_CARPLATE_RECOG:车牌识别模块
ROCKX_MODULE_OBJECT_TRACK:物体追踪模块
ROCKX_MODULE_POSE_FINGER_3:手指检测模块, 支持 3 个关键点
ROCKX_MODULE_FACE_MASKS_DETECTION:人脸口罩检测,检测这个人是否戴口罩
ROCKX_MODULE_FACE_DETECTION_V2:人脸检测模块,Version2 版本
ROCKX_MODULE_BODY_MASK:人体身体遮挡检测,主要是检测当前人体是否有遮挡物
ROCKX_MODULE_POSE_BODY_V2:人体姿态检测,V2 是 Version2,能够检测 17 个关键点
ROCKX_MODULE_FACE_DETECTION_V3:人脸检测模块,V3 是 Version3,它只能检测 320 * 320 的人脸
ROCKX_MODULE_FACE_DETECTION_V3_LARGE:人脸检测模块加强版,V3 是 Version3,Large 能够检测 640 * 640 的人脸
ROCKX_MODULE_PERSON_DETECTION:行人检测模块,主要是检测当前图像中是否有行人
ROCKX_MODULE_FACE_LANDMARK_106:人脸关键点检测模型,总共能检测出 106 个关键点
ROCKX_MODULE_FACE_BEAUTY:人脸漂亮指数检测模型,主要是检测人的漂亮指数是多少
ROCKX_MODULE_FACE_SMILE_DETECT:人脸微笑检测模型,检测当前人是否微笑
ROCKX_MODULE_FACE_MASK_CLASSIFIER:人脸口罩分类检测模型,主要是检测当前口罩的类型是什么
ROCKX_MODULE_PERSON_DETECTION_V2:行人检测模型,V2 是 Version2,它只能检测 532 * 320 的行人图像
ROCKX_MODULE_PERSON_DETECTION_V3:行人检测模型,V3 是 Version3,它可以检测多尺寸的行人图像
第三个参数: rockx_config_t 结构体指针,主要是配置 rockx 的基本参数,它的创建是用rockx_add_config 来创建
**第四个参数:**config_size,默认是 0 就可以
- rockx_ret_t rockx_add_config(rockx_config_t *config, const char *key, const char *value);
函数解释: 添加 rockx 的 config 配置
第一个参数: rockx_config_t 结构体指针,rockx_config_t 的创建是用 rockx_create_config 来分配,如:rockx_config_t *config =rockx_create_config();
第二个参数: config 的 key, 最常见的 KEY 是 ROCKX_CONFIG_DATA_PATH(ROCKX 的配置路径)
第三个参数: config 的 value, 跟 Key 一一对应, 比方说 Key 是 ROCKX_CONFIG_DATA_PATH, 那它的 value 就是对应的 rockx 的具体路径,如:/userdata/rockx_data/。
示例:
rockx_config_t *config = rockx_create_config();
rockx_add_config(config, ROCKX_CONFIG_DATA_PATH, "/userdata/rockx_data/");
- rockx_ret_t rockx_face_detect(rockx_handle_t handle, rockx_image_t *in_img,rockx_object_array_t *face_array, rockx_async_callback *callback);
函数解释: 这个 API 主要是对人脸进行检测,得到人脸检测的位置信息
第一个参数: rockx_handle_t 的结构体指针
**第二个参数:**rockx_image_t 的结构体指针,这个是输入的图像,需要检测的图像,也可以是每一帧视频流。
第四个参数: config_size,默认是 0 就可以
**第三个参数:**rockx_object_array_t 的结构体指针,主要是输出检测结果,这个检测结果的结构体如下:

count: 检测的人脸数量
**rockx_object_t:**检测的具体信息,具体的成员变量如下:

id: object 的 id 号
**cls_idx:**object 的 index 索引
score: object 物体信任分数
**box:**rockx 的区域信息,rockx_rect_t 结构体。

left: 区域左边缘的 x 坐标,其实就是 x 轴数据
top: 区域顶的 y 坐标,其实就是 Y 轴数据
right: 区域右边缘的 x 坐标,其实就是 left + width
**bottom:**区域底的 Y 坐标,其实就是 top + height

- rockx_ret_t rockx_face_recognize(rockx_handle_t handle, rockx_image_t *in_img, rockx_face_feature_t *out_feature);
**函数定义:**这个 API 主要是对人脸进行识别,并提取人脸数据
第一个参数: rockx_handle_t 的结构体指针
第二个参数: rockx_image_t 的结构体指针,这个是输入的图像,需要检测的图像,也可以是每一帧视频流。
**第三个参数:**rockx_face_feature_t 的结构体指针,rockx_face_feature_t 结构体主要是存储人脸的特征值和长度,我们来看看这个结构体的组成
version: 人脸识别版本
len: 人脸识别的长度
**feature[512]:**人脸识别的数据,512 的 float 数组,这个值是存储一个二进制数据
- rockx_ret_t rockx_face_feature_similarity(rockx_face_feature_t *in_feature1, rockx_face_feature_t *in_feature2, float *out_similarity);
函数的定义: 这个 API 主要是对比两个人脸,并计算两个人脸的对比数值
第一个参数: in_feature1,需要对比的人脸特征值 1
第一个参数: in_feature2,需要对比的人脸特征值 2
**第三个参数:**in_feature1 和 in_feature2 对比的相似度值,一般小于 1.0 可以判断为同一个人
- rockx_ret_t rockx_face_align(rockx_handle_t handle, rockx_image_t *in_img, rockx_rect_t *in_box, rockx_face_landmark_t *in_landmark, rockx_image_t *out_img);
函数的定义: 这个 API 主要是对目前检测的人脸进行对齐,这个对齐一般是用 face_landmark 检测人脸关键点进行对齐
第一个参数: rockx_handle_t 的结构体
第二个参数: in_img 输入的图像
**第三个参数:**in_box 是人脸检测的区域,用矩形来表示,我们来看看 rockx_rect_t 的结构体成员

left: 表示矩形左边缘的 X 坐标。
top: 表示矩形顶部的 y 坐标
right: 表示矩形右边缘的 x 坐标
**bottom:**表示矩形底部的 y 坐标。

**第四个参数:**rockx_face_landmark_t 的结构体指针,主要是检测人脸关键点,我们来看看这个结构体的成员变量

image_width: 图像的长度
image_height: 图像的高度
face_box: 人脸的检测区域,用矩形表示
landmarks_count: 关键点个数
**landmarks[128]:**具体的人脸关键点,rockx_point_t 来表示,它本质上就是 x,y 的点
**score:**每个关键点的分数
- rockx_ret_t rockx_face_filter(rockx_handle_t handle, rockx_image_t *in_img, rockx_rect_t *in_box, int *is_false_face);
函数的定义: 这个 API 主要是过滤人脸,过滤图像中不符合人脸的图像
第一个参数: rockx_handle_t 的结构体指针
第二个参数: in_img 是输入的图像
第三个参数: in_box 人脸检测区域,是一个矩形
**第四个参数:**is_falas_face 判断当前检测的图像是否是人脸,是人脸就等于 true,否则 false
- rockx_ret_t rockx_face_masks_detect(rockx_handle_t handle, rockx_image_t *in_img, rockx_face_mask_array_t *face_mask_array,rockx_async_callback *callback);
第一个参数: rockx_handle_t 的结构体指针
第二个参数: in_img 是输入的图像
**第三个参数:**face_mask_array 存放口罩的数据,我们来看看这个结构体的数据
count: 口罩的数量
**face_masks:**rockx_face_mask_t,具体的口罩参数,如下图

face_box : 是口罩的区域,用矩形表示
mask_score: 口罩的分数
**hasMask:**是否有戴口罩
二. ROCKX图片检测人脸并画框
1.图片检测人脸并画框的流程:
这里有个重点就是如何知道脸的位置:由rockx_face_detect函数检测并获取位置传给opencv,那位置就是width:right-left,high:bottom-top。然后opencv画框。

2.代码实现
/****************************************************************************
*
* 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 <cstddef>
#include <fcntl.h>
#include <getopt.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 "common/sample_common.h"
#include "rkmedia_api.h"
#include "rknn_rockx_include/rockx_type.h"
#include "rockx.h"
#include <opencv2/core.hpp>
// #include <opencv2/imgoroc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <memory.h>
#include <sys/time.h>
#include "rknn_rockx_include/rockx_type.h"
#include "rockx.h"
#include <opencv2/opencv.hpp>
#include <opencv2/imgcodecs.hpp>
#include "rknn_rockx_include/utils/rockx_config_util.h"
using namespace cv;
int main(int argc, char **argv)
{
const char *image_path = argv[1]; //输入图片路径
//配置rockx的config
rockx_config_t * face_detect_config = rockx_create_config();//创建配置
rockx_add_config(face_detect_config,ROCKX_CONFIG_DATA_PATH, "/userdata/rockx_data");//设置配置
//创建rockx的句柄
rockx_ret_t face_ret;
rockx_handle_t face_detect_handle ;
rockx_module_t module = ROCKX_MODULE_FACE_DETECTION_V3;
face_ret = rockx_create(&face_detect_handle,module,face_detect_config,0);//创建A模型
if(face_ret != ROCKX_RET_SUCCESS){
printf("create face detect handle failed.....\n");
return -1;
}
//读取图片
rockx_image_t image;
rockx_image_read(image_path,&image,1);//读取图片
printf("3");
//检测人脸
rockx_object_array_t face_array;
face_ret = rockx_face_detect(face_detect_handle,&image,&face_array,nullptr);//检测人脸
if(face_ret != ROCKX_RET_SUCCESS){
printf("face detect failed.....\n");
return -1;
}
//循环人脸数量并画框
Mat face_mat = Mat(image.height,image.width,CV_8UC3,image.data);//将图片转为Mat
for(int i = 0;i < face_array.count;i++){
int left = face_array.object[i].box.left;
int top = face_array.object[i].box.top;
int width = face_array.object[i].box.right - face_array.object[i].box.left;
int height = face_array.object[i].box.bottom - face_array.object[i].box.top;
Rect boundingRect(left,top,width,height);//定义矩形框
rectangle(face_mat,boundingRect,Scalar(0,0,255),1);//画框
}
//显示图片
imwrite("face_detect.jpg",face_mat);
rockx_destroy(face_detect_handle);
return 0;
}
3.效果图(V2模型会出现多个框,所以改V3模型了)

三.ROCKX视频检测人脸并画框
1.视频检测人脸并画框的流程:
首先要初始化模块包括 VI 模块、VENC 模块、并启动 VI 模块采集视频流、rockx 模块的初始化。
初始化模块后,就要分两个线程处理了。
主线程是负责 rockx 对 VI 视频流的处理,并用 OPENCV 对人脸进行画框,最后把处理后的 VI 数据传输到 VENC 模块里面。
第二个线程 rockx_face_detect_venc_thread,从 VENC 模块获取到 H264 的编码码流数据,并把 VENC 码流数据保存。

2.代码实现
/****************************************************************************
*
* 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 <cstddef>
#include <fcntl.h>
#include <getopt.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 "common/sample_common.h"
#include "rkmedia_api.h"
#include "rknn_rockx_include/rockx_type.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 cv;
void *rockx_face_detect_venc_thread(void *args)
{
pthread_detach(pthread_self());
FILE *face_detect_h264 = fopen("face_detect_venc.h264", "w+");
MEDIA_BUFFER mb = NULL;
while (1)
{
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, VENC_CHN, -1);
if (!mb)
{
printf("Get Rockx_Venc Data break...\n");
}
fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, face_detect_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(VENC_CHN, &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("RK_MPI_VI_StartStream Failed.....\n");
return 0;
}
else
{
printf("RK_MPI_VI_StartStream Success.....\n");
}
pthread_t pid;
pthread_create(&pid, NULL, rockx_face_detect_venc_thread, NULL);
rockx_config_t *face_detect_config = rockx_create_config();
rockx_add_config(face_detect_config, ROCKX_CONFIG_DATA_PATH, "/userdata/rockx_data");
rockx_handle_t face_detect_handle;
rockx_ret_t face_detect_ret;
rockx_module_t face_detect_module = ROCKX_MODULE_FACE_DETECTION_V3;
face_detect_ret = rockx_create(&face_detect_handle, face_detect_module, face_detect_config, 0);
if (face_detect_ret != ROCKX_RET_SUCCESS)
{
printf("rockx_create face_detect failed...\n");
return -1;
}
rockx_image_t rv1126_rockx_image;//图像数据
rv1126_rockx_image.width = WIDTH;//图像宽度
rv1126_rockx_image.height = HEIGHT;//图像高度
rv1126_rockx_image.pixel_format = ROCKX_PIXEL_FORMAT_YUV420SP_NV12;//图像格式
MEDIA_BUFFER mb;
while (1)
{
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VI, CAMERA_CHN, -1);
if (!mb)
{
printf("Get Vi Stream break....\n");
break;
}
rv1126_rockx_image.data = (uint8_t *)RK_MPI_MB_GetPtr(mb);
rv1126_rockx_image.size = RK_MPI_MB_GetSize(mb);
Mat rv1126_image_mat = Mat(HEIGHT, WIDTH, CV_8UC1, rv1126_rockx_image.data);
rockx_object_array_t face_detect_array;
face_detect_ret = rockx_face_detect(face_detect_handle, &rv1126_rockx_image, &face_detect_array, NULL);
if (face_detect_ret != ROCKX_RET_SUCCESS)
{
printf("face_detect failed....\n");
}
for (int i = 0; i < face_detect_array.count; i++)
{
int left = face_detect_array.object[i].box.left;
int top = face_detect_array.object[i].box.top;
int w = face_detect_array.object[i].box.right - face_detect_array.object[i].box.left;
int h = face_detect_array.object[i].box.bottom - face_detect_array.object[i].box.top;
Rect boundingRect(left, top, w, h);
rectangle(rv1126_image_mat, boundingRect, Scalar(255, 255, 0));
}
RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, VENC_CHN, mb);
RK_MPI_MB_ReleaseBuffer(mb);
}
RK_MPI_VENC_DestroyChn(VENC_CHN);
RK_MPI_VI_DisableChn(CAMERA_ID, CAMERA_CHN);
return 0;
}