はじめに
pip install opencv-pythonでインストールできるopencvにはGStreamerがついておらず、これを使ってrtspストリームをVideoCaptureするとラグがひどくてとてもリアルタイムとは呼べません。そこでGStreamerを使うために自前でビルドする必要が出てきますが、ビルドを完了すると20~30GBくらいディスクを食われます。こんなのよくないし、他のマシンにコピーだってできません。
この記事では、ビルドしたopencv(cv2フォルダ)をコピーするだけで他のマシンでも使用でき、ビルドに使ったファイルを削除しても問題ないように仕上げます。最終的に600MBくらいになりました。もっと詳しい人ならもっと小さくできるかもしれません。
また、僕の身の回りではpythonバージョンが乱立してるので、マルチバージョン対応(といってもそれぞれのバージョン用のビルドするというやっつけ仕様だが)にします。(ラップトップがPython3.9、仕事用PCには3.10、自宅用PCには3.11がインストールされちゃってます)
ビルドに必要なものの入手
以下を用意します。入手したzipは展開してください。個人的なおすすめは、CドライブにDevelopなどという名前のフォルダを作り、この中に用意したファイルを入れておきます。
- CMake:https://cmake.org/download/ より、make-x.xx.x-windows-x86_64.msiをDL。普通にインストールします。
- OpenCV:https://opencv.org/releases/ より、最新版のSourcesをDL
- OpenCV_contrib:https://github.com/opencv/opencv_contrib/tags よりOpenCVと同じバージョンをDL
- GStreamer:https://gstreamer.freedesktop.org/download/ よりWindowsタブ->x.xx.x runtime installerとx.xx.x development installerをDL。次でインストールします。
- (Visual Studio 2019:ビルドに必要です。)
gstreamerのインストール
runtimeもdevelopも、Completeでインストールします。

無駄なトラブルを避けるために(追記)
この記事を書いてから1年後、バージョンアップのために再度ビルドしようとしてめっちゃトラブったのでそのときの対処録です。
- ffmpegにパスを通している場合、一連のビルドが終わるまでいったんPathから削除する
- pythonのバージョンを変える、OpenCVのバージョンを変える、numpyのバージョンを変えるなどするときは、前のビルドディレクトリをそのまま使うのは強く非推奨です。
BUILD_opencv_python3という項目が消滅するなどしてpython用にビルドできなくなりました。
CMakeの設定
- OpenCVのパスを設定
- ビルド先のパスを設定(どこでもいい)
- Configureを押下
- 出てきたウィンドウではそのままFinishをクリック
- 以下のようにパラメーターを設定(適宜Searchを使うとよいでしょう):
OPENCV_EXTRA_MODULES_PATH=opencv-contribのmodulesフォルダ
BUILD_opencv_world=ON(なんとなく)
BUILD_SHARED_LIBS=OFF(とても大事(依存関係を一緒に含める))
GSTREAMER_~~をすべて設定(スクショ参照)
OPENCV_GAPI_GSTREAMER=ON(大事)
WITH_GSTREAMER=ON(大事)
PYTHON3_PACKAGES_PATH=C:/Develop/SiTePaCk(できるだけ変な名前/分かりやすい名前にする)

今回は、ソースもビルド先もD:/Develop/に置いてみました。SSD(Cドライブ)の空き容量に不安があったので大容量HDD(Dドライブ)にしただけで、深い意味はないのでみんなはCドライブでいいと思います。gstreamerがDドライブにインストールされているのはたまたまで、通常はCドライブにインストールされるはずです(つまりD:/gstreamer/~をC:/gstreamer/~に読み替えてください)。
PYTHON3_PACKAGES_PATH=C:/Develop/SiTePaCkと変な名前にする理由は、デフォルトだと現在アクティブなpythonのsite-packagesにインストールされてしまうからです。うっかりpip版のopencvが入っていると競合しそうなので、変な名前に設定することでそれを明示的に回避します。 - Configureを押下、その後Generateを押下(configureはしょっちゅう押してもいいらしい)
- 下の画面でビルドオプションを確認する。ダメそうなら設定を見直す。
Video I/OのGStreamerがYESになっていること
Python 3 のinstall path が変な名前のフォルダ/cv2/python3.x のようになっていること - Open Projectを押してVisual Studioを開く
- Releaseにする
- ビルド>ビルド>ALL_BUILDとINSTALL をビルドする(1時間はかかる)
使えるようにする
ビルドが正常終了すると、ビルド先のフォルダにたくさんのデータが(数十GB)、C:/Develop/SiTePaCk(変な名前を付けたフォルダ)にcv2フォルダができているはずです(80MBくらい)。ビルド先のフォルダの中身はほとんど使いませんが、せっかくなのでbinフォルダの中のopencv_videoio_ffmpeg4xx_64.dllをcv2フォルダにコピーしておきます。以下の記述はcv2フォルダについてのものです。
僕の環境では(仕事用PCのPython3.10でビルドしたため)、この中にconfig-3.10.pyとpython-3.10フォルダの中にcv2.cp310-win_amd64.pydが居ました。ここからはpython3.10として書いていますが、皆さんのバージョンに合わせて適宜3.xと読み替えてください。
このパソコンのみで使用する場合はこのままで良いのですが、マルチバージョンにしたい場合は、新たに
python-3フォルダ(名前はなんでもよい)を作り、その中にcv2.pc3x-(略).pydを移動させ、紛らわしいのでpython-3.xフォルダは削除します。
ここで、コントロールパネル>プログラムのアンインストールから、GStreamer 1.0(Development Files)をアンインストールします(デカくて邪魔なので)。GStreamer 1.0はまだ残しておきます(これは必要です)。
マルチバージョンにしたい場合は、まだDevelopmentを使用するので先にビルドをしたほうがいいです

cv2/python3.10フォルダに、C:/gstreamer/1.0/msvc_x86_64/binとC:/gstreamer/1.0/msvc_x86_64/libをフォルダごとコピーします。
フォルダ構造は次のようになります(一部抜粋):
└ SiTePaCk/
└ cv2/
├ python-3.10/
| ├ bin/
| ├ lib/
| └ cv2.cp310-win_amd64.pyd
├ config-3.10.py
└ ...
(ここまでできたら、ビルドしたマシンでは動作を確認できます。)
続いて、cv2ディレクトリのconfig-3.10.pyの内容を以下のように編集します。
お詫びと修正(この記事をかつて見たことがある人向け)
初版の記事ではここの`config-310.py`に全角日本語にてコメントを入れていましたが、そのせいでimport時にcp932のエラーが出て失敗します。修正としてコメントと日本語文字列はすべて削除しました。 修正前のコードはコチラ:import os
file_path=__file__ #このファイルのパスを取得
dir_path=os.path.dirname(file_path) #このファイルのあるフォルダまでのディレクトリ
PYTHON_EXTENSIONS_PATHS = [
os.path.join(dir_path, 'python-3.10') #相対パスに直す
] + PYTHON_EXTENSIONS_PATHS
BINARIES_PATHS = [ #gstreamerをコピーした理由はポータブルにするため
os.path.join(dir_path, 'python-3.10', 'bin')
] + BINARIES_PATHS
以下は修正(コメント消し)後
import os
file_path=__file__
dir_path=os.path.dirname(file_path)
PYTHON_EXTENSIONS_PATHS = [
os.path.join(dir_path, 'python-3.10')
] + PYTHON_EXTENSIONS_PATHS
BINARIES_PATHS = [
os.path.join(dir_path, 'python-3.10', 'bin')
] + BINARIES_PATHS
マルチバージョンにしたいときは、config-3.pyなどを新たに作り、これをコピペして'python-3'に直します。
また、__init__.pyに
'config-{}.{}.py'.format(sys.version_info[0], sys.version_info[1]),という行があるのですが、これは現在実行中のpythonバージョンに合わせて参照ファイルを変えていますので、これを
'config-3.py',にしちゃいます。
ここで気を付けなければならないのが、後から別バージョン用にビルドすると、__init__.pyが書き換えられてもとに戻ってしまうので、ビルド後には確認するようにしてください。
config-3.pyができれば、もうconfig-3.10.pyはいらないので消しちゃいましょう。
使ってみる
自前でビルドしたはいいものの、依存関係がないと動かないと思うので、いったん普通にpip install opencv-pythonをしたほうがいいと思います。
site-packagesのcv2フォルダは、僕はとりあえずcv2-originalとリネームして保持しておきました。
site-packagesに自前でビルドしたcv2フォルダをコピーすれば完成です。普通にコマンドプロンプトからpythonを起動し、
import cv2
print(cv2.getBuildInformation())
などで動作を確認してみます。実際に
cap=cv2.VideoCapture("rtspsrc location=rtsp://ip-address:port latency=0 ! decodebin ! videoconvert ! appsink", cv2.CAP_GSTREAMER)
ができることを確認しましょう。もし動かない場合はProcess Monitorが便利です。
マルチバージョンにする
僕の環境では自宅用PCでもラップトップでも動作させたいので、追加でpython3.9用とpython3.11用にもビルドします。このとき、gstreamerのdevelopmentをアンインストールしちゃった人はもう一回インストールしましょう。
ビルドするマシンにターゲットとなるバージョンのpythonをインストールしましょう。(ここで多分3.9.y、3.11.yなどの孫バージョンは問わないと思います。)
https://www.python.org/downloads/windows/ から目的のバージョンのWindows installer (64-bit)をダウンロードします(embedじゃダメです。見つからない場合はCtrl+Fを使いつつ、下にスクロールしてみましょう。)
ビルド用に一時的にインストールするだけなので、Customize installationを選びます。

いらないのでチェックは全部外しちゃいます。

次の画面でもチェックを全部外し、インストール場所を好きな場所(C:/Develop/ など)にします。(たまたま今回はDドライブにしましたが、みんなはCドライブで良いと思います。)

次にcmakeの設定を別のバージョンのpython用に書き換えます。
いったんcmakeを終了させておきます。
ビルドフォルダ(C:/Develop/BUILD_410GST など)にあるCMakeCache.txtを開き、pythonのバージョンが書いてあるところを修正していきます。
例えばC:/Users/ユーザー名/AppData/Local/Programs/Python/Python310/python.exeをC:/Develop/Python311/python.exeに変えたり、
Python310/includeをPython311/includeに、
Python310/libs/python310.libをPython311/libs/python311.libに、
3.10.5と書かれているところを3.11.9にしたりします。
エディタの検索機能でython310や3.10などで検索し、必要に応じてython311や3.11、3.11.9などにします(大文字小文字区別のないp'ython'で検索すると良いでしょう)。一つ注意なのは、numpyのincludeディレクトリのパスにPython310が入っていてもここは変更しないでください。numpyのバージョンはそろえておきます。
全部できたらCMake GUIを起動し、Configureを押下します。下の画面(⑦)のPythonの項目で目的のPythonバージョンになっているか確認したらGenerateしてOpen Project、ALL_BUILDとINSTALLをビルドします。2回目なので1回目ほど時間はかからないはずです。
この作業を目的のpythonバージョン分繰り返し、目的のcv2.cp3x-win_amd64.pydができたらpython-3フォルダにコピーしちゃいます。__init__.pyが毎回もとに戻されてしまうので、
'config-{}.{}.py'.format(sys.version_info[0], sys.version_info[1]),
を
'config-3.py',
にしちゃいます。