简体   繁体   中英

Image subtraction with CUDA and textures

My goal is to use C++ with CUDA to subtract a dark frame from a raw image. I want to use textures for acceleration. The input of the images is cv::Mat with the type CV_8UC4 (I use the pointer to the data of the cv::Mat). This is the kernel I came up with, but I have no idea how to eventually subtract the textures from each other:

__global__ void DarkFrameSubtractionKernel(unsigned char* outputImage, size_t pitchOutputImage,
cudaTextureObject_t inputImage, cudaTextureObject_t darkImage, int width, int height)
{
    const int x = blockIdx.x * blockDim.x + threadIdx.x;
    const int y = blockDim.y * blockIdx.y + threadIdx.y;

    const float tx = (x + 0.5f);
    const float ty = (y + 0.5f);

    if (x >= width || y >= height) return;

    uchar4 inputImageTemp = tex2D<uchar4>(inputImage, tx, ty);
    uchar4 darkImageTemp = tex2D<uchar4>(darkImage, tx, ty);

    outputImage[y * pitchOutputImage + x] = inputImageTemp - darkImageTemp; // this line will throw an error
}

This is the function that calls the kernel (you can see that I create the textures from unsigned char):

void subtractDarkImage(unsigned char* inputImage, size_t pitchInputImage, unsigned char* outputImage,
size_t pitchOutputImage, unsigned char* darkImage, size_t pitchDarkImage, int width, int height, 
cudaStream_t stream)
{
    cudaResourceDesc resDesc = {};
    resDesc.resType = cudaResourceTypePitch2D;
    resDesc.res.pitch2D.width = width;
    resDesc.res.pitch2D.height = height;
    resDesc.res.pitch2D.devPtr = inputImage;
    resDesc.res.pitch2D.pitchInBytes = pitchInputImage;
    resDesc.res.pitch2D.desc = cudaCreateChannelDesc(8, 8, 8, 8, cudaChannelFormatKindUnsigned);

    cudaTextureDesc texDesc = {};
    texDesc.readMode = cudaReadModeElementType;
    texDesc.addressMode[0] = cudaAddressModeBorder;
    texDesc.addressMode[1] = cudaAddressModeBorder;

    cudaTextureObject_t imageInputTex, imageDarkTex;
    CUDA_CHECK(cudaCreateTextureObject(&imageInputTex, &resDesc, &texDesc, 0));

    resDesc.res.pitch2D.devPtr = darkImage;
    resDesc.res.pitch2D.pitchInBytes = pitchDarkImage;
    CUDA_CHECK(cudaCreateTextureObject(&imageDarkTex, &resDesc, &texDesc, 0));

    dim3 block(32, 8);
    dim3 grid = paddedGrid(block.x, block.y, width, height);

    DarkImageSubtractionKernel << <grid, block, 0, stream >> > (reinterpret_cast<uchar4*>(outputImage), pitchOutputImage / sizeof(uchar4),
    imageInputTex, imageDarkTex, width, height);


    CUDA_CHECK(cudaDestroyTextureObject(imageInputTex));
    CUDA_CHECK(cudaDestroyTextureObject(imageDarkTex));
}

The code does not compile as I can not subtract a uchar4 from another one (in the kernel). Is there an easy way of subtraction here?

Help is very much appreciated.

Is there an easy way of subtraction here?

There are no arithmetic operators defined for CUDA built-in vector types. If you replace

outputImage[y * pitchOutputImage + x] = inputImageTemp - darkImageTemp;

with

uchar4 val;
val.x = inputImageTemp.x - darkImageTemp.x;
val.y = inputImageTemp.y - darkImageTemp.y;
val.z = inputImageTemp.z - darkImageTemp.z;
val.w = inputImageTemp.w - darkImageTemp.w;
outputImage[y * pitchOutputImage + x] = val;

things will work. If this offends you, I suggest writing a small library of helper functions to hide the mess.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM