0

私は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]];
        }
    }
}
4

1 に答える 1

7

コンパイラ (clang) には NEON ベクトル レジスタを表す特別な型があり、通常の C 演算子をそれらに適用する方法を知っているため、行が常に 16 バイトの倍数であることを確認できれば、実際には非常に簡単です。ここに私の小さなテスト関数があります:

#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 バイトで動作します。Auint8x16_tは、16 個の 8 ビット符号なし整数を含むベクトル レジスタです。は、引数の16 個のコピーで満たされvdupq_n_u8たベクトルを返します。uint8x16_t

2 つの値>に適用される演算子は、uint8x16_t8 ビット符号なし int のペア間で 16 回の比較を行います。>左の入力が右の入力よりも大きい場合、0xff を返します (これは、0x01 を返す通常の C とは異なります)。左の入力が右の入力より小さいか等しい場合、0 を返します (VCGT.U8 命令にコンパイルされます)。

2 つの値&に適用される演算子は、uint8x16_t128 ペアのビットのブール 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
于 2012-07-20T22:54:22.073 に答える