前幾天想把代碼移植到linux下,想用服務器上的GPU來加速處理,結果搞了幾天,頭都大了,環境還沒配好,ffmpeg ,opencv,gstreamer,單獨裝都沒毛病,想讓這些庫關聯起來,而且沒毛病簡直是鬧心,還有各種依賴庫,幾十個,看着都頭大,於是棄坑,還是迴歸到Windows的懷抱。不過配置的過程,也是頭疼,網上各種教程,於是總結一下,加上自己的親身經歷,親測有效,代碼可以運行。
所需的軟件和庫
1.GPU
首先要確定你電腦上的GPU支持cuda嗎,這個可以再英偉達的官網上查看規格參數,我用的是筆記本,配的是GTX950M,cuda核心數:640 ,架構:Maxwell,還算新的架構,這個架構問題後面還是挺蛋疼的。
2.opencv2.4.13
下載地址:http://opencv.org/downloads.html
如果是2.4.9也是可以的
安裝後,就是解壓到一個文件下,
安裝完,需要配置windows的環境變量,在path中加入:D:\application\opencv\build\x64\vc12\bin; D:\application\opencv\build\x86\vc12\bin
3.CUDA ToolKit 7.5
下載地址:https://developer.nvidia.com/cuda-75-downloads-archive
讓它默認安裝,一般在c:programfiles/NVIDIAGPU computing toolkit/下。
沒有用最新的8.0,感覺應該沒差吧
4.cmake3.4.3
下載地址:https://cmake.org/download/
別問爲什麼是3.4.3,網上有人說只能用這個,說其他的報錯,好吧,我信了,且也用了。它的作用就是將opencv和cuda一起編譯,生成一個新的版本。
5.TBB ,據說是編譯opencv_core庫用的,我下的最新的,
下載地址:https://github.com/01org/tbb/releases
可以自定義安裝,好找位置。
將D:\application\tbb2017_20170226oss\bin\intel64\vc12添加到環境變量中。
6.python2.7
下載地址:https://www.python.org/downloads/
這個作用不明,好像有用吧
開始配置
啓動cmake
1.在source code :填入D:/application/opencv/sources(根據自己的目錄定,就是sources文件夾位置)
在where is to build :填入D:/application/opencv/build/cuda。這個cuda文件夾是自己建的,意思是最後編入得目的文件夾。
注意選擇advanced
2.然後點configure
會提示你選擇編譯器,選擇visual studio 12 2013 win64
cmake配置:
取消選擇BUILD_DOCS 和‘BUILD_EXAMPLES
確認‘CMAKE_LINKER’, Visual Studio vs2013的路徑
取消‘CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE’
選擇‘WITH_CUBLAS’, ‘WITH_CUDA’, ‘WITH_OPENGL’, ‘WITH_TBB’ (TBB is optional)
在CUDA_GENERATION,只能找到kelper,fermi,auto,還有空白,找不到maxwell,於是就選擇空白,不要選其他的,如果你的可以找到可以直接選擇,下邊這兩項就可以省略了。
由於我的顯卡是maxwell,它的計算能力是5.0,這個你可以官網查到
所以就要設置,CUDA_ARCH_BIN=2.0 2.1(2.0) 3.0 3.5 5.0、CUDA_ARCH_PTX=5.0
再點擊configure
會發現許多紅的消失了
這時候回彈出新的紅色,關於tbb的路徑問題
include path :D:/tbb43_20140724oss\include
再次點擊configure
會彈出配置tbb lib路徑:D:/tbb43_20140724oss/lib/intel64/vc12
再點擊configure,這次應該沒紅色了
3,沒有紅色,就可以點擊generate
如果成功,就可以再目標目錄D:/application/opencv/build/cuda下面找到一個opencv.sln
先管理員權限打開vs2013,然後打開這個opencv.sln
在解決方案管理器下,看到許多的庫,這就是要重新編譯的部分,
首先,先編譯modules下的opencv_core,opencv_gpu,分別,右鍵-僅用於此項目-生成
如果這兩個沒問題,那恭喜你,基本沒問題了,其中opencv_gpu是最慢的。
你就可以ALL_BUILD,如果沒有錯誤,就cmake_target 中INSTALL
先在release下編譯,完成後,再到debug下進行。
一次要兩個小時,這過程,慢慢等吧,而且還要祈禱沒問題發生。
編譯完會有一個重新加載,點擊全部重新加載。
比較開心的就是,我release沒報錯,在debug的時候,報錯了,於是我在debug下先編譯了opencv_gpu,然後再all_build,就成功了,簡直是個玄學。
安裝成功後,就在build/cuda/下生成install文件夾。
4.就是使用和測試了
好多坑,這個搞了一天
先將D:\application\opencv\build\cuda\install\x64\vc12\bin中的dll,拷貝到C:windows/system32目錄下。
將C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\bin加入到系統環境變量中。
D:\application\opencv\build\cuda\install\x64\vc12\bin加入到系統變量中
重啓電腦。
新建一個項目,比如main.cpp,打開視圖-其他窗口-屬性管理器,win32.user-屬性
vc++目錄
包含目錄:
D:\application\opencv\build\cuda\install\include\opencv2
D:\application\opencv\build\cuda\install\include\opencv
D:\application\opencv\build\cuda\install\includ
庫目錄:
D:\application\opencv\build\cuda\install\x64\vc12\lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib\Win32
鏈接器-輸入:
debug下
opencv_imgproc2413d.lib
opencv_calib3d2413d.lib
opencv_contrib2413d.lib
opencv_core2413d.lib
opencv_features2d2413d.lib
opencv_flann2413d.lib
opencv_gpu2413d.lib
opencv_highgui2413d.lib
opencv_legacy2413d.lib
opencv_ml2413d.lib
opencv_nonfree2413d.lib
opencv_objdetect2413d.lib
opencv_ocl2413d.lib
opencv_photo2413d.lib
opencv_stitching2413d.lib
opencv_superres2413d.lib
opencv_ts2413d.lib
opencv_video2413d.lib
opencv_videostab2413d.lib
cudart.lib
release下
opencv_imgproc2413.lib
opencv_calib3d2413.lib
opencv_contrib2413.lib
opencv_core2413.lib
opencv_features2d2413.lib
opencv_flann2413.lib
opencv_gpu2413.lib
opencv_highgui2413.lib
opencv_legacy2413.lib
opencv_ml2413.lib
opencv_nonfree2413.lib
opencv_objdetect2413.lib
opencv_ocl2413.lib
opencv_photo2413.lib
opencv_stitching2413.lib
opencv_superres2413.lib
opencv_ts2413.lib
opencv_video2413.lib
opencv_videostab2413.lib
cudart.lib
配置完debug,配置release(感覺沒啥用)
然後調試
報錯:
模塊計算機類型“x64”與目標計算機類型“X86”衝突
因爲庫是x64編譯器編出來的,但是vs默認是win32的編譯配置
在配置管理器中選擇平臺x64,沒有就新建一個,選中x64,(默認你的vs是支持編譯x64)
這個時候再去看屬性管理器,發現多了兩個debug/x64,release/x64
安裝上面配的過程,把這兩個也配了,主要是配debug
再源文件中添加,新建項-cuda7.5
test.cu文件
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
//cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);
__global__ void addKernel(int *c, const int *a, const int *b)
{
int i = threadIdx.x;
c[i] = a[i] + b[i];
}
// Helper function for using CUDA to add vectors in parallel.
extern "C"
cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)
{
int *dev_a = 0;
int *dev_b = 0;
int *dev_c = 0;
cudaError_t cudaStatus;
// Choose which GPU to run on, change this on a multi-GPU system.
cudaStatus = cudaSetDevice(0);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?");
goto Error;
}
// Allocate GPU buffers for three vectors (two input, one output) .
cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
// Copy input vectors from host memory to GPU buffers.
cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
// Launch a kernel on the GPU with one thread for each element.
addKernel<<<1, size>>>(dev_c, dev_a, dev_b);
// Check for any errors launching the kernel
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
goto Error;
}
// cudaDeviceSynchronize waits for the kernel to finish, and returns
// any errors encountered during the launch.
cudaStatus = cudaDeviceSynchronize();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
goto Error;
}
// Copy output vector from GPU buffer to host memory.
cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
Error:
cudaFree(dev_c);
cudaFree(dev_a);
cudaFree(dev_b);
return cudaStatus;
}
main.cpp文件
#include <iostream>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
using namespace std;
extern "C"
cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);
int main(int argc,char **argv)
{
const int arraySize = 5;
const int a[arraySize] = { 1, 2, 3, 4, 5 };
const int b[arraySize] = { 10, 20, 30, 40, 50 };
int c[arraySize] = { 0 };
// Add vectors in parallel.
cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "addWithCuda failed!");
return 1;
}
cout<<"{1,2,3,4,5} + {10,20,30,40,50} = {"<<c[0]<<','<<c[1]<<','<<c[2]<<','<<c[3]<<'}'<<endl;
printf("cpp工程中調用cu成功!\n");
// cudaDeviceReset must be called before exiting in order for profiling and
// tracing tools such as Nsight and Visual Profiler to show complete traces.
cudaStatus = cudaDeviceReset();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaDeviceReset failed!");
return 1;
}
system("pause"); //here we want the console to hold for a while
return 0;
}
右鍵工程-生成依賴項-生成自定義-選擇cuda7.5
右鍵工程-屬性 會發現多了很多東西
選中test.cu-右鍵-屬性-項類型-cuda c/c++
工具-選項-文本編輯器-文件擴展名
添加cu cuh
致此,終於完成了,調試運行,成功。
你也可以直接測試cuda是否安裝成功
vs2013
新建項目
起名爲test
系統會爲你生成一個kernel.cu文件
直接運行,完美,成功!
.cu文件和cpp文件混合編譯,可以先建cpp,在添加.cu。也可以先建.cu,然後將代碼替換掉系統給的kernel.cu,然後再添加cpp
其中自己的代碼也出了很多問題,慢慢改,如果配置沒問題,都是可解決的,再不行就重裝一遍嘛,哈哈。