6

画像を表すフロートポインタ(配列)を取得しました。これは要素数であり、インデックスにはwidth*heightがあります。画像は、左上に原点があるマトリックスのようなものではありません。代わりに、カルテシアン座標系のように、左下に原点があります。最大幅に達した後、左側の次の行を開始します。

したがって、この配列を2D行列に効率的に変換したいと思います(オプション:opencv)。

どうすればそれを効果的に行うことができますか?そして、どうすれば元に戻すことができますか?

前もって感謝します。

4

3 に答える 3

3

湖に岩を投げて波紋を見ます。注:主にOpenCVに関する私の駆け出しの知識が原因で、発信者がxformedデータで何を期待しているのかわかりませんただし、変革の中心的な問題は非常に単純なように思われました。ベースから離れている場合は、コメントを残してください。回答を削除します。2つのアプローチを提案します。1つはインプレースでのデータ反転用で、もう1つはC++クラスを使用した単純なアクセサーラッピング用です。

インプレース反転:呼び出し元がAPIに渡すための使用法に対応するために行を反転する必要がある場合は、インプレースで実行できます。反転データの使用が終了したら、必ずもう一度実行してください。純粋にバイト指向の例は次のとおりです。

// in-place inversion of the linear matrix to re-origin.
void mat_invert(float *data, size_t height, size_t width)
{
    // must be at least 2 rows high for this to mean anything.
    if (height < 2)
        return;

    // setup a pair of pointers to walk the rows in byte-form
    unsigned char* top = (unsigned char*)data;
    unsigned char *bottom = (unsigned char *)(data + (height-1)*width);
    size_t row_width = sizeof(data[0]) * width;
    while (top < bottom)
    {
        for (size_t i=0; i<row_width; i++)
        {
            *top ^= *bottom;
            *bottom ^= *top;
            *top++ ^= *bottom++;
        }
        bottom -= 2*row_width;
    }
}

使用例:

int main(int argc, char *argv[])
{
    const size_t w = 10;
    const size_t h = 5;

    float ar[h*w];
    memset(ar, 0, sizeof(ar));

    ar[0]       = 0.1;
    ar[1*w + 1] = 1.1;
    ar[2*w + 2] = 2.1;
    ar[3*w + 3] = 3.1;
    ar[4*w + 4] = 4.1;

    // dump original
    for (size_t i=0; i<h; i++)
    {
        for (size_t j=0; j<w; j++)
            cout << ar[i*w+j] << ' ';
        cout << endl;
    }
    cout << endl;

    // invert original
    mat_invert(ar, h, w);
    for (size_t i=0; i<h; i++)
    {
        for (size_t j=0; j<w; j++)
            cout << ar[i*w+j] << ' ';
        cout << endl;
    }
    cout << endl;

    // invert again
    mat_invert(ar, h, w);
    for (size_t i=0; i<h; i++)
    {
        for (size_t j=0; j<w; j++)
            cout << ar[i*w+j] << ' ';
        cout << endl;
    }
    cout << endl;

    return EXIT_SUCCESS;
}

結果:

0.1 0 0 0 0 0 0 0 0 0 
0 1.1 0 0 0 0 0 0 0 0 
0 0 2.1 0 0 0 0 0 0 0 
0 0 0 3.1 0 0 0 0 0 0 
0 0 0 0 4.1 0 0 0 0 0 

0 0 0 0 4.1 0 0 0 0 0 
0 0 0 3.1 0 0 0 0 0 0 
0 0 2.1 0 0 0 0 0 0 0 
0 1.1 0 0 0 0 0 0 0 0 
0.1 0 0 0 0 0 0 0 0 0 

0.1 0 0 0 0 0 0 0 0 0 
0 1.1 0 0 0 0 0 0 0 0 
0 0 2.1 0 0 0 0 0 0 0 
0 0 0 3.1 0 0 0 0 0 0 
0 0 0 0 4.1 0 0 0 0 0 

暗黙的なアクセスクラス:必要なのが仮想化された行/高さの計算だけである場合、それを行うには以下で十分です。

#include <iostream>
#include <exception>
#include <stdexcept>
using namespace std;

class matrix_xform
{
private:
    size_t width, height;
    float *data;

public:
    matrix_xform(float *data, size_t height, size_t width)
        : data(data), width(width), height(height)
    {
    }

    float * operator[](size_t x)
    {
        if (x > (height-1))
            throw std::out_of_range("matrix_xform[x]");
        return data + (width * (height - 1 - x));
    }

    const float * operator[](size_t x) const
    {
        if (x > (height-1))
            throw std::out_of_range("matrix_xform[x]");
        return data + (width * (height - 1 - x));
    }
};

使用例:

int main(int argc, char *argv[])
{
    const size_t w = 10;
    const size_t h = 5;

    float ar[h*w];
    memset(ar, 0, sizeof(ar));

    matrix_xform mat(ar, h, w);
    mat[0][0] = 1.0;
    mat[1][1] = 1.0;
    mat[2][2] = 1.0;
    mat[3][3] = 1.0;
    mat[4][4] = 1.0;

    // dump original
    for (size_t i=0; i<h; i++)
    {
        for (size_t j=0; j<w; j++)
            cout << ar[i*w+j] << ' ';
        cout << endl;
    }
    cout << endl;

    // dump using accessor
    for (size_t i=0; i<h; i++)
    {
        for (size_t j=0; j<w; j++)
            cout << mat[i][j] << ' ';
        cout << endl;
    }

    return EXIT_SUCCESS;
}

結果:

0 0 0 0 1 0 0 0 0 0 
0 0 0 1 0 0 0 0 0 0 
0 0 1 0 0 0 0 0 0 0 
0 1 0 0 0 0 0 0 0 0 
1 0 0 0 0 0 0 0 0 0 

1 0 0 0 0 0 0 0 0 0 
0 1 0 0 0 0 0 0 0 0 
0 0 1 0 0 0 0 0 0 0 
0 0 0 1 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 0 0 

OPが探しているすべてのベースをカバーすることを願っています。

于 2012-11-12T10:44:13.217 に答える
1

画像処理APIを次のように計画する

 void my_func (int *src, int *dst, int x_stride, int y_stride, int N);

スキャン方向を左<->右間だけでなく、上<->下の間でも反転させながら、連続メモリでの反復を容易にします。

APIがさまざまな入出力ストライド用に設計されている場合は、画像要素ごとのバイト数を変更することもできます(たとえば、カラーモードをRGBAからRGBに、または24ビットRGBから16ビットR5G6B5に、intからfloatに変更するなど)。 。)だけでなく、画像の幅(および高さも...)。

重要なのは、画像の各行の位置に関係なく、数学は同じでなければならないということです。

これらの関数の1つは次のとおりです。

 copy_row(int *src, int* dst, int N, int x_stride);
 copy_2D_mem(int *src_base, int* dst_base, int N, int M, int y_stride, int x_stride);

繰り返しになりますが、既存のopencvアルゴリズムの多くが画像の向きを気にしない可能性があります。そして、自分で書くことで、同じアプローチを利用することができます。

于 2012-11-12T10:01:16.913 に答える
1

私があなたの問題を理解しているので、配列をOpenCV APIに渡して、(top,left)インデックス付きの2次元行列として解釈するようにします。配列を再配置せずにこれを行う簡単な方法の1つを、次の例で示します。

float a[8] = {1,2,3,4,5,6,7,8};  //your array containing the image
int img_width = 2;
int img_height = 4;
float** b = new float*[img_height];
for(int i=img_height ; i>0; i--)
    b[img_height-i] = a+ (i-1)*img_width;

//call your API
do_something(b,img_height,img_width); 


//your OpenCV API that expects a 2-d matrix 
void do_something(float** x , int r, int c){};

必要に応じて、これを便利な関数/マクロに変換して、OpenCVAPIを呼び出す前に呼び出して目的の形式の2次元行列を取得できます。また、完了したら、この目的で作成された一時配列のメモリの割り当てを解除することを忘れないでください。

于 2012-11-12T10:41:35.543 に答える