技术专栏
本节内容主要分为3部分,第一部分是流程结构图;第二部分为人脸识别代码流程;第三部分为具体的代码分析。
1.流程结构图
2.人脸识别代码流程
1、人脸数据的初始化:
init_all_rockx_face_data();
init_face_data();
- 1
- 2
2、创建rtsp会话,这里包括发送码流数据,得客户端,也就是我们在windows上用ffplay去拉流得时候,才会发送码流数据给客户端:
create_rtsp_demo(554);
rtsp_new_session
rtsp_set_video
rtsp_sync_video_ts
- 1
- 2
- 3
- 4
3、初始化vi通道属性
VI_CHN_ATTR_S vi_chn_attr;
- 1
4、初始化视频处理属性
RGA_ATTR_S stRgaAttr;
- 1
5、初始化编码通道属性:
VENC_CHN_ATTR_S venc_chn_attr;
- 1
6、绑定数据源:
RK_MPI_SYS_Bind
- 1
7、开始捕获码流:
RK_MPI_VI_StartStream
- 1
8、执行三个对应的线程:
- pthread_create(&rockx_pid, NULL, rockx_vi_detect_thread, NULL);
- pthread_create(&venc_pid, NULL, rockx_vi_face_recognize_venc_thread, NULL);
- pthread_create(&rtsp_pid, NULL, rockx_venc_rtsp_thread, NULL);
9、销毁申请的系统资源;
3.核心代码分析
初始化vi通道属性;初始化视频处理属性;初始化编码通道属性;绑定数据源;开始捕获码流:
//初始化vi通道属性
VI_CHN_ATTR_S vi_chn_attr;
vi_chn_attr.pcVideoNode = pDeviceName;
vi_chn_attr.u32BufCnt = u32BufCnt;
vi_chn_attr.u32Width = u32Width;
vi_chn_attr.u32Height = u32Height;//你的摄像头分辨率大小不要超过venc
vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;
vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;
vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
ret = RK_MPI_VI_SetChnAttr(s32CamId, 0, &vi_chn_attr);//设置vi通道属性
ret |= RK_MPI_VI_EnableChn(s32CamId, 0);//使能vi通道属性,让其生效
if (ret)
{
printf("ERROR: create rkisp0 VI[0] error! ret=%d\n", ret);
return 0;
}
//初始化rga属性
RGA_ATTR_S stRgaAttr;
stRgaAttr.bEnBufPool = RK_TRUE;
stRgaAttr.u16BufPoolCnt = 2;
stRgaAttr.u16Rotaion = 0;
stRgaAttr.stImgIn.u32X = 0;
stRgaAttr.stImgIn.u32Y = 0;
stRgaAttr.stImgIn.imgType = IMAGE_TYPE_NV12;
stRgaAttr.stImgIn.u32Width = u32Width;
stRgaAttr.stImgIn.u32Height = u32Height;
stRgaAttr.stImgIn.u32HorStride = u32Width;
stRgaAttr.stImgIn.u32VirStride = u32Height;
stRgaAttr.stImgOut.u32X = 0;
stRgaAttr.stImgOut.u32Y = 0;
stRgaAttr.stImgOut.imgType = IMAGE_TYPE_NV12;
stRgaAttr.stImgOut.u32Width = disp_width;
stRgaAttr.stImgOut.u32Height = disp_height;
stRgaAttr.stImgOut.u32HorStride = disp_width;
stRgaAttr.stImgOut.u32VirStride = disp_height;
ret = RK_MPI_RGA_CreateChn(0, &stRgaAttr);//rga通道
if (ret)
{
printf("ERROR: Create rga[0] falied! ret=%d\n", ret);
return -1;
}
//初始化编码属性
VENC_CHN_ATTR_S venc_chn_attr;
memset(&venc_chn_attr, 0, sizeof(VENC_CHN_ATTR_S));
venc_chn_attr.stVencAttr.u32PicWidth = disp_width;
venc_chn_attr.stVencAttr.u32PicHeight = disp_height;
venc_chn_attr.stVencAttr.u32VirWidth = disp_width;
venc_chn_attr.stVencAttr.u32VirHeight = disp_height;
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 = 30;
venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = disp_width * disp_height * 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);
}
//初始化mpp通道
MPP_CHN_S vi_chn;
MPP_CHN_S rga_chn;
vi_chn.enModId = RK_ID_VI;
vi_chn.s32ChnId = 0;
rga_chn.enModId = RK_ID_RGA;
rga_chn.s32ChnId = 0;
ret = RK_MPI_SYS_Bind(&vi_chn, &rga_chn);//绑定vi和rga通道
if (ret != 0)
{
printf("[VI] vi id: %d bind venc id: %d, ret: %d error\n", vi_chn.s32ChnId, rga_chn.s32ChnId, ret);
return -1;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
<
初始化三个线程
//初始化三个线程id
pthread_t rockx_pid;
pthread_t venc_pid;
pthread_t rtsp_pid;
//创建人脸检测线程
pthread_create(&rockx_pid, NULL, rockx_vi_detect_thread, NULL);
//人脸识别线程
pthread_create(&venc_pid, NULL, rockx_vi_face_recognize_venc_thread, NULL);
//人脸编码rtsp传输线程
pthread_create(&rtsp_pid, NULL, rockx_venc_rtsp_thread, NULL);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
人脸检测线程
void *rockx_vi_detect_thread(void *args)
{
//自动释放线程资源
pthread_detach(pthread_self());
//创建一个类对象thread_map
S_THREAD_MAP thread_map;
//对thread_map进行初始化
get_thread_map(0, &thread_map);
//定义了一个map类型database_face_map对象
map<string, rockx_face_feature_t> database_face_map = thread_map.thread_map;
//定义迭代器database_iter
map<string, rockx_face_feature_t>::iterator database_iter;
//定义一个缓冲区
MEDIA_BUFFER src_mb = NULL;
//人脸模式枚举变量定义
rockx_module_t data_version;
data_version = ROCKX_MODULE_FACE_DETECTION_V2;
//定义一个人脸执行返回结果变量
rockx_ret_t rockx_ret;
//定义人脸检测处理指针变量
rockx_handle_t face_det_handle;
//定义人脸识别特征提取处理指针变量
rockx_handle_t face_recognize_handle;
//定义人脸特征点定位处理指针变量
rockx_handle_t face_5landmarks_handle;
//定义了人脸标记检测处理指针变量
rockx_handle_t face_masks_det_handle;
//定义人脸配置结构体指针变量
rockx_config_t *config = rockx_create_config();//获取人脸配置值
//添加配置人脸模型存放路径,这里是存放在共享目录下:/mnt/nfs/rockx_data/
rockx_add_config(config, ROCKX_CONFIG_DATA_PATH, "/mnt/nfs/rockx_data/");
//创建使用人脸模型数据,来处理人脸检测
rockx_ret = rockx_create(&face_det_handle, data_version, config,
sizeof(rockx_config_t));
//判断是否创建使用人脸模型数据 来处理人脸检测是否成功
if (rockx_ret != ROCKX_RET_SUCCESS)
{
printf("init face_detect error %d\n", rockx_ret);
return NULL;
}
//使用人脸模型数据来人脸识别特征提取
rockx_ret = rockx_create(&face_recognize_handle, ROCKX_MODULE_FACE_RECOGNIZE,
config, sizeof(rockx_config_t));
//识别是否成功
if (rockx_ret != ROCKX_RET_SUCCESS)
{
printf("init face_recognize error %d\n", rockx_ret);
return NULL;
}
//使用模型算法数据来做人脸特征点定位处理
rockx_ret = rockx_create(&face_5landmarks_handle,
ROCKX_MODULE_FACE_LANDMARK_5, config, 0);
//判断是否处理成功
if (rockx_ret != ROCKX_RET_SUCCESS)
{
printf("init rockx module ROCKX_MODULE_FACE_LANDMARK_68 error %d\n",
rockx_ret);
}
// rockx_handle_t face_masks_det_handle;进行标记处理
rockx_ret = rockx_create(&face_masks_det_handle,
ROCKX_MODULE_FACE_MASKS_DETECTION, config, 0);
if (rockx_ret != ROCKX_RET_SUCCESS)
{
printf("init rockx module ROCKX_MODULE_FACE_MASKS_DETECTION error %d\n",
rockx_ret);
}
//定义人脸图片结构体变量,并进行成员赋值
rockx_image_t input_image;
input_image.width = 1920;
input_image.height = 1080;
input_image.pixel_format = ROCKX_PIXEL_FORMAT_YUV420SP_NV12;
bool is_recognize = false;
string predict = "";
//rockx_face_result_t face_result;
int ret;
//做轮询操作
while (!quit)
{
#if 1
//从指定通道中获取数据缓冲区
src_mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VI, 0, -1);
if (!src_mb)
{
printf("ERROR: RK_MPI_SYS_GetMediaBuffer get null buffer!\n");
break;
}
//从指定的MEDIA_BUFFER中获取缓冲区数据大小
input_image.size = RK_MPI_MB_GetSize(src_mb);
input_image.data = (unsigned char *)RK_MPI_MB_GetPtr(src_mb);//从指定的MEDIA_BUFFER中获取缓冲区数据指针
#endif
#if 1
//rockx_face_result_group_t face_result_group;
//memset(&face_result_group, 0, sizeof(face_result_group));
//定义人脸处理结果结构体变量
rockx_object_array_t face_array;
memset(&face_array, 0, sizeof(face_array));
//开始人脸检测
rockx_ret = rockx_face_detect(face_det_handle, &input_image, &face_array, NULL);
if (rockx_ret != ROCKX_RET_SUCCESS)
{
printf("rockx_face_detect ERROR %d\n", rockx_ret);
}
//进行互斥处理
set_rockx_face_array(face_array);
//判断检测人脸特征数量值是否大于0
if (face_array.count > 0)
{
//rockx_queue->putRockxFaceArray(face_array);
printf("face_count : %d\n", face_array.count);
for (int i = 0; i < face_array.count; i++)
{
if (1)
{
int is_false_face;
//进行人脸过滤处理
ret = rockx_face_filter(face_5landmarks_handle, &input_image,
&face_array.object[i].box, &is_false_face);
if (ret != ROCKX_RET_SUCCESS)
{
printf("rockx_face_filter error %d\n", ret);
}
if (is_false_face)
continue;
}
#if 1
//人脸检测结果(包括人脸、车牌、头部、物体等)变量定义
rockx_object_t max_face;
rockx_object_t cur_face = face_array.object[i];
//进行人脸区域计算处理操作
int cur_face_box_area = (cur_face.box.right - cur_face.box.left) *
(cur_face.box.bottom - cur_face.box.top);
int max_face_box_area = (max_face.box.right - max_face.box.left) *
(max_face.box.bottom - max_face.box.top);
if (cur_face_box_area > max_face_box_area)
{
max_face = cur_face;
}
//检测输出处理
rockx_image_t out_img;
memset(&out_img, 0, sizeof(rockx_image_t));
//进行面部矫正对齐
ret = rockx_face_align(face_5landmarks_handle, &input_image,
&(max_face.box), NULL, &out_img);
if (ret != ROCKX_RET_SUCCESS)
{
printf("face_align failed\n");
}
//人脸特征结果变量定义
rockx_face_feature_t out_feature;
//获取人脸特征
rockx_face_recognize(face_recognize_handle, &out_img, &out_feature);
for (database_iter = database_face_map.begin();
database_iter != database_face_map.end(); database_iter++)
{
float similarity;
//比较两个人脸特征的相似性
ret = rockx_face_feature_similarity(&database_iter->second,
&out_feature, &similarity);
printf("simple_value = %lf\n", similarity);
//判断预测精度
if (similarity <= 1.0)
{
is_recognize = true;
//predict_name_bak = database_iter->first;
predict = database_iter->first;
break;
}
else
{
is_recognize = false;
predict = "";
continue;
}
}
if (is_recognize == true)
{
predict = database_iter->first;
}
else
{
predict = "";
}
set_rockx_prdict_name(predict);
#endif
}
}
#endif
//释放缓冲区
RK_MPI_MB_ReleaseBuffer(src_mb);
src_mb = NULL;
}
//释放相关人脸处理数据模块
rockx_destroy(face_det_handle);
rockx_destroy(face_recognize_handle);
rockx_destroy(face_5landmarks_handle);
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
<
人脸识别线程
void *rockx_vi_face_recognize_venc_thread(void *args)
{
pthread_detach(pthread_self());//线程资源自动释放
MEDIA_BUFFER mb = NULL; //媒体缓存区
int ret;
float x_rate = (float)1280 / 1920;
float y_rate = (float)720 / 1080;
while (!quit)
{
//从指定通道中获取数据缓冲区
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, 0, -1);
if (!mb)
{
printf("ERROR: RK_MPI_SYS_GetMediaBuffer get null buffer!\n");
break;
}
//获取人脸处理结果
rockx_object_array_t face_array = get_rockx_face_array();
//创建mat对象,并创建了720x1080的像素块,每个像素每个通道的位数都是8位,一个字节的。上述CV_8UC3中的8表示8位、UC表示uchar类型、1表示1个通道
Mat tmp_img = Mat(720, 1280, CV_8UC1, RK_MPI_MB_GetPtr(mb));
#if 1
//对人脸x,y,w,h进行处理
for (int i = 0; i < face_array.count; i++)
{
int x = face_array.object[i].box.left * x_rate;
int y = face_array.object[i].box.top * y_rate;
int w = (face_array.object[i].box.right - face_array.object[i].box.left) * x_rate;
int h = (face_array.object[i].box.bottom - face_array.object[i].box.top) * y_rate;
if (x < 0)
x = 0;
if (y < 0)
y = 0;
while ((uint32_t)(x + w) >= 1280)
{
w -= 16;
}
while ((uint32_t)(y + h) >= 720)
{
h -= 16;
}
//获取人脸预测名字
string predict_name = get_rockx_prdict_name();
printf("predict_name = %s\n", predict_name.c_str());
nv12_border((char *)RK_MPI_MB_GetPtr(mb), 1280, 720, x, y, w, h, 255, 0, 255);
int baseline;
//计算人脸名字文本大小
Size text_size = getTextSize(predict_name, 2, 2, 2, &baseline);
Point origin;
origin.x = tmp_img.cols / 4 - text_size.width / 4;
origin.y = tmp_img.rows / 4 + text_size.height / 4;
//把名字字符填充到文本框里面去
cv::putText(tmp_img, predict_name, origin, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 0, 255), 3);
}
#endif
//释放对应的资源
RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, 0, mb);
RK_MPI_MB_ReleaseBuffer(mb);
mb = NULL;
}
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
<
人脸编码rtsp传输线程
void *rockx_venc_rtsp_thread(void *args)
{
pthread_detach(pthread_self());
MEDIA_BUFFER mb = NULL;
while (!quit)
{
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, 0, -1);
if (!mb)
{
printf("ERROR: RK_MPI_SYS_GetMediaBuffer get null buffer!\n");
break;
}
//rtsp来传输码流
rtsp_tx_video(g_rtsp_session, (unsigned char *)RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), RK_MPI_MB_GetTimestamp(mb));
RK_MPI_MB_ReleaseBuffer(mb);
rtsp_do_event(g_rtsplive);
}
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
<
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
评论
0个
手气红包

相关专栏
-
浏览量:2399次2024-05-24 17:53:56
-
浏览量:4865次2021-03-30 17:33:20
-
浏览量:10990次2024-01-04 14:35:55
-
浏览量:1665次2024-05-24 17:11:01
-
浏览量:1635次2024-05-24 17:28:44
-
浏览量:4223次2021-04-02 09:47:41
-
浏览量:1798次2024-05-24 19:05:42
-
浏览量:4170次2021-04-01 13:54:47
-
浏览量:2579次2022-10-09 10:38:23
-
浏览量:7293次2021-04-01 17:04:01
-
浏览量:6126次2021-04-01 16:47:04
-
浏览量:2336次2023-08-08 13:59:23
-
浏览量:6413次2022-05-11 15:14:51
-
浏览量:3683次2022-09-03 09:03:36
-
浏览量:2037次2022-12-16 16:27:02
-
浏览量:6829次2022-05-31 11:14:16
-
浏览量:6271次2021-04-01 16:50:31
-
浏览量:1429次2024-01-23 11:28:32
-
浏览量:2452次2024-01-18 18:05:38
置顶时间设置
结束时间
删除原因
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
审核成功
发布时间设置
发布时间:
请选择发布时间设置
是否关联周任务-专栏模块
审核失败
失败原因
请选择失败原因
备注
请输入备注