Hi3516DV300的yolo识别代码详解
Hi3516DV300的yolo识别代码详解
源码在https://gitee.com/jiang-guolong/openharmony
主函数sample_ai_main.cpp
switch (*argv[1]) {
case '0':
SAMPLE_MEDIA_CNN_TRASH_CLASSIFY();
break;
case '1':
SAMPLE_MEDIA_HAND_CLASSIFY();
break;
case '2':
mediaOpencv.SAMPLE_MEDIA_TENNIS_DETECT();
break;
default:
SAMPLE_AI_Usage(argv[0]);
break;
}
中的
case '1':
SAMPLE_MEDIA_HAND_CLASSIFY();
调用了这个函数之后,转到sample_media_ai.cpp文件
sample_media_ai.cpp
该文件中的SAMPLE_MEDIA_HAND_CLASSIFY函数为程序的第二执行顺序
HI_S32 SAMPLE_MEDIA_HAND_CLASSIFY(HI_VOID) //主函数2
{
HI_S32 s32Ret;
HI_S32 fd = 0;
/*
* 配置VI参数
* Config VI parameter
*/
ViPramCfg();
/*
* 通过Sensor型号获取enPicSize
* Obtain enPicSize through the Sensor type
*/
s32Ret = SAMPLE_COMM_VI_GetSizeBySensor(g_aicMediaInfo.viCfg.astViInfo[0].stSnsInfo.enSnsType,
&g_aicMediaInfo.enPicSize);
SAMPLE_CHECK_EXPR_RET(s32Ret != HI_SUCCESS, s32Ret, "get pic size by sensor fail, s32Ret=%#x\n", s32Ret);
/*
* 根据enPicSize,得到图片的宽高
* Get picture size(w*h), according enPicSize
*/
s32Ret = SAMPLE_COMM_SYS_GetPicSize(g_aicMediaInfo.enPicSize, &g_aicMediaInfo.stSize);
SAMPLE_PRT("AIC: snsMaxSize=%ux%u\n", g_aicMediaInfo.stSize.u32Width, g_aicMediaInfo.stSize.u32Height);
SAMPLE_CHECK_EXPR_RET(s32Ret != HI_SUCCESS, s32Ret, "get picture size failed, s32Ret=%#x\n", s32Ret);
/*
* 配置VB参数
* Config VB parameter
*/
StVbParamCfg(&g_aicMediaInfo.vbCfg);
/*
* 视频缓存池初始化以及MPI系统初始化
* VB init & MPI system init
*/
s32Ret = SAMPLE_COMM_SYS_Init(&g_aicMediaInfo.vbCfg);
SAMPLE_CHECK_EXPR_RET(s32Ret != HI_SUCCESS, s32Ret, "system init failed, s32Ret=%#x\n", s32Ret);
/*
* 设置VO至MIPI通路,获取MIPI设备
* Set VO config to MIPI, get MIPI device
*/
s32Ret = SAMPLE_VO_CONFIG_MIPI(&fd);
SAMPLE_CHECK_EXPR_GOTO(s32Ret != HI_SUCCESS, EXIT, "CONFIG MIPI FAIL.s32Ret:0x%x\n", s32Ret);
/*
* 配置VPSS参数
* Config VPSS parameter
*/
VpssParamCfg();
s32Ret = ViVpssCreate(&g_aicMediaInfo.viSess, &g_aicMediaInfo.viCfg, &g_aicMediaInfo.vpssCfg);
SAMPLE_CHECK_EXPR_GOTO(s32Ret != HI_SUCCESS, EXIT1, "ViVpss Sess create FAIL, ret=%#x\n", s32Ret);
g_aicMediaInfo.vpssGrp = AIC_VPSS_GRP;
g_aicMediaInfo.vpssChn0 = AIC_VPSS_ZOUT_CHN;
/*
* 配置VO参数
* Config VO parameter
*/
StVoParamCfg(&g_aicMediaInfo.voCfg);
/*
* 启动VO到MIPI lcd通路
* Start VO to MIPI lcd
*/
s32Ret = SampleCommVoStartMipi(&g_aicMediaInfo.voCfg);
SAMPLE_CHECK_EXPR_GOTO(s32Ret != HI_SUCCESS, EXIT1, "start vo FAIL. s32Ret: 0x%x\n", s32Ret);
/*
* VPSS绑定VO
* VPSS bind VO
*/
s32Ret = SAMPLE_COMM_VPSS_Bind_VO(g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0, g_aicMediaInfo.voCfg.VoDev, 0);
SAMPLE_CHECK_EXPR_GOTO(s32Ret != HI_SUCCESS, EXIT2, "vo bind vpss FAIL. s32Ret: 0x%x\n", s32Ret);
SAMPLE_PRT("vpssGrp:%d, vpssChn:%d\n", g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0);
/*
* 创建工作线程运行ai
* Create work thread to run ai
*/
s32Ret = HandClassifyAiThreadProcess(); //主函数3
SAMPLE_CHECK_EXPR_RET(s32Ret != HI_SUCCESS, s32Ret, "ai proccess thread creat fail:%s\n", strerror(s32Ret));
Pause();
g_bAiProcessStopSignal = HI_TRUE;
/*
* 等待一个线程结束,线程间同步的操作
* Waiting for the end of a thread, the operation of synchronization between threads
*/
pthread_join(g_aiProcessThread, NULL);
g_aiProcessThread = 0;
PauseDoUnloadHandClassifyModel();
SAMPLE_COMM_VPSS_UnBind_VO(g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0, g_aicMediaInfo.voCfg.VoDev, 0);
SAMPLE_VO_DISABLE_MIPITx(fd);
SampleCloseMipiTxFd(fd);
system("echo 0 > /sys/class/gpio/gpio55/value");
EXIT2:
SAMPLE_COMM_VO_StopVO(&g_aicMediaInfo.voCfg);
EXIT1:
VpssStop(&g_aicMediaInfo.vpssCfg);
SAMPLE_COMM_VI_UnBind_VPSS(g_aicMediaInfo.viCfg.astViInfo[0].stPipeInfo.aPipe[0],
g_aicMediaInfo.viCfg.astViInfo[0].stChnInfo.ViChn, g_aicMediaInfo.vpssGrp);
ViStop(&g_aicMediaInfo.viCfg);
free(g_aicMediaInfo.viSess);
EXIT:
SAMPLE_COMM_SYS_Exit();
return s32Ret;
}
其中的
/*
* 创建工作线程运行ai
* Create work thread to run ai
*/
s32Ret = HandClassifyAiThreadProcess(); //主函数3
SAMPLE_CHECK_EXPR_RET(s32Ret != HI_SUCCESS, s32Ret, "ai proccess thread creat fail:%s\n", strerror(s32Ret));
此处函数3调用的本体函数如下
static HI_S32 HandClassifyAiThreadProcess(HI_VOID)
{
HI_S32 s32Ret;
if (snprintf_s(acThreadName, BUFFER_SIZE, BUFFER_SIZE - 1, "AIProcess") < 0) {
HI_ASSERT(0);
}
prctl(PR_SET_NAME, (unsigned long)acThreadName, 0, 0, 0);
s32Ret = pthread_create(&g_aiProcessThread, NULL, GetVpssChnFrameHandClassify, NULL);//主函数4
return s32Ret;
}
此处将会创造一个线程用来处理yolo识别,紧接着在创建线程之后,程序会调用函数5 GetVpssChnFrameHandClassify
static HI_VOID* GetVpssChnFrameHandClassify(HI_VOID* arg) //主函数5循环
{
int ret;
VIDEO_FRAME_INFO_S frm;
HI_S32 s32MilliSec = 2000;
VO_LAYER voLayer = 0;
VO_CHN voChn = 0;
SAMPLE_PRT("vpssGrp:%d, vpssChn0:%d\n", g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0);
while (HI_FALSE == g_bAiProcessStopSignal) {
ret = HI_MPI_VPSS_GetChnFrame(g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0, &frm, s32MilliSec);//获取图片
if (ret != 0) {
SAMPLE_PRT("HI_MPI_VPSS_GetChnFrame FAIL, err=%#x, grp=%d, chn=%d\n",
ret, g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0);
ret = HI_MPI_VPSS_ReleaseChnFrame(g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0, &frm);
if (ret != HI_SUCCESS) {
SAMPLE_PRT("Error(%#x),HI_MPI_VPSS_ReleaseChnFrame failed,Grp(%d) chn(%d)!\n",
ret, g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0);
}
continue;
}
SAMPLE_PRT("get vpss frame success, weight:%d, height:%d\n", frm.stVFrame.u32Width, frm.stVFrame.u32Height);
if (g_num == 0) {
ConfBaseInit(AI_SAMPLE_CFG_FILE);
g_num++;
}
HandClassifyAiProcess(frm, voLayer, voChn);//主函数6
}
return HI_NULL;
}
主函数5的作用
GetVpssChnFrameHandClassify 函数的作用是循环从视频输入源(通过 VPSS,视频处理和安全子系统)获取图像帧,并对这些帧进行手部分类处理。这个函数主要负责持续地从视频流中获取帧,并将其传递给手部分类处理函数 (HandClassifyAiProcess),同时它也负责管理帧资源的获取和释放。
int ret;
VIDEO_FRAME_INFO_S frm;
HI_S32 s32MilliSec = 2000;
VO_LAYER voLayer = 0;
VO_CHN voChn = 0;
局部变量定义:
ret:用于存储函数的返回值。frm:用来存储从视频源获取的图像帧信息。s32MilliSec:获取帧时的超时时间,设置为 2000 毫秒(即 2 秒)。voLayer和voChn:视频输出层和通道,用于后续帧的显示输出。
SAMPLE_PRT("vpssGrp:%d, vpssChn0:%d\n", g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0);
- 打印出当前的 VPSS 组和通道信息,用于调试。
while (HI_FALSE == g_bAiProcessStopSignal) {
- 循环:这个
while循环会一直执行,直到g_bAiProcessStopSignal为HI_TRUE,即停止信号被触发。
ret = HI_MPI_VPSS_GetChnFrame(g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0, &frm, s32MilliSec);
- 获取视频帧:
- 使用
HI_MPI_VPSS_GetChnFrame函数从 VPSS 通道中获取一帧图像,并将结果存储在frm中。 - 如果获取失败,返回值
ret不为 0,表示获取帧失败。
- 使用
if (ret != 0) {
SAMPLE_PRT("HI_MPI_VPSS_GetChnFrame FAIL, err=%#x, grp=%d, chn=%d\n",
ret, g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0);
-
获取失败的处理:
- 如果
HI_MPI_VPSS_GetChnFrame返回失败,打印错误信息,并释放已获取的帧资源:
ret = HI_MPI_VPSS_ReleaseChnFrame(g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0, &frm); if (ret != HI_SUCCESS) { SAMPLE_PRT("Error(%#x),HI_MPI_VPSS_ReleaseChnFrame failed,Grp(%d) chn(%d)!\n", ret, g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0); } continue;- 如果释放帧失败,打印错误信息并继续循环,尝试获取下一帧。
- 如果
SAMPLE_PRT("get vpss frame success, weight:%d, height:%d\n", frm.stVFrame.u32Width, frm.stVFrame.u32Height);
- 帧获取成功:
- 打印获取到的视频帧的宽度和高度,表明帧已成功获取。
if (g_num == 0) {
ConfBaseInit(AI_SAMPLE_CFG_FILE);
g_num++;
}
- 配置初始化:
- 在第一次执行时(
g_num == 0),调用ConfBaseInit函数进行配置初始化,加载配置文件AI_SAMPLE_CFG_FILE。
- 在第一次执行时(
HandClassifyAiProcess(frm, voLayer, voChn); // 主函数 6
- 手部分类处理:
- 调用
HandClassifyAiProcess函数进行手部分类推理,并将获取到的帧frm传递给该函数。该函数会对图像进行推理,处理分类任务,并将结果输出到显示层(由voLayer和voChn指定)。
- 调用
return HI_NULL;
- 循环结束:
- 如果外部停止信号触发,循环结束,函数返回
HI_NULL。
- 如果外部停止信号触发,循环结束,函数返回
其中的函数6,会调用HandClassifyAiProcess
HandClassifyAiProcess(frm, voLayer, voChn);//主函数6
HandClassifyAiProcess的本体如下
static HI_VOID HandClassifyAiProcess(VIDEO_FRAME_INFO_S frm, VO_LAYER voLayer, VO_CHN voChn)//主函数7 试验过了((1980,1080)),0,0)
{
int ret;
if (GetCfgBool("hand_classify_switch:support_hand_classify", true)) {
if (g_workPlug.model == 0) {
ret = Yolo2HandDetectResnetClassifyLoad(&g_workPlug.model); //主函数8
if (ret == 0){
printf("---------------------model success-------------------\n");
}
}
VIDEO_FRAME_INFO_S resizeFrm;
ret = MppFrmResize(&frm, &resizeFrm, HAND_FRM_WIDTH, HAND_FRM_HEIGHT); //(1980,1080)->(640,384)
ret = Yolo2HandDetectResnetClassifyCal(g_workPlug.model, &resizeFrm, &frm); //主函数10
SAMPLE_CHECK_EXPR_GOTO(ret < 0, HAND_RELEASE,
"hand classify plug cal FAIL, ret=%#x\n", ret);
ret = HI_MPI_VO_SendFrame(voLayer, voChn, &frm, 0);
SAMPLE_CHECK_EXPR_GOTO(ret != HI_SUCCESS, HAND_RELEASE,
"HI_MPI_VO_SendFrame fail, Error(%#x)\n", ret);
MppFrmDestroy(&resizeFrm);
}
HAND_RELEASE:
ret = HI_MPI_VPSS_ReleaseChnFrame(g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0, &frm);
if (ret != HI_SUCCESS) {
SAMPLE_PRT("Error(%#x),HI_MPI_VPSS_ReleaseChnFrame failed,Grp(%d) chn(%d)!\n",
ret, g_aicMediaInfo.vpssGrp, g_aicMediaInfo.vpssChn0);
}
}
此函数的作用
HandClassifyAiProcess 函数的主要作用是进行图像帧的手部分类处理。它通过加载和应用手部检测模型(例如 YOLO2 手部分类模型),调整图像的尺寸,并通过模型推理来分类图像,最终将处理后的图像输出到显示层。
if (GetCfgBool("hand_classify_switch:support_hand_classify", true)) {
配置检查:
- 通过
GetCfgBool函数检查是否支持手部分类。hand_classify_switch:support_hand_classify是一个配置项,用于确定是否开启手部分类功能。如果该配置项为true,则继续执行手部分类任务。
if (g_workPlug.model == 0) {
ret = Yolo2HandDetectResnetClassifyLoad(&g_workPlug.model); // 主函数 8
if (ret == 0) {
printf("---------------------model success-------------------\n");
}
}
加载模型:
- 如果
g_workPlug.model为 0(即模型尚未加载),则调用Yolo2HandDetectResnetClassifyLoad函数加载 YOLO2 手部检测模型。加载成功后会打印model success。
VIDEO_FRAME_INFO_S resizeFrm;
ret = MppFrmResize(&frm, &resizeFrm, HAND_FRM_WIDTH, HAND_FRM_HEIGHT); //(1980,1080)->(640,384)
调整图像大小:
- 调用
MppFrmResize函数将输入帧frm调整为目标尺寸(如 640x384),并将调整后的图像存储在resizeFrm中。
ret = Yolo2HandDetectResnetClassifyCal(g_workPlug.model, &resizeFrm, &frm); // 主函数 10
SAMPLE_CHECK_EXPR_GOTO(ret < 0, HAND_RELEASE,
"hand classify plug cal FAIL, ret=%#x\n", ret);
进行推理:
- 使用已经加载的 YOLO2 手部检测模型对调整后的图像
resizeFrm进行推理,推理结果会存储在frm中。 - 如果推理失败(
ret < 0),则跳转到HAND_RELEASE进行资源释放。
ret = HI_MPI_VO_SendFrame(voLayer, voChn, &frm, 0);
SAMPLE_CHECK_EXPR_GOTO(ret != HI_SUCCESS, HAND_RELEASE,
"HI_MPI_VO_SendFrame fail, Error(%#x)\n", ret);
输出处理后的图像:
- 使用
HI_MPI_VO_SendFrame函数将处理后的图像帧frm发送到指定的视频输出层(voLayer)和通道(voChn),显示处理后的图像。 - 如果发送失败(
ret != HI_SUCCESS),则跳转到HAND_RELEASE进行资源释放。
主函数8调用的函数本体如下
HI_S32 Yolo2HandDetectResnetClassifyLoad(uintptr_t* model)//主函数9
{
SAMPLE_SVP_NNIE_CFG_S *self = NULL;
HI_S32 ret;
*model = 1;
// ret = CnnCreate(&self, MODEL_FILE_GESTURE); //不需要加载
// *model = ret < 0 ? 0 : (uintptr_t)self;
HandDetectInit(); // Initialize the hand detection model //支线1.3---重点---这才是加载yolov5模型的入口
SAMPLE_PRT("Load hand detect claasify model success\n");
/*
* Uart串口初始化
* Uart open init
*/
uartFd = UartOpenInit();
if (uartFd < 0) {
printf("uart1 open failed\r\n");
} else {
printf("uart1 open successed\r\n");
}
return ret;
}
Yolo2HandDetectResnetClassifyLoad 函数的作用是加载手部检测和分类模型,并进行一些必要的初始化工作。这包括初始化手部检测模型、打开串口(UART)等。
HandDetectInit(); // Initialize the hand detection model // 支线1.3---重点---这才是加载yolov5模型的入口
初始化手部检测模型:
- 调用
HandDetectInit函数来初始化手部检测模型。这是一个关键步骤,它实际完成了 YOLOv5 模型的加载和配置。HandDetectInit函数可能会加载 YOLOv5 模型的权重、配置文件以及初始化所需的其他资源。
/*
* Uart串口初始化
* Uart open init
*/
uartFd = UartOpenInit();
if (uartFd < 0) {
printf("uart1 open failed\r\n");
} else {
printf("uart1 open successed\r\n");
}
串口初始化:
调用 UartOpenInit 函数初始化串口(UART)。串口通常用于与外部设备(如调试控制台或传感器)进行通信。
如果串口初始化失败(uartFd < 0),则打印 “uart1 open failed”;否则,打印 “uart1 open successed”,表示串口已成功打开。
其中函数10的本体如下
HI_S32 Yolo2HandDetectResnetClassifyCal(uintptr_t model, VIDEO_FRAME_INFO_S *srcFrm, VIDEO_FRAME_INFO_S *dstFrm)//2 //cnnmodel,rezeimg,img
{
SAMPLE_SVP_NNIE_CFG_S *self = (SAMPLE_SVP_NNIE_CFG_S*)model;
HI_S32 resLen = 0;
int objNum;
int ret;
int num = 0;
ret = FrmToOrigImg((VIDEO_FRAME_INFO_S*)srcFrm, &img);
SAMPLE_CHECK_EXPR_RET(ret != HI_SUCCESS, ret, "hand detect for YUV Frm to Img FAIL, ret=%#x\n", ret);
objNum = HandDetectCal(&img, objs); // Send IMG to the detection net for reasoning
for (int i = 0; i < objNum; i++) {
cnnBoxs[i] = objs[i].box;
RectBox *box = &objs[i].box;
RectBoxTran(box, HAND_FRM_WIDTH, HAND_FRM_HEIGHT,
dstFrm->stVFrame.u32Width, dstFrm->stVFrame.u32Height);
SAMPLE_PRT("yolo5_out: {%d, %d, %d, %d} cls:%s, score:%f \n", box->xmin, box->ymin, box->xmax, box->ymax, classnamee[objs[i].cls], objs[i].score);
boxs[i] = *box;
}
biggestBoxIndex = GetBiggestHandIndex(boxs, objNum);
SAMPLE_PRT("biggestBoxIndex:%d, objNum:%d\n", biggestBoxIndex, objNum);
/*
* 当检测到对象时,在DSTFRM中绘制一个矩形
* When an object is detected, a rectangle is drawn in the DSTFRM
*/
if (biggestBoxIndex >= 0) {
objBoxs[0] = boxs[biggestBoxIndex];
MppFrmDrawRects(dstFrm, objBoxs, 1, RGB888_GREEN,8); // Target hand objnum is equal to 1
for (int j = 0; (j < objNum) && (objNum > 1); j++) {
if (j != biggestBoxIndex) {
remainingBoxs[num++] = boxs[j];
/*
* 其他手objnum等于objnum -1
* Others hand objnum is equal to objnum -1
*/
MppFrmDrawRects(dstFrm, remainingBoxs, objNum - 1, RGB888_RED, 8);
}
}
}
free(objs);
return 1;
}
Yolo2HandDetectResnetClassifyCal 函数的主要作用是使用 YOLO 模型对图像进行手部检测和分类推理,并根据检测结果在目标帧中绘制矩形框,标记出检测到的手部对象。
ret = FrmToOrigImg((VIDEO_FRAME_INFO_S*)srcFrm, &img);
SAMPLE_CHECK_EXPR_RET(ret != HI_SUCCESS, ret, "hand detect for YUV Frm to Img FAIL, ret=%#x\n", ret);
帧转换:
调用 FrmToOrigImg 将 YUV 格式的帧 srcFrm 转换为原始图像格式(例如 RGB),并将结果存储在 img 中。如果转换失败,打印错误信息并返回。
objNum = HandDetectCal(&img, objs); // Send IMG to the detection net for reasoning
手部检测推理:
调用 HandDetectCal 函数,将转换后的图像 img 传递给手部检测网络进行推理。返回值 objNum 表示检测到的手部对象数量,objs 是检测到的手部对象数组。
for (int i = 0; i < objNum; i++) {
cnnBoxs[i] = objs[i].box;
RectBox *box = &objs[i].box;
RectBoxTran(box, HAND_FRM_WIDTH, HAND_FRM_HEIGHT,
dstFrm->stVFrame.u32Width, dstFrm->stVFrame.u32Height);
SAMPLE_PRT("yolo5_out: {%d, %d, %d, %d} cls:%s, score:%f \n", box->xmin, box->ymin, box->xmax, box->ymax, classnamee[objs[i].cls], objs[i].score);
boxs[i] = *box;
}
处理检测结果:
对检测到的每个手部对象,存储其边界框(box)信息,并将框的坐标通过 RectBoxTran 函数转换为目标帧的尺寸。
打印每个检测框的信息,包括框的坐标(xmin, ymin, xmax, ymax),分类标签(cls)以及置信度(score)。
将每个检测框存储在 boxs[i] 中。
biggestBoxIndex = GetBiggestHandIndex(boxs, objNum);
SAMPLE_PRT("biggestBoxIndex:%d, objNum:%d\n", biggestBoxIndex, objNum);
找到最大框:
调用 GetBiggestHandIndex 函数,获取最大小的手部框的索引,并打印出最大的框的索引和检测到的对象数量。
if (biggestBoxIndex >= 0) {
objBoxs[0] = boxs[biggestBoxIndex];
MppFrmDrawRects(dstFrm, objBoxs, 1, RGB888_GREEN, 8); // Target hand objnum is equal to 1
- 绘制最大检测框:
- 如果检测到的手部对象数量大于 0,选择最大的框(通过
biggestBoxIndex获取),并在目标帧dstFrm中绘制一个绿色的矩形框,标记出最大的手部对象。
- 如果检测到的手部对象数量大于 0,选择最大的框(通过
for (int j = 0; (j < objNum) && (objNum > 1); j++) {
if (j != biggestBoxIndex) {
remainingBoxs[num++] = boxs[j];
MppFrmDrawRects(dstFrm, remainingBoxs, objNum - 1, RGB888_RED, 8);
}
}
}
绘制其他检测框:
- 对于其他的检测到的手部框(排除最大的框),将它们存储在
remainingBoxs中,并在目标帧dstFrm上绘制红色的矩形框。
其中
objNum = HandDetectCal(&img, objs); // Send IMG to the detection net for reasoning
的HandDetectCal函数本体如下
HI_S32 HandDetectCal(IVE_IMAGE_S *srcYuv, DetectObjInfo resArr[]) //主函数11 srcYuv是图像
{
int ret = HandDetect(g_handModel, srcYuv, resArr);
return ret;
}
此处开始套娃
static HI_S32 HandDetect(uintptr_t model, IVE_IMAGE_S *srcYuv, DetectObjInfo boxs[])//主函数12
{
SAMPLE_SVP_NNIE_CFG_S *self = (SAMPLE_SVP_NNIE_CFG_S*)model;
int objNum;
int ret = Yolo2CalImg(self, srcYuv, boxs, DETECT_OBJ_MAX, &objNum); //yolov2模型, 图像, bbox,32 // detect max obj,int?
if (ret < 0) {
SAMPLE_PRT("Hand detect Yolo2CalImg FAIL, for cal FAIL, ret:%d\n", ret);
return ret;
}
return objNum;
}
调用Yolo2CalImg,此函数在ai_infer_process.c中
int Yolo2CalImg(SAMPLE_SVP_NNIE_CFG_S* self,
const IVE_IMAGE_S *img, DetectObjInfo resBuf[], int resSize, int* resLen) // 主函数10 //yolov2模型, 图像, bbox,32最大框数detect max obj,*int
{
SAMPLE_SVP_NNIE_INPUT_DATA_INDEX_S stInputDataIdx = {0};
SAMPLE_SVP_NNIE_PROCESS_SEG_INDEX_S stProcSegIdx = {0};
HI_S32 s32Ret;
yolo_result *output_result = NULL;
/*
* 填充源数据
* Fill src data
*/
self->pszPic = NULL;
stInputDataIdx.u32SegIdx = 0;
stInputDataIdx.u32NodeIdx = 0;
s32Ret = FillNnieByImg(self, &g_stYolov2NnieParam, 0, 0, img); // 主函数11
SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret, YOLOV2_FAIL_0, SAMPLE_SVP_ERR_LEVEL_ERROR,
"Error, SAMPLE_SVP_NNIE_FillSrcData failed!\n");
/*
* NNIE推理(process the 0-th segment)
* NNIE process(process the 0-th segment)
*/
stProcSegIdx.u32SegIdx = 0;
s32Ret = SAMPLE_SVP_NNIE_Forward(&g_stYolov2NnieParam, &stInputDataIdx, &stProcSegIdx, HI_TRUE);
SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret, YOLOV2_FAIL_0, SAMPLE_SVP_ERR_LEVEL_ERROR,
"Error, SAMPLE_SVP_NNIE_Forward failed!\n");
yolov5__process(&g_stYolov2NnieParam, resBuf, resLen);
return 0;
YOLOV2_FAIL_0:
return -1;
}
更多推荐



所有评论(0)