🎥
【Tapo C200】1台のカメラで複数の箇所を定点観測してみた
Tapo C200を利用して、複数の箇所を定点観測したかったため、Pythonで実装してみました。
利用機材
事前準備
以下のページを参考にし、RTSPライブストリーミングを利用可能な状態にしておきます。
実装コード
onvifを利用して、カメラの設定情報の取得や、パンチルト操作を行います。
camera.py
import time
import rtsp
from PIL import Image
from onvif import ONVIFCamera
# 定数
LOOP_COUNT = 2
WAIT_TIME = 15
FILENAME_FORMAT = "saved_frame_{DATE}.jpg"
# カメラ設定
CAMERA_SETTING = {
"ip_address": "IP_Address",
"port": "554",
"stream": "stream2",
"user_id": "user_id",
"password": "password",
"onvif_port": "2020"
}
# 絶対座標でカメラを動かす
def move_cam_absolute(x, y):
x, y = check_camera_range(x, y)
try:
print("move_cam_absolute: x:{x}, y:{y}".format(x=x, y=y))
absolute_move_request = ptz.create_type('AbsoluteMove')
absolute_move_request.ProfileToken = media_profile.token
absolute_move_request.Position = {
'PanTilt': {
'x': x,
'y': y
}
}
ptz.AbsoluteMove(absolute_move_request)
except Exception as e:
print("Error: move_cam_absolute")
print(e)
# カメラの動作範囲情報を取得する
def get_camera_range(request):
ptz_configuration_options = ptz.GetConfigurationOptions(request)
velocity_space = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0]
return {
"X_MAX": velocity_space.XRange.Max,
"X_MIN": velocity_space.XRange.Min,
"Y_MAX": velocity_space.YRange.Max,
"Y_MIN": velocity_space.YRange.Min
}
# 座標設定について、カメラの動作範囲を超えないようにする
def check_camera_range(x, y):
print("check_camera_range: x:{x}, y:{y}".format(x=x, y=y))
if x > X_MAX:
x = X_MAX
if x < X_MIN:
x = X_MIN
if y > Y_MAX:
y = Y_MAX
if y < Y_MIN:
y = Y_MIN
return x, y
# Main
try:
user, pwd, ip, port, stream, onvif_port = (
CAMERA_SETTING['user_id'],
CAMERA_SETTING['password'],
CAMERA_SETTING['ip_address'],
CAMERA_SETTING['port'],
CAMERA_SETTING['stream'],
CAMERA_SETTING['onvif_port']
)
rtsp_url = f"rtsp://{user}:{pwd}@{ip}:{port}/{stream}"
client = rtsp.Client(rtsp_server_uri=rtsp_url, verbose=True)
camera = ONVIFCamera(ip, onvif_port, user, pwd)
media = camera.create_media_service()
ptz = camera.create_ptz_service()
media_profile = media.GetProfiles()[0]
request = ptz.create_type('GetConfigurationOptions')
request.ConfigurationToken = media_profile.PTZConfiguration.token
X_MAX, X_MIN, Y_MAX, Y_MIN = get_camera_range(request=request).values()
# Set Default Position
move_cam_absolute(0, 0)
time.sleep(20)
for i in range(LOOP_COUNT):
move_cam_absolute(0.5, -1.0)
frame = client.read()
time.sleep(WAIT_TIME)
datetime_string = time.strftime("%Y-%m-%d_%H-%M-%S")
frame.save(FILENAME_FORMAT.format(DATE=datetime_string))
move_cam_absolute(-0.5, -1.0)
frame = client.read()
time.sleep(WAIT_TIME)
datetime_string = time.strftime("%Y-%m-%d_%H-%M-%S")
frame.save(FILENAME_FORMAT.format(DATE=datetime_string))
except Exception as e:
print("Error: main")
print(e)
コード説明
get_camera_range
get_camera_rangeメソッドでは、稼働可能範囲のX、Y座標の最大・最低値を取得してきています。
ptz.GetConfigurationOptions
にて、接続したカメラの設定情報を取得しており、後続の処理にて可動域の最大・最低値を取得しています。
move_cam_absolute
カメラを絶対座標指定で動かします。
絶対座標指定(AbsoluteMove)以外にも、以下の指定が可能となっています。
- RelativeMove:相対座標指定
- ContinuousMove:旋回時間指定
定点観測をしたかったため、絶対座標指定にて実装しました。
メイン処理
カメラへの接続が成功したら、move_cam_absolute(0, 0)
を実行してカメラを定位置に戻しています。
その後は、座標(0.5, -1.0)
と、(-0.5, -1.0)
の座標を一定の間隔で動かしています。
動作結果
python ./camera.py
コマンドで実行するだけです。
まずカメラに映り込んだのは・・・
プリンちゃん!!🍮
次は、うさぎ。
撮影時間を見ると、15秒間隔に撮影できていることが確認できますね📷
これ以降も15秒間隔でカメラが動いていることが確認できました。
まとめ
カメラを利用した物体の認識処理も楽しいですが、
カメラ自体を操作できるとやれることの幅が広がりますね!
畑での作物の定点観測を行ってみたいので、少しずつ機能を拡張していってみます!🌾
Discussion