PTZ(Pan-Tilt-Zoom)控制云台的基本流程如下:

  1. 创建 ONVIF 设备服务对象:使用 ONVIF 协议连接到摄像头设备,并创建与设备交互的服务对象。
  2. 获取 PTZ 配置信息:通过 ONVIF 设备服务对象的 GetConfigurationOptions 方法获取摄像头支持的 PTZ 配置选项,包括 Pan、Tilt 和 Zoom 选项的范围和默认值等。
  3. 获取 PTZ 节点信息:通过 ONVIF 设备服务对象的 GetNodes 方法获取摄像头上所有的 PTZ 节点。
  4. 获取 PTZ 节点的状态:通过 ONVIF PTZ 服务对象的 GetStatus 方法获取 PTZ 节点的状态,包括当前云台的位置、缩放级别等信息。
  5. 控制云台移动:通过 ONVIF PTZ 服务对象的 ContinuousMove、RelativeMove 或 AbsoluteMove 等方法,控制云台的移动,达到调整摄像头视角的效果。
  6. 控制云台缩放:通过 ONVIF PTZ 服务对象的 ContinuousZoom、RelativeZoom 或 AbsoluteZoom 等方法,控制云台的缩放,调整摄像头的焦距。

实际进行球机控制会遇到的两个问题:

一、球机的时间要和电脑的时间是同步的,在算法验证里面如果不一致会导致返回用户名和密码错误致使无法使用Onvif协议。

二、由于库函数在获取值时返回的只有Zoom的值而无Pantilt的值,导致控制云台运动出错,故采用两种获取球机PTZ控制器配置的方法解决此问题。

通过Onvif对PTZ控制器控制的Python实际步骤:

需要导入的库和变量的初始化:

例如:

from time import sleep
from onvif import ONVIFCamera
import zeep
XMAX = 1
XMIN = -1
YMAX = 1
YMIN = -1
1.利用ONVIFCamera函数初始化对象
例如;mycam = ONVIFCamera('192.168.0.108', 80, 'admin', '8756933...')

2.利用create_service()创建服务对象

需要创建两个服务对象

media = mycam.create_media_service()#创建media服务对象
ptz = mycam.create_ptz_service()#创建ptz服务对象
3.创建zeep_pythonvalue()函数
例如;def zeep_pythonvalue(self, xmlvalue):
      return xmlvalue
在获取配置参数前需要运用编写的zeep_pythonvalue()函数
zeep.xsd.simple.AnySimpleType.pythonvalue = zeep_pythonvalue #
4.获取PTZ配置参数
 media_profile = media.GetProfiles()[0]

5.创建节点

例如:request = ptz.create_type('GetConfigurationOptions')
request.ConfigurationToken = media_profile.PTZConfiguration.token
ptz_configuration_options = ptz.GetConfigurationOptions(request)
    request = ptz.create_type('ContinuousMove')
    request.ProfileToken = media_profile.token
    ptz.Stop({'ProfileToken': media_profile.token})
6.通过GetConfigurations()再次获取PTZ配置参数 ,原media_profile中缺少pantilt,此时补上
    ptz_configuration_list = ptz.GetConfigurations()
    a = ptz_configuration_list[0].DefaultPTZSpeed
b = a.PanTilt
    #b为从PTZ控制器中提取的有关Pantilt的参数
request.Velocity = ptz.GetStatus({'ProfileToken': media_profile.token}).Position
request.Velocity.PanTilt=b
1. 设计最大最小值
global XMAX, XMIN, YMAX, YMIN
XMAX = 1
XMIN = -1
YMAX = 1
YMIN = -1
  1. 调用设定的函数对云台进行控制

例如:

def move_up(ptz, request, timeout=1):
    print('move up...')
    request.Velocity.PanTilt.x = 0
    request.Velocity.PanTilt.y = YMAX
    request.Velocity.Zoom.x= 0
perform_move(ptz, request, timeout)
def perform_move(ptz, request, timeout):
    # Start continuous move
    ptz.ContinuousMove(request)
    # Wait a certain time
    sleep(timeout)
    # Stop continuous move
ptz.Stop({'ProfileToken': request.ProfileToken})

本例子给了move_up如果是down则变化 request.Velocity.PanTilt.y=YMIN类推

  1. 调用设定的zoom函数对倍数进行控制

例如;

def zoom(ptz,request,zoomdata,timeout=1):
    """
    变焦
    :param zoom: 1为拉近或-1为远离
    :param timeout: 生效时间
    :return:
    """
    request.Velocity.PanTilt.x = 0
    request.Velocity.PanTilt.y = 0
    request.Velocity.Zoom.x=zoomdata
    print(request.Velocity)
perform_move(ptz, request, timeout)

调用时设置datazoom为-1则为远离,1则为放大。

  这篇博文的代码,通过onvif达到控制相机截图、移动到预置点、PTZ控制的功能,已验证,可以顺利跑通,对于新手很好用:

Python3-onvif协议之相机截图、相机获取预置点、移动到预置点 - 简书 (jianshu.com)

最后为博主改动的PTZ控制的原程序,此程序实现了左右上下转:


from time import sleep

from onvif import ONVIFCamera
import zeep

XMAX = 1
XMIN = -1
YMAX = 1
YMIN = -1


def zeep_pythonvalue(self, xmlvalue):
    return xmlvalue


def perform_move(ptz, request, timeout):
    # Start continuous move
    ptz.ContinuousMove(request)
    # Wait a certain time
    sleep(timeout)
    # Stop continuous move
    ptz.Stop({'ProfileToken': request.ProfileToken})


def move_up(ptz, request, timeout=1):
    print('move up...')
    request.Velocity.PanTilt.x = 0
    request.Velocity.PanTilt.y = YMAX
    request.Velocity.Zoom.x= 0
    perform_move(ptz, request, timeout)


def move_down(ptz, request, timeout=1):
    print('move down...')
    request.Velocity.PanTilt.x = 0
    request.Velocity.PanTilt.y = YMIN
    request.Velocity.Zoom.x= 0
    perform_move(ptz, request, timeout)


def move_right(ptz, request, timeout=1):
    print('move right...')
    request.Velocity.PanTilt.x = XMAX
    request.Velocity.PanTilt.y = 0
    request.Velocity.Zoom.x = 0
    perform_move(ptz, request, timeout)


def move_left(ptz, request, timeout=1):
    print('move left...')
    request.Velocity.PanTilt.x = XMIN
    request.Velocity.PanTilt.y = 0
    request.Velocity.Zoom.x=0
    perform_move(ptz, request, timeout)


def continuous_move():
    mycam = ONVIFCamera('192.168.0.xx', 80, 'admin', 'password')
    #初始化
    media = mycam.create_media_service()
    #创建media服务对象
    ptz = mycam.create_ptz_service()
    #创建ptz服务对象
    zeep.xsd.simple.AnySimpleType.pythonvalue = zeep_pythonvalue
    media_profile = media.GetProfiles()[0]
    #获取ptz配置参数
    request = ptz.create_type('GetConfigurationOptions')
    request.ConfigurationToken = media_profile.PTZConfiguration.token
    # ptz_configuration_options = ptz.GetConfigurationOptions(request)
    request = ptz.create_type('ContinuousMove')
    request.ProfileToken = media_profile.token
    ptz.Stop({'ProfileToken': media_profile.token})

    ptz_configuration_list = ptz.GetConfigurations()
    #获取ptz配置参数,原media_profile中缺少pantilt,此时补上
    a = ptz_configuration_list[0].DefaultPTZSpeed
    b = a.PanTilt
    #b为从PTZ控制器中提取的有关Pantilt的参数
    request.Velocity = ptz.GetStatus({'ProfileToken': media_profile.token}).Position

    request.Velocity.PanTilt=b
    print(request.Velocity)


    global XMAX, XMIN, YMAX, YMIN
    # XMAX = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].XRange.Max
    # XMIN = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].XRange.Min
    # YMAX = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].YRange.Max
    # YMIN = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].YRange.Min
    XMAX = 1
    XMIN = -1
    YMAX = 1
    YMIN = -1

    # move right
    move_right(ptz, request)

    # move left
    move_left(ptz, request)
    #
    # # Move up
    move_up(ptz, request)
    #
    # # move down
    move_down(ptz, request)


if __name__ == '__main__':
    continuous_move()