博主将在 编程语言|CUDA入门中不定期更新NPP库相关知识
本文主要利用npp实现图像中的resize操作,主要步骤如下:
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 W∗3,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;
通常调用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 512∗512大小
resize后 450 ∗ 800 450*800 450∗800大小