Visual Studio 2017でOpenCVをビルド with CUDA9.2

こんにちは、すすむです。初投稿です。
半導体エンジニアをやりながら機械学習について学んでます。

#やること
OpenCV を CMake GUI と Visual Studio 2017 でビルドしました。
CUDA の連携に苦労したので手順覚え書きです。

##環境
CPU: Intel(R) Core(TM) i7-8700
GPU: NVIDIA GTX 1070Ti

Windows 10 Home
CUDA 9.2  

Visual Studio Community 2017 (version 15.8.1)
Visual C++ SDK : VC15 (version 14.15 及び 14.13ミラー)
CMake 3.12.0
git version 2.17.0.windows.1
Python 3.6.6


>更新 2018/8/28
>・Cuda9.2 で tensorflow-gpu インストールできるようPythonの
>　バージョンを変更。
>　　× Python3.7.0  → 〇Python3.6.6
>・Visual Studioのバージョンを15.7.5から15.8.1に更新した
>　ことに伴い、記事下方の "yvals.h" の記述を変更。


##ビルドするもの
OpenCV 3.4.2 (with CUDA9.2)
OpenCV contrib 3.4.2


##！注意！
CUDA と Visual C++ SDK バージョンに要注意です！
CUDA のサポートが無いバージョンの場合、適切な設定をしないと
ビルドが通せないようです。

CUDA9.2 の VC++ SDK バージョン対応は以下のようになります。
![CUDA_VC++対応.png](https://qiita-image-store.s3.amazonaws.com/0/270214/bd9e76ae-4aa0-eaf7-0077-61161e14a644.png)


##VC++ SDK のバージョン確認
まずは Visual C++ SDK のバージョンを確認しましょう。
@yumetodo様の[こちらの記事](https://qiita.com/yumetodo/items/8c112fca0a8e6b47072d)にバージョン表が詳しく載っています。


VC++ SDK バージョンが14.14 以上の場合、[NVIDIA公式](https://devtalk.nvidia.com/default/topic/1027209/cuda-9-0-does-not-work-with-the-latest-vs-2017-update/)に
記載の通り、VC++ SDK の旧バージョンのミラーが必要になります。

※CUDA9.0 以下の場合は対応するミラーが無いようなので、
　大人しくVisual Studio 2015 にするしかないかもです。。


#VC++ SDK ミラーのインストール
まずは[Microsoft公式](https://blogs.msdn.microsoft.com/vcblog/2017/11/15/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2017/
)の方法で古いバージョンのVC++ SDKミラーを入れます。
Visual Studio を起動し、

　ツール -> ツールと機能を取得

から Visual Studio Installer を立上げ、"個別のコンポーネント" の中から所望の
ミラーをインストールできます。CUDA9.2 の場合は 14.13 を選べばOKです。
![VC++ミラー_インストール.png](https://qiita-image-store.s3.amazonaws.com/0/270214/e9b7ff79-842a-7acd-f2b8-a2976e1d7c42.png)


#事前の設定
##Visual Studio の言語を英語に設定
日本語設定の場合は以下で英語に変更。(CUDA関連ヘッダファイルの
エンコードが CP932 のものがあり、日本語環境だとビルドエラーします。)
![VS言語設定.png](https://qiita-image-store.s3.amazonaws.com/0/270214/d673b444-ae0d-a998-b541-f345814572d6.png)

##Pythonインストール
[Python](https://www.python.org/)もしくは[Anaconda](https://www.anaconda.com/download/)どちらでも良いのでインストール。
以下では Python 3.6.6 をインストールした体で進めます。
環境変数Pathの設定、並びに設定後のPC再起動をお忘れなく。
↓
Numpyと連携のためにpipでnumpyパッケージをインストールしておきましょう。
管理者権限のコマンドラインにて

```コマンドライン(管理者権限)
> pip install numpy
```

##Proxyの設定
Proxyが適切でないと CMake 中に必要なパッケージがダウンロードできないことが
ありますので、事前に設定しておくと良いです。

##C/C++のヘッダファイル書き換え
あまり良くないことかもしれませんが、、VC++ のヘッダーファイルを
書き換えることでビルドが通るようになります。

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\    \include\
にある yvals_core.h の299~300行目あたりを以下のように書き換え。

```C++:yvals_core.h
elif defined(_MSC_VER)
 if _MSC_VER < 1915	// Coarse-grained, not inspecting _MSC_FULL_VER

// ↓のように書き換え

elif defined(_MSC_VER)
 if _MSC_VER < 1913	// Coarse-grained, not inspecting _MSC_FULL_VER
```


#OpenCVダウンロード
C:\opencv の下でコマンドラインから

```
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
```

もしくは[ここ](https://github.com/opencv)からブラウザでダウンロードしてもOK。


#CMake
以下、CMake GUIで設定。
```Where is the source code: C:/opencv/opencv```
```Where to build the binaries: C:/opencv/opencv/build```
↓
```Configure```
↓
```Visual Studio 15 2017 Win64```
↓
再度、CMake GUIで設定

|Name|Value|
|:------------|:------------|
|CMAKE_INSTALL_PREFIX|C:/opencv/opencv/build/install|
|BUILD_EXAMPLES|ON|
|BUILD_opencv_python3|ON|
|BUILD_opencv_python_bindings_generator|ON|
|BUILD_opencv_world|ON|
|BUILD_PERF_TESTS|OFF| 
|BUILD_TESTS|OFF|
|BUILD_TBB|OFF|
|INSTALL_CREATE_DISTRIB|ON|
|OPENCV_EXTRA_MODULE_PATH|C:/opencv/opencv_contrib/modules|
|PYTHON3_NUMPY_INCLUDE_LIBS|C:/Program Files/Python36/Lib/site-packages/numpy/core/include|
|WITH_CUBLAS|ON|
|WITH_CUDA|ON|
|WITH_CUFFT|ON|
|WITH_LAPACK|OFF|
|WITH_MATLAB|OFF|
|WITH_VTK|OFF|
|WITH_TBB|OFF|

※PATH の設定でバックスラッシュでなく普通のスラッシュを使うことに注意。
↓
```Configure```
↓
再度、CMake GUIで設定。
CUDA architecture番号を[ここ](https://developer.nvidia.com/cuda-gpus)で確認。
Geforce 1070ti は 6.1 。

|Name|Value|
|:------------|:------------|
|CUDA_ARCH_BIN|6.1|
|CUDA_ARCH_PTX|6.1|
|CUDA_TOOLKIT_ROOT_DIR|C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v9.2|
↓
```Configure```
↓
```Generate```


#VC++ SDK 14.13ミラーを有効化
Visual Studioを管理者権限で開き、C:\opencv\opencv\build\OpenCV.sln を開く。
以下、[Microsoft公式](https://blogs.msdn.microsoft.com/vcblog/2017/11/15/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2017/
)に記載の方法です。

####opencv_worldのプロパティ
ソリューションエクスプローラーに出てくるopencv_worldについて、右クリック 
-> プロパティ を選択。下図のように 構成プロパティ-> C/C++ -> コマンドライン 
-> 追加のオプション の項を "-Bv" に変更。
![VC++ミラー_導入手順1.png](https://qiita-image-store.s3.amazonaws.com/0/270214/107915ff-ac0b-fc9d-b193-606e3fd55a67.png)

(この設定-Bvを入れたプロジェクトは、ビルド時にSDKのバージョンを
逐一探しにいくようになります。opencv_world 以外はデフォルト設定でOK)

####プロパティファイルを置く
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\14.13\Microsoft.VCToolsVersion.14.13.props を C:\opencv\opencv\build にコピー。(OpenCV.sln があるフォルダ)

####opencv_worldのプロジェクトファイル書き換え
opencv_world を右クリックし、プロジェクトを unload します。
そして再度右クリックして opencv_world.vcxproj の編集を選びます。
下図のように、\<Import Project="......14.13.props" /\> の行を追記、
上書き保存して opencv_world 右クリックから reload します。
![VC++ミラー_導入手順3_旧.png](https://qiita-image-store.s3.amazonaws.com/0/270214/c11cb9ed-b992-dbc5-aa16-ed7d5d4eaa35.png)



#ビルド
筆者はDebugの.dllファイルも欲しかったため、DebugとReleaseの両方でビルド。

####Debug ビルド

```ソリューション構成 -> Debug```
```ソリューションプラットフォーム -> x64```

ソリューションエクスプローラーで "Solution OpenCV" を選択して、
ビルド -> ソリューションのビルド を選択しビルド開始。

※Pythonインストール時に、カスタムインストールを選択して
　デバッグdllファイルをインストールしておけば、Debugビルドできます。
↓
ソリューションエクスプローラーで "INSTALL" を選択して
ビルド -> Project Only -> Build Only INSTALL を選択し
INSTALLのビルド開始。

####Release ビルド

```ソリューション構成 -> Release```
```ソリューションプラットフォーム -> x64```

ソリューションエクスプローラーで 'Solution OpenCV' を選択して、
ビルド -> ソリューションのビルド を選択しビルド開始。
↓
ソリューションエクスプローラーで "INSTALL" を選択して
ビルド -> Project Only -> Build Only INSTALL を選択し
INSTALLのビルド開始。


#環境変数の設定
変数名：OPENCV_DIR
変数値：C:\opencv\opencv\build

変数名：OPENCV_VER
変数値：342

変数名：PATH
変数値：%OPENCV_DIR%¥bin¥Debug;%OPENCV_DIR%¥bin¥Release
　　　：C:\opencv\opencv\build\install\x64\vc15\bin
↓
PC再起動。


#Python で CV2 をインポートできるようにする
C:\opencv\opencv\build\lib\python3\Release\cv2.cp36-win_amd64.pyd
を以下のフォルダにコピー。

C:\Program Files\Python36\Lib\site-packages
↓
以下でimportできるかを確認。コマンドラインにて

```
python
>>> import cv2 //エラーが出なければOK
```


#おわりに
いかがでしたでしょうか？ご参考になれば幸いです。

今後、画像処理/機械学習や半導体のトピックスについて
随時ご紹介していくので是非フォローいただけると嬉しいです！


##おまけ
Cuda9.2対応のtensorflow-GPUは[ここ](https://github.com/fo40225/tensorflow-windows-wheel/tree/master/1.9.0/py36/GPU)からwheelファイルを
ダウンロードして pip install により Python で使用可です。
(Tensorflow使用方法は他記事をご参照ください。)