图像处理系列——利用Nvidia NPP库快速实现GPU加速

图像处理系列——利用Nvidia NPP库快速实现GPU加速

背景

如果没有编译GPU版本的OpenCV,也可以利用Nvidia提供的基于cuda的图像处理高层api。
NPP是一个用于执行CUDA加速2D图像和信号处理的函数库。库中的主要功能集中于图像处理,广泛适用于这些领域的开发人员。随着时间的推移,NPP将在各种问题领域中包含更多计算繁重的任务。NPP库的编写是为了最大限度地提高灵活性,同时保持高性能

主要步骤

  1. 分配设备内存
  2. 内存拷贝 cpu -> gpu
  3. 图像操作(注意:nppi函数参数step是图像宽的三倍(三通道))
  4. 内存拷贝 gpu -> cpu (按需)
  5. free 内存 (按需)

范例1——Resize

void cudaResize(cv::Mat &image, cv::Mat &rsz_img)
{
    int outsize = rsz_img.cols * rsz_img.rows * sizeof(uchar3);

    int inwidth = image.cols;
    int inheight = image.rows;
    int memSize = inwidth * inheight * sizeof(uchar3);

    NppiSize srcsize = {inwidth, inheight};
    NppiRect srcroi  = {0, 0, inwidth, inheight};
    NppiSize dstsize = {rsz_img.cols, rsz_img.rows};
    NppiRect dstroi  = {0, 0, rsz_img.cols, rsz_img.rows};

    uchar3* d_src = NULL;
    uchar3* d_dst = NULL;

    cudaMalloc((void**)&d_src, memSize);
    cudaMalloc((void**)&d_dst, outsize);
    cudaMemcpy(d_src, image.data, memSize, cudaMemcpyHostToDevice);

    // nvidia npp 图像处理,注意:函数参数step是图像宽的三倍(三通道)
    nppiResize_8u_C3R( (Npp8u*)d_src, inwidth * 3, srcsize, srcroi,
                       (Npp8u*)d_dst, rsz_img.cols * 3, dstsize, dstroi,
                       NPPI_INTER_NN);
    cudaMemcpy(rsz_img.data, d_dst, outsize, cudaMemcpyDeviceToHost);
    cudaFree(d_src);
    cudaFree(d_dst);
}

范例2——Remap、Rotate180°

对于旋转操作,需注意旋转中心是左上角,旋转180°后需要shift图片才行,具体见代码

void cudaRemap(cv::Mat &image, cv::Mat &rsz_img, Npp32f* d_mapx, Npp32f* d_mapy, bool rotate_flag)
{
    int outsize = rsz_img.cols * rsz_img.rows * sizeof(uchar3);

    int inwidth = image.cols;
    int inheight = image.rows;
    int memSize = inwidth * inheight * sizeof(uchar3);

    NppiSize srcsize = {inwidth, inheight};
    NppiRect srcroi  = {0, inheight/2, inwidth, inheight};
    NppiSize dstsize = {rsz_img.cols, rsz_img.rows};
    NppiRect dstroi  = {0, 0, rsz_img.cols, rsz_img.rows};

    Npp8u* d_src = NULL;
    Npp8u* r_tmp = NULL;
    Npp8u* d_dst = NULL;

    cudaMalloc((void**)&d_src, memSize);
    cudaMalloc((void**)&r_tmp, memSize);
    cudaMalloc((void**)&d_dst, outsize);

    cudaMemcpy(d_src, image.data, memSize, cudaMemcpyHostToDevice);
    NppiRect rotate_roi = {0, 0, inwidth, inheight};
    if (rotate_flag){
        // *** nppiRotate_8u_C3R: Rotates an image around the origin (0,0) and then shifts it.  Origin -> left bottom corner ***
        NppStatus res = nppiRotate_8u_C3R(d_src, srcsize, inwidth * 3, rotate_roi,
                                        r_tmp, inwidth * 3, rotate_roi, 180.0, srcsize.width-1, srcsize.height-1, NPPI_INTER_NN);
        nppiRemap_8u_C3R(r_tmp,
                        srcsize,
                        inwidth * 3,
                        srcroi,
                        d_mapx,
                        (rsz_img.cols * sizeof(float)),
                        d_mapy,
                        (rsz_img.cols * sizeof(float)),
                        d_dst,
                        rsz_img.cols * 3,
                        dstsize,
                        NPPI_INTER_LINEAR);
    }
    else{
        nppiRemap_8u_C3R(d_src,
                        srcsize,
                        inwidth * 3,
                        srcroi,
                        d_mapx,
                        (rsz_img.cols * sizeof(float)),
                        d_mapy,
                        (rsz_img.cols * sizeof(float)),
                        d_dst,
                        rsz_img.cols * 3,
                        dstsize,
                        NPPI_INTER_LINEAR);
    }
    cudaMemcpy(rsz_img.data, d_dst, outsize, cudaMemcpyDeviceToHost);
    cudaFree(d_src);
    cudaFree(r_tmp);
    cudaFree(d_dst);    
}

参考

https://docs.nvidia.com/cuda/npp/index.html

你可能感兴趣的:(计算机视觉,CUDA,C++,图像处理,计算机视觉,人工智能)