docs and better zooming

This commit is contained in:
Josh Hawkins 2023-10-04 16:12:51 -05:00
parent 9c822a0b5a
commit 9f027231e0
3 changed files with 103 additions and 36 deletions

View File

@ -23,6 +23,8 @@ Many cheaper or older PTZs may not support this standard. Frigate will report an
Alternatively, you can download and run [this simple Python script](https://gist.github.com/hawkeye217/152a1d4ba80760dac95d46e143d37112), replacing the details on line 4 with your camera's IP address, ONVIF port, username, and password to check your camera.
A growing list of cameras and brands that have been reported by users to work with Frigate's autotracking can be found [here](cameras.md).
## Configuration
First, set up a PTZ preset in your camera's firmware and give it a name. If you're unsure how to do this, consult the documentation for your camera manufacturer's firmware. Some tutorials for common brands: [Amcrest](https://www.youtube.com/watch?v=lJlE9-krmrM), [Reolink](https://www.youtube.com/watch?v=VAnxHUY5i5w), [Dahua](https://www.youtube.com/watch?v=7sNbc5U-k54).
@ -89,15 +91,21 @@ PTZ motors operate at different speeds. Performing a calibration will direct Fri
Calibration is optional, but will greatly assist Frigate in autotracking objects that move across the camera's field of view more quickly.
To begin calibration, set the `calibrate_on_startup` for your camera to `True` and restart Frigate. Frigate will then make a series of 30 small and large movements with your camera. Don't move the PTZ manually while calibration is in progress. Once complete, camera motion will stop and your config file will be automatically updated with a `movement_weights` parameter to be used in movement calculations. You should not modify this parameter manually.
To begin calibration, set the `calibrate_on_startup` for your camera to `True` and restart Frigate. Frigate will then make a series of small and large movements with your camera. Don't move the PTZ manually while calibration is in progress. Once complete, camera motion will stop and your config file will be automatically updated with a `movement_weights` parameter to be used in movement calculations. You should not modify this parameter manually.
After calibration has ended, your PTZ will be moved to the preset specified by `return_preset`.
:::note
Frigate's web UI and all other cameras will be unresponsive while calibration is in progress. This is expected and normal to avoid excessive network traffic or CPU usage during calibration. Calibration for most PTZs will take about two minutes. The Frigate log will show calibration progress and any errors.
:::
At this point, Frigate will be running and will continue to refine and update the `movement_weights` parameter in your config automatically as the PTZ moves during autotracking and more measurements are obtained.
Before restarting Frigate, you should set `calibrate_on_startup` in your config file to `False`, otherwise your refined `movement_weights` will be overwritten and calibration will occur when starting again.
You can recalibrate at any time by removing the `movement_weights` parameter, setting `calibrate_on_startup` to `True`, and then restarting Frigate. You may need to recalibrate or remove `movement_weights` from your config altogether if autotracking is erratic. If you change your `return_preset` in any way, a recalibration is also recommended.
You can recalibrate at any time by removing the `movement_weights` parameter, setting `calibrate_on_startup` to `True`, and then restarting Frigate. You may need to recalibrate or remove `movement_weights` from your config altogether if autotracking is erratic. If you change your `return_preset` in any way or if you change your camera's detect `fps` value, a recalibration is also recommended.
## Best practices and considerations
@ -111,13 +119,15 @@ A fast [detector](object_detectors.md) is recommended. CPU detectors will not pe
A full-frame zone in `required_zones` is not recommended, especially if you've calibrated your camera and there are `movement_weights` defined in the configuration file. Frigate will continue to autotrack an object that has entered one of the `required_zones`, even if it moves outside of that zone.
Some users have found it helpful to adjust the zone `inertia` value or the camera's `max_disappeared` parameter as well. See the [configuration reference](index.md).
## Zooming
Zooming is still a very experimental feature and may use significantly more CPU when tracking objects than panning/tilting only. It may be helpful to tweak your camera's autofocus settings if you are noticing focus problems when using zooming.
Zooming is still a very experimental feature and may use significantly more CPU when tracking objects than panning/tilting only.
Absolute zooming makes zoom movements separate from pan/tilt movements. Most PTZ cameras will support absolute zooming.
Absolute zooming makes zoom movements separate from pan/tilt movements. Most PTZ cameras will support absolute zooming. Absolute zooming was developed to be very conservative to work best with a variety of cameras and scenes. Absolute zooming usually will not occur until an object has stopped moving or is moving very slowly.
Relative zooming attempts to make a zoom movement concurrently with any pan/tilt movements. It was tested to work with some Dahua and Amcrest PTZs. But the ONVIF specification indicates that there no assumption about how the generic zoom range is mapped to magnification, field of view or other physical zoom dimension when using relative zooming. So if relative zooming behavior is erratic or just doesn't work, use absolute zooming.
Relative zooming attempts to make a zoom movement concurrently with any pan/tilt movements. It was tested to work with some Dahua and Amcrest PTZs. But the ONVIF specification indicates that there no assumption about how the generic zoom range is mapped to magnification, field of view or other physical zoom dimension when using relative zooming. So if relative zooming behavior is erratic or just doesn't work, try absolute zooming.
You can optionally adjust the `zoom_factor` for your camera in your configuration file. Lower values will leave more space from the scene around the tracked object while higher values will cause your camera to zoom in more on the object. However, keep in mind that Frigate needs a fair amount of pixels and scene details outside of the bounding box of the tracked object to estimate the motion of your camera. If the object is taking up too much of the frame, Frigate will not be able to track the motion of the camera and your object will be lost.
@ -126,3 +136,19 @@ The range of this option is from 0.1 to 0.75. The default value of 0.3 should be
## Usage applications
In security and surveillance, it's common to use "spotter" cameras in combination with your PTZ. When your fixed spotter camera detects an object, you could use an automation platform like Home Assistant to move the PTZ to a specific preset so that Frigate can begin automatically tracking the object. For example: a residence may have fixed cameras on the east and west side of the property, capturing views up and down a street. When the spotter camera on the west side detects a person, a Home Assistant automation could move the PTZ to a camera preset aimed toward the west. When the object enters the specified zone, Frigate's autotracker could then continue to track the person as it moves out of view of any of the fixed cameras.
## Troubleshooting and FAQ
### The autotracker loses track of my object. Why?
There are many reasons this could be the case. Camera motion might be causing Frigate to lose track of the object. The object might be traveling too quickly. The scene is too dark, motion settings are not sensitive enough or are too sensitive, or the scene is less than optimal for Frigate to maintain tracking.
Watching Frigate's debug view can help to determine a possible cause. The autotracked object will have a thicker colored box around it.
### I'm seeing an error in the logs that my camera "has been in ONVIF 'MOVING' status for over 10 seconds." What does this mean?
There are two possible reasons for this: a slow PTZ motor, and buggy Hikvision firmware. Frigate uses an ONVIF parameter provided by the camera, `MoveStatus`, to determine when the PTZ's motor is moving or idle. According to some users, Hikvision PTZs (even with the latest firmware), are not updating this value after PTZ movement. Unfortunately there is no workaround to this bug in Hikvision firmware, so autotracking will not function correctly and should be disabled in your config.
### I tried calibrating my camera, but it is stuck at 0%.
This is often caused by the same reason as above - the `MoveStatus` ONVIF parameter is not changing due to a bug in Hikvision firmware.

View File

@ -80,7 +80,7 @@ class PtzMotionEstimator:
frame_time, self.ptz_start_time.value, self.ptz_stop_time.value
):
logger.debug(
f"{camera}: Motion estimator running - frame time: {frame_time}, {self.ptz_start_time.value}, {self.ptz_stop_time.value}"
f"{camera}: Motion estimator running - frame time: {frame_time}, ptz start: {self.ptz_start_time.value}, ptz stop: {self.ptz_stop_time.value}"
)
frame_id = f"{camera}{frame_time}"
@ -326,6 +326,10 @@ class PtzAutoTracker:
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
self.onvif.get_camera_status(camera)
logger.info(
f"Calibration for {camera} in progress: {round((step/num_steps)*100)}% complete"
)
self.calibrating[camera] = False
logger.info(f"Calibration for {camera} complete")
@ -554,6 +558,7 @@ class PtzAutoTracker:
return centroid_distance < distance_threshold
def _should_zoom_in(self, camera, obj, box):
# returns True if we should zoom in, False if we should zoom out, None to do nothing
camera_config = self.config.cameras[camera]
camera_width = camera_config.frame_shape[1]
camera_height = camera_config.frame_shape[0]
@ -642,7 +647,6 @@ class PtzAutoTracker:
f"{camera}: Zoom test: below velocity threshold: {below_velocity_threshold} velocity x: {abs(average_velocity[0])}, x threshold: {velocity_threshold_x}, velocity y: {abs(average_velocity[1])}, y threshold: {velocity_threshold_y}"
)
# returns True to zoom in, False to zoom out
# Zoom in conditions
if (
far_from_edge
@ -652,10 +656,15 @@ class PtzAutoTracker:
return True
# Zoom out conditions
if not far_from_edge and below_distance_threshold:
if (
(not far_from_edge and below_distance_threshold)
or not below_velocity_threshold
or (not below_area_threshold and not below_distance_threshold)
):
return False
return False
# Don't zoom at all
return None
def _autotrack_move_ptz(self, camera, obj):
camera_config = self.config.cameras[camera]
@ -690,7 +699,12 @@ class PtzAutoTracker:
# get euclidean distance of the two points, sometimes the estimate is way off
distance = np.linalg.norm([x2 - x1, y2 - y1])
if distance <= 7:
# don't move ptz for estimates that are way too high either
if (
distance <= 7
and average_velocity[0] < (camera_width / camera_fps / 2)
and average_velocity[1] < (camera_height / camera_fps / 2)
):
# this box could exceed the frame boundaries if velocity is high
# but we'll handle that in _enqueue_move() as two separate moves
predicted_box = [
@ -728,20 +742,22 @@ class PtzAutoTracker:
camera_height = camera_config.frame_shape[0]
zoom = 0
result = None
current_zoom_level = self.ptz_metrics[camera]["ptz_zoom_level"].value
# absolute zooming separately from pan/tilt
if camera_config.onvif.autotracking.zooming == ZoomingModeEnum.absolute:
zoom_level = self.ptz_metrics[camera]["ptz_zoom_level"].value
# don't zoom on initial move
if self.tracked_object_previous[camera] is None:
zoom = zoom_level
zoom = current_zoom_level
else:
if 0 < zoom_level <= 1:
if self._should_zoom_in(camera, obj, obj.obj_data["box"]):
zoom = min(1.0, zoom_level + 0.1)
if (
result := self._should_zoom_in(camera, obj, obj.obj_data["box"])
) is not None:
if result:
zoom = min(1.0, current_zoom_level + 0.1)
else:
zoom = max(0.0, zoom_level - 0.1)
zoom = max(0.0, current_zoom_level - 0.2)
# don't make small movements to zoom in if area hasn't changed significantly
# but always zoom out if necessary
@ -752,7 +768,7 @@ class PtzAutoTracker:
)
/ obj.obj_data["area"]
< 0.3
and zoom <= zoom_level
and zoom <= current_zoom_level
):
zoom = 0
@ -762,22 +778,28 @@ class PtzAutoTracker:
if self.tracked_object_previous[camera] is None:
zoom = 0
else:
zoom_level = obj.obj_data["area"] / (camera_width * camera_height)
target_zoom_level = obj.obj_data["area"] / (
camera_width * camera_height
)
if self._should_zoom_in(
camera,
obj,
predicted_box
if camera_config.onvif.autotracking.movement_weights
else obj.obj_data["box"],
):
# zoom in
zoom = min(1, zoom_level * (1 / self.zoom_factor[camera]) ** 1.2)
else:
# zoom out
zoom = -(1 - zoom) if zoom != 0 else 0
if (
result := self._should_zoom_in(
camera,
obj,
predicted_box
if camera_config.onvif.autotracking.movement_weights
else obj.obj_data["box"],
)
) is not None:
# zoom in value
zoom = min(
1, target_zoom_level * (1 / self.zoom_factor[camera]) ** 1.2
)
if not result:
# zoom out
zoom = -(1 - zoom) if zoom != 0 else 0
logger.debug(f"{camera}: Zoom amount: {zoom}")
logger.debug(f"{camera}: Zooming: {result} Zoom amount: {zoom}")
return zoom
@ -922,14 +944,14 @@ class PtzAutoTracker:
)
and autotracker_config.return_preset
):
# empty move queue
while not self.move_queues[camera].empty():
self.move_queues[camera].get()
# clear tracked object
self.tracked_object[camera] = None
self.tracked_object_previous[camera] = None
# empty move queue
while not self.move_queues[camera].empty():
self.move_queues[camera].get()
self.ptz_metrics[camera]["ptz_stopped"].wait()
logger.debug(
f"{camera}: Time is {self.ptz_metrics[camera]['ptz_frame_time'].value}, returning to preset: {autotracker_config.return_preset}"

View File

@ -553,3 +553,22 @@ class OnvifController:
logger.debug(
f'{camera_name}: Camera zoom level: {self.ptz_metrics[camera_name]["ptz_zoom_level"].value}'
)
# some hikvision cams won't update MoveStatus, so warn if it hasn't changed
if (
not self.ptz_metrics[camera_name]["ptz_stopped"].is_set()
and not self.ptz_metrics[camera_name]["ptz_reset"].is_set()
and self.ptz_metrics[camera_name]["ptz_frame_time"].value
> (self.ptz_metrics[camera_name]["ptz_start_time"].value + 10)
and self.ptz_metrics[camera_name]["ptz_stop_time"].value == 0
):
logger.debug(
f'Start time: {self.ptz_metrics[camera_name]["ptz_start_time"].value}, Stop time: {self.ptz_metrics[camera_name]["ptz_stop_time"].value}, Frame time: {self.ptz_metrics[camera_name]["ptz_frame_time"].value}'
)
# set the stop time so we don't come back into this again and spam the logs
self.ptz_metrics[camera_name]["ptz_stop_time"].value = self.ptz_metrics[
camera_name
]["ptz_frame_time"].value
logger.warning(
f"Camera {camera_name} has been in ONVIF 'MOVING' status for over 10 seconds."
)