[置顶] OpenCV&OpenCL宏观预览
2016-06-28 16:04
267 查看
撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/51745250本文来自 【jscese】的博客!
通俗理解为 计算机视图处理的一层封装库,可服务于多个平台的开源c.c++框架
OpenCL :Open Computing Language
类似于前文提到过的OpenGL ,为同一组织维护的标准接口框架,用在调度CPU GPU协作,利用起GPU的资源进行并行计算,提高性能
不同GPU厂商根据OpenCL的标准头文件实现底层逻辑
关注 linux 版本 以及 android-sdk版本 ,网址:http://opencv.org/downloads.html
linux 版本含所有源码,可自己编译整个opencv ,拿需要的module
android-sdk版本是现成的so,含有头文件, 可直接拿来用
OpenCL :
标准框架以及头文件可通过 https://www.khronos.org/opencl/获取
但是真正的实现,是由各GPU厂商根据框架的头文件来做,要细究开发,需要对应的驱动代码
在ubuntu下编译linux版本,目标平台选为android
为android编译动态库,少不了编译工具链,配置NDK :
export ANDROID_NDK=tool/android-ndk-r10 ,NDK的根目录,网上有人说什么一般NDK不行,需要什么crystal版的NDK,扯淡~
因为OpenCV 跨平台,所以编译系统采用了cmake(cross platform make),通俗理解:可根据平台不同 适配成对应的编译环境
linux下自然是纯正的Makefile-gcc-g++ , 所以ubuntu下要编译opencv ,得先安装好cmake,cmake –version 查看版本
我下载的最新2.4.13,编译步骤记录如下:
1:运行~/opencv-2.4.13/platforms/scripts/cmake_android_arm.sh 脚本内容如下:
很明显,通过cmake 进行配置编译环境,android.toolchain.cmake 为核心逻辑
2:到build_android_arm 目录下 make ,就开始全编译,最终会在这个目录下生成对应的lib 以及 测试bin之类的,makefile 环境也同样在这个目录下
make install 会生成install/sdk 目录,含有对应so以及头文件
注意事项:
android L版本后,可执行文件需要PIE,可查看android.toolchain.cmake中有这么一段:
没有PIE,编译出来的测试用例bin ,在android上跑不了
OpenCL :
各个实现平台编译手段不同,没有参考价值,不记录了
OpenCL :原理架构可参考OpenCL 原理架构
软件层面-根据OpenCL的标准接口头文件 cl.h 实现逻辑大体如下:
选择opencl框架下的platform device
platform 指接口实现平台, 也就是gpu的平台
device 指选取进行计算的设备(cpu 或者 gpu),当前准备这些的 当做 host
创建device上面的content 和 memory, 当前host与这个device属于同一content,同content才能进行数据交互
会有从当前内存 copy 数据到 devices上memory的操作,如device为gpu 即为显存
需要编写 devices上运行的程序,类似于opengl 的shader编程, 这里由opencl 往下解析运行在devices上的操作, 统称 program 程序
program 程序需要动态编译,可以得到抽象的 kernel 函数,可理解为入口函数,设置这个kernel函数的参数,host, device两端所准备的数据资源等
为device创建commandqueue,用来存放 kernel
调用clEnqueueNDRangeKernel 接口将kernel加入到commandqueue中,device会根据顺序执行当前queue中的kernel
执行之后的结果存放在 device 上,可通过clEnqueueReadBuffer 接口读回host,也就是我们当前cpu程序
host 在加入kernel之后 就与device出于异步执行状态,所以某些情况下还需要 创建event 用来同步
可以看到上面 编译步骤的第一个执行脚本cmake_android_arm.sh 中需要传入参数:
/opencv-2.4.13/module/ocl/src/cl_runtime/cl_runtime.cpp中添加动态库加载的路径 返回CV_CL_GET_PROC_ADDRESS(name)
可看到适配了有 APPLE ,WIN ,LINUX 的,需要添加ANDROID的GetProcAddress ,可参考LINUX的:
对应加一段 #if defined(ANDROID) … #endif 中间的加载so路径名称 视具体平台而定
从编译上来看 是依赖于opencv的算法
动态编译为opencl的kernel函数:\opencv-2.4.13\modules\ocl\src\cl_operations.cpp 中的 openCLGetKernelFromSource:
编译好kernel之后,调用openCLExecuteKernel 加入到opencl的commandqueue中:
opencl的标准接口,其中的3代表维度,globalThreads 代表需要处理的数据资源线程数,
localThreads 代表opencl设备并行计算的线程数-受限于CL_DEVICE_MAX_WORK_ITEM_SIZES
性能主要由globalThreads 以及 localThreads 大小决定
可查看OpenCL标准cl.h中的:
这些可以调OpenCL 标准接口,从GPU驱动CL实现中获取,是作为编写OpenCL 的program-kernel程序的重要依据
附一个stack overflow:http://stackoverflow.com/questions/7996537/cl-invalid-work-group-size-error
其中有这么一段话,可以帮助理解参数含义关系:
libopencv_core . libopencv_ocl 这两个上面编译步骤lib下的库
core为OpenCV的核心,为必须的,这里用到OpenCL 就只要拿ocl这个module对应的库libopencv_ocl 即可
通过添加prebuilt编译copy到/system/lib即可
opencv2 头文件夹可又上面编译步骤说到的 make install 得到的sdk中拷贝到这里
还需要添加:
加上这个,虚函数的类没有析构函数 不当做error停止
android编译系统默认的Werror:
Android.mk中添加的LOCAL_CFLAGS是可以覆盖的
因为opencv2/core/core.hpp里面的_InputArray类析构函数并没有实现:
并没有定义该宏,而OpenCV中编译没有加Werror,并不会报错停止
~/opencv-2.4.13/platforms/build_android_arm/bin/
比如opencv_perf_ocl 即为opencv调用opencl的测试用例
opencv_perf_ocl –help 查看command info:
使用的是 googletest 框架,比较高大上,不怎么熟悉
–gtest_list_tests 查看所有的用例
–gtest_filter=XXX 跑我们想跑的用例
–gtest_repeat=[COUNT] 设置重复次数
–gtest_color=(yes|no|auto) 设置输出结果颜色
这几个参数比较实用
概念
OpenCV :Open Source Computer Vision Library通俗理解为 计算机视图处理的一层封装库,可服务于多个平台的开源c.c++框架
OpenCL :Open Computing Language
类似于前文提到过的OpenGL ,为同一组织维护的标准接口框架,用在调度CPU GPU协作,利用起GPU的资源进行并行计算,提高性能
不同GPU厂商根据OpenCL的标准头文件实现底层逻辑
源代码
OpenCV:关注 linux 版本 以及 android-sdk版本 ,网址:http://opencv.org/downloads.html
linux 版本含所有源码,可自己编译整个opencv ,拿需要的module
android-sdk版本是现成的so,含有头文件, 可直接拿来用
OpenCL :
标准框架以及头文件可通过 https://www.khronos.org/opencl/获取
但是真正的实现,是由各GPU厂商根据框架的头文件来做,要细究开发,需要对应的驱动代码
编译
OpenCV:在ubuntu下编译linux版本,目标平台选为android
为android编译动态库,少不了编译工具链,配置NDK :
export ANDROID_NDK=tool/android-ndk-r10 ,NDK的根目录,网上有人说什么一般NDK不行,需要什么crystal版的NDK,扯淡~
因为OpenCV 跨平台,所以编译系统采用了cmake(cross platform make),通俗理解:可根据平台不同 适配成对应的编译环境
linux下自然是纯正的Makefile-gcc-g++ , 所以ubuntu下要编译opencv ,得先安装好cmake,cmake –version 查看版本
我下载的最新2.4.13,编译步骤记录如下:
1:运行~/opencv-2.4.13/platforms/scripts/cmake_android_arm.sh 脚本内容如下:
#!/bin/sh cd `dirname $0`/.. mkdir -p build_android_arm cd build_android_arm cmake -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DBUILD_SHARED_LIBS=ON -DWITH_OPENCL=ON -DCMAKE_TOOLCHAIN_FILE=../android/android.toolchain.cmake $@ ../..
很明显,通过cmake 进行配置编译环境,android.toolchain.cmake 为核心逻辑
2:到build_android_arm 目录下 make ,就开始全编译,最终会在这个目录下生成对应的lib 以及 测试bin之类的,makefile 环境也同样在这个目录下
make install 会生成install/sdk 目录,含有对应so以及头文件
注意事项:
android L版本后,可执行文件需要PIE,可查看android.toolchain.cmake中有这么一段:
# pie/pic if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8)) set( CMAKE_POSITION_INDEPENDENT_CODE TRUE ) set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie") else() set( CMAKE_POSITION_INDEPENDENT_CODE FALSE ) set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" ) endif()
没有PIE,编译出来的测试用例bin ,在android上跑不了
OpenCL :
各个实现平台编译手段不同,没有参考价值,不记录了
框架实现
OpenCV: 上面有说到,实为处理封装库,主要是一些复杂的矩阵变换,以及图形处理算法的集合,模块化清晰,有需求可以针对性的研究其中的某一个模块处理流程。OpenCL :原理架构可参考OpenCL 原理架构
软件层面-根据OpenCL的标准接口头文件 cl.h 实现逻辑大体如下:
选择opencl框架下的platform device
platform 指接口实现平台, 也就是gpu的平台
device 指选取进行计算的设备(cpu 或者 gpu),当前准备这些的 当做 host
创建device上面的content 和 memory, 当前host与这个device属于同一content,同content才能进行数据交互
会有从当前内存 copy 数据到 devices上memory的操作,如device为gpu 即为显存
需要编写 devices上运行的程序,类似于opengl 的shader编程, 这里由opencl 往下解析运行在devices上的操作, 统称 program 程序
program 程序需要动态编译,可以得到抽象的 kernel 函数,可理解为入口函数,设置这个kernel函数的参数,host, device两端所准备的数据资源等
为device创建commandqueue,用来存放 kernel
调用clEnqueueNDRangeKernel 接口将kernel加入到commandqueue中,device会根据顺序执行当前queue中的kernel
执行之后的结果存放在 device 上,可通过clEnqueueReadBuffer 接口读回host,也就是我们当前cpu程序
host 在加入kernel之后 就与device出于异步执行状态,所以某些情况下还需要 创建event 用来同步
OpenCV调用OpenCL
这篇博客将cv和cl放一起来概述,原因就是cv和cl可以一起协作,通过cl的加速在图形的处理上达到最优表现适配
目前OpenCV中已经兼容支持了OpenCL ,当做了一个子模块,/opencv-2.4.13/module/ocl ,需要进行一些适配如下:可以看到上面 编译步骤的第一个执行脚本cmake_android_arm.sh 中需要传入参数:
-DBUILD_SHARED_LIBS=ON -DWITH_OPENCL=ON
/opencv-2.4.13/module/ocl/src/cl_runtime/cl_runtime.cpp中添加动态库加载的路径 返回CV_CL_GET_PROC_ADDRESS(name)
可看到适配了有 APPLE ,WIN ,LINUX 的,需要添加ANDROID的GetProcAddress ,可参考LINUX的:
#if defined(__linux__) #include <dlfcn.h> #include <stdio.h> static void* GetProcAddress (const char* name) { static void* h = NULL; if (!h) { const char* name = "libOpenCL.so"; const char* envOpenCLBinary = getenv("OPENCV_OPENCL_BINARY"); if (envOpenCLBinary) name = envOpenCLBinary; h = dlopen(name, RTLD_LAZY | RTLD_GLOBAL); if (!h) return NULL; } return dlsym(h, name); } #define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name) #endif
对应加一段 #if defined(ANDROID) … #endif 中间的加载so路径名称 视具体平台而定
大体流程
ocl的program-kernel程序代码 目录:opencv-2.4.13\platforms\build_android_arm\modules\ocl\opencl_kernels.cpp从编译上来看 是依赖于opencv的算法
动态编译为opencl的kernel函数:\opencv-2.4.13\modules\ocl\src\cl_operations.cpp 中的 openCLGetKernelFromSource:
kernel = clCreateKernel(program, kernelName.c_str(), &status);
编译好kernel之后,调用openCLExecuteKernel 加入到opencl的commandqueue中:
clEnqueueNDRangeKernel(getClCommandQueue(ctx), kernel, 3, NULL, globalThreads, localThreads, 0, NULL, NULL)
opencl的标准接口,其中的3代表维度,globalThreads 代表需要处理的数据资源线程数,
localThreads 代表opencl设备并行计算的线程数-受限于CL_DEVICE_MAX_WORK_ITEM_SIZES
性能主要由globalThreads 以及 localThreads 大小决定
可查看OpenCL标准cl.h中的:
/* cl_device_info */ #define CL_DEVICE_TYPE 0x1000 #define CL_DEVICE_VENDOR_ID 0x1001 #define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 #define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 //支持维度 #define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 //一个work group上 work item的最大数量 = MAX_WORK_ITEM X*Y*Z #define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 //维度上 work item最大数
这些可以调OpenCL 标准接口,从GPU驱动CL实现中获取,是作为编写OpenCL 的program-kernel程序的重要依据
附一个stack overflow:http://stackoverflow.com/questions/7996537/cl-invalid-work-group-size-error
其中有这么一段话,可以帮助理解参数含义关系:
Ok, let me give you a 1D example. Let's say you have 10,000 things you want to process with your CL kernel. That's your global size: 10,000. Perhaps you want to process these in groups of 100 things. That's your local size: 100. Because 10,000/100 == 100, this particular arrangement will give you 100 workgroups. Above, you have a global size of 16, and a local size of 128. This doesn't make sense for OpenCL -- 16 / 128. Perhaps you wanted 16*128 as your global size, and 128 as your local size? That would yield 16 workgroups of 128 items each
android上的移植
在模块Android.mk中添加如下:LOCAL_SHARED_LIBRARIES += \ libopencv_ocl \ libopencv_core \ libstlport LOCAL_C_INCLUDES += \ opencv2 \ bionic \ bionic/libstdc++/include \ external/stlport/stlport
libopencv_core . libopencv_ocl 这两个上面编译步骤lib下的库
core为OpenCV的核心,为必须的,这里用到OpenCL 就只要拿ocl这个module对应的库libopencv_ocl 即可
通过添加prebuilt编译copy到/system/lib即可
opencv2 头文件夹可又上面编译步骤说到的 make install 得到的sdk中拷贝到这里
还需要添加:
LOCAL_CFLAGS += -Wno-error=non-virtual-dtor
加上这个,虚函数的类没有析构函数 不当做error停止
android编译系统默认的Werror:
./build/core/config.mk:129:TARGET_ERROR_FLAGS := -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point
Android.mk中添加的LOCAL_CFLAGS是可以覆盖的
因为opencv2/core/core.hpp里面的_InputArray类析构函数并没有实现:
#ifdef OPENCV_CAN_BREAK_BINARY_COMPATIBILITY virtual ~_InputArray(); #endif
并没有定义该宏,而OpenCV中编译没有加Werror,并不会报错停止
OpenCV test 用例
最终生成的测试用例目录:~/opencv-2.4.13/platforms/build_android_arm/bin/
比如opencv_perf_ocl 即为opencv调用opencl的测试用例
opencv_perf_ocl –help 查看command info:
--perf_affinity_mask=[0] set affinity mask for the main thread --perf_force_samples=[100] force set maximum number of samples for all tests ... Test Selection: --gtest_list_tests List the names of all tests instead of running them. The name of TEST(Foo, Bar) is "Foo.Bar". --gtest_filter=POSTIVE_PATTERNS[-NEGATIVE_PATTERNS] Run only the tests whose name matches one of the positive patterns but none of the negative patterns. '?' matches any single character; '*' matches any substring; ':' separates two patterns. --gtest_param_filter=POSITIVE_PATTERNS[-NEGATIVE_PATTERNS] Like --gtest_filter, but applies to the test's parameter. If a test is not parameterized, its parameter is considered to be the empty string. --gtest_also_run_disabled_tests Run all disabled tests too. Test Execution: --gtest_repeat=[COUNT] Run the tests repeatedly; use a negative count to repeat forever. ... Test Output: --gtest_color=(yes|no|auto) ...
使用的是 googletest 框架,比较高大上,不怎么熟悉
–gtest_list_tests 查看所有的用例
–gtest_filter=XXX 跑我们想跑的用例
–gtest_repeat=[COUNT] 设置重复次数
–gtest_color=(yes|no|auto) 设置输出结果颜色
这几个参数比较实用
相关文章推荐
- nginx下载、windows系统安装、设置欢迎页
- makefile 获取shell命令的结果
- CentOS 7最小化安装后找不到‘ifconfig’命令——修复小提示
- tomcat8 下利用jconsole实现监控
- LINUX 常用命令集合
- tomcat 出现的PermGen Space问题
- linux常用命令
- 【linux】linux tomcat服务器跑项目
- Yocto令Linux羽化成蝶
- Linux下安装Scala
- ubuntu 安装apache2并配置cgi,搭建mimetex转化公式图片的服务
- Linux下搭建maven私服nexus3.x
- meave项目导入eclipse中并发布到tomcat上
- Linux/UNIX 定时任务 cron 详解
- .Net中的AOP读书笔记系列之AOP介绍
- Shell 编程
- Ubuntu默认防火墙安装、启用、配置、端口、查看状态相关信息(转)
- RHEL6换CentOS6的yum源步骤大全(附命令代码)
- 完美解读Linux中文件系统的目录结构
- linux epoll模型使用注意点