一Gpu模块介绍
Gpu有自己的存储叫做显存。当产生一个Mat对象时会存储到内存,这个对象由Cpu管理,这时Gpu并不能操作内存中的对象,Gpu只能操作分配在显存中的对象
1,基本类和函数
1>gpu::GpuMat类
相当于Mat
[1]不支持多维,只支持二维
[2]函数无法返回其引用
[3]没有表达式模板技术的支持
成员函数
//从m得到信息进行加载
void upload(const cv::Mat& m);
void upload(const CudaMem& m, Stream& stream);
//将信息保存到m
void download(cv::Mat& m) const;
void download(CudaMem& m, Stream& stream) const;
//exp:
Mat I1; // 内存对象,可以用imread来创建
gpu::GpuMat gI; // GPU 矩阵 - 现在为空
gI1.upload(I1); //将内存数据上传到显存中
I1 = gI1; //回传, gI1.download(I1) 也可以
很多时候,GPU函数只能接收单通道或者4通道的uchar或者float类型(CV_8UC1,CV_8UC4,CV_32FC1,CV_32FC4),GPU函数不支持双精度
如果函数只接收4通道或者单通道的图像而你的数据类型刚好是3通道的话,你能做的就是两件事:1.增加一个新的通道(使用char类型)或 2.将图像的三个通道切分为三个独立的图像,为每个图像调用该函数(推荐使用)。
2>gpu::Stream类
异步调用类
默认情况下,无论何时你调用一个GPU函数,系统都将等待调用完成并返回后继结果,这就意味着在GPU计算的时候CPU没干活。如果使异步调用,就会意味着它将调用后立即返回,并在后台异步执行,也就是说虽然CPU需要的数据还没从GPU返回,但是并不妨碍CPU进行其它的计算或者调用另一个函数。
可以异步进行类型转换,Mat与GpuMat,等其它操作
gpu::Stream stream;
//进行GpuMat的类型转换
stream.enqueueConvert(b.gI1, b.t1, CV_32F);
3>操作函数
针对GpuMat,Gpu模块中对应了Cpu模块中的一部分操作函数,进行gpu操作时调用对应的函数
//进行异步通道分离
gpu::split(b.t1, b.vI1, stream);
//进行异步乘法
gpu::multiply(b.vI1[i], b.vI1[i], b.I1_2, stream);
2,操作原则
1>在现有对象上进行计算
在GPU中,任何小的数据传输都是一次大的开销,所以应该尽量避免不必要的数据传输。因此应该尽可能的在现有对象上计算(不创造新的显存对象)
//在下面的表达式中,会有一个隐性内存分配过程,调用乘法的结果必然要
//用一个临时对象储存,然后才能和*C1*相加
b.t1 = 2 * b.mu1_mu2 + C1;
//我们应该使用GPU处理函数代替算术表达式,
//从而避免额外创建不必要的临时对象
gpu::multiply(b.mu1_mu2, 2, b.t1);
gpu::add(b.t1, C1, b.t1);
2>对gpu的对象尽量一次性分配完成
exp:
如果你需要创建一个调用多次的函数,