5

我的图像处理项目适用于灰度图像。我有 ARM Cortex-A8 处理器平台。我想使用NEON。

我有一个灰度图像(考虑下面的例子),在我的算法中,我只需要添加列。

如何将四个 8 位像素值(即uint8_t)作为四个 uint32_t并行加载到 128 位 NEON 寄存器之一中?我必须使用什么内在功能来做到这一点?

我是说:

替代文字

我必须将它们加载为 32 位,因为如果您仔细观察,我执行 255 + 255 的那一刻是 512,它不能保存在 8 位寄存器中。

例如

255 255 255 255 ......... (640 pixels)
255 255 255 255
255 255 255 255
255 255 255 255
.
.
.
.
.
(480 pixels) 
4

5 回答 5

11

我建议您花点时间了解 SIMD 在 ARM 上的工作原理。看着:

看一眼:

  1. http://blogs.arm.com/software-enablement/161-coding-for-neon-part-1-load-and-stores/
  2. http://blogs.arm.com/software-enablement/196-coding-for-neon-part-2-dealing-with-leftovers/
  3. http://blogs.arm.com/software-enablement/241-coding-for-neon-part-3-matrix-multiplication/
  4. http://blogs.arm.com/software-enablement/277-coding-for-neon-part-4-shifting-left-and-right/

让你开始。然后,您可以使用内联汇编程序或 domen 推荐的相应 ARM 内部函数来实现您的 SIMD 代码。

于 2010-09-09T22:38:11.043 回答
5

取决于您的编译器和(可能缺少)扩展。

IE。对于 GCC,这可能是一个起点: http: //gcc.gnu.org/onlinedocs/gcc/ARM-NEON-Intrinsics.html

于 2010-09-09T11:01:41.420 回答
3

如果您需要总计 480 个 8 位值,那么从技术上讲,您需要 17 位中间存储。但是,如果您分两个阶段执行加法运算,即前 240 行,然后是后 240 行,您可以分别以 16 位进行。然后你可以将两半的结果相加得到最终的答案。

实际上有一条 NEON 指令适合您的算法,称为 vaddw。它将一个 dword 向量添加到一个 qword 向量,后者包含的元素的宽度是前者的两倍。在您的情况下, vaddw.u8 可用于将 8 个像素添加到 8 个 16 位累加器。然后,可以使用 vaddw.u16 将两组 8 个 16 位累加器添加到一组 8 个 32 位累加器中 - 请注意,您必须使用该指令两次才能获得两半。

如有必要,您还可以使用 vmovn 或 vqmovn 将值转换回 16 位或 8 位。

于 2010-10-25T20:56:46.757 回答
2

没有指令可以将您的 4 个 8 位值加载到 4 个 32 位寄存器中。

您必须加载它们,然后使用 vshl 两次。因为霓虹灯不能使用 32 个寄存器,所以你必须处理 8 个像素(而不是 4 个)

您只能使用 16 位寄存器。应该够了……

于 2011-04-09T15:18:14.733 回答
0

使用单通道加载指令 ( vld1 <register>[<lane>], [<address]) 将 4 个字节加载到 q 寄存器中,然后使用两个移动长指令 ( vmovl) 先将它们提升到 16 位,然后再提升到 32 位。结果应该类似于(在 GNU 语法中)

vld1 d0[0], [<address>] @Now d0 = (*<addr>, *<addr+1>, *<addr+2>, *<addr+3>, <junk>, ... <junk> )
vmovl.u8 q0, d0 @Now q1 = (d0, d1) = ((uint16_t)*<addr>, ... (uint16_t)*<addr+3>, <junk>, ... <junk>)
vmovl.u16 q0, d2 @Now d0 = ((uint32_t)*<addr>, ... (uint32_t)*<addr+3>), d1 = (<junk>, ... <junk>)

如果可以保证<address>是 4 字节对齐的,那么[<address>: 32]在加载指令中改写,以节省一两个周期。但是,如果您这样做并且地址未对齐,那么您将遇到错误。

嗯,我刚刚意识到你想使用内在函数,而不是汇编,所以内在函数也是一样的。

uint32x4_t v8; // Will actually hold 4 uint8_t
v8 = vld1_lane_u32(ptr, v8, 0);
const uint16x4_t v16 = vget_low_u16(vmovl_u8(vreinterpret_u8_u32(v8)));
const uint32x4_t v32 = vmovl_u16(v16);
于 2012-08-07T16:47:25.673 回答