1.OpenCV中几种卷积的源码实现方式
2.opencv cv::distanceTransform()距离变换论文与源码
3.OpenCV:吊打高斯模糊的StackBlur加入
4.OpenCV中DNN库的架构
OpenCV中几种卷积的实现方式
自从opencv引入dnn模块后,卷积实现方式不断扩展,并行以适应PC、源码手机、并行边缘计算设备的源码部署需求。目前,并行台式源码还君明珠可调用CUDA、源码OpenCL、并行Tengine、源码Vulkan实现卷积。并行Tengine、源码Vulkan特别适用于移动设备和边缘计算,并行它们内部是源码如何实现的?
Vulkan是一个渲染库,与OpenGL、并行DirectX等GPU渲染库相比,源码移动设备上使用较多,而深度学习模型又需要在移动设备上部署。因此,探索是否可以使用Vulkan实现卷积等深度学习操作。
接下来,让我们看看OpenCV是如何使用Vulkan实现深度神经网络中的卷积。
打开OpenCV源码库的modules/dnn/src目录,可以看到最后一个文件夹是vkcom。"vkcom"这个名字由"Vulkan"库本身与"comp"(glsl语言的源代码后缀)组成。glsl语言可以通过以下命令编译:“vkcom”。gb资源源码GLSL是OpenGL着色语言,用于编写OpenGL着色器的编程语言,通常与并行处理功能强大的GPU结合使用。深度学习操作如卷积、池化都是对图像颜色的处理,因此可以将这些操作实现为着色器,用GLSL编写,然后使用Vulkan调用GPU。
Vulkan实现的卷积代码示例如下:
代码中指定了输入输出变量(第3、6、9、行)。在第行计算了输出变量convolved_image_data的值。第行开始的for循环遍历卷积核的c、w、h,计算单个像素位置的卷积结果。显然,这个卷积仅计算一个像素位置的卷积结果,卷积核的滑动过程由Vulkan管理GPU,多个GPU计算单元并行完成。
在OpenCV中,文件conv.comp首先被编译为二进制,然后将此二进制作为字符串放入conv_spv.cpp中。淘宝拉新源码cpp文件定义了conv_spv数组,其中包含编译后的卷积着色器执行代码。由OpBase::createShaderModule函数将此二进制送入vkCreateShaderModule,从而调度GPU。
通过分析代码,可以看到Vulkan实现的算子被调用的方式,这同样适用于CUDA、OpenCL、Ngraph、Inference Engine等实现的算子。
Vulkan渲染库在OpenCV中的调用逻辑已经阐述完毕。Tengine是如何使用的?在convolution_layer.cpp的forward函数的行,调用了tengine_forward(tengine_graph)。
Tengine_forward来自teng_run_graph函数,我们只需调用库即可得到结果。传入的graph是卷积图,由create_conv_graph在第行创建。create_conv_graph使用create_conv_node、create_input_node生成卷积算子所需的图。
使用Tengine相对使用Vulkan、CUDA等库完成算子,要简单许多。调用库内的函数生成节点,使用节点构建图即可,战队头像源码素材无需自己实现算子内的计算。
本文概述了OpenCV中卷积实现方式的多样性,以下为总结:
本文详细分析了使用Vulkan用着色器实现卷积计算的方法及其调用路径,这个路径在分析其他类型实现时也很有用。本文还探讨了不同库算子的兼容性。当然,不同算子兼容还涉及更多细节,本文仅关注卷积forward函数的传递。
本文后半部分简要介绍了Tengine在OpenCV中的集成。发现集成过程相对简单,在convolution_layer.cpp中直接运行Tengine库构建的卷积计算图。这也表明,如果存在更好的边缘计算库,很容易集成到OpenCV中。
通过几天的分析,我们已经了解了OpenCL、Vulkan、Tengine的实现方式。可以预计,CUDA、Halide、Inference Engine nn、Inference Engine NGraph等实现也会类似。
opencv cv::distanceTransform()距离变换论文与源码
OpenCV的栈的stl源码cv::distanceTransform()函数用于计算图像中所有点到最近‘0’点的距离,其应用广泛,例如在无人驾驶中,用于测量图像中最近障碍物的距离。它支持两种距离计算:L1和L2。当maskSize为DIST_MASK_PRECISE且distanceType为DIST_L2时,采用[]中的并行算法,借助TBB库。其他情况下,会使用[]算法。
简单来说,[]算法在年发表,而[]则更易于理解且适用于L2距离。距离变换定义了一个函数Df,它是输入函数f的欧氏距离变换,即对于每个点p,找到最近的q点,其距离加上f(q)值。
公式[公式]描述了经典的距离变换方法,它将每个网格位置与最近点P通过二值图像关联。在OpenCV的实现中,如/modules/imgproc/src/distransform.cpp的Line ,有一维和二维情况的处理方法。一维时,欧氏距离平方变换为[公式],二维则通过两次一维变换简化计算过程。
如果你对OpenCV的距离变换感兴趣,欢迎查看我的专栏并投稿,共同探讨OpenCV背后的原理和知识,共同进步。
OpenCV:吊打高斯模糊的StackBlur加入
简化版 StackBlur API介绍
StackBlur 最近才加入到OpenCV中,将在下一个Release版本(4.7)中出现。C++用户可以尝试从源码编译OpenCV体验一下。Python 用户可以尝试用pip安装rolling版本的OpenCV:pip install opencv-python-rolling==4.6.0.。StackBlur是高斯模糊的近似,同样支持水平和垂直不对称的滤波。
为什么StackBlur的API中s小写?OpenCV中对API有严格控制,以作者名称开头的API可以大写(如Sobel、GaussianBlur),除此之外都小写字母开头。
StackBlur的使用建议和最后的实验结果如下:
建议当kernel size > 时,用stackBlur替换高斯模糊;当kernel size特别大时,OpenCV的所有模糊滤波器中只推荐stackBlur。
实验结果如下:测试环境为Mac M1,8核,image size [ x ],数据类型:CV_8U3C。测试方法为跑一千次,选取最小作为耗时,测试脚本在这里。结论为stackBlur不会随着kernel size增加而增加耗时。
StackBlur算法的坑是由老瓦在年初挖的。当时他给了我一个任务,尝试增加一个新滤波器stackblur。最后在OpenCV上调通并产生正确模糊结果,但卡在了速度优化上。最近在优化OpenCV的DNN模块,学会了一些并行加速的技巧,终于填上了这个坑。
本文主要介绍新加入OpenCV的模糊算法Stackblur,Stackblur是一种高斯模糊的快速近似,由Mario Klingemann发明。其计算耗时不会随着kernel size增大而增加,专为大kernel size的模糊滤波场景量身定制。本文从新加入OpenCV的cv::stackBlur API开始介绍,通过对比BoxBlur和高斯模糊,阐述Stackblur的优势。接着,详细介绍了Stackblur算法的原始论文及其计算过程,解释了Stack、StackOut和StackIn的运作方式。最后,总结了Stackblur的加速优化策略和实验结果,表明Stackblur在大kernel size下的速度优势。
StackBlur算法采用Queue和Stack计算方式,与传统滤波算法不同,其计算耗时不会随着kernel size的增大而增加,这得益于其独特的计算机制。Stackblur算法在2维图像上的实现,通过先在水平方向进行1维stackblur算法,然后在垂直方向进行1维stackblur算法,实现整体的模糊效果。同时,通过多线程并行加速、SIMD指令优化等策略,Stackblur算法在性能上实现了显著提升,甚至在某些情况下比BoxBlur更快。
StackBlur的计算优化包括使用乘法代替除法运算,以减少计算量。同时,针对不同数据格式和通道数,提供了一系列优化策略,以提高性能。实验结果显示,StackBlur在kernel size <= 5的情况下,速度接近高斯模糊,而在大kernel size下(如kernel size=),StackBlur的速度远超高斯模糊。
如果你对StackBlur的加速优化和性能测试感兴趣,欢迎在评论区留言讨论,分享建议和反馈。
OpenCV中DNN库的架构
OpenCV的DNN库虽然代码量大,但其架构设计相当清晰。核心在于网络、层内容和层的协作。首先,网络类包含了多个层内容对象,负责整体的前向计算。层内容则包含了层对象、输入输出矩阵、数据转换器和计算节点,它们共同构成了网络计算的基本单元。
计算节点是核心计算单元,通过策略模式支持不同后台算子,如vkcom、cuda等,通过调用这些算子进行深度学习计算。数据转换器则通过策略模式处理数据在不同设备间的转换,如vkcom数据转换器和cuda数据转换器。
层内容根据输入数据和层类型动态确定输出矩阵大小,初始化数据转换器和计算节点。网络的前向计算流程会遍历层内容中的节点,调用节点中的算子执行计算。
算子的具体实现各异,如vkcom通过recordCommandBuffer和runCommandBuffer调用vk库的并行计算,Halide则通过计算节点直接调用Halide::Func进行计算。微软的推理引擎通过net的forward函数,而英伟达CUDA则是直接调用cudnn库的函数。
除了库内预定义的GPU和CPU实现,OpenCV还支持自定义的算子,如OpenCL实现的算子,这些算子同样通过层内容的前向计算过程被调用。总的来说,OpenCV的DNN库架构巧妙地整合了各种计算资源,为实现深度学习任务提供了灵活且高效的平台。