RV1126 NO.60:ROCKX+RV1126人脸识别推流项目之show_vi_thread线程讲解
摘要:show_vi_thread线程实现视频处理流程,主要包括:1)通过RK_MPI_SYS_GetMediaBuffer获取VI模块视频数据;2)从rockx_vi_handle_thread线程获取人脸识别结果(包含人脸名称和区域信息);3)使用OpenCV将人脸框和名称标注在视频画面上,包括坐标转换、边界保护等处理;4)通过RK_MPI_SYS_SendMediaBuffer将处理后的视频
一.本章节内容:
本章节详细说明show_vi_thread线程的工作流程。该线程的核心功能包括:
- 从第二VI模块获取视频数据
- 接收rockx_vi_handle_thread推理线程处理的人脸识别结果(包含人脸名称和区域信息,即rockx_object_array_t结构体)
- 使用OpenCV将人脸区域和名称标注在视频画面上
- 将处理后的视频数据传输至VENC编码器进行压缩编码
二.show_vi_thread线程大体框图

该流程图展示了show_vi_thread线程的工作流程:首先获取第二个VI模块的视频数据,随后提取人脸识别结果(包括识别名称字符串和人脸区域信息rockx_object_array_t),接着使用OpenCV绘制人脸区域矩形框并显示识别名称,最后将处理后的视频数据发送至VENC编码器。
三.show_vi_thread线程代码
3.1. 获取第二个模块VI模块的视频数据
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VI, 1, -1);
if (!mb)
{
printf("RK_MPI_SYS_GetMediaBuffer Break.....\n");
break;
}
上面是通过RK_MPI_SYS_GetMediaBuffer获取第二个模块的VI数据,模块号是RK_ID_VI,通道号是1。
3.2. 创建OPENCV并获取人脸名称和区域信息
rockx_object_array_t face_array = get_rockx_face_array();
People people = get_rockx_people();
Mat tmp_img = Mat(1080, 1920, CV_8UC1, RK_MPI_MB_GetPtr(mb));
string face_count_str = std::to_string(face_array.count);
cv::putText(tmp_img, face_count_str, pointer, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 0, 255), 3);
上述处理流程通过OpenCV对RKMEDIA获取的VI数据进行操作,具体实现是将数据转换为Mat矩阵格式(Mat rv1126_mat = Mat(HEIGHT, WIDTH, CV_8UC1, RK_MPI_MB_GetPtr(mb)))。随后,从rokx处理线程中获取人脸区域信息(get_rockx_face_array)及对应的人脸名称(get_rockx_people)。
3.3. 利用OPENCV显示人脸区域信息和人脸名称
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) >= 1920)
{
w -= 16;
}
while ((uint32_t)(y + h) >= 1080)
{
h -= 16;
}
Scalar color(255, 0, 255);
Rect boundingBox(x, y, 500, 500);
int thickness = 3;
rectangle(tmp_img, boundingBox, color, thickness);
int baseline;
Size text_size = getTextSize(people.people_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, people.people_name, origin, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 0, 255), 3);
}
这段代码使用OpenCV来显示人脸区域和对应的名称。首先通过循环遍历每个人脸的区域信息,每个区域信息存储在一个box对象中,包含四个坐标参数(left、top、right、bottom)。基于这些坐标计算出x和y值(具体计算方法见上图)。
然后调用OpenCV的rectangle函数绘制人脸区域矩形,该矩形的宽度和高度都固定设置为500像素。在绘制完人脸矩形后,使用OpenCV的putText函数将get_rockx_people获取的人脸名称显示在VI模块中。
3.4. 把处理后的VI数据发送到VENC编码器并释放资源
RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, 0, mb);
RK_MPI_MB_ReleaseBuffer(mb);
VI数据经过RK_MPI_SYS_SendMediaBuffer接口传输至VENC编码器后,编码器即可生成H.264格式的编码数据。
四.完整代码
void *show_vi_thread(void *args)
{
pthread_detach(pthread_self());
MEDIA_BUFFER mb = NULL;
float x_rate = (float)1920 / 1920;//计算 X 轴(水平方向)的坐标缩放比例
float y_rate = (float)1920 / 1080;//计算 Y 轴(垂直方向)的坐标缩放比例
Point pointer;
pointer.x = 300;
pointer.y = 300;
while (1)
{
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VI, 1, -1);
if (!mb)
{
printf("RK_MPI_SYS_GetMediaBuffer Break.....\n");
break;
}
rockx_object_array_t face_array = get_rockx_face_array();
People people = get_rockx_people();
Mat tmp_img = Mat(1080, 1920, CV_8UC1, RK_MPI_MB_GetPtr(mb));
string face_count_str = std::to_string(face_array.count);
cv::putText(tmp_img, face_count_str, pointer, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 0, 255), 3);
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) >= 1920)
{
w -= 16;
}
while ((uint32_t)(y + h) >= 1080)
{
h -= 16;
}
Scalar color(255, 0, 255);
Rect boundingBox(x, y, 500, 500);
int thickness = 3;
rectangle(tmp_img, boundingBox, color, thickness);
int baseline;
Size text_size = getTextSize(people.people_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, people.people_name, origin, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 0, 255), 3);
}
RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, 0, mb);
RK_MPI_MB_ReleaseBuffer(mb);
}
return NULL;
}
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)