欢迎关注我的公众号 [极智视界],获取我的更多经验分享
大家好,我是极智视界,本文来谈谈 cv::cuda::GpuMat 数据排布的误区。
邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https://t.zsxq.com/0aiNxERDq
opencv 是一个功能强大的图像处理库,被广泛应用于计算机视觉和机器学习领域。在计算机视觉领域,一般说到图像数据排布大抵就是 NCHW、NHWC、CHW 等等。拿 opencv 来说,它的主要图像数据结构 cv::Mat 就是 CHW 的。这应该很好理解,如果是 RGB 的图像,那它的 opencv 数据排布就是 RRRGGGBBB 的,这就是 CHW。那么如果是 HWC 呢,那应该就是 RGBRGBRGB 了。
好了,这里要开始说 cv::cuda::GpuMat 数据排布的误区了。先来看一下下面这些操作:
# cpu数据
cv::Mat img = cv::imread("./data/img.png");
cv::cvtColor(img, img, cv::COLOR_BGR2RGB, 0);
# gpu数据
uint8_t *gpuBuf;
cudaMalloc(&gpuBuf, sizeof(u_int8_t) * img.cols * img.rows * 3);
cv::cuda::GpuMat gimg;
gimg.upload(img);
cv::uint8_t *data = (cv::uint8_t *)gpuBuf;
cv::cuda::GpuMat dst(cv::Size(img.cols, img.rows), CV_8UC3, data);
gimg.copyTo(dst);
# 下放cpu数据
cv::Mat cimg;
gimg.download(cimg);
到道理,主要做了读取一张图片赋给 img,img 是 cpu 上的 cvMat,然后将它 upload 给 gimg,它是 gpu 上的 cvMat,然后这里还有个数据是 gpuBuf,它是展平后的 gpu 上的数据。
那么这个时候你可以考虑一下,不考虑 device 的话,单纯从数值来看,img.data == gimg.data == gpuBuf?
成立吗,估计大部分人都会觉得是成立的,因为中间咱们只是做了一些内存拷贝的操作,并没有太多特殊的操作,数据应该是不会改动的。我来给答案,它们是不完全一致的。哪个有问题呢,答案是 gimg.data。
来看一下下面的对比图,你就了解了:
左边是 img.data (gpuBuf 和 img.data 一致),右边是 gimg.data。可以看到 gimg.data 后面有很多补零,这是因为 cv::cuda::GpuMat.data 的数据是 2048 字节补齐的,而同为 cpu 版的 mat.data 就不会有这个问题,这个误区很容易让人犯错。比如你如果用 gimg.data 来代替 gpuBuf 使用,结果就会有问题;或者你可能实验了将 gimg download 到 cpu mat (也就是代码中的 cimg),然后结果又是正确的,就认为 gimg.data 没有问题,想当然地认为 gimg.data 等价于 cimg.data,这样其实进一步导致这个问题并不太容易被发现。
好了,以上分享了谈谈 cv::cuda::GpuMat 数据排布的误区。希望我的分享能对你的学习有一点帮助。
【极智视界】
《极智AI | cv::cuda::GpuMat数据排布的误区》
畅享人工智能的科技魅力,让好玩的AI项目不难玩。邀请您加入我的知识星球,星球内我精心整备了大量好玩的AI项目,皆以工程源码形式开放使用,涵盖人脸、检测、分割、多模态、AIGC、自动驾驶、工业等。不敢说会对你学习有所帮助,但一定非常好玩,并持续更新更加有趣的项目。https://t.zsxq.com/0aiNxERDq