OpenCVのカメラに関する困りごと
- コードを変えていないのに、カメラが別のカメラに切り替わってしまう!
- チームメンバーの環境で試してもらうときに、独自定数
camera_device_index
をいくつか試すように伝えないといけない! -
system_profiler -json SPCameraDataType
を使えばデバイスリストを取得できると聞いたのに、異なるカメラに接続されてしまうケースが頻発!
swiftスクリプトでデバイスリストを取得できます!
私が公開しているこのスクリプトで信頼できるリストがつくれます!
- 使い方は簡単、
-
swift ./avfcam_list.swift
と呼ぶだけでリストのJSONが出力されます。 - あとは
jq
コマンドで整形するもよし、pythonでそのまま受け取るもよし、自由にこの出力を使えばokです。
-
$ swift ./avfcam_list.swift
{
"SPCameraDataType" : [
{
"_name" : "FaceTime HDカメラ(内蔵)",
"manufacturer" : "Apple Inc.",
"spcamera_unique-id" : "0x1420000005acXXXX",
"spcamera_model-id" : "UVC Camera VendorID_1452 ProductID_34304"
},
{
"_name" : "Logi Capture",
"manufacturer" : "XSplit Project",
"spcamera_unique-id" : "{2B297012-XXXX-462D-8EAF-XXXXXXXXXXXX}",
"spcamera_model-id" : "LogiCapture"
},
{
"_name" : "Logitech StreamCam",
"manufacturer" : "Unknown",
"spcamera_unique-id" : "0x1200000046dXXXX",
"spcamera_model-id" : "UVC Camera VendorID_1133 ProductID_2195"
}
]
}
$
前提
- macOS (私はmacOS 11.3)
- OpenCVの
cv::VideoCapture
を利用している。 - Capture API backendsに
CAP_ANY
かCAP_AVFOUNDATION
かCAP_FFMPEG
を使っている。
仕組み
- macの
cv::VideoCapture
はCapture API backendsに様々なものを利用できるようになっています。(リスト) - 特殊な設定をしていなければmacでは
CAP_ANY
にすると、CAP_AVFOUNDATION
かCAP_FFMPEG
が選択されます。 - Capture API backendsがどちらであったとしても、macでは最終的にはAVFoundationが使われてビデオキャプチャしています。ffmpegの場合、ffmpegのAVFoundationプラグインが利用されます。
- したがって、
camera_device_index
はAVFoundationのリストと整合すればよいのです。
AVFoundationのカメラデバイスリストの取得方法
- 残念ながらAVFoundationのカメラデバイスリストを取得できるmac標準のコマンドは存在しないようです。
- また、AVFoundationそのものを
python
やc++
から直接使うには骨が折れます。 - ですが、AVFoundationは
swift
からなら非常に簡単に利用できます。 - またmacではswiftを特殊なビルドなくスクリプトのように利用できます!
- swiftスクリプトでリストをつくりstdoutに出力しさえすれば、あとは
python
やC++
からコマンド呼び出ししてstdoutを捕まえてあげればok
SwiftでのAVFoundationのカメラリスト取得コード
- あまりにも簡単すぎで説明が必要ないですね。メソッドの詳細を知りたい人は検索すればAppleのページで詳しく説明してくれています。
avfcam_list.swift
import AVFoundation
let discovery = AVCaptureDevice.DiscoverySession(
deviceTypes: [
AVCaptureDevice.DeviceType.builtInWideAngleCamera,
AVCaptureDevice.DeviceType.externalUnknown,
],
mediaType: AVMediaType.video,
position: AVCaptureDevice.Position.unspecified
)
let devices = discovery.devices
所感
- かなり振り回されました。この半年ひどくハマりました。チームメンバーにも迷惑を掛けたと思います。
- 結局、OpenCVのコードを追いかけて、ffmpegのコードを追いかけてやっとここまでたどり着きました。どちらもプラグインという概念で拡張しているためコードを追うのは一苦労です。cmakeやconfigureの引数でリンクするコードが変わってしまいます。
- やっと安心してVideoCaptureを利用できそうです。