前言 本文分享一篇关于opencv高性能计算基础的文章,这是一个作者对工作期间使用OpenCV和CUDA开发高性能算法库的过程所涉及到的知识要点和踩坑的记录,将会涉及OpenCV, CUDA和C++的一些知识。
作者:风暴洋@知乎(已授权)
编辑:CV技术指南
原文:https://zhuanlan.zhihu.com/p/429109879
OpenCV是一套Apache 2协议的C++开源库,涉及图像处理、三维重建、人工智能等领域。这些领域都对性能有着严苛的要求。OpenCV在不断的迭代中,逐渐向几个方向扩展着其计算能力,下面以OpenCV中每个方向对应的类为锚进行列举:
内存的管理是几乎每个C++项目都要谨慎考虑的问题。OpenCV中有一套高效易用的内存管理体系,使得多数情况下内存的管理不会成为效率的额外负担。此外,一些特性可能会使用户的代码产生意外的结果,有必要在用OpenCV进行开发前进行详细的了解。
引用计数
OpenCV中的各种Mat类可能具有多种含义:它们既可以用来表示一副BGR图像,也可以用来保存浮点型的视差值或者某个图像一个ROI区域的临时表示。不幸的是,这些数据通常都较大,如果经常进行深拷贝会对程序性能造成严重影响。在CUDA上,内存分配甚至可能远比Kernel耗时。对此,OpenCV的策略是,cv::Mat类以及cv::cuda::GpuMat类对同类型实例的拷贝构造函数,operator= 重载以及ROI区域截取均为浅拷贝操作,并用简单的引用计数管理共享的内存。需要注意的是,这与写时复制 (COW) 不同,OpenCV无法判断Mat的数据何时被写入,如果改变了一个副本data指针所指向的数据而在此之前没有调用create()等函数改变data指针本身的值,那么所有副本的数据都会发生变化。实现Mat类的深拷贝,可以使用copyTo()和clone()等函数。一些常见情况如下所示:
cv::Mat src(100, 100, CV_32FC1); //原始矩阵
cv::Mat shared1(src); //共享了内存
cv::Mat shared2 = src; //共享了内存
cv::Mat shared3(src(cv::Rect(10, 10, 10, 10))); //共享了内存
cv::Mat independent1 = src.clone(); //申请了新的内存
cv::Mat independent2;
src.copyTo(independent2); //申请了新的内存
create()
在图像处理领域,存在大量类似“连续对许多尺寸和类型相同但内容不同的数据进行相同操作”的算法,如实时的深度计算或神经网络的连续推理。以Guided Filter为例,其流程如下[1]:
Guided Filter
其中I, p是输入数据,q是输出数据,中间会产生许多尺寸相同的临时对象。对于其中的每一个步骤以及算法整体,输出矩阵的尺寸仅和当前的输入相关。当中间变量的生命周期足够长(如作为成员变量时),我们有两种内存分配策略:
第一种方法使得用户可以完全控制内存分配的时机,提升程序内存和效率的稳定性;而第二种方法对于用户来说十分简单快捷,能够自动适应不同的输入。
事实上第二种方法是OpenCV对绝大多数函数参数中的 cv::OutputArray (作为输出参数的 cv::Mat 等数据结构的代理) 所采用的方法,拜其所赐我们免去了在调用OpenCV函数前对dst进行手动分配的麻烦。对于cv::Mat和cv::cuda::GpuMat,此操作由create()成员函数执行,其简化的源码如下:
void cv::cuda::GpuMat::create(int _rows, int _cols, int _type) {
if (rows == _rows && cols == _cols && type() == _type && data) return; //尺寸符合条件时直接返回
if (data) release(); //减少引用计数
allocator->allocate(this, rows, cols, esz); //重新分配内存,data将指向新的空间
if (refcount) *refcount = 1; //为新分配的空间启用引用计数
}
可见,当实例目前的尺寸符合要求时,create()将会立刻返回。假设用户对同一个cv::Mat进行了100次blur() (not-in-inplace),那么只有第一次blur()会申请内存。
临时缓冲区优化
由于OpenCV的算法大部分以单独的函数而非类形式提供,无法完全避免中间变量的内存分配,OpenCV提供了一些机制以减小使用临时缓冲区的代价。
理论部分到此为止,后续会更新使用OpenCV CUDA模块进行开发的一些心得。
[1] K. He, J. Sun. Fast Guided Filter.
本文仅做学术分享,如有侵权,请联系删文。