23、OpenVX 高效数据输入输出指南

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 进行高效的数据处理。

内容概要:本文介绍了一套针对智能穿戴设备的跑步/骑行轨迹记录系统实战方案,旨在解决传统运动APP存在的定位漂移、数据断层和路径分析单一等问题。系统基于北斗+GPS双模定位、惯性测量单元(IMU)和海拔传感器,实现高精度轨迹采集,并通过卡尔曼滤波算法修正定位误差,在信号弱环境下利用惯性导航补位,确保轨迹连续性。系统支持跑步与骑行两种场景的差异化功能,包括实时轨迹记录、多维度路径分析(如配速、坡度、能耗)、数据可视化(地图标注、曲线图、3D回放)、异常提醒及智能优化建议,并可通过蓝牙/Wi-Fi同步数据至手机APP,支持社交分享与专业软件导出。技术架构涵盖硬件层、设备端与手机端软件层以及云端数据存储,强调低功耗设计与用户体验优化。经过实测验证,系统在定位精度、续航能力和场景识别准确率方面均达到预期指标,具备良好的实用性和扩展性。; 适合人群:具备一定嵌入式开发或移动应用开发经验,熟悉物联网、传感器融合与数据可视化的技术人员,尤其是从事智能穿戴设备、运动健康类产品研发的工程师和产品经理;也适合高校相关专业学生作为项目实践参考。; 使用场景及目标:① 开发高精度运动轨迹记录功能,解决GPS漂移与断点问题;② 实现跑步与骑行场景下的差异化数据分析与个性化反馈;③ 构建完整的“终端采集-手机展示-云端存储”系统闭环,支持社交互动与商业拓展;④ 掌握低功耗优化、多源数据融合、动态功耗调节等关键技术在穿戴设备中的落地应用。; 阅读建议:此资源以真实项目为导向,不仅提供详细的技术实现路径,还包含硬件选型、测试验证与商业扩展思路,建议读者结合自身开发环境,逐步实现各模块功能,重点关注定位优化算法、功耗控制策略与跨平台数据同步机制的设计与调优。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值