3

C++/ポインターのヘルプが必要です。RGB IplImage を作成し、i,j にアクセスしたい場合、http ://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv- から取得した次の C++ クラスを使用します。 intro.html

template<class T> class Image
{
private:
    IplImage* imgp;

public:
    Image(IplImage* img=0) {imgp=img;}
    ~Image(){imgp=0;}
    void operator=(IplImage* img) {imgp=img;}
    inline T* operator[](const int rowIndx) {
        return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));}
};

typedef struct{
  unsigned char b,g,r;
} RgbPixel;

typedef struct{
  float b,g,r;
} RgbPixelFloat;

typedef Image<RgbPixel>       RgbImage;
typedef Image<RgbPixelFloat>  RgbImageFloat;
typedef Image<unsigned char>  BwImage;
typedef Image<float>          BwImageFloat;

私は CUDA を扱ってきたので、すべてのデータを配列に入れる必要がある場合があります。すべてのチャネルを独自の配列に保持するのが好きで、その方法でデータを処理する方が簡単なようです。だから私は通常、次のようなことをします:

IplImage *image = cvLoadImage("whatever.tif");
RgbImageFloat img(image);
for(int i = 0; i < exrIn->height; i++)
{
    for(int j = 0; j < exrIn->width; j++)
    {
        hostr[j*data->height+i] = img[i][j].r;
        hostg[j*data->height+i] = img[i][j].g;
        hostb[j*data->height+i] = img[i][j].b;
    }
}

次に、データをデバイスにコピーし、それを使用して何らかの処理を行い、ホストに戻してから、配列を介してデータを IplImage に割り当て、結果を保存します。

ポインターを使用してこれを行うには、より高速な方法が必要ですが、私は迷っています。より効率的な方法が必要です。すべてのチャンネルにポインタを簡単に使用できる方法はありますか? 私はこのようなことを試みましたが、うまくいきませんでした:

float *hostr = &img[0][0].r
float *hostg = &img[0][0].b
float *hostb = &img[0][0].g

助言がありますか?ありがとう!

編集:答えてくれてありがとう。私の質問がよくわからなかったのかもしれません。チャネルとそのデータへのアクセス方法に精通しています。私が興味を持っているのは、データを IplImage から標準配列に完全にコピーするパフォーマンスと効率を向上させることです。これは、csl がこれまでに述べたことに沿ったものです。私が見る問題は、IplImage 内のデータの配置方法が "rgbrgbrgbrgb" であることです。

4

2 に答える 2

5

まず、C++ に慣れている場合は、OpenCV 2.0の使用を検討してください。OpenCV 2.0は、画像と行列 (IplImage*およびCvMat*) の異なるデータ型を排除し、1 つの構造体 ( Mat) を使用して両方を処理します。自動メモリ管理と、チャネルなどを処理するための便利なルーチンのトラックロードとは別に、MATLAB 風のルーチンもいくつかありますが、使用するのは本当に楽しいものです。

特定の問題については、次のようにIplImage*with のチャネルにアクセスします。Mat

 IplImage *image = cvLoadImage("lena.bmp");
 Mat Lena(image);
 vector<Mat> Channels;
 split(Lena,Channels);
 namedWindow("LR",CV_WINDOW_AUTOSIZE);
 imshow("LR",Channels[0]);
 waitKey();

これで、各チャンネルのコピーがvector Channels.

チャネルを使用および抽出したくない場合は、次の点に注意してください。OpenCV2.0OpenCV は、次の方法でマルチチャネル イメージを注文します。

x(1,1,1) x(1,1,2) x(1,1,3) x(1,2,1) x(1,2,2) x(1,2,3) ...

どこx(i,j,k) = an element in row i of column j in channel k

また、OpenCVは画像をパディングwidthStepします。そのため、これらのパディング ギャップを考慮して行をジャンプすることを忘れないでください。そして、cslが言ったことの行に沿って、外側のループで行ポインタを増やし(を使用widthStep)、このポインタを増やして行内の要素にアクセスします。

ノート:

IplImage*現在 2.0 を使用しているため、でバイパスできますMat Lena = imread("Lena.bmp");

于 2009-10-14T20:40:54.100 に答える
1

ここには多くの改善の余地があります。あまりにも多くの人がビットマップにアクセスする方法を読む必要があります。

まず、メモリの局所性を可能な限り増やします。これにより、キャッシュ ヒットとパフォーマンスが向上します。つまり、各カラー チャネルに 3 つの個別の配列を使用しないでください。おそらく主にピクセルで作業するため、それぞれを一緒に保存してください。

次に、すべてのピクセルに対して y*width 計算を行わないでください。内側のループで実行すると、多くのサイクルが消費されます。

最後に、イメージの完全なコピーが必要な場合は、memcpy() を実行するだけで、非常に高速です。浮動小数点から整数に変換したかどうかは推測できませんでしたが、そうでない場合は、重複しない領域に memcpy() を使用してください。

ポインターを使用してこれを行う方法を知りたい場合 (一種の疑似コードであり、テストもされていません):

float *dst = &hostg[0][0];
RgbPixelFloat *src = &img[0][0];
RgbPixelFloat *end = &img[HEIGHT][WIDTH] + 1;

// copy green channel of whole image
while ( src != end )  {
    *dst = src->g;
    ++dst;
    ++src;
}
于 2009-10-14T19:44:22.687 に答える