一、提高OpenCV的运算速度,有以下几种方法:
1、利用x86转为x64提速,可以提高1倍的速度
2、多线程的openmp或Intel TBB提速,将cpu的利用率从20%多提高到100%
3、利用GPU提速,至少可以提高5~10倍的运算速度
二、openmp
https://www.openmp.org/specifications/ 下载
很多主流的编译环境都内置了OpenMP。VS 版本不低于2015,都支持 OpenMP。在VS中启用OpenMP很简单,在项目上右键->属性->配置属性->C/C++->语言->OpenMP支持,选择“是”即可。这实际上使用了编译选项/openmp。但是学习和使用openmp,应该考虑使用官方的高版本,最好不要使用Visual Studio自带的,因为VS2017只支持到OpenMP2.0版本。
openmp3.0中的task(任务,可动态配置)在多线程中是很重要的。
openmp4.0中的simd(向量化,单指令多数据),在密集性计算优化中很有用,比如挖矿类型的计算。target(异构计算相关系列指令),可以直接在openmp中使用gpgpu并行。
openmp4.5和5.0加入了很多对simd及gpu支持的深化内容。
举例:
#include "stdafx.h" #include "cv.h" #include "highgui.h" #include <stdio.h> #include <stdlib.h> #include <omp.h> #pragma comment(lib,"opencv_core2410d.lib") #pragma comment(lib,"opencv_highgui2410d.lib") #pragma comment(lib,"opencv_imgproc2410d.lib") void EdgeOpenMP(IplImage *src,IplImage *dst,int thresh) { int height = src->height; int width = src->width; int step = src->widthStep; uchar *data1 = (uchar *)src->imageData; uchar *data2 = (uchar *)dst->imageData; int i = step; #pragma omp parallel for for(i=step+1;i<height*width;i++) { if(abs(data1[i]-data1[i-1])>thresh || abs(data1[i]-data1[i-step])>thresh) data2[i]=255;/* 对于单通道,前后两帧差分大于门限 或者对于多通道前后两帧的一个指标差分大于门限,则视为边缘*/ else data2[i]=0; } } void Edge(IplImage *src,IplImage *dst,int thresh) { int height = src->height; int width = src->width; int step = src->widthStep; uchar *data1 = (uchar *)src->imageData; uchar *data2 = (uchar *)dst->imageData; int i = step; for(i=step+1;i<height*width;i++) { if(abs(data1[i]-data1[i-1])>thresh || abs(data1[i]-data1[i-step])>thresh) data2[i]=255; else data2[i]=0; } } int main() { char filename[512]; IplImage *src,*edge1,*edge2; puts("File name:"); gets(filename); src = cvLoadImage(filename,CV_LOAD_IMAGE_GRAYSCALE ); edge1=cvCloneImage(src); edge2=cvCloneImage(src); cvNamedWindow("src", CV_WINDOW_AUTOSIZE); cvMoveWindow("src", 100, 100); cvShowImage( "src", src); cvNamedWindow("Edge", CV_WINDOW_AUTOSIZE); cvMoveWindow("Edge", 200, 100); cvNamedWindow("EdgeOpenMP", CV_WINDOW_AUTOSIZE); cvMoveWindow("EdgeOpenMP", 300, 100); /* 以上都是准备一些窗口和图形基本数据 */ int tekrar=100;//运行次数 int thresh=30; double start, end,t1, t2; /* 计算没有使用OpenMP优化的时间 */ start= (double)cvGetTickCount();//记下开始的时钟计数,以便计算函数或用户代码执行时间 for(int i=0;i<tekrar;i++) Edge(src,edge1,thresh); end= (double)cvGetTickCount();//记下结束的时钟计数 t1= (end-start)/((double)cvGetTickFrequency()*1000.);//计算运行时间,以毫秒为单位 printf( "Run time without OpenMP = %g ms\n", t1 ); /* 计算使用了OpenMP优化的时间 */ start= (double)cvGetTickCount(); for(int i=0;i<tekrar;i++) EdgeOpenMP(src,edge2,thresh); end= (double)cvGetTickCount(); t2= (end-start)/((double)cvGetTickFrequency()*1000.); printf( "Run time with OpenMP = %g ms\n", t2 ); printf( "Performance ratio (%%) = %% %.1f \n", 100*(t1/t2-1) ); cvShowImage( "Edge", edge1); cvShowImage( "EdgeOpenMP", edge2); cvWaitKey(); cvDestroyWindow("Edge"); cvDestroyWindow("EdgeOpenMP"); cvReleaseImage(&src); cvReleaseImage(&edge1); cvReleaseImage(&edge2); }
参考文献:
《多核异构并行计算 OpenMP 4.5 C/C++篇》语法介绍比较详细,雷洪编著的。
OpenMP并行计算入门案例
关于使用opencv的提速(二)(多线程问题,openMP)
OpenMP简介
三、TBB --- Threading Building Blocks
https://software.intel.com/en-us/tbb
按照目前网上的讨论,TBB风头要盖过openMP,比如openCV过去是使用openMP的,但从2.3版本开始抛弃openMP,转向TBB。Opencv源码需要自己编译,cmake选项勾上TBB。Add option WITH_TBB=ON when building opencv。
举例:
// A very raw example of using tbb's thread #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/video/video.hpp> #include <opencv2/highgui.hpp> #include <tbb/tbb.h> #include <iostream> using namespace std; using namespace cv; using namespace tbb; int main(int argc, char* argv[]) { int TBB_THREADS = 3; task_scheduler_init init(TBB_THREADS); Mat im1 = imread(argv[1]); Mat imGray; if (im1.data == nullptr) { cout << "Error while reading file " << argv[1]; return 1; } imshow("Input image", im1); cvtColor(im1, imGray, CV_RGB2GRAY); Mat im3, im4; tbb_thread th1([&imGray, &im3]() // in fact, you can do this with C++ thread { int windowSize = 5; // starting threshold value int constant = 5; // starting constant value adaptiveThreshold(imGray, im3, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, windowSize, constant); }); tbb_thread th2([&imGray, &im4]() { cv::GaussianBlur(imGray, im4, cv::Size(3, 3), 5.0f); }); th1.join(); th2.join(); imshow("Grayscale image", imGray); imshow("Adaptive thresholding", im3); imshow("Gaussian blur", im4); cvWaitKey(0); return 0; }
参考文献:
OpenCV加速与优化,让代码执行速度飞起来
https://www.theimpossiblecode.com/blog/faster-opencv-smiles-tbb/
四、GPU
1、主流的显卡是NVIDIA和ATI两种,简称N卡和A卡;而opencv的gpu单指N卡显卡模块,而且只支持一部分。
N卡支持的型号一览表:https://developer.nvidia.com/cuda-gpus
Windows开始菜单--运行--输入dxdiag--显示,可以看到自己电脑的显卡型号。
笔者的显卡需要查阅网页的字段:CUDA-Enabled GeForce and TITAN Products,型号是GeForce GT 630,支持!
cuda源码下载:
https://developer.nvidia.com/cuda-toolkit
https://developer.download.nvidia.cn/compute/cuda/opensource/
如果你是ATI显卡,或者用的不是电脑,又想GPU加速怎么办呢?那就让OpenCV和OpenCL结合起来,有跨平台的作用,可以应用到ATI显卡上。
2、CUDA vs OpenCL
OpenCL: Open Computing Language,开放计算语言。
https://www.khronos.org/opencl/
OpenCL和CUDA是两种异构计算(此异构平台可由CPU,GPU或其他类型的处理器组成。)的编程模型。
CUDA只支持NVIDIA自家的GPU。OpenCL最早是由Apple提出,后来交给了Khronos这个开放标准组织。
CUDA C语言与OpenCL的定位不同,或者说是使用人群不同。CUDA C是一种高级语言,那些对硬件了解不多的非专业人士也能轻松上手;而OpenCL则是针对硬件的应用程序开发接口,它能给程序员更多对硬件的控制权,相应的上手及开发会比较难一些。
从很多方面来看,CUDA和OpenCL的关系都和DirectX与OpenGL的关系很相像。如同DirectX和OpenGL一样,CUDA和OpenCL中,前者是配备完整工具包、针对单一供应商(NVIDIA)的成熟的开发平台,后者是一个开放的标准。
虽然两者抱着相同的目标:通用并行计算。但是CUDA仅仅能够在NVIDIA的GPU硬件上运行,而OpenCL的目标是面向任何一种Massively Parallel Processor,期望能够对不同种类的硬件给出一个相同的编程模型。由于这一根本区别,二者在很多方面都存在不同:
1)开发者友好程度。CUDA在这方面显然受更多开发者青睐。原因在于其统一的开发套件(CUDA Toolkit, NVIDIA GPU Computing SDK以及NSight等等)、非常丰富的库(cuFFT, cuBLAS, cuSPARSE, cuRAND, NPP, Thrust)以及NVCC(NVIDIA的CUDA编译器)所具备的PTX(一种SSA中间表示,为不同的NVIDIA GPU设备提供一套统一的静态ISA)代码生成、离线编译等更成熟的编译器特性。相比之下,使用OpenCL进行开发,只有AMD对OpenCL的驱动相对成熟。
2)跨平台性和通用性。这一点上OpenCL占有很大优势(这也是很多National Laboratory使用OpenCL进行科学计算的最主要原因)。OpenCL支持包括ATI,NVIDIA,Intel,ARM在内的多类处理器,并能支持运行在CPU的并行代码,同时还独有Task-Parallel Execution Mode,能够更好的支持Heterogeneous Computing。这一点是仅仅支持数据级并行并仅能在NVIDIA众核处理器上运行的CUDA无法做到的。
3)市场占有率。作为一个开放标准,缺少背后公司的推动,OpenCL显然没有占据通用并行计算的主流市场。NVIDIA则凭借CUDA在科学计算、生物、金融等领域的推广牢牢把握着主流市场。再次想到OpenGL和DirectX的对比,不难发现公司推广的高效和非盈利机构/标准委员会的低效(抑或谨慎,想想C++0x)。
我接触的很多开发者(包括我本人)都认为,由于目前独立显卡市场的萎缩、新一代处理器架构(AMD的Graphics Core Next (GCN)、Intel的Sandy Bridge以及Ivy Bridge)以及新的SIMD编程模型(Intel的ISPC等)的出现,未来的通用并行计算市场会有很多不确定因素,CUDA和OpenCL都不是终点,我期待未来会有更好的并行编程模型的出现(当然也包括CUDA和OpenCL,如果它们能够持续发展下去)。