2014年8月31日日曜日

ベクトル命令での画像処理

最近、画像処理をintrinsicで書いてる。
その話をちょっと書いてみようかと。
対象はAVXやAVX2、AVX512ね。

画像のフィルター処理だと、例えば3×3のマス目にblurマスクを掛けるとか。
ここでは単純に前後3マスの合計値としましょうか。

Cだと、
D[X] = S[x] + S[x+1] + S[x+2];
なんて書くわけですが、AVXでこれをこのまま書くと、
__m256 v1 = _mm256_loadu_ps(&S[x]);
__m256 v2 = _mm256_loadu_ps(&S[x+1]);
__m256 v3 = _mm256_loadu_ps(&S[x+2]);
__m256 v = _mm256_add_ps(_mm256_add_ps(v1, v2), v3);
_mm256_storeu_ps(&D[x], v);
みたいになっちゃって、ちょっとロードが勿体なくない?とかなるわけです。
これを、
__m256 s00, s08;
s08 = _mm256_loadu_ps(&S[xb]);
for (x = xb; x < xe; ++x) {
    s00 = s08;
    s08 = _mm256_loadu_ps(&S[x+8]);
    __m256 v1 = s00;
    __m256 v2 = s00とs08を合わせて4バイトシフト
    __m256 v3 = s00とs08を合わせて8バイトシフト
    __m256 v = _mm256_add_ps(_mm256_add_ps(v1, v2), v3);
    _mm256_storeu_ps(&D[x], v);
}
なんてできれば良い感じになるじゃないですか。
これがフィルター処理の基本形ですかね。

3×3など複数行をまたぐ処理の場合は、これをs0_00, s1_00, s2_00みたいに、
複数行をベクトルレジスタに読んでおいて、似たような処理を行います。

こうやってintrinsicで書いても早くならない関数もありますが、
大体は早くなりますし、最近intrinsicで書くのに慣れてきたので、
最初からintrinsicで書いてもいいかなとか思い始めてたりw

0 件のコメント:

コメントを投稿