nppi三通道Resize_8u_C3R等尺寸缩放输出乱码问题
问题根因
核心错误是显存分配、主机与设备间内存拷贝的字节数计算错误。
你之前用单通道NPP缩放函数没遇到问题,是因为单通道8位图像每个像素占1字节,mat.total()返回的像素总数刚好等于需要的字节数;但3通道8位格式CV_8UC3每个像素占3字节,你代码里只分配了实际所需1/3的显存空间,NPP运行时写入越界,未被申请的显存区域数据是随机值,最终拷贝回主机端就表现为大面积乱码。
你观察到输出图只有顶部1/3区域能正常缩放、其余区域全是乱码,和这个错误的表现完全吻合:只有前1/3的像素数据落在了你合法申请的显存地址范围内,剩余2/3的像素读写都落在未申请的非法地址上。
修复方案
把所有涉及显存字节数计算的位置,从直接使用mat.total()替换为mat.total() * mat.elemSize(),一共需要修改4处代码:
- 源图像显存分配
// 错误写法 cudaMalloc(&gpuBuffer1, mat.total()); // 修正后 cudaMalloc(&gpuBuffer1, mat.total() * mat.elemSize());
- 目标图像显存分配
// 错误写法 cudaMalloc(&gpuBuffer2, mat.total()); // 修正后 cudaMalloc(&gpuBuffer2, mat.total() * mat.elemSize());
- 主机到设备的内存拷贝
// 错误写法 cudaMemcpy(gpuBuffer1, mat.data, mat.total(), cudaMemcpyHostToDevice); // 修正后 cudaMemcpy(gpuBuffer1, mat.data, mat.total() * mat.elemSize(), cudaMemcpyHostToDevice);
- 设备到主机的内存拷贝
// 错误写法 cudaMemcpy(mat2.data, gpuBuffer2, mat.total(), cudaMemcpyDeviceToHost); // 修正后 cudaMemcpy(mat2.data, gpuBuffer2, mat.total() * mat.elemSize(), cudaMemcpyDeviceToHost);
优化建议
- 你代码里传入NPP的行步长参数
mat.cols * 3在当前场景下是正确的,但更稳妥的写法是直接传入OpenCV Mat自带的mat.step属性作为步长,后续如果遇到带行对齐填充的Mat数据,不会出现步长计算错误。 - 建议给所有CUDA API、NPP API调用加统一的错误检查,遇到越界访问这类问题时,用
cuda-memcheck工具运行程序可以直接抛出非法内存访问的报错信息,大幅缩短问题定位时间。
内容的提问来源于stack exchange,提问作者Brian Yeh
相关产品推荐
相关产品推荐

