将新的 cv::Mat 喂入 vx_graph

Feeding a new cv::Mat into a vx_graph

给定的示例代码如 in this previous question(为简洁起见删除了错误检查):

vx_image inputImage = vxCreateImage( graph, width, height, VX_DF_IMAGE_S16 );
vx_image outputImage = vxCreateImage( graph, width, height, VX_DF_IMAGE_S16 );
vx_graph graph = vxCreateGraph( context );
vx_image intermediate1 = vxCreateVirtualImage( graph, width, height, VX_DF_IMAGE_S16 );
vx_image intermediate2 = vxCreateVirtualImage( graph, width, height, VX_DF_IMAGE_S16 );
vx_image intermediate3 = vxCreateVirtualImage( graph, width, height, VX_DF_IMAGE_S16 );

vxSobel3x3Node(graph,inputImage,intermediate1,intermediate2);
vxMagnitudeNode(graph,intermediate1,intermediate2,intermediate3);
vxConvertDepthNode(graph,intermediate3,outputImage,VX_CONVERT_POLICY_WRAP,0);    

vxVerifyGraph( graph );

vxProcessGraph( graph );

以及经典的OpenCV阅读视频循环:

cv::VideoCapture cap;
cap.open("/Testing/test.avi");
for(;;)
{
    cv::Mat frame;
    cap >> frame;
    if( frame.empty() ) break;
    // TODO: what goes here?
    vxProcessGraph( graph );
}

如何将 frame 放入 inputImage 以便正确调用 vxProcessGraph()?我知道:

vx_image image = nvx_cv::createVXImageFromCVMat(frame);

是获得 vx_image 的帮手,但我似乎无法找到下一步该做什么的示例。我阅读的一些 NVidia 文档建议:

vxAccessImagePatch(...);
// copy pixel-by-pixel??
vxCommitImagePatch(...);

然而,这似乎有点过于暴力,那么有没有更好的方法(vxSetParameter,也许,但文档非常不清楚)来做到这一点?

可以创建仅引用存储在 cv::Mat 中的数据的 vx_image。使用 vx_image 访问数据的东西最终会实际访问存储在 Mat 中的数据。此方法仅使用已记录的 OpenCV 和 OpenVX functions. From this Intel documentation:

vx_image get_vx_image_from_Mat(vx_context graph, cv::Mat &mat) {
    vx_imagepatch_addressing_t frame_format {};
    frame_format.dim_x = mat.cols;
    frame_format.dim_y = mat.rows;
    return vxCreateImageFromHandle(graph, 
                                   VX_DF_IMAGE_S16, 
                                   &format, 
                                   &((void*)mat.data),
                                   VX_IMPORT_TYPE_HOST);
} 

据推测,cv:Mat 至少需要与以这种方式创建的 vx_image 一样长的时间存在。

我设法找到了解决方案,因为让我困惑的是示例中使用了官方 API 中没有的 helper function

vx_status vxAddParameterToGraphByIndex(vx_graph g, vx_node n, vx_uint32 index)
{
    vx_parameter p = vxGetParameterByIndex(n, index);
    vx_status status = vxAddParameterToGraph(g, p);
    vxReleaseParameter(&p);
    return status;
}

现在,我上面的示例代码需要快速修改:

vx_node sobel = vxSobel3x3Node(graph,inputImage,intermediate1,intermediate2);

然后是魔法线:

vxAddParameterToGraphByIndex(graph, sobel, 0);

这里的0表示sobel节点的第0个参数,不包括graph本身。

接下来,我的循环变成:

if( frame.empty() ) break;
vx_image image = nvx_cv::createVXImageFromCVMat(frame);
vxSetGraphParameterByIndex(graph, 0, (vx_reference) image);
vxProcessGraph( graph );
vxReleaseImage(&image);

在这里,0 表示我们添加到图中的第 0 个参数。如果我访问了上面的vx_parameter p,那么不友好的情况会稍微少一些:

vxSetParameterByIndex(p, (vx_reference) image);

这可能会单独起作用,但我不知道是否需要做额外的工作来通知 vx_graph 更改。