USBカメラを使って,動画を撮影する必要に迫られて,作成したソースコードになります.
なぜ,プログラムでやらなければいけないのか?というと,いつも使っているLinuxにインストールした,cheeseではカメラ認識しないんですよ.
そんなこんなで,プログラム作成しました.
# プログラム動作環境
PCはDebian 11(test版)
ノートPCで内蔵カメラ有り.
あらかじめ,opencvはインストールしておきましょう.
aptitude search python3-opencv
p python3-opencv
p python3-opencv-apps
パッケージ名はpython3-opencv
aptitudeが入ってない方はapt-getで入れましょう.
参考までに,私のPCのバージョンを以下に示しておきます.
Python3のバージョン: 3.9.2
opencvのバージョン: 4.5.2
ソースコードの説明
なんだかゴチャゴチャしていてスミマセン.
1つのプログラムでやりたいことすべてできるようにしたので,この有様です.
簡単にソースコードに説明をしますと,まず,camera_checkモードで接続されているカメラを調べます.
sys.exit()にしているので,調べて終了です.
最後にカメラのインデックス番号を表示するので,表示された番号をCAMERA_INDEXという定数に代入してください.
※内蔵カメラがあるPCでは,内蔵カメラはだいたい0番になります.その後に接続された順番に2,4,6...と振られていきます.
なぜ飛び飛びかというのは,1つのカメラにつき,/dev/以下のvideo0,video1,video2,...が2つ生成されるからです.
すなわち,内蔵カメラはvideo0,video1
次に接続したカメラはvideo2,video3...というように増えていくからです.
各変数名の説明
変数名 | 具体的な内容 |
---|---|
auto_setting | カメラのFPSと解像度を自動で設定します. |
mirror | 正像,虚像を入れ替えます. |
save_fig | キャプチャしたframeを静止画として保存します. |
save_video | 動画として保存します. |
imshow | 画像を見ます. |
calibration | 画像の中央を拡大して表示します. |
rotation | 画像を回転させます. |
check | 接続されているカメラのインデックスを表示します. |
calibrationする場合の抜き出す幅はtriming_rangeで決めています.
例のソースでは,真ん中から上下左右に50ピクセル分だけ抜き出しています.
rotationの数値はプラスだと半時計周りに回転,マイナスだと時計回りに回転します.
わかりにくいと思うので,東西南北を例として解説すると,
0°で北方向が画像の上部だったものが,90°とすると,西方向が画像の上部となります.
反対に-90°とすると,東方向が画像の上部となります.
おまけ
トリミングする最初のx,yピクセルの値を以下のように計算しています.
そこで,一度だけ沼ったので,メモ程度に.
triming_start_x = (width//2) - (triming_range//2)
triming_start_y = (hight//2) - (triming_range//2)
もしくは
triming_start_x = int((width/2) - (triming_range/2))
triming_start_y = int((hight/2) - (triming_range/2))
元々は,以下のように記載していました.
triming_start_x = (width/2) - (triming_range/2)
triming_start_y = (hight/2) - (triming_range/2)
何がいけないのかというと,/2で演算を行うと,演算結果は,floatになってしまいます.
それを//2にすることで,整数部分だけを演算結果として代入してくれるそうです.
つまり,演算結果がint型になるということです.
じゃあ,int()でかこえばいいんでしょ?
(多分同じ......)
プログラム例
#!/usr/bin/python3
import cv2
import numpy as np
import platform
import time
import datetime as dt
import sys
import os
def check_camera_connection():
"""
接続されているカメラをチェック
"""
print('接続されているカメラの番号を調べています...')
true_camera_is = [] # 空の配列を用意
cam_number = []
# カメラ番号を0~9まで変えて、COM_PORTに認識されているカメラを探す
for camera_number in range(0, 10):
try:
cap = cv2.VideoCapture(camera_number)
ret, frame = cap.read()
except:
ret = False
if ret == True:
true_camera_is.append(camera_number)
print("カメラ番号->", camera_number, "接続済")
cam_number.append(camera_number)
else:
print("カメラ番号->", camera_number, "未接続")
print("接続されているカメラは", len(true_camera_is), "台です。")
print("カメラのインデックスは", true_camera_is,"です。")
sys.exit("カメラ番号を調べ終わりました。")
return 0
camera_auto_setting = "n" # FPSと解像度を自動的に設定
camera_mirror = "n" # 反転して映る際はyesに変更
show_version = "y" # pythonとopencvのバージョンを確認する場合はyes
save_fig = "n" # 静止画保存
imshow = "y" # キャプチャー画像を見る場合はyes
calibration = "n" # センターキャリブレーション
rotation = "y" # キャプチャ画像を回転
camera_check = "n" # 接続されているカメラの番号を調べる
# 各定数定義
FPS = 40
size_X = 640
size_Y = 480
disp_X = 640
disp_Y = 480
CAMERA_INDEX=0
# 撮影する画像を回転させる角度
# ラジアンではなく,角度(°)ディグリー
ANGLE = 0
# 拡大比率
SCALE = 1.0
size = ( size_X , size_Y )
disp_size = (disp_X , disp_Y )
if camera_check == "y":
check_camera_connection()
save_video=input('# 録画しますか(y/n default=y)')
if save_video=='':
save_video = "y"
if save_video=='y':
filename = 'out.mp4'
while os.path.exists(filename):
print("# %sはすでに存在しています." % filename)
filename = input('## 新しい出力ファイル名:')
filename = filename + '.mp4'
print('%s に動画を書き出します.' % filename)
# 動画保存用設定
cap_now = dt.datetime.now()
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') # 動画保存時のfourcc設定(mp4用)
video = cv2.VideoWriter(filename, fourcc, fps, (width, hight))
# 動画の仕様(ファイル名、fourcc, FPS, サイズ)
camera = cv2.VideoCapture(CAMERA_INDEX)#camera インスタンス生成
# 0:内蔵カメラ , -1:自動的にカメラが選択される
# 0以外の番号はcamera_check.pyで確認する.
# 動画ファイル保存用の設定
if camera_auto_setting == 'y':
fps = int(camera.get(cv2.CAP_PROP_FPS)) # カメラのFPSを取得
width = int(camera.get(cv2.CAP_PROP_FRAME_WIDTH)) # カメラの横幅を取得
hight = int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT))# カメラの縦幅を取得
else:
fps = int(FPS)
width = int(size_X)
hight = int(size_Y)
# pythonとopencvのバージョンを確認
if show_version == "y":
py_ver = str(platform.python_version_tuple())
py_ver = py_ver.replace("'",'')
py_ver = py_ver.replace(",",'.')
py_ver = py_ver.replace("(",'')
py_ver = py_ver.replace(")",'')
py_ver = py_ver.replace(" ",'')
print("Python3のバージョン: ",end="")
print(py_ver)
print("opencvのバージョン: ",end="")
print(cv2.__version__)
# トリミングする際の幅,高さを計算
triming_range = 100
triming_start_x = (width//2) - (triming_range//2)
triming_start_y = (hight//2) - (triming_range//2)
print(" fps= %d " % fps , end="" )
print(" width= %d " % width , end="" )
print(" hight= %d" % hight )
size = ( width , hight )
now = time.time()
start = now
count = 0
while True:
ret, frame = camera.read()
if camera_mirror == "y":
frame = frame[:,::-1]
if save_fig == "y":
cap_time = dt.datetime.now()
cap_time = str(cap_time.strftime('%y%m%d_%H%M%S'))
cap_time = cap_time.replace("'",'')
picname = cap_time+".png"
cv2.imwrite(picname, frame)
if save_video == "y":
video.write(frame)
if rotation == "y":
#回転させる処理
center2 = tuple(np.array([frame.shape[1] * 0.5, frame.shape[0] * 0.5]))
rotation_matrix = cv2.getRotationMatrix2D(center2, ANGLE, SCALE)
frame = cv2.warpAffine(frame, rotation_matrix, size, flags=cv2.INTER_CUBIC)
if calibration == "y":
#キャプチャ画像のセンターを表示する処理
frame = frame[triming_start_x:triming_start_x + triming_range , triming_start_y:triming_start_y + triming_range]
frame = cv2.resize(frame, disp_size)
if imshow == "y":
cv2.imshow("camera", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
count = count + 1
now = time.time()
rate=count/(now-start)
speed=1.0/rate*1000
print("rate=%5.2f (Hz)" % rate)
print("speed=%5.2f (msec)" % speed)
camera.release()
cv2.destroyAllWindows()
実行結果
カメラチェックを行うと,以下のような結果になるかと思います.
接続されているカメラの番号を調べています...
カメラ番号-> 0 接続済
[ WARN:0] global /tmp/pip-req-build-qxrf2chl/opencv/modules/videoio/src/cap_v4l.cpp (890) open VIDEOIO(V4L2:/dev/video1): can't open camera by index
カメラ番号-> 1 未接続
カメラ番号-> 2 接続済
[ WARN:0] global /tmp/pip-req-build-qxrf2chl/opencv/modules/videoio/src/cap_v4l.cpp (890) open VIDEOIO(V4L2:/dev/video3): can't open camera by index
カメラ番号-> 3 未接続
[ WARN:0] global /tmp/pip-req-build-qxrf2chl/opencv/modules/videoio/src/cap_v4l.cpp (890) open VIDEOIO(V4L2:/dev/video4): can't open camera by index
カメラ番号-> 4 未接続
[ WARN:0] global /tmp/pip-req-build-qxrf2chl/opencv/modules/videoio/src/cap_v4l.cpp (890) open VIDEOIO(V4L2:/dev/video5): can't open camera by index
カメラ番号-> 5 未接続
[ WARN:0] global /tmp/pip-req-build-qxrf2chl/opencv/modules/videoio/src/cap_v4l.cpp (890) open VIDEOIO(V4L2:/dev/video6): can't open camera by index
カメラ番号-> 6 未接続
[ WARN:0] global /tmp/pip-req-build-qxrf2chl/opencv/modules/videoio/src/cap_v4l.cpp (890) open VIDEOIO(V4L2:/dev/video7): can't open camera by index
カメラ番号-> 7 未接続
[ WARN:0] global /tmp/pip-req-build-qxrf2chl/opencv/modules/videoio/src/cap_v4l.cpp (890) open VIDEOIO(V4L2:/dev/video8): can't open camera by index
カメラ番号-> 8 未接続
[ WARN:0] global /tmp/pip-req-build-qxrf2chl/opencv/modules/videoio/src/cap_v4l.cpp (890) open VIDEOIO(V4L2:/dev/video9): can't open camera by index
カメラ番号-> 9 未接続
接続されているカメラは 2 台です。
カメラのインデックスは [0, 2] です。
カメラ番号を調べ終わりました。