CUDA库之NPP入门(三):NPP实现Resize操作


博主将在 编程语言|CUDA入门中不定期更新NPP库相关知识


文章目录

    • 一、前言
    • 二、`nppiResize_8u_C3R`函数定义
    • 三、Demo示例
    • 四、祈福


一、前言

本文主要利用npp实现图像中的resize操作,主要步骤如下:

  • 1、利用Opencv读取图像;
  • 2、将图像数据拷贝到设备端;
  • 3、调用nppiResize函数,实现resize操作
  • 4、将nppiResize后的图像数据拷贝到Mat,并保存验证结果

二、nppiResize_8u_C3R函数定义

NppStatus 
nppiResize_8u_C3R(const Npp8u * pSrc, int nSrcStep, NppiSize oSrcSize, NppiRect oSrcRectROI, 
                        Npp8u * pDst, int nDstStep, NppiSize oDstSize, NppiRect oDstRectROI, int eInterpolation);

  • nSrcStep 指的是步长,即每行数据所占字节数,一般用opencv读取的图像,步长数都是 W ∗ 3 W * 3 W3
    也可以调用matSrc.step来获取步长;
  • **NppiSize**指感兴趣区域操作,这里赋值为图像的大小即可
  • **eInterpolation** e开头,显然是个枚举,这里指resize中所使用插值类型

npp支持的插值类型都定义在NppiInterpolationMode这个枚举中,可以在nppdefs.h中查看

常见的有最近邻、线程插值、三次插值等

typedef enum 
{
    NPPI_INTER_UNDEFINED         = 0,
    NPPI_INTER_NN                = 1,        /**<  最近邻插值 */
    NPPI_INTER_LINEAR            = 2,        /**<  线性插值 */
    NPPI_INTER_CUBIC             = 4,        /**<  三次插值 */
    NPPI_INTER_CUBIC2P_BSPLINE,              /**<  Two-parameter cubic filter (B=1, C=0) */
    NPPI_INTER_CUBIC2P_CATMULLROM,           /**<  Two-parameter cubic filter (B=0, C=1/2) */
    NPPI_INTER_CUBIC2P_B05C03,               /**<  Two-parameter cubic filter (B=1/2, C=3/10) */
    NPPI_INTER_SUPER             = 8,        /**<  Super sampling. */
    NPPI_INTER_LANCZOS           = 16,       /**<  Lanczos filtering. */
    NPPI_INTER_LANCZOS3_ADVANCED = 17,       /**<  Generic Lanczos filtering with order 3. */
    NPPI_SMOOTH_EDGE             = (1 << 31) /**<  Smooth edge filtering. */
} NppiInterpolationMode; 

三、Demo示例

通常调用opencv的resize函数,即可实现resize操作

cv::resize(matSrc, matDst, cv::Size(nRzW, nRzH));

但当出现图像内存解码在GPU上,总不能从GPU将数据拷贝到host端,再调用opencv的resize函数,再从host端拷贝到device端,再执行模型推断,那中间这个拷贝的过程显然是没有必要的。 好在NVIDIA已经提供了nppiResize函数用来实现这个功能;

const int nRzH = 450;
const int nRzW = 800;
void npp_resizeData()
{
    cv::Mat matSrc = cv::imread("./data/Fig0638(a)(lenna_RGB).jpg");
    int nH = matSrc.rows;
    int nW = matSrc.cols;
    int nC = matSrc.channels();
    int nStep = matSrc.step;
    printf("nH = %d, nW = %d, nC = %d, nStep = %d\n", nH, nW, nC, nStep);
    // 1. 将图像数据拷贝到设备端
    Npp8u *pu8srcData_dev = NULL;
    cudaMalloc((void **)&pu8srcData_dev, nH * nW * nC * sizeof(Npp8u));
    cudaMemcpy(pu8srcData_dev, matSrc.data, nH * nW * nC * sizeof(Npp8u), cudaMemcpyHostToDevice);

    // 2. 在设备端开辟空间
    Npp8u *pu8dstData_dev = NULL;
    NppiSize npp_srcSize{nW, nH};
    NppiSize npp_dstSize{nRzW, nRzH};
    cudaMalloc((void **)&pu8dstData_dev, nRzH * nRzW * nC * sizeof(Npp8u));
    cudaMemset(pu8dstData_dev, 0, nRzH * nRzW * nC * sizeof(Npp8u));
    // 3.调用nppiresize函数
    nppiResize_8u_C3R( (Npp8u*)pu8srcData_dev, nStep,  npp_srcSize,  NppiRect{0, 0, nW, nH},
                       (Npp8u*)pu8dstData_dev, nRzW * 3, npp_dstSize, NppiRect{0, 0, nRzW, nRzH},
                       NPPI_INTER_LINEAR );

    // 将resize后的图像内存(设备端)拷贝到host端
    cv::Mat newimage(nRzH, nRzW, CV_8UC3);
    cudaMemcpy(newimage.data, pu8dstData_dev, nRzH * nRzW * 3, cudaMemcpyDeviceToHost);
    if (pu8dstData_dev != NULL)
    {
        cudaFree(pu8dstData_dev);
        pu8dstData_dev = NULL;
    }
    if (pu8srcData_dev != NULL)
    {
        cudaFree(pu8srcData_dev);
        pu8srcData_dev = NULL;
    }
    // 保存图像,验证结果
    cv::imwrite("./rzImage_npp.jpg", newimage);
}

原图: 512 ∗ 512 512*512 512512大小
CUDA库之NPP入门(三):NPP实现Resize操作_第1张图片
resize后 450 ∗ 800 450*800 450800大小
CUDA库之NPP入门(三):NPP实现Resize操作_第2张图片

四、祈福

为河北祈福
CUDA库之NPP入门(三):NPP实现Resize操作_第3张图片
为栖霞矿难祈福
CUDA库之NPP入门(三):NPP实现Resize操作_第4张图片

你可能感兴趣的:(编程语言,CUDA入门)