使用NVIDIA NPP库转换YUV420到BGR时如何正确设置rSrcStep参数
解决nppiYUV420ToBGR_8u_P3C3R的NPP_STEP_ERROR问题
问题原因
你手动设置的rSrcStep={1920,1920/2,1920/2}不符合NPP的要求,核心问题在于:OpenCV的cv::Mat为了内存对齐,实际步长(step[0])并不等于图像的像素宽度,而NPP函数对输入步长的内存对齐有严格要求。
正确的rSrcStep设置方法
I420(YUV420P)是平面格式,Y、U、V三个平面在内存中连续存储,且共享同一个Mat的步长(因为整个YUV数据被打包进了一个单通道Mat)。正确的做法是从Mat中提取每个平面的指针和实际步长:
cv::Mat yuvMat(cv::Size(1920, 1080*3/2), CV_8UC1, (void*)data); // 分离Y、U、V平面的起始指针 Npp8u* pSrcY = yuvMat.data; Npp8u* pSrcU = yuvMat.data + 1920 * 1080; // Y平面总字节数:宽×高 Npp8u* pSrcV = pSrcU + (1920/2) * (1080/2); // U平面总字节数:(宽/2)×(高/2) // 获取Mat的实际步长(内存对齐后的数值) int matStep = yuvMat.step[0]; // 组装rSrcStep数组,三个平面的步长都等于matStep int rSrcStep[] = {matStep, matStep, matStep};
关键说明
- I420格式中,U和V平面的像素宽度是原图的一半,但它们存储在同一个连续内存块中,所以步长和Y平面一致,由Mat的内存对齐规则决定,而非单个平面的像素宽度。
- NPP要求输入步长满足内存对齐(通常是4/8字节的倍数),OpenCV的Mat默认会自动处理内存对齐,直接使用
yuvMat.step[0]就能满足要求。
完整调用示例
// 定义ROI尺寸 NppiSize roiSize = {1920, 1080}; // 分配目标BGR内存,获取目标步长 Npp8u* pDstBGR = nullptr; int nDestStep = 0; pDstBGR = nppiMalloc_8u_C3(roiSize.width, roiSize.height, &nDestStep); // 调用转换函数 NppStatus status = nppiYUV420ToBGR_8u_P3C3R( pSrcY, rSrcStep[0], pSrcU, rSrcStep[1], pSrcV, rSrcStep[2], pDstBGR, nDestStep, roiSize ); // 错误检查与内存释放 if (status != NPP_NO_ERROR) { // 处理错误,比如打印错误码 } nppiFree(pDstBGR);
内容的提问来源于stack exchange,提问作者wangz
相关产品推荐
相关产品推荐

