概要
”ONVIF"対応の市販ネットカメラはPythonで簡単に制御出来ます。 市販のネットカメラには専用のアプリが有りますが、自分でアプリを作るのも楽しいものです。
"ONVIF"と対応カメラメーカ
- ONVIF(Open Network Video Interface Forum)
- ネットワークカメラ等のIPセキュリティ機器において異なるメーカー製品同士でも互換性を保ち連携できるようにするための標準規格。
- 専用のライブラリを使用してカメラへの接続を確立し、カメラが持つ機能(映像配信やPTZ制御など)へのアクセス窓口として利用される。
- 対応している主なメーカー
- TP-Link(ティーピーリンク)、Reolink(リオリン)、Panasonic など
- TP-Link社の ”TAPOカメラ” がお薦め。
- 安価なIoTカメラ(中国製等の一部モデル)の場合、初期状態ではセキュリティや専用アプリ縛りのためONVIFが無効化されていることが多い。
準備
カメラ側
今回はTAPOカメラ "C200" と "C520SW" を使って見ました。まずは専用のアプリ(スマホ用)でカメラをセットアップします。
- 使用したネットカメラ
- "C200"
- 室内用カメラ。パン、チルト、ズーム機能を持つ。
- その他:夜間撮影(多分赤外線撮影)
- "C520SW"
- 屋外用カメラ。パン、チルト、ズーム機能を持つ。
- その他:夜間撮影(多分赤外線撮影)、ライト点灯機能
- "C200"
- スマホにTP-Link Tapoをインストール
- メーカ専用アプリをスマホにインストール。
- アカウントの登録やカメラのWiFiへの接続等行って下さい。
- インストールが完了するとスマホにアプリのアイコンが出来ます。
次に "ONVIF" 用の設定を行います。
- アプリで対象のカメラを選び、”デバイス設定”に入る。
- そこにある "高度な設定”をクリック
- "高度な設定”画面で "カメラのアカウント"、"ネットワーク設定"を行います。
- "ネットワーク設定"
- ONVIFはカメラのIPアドレスを使用する。取り扱いを考慮しIPアドレスを固定。
- 上部の "静的IP" をオンにし、IPアドレス、マスク、ゲートウェイ、DNSを入力。
- 最後に "保存" ボタンを押して終了。
- "カメラのアカウント"
- これもONVIFで必要です。上部の "カメラのアカウント"ボタンをオンにして
- "ユーザー名"、"パスワード"を入力して設定します。
サーバー側
サーバとして Raspberry PI 3B を使用します。
- Raspberry PI Imager(V1.8.5)で "Legacy,64-bit Lite (Bookworm no desktop)" をインストール
- インストール後、ホームディレクトリで下記を実行
sudo apt update sudo apt full-upgrade -y sudo apt install -y python3-flask python3-pip python3-opencv python3-numpy python3-requests ffmpeg pip install onvif-zeep --break-system-packages
カメラ制御用コード
カメラとの接続
"ONVIF" インスタンスと各種サービスを作成。
- "ONVIF" インスタンス作成。
- mycam = ONVIFCamera(target_ip, target_port, target_user, target_pass, wsdl_dir='xxxxx')
- target_ip:TAPOアプリで固定設定したIPアドレス。
- target_port:TAPOの場合は2020。
- target_user:TAPOアプリで設定したユーザー。
- target_pass:TAPOアプリで設定したパスワード。
- wsdl_dir='xxxxx':WSDLファイルのパス。
- 今回のインストールでは "/home/xxxx/.local/lib/python3.4/site-packages/wsdl" となる。
(注:xxxxはユーザ名)
- 今回のインストールでは "/home/xxxx/.local/lib/python3.4/site-packages/wsdl" となる。
- mycam = ONVIFCamera(target_ip, target_port, target_user, target_pass, wsdl_dir='xxxxx')
- メディアサービス (media): 映像の配信設定やストリーミングURIを取得するために使用。
- media = mycam.create_media_service()
- これを元にプロファイルの取得とトークンの特定
- profiles = media.GetProfiles()
- token = profiles[0].token if profiles else 'profile_1'
- PTZサービス (ptz): カメラの向き(パン・チルト・ズーム)を制御するために使用。
- ptz = mycam.create_ptz_service()
- 接続の確認
- 下記のコード "connect.py" を実行して下さい。各接続が確認出来ます。
- モニタで "python3 connect.py" を実行して "ネットカメラ接続完了" が表示されれば接続OKです。
from onvif import ONVIFCamera target_ip = "xxx.xxx.xxx.xxx" # カメラのIPアドレス target_port = 2020 # カメラのポート(TAPOは2020) target_user = "user name" # カメラのユーザー名 target_pass = "password" # カメラのパスワード try: mycam = ONVIFCamera( target_ip, target_port, target_user, target_pass, wsdl_dir='/home/xxxx/.local/lib/python3.4/site-packages/wsdl' # xxxxはユーザ ) ptz = mycam.create_ptz_service() media = mycam.create_media_service() profiles = media.GetProfiles() token = profiles[0].token if profiles else 'profile_1' print(f"ネットカメラ接続完了") except Exception as e: print(f"ネットカメラ接続失敗 ({target_ip}): {e}")
カメラから静止画とStreamingを取得
カメラから静止画とStreamingのURLを取得します。"python3 connect.py" コードに下記を追加。
これを "connect_pic.py" と保存してモニタで実行すると
静止画がエラーになりました。"ONVIF" 規格に静止画もあるのですが、このモデルの様に対応していないモデルが多いようです。
Streamingは対応していますが規格が "RTSP"。そのままではブラウザの画面に表示出来ません。 "OpenCV" を使ってブラウザに有った形式に変換する必要が有ります。
そこで今回は"OpenCV" とStreamingを使って先ず静止画を作成。Streamingは静止画を随時送る方法(MJPEG)で対応する事にしました。 下記はStreaming(RTSP)から静止画(jpg)を1画面取得するサンプルコードです。
import cv2
cap = None
try:
stream_setup = {'Stream': 'RTP-Unicast', 'Transport': {'Protocol': 'TCP'}}
uri_obj = media.GetStreamUri({'StreamSetup': stream_setup, 'ProfileToken': token})
print("動画RTSP URL取得完了")
rtsp_uri = uri_obj.Uri
protocol, rest = rtsp_uri.split('://', 1)
rtsp_uri = f"{protocol}://{username}:{password}@{rest}"
cap = cv2.VideoCapture(rtsp_uri, cv2.CAP_FFMPEG)
# フレーム取得
ret, frame = cap.read()
# フレームをjpgに変換
success, encoded_image = cv2.imencode(".jpg", frame)
print("静止画(jpg)の取得に成功しました!")
except Exception as e:
print(f"Background camera error: {e}")
finally:
if cap is not None:
cap.release()
print("カメラリソースを解放しました")
- 7行:Pythonが ONVIF に動画のURL "RTSP" を要求。
- 13行:取得した "RTSP" を OpenCV 用に形式を変換。
- 15行:変換された"URL"を用いてOpenCVで"RTSP"をライブ映像として読み込む為のオブジェクトを作成。
- 18行:1画面を取得。データ型はNumPyの多次元配列。ブラウザに表示出来ない。
- 21行:形式を "jpg" に変換。これでブラウザに表示出来る。
静止画、Streamingをブラウザに表示するアプリ
ブラウザに静止画、Streamingを表示するアプリを製作します。まずRaspberry PI のホームで下記を実行。
実行後、ホームの下に "net-camera" フォルダーが下記の様に製作されます。
フォルダ "net-camera" に移動(cd net-camera)して "net-camera.py" を修正。修正箇所は
wsdl_dir='/home/xxxx/.local/lib/python3.4/site-packages/wsdl' の "xxxx" をユーザー名に変更
try:
mycam = ONVIFCamera(
target_ip,
target_port,
target_user,
target_pass,
wsdl_dir='/home/xxxx/.local/lib/python3.4/site-packages/wsdl' # xxxxはユーザー名
)
ptz = mycam.create_ptz_service()
media = mycam.create_media_service()
profiles = media.GetProfiles()
token = profiles[0].token if profiles else 'profile_1'
その後 python3 net-camera.py で実行。
使い方
- 最初にカメラと接続
- 必要項目を入力
- IP: カメラのIPアドレス
- Port: カメラのポート(TAPOは2020)
- User: カメラのユーザー名
- Pass: カメラのパスワード
- 入力後、”接続” ボタンを押してカメラに接続。
- しばらくすると接続確認ポップアップが表示され接続完了。
- 必要項目を入力
- "Streaming" ボタン:Streamingの開始と停止を行うトグルボタン。
- "Get" ボタン:静止画(写真)を表示するボタン。
次回は
今回はネットカメラに接続しStreamingと静止画を取得する事が出来ました。次回はPTZ(Pan Tilt Zoom)機能を追加します。