forked from Github/frigate
Compare commits
34 Commits
v0.5.0-rc4
...
v0.4.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ea0eeda06 | ||
|
|
94878315ae | ||
|
|
8dab9e17dd | ||
|
|
5b2470e91e | ||
|
|
3d5faa956c | ||
|
|
b615b84f57 | ||
|
|
6f7b70665b | ||
|
|
3a5cb465fe | ||
|
|
205b8b413f | ||
|
|
1b74d7a19f | ||
|
|
b18e8ca468 | ||
|
|
9ebe186443 | ||
|
|
e580aca440 | ||
|
|
191f293037 | ||
|
|
d31ba69b1b | ||
|
|
02e1035826 | ||
|
|
3d419a39a8 | ||
|
|
474a3e604d | ||
|
|
fc757ad04f | ||
|
|
2a86d3e2e8 | ||
|
|
3e374ceb5f | ||
|
|
0b8f2cadf3 | ||
|
|
42f666491a | ||
|
|
35771b3444 | ||
|
|
2010ae8f87 | ||
|
|
fb0f6bcfae | ||
|
|
7b1da388d9 | ||
|
|
5d0c12fbd4 | ||
|
|
a43fd96349 | ||
|
|
bf94fdc54d | ||
|
|
48b3f22866 | ||
|
|
36443980ea | ||
|
|
0f8f8fa3b3 | ||
|
|
d8a3f8fc9d |
@@ -1,4 +1,4 @@
|
|||||||
FROM ubuntu:18.04
|
FROM debian:stretch-slim
|
||||||
LABEL maintainer "blakeb@blakeshome.com"
|
LABEL maintainer "blakeb@blakeshome.com"
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
@@ -16,7 +16,7 @@ RUN apt -qq update && apt -qq install --no-install-recommends -y \
|
|||||||
# pillow-simd
|
# pillow-simd
|
||||||
# zlib1g-dev libjpeg-dev \
|
# zlib1g-dev libjpeg-dev \
|
||||||
# VAAPI drivers for Intel hardware accel
|
# VAAPI drivers for Intel hardware accel
|
||||||
libva-drm2 libva2 i965-va-driver vainfo \
|
i965-va-driver vainfo \
|
||||||
&& echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" > /etc/apt/sources.list.d/coral-edgetpu.list \
|
&& echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" > /etc/apt/sources.list.d/coral-edgetpu.list \
|
||||||
&& wget -q -O - https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - \
|
&& wget -q -O - https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - \
|
||||||
&& apt -qq update \
|
&& apt -qq update \
|
||||||
|
|||||||
@@ -81,12 +81,6 @@ cameras:
|
|||||||
# hwaccel_args: []
|
# hwaccel_args: []
|
||||||
# input_args: []
|
# input_args: []
|
||||||
# output_args: []
|
# output_args: []
|
||||||
|
|
||||||
################
|
|
||||||
## Optionally specify the resolution of the video feed. Frigate will try to auto detect if not specified
|
|
||||||
################
|
|
||||||
# height: 1280
|
|
||||||
# width: 720
|
|
||||||
|
|
||||||
################
|
################
|
||||||
## Optional mask. Must be the same dimensions as your video feed.
|
## Optional mask. Must be the same dimensions as your video feed.
|
||||||
@@ -106,19 +100,7 @@ cameras:
|
|||||||
take_frame: 1
|
take_frame: 1
|
||||||
|
|
||||||
################
|
################
|
||||||
# The number of seconds frigate will allow a camera to go without sending a frame before
|
# Overrides for global object config
|
||||||
# assuming the ffmpeg process has a problem and restarting.
|
|
||||||
################
|
|
||||||
# watchdog_timeout: 300
|
|
||||||
|
|
||||||
################
|
|
||||||
# Configuration for the snapshot sent over mqtt
|
|
||||||
################
|
|
||||||
snapshots:
|
|
||||||
show_timestamp: True
|
|
||||||
|
|
||||||
################
|
|
||||||
# Camera level object config. This config is merged with the global config above.
|
|
||||||
################
|
################
|
||||||
objects:
|
objects:
|
||||||
track:
|
track:
|
||||||
|
|||||||
@@ -88,30 +88,21 @@ class DetectedObjectsProcessor(threading.Thread):
|
|||||||
obj['clipped'] = True
|
obj['clipped'] = True
|
||||||
|
|
||||||
# Compute the area
|
# Compute the area
|
||||||
# TODO: +1 right?
|
|
||||||
obj['area'] = (obj['box']['xmax']-obj['box']['xmin'])*(obj['box']['ymax']-obj['box']['ymin'])
|
obj['area'] = (obj['box']['xmax']-obj['box']['xmin'])*(obj['box']['ymax']-obj['box']['ymin'])
|
||||||
|
|
||||||
self.camera.detected_objects[frame['frame_time']].append(obj)
|
self.camera.detected_objects[frame['frame_time']].append(obj)
|
||||||
|
|
||||||
# TODO: use in_process and processed counts instead to avoid lock
|
|
||||||
with self.camera.regions_in_process_lock:
|
with self.camera.regions_in_process_lock:
|
||||||
if frame['frame_time'] in self.camera.regions_in_process:
|
self.camera.regions_in_process[frame['frame_time']] -= 1
|
||||||
self.camera.regions_in_process[frame['frame_time']] -= 1
|
|
||||||
# print(f"{frame['frame_time']} remaining regions {self.camera.regions_in_process[frame['frame_time']]}")
|
# print(f"{frame['frame_time']} remaining regions {self.camera.regions_in_process[frame['frame_time']]}")
|
||||||
|
|
||||||
if self.camera.regions_in_process[frame['frame_time']] == 0:
|
if self.camera.regions_in_process[frame['frame_time']] == 0:
|
||||||
del self.camera.regions_in_process[frame['frame_time']]
|
del self.camera.regions_in_process[frame['frame_time']]
|
||||||
# print(f"{frame['frame_time']} no remaining regions")
|
# print(f"{frame['frame_time']} no remaining regions")
|
||||||
self.camera.finished_frame_queue.put(frame['frame_time'])
|
|
||||||
else:
|
|
||||||
self.camera.finished_frame_queue.put(frame['frame_time'])
|
self.camera.finished_frame_queue.put(frame['frame_time'])
|
||||||
|
|
||||||
# Thread that checks finished frames for clipped objects and sends back
|
# Thread that checks finished frames for clipped objects and sends back
|
||||||
# for processing if needed
|
# for processing if needed
|
||||||
# TODO: evaluate whether or not i really need separate threads/queues for each step
|
|
||||||
# given that only 1 thread will really be able to run at a time. you need a
|
|
||||||
# separate process to actually do things in parallel for when you are CPU bound.
|
|
||||||
# threads are good when you are waiting and could be processing while you wait
|
|
||||||
class RegionRefiner(threading.Thread):
|
class RegionRefiner(threading.Thread):
|
||||||
def __init__(self, camera):
|
def __init__(self, camera):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
@@ -369,9 +360,6 @@ class ObjectTracker(threading.Thread):
|
|||||||
# than the number of existing object centroids we need to
|
# than the number of existing object centroids we need to
|
||||||
# register each new input centroid as a trackable object
|
# register each new input centroid as a trackable object
|
||||||
# if D.shape[0] < D.shape[1]:
|
# if D.shape[0] < D.shape[1]:
|
||||||
# TODO: rather than assuming these are new objects, we could
|
|
||||||
# look to see if any of the remaining boxes have a large amount
|
|
||||||
# of overlap...
|
|
||||||
for col in unusedCols:
|
for col in unusedCols:
|
||||||
self.register(col, group[col])
|
self.register(col, group[col])
|
||||||
|
|
||||||
@@ -411,8 +399,7 @@ class BestFrames(threading.Thread):
|
|||||||
obj['box']['xmax'], obj['box']['ymax'], obj['name'], "{}% {}".format(int(obj['score']*100), obj['area']))
|
obj['box']['xmax'], obj['box']['ymax'], obj['name'], "{}% {}".format(int(obj['score']*100), obj['area']))
|
||||||
|
|
||||||
# print a timestamp
|
# print a timestamp
|
||||||
if self.camera.snapshot_config['show_timestamp']:
|
time_to_show = datetime.datetime.fromtimestamp(obj['frame_time']).strftime("%m/%d/%Y %H:%M:%S")
|
||||||
time_to_show = datetime.datetime.fromtimestamp(obj['frame_time']).strftime("%m/%d/%Y %H:%M:%S")
|
cv2.putText(best_frame, time_to_show, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, fontScale=.8, color=(255, 255, 255), thickness=2)
|
||||||
cv2.putText(best_frame, time_to_show, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, fontScale=.8, color=(255, 255, 255), thickness=2)
|
|
||||||
|
|
||||||
self.best_frames[name] = best_frame
|
self.best_frames[name] = best_frame
|
||||||
@@ -11,7 +11,6 @@ import numpy as np
|
|||||||
import prctl
|
import prctl
|
||||||
import copy
|
import copy
|
||||||
import itertools
|
import itertools
|
||||||
import json
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from frigate.util import tonumpyarray, LABELS, draw_box_with_label, calculate_region, EventsPerSecond
|
from frigate.util import tonumpyarray, LABELS, draw_box_with_label, calculate_region, EventsPerSecond
|
||||||
from frigate.object_detection import RegionPrepper, RegionRequester
|
from frigate.object_detection import RegionPrepper, RegionRequester
|
||||||
@@ -43,29 +42,8 @@ class FrameTracker(threading.Thread):
|
|||||||
del self.recent_frames[k]
|
del self.recent_frames[k]
|
||||||
|
|
||||||
def get_frame_shape(source):
|
def get_frame_shape(source):
|
||||||
ffprobe_cmd = " ".join([
|
# capture a single frame and check the frame shape so the correct array
|
||||||
'ffprobe',
|
# size can be allocated in memory
|
||||||
'-v',
|
|
||||||
'panic',
|
|
||||||
'-show_error',
|
|
||||||
'-show_streams',
|
|
||||||
'-of',
|
|
||||||
'json',
|
|
||||||
'"'+source+'"'
|
|
||||||
])
|
|
||||||
print(ffprobe_cmd)
|
|
||||||
p = sp.Popen(ffprobe_cmd, stdout=sp.PIPE, shell=True)
|
|
||||||
(output, err) = p.communicate()
|
|
||||||
p_status = p.wait()
|
|
||||||
info = json.loads(output)
|
|
||||||
print(info)
|
|
||||||
|
|
||||||
video_info = [s for s in info['streams'] if s['codec_type'] == 'video'][0]
|
|
||||||
|
|
||||||
if video_info['height'] != 0 and video_info['width'] != 0:
|
|
||||||
return (video_info['height'], video_info['width'], 3)
|
|
||||||
|
|
||||||
# fallback to using opencv if ffprobe didnt succeed
|
|
||||||
video = cv2.VideoCapture(source)
|
video = cv2.VideoCapture(source)
|
||||||
ret, frame = video.read()
|
ret, frame = video.read()
|
||||||
frame_shape = frame.shape
|
frame_shape = frame.shape
|
||||||
@@ -87,7 +65,7 @@ class CameraWatchdog(threading.Thread):
|
|||||||
# wait a bit before checking
|
# wait a bit before checking
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
|
|
||||||
if self.camera.frame_time.value != 0.0 and (datetime.datetime.now().timestamp() - self.camera.frame_time.value) > self.camera.watchdog_timeout:
|
if self.camera.frame_time.value != 0.0 and (datetime.datetime.now().timestamp() - self.camera.frame_time.value) > 300:
|
||||||
print(self.camera.name + ": last frame is more than 5 minutes old, restarting camera capture...")
|
print(self.camera.name + ": last frame is more than 5 minutes old, restarting camera capture...")
|
||||||
self.camera.start_or_restart_capture()
|
self.camera.start_or_restart_capture()
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
@@ -173,15 +151,8 @@ class Camera:
|
|||||||
camera_objects_config = config.get('objects', {})
|
camera_objects_config = config.get('objects', {})
|
||||||
|
|
||||||
self.take_frame = self.config.get('take_frame', 1)
|
self.take_frame = self.config.get('take_frame', 1)
|
||||||
self.watchdog_timeout = self.config.get('watchdog_timeout', 300)
|
|
||||||
self.snapshot_config = {
|
|
||||||
'show_timestamp': self.config.get('snapshots', {}).get('show_timestamp', True)
|
|
||||||
}
|
|
||||||
self.regions = self.config['regions']
|
self.regions = self.config['regions']
|
||||||
if 'width' in self.config and 'height' in self.config:
|
self.frame_shape = get_frame_shape(self.ffmpeg_input)
|
||||||
self.frame_shape = (self.config['height'], self.config['width'], 3)
|
|
||||||
else:
|
|
||||||
self.frame_shape = get_frame_shape(self.ffmpeg_input)
|
|
||||||
self.frame_size = self.frame_shape[0] * self.frame_shape[1] * self.frame_shape[2]
|
self.frame_size = self.frame_shape[0] * self.frame_shape[1] * self.frame_shape[2]
|
||||||
self.mqtt_client = mqtt_client
|
self.mqtt_client = mqtt_client
|
||||||
self.mqtt_topic_prefix = '{}/{}'.format(mqtt_prefix, self.name)
|
self.mqtt_topic_prefix = '{}/{}'.format(mqtt_prefix, self.name)
|
||||||
|
|||||||
Reference in New Issue
Block a user