ソースコード
from pygrabber.dshow_graph import FilterGraph
import sys
def list_connected_cameras():
"""
pygrabber.dshow_graph.FilterGraphを使用して、
接続されているカメラデバイスの一覧を表示します。
"""
print("接続されているカメラを検索しています...")
try:
# FilterGraphオブジェクトを初期化
graph = FilterGraph()
# 入力デバイス(カメラ)のリストを取得
# (これはデバイス名の文字列リストを返します)
device_list = graph.get_input_devices()
if not device_list:
print(" 利用可能なカメラが見つかりませんでした。")
return
print("--- 接続されているカメラ一覧 ---")
# device_listは文字列のリストなので、enumerateでインデックスを付けます
for i, device_name in enumerate(device_list):
print(f" インデックス {i}: {device_name}")
print("---------------------------------")
print("※このインデックスがOpenCV等で使用できるIDに対応します。")
except Exception as e:
print(f"エラーが発生しました: {e}", file=sys.stderr)
print("pygrabberはWindows環境(DirectShow)でのみ動作します。", file=sys.stderr)
if __name__ == "__main__":
list_connected_cameras()
ビルドコマンド
nuitka --standalone --onefile --follow-imports --output-dir=build --include-package=pygrabber --include-package=comtypes --nofollow-import-to=comtypes.gen get_cam_devices.py
解説
まず、普通にpygrabberを含むスクリプトをビルドしても、モジュールが見つからないため、 --include-package=pygrabber のオプションが必要になる。
また、pygrabberはcomtypesというパッケージに依存しているので --include-package=comtypes も必要になる。
オプションを付けて、ビルドしたところ、次は以下のようなエラーとなった
C:\Users\1-10\Desktop>get_cam_devices.exe
Traceback (most recent call last):
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\get_cam_devices.py", line 2, in <module>
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\pygrabber\dshow_graph.py", line 43, in <module pygrabber.dshow_graph>
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\pygrabber\dshow_core.py", line 41, in <module pygrabber.dshow_core>
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\comtypes\client\_generate.py", line 126, in GetModule
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\comtypes\client\_generate.py", line 238, in generate
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\comtypes\client\_generate.py", line 126, in GetModule
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\comtypes\client\_generate.py", line 239, in generate
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\comtypes\client\_generate.py", line 211, in _create_module
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\comtypes\client\_generate.py", line 25, in _my_impor
File "importlib.py", line 88, in import_module
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\comtypes\gen\_00020430_0000_0000_C000_000000000046_0_2_0.py", line 671, in <module>
File "C:\Users\1-10\AppData\Local\Temp\ONEFIL~1\comtypes\_tlib_version_checker.py", line 18, in _check_version
ImportError: Typelib different than module
Geminiによると
-
comtypes のキャッシュ機構: pygrabber が内部で利用している comtypes は、WindowsのCOMライブラリ(DirectShowなど)と連携します。 comtypes は、初めてCOMライブラリにアクセスする際、その定義情報(タイプライブラリ)を読み取り、対応するPythonコードを動的に生成します。 そして、高速化のために、生成したコードを comtypes.gen というフォルダ(パッケージ)内にキャッシュファイル(.pyファイル)として保存します。
-
Nuitkaビルド時の問題: Nuitkaで --standalone ビルドを行う際、開発環境に**すでに存在していた古いキャッシュファイル(comtypes.gen フォルダの中身)**が、そのままexeファイル内にパッケージング(同梱)されてしまいます。
-
他のPCでの実行時エラー: そのexeファイルを他のPCで実行すると、comtypes はexeに同梱されたキャッシュファイル(開発環境のCOMバージョンに基づくもの)を読み込もうとします。 しかし、実行PCの実際のCOMライブラリのバージョンが、キャッシュファイル作成時のバージョンと異なっています。 comtypes はこの矛盾を検知し、「タイプライブラリとモジュール(キャッシュ)が違う」という意味の ImportError: Typelib different than module エラーを発生させます。
ということらしい。
--nofollow-import-to=comtypes.genというオプションを追加すれば解決する。
-
--nofollow-import-to=comtypes.gen ご提示いただいたヘルプの「Control the following into imported modules:」セクションにある通り、このオプションは Nuitka に対して「comtypes.gen という名前のパッケージが import されていても、それを追いかけず、ビルドに含めない」よう指示します。
-
エラーの回避 comtypes が引き起こす ImportError: Typelib different than module エラーは、開発PCで生成されたキャッシュ(comtypes.gen の中身)が、実行PCのCOMライブラリとバージョン不一致を起こすことが原因です。
このコマンドでキャッシュ(comtypes.gen)を意図的に除外することにより、exe を実行したPC上で comtypes が実行時にそのPC環境に合った正しいCOM情報を(キャッシュを使わずに)生成するようになり、エラーが解決されます。