OpenVX 数据处理与跨框架互操作性解析
1. OpenVX 数据输入输出
在处理 OpenVX 数据时,高效的输入输出操作至关重要。以下是一些关键的操作和函数:
-
映射张量
:
- 对于
vx_tensor
对象,有映射和取消映射函数。这些函数与图像和重映射对象的对应函数类似,获取的数据是对象数据的一部分,即“补丁”。不同的是,图像和重映射补丁是二维的,而张量补丁是 n 维的,维度数最高可达
VX_CONTEXT_MAX_TENSOR_DIMS
(至少为 4)。
-
vxMapTensorPatch
函数用于映射张量补丁,其参数如下:
vx_status vxMapTensorPatch(
vx_tensor tensor,
vx_size number_of_dims,
const vx_size* view_start,
const vx_size* view_end,
vx_map_id* map_id,
vx_size* stride,
void** ptr,
vx_enum usage,
vx_enum mem_type);
- 参数说明:
- `tensor`:张量本身。
- `number_of_dims`:张量的维度数。
- `view_start` 和 `view_end`:定义要检索的 n 维长方体的角点,每个是包含 `number_of_dims` 个元素的索引数组。若传入 `NULL`,`view_start` 默认全为 0 的数组,`view_end` 默认张量的全维度。
- `map_id`、`stride` 和 `ptr`:函数的输出值,描述映射到用户空间的补丁。`map_id` 用于取消映射,`ptr` 指向补丁的左上角(前端等),`stride` 是另一个 n 维数组,表示在相应维度上从一个元素到下一个元素的字节距离。
- 使用完补丁后,使用 `vxUnmapTensorPatch(tensor, map_id)` 取消映射。
-
复制张量补丁
:
-
vxCopyTensorPatch函数用于复制张量补丁,参数如下:
-
vx_status vxCopyTensorPatch(
vx_tensor tensor,
vx_size number_of_dims,
const vx_size* view_start,
const vx_size* view_end,
const vx_size* user_stride,
void* user_ptr,
vx_enum usage,
vx_enum user_memory_type);
- 参数说明:
- `view_start`、`view_end` 和 `user_stride` 是输入参数,每个都是包含 `number_of_dims` 个元素的数组,描述应用程序空间中要复制的数据区域。
2. 数据访问的最佳实践
在实际应用中,为了提高性能和降低功耗,需要注意以下几点:
-
减少数据访问量
:只访问所需的数据部分,避免访问整个图像、数组或张量。
-
选择高效的访问模式
:根据具体需求选择合适的访问模式,尽量减少数据复制。
-
合理使用映射和取消映射函数
:避免过度使用这些函数,以免导致额外的数据复制和性能下降。
3. OpenVX 与 OpenCV 的互操作性
OpenCV 是广泛使用的计算机视觉库,OpenVX 设计为可与 OpenCV 一起使用。两者的可能用例分为两类:
-
OpenCV 在 OpenVX 图外使用
:用于创建输入数据或处理输出数据,例如在桌面平台上处理网络摄像头视频流的应用程序中,OpenCV 可用于获取视频流并将其提供给 OpenVX 图。
-
OpenCV 在 OpenVX 图内使用
:用于实现用户节点,对于中等复杂度的管道,开发者可能需要使用用户节点。
4. 将 OpenCV 图像转换为 OpenVX 图像
可以使用 VXA 库中的
vxa_cv2vx
函数将 OpenCV 图像转换为 OpenVX 图像,代码如下:
vx_image vxa_cv2vx(const cv::Mat& cv_img, vx_context context)
{
vx_df_image img_type;
switch(cv_img.type())
{
case CV_8UC1:
img_type = VX_DF_IMAGE_U8;
break;
case CV_8UC3:
img_type = VX_DF_IMAGE_RGB;
break;
default:
return(NULL);
}
int width = cv_img.cols, height = cv_img.rows;
vx_image image = vxCreateImage(context, width, height, img_type);
vx_rectangle_t roi;
roi.start_x = 0;
roi.start_y = 0;
roi.end_x = width;
roi.end_y = height;
vx_map_id map_id;
vx_imagepatch_addressing_t addr;
unsigned char* ptr;
vx_status status = vxMapImagePatch(image, &roi, 0, &map_id, &addr,
(void**)&ptr, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X);
if(status != VX_SUCCESS)
{
VXA_PRINT("vxMapImagePatch returned error with code %d\n", status);
return(NULL);
}
if(addr.stride_x != 1 && addr.stride_x != 3)
{
VXA_PRINT("addressing structure not supported, stride_x = %d\n",
addr.stride_x);
return(0);
}
for(int y = 0; y < height; y++)
{
unsigned char* ptr_y = ptr + y*addr.stride_y;
memcpy(ptr_y, cv_img.ptr(y), addr.stride_y);
}
vxUnmapImagePatch(image, map_id);
return image;
}
操作步骤如下:
1. 检查 OpenCV 图像类型,仅支持 8 位灰度和 RGB 彩色图像。
2. 创建具有相同维度的 OpenVX 图像。
3. 准备数据并调用
vxMapImagePatch
函数,以写入模式映射图像。
4. 检查图像布局,确保 OpenVX 图像使用密集像素打包。
5. 逐行复制数据。
6. 调用
vxUnmapImagePatch
释放主机内存。
5. 将 OpenVX 图像转换为 OpenCV 图像
使用 VXA 库中的
vxa_vx2cv
函数将 OpenVX 图像转换为 OpenCV 图像,代码如下:
int vxa_vx2cv(vx_image image, cv::Mat& cv_img)
{
int width, height;
vxQueryImage(image, VX_IMAGE_WIDTH, &width, 4);
vxQueryImage(image, VX_IMAGE_HEIGHT, &height, 4);
vx_df_image img_type;
vxQueryImage(image, VX_IMAGE_FORMAT, &img_type, 4);
int cv_type;
switch(img_type)
{
case VX_DF_IMAGE_U8:
cv_type = CV_8UC1;
break;
case VX_DF_IMAGE_RGB:
cv_type = CV_8UC3;
break;
default:
VXA_PRINT("Format %d not supported\n", img_type);
return(-1);
}
vx_rectangle_t roi;
roi.start_x = 0;
roi.start_y = 0;
roi.end_x = width;
roi.end_y = height;
vx_map_id map_id;
vx_imagepatch_addressing_t addr;
unsigned char* ptr;
vx_status status = vxMapImagePatch(image, &roi, 0, &map_id, &addr,
(void**)&ptr, VX_READ_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X);
if(status != VX_SUCCESS)
{
VXA_PRINT("vxMapImagePatch returned error with code %d\n", status);
return(-1);
}
if(addr.stride_x != 1 && addr.stride_x != 3)
{
VXA_PRINT("addressing structure not supported, stride_x = %d\n",
addr.stride_x);
return(0);
}
cv_img = cv::Mat(height, width, cv_type);
for(int y = 0; y < height; y++)
{
unsigned char* ptr_y = ptr + y*addr.stride_y;
memcpy(cv_img.ptr(y), ptr_y, addr.stride_y);
}
status = vxUnmapImagePatch(image, map_id);
if(status != VX_SUCCESS)
{
VXA_PRINT("vxUnmapImagePatch failed...\n");
return(0);
}
return 1;
}
操作步骤如下:
1. 获取 OpenVX 图像的维度和类型。
2. 根据图像类型确定 OpenCV 图像类型,仅支持 8 位灰度和 RGB 彩色图像。
3. 准备数据并调用
vxMapImagePatch
函数,以只读模式映射图像。
4. 检查图像布局,确保 OpenVX 图像使用密集像素打包。
5. 创建具有相同维度和类型的 OpenCV 图像,并逐行复制数据。
6. 调用
vxUnmapImagePatch
释放主机内存。
6. 转换其他数据类型
除了图像,VXA 库还可以处理将 OpenCV 准备的重映射数据结构导入到 OpenVX 中。使用
vxa_import_opencv_remap
函数,代码如下:
int vxa_import_opencv_remap(const char* filename, const char* nodename,
vx_context context, vx_remap* remap, int* _dst_width, int* _dst_height)
{
FileStorage fs(filename, FileStorage::READ);
Mat cv_remap;
fs[nodename] >> cv_remap;
int src_width, src_height, dst_width, dst_height;
fs[(std::string(nodename) + std::string("_src_width")).c_str()] >> src_width;
fs[(std::string(nodename) + std::string("_src_height")).c_str()] >> src_height;
fs[(std::string(nodename) + std::string("_dst_width")).c_str()] >> dst_width;
fs[(std::string(nodename) + std::string("_dst_height")).c_str()] >> dst_height;
if(cv_remap.type() != CV_32FC2)
{
return(0);
}
vx_rectangle_t roi;
roi.start_x = 0;
roi.start_y = 0;
roi.end_x = cv_remap.cols;
roi.end_y = cv_remap.rows;
*remap = vxCreateRemap(context, src_width, src_height,
dst_width, dst_height);
if(vxCopyRemapPatch(*remap, &roi, cv_remap.step, cv_remap.ptr(),
VX_TYPE_COORDINATES2DF, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST) != VX_SUCCESS)
{
return(0);
}
return 1;
}
操作步骤如下:
1. 从文件中读取 OpenCV 重映射矩阵。
2. 检查矩阵类型是否为
CV_32FC2
。
3. 创建 OpenVX 重映射转换。
4. 使用
vxCopyRemapPatch
函数将数据从 OpenCV 复制到 OpenVX。
7. 总结
通过上述操作和函数,可以实现 OpenVX 与 OpenCV 之间的数据高效转换和互操作。在实际应用中,需要根据具体需求选择合适的方法和函数,以提高性能和降低功耗。同时,要注意避免不必要的数据复制,合理使用映射和取消映射函数。
以下是将 OpenCV 图像转换为 OpenVX 图像的流程图:
graph TD;
A[开始] --> B[检查 OpenCV 图像类型];
B -- 8 位灰度或 RGB --> C[创建 OpenVX 图像];
B -- 其他类型 --> D[返回错误];
C --> E[准备数据并映射图像];
E -- 映射成功 --> F[检查图像布局];
F -- 布局支持 --> G[逐行复制数据];
F -- 布局不支持 --> D;
G --> H[释放主机内存];
H --> I[结束];
E -- 映射失败 --> D;
通过这些操作和方法,可以更好地利用 OpenVX 和 OpenCV 的优势,实现高效的计算机视觉应用。
OpenVX 数据处理与跨框架互操作性解析
8. OpenVX 与 OpenCL 的互操作性
在实际开发中,软件开发者常倾向于使用标准编程 SDK 来加速应用。当遇到超出标准 OpenVX 函数的应用场景,如特定的预处理、后处理以及难以映射到标准 OpenVX 函数的新算法时,可利用 OpenVX 用户内核实现这些算法并插入到 OpenVX 图中,以享受图优化带来的好处。然而,目前 OpenVX 标准仅支持可在主机上调度的用户内核,使用
vxCopyXxx
或
vxMapXxx/vxUnmapXxx
API 在 OpenVX 与其他编程 SDK 之间交换数据缓冲区时,会导致目标设备与主机之间的数据来回复制,影响性能。
为解决这些效率问题,OpenVX 支持通过
vxCopyXxx
、
vxMapXxx/vxUnMapXxx
、
vxCreateXxxFromHandle
和
vxSwapXxxHandle
API 交换内存句柄。下面介绍 OpenCL 的基础知识以及 OpenVX 与 OpenCL 应用之间的互操作机制。
9. OpenCL 基础
OpenCL 是用于异构计算的开放标准,以下是其主要组成部分:
-
OpenCL C 程序
:基于 C 语言扩展的编程语言,用于编写在 OpenCL 设备上执行的内核代码。
-
OpenCL 上下文
:管理 OpenCL 设备、内存对象和命令队列的环境。
-
OpenCL 即时编译器
:在运行时将 OpenCL C 代码编译为设备可执行的代码。
-
OpenCL 缓冲区
:用于在主机和设备之间传输数据的内存对象。
-
OpenCL 内核执行
:通过命令队列将内核代码发送到设备上执行。
10. OpenVX 与 OpenCL 的互操作
OpenVX 与 OpenCL 的互操作主要涉及以下方面:
-
具有 OpenCL 互操作性的 OpenVX 上下文
:创建支持 OpenCL 互操作的 OpenVX 上下文,以便在 OpenVX 中使用 OpenCL 资源。
-
OpenCL 缓冲区访问
:通过 OpenVX API 访问 OpenCL 缓冲区,实现数据的共享和传输。
-
使用 OpenCL 加速的用户内核
:在 OpenVX 用户内核中使用 OpenCL 进行加速,提高计算性能。
11. 互操作示例
以下是一个简单的示例,展示如何在 OpenVX 中使用 OpenCL 缓冲区:
// 创建 OpenCL 上下文和缓冲区
cl_context cl_context = create_cl_context();
cl_mem cl_buffer = create_cl_buffer(cl_context);
// 创建具有 OpenCL 互操作性的 OpenVX 上下文
vx_context vx_context = vxCreateContextWithCL(cl_context);
// 创建 OpenVX 图像对象
vx_image vx_image = vxCreateImageFromHandle(vx_context, VX_DF_IMAGE_U8, width, height, cl_buffer);
// 执行 OpenVX 图
vx_graph vx_graph = vxCreateGraph(vx_context);
// 添加节点和连接
// ...
vxScheduleGraph(vx_graph);
vxWaitGraph(vx_graph);
// 释放资源
vxReleaseImage(&vx_image);
vxReleaseGraph(&vx_graph);
vxReleaseContext(&vx_context);
clReleaseMemObject(cl_buffer);
clReleaseContext(cl_context);
操作步骤如下:
1. 创建 OpenCL 上下文和缓冲区。
2. 创建具有 OpenCL 互操作性的 OpenVX 上下文。
3. 使用
vxCreateImageFromHandle
函数从 OpenCL 缓冲区创建 OpenVX 图像对象。
4. 创建并执行 OpenVX 图。
5. 释放所有资源。
12. 总结
OpenVX 与 OpenCL 的互操作性为开发者提供了更多的选择和灵活性。通过合理利用 OpenCL 的并行计算能力,可以显著提高 OpenVX 应用的性能。在实际应用中,需要根据具体需求选择合适的互操作方式,避免不必要的数据复制和性能损失。
以下是 OpenVX 与 OpenCL 互操作的流程图:
graph TD;
A[创建 OpenCL 上下文和缓冲区] --> B[创建具有 OpenCL 互操作性的 OpenVX 上下文];
B --> C[从 OpenCL 缓冲区创建 OpenVX 图像对象];
C --> D[创建并执行 OpenVX 图];
D --> E[释放所有资源];
通过以上对 OpenVX 与 OpenCV、OpenCL 的互操作性的介绍,我们可以看到在不同的计算机视觉和计算场景中,可以根据具体需求选择合适的框架和方法,实现高效的数据处理和计算。在实际开发中,要充分考虑性能、资源利用和代码复杂度等因素,以达到最佳的开发效果。
下面是一个对比 OpenVX 与 OpenCV、OpenCL 互操作性特点的表格:
| 互操作性类型 | 优点 | 缺点 | 适用场景 |
| ---- | ---- | ---- | ---- |
| OpenVX 与 OpenCV | 易于实现,利用 OpenCV 丰富的功能 | 可能存在数据复制开销 | 处理常见的计算机视觉任务,结合 OpenCV 现有算法 |
| OpenVX 与 OpenCL | 利用 OpenCL 的并行计算能力,提高性能 | 实现复杂度较高 | 需要大规模并行计算的场景,如深度学习推理 |
超级会员免费看
30

被折叠的 条评论
为什么被折叠?



