ITや趣味など気軽に投稿しています。

【Python】OpenCVで動画を読み込み、表示・保存する

これまでは画像を扱っていたが、今回からは動画を扱っていく。

おお、ワンランクアップですね!

とは言っても、動画は画像の連続であるから、基本的なことは変わらない。

変わらないんですか?動きがあるのとないので違う気がしますが。

先ほども言ったが、動画は画像の連続だ。画像をコマ送りで表示すると、動きがあるように見える。それが動画だ。

あ、なるほど。なんかわかった気がします。

この部分の話は長くなる。
さっさとOpenCVで動画を扱う方法を紹介しよう。

動画の読み込み

OpenCVでは動画ファイル(.mp4など)だけではなく、WebカメラやUSBカメラから映像を取得し処理することができる。

カメラってことは、リアルタイム映像も処理できるってことですか?

その通り。世の中では、監視カメラのリアルタイム映像を解析して、犯罪の予知や工場の安全管理など、様々なことに画像解析が使われている。

動画ファイルを読み込む

まずは動画ファイル(mp4)を読み込む。

リアルタイムじゃないやつですね。

動画の読み込みにはcv2.VideoCapture()を使う。動画ファイルの場合、引数に対象ファイルのパスを指定する。

import cv2

path = 'input/Aquarium.mp4'
cap = cv2.VideoCapture(path)

これで、変数capに動画情報が読み込まれる。

中身はどうなるんです?

それは後からだ。

もったいぶるなぁ。

USBカメラから動画を読み込む

続いてUSBカメラの映像を読み込む。
ここでは、USBでPCに接続したカメラも、PCに内蔵されたカメラも対象となる。

これはリアルタイム映像ですね!

この場合、引数を0~の数値で指定する。

import cv2

cap = cv2.VideoCapture(0)

へ、これだけですか!?

これだけだ。複数のカメラが接続されていて、お目当ての映像がヒットしない場合、0, 1, 2, …と数字を置き換えて試すといい。

???

この数字はデバイスIDというもので、PCが認識したデバイスに対し0から順にIDを振ったものだ。だからデフォルトは0になる。

さらに厄介なことに、WindowsではこのデバイスIDを確認する手段がない。

だから、0から順に試すしかないんですね。

左様。一応Linuxの場合は確認方法はあるみたいだがな。

ネットワークカメラから動画を読み込む。

最後はネットワークカメラから動画を読み込む。
ここでのネットワークカメラとは、デバイスと直接接続されておらず、ネットワークを介して繋がっているカメラを指す。

わっ、それっぽくなってきましたね。

ネットワークカメラの映像はRTSPプロトコルで取得するケースが多いと思われるので、その方法で読み込み方を紹介する。

RTSP?

Real Time Streaming Protocolの頭文字を取ってRTSPという。
その名の通り、リアルタイムの映像配信に特化したプロトコルだ。

import cv2

#URLは例です
cap = cv2.VideoCapture("rtsp://user:password@192.168.10.1:47614/ipcam_h264.sdp")

user、password、IPアドレスおよびポート番号は、使用するカメラに合わせて変えるのだ。

user、passwordはカメラにアクセスするためのユーザとパスワードってことですね。

動画を表示する

今度は読み込んだ動画をプログラムの中で表示する。

冒頭でも言ったが、動画は画像の連続だ。画像解析では、動画であっても1コマずつの画像として処理していくことが基本となる。
例えば、フレームレートが30FPSの動画の場合、動画1秒間の処理はフレーム処理を30回繰り返して行われる。

結局、処理の単位は画像なんですね。

早速、サンプルコードを見てみよう。

import cv2

path = r'input/Aquarium.mp4'
cap = cv2.VideoCapture(path)

i=1
while True :
    print("Frame: "+ str(i))
    #フレーム情報取得
    ret, img = cap.read()
    
    #動画が終われば処理終了
    if ret == False:
        break
    

    #動画表示
    cv2.imshow('Video', img)
    i +=1

    
cap.release()
cv2.destroyAllWindows()

動画を読み込んだ後、フレームごとの処理はwhile構文の中で行われている。

while True: って、処理が無限に続くあれですよね。

その通り。先ほど、動画情報は変数capに格納したな。

cap = cv2.VideoCapture(path)でしたね。

while構文の中でcap.read()をとしている部分で、フレームごとの画像情報をcapから取り出している。
そして、動画が終わると変数retにFalseがセットされ、while処理が終わる仕組みだ。

if ret == False: の部分ですね。

while構文の中をもう少し見てみよう。cv2.imshow()で映像を表示している。

あれ、画像の時と同じですね、、!

左様。何度も言うが、動画は画像の連続だ。だから、動画を分解すると画像になる。つまり、画像を処理するときと同じになる。

なんか、思ったよりシンプルな感じがします。

但し、このときcap.release()とcv2.destroyAllWindows()はwhile構文の外側に書くことを忘れないように。

whileの中だと、1フレーム目ですべて消えちゃうからですね。
ところで、cap.release()って何です?

これもおまじないだ。

またおまじない!教えてください!!

やけに熱が入っているな。
cap.release()は、明示的にカメラリソースの開放を宣言している。つまり、もう使いません、と。

これを宣言しないと、例えば他のアプリケーションからカメラにアクセスできなくなる可能性もある。
だから、おまじないとして必ず書くように。

動画を出力する

次は動画をファイルとして出力する。動画の出力にはcv2.VideoWriter()を使う。

import cv2

path = r'./input/Aquarium.mp4'
cap = cv2.VideoCapture(path)


#動画サイズ取得
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#フレームレート取得
fps = cap.get(cv2.CAP_PROP_FPS)

#フォーマット指定
fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
#注)グレースケールの映像を出力する場合は第5引数に0を与える
writer = cv2.VideoWriter('./result/output.mp4', fmt, fps, (width, height),0)

i=1
while True :
    print("Frame: "+ str(i))
    #フレーム情報取得
    ret, img = cap.read()
    
    #動画が終われば処理終了
    if ret == False:
        break
    
    #グレースケールに変換
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    #動画表示
    cv2.imshow('Video', img_gray)
    
    #動画書き込み
    writer.write(img_gray)
    
    i +=1
    

cap.release()
#これを忘れるとプログラムが出力ファイルを開きっぱなしになる
writer.release()
cv2.destroyAllWindows()

VideoWriter_fourcc()

動画の出力は画像の出力より若干手間がかかる。
まず、VideoWriter_fourcc()で動画のフォーマットを指定する必要がある。

fourccって何ですか?

fourccは、データフォーマットを一意に識別するための4文字の識別子を指す。
four-character codeの略語だ

なるほど。例えばどんなのがあります?

fourccの総数はかなりの数があるが、よく使われるデータフォーマットをいくつか紹介しよう。

コーデックFourCC説明
H.264h264高画質・高圧縮率で広く利用されているコーデック。Blu-ray Discや地上デジタル放送などでも採用されている。
H.265/HEVCh265H.264の後継規格。4K/8K映像の配信などで利用されている。
MPEG-4mp4vDVDなどで利用されているコーデック。比較的古い規格だが、互換性が高い。
VP9vp90Googleが開発したオープンソースのコーデック。YouTubeなどで採用されている。
AV1av01次世代オープンソースコーデックとして高画質・高圧縮率が期待される。
MJPEGmjpg静止画を連続して表示する方式で、動画の圧縮率は低いが、高速な処理が可能。監視カメラやWebカメラなどで利用されている。
DivXdivxMPEG-4をベースに開発されたコーデック。DVDripなどで利用されていた。
XvidxvidMPEG-4に準拠したコーデック。オープンソースであることが特徴
WMVwmv1Microsoftが開発したコーデック。Windows Media Playerなどで利用されている。
Theoratheoオープンソースのコーデック。Ogg形式の動画ファイルなどで利用されている。

cv2.VideoWriter_fourcc(‘m’, ‘p’, ‘4’, ‘v’)ではfourccを1文字ずつ引数に渡すことになっているから、間違えないように。

はいさー!

cv2.VideoWriter()

ここから動画書き出し処理の本体だ。

cv2.VideoWriter()には引数として、出力ファイルのパス、フォーマット(fmt)、フレームレート(fps)、フレームサイズ(width, height)を指定する。

最後の引数0は、グレースケール映像を出力する場合に指定する。

#注)グレースケールの映像を出力する場合は第5引数に0を与える
writer = cv2.VideoWriter('./result/output.mp4', fmt, fps, (width, height),0)

フォーマットはVideoWriter_fourcc()で指定したフォーマットですね。

この時点では、まだ出力動画のひな型を作ったに過ぎない。ここから、変数writerに対して動画を1フレームずつ書き込んでいく。

※While構文中
  #動画書き込み
    writer.write(img_gray)

While構文中でフレームごとに処理していくわけですね。

そうだ。最後はwriter.release()として、動画出力が完了する。

今回までで、画像や動画の基本的な入出力は説明した。
次回からは画像の加工や処理を取り上げていく。

ありがとうございました~~♪