我的图像处理项目适用于灰度图像。我有ARM Cortex-A8处理器平台。我想利用NEON。
我有一个灰度图像(考虑下面的例子),在我的算法中,我只需要添加列。
如何将四个8位像素值并行加载到 uint8_t ,将四个uint32_t 加载到其中一个位NEON寄存器?我必须使用什么内在的东西?
我的意思是:
我必须将它们加载为32位,因为如果仔细观察,我做255 + 255的那一刻就是512,这不能保存在8位寄存器中。
e.g。
255 255 255 255 ......... (640 pixels)
255 255 255 255
255 255 255 255
255 255 255 255
.
.
.
.
.
(480 pixels)
答案 0 :(得分:11)
我建议您花点时间了解SIMD在ARM上的工作原理。看看:
看看:
让你入门。然后,您可以使用内联汇编程序或domen推荐的相应ARM内在函数来实现您的SIMD代码。
答案 1 :(得分:5)
取决于您的编译器和(可能缺少)扩展。
IE中。对于海湾合作委员会来说,这可能是一个起点:http://gcc.gnu.org/onlinedocs/gcc/ARM-NEON-Intrinsics.html
答案 2 :(得分:3)
如果您需要总计480个8位值,那么技术上需要17位中间存储。但是,如果您分两个阶段执行添加,即前240行然后下240行,则可以每个16位执行。然后你可以添加两半的结果来得到最终答案。
实际上有一个适合你的算法的NEON指令叫做vaddw。它会将双向量添加到qword向量中,后者包含的元素宽度是前者的两倍。在您的情况下,vaddw.u8可用于向8个16位累加器添加8个像素。然后,vaddw.u16可用于将两组8个16位累加器添加到一组8个32位累加器中 - 请注意,必须使用该指令两次才能得到两半。
如有必要,您还可以使用vmovn或vqmovn将值转换回16位或8位。
答案 3 :(得分:2)
没有指令可以将4 8bit值加载到4个32位寄存器中。
您必须加载它们然后再使用vshl两次。 因为霓虹灯不能使用32个寄存器,你必须工作8个像素(而不是4个)
您只能使用16位寄存器。它应该够了......
答案 4 :(得分: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);