您的位置:首页 > 运维架构 > Linux

Linux编译OpenCV3.2.0-OCL模块并使用

2017-10-12 09:52 477 查看
之前老板已经编译好了OpenCV3.2.0 ,但是好像无法使用ocl模块?


所以我想应该是他当初编译的时候没有选择WITH_OPENCL,所以我决定重新编译一遍。

一、下载CMake并安装

1、我下载的是CMake3.4.0并安装完毕(教程网上有太多 就不重复);

但我运行./configure时出现:


解决办法:yum install ncurses-devel 如果下载不了,就自己手动下载:我是手动下载的:ncurses-devel-5.9-14.20130511.el7_4.x86_64.rpm (然后用rpm命令安装即可)。

2、安装cmake-gui

yum install cmake-gui

检验是否安装成功  :直接运行 cmake-gui  即可出现cmake界面

二、下载安装OpenCV

我是手动去官网下载OpenCV3.2.0.tar.gz的,然后解压在opencv-OpenCL-3.2.0文件夹下。

三、编译OpenCV-OCL

1、新建一个OpenCV3.2_With_OpenCL文件夹

2、终端下运行cmake-gui打开界面

3、像下面那样填写目录,开始编译:(等了很久)


我的出现这个错误:仔细看就是:



a.我试着手动下载这个红色部分提示缺少的文件:ippicv_linux_20151201.tgz
https://raw.githubusercontent.com/Itseez/opencv_3rdparty/81a676001ca8075ada498583e4166079e5744668/ippicv/ippicv_linux_20151201.tgz  在这里下载。如果这个下载不了就在: http://download.csdn.net/download/chu_ying/9432287  下载。

然后,将刚才下载的文件直接拷贝进入opencv3.1源码的下面这个目录:opencv-OpenCL-3.2.0/3rdparty/ippicv/downloads/linux-808b791a6eac9ed78d32a7666804320e


类似这个目录下。

b.终端下打开cmake-gui 点击configure  就会接着之前失败的地方进行(这次速度很快):


发现那个WITH_OPENCL竟然是自动选上的。

c.点击generate (速度比较快)(没有出现什么错误)

d.在文件夹OpenCV3.2_With_OpenCL下打开终端  运行 make  (出现很多东西 等待。。。)


类似这样的东西。。。感觉等待了一万年。。。



e.接着运行 make install  



这样编译好的OpenCV3.2.0的lib和include原来都在usr/include/下面 ,去找就找到了。(其实最好不搞在这里 开始应该指定目录的)

可以在此运行 opencv_version -v  应该出现像我一样的画面:



这样创建工程时加上库路径和头文件路径等 就OK了。运行了一个简单例子,成功。

奇怪之处:在记录这篇文章之前 我的OpenCL版本是2.0的:



但这次编译之后却变成了1.2的了?tell me why????????哦我知道了,不是编译的原因,而是硬件原因:我的驱动是OpenCL2.0,但我的显卡是Rx 560不支持OpenCL 2.0 只支持OpenCL1.2 !!! ps:大神说:当前能支持OpenCL 2.0的是 AMD GPU基于GCN 1.1或更高版本架构的GPU,比如R9 285支持。R9 3XX很多都支持。另外就是Broadwell处理器架构或更新架构的Intel HD(或Iris) Graphics能支持。

刚刚查了下:GPU型号与OpenCL版本支持关系:https://en.wikipedia.org/wiki/List_of_AMD_graphics_processing_units

Chip seriesMicro-architectureFabSupported APIsIntroduced with
renderingcomputing
VulkanOpenGL[4]Direct3DHSAOpenCL
R100fixed-pipeline180 nm

150 nm
No1.37.0NoNoOriginal "ATI Radeon", as well as Radeon DDR, 7000, 7500, VE, and LE models
R200programmable pixel&vertex pipelines150 nm1.48.18500, 9000, 9200 and 9250
R300150 nm

130 nm

110 nm
2.09.0

11 (FL 9_2)
9500–9800, X300-X600, X1050
R420130 nm

110 nm
9.0b

11 (FL 9_2)
X700–X850
R52090 nm

80 nm
9.0c

11 (FL 9_3)
X1300–X1950
R600TeraScale
1
80 nm

65 nm
3.310.0

11 (FL 10_0)
ATI StreamHD 2000 series, HD 3410
RV67055 nm10.1

11 (FL 10_1)
ATI Stream APP[5]HD 3450-3870, Mobility HD 2000 and 3000 series
RV77055 nm

40 nm
1.0HD 4000 series
EvergreenTeraScale
2
40 nm4.411 (FL 11_0)

12 (FL 11_0)
1.2HD 5000 series
Northern IslandsTeraScale
3
HD
6000 series, and IGP 7000 series
Southern IslandsGCN
1st gen
28 nm1.04.511 (FL 11_1)

12 (FL11_1)
Yes1.2, new driver 2.0 possibleHD 7000 series
Sea IslandsGCN
2nd gen
11 (FL 12_0)

12 (FL 12_0)
2.0 (2.1 in Beta and 2.2 with driver update)Radeon 200 series
Volcanic IslandsGCN
3rd gen
Radeon 300 series
Arctic IslandsGCN
4th gen
14 nmRadeon 400 series
VegaVega12 (FL 12_1)Radeon VEGA series


四、运行ocl的例子

但运行ocl的例子时还是报错说:oclMat 不是‘cv::ocl’成员  ??

最近谷歌打不开。

终于知道了:http://blog.csdn.net/jia20003/article/details/69802932  原来OpenCV3.x后使用UMat取代了OpenCV2.x的oclMat!难怪无论是我编译的还是之前老板编译的OpenCV3.2使用oclMat都错的!(不过发现还是要自己编译,最好不用老板编译好的,因为刚刚发现老板编译好的include下没有3rdparty更没有CL文件夹,所以想了下,如果不要用到opencv-ocl模块,还是可以用老板编译的版本;但如果要用opencv-ocl模块,还是用我自己编译的)用UMat就好了!UMat就是以前的oclMat!

1、UMat(ocl)小例子


按照这个人的介绍 UMat即是ocl,我的设备支持OpenCL,故启动UMat就是启动了GPU运行。 我这个例子应该是在GPU上,但耗时是341 ms。 

    2、对比原opencv程序

原来的纯CPU的程序:



这个耗时只要19ms!!!

3、对比我自己写的纯OpenCL程序

     我自己写了一个纯OpenCL的腐蚀:


我这个耗时是129 ms!!!

当然这个没太多可比性,只是一个参考数据!因为UMat那个参杂了Mat到UMat的转化(需要时间),或者可能这个简单的运算并不适合GPU并行?!

后来看了 https://stackoverflow.com/questions/41688751/understanding-the-usage-of-opencl-in-opencv-mat-umat-objects  

又用这个例子试了下:main.cpp

#include <opencv2/core/ocl.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace cv::ocl;
using namespace std;

int main()
{
TickMeter tm;
tm.start();

//launch OpenCL environment...
std::vector<cv::ocl::PlatformInfo> plats;
cv::ocl::getPlatfomsInfo(plats);
const cv::ocl::PlatformInfo *platform=&plats[0];
//	cout<<"Platform name: "<<platform->name().c_str()<<endl;
cv::ocl::Device current_device;
platform->getDevice(current_device,0);
//	cout<<"Device name: "<<current_device.name().c_str()<<endl;
current_device.set(0);
ocl::setUseOpenCL(true);

cv::UMat test_ocl_img;
imread("/home/jumper/Ecology_OpenCL/erodecontrasttest/test.bmp").copyTo(test_ocl_img);
cv::UMat test_gray_img(test_ocl_img.rows,test_ocl_img.cols,CV_8UC1);
cvtColor(test_ocl_img, test_gray_img, CV_BGR2GRAY);
threshold(test_gray_img, test_gray_img, 40, 255, 0);
imwrite("ocltemp.bmp",test_gray_img);

cv::UMat element_img;
getStructuringElement(MORPH_RECT, Size(2, 2)).copyTo(element_img);
erode(test_gray_img, test_gray_img, element_img);

tm.stop();
std::cout<<"count="<<tm.getCounter()<<" ,process time="<<tm.getTimeMilli()<<" ms."<<std::endl;

return 0;
}
结果发现时间还是很慢啊!?个人觉得:这个不适合用OpenCL  这么一点又没什么计算量 时间当然比用纯CPU的API多!
 就相当于 杀鸡用牛刀和水果刀的区别 : 牛刀切开鸡脖子比水果刀快  但牛刀重 ,举起来就要花很久  而水果刀轻方便拿!!!

五、总结
刚刚在windows下查看了OpenCV3.1的源码,发现opencv_core和opencv_highgui库下有很多核函数即cl文件:



图中这个cv::split()就是我们以前常用的纯opencv函数纯CPU的!
然后再看下面这个:这个opencv的gpu版本即ocl版本的split()函数,即这个函数启动时会在GPU上运行!看这里有核函数、globalsize及run等



而第一个图的这句话:
CV_OCL_RUN(_m.dims() <= 2 && _mv.isUMatVector(),
ocl_split(_m, _mv))
说明,OpenCV3.x版本的纯CPU的API中都有了GPU的判断接口,如果判断是UMat,则启动这个API的GPU版本的函数!否则启动以前的老的纯CPU版本的函数!

所以:只要是硬件条件支持OpenCL、为工程添加所需的OpenCL库及头文件、在main中添加进ocl命名空间、使用UMat ,只要满足这4个条件那么就是在GPU上运行的!!!

#include <opencv2/core/ocl.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace cv::ocl;
using namespace std;

int main()
{
TickMeter tm;
tm.start();

//launch OpenCL environment...
std::vector<cv::ocl::PlatformInfo> plats;
cv::ocl::getPlatfomsInfo(plats);
const cv::ocl::PlatformInfo *platform=&plats[0];
//	cout<<"Platform name: "<<platform->name().c_str()<<endl;
cv::ocl::Device current_device;
platform->getDevice(current_device,0);
//	cout<<"Device name: "<<current_device.name().c_str()<<endl;
current_device.set(0);
ocl::setUseOpenCL(true);

cv::UMat test_ocl_img;
imread("/home/jumper/Ecology_OpenCL/erodecontrasttest/test.bmp").copyTo(test_ocl_img);
cv::UMat test_gray_img(test_ocl_img.rows,test_ocl_img.cols,CV_8UC1);
cvtColor(test_ocl_img, test_gray_img, CV_BGR2GRAY);
threshold(test_gray_img, test_gray_img, 40, 255, 0);
imwrite("ocltemp.bmp",test_gray_img);

cv::UMat element_img;
getStructuringElement(MORPH_RECT, Size(2, 2)).copyTo(element_img);
erode(test_gray_img, test_gray_img, element_img);

tm.stop();
std::cout<<"count="<<tm.getCounter()<<" ,process time="<<tm.getTimeMilli()<<" ms."<<std::endl;

return 0;
}
像我这个文件中的灰度转换、阈值化、存图、腐蚀都是在GPU上!

当然等谷歌重新开放时我会再次查证!

我刚刚又看了OpenCV3.1的源码:(只是看了一部分,几个库中)

1、发现图像校正、图像轮廓、ml中的所有函数都没有OpenCL加速版本!

2、只要是#include "opencl_kernels_....hpp" 的都有OpenCL版本的API!如:图像分离与合成、形态学操作、阈值化、平滑滤波、边缘检测、Harris角点检测相关的(比如梯度矩阵的最小特征值cornerMinEigenVal())、特征检测、直方图检测、霍夫直线检测、图像缩放、图像的几何变换、图像金字塔等相关的API都有相应的OpenCL版本!

他还说:

通过Mat::getUMat()之后就获取一个UMat对象,同样在UMat对象操作期间,作为父对象Mat也会被LOCK直到子对象UMat销毁之后才可以继续使用。

OpenCV的官方文档说不鼓励在一个方法和一段代码中同时使用Mat与UMat两种方式,因为这样做真的非常危险。此外Mat与UMat还可以相互拷贝,但是这种方式也不是OpenCV官方提倡与推荐的,所以尽量别用这种方式。

参考了 http://www.cnblogs.com/emouse/archive/2013/02/22/2922940.html 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  OpenCL opencv linux