質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

1509閲覧

二台のwebカメラから画像を読み込みたい

kakakatokyoeki

総合スコア85

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/06/17 23:18

編集2022/06/17 23:32

目的
もともとwebカメラを一台で使うプログラムを改造して、二台で使えるようにしようとしています。ひとまず、cv2.videocaptureで二つのカメラを読み込み、うち、一台の映像を出力することから始めました。
問題
ですが、
終了しますのメッセージが出るか、can't open camera by indexという警告が出ます。
また、usbを指して一回目に実行すると、無事、一台の映像が出るが、二回目に実行するとメッセージが出るか、警告が出ます。

試したこと
webカメラの番号を調べました。(以下、コマンドと写真)
イメージ説明
素人の考えとして
1.なぜ、0番と1番ではないのか。(二番というのは、色々試していて引数を2にしたら読み込めることに気づきました)
2.そもそもvideo22などという大きな数字がなぜ出てくるのか
という二点が、このプログラムのエラーにかかわっているのではないかと考えています。

どこを変更すれば、安定して、2台のカメラ映像が読み込め、うち、一台を表示できるのかを教えていただきたいです。

実際のプログラム

python

1!/usr/bin/env python3 2 -*- coding: utf-8 -*- 3""" 4Created on Sun May 22 11:18:37 2022 5 6@author: pi 7""" 8 9import os 10import sys 11import cv2 12 13if __name__ == "__main__": 14 DEVICE_NUMBER1 =0 15 DEVICE_NUMBER2 =2 16 DST_DIRNAME = "./images" 17 18 capture1 = cv2.VideoCapture(DEVICE_NUMBER1) 19 capture2 = cv2.VideoCapture(DEVICE_NUMBER2) 20 if not capture1.isOpened() or capture2.isOpened(): 21 print("終了します", file=sys.stderr) 22 sys.exit(1) 23 24 fps1 = int(capture1.get(cv2.CAP_PROP_FPS)) 25 while True: 26 _, frame = capture1.read() 27 if frame is None: 28 continue 29 30 cv2.imshow('frame', frame) 31 key = cv2.waitKey(fps1) 32 if key == ord('s'): 33 break 34

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

素朴な質問への回答

1. なぜ、0番と1番ではないのか。(二番というのは、色々試していて引数を2にしたら読み込めることに気づきました)

なぜ、の答えになっていませんが、カメラを何度も抜いたり刺したりすると、質問にあるように「ゼロ番から詰めた番号ではない」ことがよくあります。いい言葉ではありませんが、「OpenCVのcv2.VideoCapture()はそんなもの」という認識です。
恐らくOpenCVはOSの認識した言い分を鵜呑みにして「だってOSのいうUSBカメラのリストの●番目なんだから、カメラがなくたって知ったこっちゃないよ」という実装がされているのだと思います。

しかも、カメラによっては1台しかつないでいないのに番号が4つくらい振られることもあります。これには訳があって、1台のカメラでRGBカメラだけではなくLiDARも搭載していると番号が4つあるけれども「使えるのは常に0と3だけ(1,2は指定できるけれどもデータを受け取れない)。0、3はカラーと深度を受け取る」みたいなこともあります。

  1. そもそもvideo22などという大きな数字がなぜ出てくるのか

恐らく内部でカメラを抜き差し(認識・解除)をしたときに、前の情報をうまく解放できずにそのまま、が積み重なっているのだと思います。

実際の質問への回答

どこを変更すれば、安定して、2台のカメラ映像が読み込め、うち、一台を表示できるのかを教えていただきたいです。

理由は何であれ、上述のようにOSの認識しているカメラ≒OpenCVが認識できるカメラ≠実際に使えるカメラ、ということがよくあります。

A.1 物理的に同じカメラを認識したい、であれば
OSの提示するカメラを1台ずつシリアル番号を調べます。キチンと認識できればシリアル番号を返すはずです。認識できなければエラーを吐くのでtry:~except:~で適宜避けてください。
これはpyudevリンクでも行けますし、コマンドラインであればlsusbリンクから行けるはずです。

疑似コード

Python3

1list_path = [OSの認識したカメラのありそうなパス一覧] 2 3list_actual_path = [] 4for path in list_path: 5 try: 6 serial = pyudevのパスからシリアル番号を抜き出す関数(path ) 7 if serial == "期待していたシリアル番号": 8 list_actual_path.append(path ) 9 except: 10 pass 11 12if list_actual_path != []: 13 # list_capsに認識したカメラのcapを突っ込む 14 list_caps = [cv2.VideoCapture(path) for path in list_actual_path ]

※カメラの解像度によりますが、cv2.VideoCapture()を複数のカメラに対してすると、画像を取得しなくても予約するだけでUSBのバスを逼迫し、画像が取得できないことがありますので気を付けてください。

A.2 物理的に同じカメラでなくていい、であれば
とりあえずcapが使えるか走らせてダメなら避ける、で行けます。

Python3

1list_path = [OSの認識したカメラのありそうなパス一覧] 2 3list_actual_path = [] 4for path in list_path: 5 try: 6 cap = cv2.VideoCapture(path) 7 ret,frame = cap.read() 8 if ret is True: 9 list_actual_path .append(path) 10 cap.release() 11 except: 12 cap.release() 13 14if list_actual_path != []: 15 # list_capsに認識したカメラのcapを突っ込む 16 list_caps = [cv2.VideoCapture(path) for path in list_actual_path ]

投稿2022/06/18 00:20

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kakakatokyoeki

2022/06/18 02:00

丁寧なご回答ありがとうございます。 素朴な質問に対する答えはわかりました。 ですが、肝心の実際の質問への回答のプログラムについて詳しく教えていただけないでしょうか。 1.osの認識したカメラのありそうなパス一覧というのは、どのようにして調べ(lxターミナルの場合)  ればよいでしょうか。 2.パスからシリアル番号を吐き出す関数とは具体的には何ですか。 3.期待していたシリアル番号とはどのようなものを入れたらよいのでしょうか 厚かましいですがご教授いただければ幸いです。
退会済みユーザー

退会済みユーザー

2022/06/18 02:59 編集

1.osの認識したカメラのありそうなパス一覧というのは、どのようにして調べ(lxターミナルの場合)  ればよいでしょうか。 質問の画像に乗っている「ls /dev/video*」がそのまま調べる方法です。pythonで使うにはsubprocessを使えばできます。subprocessに上記コマンドを放り込んで、返り値をPythonで捌くイメージです。 参考: https://teratail.com/questions/225257 ※cv2.VideoCapture("/dev/video1")みたいな感じでアクセスできるためこの方法が有効です。 2.パスからシリアル番号を吐き出す関数とは具体的には何ですか。 たとえば、pyudebでUSB機器を認識できるので、そこでID_SERIAL_SHORTを指定すれば機器のシリアル番号を拾えます。もしデバイスがdevであれば、dev.get("ID_SERIAL_SHORT")とするだけです。 参考:https://uepon.hatenadiary.com/entry/2017/04/16/203934 3. 期待していたシリアル番号とはどのようなものを入れたらよいのでしょうか これは手持ちのUSB機器に製造時に刻み込まれたシリアル番号です。 例えば、手持ちの機器のシリアル番号を上記の2で調べておいて、シリアル番号がABCDだったとしましょう。 同じ型番の機器もう一つ持っていて、それのシリアル番号がEFGHだったとしましょう。 if シリアル番号 == "ABCD": ____print("機器1") elif シリアル番号 == "EFHG": ____print("機器2") else: ____print("未知のシリアル番号") みたいにできます。
kakakatokyoeki

2022/08/01 09:44

無事、つながりました。参考にしたサイトは別ですが、fourteenlengthさんのお返事で色々勉強できました。 ありがとうございました。
guest

0

自己解決

投稿2022/08/01 10:31

kakakatokyoeki

総合スコア85

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

投稿2022/08/01 09:53

kakakatokyoeki

総合スコア85

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問