自分のキャリアをあれこれ考えながら、Pythonで様々なデータを分析していくブログです

PythonでAXISのIPカメラの録画からMKVの短い動画を切り出してJPEG画像に変換する方法

Python
Python

IPカメラの録画動画から映像を1秒ずつ切り出し、JPGファイルに変換する処理が必要だったので書きました。
今回はAXISのIPカメラの使用例になりますが、他のIPカメラも同じような感じで出来ると思います。

※ 動画取得コマンドはメーカーごとに異なるらしいので、動画取得部分はメーカーの仕様書をお読みください。
参考: https://www.networkcamera.work/entry/command

環境構築
python3.8 -m venv venv_opencv
source venv_opencv/bin/activate
pip install pip -U
pip install opencv-contrib-python==4.5.1.48
pip install pandas
pip install requests imageio
pip install ipykernel
python3 -m ipykernel install --user --name venv_opencv --display-name "venv_opencv"

import cv2するときに下記エラーが出る場合があります。(Mac OS 10.xを使っている場合)

ImportError: dlopen(/Users/hinomaruc/Desktop/blog/venv_opencv/lib/python3.8/site-packages/cv2/cv2.abi3.so, 2): Symbol not found: _VTRegisterSupplementalVideoDecoderIfAvailable
Referenced from: /Users/hinomaruc/Desktop/blog/venv_opencv/lib/python3.8/site-packages/cv2/.dylibs/libavcodec.59.37.100.dylib (which was built for Mac OS X 11.0)

どうやらMacOS11.0以上でないと最新opencvは使えないようです。
→ 23/3/22追記: そんなことありませんでした。時間はかかりますが、ソースからビルドすることによって最新版をインストール出来ました。

エラーが出る場合は、opencvをダウングレードしてみてください。

それではやってみます。本当は実際にIPカメラに繋いで見たいのですがすぐに用意が出来ないのでアウトプット結果は省略します。

スポンサーリンク

必要なライブラリをインポート

各ライブラリのインポート
import cv2
import urllib
import datetime
import time
import os
import glob
スポンサーリンク

IPカメラの録画データから取得したい日付リストの作成

とりあえず1/1 9:00:00 ~ 1/3 17:00:00まで30分ごとのデータを取得することにします。

import datetime

starttime = datetime.datetime(2023, 1, 1, 9, 0, 0)
stoptime = datetime.datetime(2023, 1, 3, 17, 0, 0)

starttime_list = []
stoptime_list = []

while starttime < stoptime:
    starttime_list.append(starttime.isoformat())
   #1秒間の動画にしているが、任意の値でOK
    stoptime_list.append((starttime + datetime.timedelta(0, 1)).isoformat())
    starttime += datetime.timedelta(minutes=30)

print(starttime_list[:3])
print(stoptime_list[:3])
Out[0]
['2023-01-01T09:00:00', '2023-01-01T09:30:00', '2023-01-01T10:00:00']
['2023-01-01T09:00:01', '2023-01-01T09:30:01', '2023-01-01T10:00:01']
スポンサーリンク

取得URLリストの作成

IPカメラのcgiに投げるURLを組み立てます。AXISだとEdge storage APIを確認すると色々情報が載っています。

URLリストのベースを作成(初回だけ実行)
url="http://192.168.1.1/axis-cgi/record/export/exportrecording.cgi"
urlparsed = urllib.parse.urlparse(url)

q = {
    'schemaversion':'1',
    'recordingid':'AXISRECORDID',
    'diskid':"SD_CARD",
    'exportformat':'matroska',
    'starttime':'2023-01-01T00:00:00Z',
    'stoptime':'2023-01-01T00:00:01Z'
}

geturl = urlparsed._replace(query=urllib.parse.urlencode(q)).geturl()
print(urlparsed,geturl)
Out[0]
ParseResult(scheme='http', netloc='192.168.1.1', path='/axis-cgi/record/export/exportrecording.cgi', params='', query='', fragment='') http://192.168.1.1/axis-cgi/record/export/exportrecording.cgi?schemaversion=1&recordingid=AXISRECORDID&diskid=SD_CARD&exportformat=matroska&starttime=2023-01-01T00%3A00%3A00Z&stoptime=2023-01-01T00%3A00%3A01Z

基本になるURLを組み立てることができました。あとはstarttimeとstoptimeの値を変更したURLをたくさん作成します。

URLリストの作成
url_list=[]
for starttime,stoptime in zip(starttime_list,stoptime_list):
    q["starttime"] = starttime
    q["stoptime"] = stoptime
    urlparsed = urllib.parse.urlparse(geturl)
    geturl = urlparsed._replace(query=urllib.parse.urlencode(q)).geturl()
    url_list.append(geturl)
url_list
Out[0]
['http://192.168.1.1/axis-cgi/record/export/exportrecording.cgi?schemaversion=1&recordingid=AXISRECORDID&diskid=SD_CARD&exportformat=matroska&starttime=2023-01-01T09%3A00%3A00&stoptime=2023-01-01T09%3A00%3A01',
 'http://192.168.1.1/axis-cgi/record/export/exportrecording.cgi?schemaversion=1&recordingid=AXISRECORDID&diskid=SD_CARD&exportformat=matroska&starttime=2023-01-01T09%3A30%3A00&stoptime=2023-01-01T09%3A30%3A01',
 'http://192.168.1.1/axis-cgi/record/export/exportrecording.cgi?schemaversion=1&recordingid=AXISRECORDID&diskid=SD_CARD&exportformat=matroska&starttime=2023-01-01T10%3A00%3A00&stoptime=2023-01-01T10%3A00%3A01',
 ・・・省略・・・
スポンサーリンク

mkvファイルの取得

mkvファイルをダウンロードします。

認証方法はベーシック認証を例にしていますが、ダイジェスト認証の場合はコードを変更する必要があります。

import requests
import cgi
import os
from requests.auth import HTTPBasicAuth

OUTPUT_DIR="/Users/hinomaruc/mkv"
USER="user"
PASS="pass"

auth=HTTPBasicAuth(USER,PASS)

for url starttime in zip(url_list,starttime_list):
    # yyyyMMdd_hhmmss.mkvというファイルを作成する
    filename=starttime.replace("-","").replace("T","_").replace(":","")+".mkv"

    # すでにファイルをダウンロード済みの場合はスキップ
    is_file=os.path.isfile(os.path.join(OUTPUT_DIR,fileName))
    if is_file:
        continue

    # mkvファイルの取得 stream=Trueにした方がいい?要検討
    r = requests.get(url,auth=auth)

    with open(os.path.join(OUTPUT_DIR,fileName),'wb') as saveFile:
        saveFile.write(r.content)

    # IPカメラの負荷を考え1秒毎に取得
    time.sleep(1)
スポンサーリンク

mkvをjpegファイルに変換する (1秒目の画像を取得)

好きな秒数のフレームの画像を取得出来ます。

import cv2
import glob
import os

VIDEO_DIR = "/Users/hinomaruc/mkv"
OUTPUT_DIR = "/Users/hinomaruc/jpg"
IMAGE_SIZE = (240, 240)

for video_path in glob.glob(os.path.join(VIDEO_DIR, "*.mkv")):
    # ファイル名を取得。yyyyMMdd_hhmmss.mkv
    filename = os.path.basename(video_path)
    #ファイル名から拡張子を除外
    filename_noext = os.path.splitext(filename)[0]
    cap = cv2.VideoCapture(video_path)

    #動画のフレーム数
    num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    #1秒目のフレームの取得
    target_frame = int(cap.get(cv2.CAP_PROP_FPS) * 1)
    cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)
    _, frame = cap.read()

    #リサイズ
    img = cv2.resize(frame, IMAGE_SIZE)

    # 保存
    output_path = os.path.join(OUTPUT_DIR, filename_noext + ".jpg")
    cv2.imwrite(output_path, img)

    cap.release()

cap.relase()の位置はループの内側でないとメモリリークの可能性があるかも知れません。(外側だと最後のcapしかリリースされないかも?)

スポンサーリンク

まとめ

録画データをダウンロードするのに時間がかかるので、それだったら細切れにして必要な分だけ持ってこようと思ってコードを書いてみました。

スポンサーリンク

更新履歴

・23年3月22日: opencvのインストールに関して、最新版はMacOS11以上でないとインストール出来ないようなことを書いていましたが、ソースからビルドすることによってopencv_python-4.7.0.72をインストール出来ることを確認 (MacOS 10.15.7で確認)

Building wheels for collected packages: opencv-python
Building wheel for opencv-python (pyproject.toml) ... done
Created wheel for opencv-python: filename=opencv_python-4.7.0.72-cp37-cp37m-macosx_10_15_x86_64.whl size=26733907 sha256=3ffecca8b4f0a57e370810e6aa9845c869d30d412f5a9e090c82a60f1f5f9683
Stored in directory: /Users/hinomaruc/Library/Caches/pip/wheels/c6/95/44/d6c355d93cca592181103e5b320fdc16acf960d70d5427c90e
Successfully built opencv-python

タイトルとURLをコピーしました