Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.10.0 #1927

Merged
merged 115 commits into from
Feb 19, 2022
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
61c62d4
version tick
blakeblackshear Oct 6, 2021
b63c56d
only save recordings when an event is in progress
blakeblackshear Oct 23, 2021
8f101cc
improve box merging and keep tracking
blakeblackshear Oct 30, 2021
d17bd74
reduce detection rate for stationary objects
blakeblackshear Oct 30, 2021
24cc63d
drop high overlap detections
blakeblackshear Oct 31, 2021
5bec438
config option for stationary detection interval
blakeblackshear Oct 31, 2021
58117e2
check for overlapping motion boxes
blakeblackshear Nov 4, 2021
9dc6c42
improve contrast
blakeblackshear Nov 4, 2021
57dcb29
consolidate regions
blakeblackshear Nov 4, 2021
ff667b0
remove min frame height of 180 and increase contour area
blakeblackshear Nov 4, 2021
d554175
no longer make motion settings dynamic
blakeblackshear Nov 7, 2021
bd7755f
revamp process clip
blakeblackshear Nov 7, 2021
8f43a2d
use resolution of clip
blakeblackshear Nov 8, 2021
4422e86
clarify shm in docs
blakeblackshear Nov 8, 2021
1c1c28d
create ffmpeg commands on startup
blakeblackshear Nov 8, 2021
cdd3000
fix ffmpeg config for env vars
blakeblackshear Nov 9, 2021
c7faef8
don't modify ffmpeg_cmd object
blakeblackshear Nov 9, 2021
3541f96
error handling for the recording maintainer
blakeblackshear Nov 9, 2021
51fb532
set retain when setting switches from frontend
blakeblackshear Nov 9, 2021
14c74e4
more robust cache management
blakeblackshear Nov 11, 2021
b912851
fix default motion comment
blakeblackshear Nov 15, 2021
ae96804
revert switch to b/w frame prep
blakeblackshear Nov 17, 2021
1ebb8a5
avoid divide by zero
blakeblackshear Nov 17, 2021
19a6978
avoid proactive messages with retain_days 0 and handle first pass
blakeblackshear Nov 17, 2021
c7d4743
better cache handling
blakeblackshear Nov 17, 2021
585efe1
keep 5 segments in cache
blakeblackshear Nov 19, 2021
3d556cc
warn if no wait time
blakeblackshear Nov 19, 2021
a3301e0
avoid running ffprobe for each segment multiple times
blakeblackshear Nov 19, 2021
e6d2df5
add duration to cache
blakeblackshear Nov 19, 2021
63b7465
ensure stationary interval is greater than 0
blakeblackshear Nov 20, 2021
494e5ac
use snapshot url to support in progress events
blakeblackshear Nov 20, 2021
77c66d4
ensure duration > 0 for segments
blakeblackshear Nov 21, 2021
7a2a85d
log error messages on vod endpoints
blakeblackshear Nov 21, 2021
ae3c01f
handle missing file edge case
blakeblackshear Nov 21, 2021
77c1f1b
cleanup missing files from database once per hour
blakeblackshear Nov 21, 2021
c1155af
ensure cache copies when events have ended
blakeblackshear Nov 21, 2021
26241b0
no need to expire recordings every minute
blakeblackshear Dec 5, 2021
92e08b9
sync recordings with disk once on startup
blakeblackshear Dec 5, 2021
af00132
fix process_clip
blakeblackshear Dec 5, 2021
f3efc06
retain frame data for recording maintenance
blakeblackshear Dec 11, 2021
63f8034
pass processed tracked objects
blakeblackshear Dec 11, 2021
9f18629
switch to retain config instead of retain_days
blakeblackshear Dec 11, 2021
cbb2882
refactor segment stats logic
blakeblackshear Dec 11, 2021
df0246a
warn when retention mismatch
blakeblackshear Dec 11, 2021
18fd50d
store objects and motion counts in the db
blakeblackshear Dec 11, 2021
b19a028
expire overlapping segments based on mode
blakeblackshear Dec 11, 2021
589432b
update docs
blakeblackshear Dec 11, 2021
fcb4aae
limit vod response cache
blakeblackshear Dec 12, 2021
a5c13e7
Add temperature of coral tpu to telemetry mqtt message
mattthewclayton Nov 29, 2021
156e1a4
Allow for ".yaml" (#2244)
jcgoette Dec 12, 2021
251d29a
#2117 change entered_zones from set to list so that they are not auto…
ryanm101 Dec 12, 2021
95bdf9f
check for apex dir
blakeblackshear Dec 12, 2021
609b436
fix migrations
blakeblackshear Dec 13, 2021
db1255a
disable disk sync on startup
blakeblackshear Dec 13, 2021
1569ce7
Change JPEG mime type (#2543)
tjhorner Dec 30, 2021
9edf383
safe refactoring (#2552)
yury-sannikov Dec 31, 2021
bd8e238
Run python unit tests in a github actions (#2589)
yury-sannikov Jan 14, 2022
273f803
Event Datepicker (#2428)
Feb 2, 2022
040d8c9
require url safe camera names
blakeblackshear Feb 2, 2022
326b368
cleanup clean snapshots on event deletion too
blakeblackshear Feb 2, 2022
944b918
if recording not on disk, delete from db and return
blakeblackshear Feb 2, 2022
82c6009
improve method for determining position
blakeblackshear Feb 4, 2022
92f9195
randomize the region multiplier for variation
blakeblackshear Feb 4, 2022
077d900
require a position change to be an active object
blakeblackshear Feb 5, 2022
307068a
scan the frame on startup
blakeblackshear Feb 5, 2022
037f866
default periodic checks to never
blakeblackshear Feb 5, 2022
955c277
dont stop scanning when there are other regions
blakeblackshear Feb 5, 2022
f801930
use iou instead of centroid
blakeblackshear Feb 5, 2022
2b7d38f
avoid extra tracking work on stationary frames
blakeblackshear Feb 5, 2022
0916481
make expire interval configurable for users wanting to minimize i/o
blakeblackshear Feb 5, 2022
23c70ac
update stationary interval docs
blakeblackshear Feb 5, 2022
e6ec5cb
make motion the default retain mode
blakeblackshear Feb 5, 2022
b1e84ca
allow dash in camera name
blakeblackshear Feb 5, 2022
7b4cb95
package updates for docs
blakeblackshear Feb 6, 2022
794a9ff
upgrade npm in dev container
blakeblackshear Feb 6, 2022
21cc29b
add additional info for non-H264 cameras
blakeblackshear Feb 6, 2022
21f1a98
add new properties to the docs
blakeblackshear Feb 6, 2022
50b5d40
add stacktrace to config validation errors
blakeblackshear Feb 6, 2022
3600ebc
adjust error messages on ffmpeg crash
blakeblackshear Feb 6, 2022
499f75e
set has_clip to false when recordings fail
blakeblackshear Feb 6, 2022
2d5ec25
invert active_count logic
blakeblackshear Feb 6, 2022
5a2076f
improve warning for retain modes
blakeblackshear Feb 6, 2022
1a3f21e
note for future
blakeblackshear Feb 6, 2022
f57501d
avoid rare divide by zero
blakeblackshear Feb 6, 2022
47e0e1d
add example for ios camera live feed notification
blakeblackshear Feb 6, 2022
5e156f8
update addon urls
blakeblackshear Feb 6, 2022
02c91d4
clarify that zones are based on the bottom center
blakeblackshear Feb 6, 2022
acc1022
remove outdated output args tip
blakeblackshear Feb 6, 2022
4e23967
clarify addon versions
blakeblackshear Feb 6, 2022
24f9937
fix resolution on reolink example
blakeblackshear Feb 6, 2022
9a0d276
allow motion based retention when detect is disabled
blakeblackshear Feb 6, 2022
ad4929c
increment motionless_count
blakeblackshear Feb 6, 2022
3617a62
only update db entry when a stored property changes
blakeblackshear Feb 8, 2022
8670a3d
publish an update on position changes
blakeblackshear Feb 8, 2022
0b02f20
make stationary_threshold configurable
blakeblackshear Feb 8, 2022
64f80a4
signal an update when object becomes stationary
blakeblackshear Feb 8, 2022
a3fa3cb
update an object once per minute
blakeblackshear Feb 9, 2022
54b88fb
Add in progress events to recordings view
hunterjm Feb 9, 2022
45b56bd
Update package-lock.json
hunterjm Feb 9, 2022
9ecc792
Fix playback rate resetting to 1 on source change
hunterjm Feb 9, 2022
62c1a61
remove invalid warning
blakeblackshear Feb 9, 2022
54d1a22
Allow download of in progress clips
hunterjm Feb 9, 2022
1171770
Only send significant update once when motionless count reaches the d…
hunterjm Feb 9, 2022
4deb365
Fix duration for long events and playback rate for top of the hour
hunterjm Feb 9, 2022
adbc54b
selectively increment position changes
blakeblackshear Feb 10, 2022
7934f86
fix the bounding box calculation position at 10
blakeblackshear Feb 11, 2022
4e52461
set stationary_threshold default to 5x fps
blakeblackshear Feb 11, 2022
95ab22d
bump default stationary_threshold to 10s
blakeblackshear Feb 11, 2022
6b2bae0
stop forcing detection all the way to stationary_threshold
blakeblackshear Feb 11, 2022
334e28f
use second stream in docs example
blakeblackshear Feb 12, 2022
ee01396
update birdseye to handle stationary objects
blakeblackshear Feb 12, 2022
889835a
Always show recording link even if recordings are currently disabled …
NickM-27 Feb 12, 2022
304ffa8
refactor stationary config into section
blakeblackshear Feb 13, 2022
3be0b91
deregister based on max_frames setting
blakeblackshear Feb 13, 2022
e5714f5
add missing optional comment in docs
blakeblackshear Feb 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ models
*.mp4
*.ts
*.db
*.csv
frigate/version.py
web/build
web/node_modules
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ default_target: amd64_frigate
COMMIT_HASH := $(shell git log -1 --pretty=format:"%h"|tail -1)

version:
echo "VERSION='0.9.4-$(COMMIT_HASH)'" > frigate/version.py
echo "VERSION='0.10.0-$(COMMIT_HASH)'" > frigate/version.py

web:
docker build --tag frigate-web --file docker/Dockerfile.web web/
Expand Down
22 changes: 14 additions & 8 deletions docs/docs/configuration/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ detect:
enabled: True
# Optional: Number of frames without a detection before frigate considers an object to be gone. (default: 5x the frame rate)
max_disappeared: 25
# Optional: Frequency for running detection on stationary objects (default: 10x the frame rate)
stationary_interval: 50

# Optional: Object configuration
# NOTE: Can be overridden at the camera level
Expand Down Expand Up @@ -192,10 +194,14 @@ motion:
# Increasing this value will make motion detection less sensitive and decreasing it will make motion detection more sensitive.
# The value should be between 1 and 255.
threshold: 25
# Optional: Minimum size in pixels in the resized motion image that counts as motion (default: ~0.17% of the motion frame area)
# Increasing this value will prevent smaller areas of motion from being detected. Decreasing will make motion detection more sensitive to smaller
# moving objects.
contour_area: 100
# Optional: Minimum size in pixels in the resized motion image that counts as motion (default: 30)
# Increasing this value will prevent smaller areas of motion from being detected. Decreasing will
# make motion detection more sensitive to smaller moving objects.
# As a rule of thumb:
# - 15 - high sensitivity
# - 30 - medium sensitivity
# - 50 - low sensitivity
contour_area: 30
# Optional: Alpha value passed to cv2.accumulateWeighted when averaging the motion delta across multiple frames (default: shown below)
# Higher values mean the current frame impacts the delta a lot, and a single raindrop may register as motion.
# Too low and a fast moving person wont be detected as motion.
Expand All @@ -205,10 +211,10 @@ motion:
# Low values will cause things like moving shadows to be detected as motion for longer.
# https://www.geeksforgeeks.org/background-subtraction-in-an-image-using-concept-of-running-average/
frame_alpha: 0.2
# Optional: Height of the resized motion frame (default: 1/6th of the original frame height, but no less than 180)
# This operates as an efficient blur alternative. Higher values will result in more granular motion detection at the expense of higher CPU usage.
# Lower values result in less CPU, but small changes may not register as motion.
frame_height: 180
# Optional: Height of the resized motion frame (default: 80)
# This operates as an efficient blur alternative. Higher values will result in more granular motion detection at the expense
# of higher CPU usage. Lower values result in less CPU, but small changes may not register as motion.
frame_height: 50
# Optional: motion mask
# NOTE: see docs for more detailed info on creating masks
mask: 0,900,1080,900,1080,1920,0,1920
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/configuration/record.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ record:

This configuration will retain recording segments that overlap with events for 10 days. Because multiple events can reference the same recording segments, this avoids storing duplicate footage for overlapping events and reduces overall storage needs.

When `retain_days` is set to `0`, events will have up to `max_seconds` (defaults to 5 minutes) of recordings retained. Increasing `retain_days` to `1` will allow events to exceed the `max_seconds` limitation of up to 1 day.
When `retain_days` is set to `0`, segments will be deleted from the cache if no events are in progress
2 changes: 1 addition & 1 deletion docs/docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Frigate utilizes shared memory to store frames during processing. The default `s

The default shm-size of 64m is fine for setups with 2 or less 1080p cameras. If frigate is exiting with "Bus error" messages, it is likely because you have too many high resolution cameras and you need to specify a higher shm size.

You can calculate the necessary shm-size for each camera with the following formula:
You can calculate the necessary shm-size for each camera with the following formula using the resolution specified for detect:

```
(width * height * 1.5 * 9 + 270480)/1048576 = <shm size in mb>
Expand Down
3 changes: 3 additions & 0 deletions frigate/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ def init_config(self):
self.config = user_config.runtime_config

for camera_name in self.config.cameras.keys():
# generage the ffmpeg commands
self.config.cameras[camera_name].create_ffmpeg_cmds()

# create camera_metrics
self.camera_metrics[camera_name] = {
"camera_fps": mp.Value("d", 0.0),
Expand Down
29 changes: 16 additions & 13 deletions frigate/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from pydantic import BaseModel, Extra, Field, validator
from pydantic.fields import PrivateAttr

from frigate.const import BASE_DIR, CACHE_DIR, RECORD_DIR
from frigate.const import BASE_DIR, CACHE_DIR
from frigate.edgetpu import load_labels
from frigate.util import create_mask, deep_merge

Expand Down Expand Up @@ -103,10 +103,10 @@ class MotionConfig(FrigateBaseModel):
ge=1,
le=255,
)
contour_area: Optional[int] = Field(title="Contour Area")
contour_area: Optional[int] = Field(default=30, title="Contour Area")
delta_alpha: float = Field(default=0.2, title="Delta Alpha")
frame_alpha: float = Field(default=0.2, title="Frame Alpha")
frame_height: Optional[int] = Field(title="Frame Height")
frame_height: Optional[int] = Field(default=50, title="Frame Height")
mask: Union[str, List[str]] = Field(
default="", title="Coordinates polygon for the motion mask."
)
Expand All @@ -119,15 +119,6 @@ class RuntimeMotionConfig(MotionConfig):
def __init__(self, **config):
frame_shape = config.get("frame_shape", (1, 1))

if "frame_height" not in config:
config["frame_height"] = max(frame_shape[0] // 6, 180)

if "contour_area" not in config:
frame_width = frame_shape[1] * config["frame_height"] / frame_shape[0]
config["contour_area"] = (
config["frame_height"] * frame_width * 0.00173611111
)

mask = config.get("mask", "")
config["raw_mask"] = mask

Expand Down Expand Up @@ -162,6 +153,9 @@ class DetectConfig(FrigateBaseModel):
max_disappeared: Optional[int] = Field(
title="Maximum number of frames the object can dissapear before detection ends."
)
stationary_interval: Optional[int] = Field(
title="Frame interval for checking stationary objects."
)


class FilterConfig(FrigateBaseModel):
Expand Down Expand Up @@ -495,6 +489,7 @@ class CameraConfig(FrigateBaseModel):
timestamp_style: TimestampStyleConfig = Field(
default_factory=TimestampStyleConfig, title="Timestamp style configuration."
)
_ffmpeg_cmds: List[Dict[str, List[str]]] = PrivateAttr()

def __init__(self, **config):
# Set zone colors
Expand All @@ -521,14 +516,17 @@ def frame_shape_yuv(self) -> Tuple[int, int]:

@property
def ffmpeg_cmds(self) -> List[Dict[str, List[str]]]:
return self._ffmpeg_cmds

def create_ffmpeg_cmds(self):
ffmpeg_cmds = []
for ffmpeg_input in self.ffmpeg.inputs:
ffmpeg_cmd = self._get_ffmpeg_cmd(ffmpeg_input)
if ffmpeg_cmd is None:
continue

ffmpeg_cmds.append({"roles": ffmpeg_input.roles, "cmd": ffmpeg_cmd})
return ffmpeg_cmds
self._ffmpeg_cmds = ffmpeg_cmds

def _get_ffmpeg_cmd(self, ffmpeg_input: CameraInput):
ffmpeg_output_args = []
Expand Down Expand Up @@ -745,6 +743,11 @@ def runtime_config(self) -> FrigateConfig:
if camera_config.detect.max_disappeared is None:
camera_config.detect.max_disappeared = max_disappeared

# Default stationary_interval configuration
stationary_interval = camera_config.detect.fps * 10
if camera_config.detect.stationary_interval is None:
camera_config.detect.stationary_interval = stationary_interval

# FFMPEG input substitution
for input in camera_config.ffmpeg.inputs:
input.path = input.path.format(**FRIGATE_ENV_VARS)
Expand Down
38 changes: 34 additions & 4 deletions frigate/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ def __init__(
self.stop_event = stop_event

def run(self):
# set an end_time on events without an end_time on startup
Event.update(end_time=Event.start_time + 30).where(
Event.end_time == None
).execute()

while not self.stop_event.is_set():
try:
event_type, camera, event_data = self.event_queue.get(timeout=10)
Expand All @@ -38,14 +43,35 @@ def run(self):

logger.debug(f"Event received: {event_type} {camera} {event_data['id']}")

event_config: EventsConfig = self.config.cameras[camera].record.events

if event_type == "start":
self.events_in_process[event_data["id"]] = event_data

if event_type == "end":
event_config: EventsConfig = self.config.cameras[camera].record.events
elif event_type == "update":
self.events_in_process[event_data["id"]] = event_data
# TODO: this will generate a lot of db activity possibly
if event_data["has_clip"] or event_data["has_snapshot"]:
Event.replace(
id=event_data["id"],
label=event_data["label"],
camera=camera,
start_time=event_data["start_time"] - event_config.pre_capture,
end_time=None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end_time can not be None/Null, peewee comes back with a database exception, I believe you need to set DateTimeField(null=True) in models.py:Event()

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a database migration that should be removing the null constraint. I am not seeing any issues here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, a problem with my adhoc dev environment. I will follow the contributing guidelines from now on.

top_score=event_data["top_score"],
false_positive=event_data["false_positive"],
zones=list(event_data["entered_zones"]),
thumbnail=event_data["thumbnail"],
region=event_data["region"],
box=event_data["box"],
area=event_data["area"],
has_clip=event_data["has_clip"],
has_snapshot=event_data["has_snapshot"],
).execute()

elif event_type == "end":
if event_data["has_clip"] or event_data["has_snapshot"]:
Event.create(
Event.replace(
id=event_data["id"],
label=event_data["label"],
camera=camera,
Expand All @@ -60,11 +86,15 @@ def run(self):
area=event_data["area"],
has_clip=event_data["has_clip"],
has_snapshot=event_data["has_snapshot"],
)
).execute()

del self.events_in_process[event_data["id"]]
self.event_processed_queue.put((event_data["id"], camera))

# set an end_time on events without an end_time before exiting
Event.update(end_time=datetime.datetime.now().timestamp()).where(
Event.end_time == None
).execute()
logger.info(f"Exiting event processor...")


Expand Down
10 changes: 7 additions & 3 deletions frigate/http.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import base64
from collections import OrderedDict
from datetime import datetime, timedelta
import copy
import json
import glob
import logging
Expand Down Expand Up @@ -190,7 +191,7 @@ def event_snapshot(id):
download = request.args.get("download", type=bool)
jpg_bytes = None
try:
event = Event.get(Event.id == id)
event = Event.get(Event.id == id, Event.end_time != None)
if not event.has_snapshot:
return "Snapshot not available", 404
# read snapshot from disk
Expand Down Expand Up @@ -321,7 +322,7 @@ def config():
# add in the ffmpeg_cmds
for camera_name, camera in current_app.frigate_config.cameras.items():
camera_dict = config["cameras"][camera_name]
camera_dict["ffmpeg_cmds"] = camera.ffmpeg_cmds
camera_dict["ffmpeg_cmds"] = copy.deepcopy(camera.ffmpeg_cmds)
for cmd in camera_dict["ffmpeg_cmds"]:
cmd["cmd"] = " ".join(cmd["cmd"])

Expand Down Expand Up @@ -697,7 +698,10 @@ def vod_event(id):
clip_path = os.path.join(CLIPS_DIR, f"{event.camera}-{id}.mp4")

if not os.path.isfile(clip_path):
return vod_ts(event.camera, event.start_time, event.end_time)
end_ts = (
datetime.now().timestamp() if event.end_time is None else event.end_time
)
return vod_ts(event.camera, event.start_time, end_ts)

duration = int((event.end_time - event.start_time) * 1000)
return jsonify(
Expand Down
50 changes: 43 additions & 7 deletions frigate/motion.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def __init__(self, frame_shape, config: MotionConfig):
interpolation=cv2.INTER_LINEAR,
)
self.mask = np.where(resized_mask == [0])
self.save_images = False

def detect(self, frame):
motion_boxes = []
Expand All @@ -36,10 +37,13 @@ def detect(self, frame):
interpolation=cv2.INTER_LINEAR,
)

# TODO: can I improve the contrast of the grayscale image here?

# convert to grayscale
# resized_frame = cv2.cvtColor(resized_frame, cv2.COLOR_BGR2GRAY)
# Improve contrast
minval = np.percentile(resized_frame, 4)
maxval = np.percentile(resized_frame, 96)
resized_frame = np.clip(resized_frame, minval, maxval)
resized_frame = (((resized_frame - minval) / (maxval - minval)) * 255).astype(
np.uint8
)

# mask frame
resized_frame[self.mask] = [255]
Expand All @@ -49,6 +53,8 @@ def detect(self, frame):
if self.frame_counter < 30:
self.frame_counter += 1
else:
if self.save_images:
self.frame_counter += 1
# compare to average
frameDelta = cv2.absdiff(resized_frame, cv2.convertScaleAbs(self.avg_frame))

Expand All @@ -58,7 +64,6 @@ def detect(self, frame):
cv2.accumulateWeighted(frameDelta, self.avg_delta, self.config.delta_alpha)

# compute the threshold image for the current frame
# TODO: threshold
current_thresh = cv2.threshold(
frameDelta, self.config.threshold, 255, cv2.THRESH_BINARY
)[1]
Expand All @@ -75,8 +80,10 @@ def detect(self, frame):

# dilate the thresholded image to fill in holes, then find contours
# on thresholded image
thresh = cv2.dilate(thresh, None, iterations=2)
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
thresh_dilated = cv2.dilate(thresh, None, iterations=2)
cnts = cv2.findContours(
thresh_dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
cnts = imutils.grab_contours(cnts)

# loop over the contours
Expand All @@ -94,6 +101,35 @@ def detect(self, frame):
)
)

if self.save_images:
thresh_dilated = cv2.cvtColor(thresh_dilated, cv2.COLOR_GRAY2BGR)
# print("--------")
# print(self.frame_counter)
for c in cnts:
contour_area = cv2.contourArea(c)
# print(contour_area)
if contour_area > self.config.contour_area:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(
thresh_dilated,
(x, y),
(x + w, y + h),
(0, 0, 255),
2,
)
# print("--------")
image_row_1 = cv2.hconcat(
[
cv2.cvtColor(frameDelta, cv2.COLOR_GRAY2BGR),
cv2.cvtColor(avg_delta_image, cv2.COLOR_GRAY2BGR),
]
)
image_row_2 = cv2.hconcat(
[cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR), thresh_dilated]
)
combined_image = cv2.vconcat([image_row_1, image_row_2])
cv2.imwrite(f"motion/motion-{self.frame_counter}.jpg", combined_image)

if len(motion_boxes) > 0:
self.motion_frame_count += 1
if self.motion_frame_count >= 10:
Expand Down
5 changes: 5 additions & 0 deletions frigate/object_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@ def start(camera, obj: TrackedObject, current_frame_time):
self.event_queue.put(("start", camera, obj.to_dict()))

def update(camera, obj: TrackedObject, current_frame_time):
obj.has_snapshot = self.should_save_snapshot(camera, obj)
obj.has_clip = self.should_retain_recording(camera, obj)
after = obj.to_dict()
message = {
"before": obj.previous,
Expand All @@ -613,6 +615,9 @@ def update(camera, obj: TrackedObject, current_frame_time):
f"{self.topic_prefix}/events", json.dumps(message), retain=False
)
obj.previous = after
self.event_queue.put(
("update", camera, obj.to_dict(include_thumbnail=True))
)

def end(camera, obj: TrackedObject, current_frame_time):
# populate has_snapshot
Expand Down
Loading