前段时间,在TX2上装了OpenCV3.4,TX2更新源失败的问题,OpenCV内部很多函数都已经实现了GPU加速,但是我们手动写的函数,想要通过GPU加速就需要手动调用CUDA进行加速。下面介绍Linux平台的环境配置以及与OpenCV混合编译。
Linux平台CUDA+OpenCV3.4配置
1 环境安装
首先需要安装OpenCV及CUDA环境安装,有TX2平台下OpenCV和CUDA参考百度。注意TX2自带了OpenCV2.14,如果需要安装高版本的OpenCV话需要注意多版本管理的问题。安装完成后,可以编译OpenCV例程来判断OpenCV是否安转完成,CUDA安装可以在终端输入
nvcc
如果终端打印下面信息,表示安装完成
2 CUDA编译流程
CUDA的程序通过nvcc编译器编译成可执行文件,CUDA的可执行文件有两种,分别是在Host上执行的CPU相关代码,另一部分是在Device上执行的GPU代码,nvcc编译的指令与gcc/g++编译器差不多,基本指令如下
nvcc --gpu-architecture=compute_62 --gpu-code=compute_62 -I/usr/local/cuda/include/ -c kernels.cu -o kernels.o
其中:
--gpu-architecture和--gpu-code指定了GPU的计算能力,请根据自己GPU的运算能力修改,有关GPU运算能力可以在这里查找(NVIDIA官网挂了,将就着在维基百科里面看吧),--gpu-architecture指定ptx将来可以生成怎么样的版本,--gpu-code指定马上生成的代码版本,--gpu-architecture和--gpu-code可以有多个值,这样nvcc会将多个版本的代码一同放在fatbin文件中,
-I/usr/local/cuda/include/指定了CUDA包含头文件的目录,如果还有其他的头文件,要将这些头文件的路径包含进来(见3)
-c表示只对源文件进行编译,不进行链接,及将.cu文件编译生成.cu文件
-o指定要生成.o文件的文件名
还有其他的一些编译选项可以参考NVIDIA的nvcc编译手册,在CUDA的安装目录下可以找到
3 CUDA与OpenCV混合编译
CUDA与OpenCV的混合编译其实就是讲.cu文件与.c/.cpp文件混合编译,编译的方法比较多,NVIDIA官网有介绍利用cmake进行编译的方法,点这里,网上介绍的比较多的也是利用cmake进行编译,使用Makefile编译的教程比较少,这里介绍一下利用Makefile对CUDA与c++进行混合编译。
其实CUDA与c/c++一起编译原理很简单,CUDA C也只是一个拓展的c语言集,所以我采用的是利用nvcc编译器和g++分别对.cu文件和.cpp文件进行编译,生成.o文件,然后利用g++进行链接,实测方法可行。因为我CUDA的程序全部都在.cu文件中,然后在.cpp文件中通过extern对CUDA的函数申明,像下面这样:
/*main.cpp*/ extern int buildMaps(float *model, float *input, float *output, int height, int width); int main() { /*初始化代码*/ ...... buildMaps((float *)model, (float *)input, output, width, width); /*other*/ ...... }
/*kernel.cu*/ /*GPU内核函数*/ __global__ void kernel_compute(float *model, float *input, float *output) { ...... } int buildMaps(float *model, float *input, float *output, int height, int width) { /*init*/ ...... kernel_compute <<<grid, block>>> (dev_m, dev_i, dev_o); /*other*/ ...... }
所以这里的OpenCV代码像普通OpenCV代码一样写Makefile就行,写CUDA的代码的Makefile时注意,如果.cu文件中有OpenCV的相关代码的话,需要在nvcc编译的时候添加
-DOPENCV `pkg-config --cflags opencv-3.4`
用来指定OpenCV的包含头文件路径,没有错误的话,编译完成就可以使用g++链接就可以了。
这里贴一下我自己在用的一个Makefile模板,写的比较粗糙,不过平常的编译基本够了,中小型的工程的Makefile都可以用这个模板修改的到,模板有不完善的地方还请大家指正
#cpp源文件路径 SRCS = $(wildcard ./src/*.cpp) #cu文件路径 CU_SRC = $(wildcard ./src/*.cu) #.o文件 OBJS = $(patsubst %.cpp,%.o,$(SRCS)) CU_OBJ = $(patsubst %.cu,%.o,$(CU_SRC)) #g++和nvcc编译器 CXX = g++ NVCC = nvcc #C/C++编译选项 -- OpenCV头文件路径 CFLAGS = `pkg-config --cflags opencv-3.4` #C/C++编译选项 -- 当前工程头文件路径及优化选项(-O3) CFLAGS += -I./include/ -std=c++11 -O3 #开启OpenMP CFLAGS += -fopenmp #CUDA C编译选项 NVFLAGS = --gpu-architecture=compute_62 --gpu-code=compute_62 NVFLAGS += -DOPENCV `pkg-config --cflags opencv-3.4` #C/C++链接器选项 -- OpenCV库及其路径 LDFLAGS = `pkg-config --libs opencv-3.4` -O3 LDFLAGS += -fopenmp #C/C++链接器选项 -- CUDA8.0库及其路径 NVLDFLAGS = `pkg-config --libs cuda-8.0` #最终目标 EXE = video #OpenMP选项 -- 指定绑定CPU GOMP_CPU_AFFINITY="0 3 4 5" #链接 $(EXE) : $(OBJS) $(CU_OBJ) @echo Linking ... @$(CXX) -o $@ $^ $(LDFLAGS) $(NVLDFLAGS) #C/C++编译 %.o : %.cpp @echo Compiling $< ... @$(CXX) $(CFLAGS) -c $< @-mv *.o src/ #CUDA C编译 %.o : %.cu @echo NVCC Compiling $< ... @$(NVCC) $(NVFLAGS) -c $< @-mv *.o src/ .PHONY:clean clean : -rm src/*.o -rm $(EXE)