🎥

【Tapo C200】1台のカメラで複数の箇所を定点観測してみた

2024/02/22に公開

Tapo C200を利用して、複数の箇所を定点観測したかったため、Pythonで実装してみました。

利用機材

https://www.tp-link.com/jp/smart-home/tapo/tapo-c200/

事前準備

以下のページを参考にし、RTSPライブストリーミングを利用可能な状態にしておきます。
https://www.tapo.com/jp/faq/34/

実装コード

onvifを利用して、カメラの設定情報の取得や、パンチルト操作を行います。
https://canon.jp/business/trend/what-is-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秒間隔でカメラが動いていることが確認できました。

まとめ

カメラを利用した物体の認識処理も楽しいですが、
カメラ自体を操作できるとやれることの幅が広がりますね!

畑での作物の定点観測を行ってみたいので、少しずつ機能を拡張していってみます!🌾

コラボスタイル Developers

Discussion