OpenVX 高效数据输入输出指南
1. 数据所有权与映射规则
在处理数据时,应用程序在调用映射函数之前,对数据没有访问权或“所有权”。调用映射函数后,应用程序获得数据的“所有权”,可以对其进行任意操作。操作完成后,应用程序应取消映射,将数据所有权交还给 OpenVX。
需要注意的是,如果不遵循这些所有权规则,程序可能无法按预期运行。例如,使用完对象后忘记取消映射,接着在 OpenVX 图中使用该对象,对象可能不会反映更新,不同的实现方式可能会有不同的表现。
另外,不能映射虚拟对象。虚拟对象允许实现进行优化,甚至消除对象的存在,因此映射虚拟对象没有意义。将对象声明为虚拟对象意味着承诺不会映射该对象以查看其内容,这样 OpenVX 可以对其进行优化。如果尝试映射虚拟对象,根据具体实现,可能会出现错误、正常工作或出现奇怪的行为。反之,如果有永远不会映射的对象,应将其声明为虚拟对象,以便 OpenVX 进行最佳优化。
2. 映射图像补丁
以
vx_image
函数为例,深入讨论映射和取消映射操作,其他对象的映射和取消映射行为类似。
vx_image
对象的映射函数是
vxMapImagePatch
,用于访问图像的小部分或矩形“补丁”。如果应用程序允许,映射图像的小子集会更高效。
vxMapImagePatch
函数的头文件和参数如下:
vx_status vxMapImagePatch(
vx_image image,
const vx_rectangle_t* rect,
vx_uint32 plane_index,
vx_map_id* map_id,
vx_imagepatch_addressing_t* addr,
void** ptr,
vx_enum usage,
vx_enum mem_type,
vx_uint32 flags);
参数说明如下表:
| 参数 | 说明 |
| ---- | ---- |
|
image
| 要访问的图像对象 |
|
rect
| 定义要访问的图像补丁的坐标,必须在图像范围内 |
|
plane_index
| 指示要访问的图像平面,单平面图像使用 0 |
|
map_id
| 用于标识检索的补丁,取消映射时需要 |
|
addr
| 图像补丁寻址结构,由 OpenVX 提供数据组织信息 |
|
ptr
| 指向映射调用检索的实际补丁数据的指针 |
|
usage
| 告诉 OpenVX 应用程序如何使用补丁数据,可选值为
VX_READ_ONLY
、
VX_READ_AND_WRITE
、
VX_WRITE_ONLY
|
|
mem_type
| 告诉 OpenVX 要将图像补丁映射到的内存类型,标准中合法值为
VX_MEMORY_TYPE_HOST
|
|
flags
| 主要用于供应商扩展,通常使用 0,另一个可能的值是
VX_NOGAP_X
|
以下是操作步骤:
1. 确定要访问的图像补丁,设置
image
、
rect
和
plane_index
参数。
2. 调用
vxMapImagePatch
函数,获取
map_id
、
addr
和
ptr
。
3. 根据
usage
参数的设置,对图像补丁进行相应的读写操作。
4. 操作完成后,调用
vxUnmapImagePatch(image, map_id)
取消映射。
OpenVX 提供了两个函数来帮助访问映射图像中的单个像素:
-
vxFormatImagePatchAddress1d
:将像素视为一维数组,访问第 i 个像素。
for (i = 0; i < addr.dim_x*addr.dim_y; i++) {
vx_uint8 *ptr2 = vxFormatImagePatchAddress1d(ptr, i, &addr);
*ptr2 = MY_NEW_VALUE;
}
-
vxFormatImagePatchAddress2d:以 (x, y) 方式访问像素,将其视为二维数组。
for (y = 0; y < addr.dim_y; y+=addr.step_y) {
for (x = 0; x < addr.dim_x; x+=addr.step_x) {
vx_uint8 *ptr2 = vxFormatImagePatchAddress2d(ptr, x, y, &addr);
*ptr2 = MY_NEW_VALUE;
}
}
如果只是想将图像补丁从图像对象复制到主机内存,或从主机内存复制到图像对象,可以使用
vxCopyImagePatch
函数:
vx_status vxCopyImagePatch(
vx_image image,
const vx_rectangle_t* rect,
vx_uint32 plane_index,
const vx_imagepatch_addressing_t* user_addr,
void* user_ptr,
vx_enum usage,
vx_enum user_mem_type);
该函数的效果是执行映射 - 复制 - 取消映射序列。
3. 像素寻址结构详解
像素寻址结构在图像创建和映射函数中使用,其定义如下:
typedef struct _vx_imagepatch_addressing_t {
vx_uint32 dim_x;
vx_uint32 dim_y;
vx_int32 stride_x;
vx_int32 stride_y;
vx_uint32 scale_x;
vx_uint32 scale_y;
vx_uint32 step_x;
vx_uint16 step_y;
vx_uint16 stride_x_bits;
} vx_imagepatch_addressing_t;
各组件的作用如下:
-
dim
:表示尺寸,
dim_x
和
dim_y
分别是 x 和 y 方向的像素数。
-
stride
:表示步长,以字节为单位。
stride_x
是同一行中相邻像素之间的字节数,
stride_y
是从一个像素到其正下方像素的字节数。
-
scale
:用于处理颜色通道,每个通道相对于“主”通道有自己的比例。在 OpenVX 中,比例值隐式除以
VX_SCALE_UNITY
(示例实现中为 1024)。
-
step
:用于抵消
scale
组件的影响,是逻辑像素单位的跳过数,以到达下一个物理唯一像素。
在
vxFormatImagePatchAddress2d
函数中,计算给定像素 (x, y) 在图像中的位置的偏移量的公式如下:
(addr->stride_y * ((addr->scale_y * y)/VX_SCALE_UNITY)) +
(addr->stride_x * ((addr->scale_x * x)/VX_SCALE_UNITY))
以下是一个简单的 mermaid 流程图,展示映射图像补丁的流程:
graph TD;
A[确定图像补丁] --> B[调用 vxMapImagePatch];
B --> C[根据 usage 进行读写操作];
C --> D[调用 vxUnmapImagePatch 取消映射];
4. 映射其他对象
除了图像补丁,还可以映射数组、分布、查找表和重映射对象。
4.1 映射数组
使用
vxMapArrayRange
函数将
vx_array
对象的一部分映射到主机内存进行读写:
vx_status vxMapArrayRange(
vx_array array,
vx_size start,
vx_size end,
vx_map_id* map_id,
vx_size* stride,
void** ptr,
vx_enum usage,
vx_enum mem_type,
vx_uint32 flags);
操作步骤如下:
1. 确定要映射的数组范围,设置
array
、
start
和
end
参数。
2. 调用
vxMapArrayRange
函数,获取
map_id
、
stride
和
ptr
。
3. 进行读写操作。
4. 调用
vxUnmapArrayRange(array, map_id)
取消映射。
也可以使用
vxCopyArrayRange
函数进行数组范围的复制:
vx_status vxCopyArrayRange(
vx_array array,
vx_size range_start,
vx_size range_end,
vx_size user_stride,
void* user_ptr,
vx_enum usage,
vx_enum user_mem_type);
4.2 映射分布
映射分布更简单,总是映射整个分布。使用
vxMapDistribution
函数:
vx_status vxMapDistribution(
vx_distribution distribution,
vx_map_id* map_id,
void** ptr,
vx_enum usage,
vx_enum mem_type,
vx_bitfield flags);
操作步骤:
1. 调用
vxMapDistribution
函数,获取
map_id
和
ptr
。
2. 进行读写操作。
3. 调用
vxUnmapDistribution(distribution, map_id)
取消映射。
使用
vxCopyDistribution
函数进行分布的复制:
vx_status vxCopyDistribution(
vx_distribution distribution,
void* user_ptr,
vx_enum usage,
vx_enum user_mem_type);
4.3 映射查找表
查找表(
vx_lut
)的映射和复制函数与分布类似。使用
vxMapLUT
函数:
vx_status vxMapLUT(
vx_lut lut,
vx_map_id* map_id,
void** ptr,
vx_enum usage,
vx_enum mem_type,
vx_bitfield flags);
操作步骤:
1. 调用
vxMapLUT
函数,获取
map_id
和
ptr
。
2. 进行读写操作。
3. 调用
vxUnmapLUT(lut, map_id)
取消映射。
使用
vxCopyLUT
函数进行查找表的复制:
vx_status vxCopyLUT(
vx_lut lut,
void* user_ptr,
vx_enum usage,
vx_enum user_mem_type);
4.4 映射重映射对象
重映射对象用于描述如何将图像转换为变形版本。使用
vxMapRemapPatch
函数:
vx_status vxMapRemapPatch(
vx_remap remap,
const vx_rectangle_t* rect,
vx_map_id* map_id,
vx_size* stride_y,
void** ptr,
vx_enum coordinate_type,
vx_enum usage,
vx_enum mem_type);
操作步骤:
1. 确定要映射的重映射对象的矩形子集,设置
remap
和
rect
参数。
2. 调用
vxMapRemapPatch
函数,获取
map_id
、
stride_y
和
ptr
。
3. 进行读写操作。
4. 调用
vxUnmapRemapPatch(remap, map_id)
取消映射。
使用
vxCopyRemapPatch
函数进行重映射对象补丁的复制:
vx_status vxCopyRemapPatch(
vx_remap remap,
const vx_rectangle_t* rect,
vx_size* user_stride_y,
void* user_ptr,
vx_enum user_coordinate_type,
vx_enum usage,
vx_enum user_mem_type);
通过以上步骤和函数,可以在 OpenVX 中高效地进行数据的输入输出操作。不同对象的映射和复制操作有相似之处,也有各自的特点,需要根据具体需求选择合适的函数和参数。
OpenVX 高效数据输入输出指南
5. 各对象映射操作对比总结
为了更清晰地了解不同对象的映射和复制操作,下面通过表格进行对比总结:
| 对象类型 | 映射函数 | 复制函数 | 操作特点 |
| ---- | ---- | ---- | ---- |
| 图像补丁 |
vxMapImagePatch
|
vxCopyImagePatch
| 可访问图像的部分区域,需处理多平面和像素寻址结构 |
| 数组 |
vxMapArrayRange
|
vxCopyArrayRange
| 指定数组范围进行映射,使用步长代替寻址结构 |
| 分布 |
vxMapDistribution
|
vxCopyDistribution
| 总是映射整个分布,无需寻址结构或步长 |
| 查找表 |
vxMapLUT
|
vxCopyLUT
| 与分布类似,元素大小取决于
VX_LUT_TYPE
|
| 重映射对象 |
vxMapRemapPatch
|
vxCopyRemapPatch
| 映射图像变形信息,返回二维数据补丁 |
从这个表格可以看出,虽然不同对象的映射和复制操作有相似的参数(如
usage
、
mem_type
),但也有各自独特的处理方式,在实际应用中需要根据对象类型进行正确的操作。
6. 操作注意事项
在进行 OpenVX 数据映射和操作时,有以下几点重要的注意事项:
-
数据所有权规则
:务必遵循数据所有权规则,映射后及时取消映射,否则可能导致程序行为异常。例如,使用完对象后忘记取消映射,接着在 OpenVX 图中使用该对象,对象可能不会反映更新,不同的实现方式可能会有不同的表现。
-
虚拟对象限制
:不能映射虚拟对象。将对象声明为虚拟对象意味着承诺不会映射该对象以查看其内容,这样 OpenVX 可以对其进行优化。如果尝试映射虚拟对象,根据具体实现,可能会出现错误、正常工作或出现奇怪的行为。
-
参数使用规范
:
-
usage
参数
:要如实告知 OpenVX 应用程序如何使用数据,避免错误使用。例如,如果声明为
VX_READ_ONLY
却进行写操作,程序可能会出现不可预期的结果。
-
mem_type
参数
:标准中合法值为
VX_MEMORY_TYPE_HOST
,特定供应商可能有额外选项,但要确保使用合法值。
-
flags
参数
:通常使用 0,只有在需要特定供应商扩展时才使用其他值。
7. 综合应用示例
下面通过一个简单的综合示例,展示如何在实际应用中使用上述的映射和复制操作。假设我们要将一个图像的部分区域复制到主机内存,对其进行修改后再复制回图像对象。
#include <VX/vx.h>
// 假设已经创建了图像对象 image
vx_image image;
// 定义要复制的图像区域
vx_rectangle_t rect = {0, 0, 100, 100};
vx_uint32 plane_index = 0;
// 分配主机内存
vx_imagepatch_addressing_t user_addr;
void* user_ptr = malloc(100 * 100 * sizeof(vx_uint8));
// 从图像对象复制数据到主机内存
vx_status status = vxCopyImagePatch(image, &rect, plane_index, &user_addr, user_ptr, VX_READ_ONLY, VX_MEMORY_TYPE_HOST);
if (status != VX_SUCCESS) {
// 处理错误
}
// 对主机内存中的数据进行修改
for (int i = 0; i < 100 * 100; i++) {
((vx_uint8*)user_ptr)[i] = 255;
}
// 将修改后的数据复制回图像对象
status = vxCopyImagePatch(image, &rect, plane_index, &user_addr, user_ptr, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
if (status != VX_SUCCESS) {
// 处理错误
}
// 释放主机内存
free(user_ptr);
8. 总结与展望
通过本文的介绍,我们详细了解了 OpenVX 中数据的映射、复制和操作方法,包括图像补丁、数组、分布、查找表和重映射对象等不同类型的对象。掌握这些操作可以帮助我们在 OpenVX 应用中高效地进行数据的输入输出。
在实际应用中,我们需要根据具体需求选择合适的对象和操作函数,并严格遵循数据所有权规则和参数使用规范。同时,要注意虚拟对象的限制,合理利用 OpenVX 的优化功能。
未来,随着计算机视觉和图像处理技术的不断发展,OpenVX 可能会有更多的功能和优化,我们可以期待更高效、更灵活的数据处理方式。例如,可能会有更丰富的内存类型选项,或者更智能的像素寻址和数据映射机制,以满足日益增长的应用需求。
以下是一个 mermaid 流程图,展示综合应用示例的流程:
graph TD;
A[创建图像对象] --> B[定义复制区域];
B --> C[分配主机内存];
C --> D[从图像复制到主机内存];
D --> E[修改主机内存数据];
E --> F[从主机内存复制回图像];
F --> G[释放主机内存];
通过以上内容,我们全面了解了 OpenVX 中数据输入输出的相关操作和注意事项,希望能帮助大家在实际开发中更好地运用 OpenVX 进行高效的数据处理。
超级会员免费看
34

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



