AVX2 を使用して、視差推定アルゴリズムの「勝者総取り」部分を最適化しています。私のスカラー ルーチンは正確ですが、QVGA 解像度と 48 視差では、私のラップトップでは実行時間が 14 ミリ秒と残念なほど遅くなります。LR 視差画像と RL 視差画像の両方を作成しますが、簡単にするために、ここでは RL 検索のコードのみを含めます。
私のスカラールーチン:
int MAXCOST = 32000;
for (int i = maskRadius; i < rstep-maskRadius; i++) {
// WTA "RL" Search:
for (int j = maskRadius; j+maskRadius < cstep; j++) {
int minCost = MAXCOST;
int minDisp = 0;
for (int d = 0; d < numDisp && j+d < cstep; d++) {
if (asPtr[(i*numDisp*cstep)+(d*cstep)+j] < minCost) {
minCost = asPtr[(i*numDisp*cstep)+(d*cstep)+j];
minDisp = d;
}
}
dRPtr[(i*cstep)+j] = minDisp;
}
}
AVX2 を使用する私の試み:
int MAXCOST = 32000;
int* dispVals = (int*) _mm_malloc( sizeof(int32_t)*16, 32 );
for (int i = maskRadius; i < rstep-maskRadius; i++) {
// WTA "RL" Search AVX2:
for( int j = 0; j < cstep-16; j+=16) {
__m256i minCosts = _mm256_set1_epi16( MAXCOST );
__m128i loMask = _mm_setzero_si128();
__m128i hiMask = _mm_setzero_si128();
for (int d = 0; d < numDisp && j+d < cstep; d++) {
// Grab 16 costs to compare
__m256i costs = _mm256_loadu_si256((__m256i*) (asPtr[(i*numDisp*cstep)+(d*cstep)+j]));
// Get the new minimums
__m256i newMinCosts = _mm256_min_epu16( minCosts, costs );
// Compare new mins to old to build mask to store minDisps
__m256i mask = _mm256_cmpgt_epi16( minCosts, newMinCosts );
__m128i loMask = _mm256_extracti128_si256( mask, 0 );
__m128i hiMask = _mm256_extracti128_si256( mask, 1 );
// Sign extend to 32bits
__m256i loMask32 = _mm256_cvtepi16_epi32( loMask );
__m256i hiMask32 = _mm256_cvtepi16_epi32( hiMask );
__m256i currentDisp = _mm256_set1_epi32( d );
// store min disps with mask
_mm256_maskstore_epi32( dispVals, loMask32, currentDisp ); // RT error, why?
_mm256_maskstore_epi32( dispVals+8, hiMask32, currentDisp ); // RT error, why?
// Set minCosts to newMinCosts
minCosts = newMinCosts;
}
// Write the WTA minimums one-by-one to the RL disparity image
int index = (i*cstep)+j;
for( int k = 0; k < 16; k++ ) {
dRPtr[index+k] = dispVals[k];
}
}
}
_mm_free( dispVals );
Disparity Space Image (DSI) のサイズは HxWxD (320x240x48) で、各行のサイズが WxD になるように、メモリ アクセスを改善するために水平に配置します。
Disparity Space Image には、ピクセルごとのマッチング コストがあります。これを単純なボックス フィルターで集約して、まったく同じサイズの別の画像を作成しましたが、合計コストは、たとえば 3x3 または 5x5 ウィンドウでした。この平滑化により、結果がより「ロバスト」になります。asPtr でアクセスしているときは、この集計コスト イメージにインデックスを付けています。
また、不要な計算を節約するために、マスク半径によってオフセットされた行で開始および終了しています。このマスク半径は、私の国勢調査マスクの半径です。派手な境界反射を行うこともできますが、この境界の不一致を気にしない方が簡単で高速です。もちろん、これは最初と最後の列にも当てはまりますが、アルゴリズム全体を列が 16 の倍数 (例: QVGA: 320x240) である画像に対してのみ実行するように強制している場合、ここでインデックスをいじるのは良くありません。単純にインデックスを作成し、すべてを SIMD でヒットします (残差スカラー処理なし)。
また、私のコードがごちゃごちゃしていると思われる場合は、高度に最適化された OpenCV ステレオ アルゴリズムを確認することをお勧めします。私はそれらを不可能だと思っており、それらをほとんどまたはまったく使用することができませんでした.
コードはコンパイルされますが、実行時に失敗します。VS 2012 Express Update 4 を使用しています。デバッガーで実行すると、洞察を得ることができません。私は組み込み関数の使用に比較的慣れていないため、デバッグ時にどのような情報が表示されるか、レジスターの数、__m256i 変数を表示する必要があるかどうかなど、よくわかりません。
以下のコメントのアドバイスに注意して、よりスマートなインデックス作成を使用して、スカラー時間を ~14 から ~8 に改善しました。私の CPU は i7-4980HQ で、同じファイルの別の場所で AVX2 組み込み関数を正常に使用しています。