forked from Github/frigate
Adjustments and fixes (#10346)
* Increase duration of alerts and detections * Add key * Fix cancel button * Fix motion review when switching days * Add reset buttons and make calendar apply immediately * Adjust apis for motion and audio activity * Write review thumbs as webp and reduce size
This commit is contained in:
@@ -353,8 +353,8 @@ def delete_reviews(ids: str):
|
||||
return make_response(jsonify({"success": True, "message": "Delete reviews"}), 200)
|
||||
|
||||
|
||||
@ReviewBp.route("/review/activity")
|
||||
def review_activity():
|
||||
@ReviewBp.route("/review/activity/motion")
|
||||
def motion_activity():
|
||||
"""Get motion and audio activity."""
|
||||
cameras = request.args.get("cameras", "all")
|
||||
before = request.args.get("before", type=float, default=datetime.now().timestamp())
|
||||
@@ -374,6 +374,68 @@ def review_activity():
|
||||
Recordings.duration,
|
||||
Recordings.objects,
|
||||
Recordings.motion,
|
||||
)
|
||||
.where(reduce(operator.and_, clauses))
|
||||
.order_by(Recordings.start_time.asc())
|
||||
.iterator()
|
||||
)
|
||||
|
||||
# format is: { timestamp: segment_start_ts, motion: [0-100], audio: [0 - -100] }
|
||||
# periods where active objects / audio was detected will cause motion to be scaled down
|
||||
data: list[dict[str, float]] = []
|
||||
|
||||
for rec in all_recordings:
|
||||
data.append(
|
||||
{
|
||||
"start_time": rec.start_time,
|
||||
"motion": rec.motion if rec.objects == 0 else 0,
|
||||
}
|
||||
)
|
||||
|
||||
# get scale in seconds
|
||||
scale = request.args.get("scale", type=int, default=30)
|
||||
|
||||
# resample data using pandas to get activity on scaled basis
|
||||
df = pd.DataFrame(data, columns=["start_time", "motion"])
|
||||
|
||||
# set date as datetime index
|
||||
df["start_time"] = pd.to_datetime(df["start_time"], unit="s")
|
||||
df.set_index(["start_time"], inplace=True)
|
||||
|
||||
# normalize data
|
||||
df = df.resample(f"{scale}S").sum().fillna(0.0)
|
||||
df["motion"] = (
|
||||
(df["motion"] - df["motion"].min())
|
||||
/ (df["motion"].max() - df["motion"].min())
|
||||
* 100
|
||||
)
|
||||
|
||||
# change types for output
|
||||
df.index = df.index.astype(int) // (10**9)
|
||||
normalized = df.reset_index().to_dict("records")
|
||||
return jsonify(normalized)
|
||||
|
||||
|
||||
@ReviewBp.route("/review/activity/audio")
|
||||
def audio_activity():
|
||||
"""Get motion and audio activity."""
|
||||
cameras = request.args.get("cameras", "all")
|
||||
before = request.args.get("before", type=float, default=datetime.now().timestamp())
|
||||
after = request.args.get(
|
||||
"after", type=float, default=(datetime.now() - timedelta(hours=1)).timestamp()
|
||||
)
|
||||
|
||||
clauses = [(Recordings.start_time > after) & (Recordings.end_time < before)]
|
||||
|
||||
if cameras != "all":
|
||||
camera_list = cameras.split(",")
|
||||
clauses.append((Recordings.camera << camera_list))
|
||||
|
||||
all_recordings: list[Recordings] = (
|
||||
Recordings.select(
|
||||
Recordings.start_time,
|
||||
Recordings.duration,
|
||||
Recordings.objects,
|
||||
Recordings.dBFS,
|
||||
)
|
||||
.where(reduce(operator.and_, clauses))
|
||||
@@ -382,14 +444,13 @@ def review_activity():
|
||||
)
|
||||
|
||||
# format is: { timestamp: segment_start_ts, motion: [0-100], audio: [0 - -100] }
|
||||
# periods where active objects / audio was detected will cause motion / audio to be scaled down
|
||||
# periods where active objects / audio was detected will cause audio to be scaled down
|
||||
data: list[dict[str, float]] = []
|
||||
|
||||
for rec in all_recordings:
|
||||
data.append(
|
||||
{
|
||||
"start_time": rec.start_time,
|
||||
"motion": rec.motion if rec.objects == 0 else 0,
|
||||
"audio": rec.dBFS if rec.objects == 0 else 0,
|
||||
}
|
||||
)
|
||||
@@ -398,7 +459,7 @@ def review_activity():
|
||||
scale = request.args.get("scale", type=int, default=30)
|
||||
|
||||
# resample data using pandas to get activity on scaled basis
|
||||
df = pd.DataFrame(data, columns=["start_time", "motion", "audio"])
|
||||
df = pd.DataFrame(data, columns=["start_time", "audio"])
|
||||
|
||||
# set date as datetime index
|
||||
df["start_time"] = pd.to_datetime(df["start_time"], unit="s")
|
||||
@@ -406,11 +467,6 @@ def review_activity():
|
||||
|
||||
# normalize data
|
||||
df = df.resample(f"{scale}S").mean().fillna(0.0)
|
||||
df["motion"] = (
|
||||
(df["motion"] - df["motion"].min())
|
||||
/ (df["motion"].max() - df["motion"].min())
|
||||
* 100
|
||||
)
|
||||
df["audio"] = (
|
||||
(df["audio"] - df["audio"].max())
|
||||
/ (df["audio"].min() - df["audio"].max())
|
||||
|
||||
@@ -28,6 +28,10 @@ logger = logging.getLogger(__name__)
|
||||
THUMB_HEIGHT = 180
|
||||
THUMB_WIDTH = 320
|
||||
|
||||
THRESHOLD_ALERT_ACTIVITY = 120
|
||||
THRESHOLD_DETECTION_ACTIVITY = 30
|
||||
THRESHOLD_MOTION_ACTIVITY = 30
|
||||
|
||||
|
||||
class SeverityEnum(str, Enum):
|
||||
alert = "alert"
|
||||
@@ -100,7 +104,7 @@ class PendingReviewSegment:
|
||||
path = os.path.join(CLIPS_DIR, f"thumb-{self.camera}-{self.id}.jpg")
|
||||
|
||||
if self.frame is not None:
|
||||
cv2.imwrite(path, self.frame)
|
||||
cv2.imwrite(path, self.frame, [int(cv2.IMWRITE_WEBP_QUALITY), 60])
|
||||
|
||||
return {
|
||||
ReviewSegment.id: self.id,
|
||||
@@ -195,15 +199,16 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
if len(object["current_zones"]) > 0:
|
||||
segment.zones.update(object["current_zones"])
|
||||
elif (
|
||||
segment.severity == SeverityEnum.signification_motion and len(motion) >= 20
|
||||
segment.severity == SeverityEnum.signification_motion
|
||||
and len(motion) >= THRESHOLD_MOTION_ACTIVITY
|
||||
):
|
||||
segment.last_update = frame_time
|
||||
else:
|
||||
if segment.severity == SeverityEnum.alert and frame_time > (
|
||||
segment.last_update + 60
|
||||
segment.last_update + THRESHOLD_ALERT_ACTIVITY
|
||||
):
|
||||
self.end_segment(segment)
|
||||
elif frame_time > (segment.last_update + 10):
|
||||
elif frame_time > (segment.last_update + THRESHOLD_DETECTION_ACTIVITY):
|
||||
self.end_segment(segment)
|
||||
|
||||
def check_if_new_segment(
|
||||
|
||||
Reference in New Issue
Block a user