Go语言实现Onvif客户端:8、摄像头PTZ控制(云台控制)
1、PTZ简单再介绍
之前学习Onvif协议的时候我们已经对PTZ有了基本的了解,这里当我们实现PTZ控制的时候再简单做一下介绍说明,主要针对我们这里实现的PTZ的说明。
PTZ:Pan/Tilt/Zoom,对于枪机的话基本就是固定一个位置或者水平移动,但是球机除了水平移动外,还可以旋转(没有跳跃),此外摄像头还有变焦的功能,目前我们暂时只实现简单的水平移动和旋转,变焦的接口等有需要也可以类似封装。而移动一般包含绝对移动、相对移动和连续移动三种方式,我们暂时使用连续移动,通过移动后调用停止也可以模拟其它两种移动的效果。
连续移动速度原点坐标(x=0,y=0)上(x=0,y=正的相对位置)下(x=0,y=负的相对位置)左(x=负的相对位置,y=0)右(x=正的相对位置,y=0)左上(x=负的相对位置,y=正的相对位置)左下(x=负的相对位置,y=负的相对位置)右上(x=正的相对位置,y=正的相对位置)右下(x=正的相对位置,y=负的相对位置)
2、代码
/**
* @Description: 摄像头云台控制,包括模式设置和移动方向控制
* @time: 2021-03-30 11:14:14
* @receiver client:onvif客户端
* @param direction:云台移动方向,通过PTZDirection接口传入封装后的方向值进行方向传递
* @param moveMode:云台移动模式,通过MoveMode接口传入封装后的模式值进行模式控制
* @return returnInfo:结果Code码和Info信息,Code码为0则成功,否则失败,通过获取Info查看失败原因
*/
func (client *GoOnvifClient) PTZControl(direction PTZDirection, moveMode moveMode) returnInfo {
if client.localSelectProfileToken == "" {
return returnInfo{PTZErr, "profile token is nil."}
}
if moveMode == CONTINUOUS || moveMode == DISCONTINUOUS {
client.ptzMoveMode = moveMode
} else {
client.ptzMoveMode = DISCONTINUOUS
}
switch direction {
case UP, DOWN, LEFT, RIGHT, UP_LEFT, DOWN_LEFT, UP_RIGHT, DOWN_RIGHT, STOP:
client.direction = direction
res := client.ptzControl()
if res.Code != 0 {
return res
}
if moveMode == DISCONTINUOUS {
time.Sleep(1 * time.Second)
res = client.ptzStop()
if res.Code != 0 {
return res
}
}
default:
return returnInfo{PTZErr, "direction err."}
}
return returnInfo{OK, "ptz control success!"}
}
/**
* @Description: 根据输入的Profile token和PTZ速度、方向进行PTZ控制
* @time: 2021-03-25 14:31:55
* @receiver client
* @return returnInfo
*/
func (client *GoOnvifClient) ptzControl() returnInfo {
ptzContinuousMoveReq := ptz.ContinuousMove{
ProfileToken: onvif.ReferenceToken(client.localSelectProfileToken),
Velocity: onvif.PTZSpeed{
PanTilt: onvif.Vector2D{
X: 0,
Y: 0,
},
},
}
switch client.direction {
case UP:
ptzContinuousMoveReq.Velocity.PanTilt.Y = client.ptzSpeed
case DOWN:
ptzContinuousMoveReq.Velocity.PanTilt.Y = -client.ptzSpeed
case LEFT:
ptzContinuousMoveReq.Velocity.PanTilt.X = -client.ptzSpeed
case RIGHT:
ptzContinuousMoveReq.Velocity.PanTilt.X = client.ptzSpeed
case UP_LEFT:
ptzContinuousMoveReq.Velocity.PanTilt.X = -client.ptzSpeed
ptzContinuousMoveReq.Velocity.PanTilt.Y = client.ptzSpeed
case DOWN_LEFT:
ptzContinuousMoveReq.Velocity.PanTilt.X = -client.ptzSpeed
ptzContinuousMoveReq.Velocity.PanTilt.Y = -client.ptzSpeed
case UP_RIGHT:
ptzContinuousMoveReq.Velocity.PanTilt.X = client.ptzSpeed
ptzContinuousMoveReq.Velocity.PanTilt.Y = client.ptzSpeed
case DOWN_RIGHT:
ptzContinuousMoveReq.Velocity.PanTilt.X = client.ptzSpeed
ptzContinuousMoveReq.Velocity.PanTilt.Y = -client.ptzSpeed
case STOP:
return client.ptzStop()
default:
return returnInfo{PTZErr, "Unknown ptz direction."}
}
return client.sendReqGetResp(PTZErr, ptzContinuousMoveReq)
}
/**
* @Description: 根据输入的Profile token设置PTZ停止
* @time: 2021-03-25 14:29:43
* @receiver client
* @return returnInfo
*/
func (client *GoOnvifClient) ptzStop() returnInfo {
stopReq := ptz.Stop{
ProfileToken: onvif.ReferenceToken(client.localSelectProfileToken),
}
return client.sendReqGetResp(PTZErr, stopReq)
}
调用,我们可以选择在循环中调用,也可以做一个web服务,从web界面上获取控制参数:
//设置速度后循环进行ptz控制,初始化时设置了默认速度0.2
PTZ:for {
//断续模式移动一次1s后会调用停止进行停止,连续模式则会绕着指定的方向一直移动
fmt.Println("选择控制模式,1:连续移动,0:断续移动,2:退出PTZ")
moveMode := uint(0)
fmt.Scanln(&moveMode)
switch moveMode {
case 2:
break PTZ
default:
}
direction := uint(0)
fmt.Println("输入PTZ:1:上;2:下;3:左;4:右;5:左上;6:左下;7:右上;8:右下;9:停")
fmt.Scanln(&direction)
switch direction {
case 1, 2, 3, 4, 5, 6, 7, 8, 9:
res = client.PTZControl(client.PTZDirection(direction), client.MoveMode(moveMode))
if res.Code != 0 {
fmt.Println(res.Info)
return
}
default:
continue
}
}