5

私は8ビットの画像を持っています。ピクセルごとに、現在の行の順序位置を計算する必要があります。たとえば、行が次の場合:

32 128 16 64,

次に、結果が必要です。

1 3 0 2,

32は行の1番目に高い値であるため、128は3番目に高く、16は0番目に高く、64は2番目に高い値です。

画像のすべての行に対して上記の手順を繰り返す必要があります。ベクトル化されていないコードは次のとおりです。

for (int curr = 0; curr < new_height; ++curr)
{
    vector<pair<unsigned char, char> > ordered;
    for (char i = 0; i < 4; ++i)
    {
        unsigned char val = luma24.at<unsigned char>(curr, i);
        ordered.push_back(pair<unsigned char, char>(val, i));
    }
    sort(ordered.begin(), ordered.end(), cmpfun);
    for (int i = 0; i < 4; ++i)
        signature.at<char>(curr, ordered[i].second) = i;
}

luma24は私が読んでいる8ビットの画像で、new_height行と4列があります。 signatureは同じサイズの署名付き画像です(関連性がないため、今のところ記号の違いは無視してください)。ここに結果を保存します。cmpfun簡単なコンパレータ関数です。

私は上記のコードをベクトル化しようとしましたが、これを取得しました:

Mat ordinal;
luma24.convertTo(ordinal, CV_16UC1, 256, 0);
Mat sorted = ordinal.clone();
for (int i = 0; i < 4; ++i)
    ordinal(Range::all(), Range(i, i+1)) += i;
cv::sort(ordinal, sorted, CV_SORT_EVERY_ROW | CV_SORT_ASCENDING);
bitwise_and(sorted, Scalar(0x00ff), ordinal);
Mat ordinal8;
ordinal.convertTo(ordinal8, CV_8SC1, 1, 0);
ordinal8.copyTo(signature(Range::all(), Range(0, 4)));

OpenCVはマルチチャネル画像の並べ替えを実行しないため、8ビット値と8ビット序数を単一の16ビットチャネルにパックする必要がありました。これはほとんど私が必要としているものですが、完全ではありません。入力例の場合、次のようになります。

2 0 3 1

最小値は2列目にあるので、次に低い値は0列目にあります。各ピクセルに個別にアクセスせずに、これを必要な結果に変換するにはどうすればよいですか。

基本的に、私はこれをどういうわけかベクトル化する必要があります:

uint8_t x[] = {2, 0, 3, 1};
uint8_t y[4];
for (uint8_t i = 0; i < 4; ++i)
    y[x[i]] = i;

ここxで、は現在のベクトル化されたコードが私に与える中間結果であり、yは私が望む結果です。

できますか?

4

2 に答える 2

0

これでうまくいくと思います。割り当て、スタック、またはソートは必要ありませんが、範囲が 0 ~ 255 (uint8 など) であることを前提としています。より大きな前提: 幅の広い行がある場合にのみパフォーマンスが向上します。それらが実際に 4 ピクセル幅である場合、i<256 はちょっと醜いです。それをなくす方法はありますが、単純にするために 4 ピクセルは単なる「例」に過ぎないと思います。

void processRow (int* rowpos, uint8_t* pixelsForRow, int w) {
   uint32_t i, pv, v=0, hist[256]={0};
   for (i=0; i<w; i++)      hist[pixelsForRow[i]]++;
   for (i=0; i<256; i++)    {pv=hist[i]; hist[i]=v; v+=pv;}
   for (i=0; i<w; i++)      rowpos[i] = hist[pixelsForRow[i]]++;
}

わかりました - それで、それはどのように機能しますか?
この関数の 1 行目は、ヒストグラム テーブルを宣言して空にします。
行 2 は、ヒストグラムを計算します。
3 行目は、それをカウントされた並べ替えに変換します。これが、hist が uint8 よりも大きな要素サイズを使用する理由です
。4 行目は、並べ替えられた位置を適用します。

2 つのトリックがあります。まず、3 行目で、ヒストグラムが「1 インデックス分シフト」され、最初の値は常に '0' であり、2 番目の値は最初のカウントと同じになります。2 番目のトリックは、4 行目の "++" です。序数の値が常に一意であることを保証します。

入力で試してみましょう:
[32 128 16 64]
行 2: [0...1....1....1...1...0] インデックス [0, 16, 32, 64、128、255] それぞれ
3 行目: [0...0....1....2...3...0] インデックス [0, 16, 32, 64, 128, 255] それぞれ
4 行目: [1, 3, 0, 2] ... 正しいようです

少し異なる入力で試してみましょう:
[32 128 16 32]
2 行目: [0...1....2....0...1.. .0] at index [0, 16, 32, 64, 128, 255] それぞれ
3行目: [0...0....1....3...3...0] at index [ 0, 16, 32, 64, 128, 255] それぞれ
4 行目: [1, 3, 0, 2] ... 完璧


ですが、ベクトル化のニーズを満たすかどうかはよくわかりません -- :)

于 2013-03-17T05:51:30.677 に答える