Skip to content

Analítica de la cámara mediante la API

La pestaña Analítica funciona con la solicitud de central POST /central/api-v4/streams/{stream}/onvif-call/analytics/{method}. Un sistema externo usa la misma solicitud. Central reenvía la llamada al streamer que captura el vídeo de la cámara, y el streamer la pasa a la cámara.

Antes de empezar

La solicitud está disponible para los roles superadmin y admin. El stream debe estar en marcha y la cámara preparada como se describe en Preparación del stream. Los ejemplos requieren Bash, curl y jq. Las respuestas de los ejemplos proceden de una cámara Optimus; otra cámara tiene su propio conjunto de tipos y parámetros.

export CENTRAL_URL='https://central.example.com'
export API_LOGIN='admin'
export API_PASSWORD='your-password'
export STREAM='entrance'
analytics() {
  curl --fail-with-body --silent --show-error \
    --user "$API_LOGIN:$API_PASSWORD" \
    --header 'Content-Type: application/json' \
    --data "$2" \
    "$CENTRAL_URL/central/api-v4/streams/$STREAM/onvif-call/analytics/$1"
}

Un nombre de stream con barra se pasa codificado: cams%2Fentrance.

Métodos

Los nombres y cuerpos de los métodos siguen el servicio ONVIF Analytics escrito en JSON. Los atributos XML llevan el prefijo $; Optic añade por sí mismo el token de configuración de analítica.

  • GetSupportedRules — los tipos de regla de la cámara, su número y los escenarios incompatibles.
  • GetRuleOptions — los límites de los parámetros de una regla.
  • GetRules — las reglas de la cámara.
  • CreateRules, ModifyRules, DeleteRules — crear, cambiar y eliminar reglas.
  • GetServiceCapabilities — qué admite el servicio de analítica de la cámara.
  • GetSupportedAnalyticsModules, GetAnalyticsModuleOptions, GetAnalyticsModules, ModifyAnalyticsModules — los módulos de analítica, por ejemplo la rejilla y la sensibilidad del detector de movimiento.

Los demás métodos de escritura se rechazan con el código unsupported_method. Cada intento de escribir reglas queda en el registro de auditoría de central con la acción stream_onvif.rules_write.

Capacidades de la cámara

Tipos de regla, su número máximo y escenarios incompatibles:

analytics GetSupportedRules '{}' | jq '.SupportedRules.RuleDescription[]
  | {type: ."$Name", max: ."$maxInstances", excludes: .Extension.Excludes}'
{"type":"tt:LineDetector","max":"4","excludes":["tt:LineCounting","tt:ObjectAbandoned","tt:ObjectRemoved","cus:CrowdDetector","cus:QueueDetector","tt:ObjectDetection","tt:LicensePlateRecognition"]}

Límites de los parámetros de un tipo:

analytics GetRuleOptions '{"RuleType":"tt:LineDetector"}' | jq '.RuleOptions'
[{"$Name":"Direction","$RuleType":"tt:LineDetector","StringList":"Right Left Any"},
 {"$MaxItems":"3","$Name":"ClassFilter","$RuleType":"tt:LineDetector","StringList":"Human Vehicle NonMotorVehicle"},
 {"$Name":"Sensitivity","$RuleType":"tt:LineDetector","IntRange":{"Max":"100","Min":"1"}}]

El streamer guarda las capacidades de la cámara en memoria. Para leerlas de nuevo de la cámara, por ejemplo tras actualizar el firmware, añada el encabezado x-onvif-fresh: true.

Lectura de reglas

analytics GetRules '{}' | jq

En la respuesta, Extension.Executor indica el ejecutor: optimus para el adaptador Optimus, camera para ONVIF estándar. Extension.Clock.UtcOffsetMinutes es el desfase del reloj de la cámara respecto a UTC; el horario se indica en esas horas.

Crear, cambiar y eliminar

Cree una línea. El nombre de la regla <tipo>_<número> se asigna al crearla y se devuelve en RuleName:

analytics CreateRules '{"Rule":[{"$Type":"tt:LineDetector","Parameters":{
  "SimpleItem":[{"$Name":"Armed","$Value":"false"},{"$Name":"Direction","$Value":"Any"}],
  "ElementItem":[{"$Name":"Segments","Polyline":{"Point":[{"$x":-0.5,"$y":0},{"$x":0.5,"$y":0}]}}]}}]}'
{"Extension":{"Executor":"optimus","NotApplied":[]},"RuleName":["LineDetector_2"]}

Arme la línea con un horario de lunes a viernes de 9 a 14:

analytics ModifyRules '{"Rule":[{"$Name":"LineDetector_2","$Type":"tt:LineDetector","Parameters":{
  "SimpleItem":[{"$Name":"Armed","$Value":"true"}],
  "ElementItem":[{"$Name":"Schedule","HourSchedule":{
    "Mon":[[9,14]],"Tue":[[9,14]],"Wed":[[9,14]],"Thu":[[9,14]],"Fri":[[9,14]],"Sat":[],"Sun":[]}}]}}]}'

Si la cámara declaró escenarios incompatibles (Extension.Excludes) y la ventana se solapa con uno de ellos, la escritura se rechaza: la respuesta es 422 schedule_overlap, consulte Errores.

Elimine la línea:

analytics DeleteRules '{"RuleName":["LineDetector_2"]}'

La sensibilidad del detector de movimiento se indica en el módulo de analítica:

analytics ModifyAnalyticsModules '{"AnalyticsModule":[{"$Name":"CellMotionEngine_1","$Type":"tt:CellMotionEngine",
  "Parameters":{"SimpleItem":[{"$Name":"Sensitivity","$Value":"6"}]}}]}'

Reglas de escritura:

  • Coordenadas — de −1 a 1 en ambos ejes, origen en el centro del fotograma, el eje y apunta hacia arriba.
  • Horario — un ElementItem llamado Schedule: los siete días (Mon…Sun), intervalos [inicio, fin) en horas enteras del reloj de la cámara. Un día vacío apaga el escenario ese día. En las cámaras Optimus, el horario es común a todas las reglas del tipo.
  • Reglas permanentes (tipo con $fixed="true") — CreateRules se rechaza; DeleteRules desarma la regla.
  • ModifyRules — cambia solo los parámetros enviados.
  • Extension.NotApplied — parámetros que la cámara aceptó pero no guardó, consulte Extensiones de la respuesta.

Extensiones de la respuesta

Lo que el estándar ONVIF no contempla, Optic lo transmite como extensiones:

  • Extension.Executor — en cada respuesta: optimus para el adaptador Optimus, camera para ONVIF estándar.
  • Extension.Excludes — en la descripción de un tipo en GetSupportedRules: tipos que la cámara no mantiene activos en las mismas horas que este. Las cámaras con ONVIF estándar no los declaran.
  • Extension.Clock.UtcOffsetMinutes — en GetRules: el desfase del reloj de la cámara respecto a UTC; el horario se indica en esas horas.
  • Extension.NotApplied — en las respuestas de escritura: un elemento por parámetro que la cámara aceptó pero no guardó. $Rule es la regla, $Parameter el parámetro, $Sent el valor enviado y $Read el leído tras la escritura. Una lista vacía significa que la cámara lo guardó todo.
  • $Source de un parámetro en la descripción de un tipo: extension — el parámetro no está en el estándar, por ejemplo Sensitivity, MinSize o Schedule; by-analogy — el nombre del parámetro se tomó por analogía con una regla de tipo similar.
  • $Unit de un parámetro:

    • pixel — píxeles del fotograma;
    • second — segundos;
    • frame-width — fracción del ancho del fotograma.
    • $fixed="true" de un tipo — la regla es permanente: no se puede crear ni eliminar, solo armar o desarmar.
    • El prefijo cus: — un tipo o parámetro fuera del estándar ONVIF, por ejemplo cus:RegionEntranceDetector o cus:HourSchedule.

Descripción de un tipo con extensiones:

{"$Name":"cus:RegionEntranceDetector","$maxInstances":"4","Extension":{"Excludes":["tt:LineCounting","tt:ObjectAbandoned","tt:ObjectRemoved","cus:CrowdDetector","cus:QueueDetector","tt:ObjectDetection","tt:LicensePlateRecognition"]},
 "Parameters":{"SimpleItemDescription":[{"$Name":"MinSize","$Type":"xs:int","$Source":"extension","$Unit":"pixel"}],
  "ElementItemDescription":[{"$Name":"Schedule","$Type":"cus:HourSchedule","$Source":"extension"}]}}

Respuesta de escritura en la que la cámara mantuvo el interruptor de la regla a su manera:

{"Extension":{"Executor":"optimus","NotApplied":[{"$Parameter":"Armed","$Read":true,"$Rule":"LineDetector_1","$Sent":false}]}}

Activaciones

Las activaciones de las reglas se guardan como episodios con episode_type=trigger. El código de la regla va en episode_subtype; varios códigos se separan con comas.

curl --fail-with-body --silent --show-error \
  --user "$API_LOGIN:$API_PASSWORD" \
  "$CENTRAL_URL/central/api-v4/episodes?media=$STREAM&episode_type=trigger&episode_subtype=lcd,enter" | jq
{"episode_id":"7701038866144167249","media":"entrance","opened_at":1793037836008,"closed_at":1793037836008,
 "frame_preview":{"sha256":"5c43636115c17e9cdd6810added59741109f637ce529f4d38e06fd2f341e954a","mime_type":"image/jpeg"},
 "detections":[],"details":{"type":"trigger","rule":"lcd"}}

Códigos de regla:

  • lcd — cruce de línea;
  • cc — conteo de cruces;
  • enter — entrada en zona;
  • exit — salida de zona;
  • pid — intrusión;
  • sod — objeto abandonado o retirado;
  • cd — aglomeración;
  • qd — cola;
  • tamper — sabotaje.

El fotograma de la activación lo devuelve GET /central/api-v4/episodes/{episode_id}/images/{sha256}, con sha256 tomado de frame_preview.

Encabezados de la solicitud

  • x-onvif-fresh: true — leer de nuevo las capacidades de la cámara, sin la memoria del streamer.
  • x-onvif-auth: user:password — credenciales de la cámara en lugar de las de la URL RTSP.
  • x-onvif-port — el puerto HTTP de la cámara si no es el predeterminado.

Errores

  • 400 unsupported_method — un método de escritura fuera de la lista de analítica; 400 auth_error — el encabezado x-onvif-auth no tiene la forma user:password.
  • 401 — credenciales de Optic incorrectas.
  • 404 not_found — el stream no está en marcha en ningún streamer.
  • 409 no_camera_target — el stream no tiene una fuente RTSP con la dirección de la cámara.
  • 422 param_error — un valor fuera de los límites de la cámara; 422 schedule_overlap — escenarios incompatibles en las mismas horas. errors[].path indica el campo.
  • 502 auth_error — la cámara rechazó el usuario y la contraseña; 502 onvif_error — la cámara respondió con un error o no está accesible.
  • 503 — la cámara está ocupada o pide esperar; repita la solicitud más tarde.
  • 504 — la cámara no respondió a tiempo. La escritura puede haberse aplicado: lea las reglas con GetRules antes de reintentar; si no, repetir CreateRules crea una segunda regla.

Ejemplos de respuesta 422:

{"error":{"code":"param_error","message":"tt:LineDetector: MinSize is 8 px, the camera takes 64..1080 px",
  "errors":[{"path":["Rule",0,"Parameters","SimpleItem",4,"$Value"],"message":"tt:LineDetector: MinSize is 8 px, the camera takes 64..1080 px"}]}}
{"error":{"code":"schedule_overlap","message":"tt:LineDetector and tt:LicensePlateRecognition are both active on day 0 from 14:00 to 18:00 by the camera clock; the camera keeps only one of them at a time",
  "errors":[{"path":["Rule",0,"Parameters","ElementItem",0,"HourSchedule"],"message":"…"}]}}

Central no repite una llamada en otro streamer tras perder la conexión: la escritura en la cámara puede haberse hecho ya, y repetirla la cambiaría dos veces.