SIMD——请不要妄图优化opencv的函数

2023-11-21 15:10

本文主要是介绍SIMD——请不要妄图优化opencv的函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

大纲

  • ORB-SLAM特征提取之SIMD优化
    • 一、优化手段
      • 1、NEON
      • 2、SSE
    • 二、cv::gaussianblur函数优化
    • 三、cv::FAST函数优化
    • 四、原因分析

ORB-SLAM特征提取之SIMD优化

一、优化手段

1、NEON

NEON是基于ARM架构的一种128位的SIMD(Single Instruction, Multiple Data,单指令、多数据)的拓展结构,具体的细节在这里不做过多的介绍,我们来讨论NEON在实际工程中的两种使用方式:

(1)汇编

相信学习过单片机的朋友对汇编语言一定都是又恨又怕,复杂的指令与奇怪的逻辑令人望而却步,我们来看一小段基于汇编的NEON指令:

 "vld1.8       {d8,d9}, [%[in0]]\n\t""add          %[in0], %[step]\n\t""vld1.8       {d10,d11}, [%[in1]]\n\t""add          %[in1], %[step]\n\t""vld1.8       {d12,d13}, [%[in0]]\n\t""add          %[in0], %[step]\n\t""vld1.8       {d14,d15}, [%[in1]]\n\t"

什么东西?这是什么东西!说实话,我也看不太懂,所以基于汇编的NEON指令难度大,可移植性差,但是由于汇编语言的特性,决定了它具有很高的效率。Anyway,我们来看下一种方式。

(2)使用arm提供的Intrinsics函数
可以认为是内联函数,但是在编译时编译器会将函数转化为neon指令。调用该函数需要包含头文件arm_neon.h,该头文件包含了neon各种操作函数。当然,我在这里同样来展示一段代码:

 for(; j < img.cols - 16 - 3; j += 16, ptr += 16){uint8x16_t m0,m1;uint8x16_t v0 = vld1q_u8((const uint8_t*)ptr);uint8x16_t v1 = vqsubq_u8(v0,t);v0 = vqaddq_u8(v0,t);

了解过NEON的同学这段代码应该不难看懂,就是简单的加减法,我们可以看到,这种内联方式的NEON代码指令难度低,可移植行也就比汇编形式的高很多。

2、SSE

SSE是Intel x86架构CPU的SIMD指令的简称,与NEON一样具有汇编和内联函数两种形式。

二、cv::gaussianblur函数优化

由于本次实验的电脑是intel的CPU,所以采用SSE优化的方式对高斯模糊函数进行优化,在优化之前,记录了cv::gaussianblur函数的效率如下图所示:在这里插入图片描述9.41ms,在我的认知领域内,应该不是具有很高效率的时常,所以我对该函数进行了SSE优化,对gaussainblur函数的源码进行了修改,执行时间如下:在这里插入图片描述惊人的148ms。当然,如果你需要的源码,可以私信我,我发给你自己run一下。总的来说,这并不是一次非常愉快的优化过程,同样的,接下来的SSE优化也令我大跌眼镜。

三、cv::FAST函数优化

FAST提取图像中的特征点是ORB-SLAM系列中使用的一种方法,具体原理不再赘述,因为这毕竟不是一篇介绍SLAM算法的blog,我们来看opencv实现的FAST函数耗时如何:在这里插入图片描述
结果是2.65ms,不得不说opencv优化的已经很好了。注意!!!这里使用了和ORBSLAM2中相同的阈值:20。在ORBSLAM2中该函数在网格的循环遍历中被调用,ORBSLAM2将图像分为30x30个网格,在每个网格中进行FAST角点检测,经过测量,每个网格中耗时约为0.02ms,为什么差异这么大呢,首先于ORBSLAM中独特的网格划分有关系,其次与图像的大小也有关系。接下来,我们来看我进行了SSE优化的代码,相关代码已经有NEON实现,你需要做的只是将NEON转化为SSE即可:在这里插入图片描述50ms。。唉,当我看到这个结果的时候,心里有一种说不出的酸楚…

四、原因分析

实验失败不可怕,可怕的是不分析为什么失败,经过资料的查询与文献的阅读我大概的掌握了其中的奥义。

(1)OpenCV的函数自带SIMD加速,无论是gaussainblur还是FAST都自带了SMID的并行加速,并且OpenCV代码结构和顺序更加合理,能够更好的发挥CPU的全部性能
(2)OpenCV的优化是按照运行环境中CPU的架构来决定的,我们知道到INTEL的SIMD指令集avx512是高于SSE的,由于我运行的环境中支持avx512,所以使用该指令集的优化代码效率必然高于SSE。
(3)最终的建议是:别动OpenCV的源码为好,除非用汇编…,这得是神人来写了。

这篇关于SIMD——请不要妄图优化opencv的函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/403146

相关文章

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

一文详解SpringBoot响应压缩功能的配置与优化

《一文详解SpringBoot响应压缩功能的配置与优化》SpringBoot的响应压缩功能基于智能协商机制,需同时满足很多条件,本文主要为大家详细介绍了SpringBoot响应压缩功能的配置与优化,需... 目录一、核心工作机制1.1 自动协商触发条件1.2 压缩处理流程二、配置方案详解2.1 基础YAML

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

MySQL中慢SQL优化的不同方式介绍

《MySQL中慢SQL优化的不同方式介绍》慢SQL的优化,主要从两个方面考虑,SQL语句本身的优化,以及数据库设计的优化,下面小编就来给大家介绍一下有哪些方式可以优化慢SQL吧... 目录避免不必要的列分页优化索引优化JOIN 的优化排序优化UNION 优化慢 SQL 的优化,主要从两个方面考虑,SQL 语

MySQL中慢SQL优化方法的完整指南

《MySQL中慢SQL优化方法的完整指南》当数据库响应时间超过500ms时,系统将面临三大灾难链式反应,所以本文将为大家介绍一下MySQL中慢SQL优化的常用方法,有需要的小伙伴可以了解下... 目录一、慢SQL的致命影响二、精准定位问题SQL1. 启用慢查询日志2. 诊断黄金三件套三、六大核心优化方案方案

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

kotlin的函数forEach示例详解

《kotlin的函数forEach示例详解》在Kotlin中,forEach是一个高阶函数,用于遍历集合中的每个元素并对其执行指定的操作,它的核心特点是简洁、函数式,适用于需要遍历集合且无需返回值的场... 目录一、基本用法1️⃣ 遍历集合2️⃣ 遍历数组3️⃣ 遍历 Map二、与 for 循环的区别三、高