まだそんなことやってんの?

技術系備忘録ブログがメイン

CUDAGpuMatで3ch画像の扱い方

GpuMatの3ch画像の扱いに少し手間取ったのでメモ

GpuMatの構造はBGRBGR・・・とチャンネルが続いていく。 CUDAカーネルによってGpuMatを扱うときは PtrStepSzに変換すると扱いやすい

例えば

using namespace cv;


Scalar black(0, 0, 0);
Mat img(Size(1000, 1000), CV_8UC3, black);
cuda::GpuMat gpuImg(img);
cuda::PtrStepSz<uchar> ptrImg = cuda::PtrStepSz<uchar>(gpuImg.rows, gpuImg.cols * gpuImg.channels(), gpuImg.ptr<uchar>(),gpuImg.step);

とかくことによりPtrStepSz型に変換できる。 PtrStepSzはCUDAカーネルの引数に指定するのに便利な型である。

CUDAカーネル内で3chのPtrStepSzを扱う際は以下のようなマクロを定義すると便利

#define GRU(IMG, X, Y) ((IMG).data[(IMG).step * (Y) + 3 * sizeof(unsigned char) * X + sizeof(unsigned char) * 2])
#define GGU(IMG, X, Y) ((IMG).data[(IMG).step * (Y) + 3 * sizeof(unsigned char) * X + sizeof(unsigned char) * 1])
#define GBU(IMG, X, Y) ((IMG).data[(IMG).step * (Y) + 3 * sizeof(unsigned char) * X + sizeof(unsigned char) * 0])

このマクロを定義した後CUDAカーネル内でたとえば (R,G,B) = (255, 0, 0)の画像を作成するときは

__global__ void myKernel(cuda::PtrStepSz<uchar> ptrImg){
    const int x = blockDim.x * blockIdx.x + threadIdx.x;
    const int y = blockDim.y * blockIdx.y + threadIdx.y;

    if((x < ptrImg.cols) && (y < ptrImg.rows)){
        GRU(ptrImg, x, y) = 255;
        GGU(ptrImg, x, y) = 0;
        GBU(ptrImg, x, y) = 0;
    }
}

によって作成することができる。