【備忘録】OpenCV PythonをCUDA対応でビルドしてAnaconda環境にインストール(Windows)

執筆開始時点：22/06/01

Anaconda環境のPythonでcv2を使いたい！
という単純な目的のためだけにここまでやるとは思っていなかった

ひとまずいつも通りインストール方法をググったところ
~~~:Anaconda Prompt
conda install opencv -c conda-forge
~~~
でうまくいくはず！とのことだったが
いつまで経ってもSolving environmentが終わらない
チャンネルをconda-forgeからanacondaやmempoにしても変化なし
conda自体のアプデやconda update --all をやっても変化なし

~~~
pip install opencv-python
~~~
でもいいのだが，Anaconda環境をできるだけ崩したくない
(仮想環境下でならpipでもいいけど，画像処理が主な仕事なのでbaseに入れたい)

ここで
CUDAも使えると~~色々と遊べて楽しい~~パフォーマンスが向上するので便利だし
どうせなら最新バージョンを入れたい
ということで自分で最新版のOpenCVをビルドすることにした
かなり苦戦したが使えるようになったので試行錯誤の結果をほぼ自分用にメモ

参考
https://www.kkaneko.jp/tools/win/windows_opencv.html
https://qiita.com/y-vectorfield/items/d6db3c1022fc76e7fda7
https://dev.infohub.cc/build-opencv-430-with-cuda/
https://www.usagi1975.com/201911241030/
https://elda27.hatenablog.com/entry/2020/01/29/225534

# 構築環境
+ OS: Windows 11 (バージョン 21H2)
+ CPU: 第9世代 Intel Core i7
+ GPU: NVIDIA GeForce GTX 1660Ti
+ メモリ: 16 GB
+ Anaconda
  + Python: 3.8.13
  + numpy: 1.21.5
  + Anaconda Navigator: 2.1.1
  + JupyterLab: 3.3.2
  + Jupyter Notebook: 6.4.8
  + conda: 4.12.0

OSはWin10でも基本的にやることは変わらないと思う

私は普段Anaconda環境下でJupyterLabを使っている
使っているcondaのチャンネルは
基本的にconda-forge > anaconda > defaults
の優先順位にしている (channel_priorityはstrictではなくflexible)

Pythonのバージョンは3.8で使っているが現時点では3.10まで出ているはず
問題なさそうか確認取れればそのうちアプデ後にもう一度OpenCVのビルドもやる予定

# ビルド構成
+ OpenCV: 4.5.5 (OpenCV contribも同じバージョンで)
+ NVIDIA
  + CUDA: 11.7
  + cuDNN: 8.4.1
+ Pyhton3用パッケージ

CUDAのRuntimeなどはとりあえず古いものをアンインストールして最新版を入れなおした
CUDAのインストールは [「ここ」](https://developer.nvidia.com/cuda-toolkit-archive "https://developer.nvidia.com/cuda-toolkit-archive")から
OSなどの環境を順番に選んでexeをダウンロード(localでもnetでもOK)
グラフィックのドライバなども同時に入れられるが，すでにあるので
CUDAに関連するものだけを選んでインストール (ディレクトリはデフォルトのままでOK)
環境変数Pathもデフォで通してくれます
もし通してくれなかったら
"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.7"をPathに追加

cuDNNは [「ここ」](https://developer.nvidia.com/cudnn "https://developer.nvidia.com/cudnn")からダウンロードするのに
Developer Membershipに入らないといけないらしい
NVIDIAのアカウントでログインして cuDNNが必要な理由などアンケートに答える必要がある
適当に答えてダウンロード後 解凍してCUDAをインストールしたディレクトリ
(デフォルトでは"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.7")
に中身をすべてコピー

# 使用したソフトウェア
+ [Microsoft Visual Studio Community 2022](https://visualstudio.microsoft.com/ja/ "https://visualstudio.microsoft.com/ja/")
+ [CMake 3.23.2](https://cmake.org/download/ "https://cmake.org/download/") (Windows x64 Installer をインストール)
+ [Git for Windows 2.30.0](https://gitforwindows.org/ "https://gitforwindows.org/")

Gitについては Windowsのcmdでgitコマンドを使えれば最新版じゃなくても大丈夫そう
CMakeとVS Communityは以前使用したv3.0と2019の組み合わせだとエラーが出たので
最新版をインストールしなおした

gitコマンドとcmakeコマンドが使えるように
インストールしたディレクトリを環境変数Pathに加える
gitとcmakeをターミナルで実行したときにオプション一覧(Usage)が表示されればOK

# ビルド手順
#### OpenCVのソースコードをgit clone
~~~cmd:cmd
cd C:\
md opencv
cd opencv
git clone https://github.com/opencv/opencv.git source -b 4.5.5
git clone https://github.com/opencv/opencv_contrib.git -b 4.5.5
md build
~~~
今回はソースのディレクトリとビルドのディレクトリを分かりやすくするために
C:/opencv/source にcloneを作った
~~~
C:/opencv
    ├─ source
    ├─ opencv_contrib
    └─ build
~~~
こうなるはず

#### CMakeでのビルド
パスには "\\" (バックスラッシュ)ではなく "/" (スラッシュ)を使う

色々調べるとNinjaを使うとデフォルトのVisual Studio 17 2022を指定するより
数倍速く完了するらしい (今回はやらなかったけど)

もしやるならWindowsのcmdを使わずに
VS2022 の x64 Native Tools Command Prompt から実行する
-G "Ninja" を指定して -A x64 -T host=x64 は削除
~~~
cmake -S source -B build ^
-G "Visual Studio 17 2022" -A x64 -T host=x64 ^
-D CMAKE_CONFIGURATION_TYPES="Release" ^
-D CMAKE_BUILD_TYPE="Release" ^
-D WITH_CUDA=ON ^
-D OPENCV_DNN_CUDA=ON ^
-D CMAKE_INSTALL_PREFIX=C:/OpenCV455 ^
-D CUDA_FAST_MATH=ON ^
-D ENABLE_FAST_MATH=ON ^
-D OPENCV_EXTRA_MODULES_PATH=opencv_contrib/modules ^
-D INSTALL_TESTS=OFF ^
-D INSTALL_C_EXAMPLES=OFF ^
-D BUILD_EXAMPLES=OFF ^
-D BUILD_TESTS=OFF ^
-D BUILD_PERF_TESTS=OFF ^
-D BUILD_JPEG_TURBO_DISABLE=ON ^
-D WITH_PYTHON=ON ^
-D INSTALL_PYTHON_EXAMPLES=OFF ^
-D BUILD_opencv_python2=OFF ^
-D BUILD_opencv_python3=ON ^
-D PYTHON_DEFAULT_EXECUTABLE=C:/Anaconda3/python.exe ^
-D PYTHON3_EXECUTABLE=C:/Anaconda3/python.exe ^
-D PYTHON3_INCLUDE_DIR=C:/Anaconda3/include ^
-D PYTHON3_LIBRARY=C:/Anaconda3/libs/python38.lib ^
-D PYTHON3_NUMPY_INCLUDE_DIRS=C:/Anaconda3/lib/site-packages/numpy/core/include ^
-D PYTHON3_PACKAGES_PATH=C:/Anaconda3/lib/site-packages ^
-D WITH_CUBLAS=ON ^
-D WITH_OPENGL=ON ^
-D WITH_CUDNN=ON ^
-D WITH_NVCUVID=ON ^
-D OPENCV_ENABLE_NONFREE=ON ^
-D OPENCV_PYTHON3_VERSION=3.8 ^
-D CPU_BASELINE="SSE3" ^
-D CUDA_GENERATION="Turing" ^
-D CUDA_ARCH_PTX=7.5 ^
-D BUILD_opencv_world=ON
~~~
CMAKE_INSTALL_PREFIX=C:/OpenCV455
ここがインストール先のフォルダ
あとでこの中にできる.exeにパスを通すので分かりやすければOK

PYTHON_DEFAULT_EXECUTABLE=C:/Anaconda3/python.exe
この辺りについて
自分の環境ではAnaconda3のディレクトリをCドライブ直下にしてあるが
環境に合わせて適宜変える必要がある

CPU_BASELINE
CUDA_GENERATION
CUDA_ARCH_PTX
この辺もPCのCPU,GPUに合わせて変える必要がある
よくわからないなら設定しなくてもいい(自動で検出してくれる)
ただしCUDAの設定の2つはやらないとビルド時間が多少伸びるっぽいので
[ここ](https://developer.nvidia.com/cuda-gpus "https://developer.nvidia.com/cuda-gpus") や [ここ](https://wikiwiki.jp/nvidiavga/GPU%E4%BB%95%E6%A7%98%E4%B8%80%E8%A6%A7%E8%A1%A8 "https://wikiwiki.jp/nvidiavga/GPU%E4%BB%95%E6%A7%98%E4%B8%80%E8%A6%A7%E8%A1%A8") を確認して環境に合わせて設定


Pythonのバージョンが3.8の場合は
PYTHON3_LIBRARY=C:/Anaconda3/libs/python38.lib となるが
たとえば3.9の場合はここがpython39.libとなるはず
Anaconda3/libs/ 内を確認すればOK

今回はデフォルトでGstreamerを使わない設定になっていたが
OpenCV 4.5.5ではvideoioの依存関係で
gstreamerのオーディオ関連の.dllを紐づけることができないバグがある
-D WITH_GSTREAMER=OFF にすれば問題ないが
どうしてもFFmpegのライブラリよりもGstreamerが使いたい場合は
OpenCVのバージョンを最初から4.6.0で試してみるといいと思う

**!!重要!!**
OPENCV_PYTHON3_VERSION=3.8 もしくは
OPENCV_PYTHON3_VERSION:STRING=3.8
実はここが一番厄介だった
色々な記事で OPENCV_PYTHON3_VERSION=ON と紹介されており
cmakeのオプションを-Lで確認してもBoolになっている
しかしここはPythonのバージョンをBoolではなくStringで入れる必要がある
これが間違っていると
PYTHON3_EXECUTABLE=C:/Anaconda3/python.exe と指定しているのに
CMakeがpython.exeを見つけてくれない

BUILD_opencv_world=ON
これをONにしておくと最後に作られる.dllファイルが1つにまとまる
(20 MBくらいの巨大な opencv_world455.dll ができる)
整理されている感じがするのでONにするのが好みですがOFFでもいいです

他にも細かく設定したい場合は
~~~
cmake-gui -S source
~~~
とすればGuiが起動してすべての変数が一覧に表示されている
設定を変えた場合はConfigureとGenerateを押す

#### インストール
設定がすべて終わってconfigurationが完了したら
~~~
cmake --build build --config Release --target INSTALL
~~~
これをターミナルからおこなってもいいし
Guiを使ったならOpen ProjectからVS Studioを起動して
INSTALLを右クリック→ビルド をやってもいい

# インストールのチェック
インストールが完了したら 設定したインストール先のディレクトリの中
{CMAKE_INSTALL_PREFIX}\x64\vc17\binに .exeや.dllなど色々入っている
上の設定の通りで進めたなら 環境変数Pathに
C:\OpenCV455\x64\vc17\bin を追加する
~~~
opencv_version
> 4.5.5
~~~
無事にパスが通っていればこのように表示されるはず

#### Pythonでcv2のインポート
~~~
python -c "import cv2;print(cv2.__version__)"
> 4.5.5


python -c "import cv2;print(cv2.getBuildInformation())"
> General configuration for OpenCV 4.5.5 =====================================
  Version control:               4.5.5

  Extra modules:
    Location (extra):            C:/opencv/opencv_contrib/modules
    Version control (extra):     4.5.5

~~中略~~

 NVIDIA CUDA:                   YES (ver 11.7, CUFFT CUBLAS FAST_MATH)
    NVIDIA GPU arch:             75
    NVIDIA PTX archs:

  cuDNN:                         YES (ver 8.4.1)

  OpenCL:                        YES (NVD3D11)
    Include path:                C:/opencv/source/3rdparty/include/opencl/1.2
    Link libraries:              Dynamic load

  Python 3:
    Interpreter:                 C:/Anaconda3/python.exe (ver 3.8.13)
    Libraries:                   C:/Anaconda3/libs/python39.lib (ver 3.8.13)
    numpy:                       C:/Anaconda3/Lib/site-packages/numpy/core/include (ver 1.21.5)
    install path:                C:/Anaconda3/Lib/site-packages/cv2/python-3.8

  Python (for build):            C:/Anaconda3/python.exe

  Java:
    ant:                         NO
    JNI:                         NO
    Java wrappers:               NO
    Java tests:                  NO

  Install to:                    C:/OpenCV455
-----------------------------------------------------------------
~~~
ここまでできたらオッケー！
お疲れ様でした！！

---
22/06/08追記
conda環境のupdateをおこなって再度ビルド
Python 3.9.12 + Anaconda Navigator 2.1.4でも問題なくインストールできた

Ninjaを使ってみたかったのでインストールしてやってみた
[「ここ」](https://github.com/ninja-build/ninja/releases "https://github.com/ninja-build/ninja/releases")から 最新版のninja-win.zip (今回はv1.11.0) をダウンロードして
任意の場所に解凍 → ninja.exeにパスを通して
上記のようにVS Studioのプロンプトから-G "Ninja" でビルドしたところ
VS Studioで2~3時間かかっていたビルドが わずか30分程度で完了する 速い！

OpenCVのバージョンも4.6.0をインストールした
~~~
git clone https://github.com/opencv/opencv.git source -b 4.6.0
git clone https://github.com/opencv/opencv_contrib.git -b 4.6.0
~~~
cmake のオプションも一部変更
~~~
cmake -B build -S source ^
-G "Ninja" ^
~~以下変更部分のみ~~
-D CMAKE_INSTALL_PREFIX=C:/OpenCV460 ^
-D PYTHON3_LIBRARY=C:/Anaconda3/libs/python39.lib ^
-D OPENCV_PYTHON3_VERSION=3.9 ^
-D WITH_GSTREAMER=ON ^

cmake --build build --target install
~~~
Gstreamerも追加してみた
[「ここ」](https://gstreamer.freedesktop.org/download/ "https://gstreamer.freedesktop.org/download/")からダウンロードしてインストール
runtimeとdevelopmentどちらも必要
環境変数Pathに
C:\gstreamer\1.0\msvc_x86_64\bin と
C:\gstreamer\1.0\msvc_x86_64\lib を追加

WITH_GSTREAMERをONにしたところ
上記のとおりOpenCV4.5.5ではビルドに失敗する
そもそも GSTREAMER_audio_LIBRARY の変数が最初からない
-D GSTREAMER_audio_LIBRARY=C:/gstreamer/1.0/msvc_x86_64/lib/gstaudio-1.0.lib
と無理やり認識させても変化なし

OpenCV4.6.0では変数に最初からgstaudio-1.0.libが読み込まれておりビルドもすんなり終わる

~~~
General configuration for OpenCV 4.6.0 =====================================
  Version control:               4.6.0

  Extra modules:
    Location (extra):            C:/opencv/opencv_contrib/modules
    Version control (extra):     4.6.0

  Platform:
    Timestamp:                   2022-06-08T11:04:45Z
    Host:                        Windows 10.0.22000 AMD64
    CMake:                       3.22.22040401-MSVC_2
    CMake generator:             Ninja
    CMake build tool:            C:/PROGRA~1/ninja/ninja.exe
    MSVC:                        1932
    Configuration:               Release

~~中略~~

 Video I/O:
    DC1394:                      NO
    FFMPEG:                      YES (prebuilt binaries)
      avcodec:                   YES (58.134.100)
      avformat:                  YES (58.76.100)
      avutil:                    YES (56.70.100)
      swscale:                   YES (5.9.100)
      avresample:                YES (4.0.0)
    GStreamer:                   YES (1.20.2)
    DirectShow:                  YES
    Media Foundation:            YES
      DXVA:                      YES

~~中略~~

NVIDIA CUDA:                   YES (ver 11.7, CUFFT CUBLAS FAST_MATH)
    NVIDIA GPU arch:             75
    NVIDIA PTX archs:

  cuDNN:                         YES (ver 8.4.1)

  OpenCL:                        YES (NVD3D11)
    Include path:                C:/opencv/source/3rdparty/include/opencl/1.2
    Link libraries:              Dynamic load

  Python 3:
    Interpreter:                 C:/Anaconda3/python.exe (ver 3.9.12)
    Libraries:                   C:/Anaconda3/libs/python39.lib (ver 3.9.12)
    numpy:                       C:/Anaconda3/Lib/site-packages/numpy/core/include (ver 1.21.5)
    install path:                C:/Anaconda3/Lib/site-packages/cv2/python-3.9

  Python (for build):            C:/Anaconda3/python.exe

  Java:
    ant:                         NO
    JNI:                         NO
    Java wrappers:               NO
    Java tests:                  NO

  Install to:                    C:/OpenCV460
-----------------------------------------------------------------
~~~
---
22/06/10追記

{CMAKE_INSTALL_PREFIX}\x64\vc17\binにPathが通ってて
~~~
opencv_version
> 4.5.5 (or 4.6.0)
~~~
の実行ができるのに
~~~
python -c "import cv2"
> ImportError: DLL load failed while importing cv2
~~~
となる場合もある

おそらく自前ビルドしたOpenCVと
他の何かのパッケージのバージョンが適合していないために
DLLが読み込めていないんだと思う
~~~
conda update --all
~~~
をすると解決したので追記しておきます

以上
また何かあれば追記します！