我正在为 iOS 开发一些图像处理应用程序,阈值处理确实是一个巨大的瓶颈。所以我正在尝试使用 NEON 对其进行优化。这是函数的 C 版本。有什么方法可以使用 NEON 重写它(不幸的是我完全没有这方面的经验)?
static void thresh_8u( const Image& _src, Image& _dst, uchar thresh, uchar maxval, int type ) {
int i, j;
uchar tab[256];
Size roi = _src.size();
roi.width *= _src.channels();
memset(&tab[0], 0, thresh);
memset(&tab[thresh], maxval, 256-thresh);
for( i = 0; i < roi.height; i++ ) {
const uchar* src = (const uchar*)(_src.data + _src.step*i);
uchar* dst = (uchar*)(_dst.data + _dst.step*i);
j = 0;
for(; j <= roi.width; ++j) {
dst[j] = tab[src[j]];
}
}
}
最佳答案
如果您能确保您的行始终是 16 字节宽的倍数,这实际上非常简单,因为编译器 (clang) 具有表示 NEON vector 寄存器的特殊类型,并且知道如何将普通 C 运算符应用于它们.这是我的小测试功能:
#ifdef __ARM_NEON__
#include <arm_neon.h>
void computeThreshold(void *input, void *output, int count, uint8_t threshold, uint8_t highValue) {
uint8x16_t thresholdVector = vdupq_n_u8(threshold);
uint8x16_t highValueVector = vdupq_n_u8(highValue);
uint8x16_t *__restrict inputVector = (uint8x16_t *)input;
uint8x16_t *__restrict outputVector = (uint8x16_t *)output;
for ( ; count > 0; count -= 16, ++inputVector, ++outputVector) {
*outputVector = (*inputVector > thresholdVector) & highValueVector;
}
}
#endif
这一次对 16 个字节进行操作。 uint8x16_t
是一个包含 16 个 8 位无符号整数的 vector 寄存器。 vdupq_n_u8
返回一个 vector uint8x16_t
,其中填充了其参数的 16 个副本。
应用于两个 uint8x16_t
值的 运算符在 8 位无符号整数对之间进行 16 次比较。在左输入大于右输入的情况下,它返回 0xff(这不同于普通的 C
>
,它只返回 0x01)。当左输入小于或等于右输入时,返回0。(编译成VCGT.U8指令。)
应用于两个 uint8x16_t
值的 &
运算符计算 128 对位的 bool AND。
循环在发布版本中编译为:
0x6e668: vldmia r2, {d4, d5}
0x6e66c: subs r0, #16
0x6e66e: vcgt.u8 q10, q10, q8
0x6e672: adds r2, #16
0x6e674: cmp r0, #0
0x6e676: vand q10, q10, q9
0x6e67a: vstmia r1, {d4, d5}
0x6e67e: add.w r1, r1, #16
0x6e682: bgt 0x6e668
关于iphone - 使用 NEON 指令进行图像阈值处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11587577/