This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] J721S2XSOMXEVM:TIDL 流水线上绘制检测模块的输出行为

Guru**** 2468460 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1464735/j721s2xsomxevm-weired-output-behavior-of-draw-detection-module-on-tidl-pipeline

器件型号:J721S2XSOMXEVM

工具与软件:

您好、TI 专家!

我正在实施一个参考 app_tidl_od_cam 和 app_tidl_od 演示应用的自定义 tidl 应用。

该应用程序接收从另一个与之并行运行的应用程序捕获的 nv12图像。

流水线如下所示

收到的 NV12图像->缩放节点-->(输出1) TIDL 节点-> DrawDetections 节点-> Mosaic 节点->显示节点
                               |                      |
                               -->(output2)-------------------------------------------------------

显示屏是非常必要的、看起来像是 DrawDetection Node 处理索引错误的缓冲区。
e2e.ti.com/.../20250121_5F00_drawdetect_5F00_image_5F00_buffer_5F00_issue.mp4

如果我在 DrawDetection Node 的输入直接进入 Display Node 时改变流量、则显示效果为 Find。

收到的 NV12图像->缩放节点-->(输出1) TIDL 节点-> DrawDetections 节点-> Mosaic 节点
                               |                      
                               -->(output2)--------------- > 显示节点

e2e.ti.com/.../20250121_5F00_scaler_5F00_to_5F00_display.mp4

所以我想标量的输出是可以的、但是  DrawDetection Node 可能有问题。

下面是相关的代码片段。 (从 vision_apps/modules 和 app_tidl_od_cam 使用的内核模块 API)

static vx_status app_init(AppObj *obj)
{
    vx_status status = VX_SUCCESS;

    /* Create OpenVx Context */
    obj->context = vxCreateContext();
    status = vxGetStatus((vx_reference) obj->context);

    if(status == VX_SUCCESS)
    {
        tivxHwaLoadKernels(obj->context);
        tivxImgProcLoadKernels(obj->context);
        tivxTIDLLoadKernels(obj->context);
        tivxVideoIOLoadKernels(obj->context);
    }

    /* Initialize modules */
    app_init_scaler(obj->context, &obj->scalerObj, "scaler_obj", 1, 2);
    app_init_tidl(obj->context, &obj->tidlObj, "tidl_obj", 1);
    app_update_pre_proc(obj->context, &obj->preProcObj, obj->tidlObj.config, 1);
    app_init_pre_proc(obj->context, &obj->preProcObj, "pre_proc_obj");
    app_update_draw_detections(&obj->drawDetectionsObj, obj->tidlObj.config);
    app_init_draw_detections(obj->context, &obj->drawDetectionsObj, "draw_detections_obj", 1);
    app_init_img_mosaic(obj->context, &obj->imgMosaicObj, "img_mosaic_obj", 4);
    app_init_display(obj->context, &obj->displayObj, "display_obj");

    return status;
}


static vx_status app_create_graph(AppObj *obj)
{
    vx_status status = VX_SUCCESS;
    vx_graph_parameter_queue_params_t graph_parameters_queue_params_list[2];
    vx_int32 graph_parameter_index;

    obj->graph = vxCreateGraph(obj->context);
    status = vxGetStatus((vx_reference)obj->graph);
    vxSetReferenceName((vx_reference)obj->graph, "app_tidl_od_cam_graph");

    app_create_graph_scaler_single(obj->context, obj->graph, &obj->scalerObj, obj->imgs[0]);
    app_create_graph_pre_proc(obj->graph, &obj->preProcObj, obj->scalerObj.output[0].arr);
    app_create_graph_tidl(obj->context, obj->graph, &obj->tidlObj, obj->preProcObj.output_tensor_arr);

    status = app_create_graph_draw_detections(obj->graph, &obj->drawDetectionsObj, obj->tidlObj.output_tensor_arr[0], obj->scalerObj.output[1].arr);
    obj->draw_detect_output_img = (vx_image)vxGetObjectArrayItem((vx_object_array)obj->drawDetectionsObj.output_image_arr, 0);

    vx_int32 idx = 0;
    obj->imgMosaicObj.input_arr[idx++] = obj->drawDetectionsObj.output_image_arr;
    obj->imgMosaicObj.num_inputs = idx;

    app_create_graph_img_mosaic(obj->graph, &obj->imgMosaicObj, NULL);
 
    //obj->display_image = (vx_image)vxGetObjectArrayItem(obj->scalerObj.output[1].arr, 0);
    obj->display_image = obj->draw_detect_output_img;
    //obj->display_image = obj->imgMosaicObj.output_image[0];
    status = app_create_graph_display(obj->graph, &obj->displayObj, obj->display_image);

    if(status == VX_SUCCESS)
    {
        graph_parameter_index = 0;
        add_graph_parameter_by_node_index(obj->graph, obj->scalerObj.node, 0);
        obj->scalerObj.graph_parameter_index = graph_parameter_index;
        graph_parameters_queue_params_list[graph_parameter_index].graph_parameter_index = graph_parameter_index;
        graph_parameters_queue_params_list[graph_parameter_index].refs_list_size = obj->imgs_num;
        graph_parameters_queue_params_list[graph_parameter_index].refs_list = (vx_reference*)&obj->imgs[0];
        graph_parameter_index++;

        vxSetGraphScheduleConfig(obj->graph,
                VX_GRAPH_SCHEDULE_MODE_QUEUE_AUTO,
                graph_parameter_index,
                graph_parameters_queue_params_list);

        tivxSetGraphPipelineDepth(obj->graph, APP_PIPELINE_DEPTH);

        tivxSetGraphPipelineDepth(obj->graph, 5);

        tivxSetNodeParameterNumBufByIndex(obj->scalerObj.node, 1, 4);
        tivxSetNodeParameterNumBufByIndex(obj->scalerObj.node, 2, 4);

        printf("Pipeline params setup done!\n");
    }
	
	return status;
}

 

您能告诉我导致问题的原因吗?

此致、

Juhyun

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Junhyun:

     您是否使用对象数组作为绘图节点的输入或输出?  

    此致、

    Brijesh

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Brijesh:

    是的、输入和输出都是 vx_object_array。

    但我使用 vx_image 数组作为标量输入,而不是用于 app_create_graph_scaler() API 的 vx_object_array。

    我之所以将其更改为 vx_image、是因为源映像来自另一个应用程序、即 vx_reference (vx_image)、
    当时我不知道如何用现有的 vx_images 创建 vx_object_array 而且摄像机通道是单一的。

    然后我发现  app_create_graph_scaler()似乎只获得并使用 vx_object_array 作为输入传递的第一个元素、
    所以我决定制作一个 API 的副本、用 vx_image 替换输入类型。 在该过程中,我还删除了 vxReplicatedNode ,因为它一直抱怨某种缺少 vx_object_array 类型。 我认为通道是单通道的、因此可以。

    相关代码是、

    app_create_graph_scaler_single(obj->context, obj->graph, &obj->scalerObj, obj->imgs[0]);

    app_create_graph_scaler()的副本 如下所示。

    该图几乎与 app_tidl_od 中的图形相似、因此我在该应用中进行了测试、发现将标量输入类型从 vx_object_array 更改为 vx_image 会导致来回闪烁显示问题。

    我仍然不知道为什么会发生,但至少找出了原因,所以进入了 vx_object_array 问题。

    幸运的是,我可以设法解决它,感谢 

    https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1463767/j721s2xsomxevm-vxobjectarray-with-existing-vx_reference/5624248?tisearch=e2e-sitesearch&keymatch=%2520user%253A611727#5624248

    将 vx_object_array 用于标量输入和原始 app_create_graph_scaler()后、显示问题已得到解决。

    这一定是因为我对 OpenVX/TIOVX 框架缺乏了解,但仍然很难理解为什么 vx_obejct_array 会导致这个问题,即使通道是单一的。

    现在问题已经解决了、能否就此给我一些解释?

    此致、

    Juhyun

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    我将其更改为 vx_image 的原因是源映像来自另一个应用程序、即 vx_reference (vx_image)、
    当时我不知道如何使用现有的 vx_images 创建 vx_object_array、而且摄像机通道是单一的。[/报价]

    但在本例中您的节点是否会被复制? 如果您将其用于单摄像头用例、 请不要为此节点调用 replicateNode API。  

    此致、

    Brijesh

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    不是。 我删除了  app_create_graph_scaler_single()中的 vxReplicateNode 、它是 app_create_graph_scaler()的副本。

    但是在模块的其余创建 API 中、如 PreProc、TIDL、DrawDetection、vxReplicateNode 在原始代码中被调用、而不管通道的数量是多少、我没有触摸它、因此这些模块仍然称为 vxReplicatedNode。

    实际上 ,我想知道他们,这些 vxReplicateNode 在这种情况下的目的和作用是什么?

    此致、

    Juhyun

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Junyun:

    仅复制节点不是问题、而是复制将对象数组作为参数且该对象数组具有多个元素大小的节点、这可能是单个摄像机应用程序的问题。  

    此致、

    Brijesh

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Brijesh:

    我按照模块 API 使用 TIOVX 内核、这些 API 在 vision_apps/modules 和 vision_apps/apps/dl_demos/app_tidl_od 中提供、使用的方法是 app_tidl_od。

    用于 tiovx 内核 API 的大多数对象数组似乎由模块 API 本身进行管理、我检查这些对象数组的大小全部为1。
    此外、对于其余的对象数组、我不是使用多个元素手动创建的。

    我刚才做的是将  app_create_graph_scaler()的 vx_object_array 输入参数更改为 vx_image、并在例程中删除 vxReplicateNode 调用。

    此致、

    Juhyun

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Juhunyun 、您好!

    本质上、对于复制的所有参数、请确保在调用复制节点时使用大小为的对象数组。 或者、为了更安全、您可以尝试禁用 对复制节点 API 的调用。  

    此致、

    Brijesh

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的、我明白了。 感谢您发送编修。

    此致、

    Juhyun