mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-31 11:06:35 +08:00 
			
		
		
		
	Compare commits
	
		
			29 Commits
		
	
	
		
			v0.7.1
			...
			v0.7.0-rc2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 45e9f84f6c | ||
|   | 20cff853e8 | ||
|   | d28d5e04a9 | ||
|   | 26f4e27df0 | ||
|   | 106d513e0b | ||
|   | 223ec76601 | ||
|   | 405837de22 | ||
|   | 51bd107536 | ||
|   | 08c43e7918 | ||
|   | 6f070502b5 | ||
|   | 61081b91a3 | ||
|   | 2a84d0afb9 | ||
|   | 2c17f27ab4 | ||
|   | 5bb9838c4f | ||
|   | d59018a14c | ||
|   | 5f2b8bb6ad | ||
|   | 6554640a61 | ||
|   | 5fbb092212 | ||
|   | dbb4ca7c87 | ||
|   | e506931830 | ||
|   | feaf63c15f | ||
|   | a94179be4d | ||
|   | 7837de8bc8 | ||
|   | 0366781728 | ||
|   | e898fca70a | ||
|   | d788ceb1d3 | ||
|   | 90a48fc761 | ||
|   | de57c79bf9 | ||
|   | af8c4e7eac | 
							
								
								
									
										32
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								Makefile
									
									
									
									
									
								
							| @@ -12,26 +12,26 @@ amd64_frigate: | |||||||
|  |  | ||||||
| amd64_all: amd64_wheels amd64_ffmpeg amd64_frigate | amd64_all: amd64_wheels amd64_ffmpeg amd64_frigate | ||||||
|  |  | ||||||
| aarch64_wheels: | arm64_wheels: | ||||||
| 	docker build --tag blakeblackshear/frigate-wheels:aarch64 --file docker/Dockerfile.wheels.aarch64 . | 	docker build --tag blakeblackshear/frigate-wheels:arm64 --file docker/Dockerfile.wheels.arm64 . | ||||||
|  |  | ||||||
| aarch64_ffmpeg: | arm64_ffmpeg: | ||||||
| 	docker build --tag blakeblackshear/frigate-ffmpeg:aarch64 --file docker/Dockerfile.ffmpeg.aarch64 . | 	docker build --tag blakeblackshear/frigate-ffmpeg:arm64 --file docker/Dockerfile.ffmpeg.arm64 . | ||||||
|  |  | ||||||
| aarch64_frigate: | arm64_frigate: | ||||||
| 	docker build --tag frigate-base --build-arg ARCH=aarch64 --file docker/Dockerfile.base . | 	docker build --tag frigate-base --build-arg ARCH=arm64 --file docker/Dockerfile.base . | ||||||
| 	docker build --tag frigate --file docker/Dockerfile.aarch64 . | 	docker build --tag frigate --file docker/Dockerfile.arm64 . | ||||||
|  |  | ||||||
| armv7_all: armv7_wheels armv7_ffmpeg armv7_frigate | armv7hf_all: arm64_wheels arm64_ffmpeg arm64_frigate | ||||||
|  |  | ||||||
| armv7_wheels: | armv7hf_wheels: | ||||||
| 	docker build --tag blakeblackshear/frigate-wheels:armv7 --file docker/Dockerfile.wheels . | 	docker build --tag blakeblackshear/frigate-wheels:armv7hf --file docker/Dockerfile.wheels . | ||||||
|  |  | ||||||
| armv7_ffmpeg: | armv7hf_ffmpeg: | ||||||
| 	docker build --tag blakeblackshear/frigate-ffmpeg:armv7 --file docker/Dockerfile.ffmpeg.armv7 . | 	docker build --tag blakeblackshear/frigate-ffmpeg:armv7hf --file docker/Dockerfile.ffmpeg.armv7hf . | ||||||
|  |  | ||||||
| armv7_frigate: | armv7hf_frigate: | ||||||
| 	docker build --tag frigate-base --build-arg ARCH=armv7 --file docker/Dockerfile.base . | 	docker build --tag frigate-base --build-arg ARCH=armv7hf --file docker/Dockerfile.base . | ||||||
| 	docker build --tag frigate --file docker/Dockerfile.armv7 . | 	docker build --tag frigate --file docker/Dockerfile.armv7hf . | ||||||
|  |  | ||||||
| armv7_all: armv7_wheels armv7_ffmpeg armv7_frigate | armv7hf_all: armv7hf_wheels armv7hf_ffmpeg armv7hf_frigate | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ docker run --rm \ | |||||||
| -v /etc/localtime:/etc/localtime:ro \ | -v /etc/localtime:/etc/localtime:ro \ | ||||||
| -p 5000:5000 \ | -p 5000:5000 \ | ||||||
| -e FRIGATE_RTSP_PASSWORD='password' \ | -e FRIGATE_RTSP_PASSWORD='password' \ | ||||||
| blakeblackshear/frigate:0.7.0-amd64 | blakeblackshear/frigate:stable | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Example docker-compose: | Example docker-compose: | ||||||
| @@ -41,7 +41,7 @@ Example docker-compose: | |||||||
|     restart: unless-stopped |     restart: unless-stopped | ||||||
|     privileged: true |     privileged: true | ||||||
|     shm_size: '100m' # only needed with large numbers of high res cameras |     shm_size: '100m' # only needed with large numbers of high res cameras | ||||||
|     image: blakeblackshear/frigate:0.7.0-amd64 |     image: blakeblackshear/frigate:stable | ||||||
|     volumes: |     volumes: | ||||||
|       - /dev/bus/usb:/dev/bus/usb |       - /dev/bus/usb:/dev/bus/usb | ||||||
|       - /etc/localtime:/etc/localtime:ro |       - /etc/localtime:/etc/localtime:ro | ||||||
|   | |||||||
| @@ -31,8 +31,6 @@ save_clips: | |||||||
|   # will begin to expire and the resulting clip will be the last x seconds of the event. |   # will begin to expire and the resulting clip will be the last x seconds of the event. | ||||||
|   ########### |   ########### | ||||||
|   max_seconds: 300 |   max_seconds: 300 | ||||||
|   clips_dir: /clips |  | ||||||
|   cache_dir: /cache |  | ||||||
|  |  | ||||||
| ################# | ################# | ||||||
| # Default ffmpeg args. Optional and can be overwritten per camera. | # Default ffmpeg args. Optional and can be overwritten per camera. | ||||||
| @@ -217,7 +215,6 @@ cameras: | |||||||
|     snapshots: |     snapshots: | ||||||
|       show_timestamp: True |       show_timestamp: True | ||||||
|       draw_zones: False |       draw_zones: False | ||||||
|       draw_bounding_boxes: True |  | ||||||
|  |  | ||||||
|     ################ |     ################ | ||||||
|     # Camera level object config. If defined, this is used instead of the global config. |     # Camera level object config. If defined, this is used instead of the global config. | ||||||
|   | |||||||
| @@ -9,7 +9,6 @@ import time | |||||||
| import datetime | import datetime | ||||||
| import queue | import queue | ||||||
| import yaml | import yaml | ||||||
| import json |  | ||||||
| import threading | import threading | ||||||
| import multiprocessing as mp | import multiprocessing as mp | ||||||
| import subprocess as sp | import subprocess as sp | ||||||
| @@ -26,22 +25,8 @@ from frigate.edgetpu import EdgeTPUProcess | |||||||
|  |  | ||||||
| FRIGATE_VARS = {k: v for k, v in os.environ.items() if k.startswith('FRIGATE_')} | FRIGATE_VARS = {k: v for k, v in os.environ.items() if k.startswith('FRIGATE_')} | ||||||
|  |  | ||||||
| CONFIG_FILE = os.environ.get('CONFIG_FILE', '/config/config.yml') | with open('/config/config.yml') as f: | ||||||
|  |     CONFIG = yaml.safe_load(f) | ||||||
| if CONFIG_FILE.endswith(".yml"): |  | ||||||
|     with open(CONFIG_FILE) as f: |  | ||||||
|         CONFIG = yaml.safe_load(f) |  | ||||||
| elif CONFIG_FILE.endswith(".json"): |  | ||||||
|     with open(CONFIG_FILE) as f: |  | ||||||
|         CONFIG = json.load(f) |  | ||||||
|  |  | ||||||
| CACHE_DIR = CONFIG.get('save_clips', {}).get('cache_dir', '/cache') |  | ||||||
| CLIPS_DIR = CONFIG.get('save_clips', {}).get('clips_dir', '/clips') |  | ||||||
|  |  | ||||||
| if not os.path.exists(CACHE_DIR) and not os.path.islink(CACHE_DIR): |  | ||||||
|     os.makedirs(CACHE_DIR) |  | ||||||
| if not os.path.exists(CLIPS_DIR) and not os.path.islink(CLIPS_DIR): |  | ||||||
|     os.makedirs(CLIPS_DIR) |  | ||||||
|  |  | ||||||
| MQTT_HOST = CONFIG['mqtt']['host'] | MQTT_HOST = CONFIG['mqtt']['host'] | ||||||
| MQTT_PORT = CONFIG.get('mqtt', {}).get('port', 1883) | MQTT_PORT = CONFIG.get('mqtt', {}).get('port', 1883) | ||||||
| @@ -179,8 +164,7 @@ def main(): | |||||||
|     for name, config in CONFIG['cameras'].items(): |     for name, config in CONFIG['cameras'].items(): | ||||||
|         config['snapshots'] = { |         config['snapshots'] = { | ||||||
|             'show_timestamp': config.get('snapshots', {}).get('show_timestamp', True), |             'show_timestamp': config.get('snapshots', {}).get('show_timestamp', True), | ||||||
|             'draw_zones': config.get('snapshots', {}).get('draw_zones', False), |             'draw_zones': config.get('snapshots', {}).get('draw_zones', False) | ||||||
|             'draw_bounding_boxes': config.get('snapshots', {}).get('draw_bounding_boxes', True) |  | ||||||
|         } |         } | ||||||
|         config['zones'] = config.get('zones', {}) |         config['zones'] = config.get('zones', {}) | ||||||
|  |  | ||||||
| @@ -238,7 +222,7 @@ def main(): | |||||||
|                 "-an", |                 "-an", | ||||||
|                 "-map", |                 "-map", | ||||||
|                 "0", |                 "0", | ||||||
|                 f"{os.path.join(CACHE_DIR, name)}-%Y%m%d%H%M%S.mp4" |                 f"/cache/{name}-%Y%m%d%H%M%S.mp4" | ||||||
|             ] + ffmpeg_output_args |             ] + ffmpeg_output_args | ||||||
|         ffmpeg_cmd = (['ffmpeg'] + |         ffmpeg_cmd = (['ffmpeg'] + | ||||||
|                 ffmpeg_global_args + |                 ffmpeg_global_args + | ||||||
| @@ -304,7 +288,7 @@ def main(): | |||||||
|         camera_process['process'].start() |         camera_process['process'].start() | ||||||
|         print(f"Camera_process started for {name}: {camera_process['process'].pid}") |         print(f"Camera_process started for {name}: {camera_process['process'].pid}") | ||||||
|  |  | ||||||
|     event_processor = EventProcessor(CONFIG, camera_processes, CACHE_DIR, CLIPS_DIR, event_queue, stop_event) |     event_processor = EventProcessor(CONFIG, camera_processes, '/cache', '/clips', event_queue, stop_event) | ||||||
|     event_processor.start() |     event_processor.start() | ||||||
|      |      | ||||||
|     object_processor = TrackedObjectProcessor(CONFIG['cameras'], client, MQTT_TOPIC_PREFIX, tracked_objects_queue, event_queue, stop_event) |     object_processor = TrackedObjectProcessor(CONFIG['cameras'], client, MQTT_TOPIC_PREFIX, tracked_objects_queue, event_queue, stop_event) | ||||||
| @@ -328,7 +312,7 @@ def main(): | |||||||
|                 shm.close() |                 shm.close() | ||||||
|                 shm.unlink() |                 shm.unlink() | ||||||
|  |  | ||||||
|         for detector in detectors.values(): |         for detector in detectors: | ||||||
|             detector.stop() |             detector.stop() | ||||||
|         for shm in camera_shms: |         for shm in camera_shms: | ||||||
|             shm.close() |             shm.close() | ||||||
| @@ -404,11 +388,9 @@ def main(): | |||||||
|     def best(camera_name, label): |     def best(camera_name, label): | ||||||
|         if camera_name in CONFIG['cameras']: |         if camera_name in CONFIG['cameras']: | ||||||
|             best_object = object_processor.get_best(camera_name, label) |             best_object = object_processor.get_best(camera_name, label) | ||||||
|             best_frame = best_object.get('frame') |             best_frame = best_object.get('frame', np.zeros((720,1280,3), np.uint8)) | ||||||
|             if best_frame is None: |  | ||||||
|                 best_frame = np.zeros((720,1280,3), np.uint8) |             best_frame = cv2.cvtColor(best_frame, cv2.COLOR_YUV2BGR_I420) | ||||||
|             else: |  | ||||||
|                 best_frame = cv2.cvtColor(best_frame, cv2.COLOR_YUV2BGR_I420) |  | ||||||
|              |              | ||||||
|             crop = bool(request.args.get('crop', 0, type=int)) |             crop = bool(request.args.get('crop', 0, type=int)) | ||||||
|             if crop: |             if crop: | ||||||
|   | |||||||
| @@ -181,12 +181,10 @@ class CameraState(): | |||||||
|             # check each zone |             # check each zone | ||||||
|             for name, zone in self.config['zones'].items(): |             for name, zone in self.config['zones'].items(): | ||||||
|                 contour = zone['contour'] |                 contour = zone['contour'] | ||||||
|                 # check if the object is in the zone |                 # check if the object is in the zone and not filtered | ||||||
|                 if (cv2.pointPolygonTest(contour, bottom_center, False) >= 0): |                 if (cv2.pointPolygonTest(contour, bottom_center, False) >= 0  | ||||||
|                     # if the object passed the filters once, dont apply again |                     and not zone_filtered(obj, zone.get('filters', {}))): | ||||||
|                     if name in obj.get('zones', []) or not zone_filtered(obj, zone.get('filters', {})): |                     current_zones.append(name) | ||||||
|                         current_zones.append(name) |  | ||||||
|                      |  | ||||||
|             obj['zones'] = current_zones |             obj['zones'] = current_zones | ||||||
|  |  | ||||||
|         # maintain best objects |         # maintain best objects | ||||||
| @@ -268,14 +266,7 @@ class TrackedObjectProcessor(threading.Thread): | |||||||
|         def snapshot(camera, obj): |         def snapshot(camera, obj): | ||||||
|             if not 'frame' in obj: |             if not 'frame' in obj: | ||||||
|                 return |                 return | ||||||
|              |  | ||||||
|             best_frame = cv2.cvtColor(obj['frame'], cv2.COLOR_YUV2BGR_I420) |             best_frame = cv2.cvtColor(obj['frame'], cv2.COLOR_YUV2BGR_I420) | ||||||
|             if self.camera_config[camera]['snapshots']['draw_bounding_boxes']: |  | ||||||
|                 thickness = 2 |  | ||||||
|                 color = COLOR_MAP[obj['label']] |  | ||||||
|                 box = obj['box'] |  | ||||||
|                 draw_box_with_label(best_frame, box[0], box[1], box[2], box[3], obj['label'], f"{int(obj['score']*100)}% {int(obj['area'])}", thickness=thickness, color=color) |  | ||||||
|                  |  | ||||||
|             mqtt_config = self.camera_config[camera].get('mqtt', {'crop_to_region': False}) |             mqtt_config = self.camera_config[camera].get('mqtt', {'crop_to_region': False}) | ||||||
|             if mqtt_config.get('crop_to_region'): |             if mqtt_config.get('crop_to_region'): | ||||||
|                 region = obj['region'] |                 region = obj['region'] | ||||||
| @@ -284,16 +275,6 @@ class TrackedObjectProcessor(threading.Thread): | |||||||
|                 height = int(mqtt_config['snapshot_height']) |                 height = int(mqtt_config['snapshot_height']) | ||||||
|                 width = int(height*best_frame.shape[1]/best_frame.shape[0]) |                 width = int(height*best_frame.shape[1]/best_frame.shape[0]) | ||||||
|                 best_frame = cv2.resize(best_frame, dsize=(width, height), interpolation=cv2.INTER_AREA) |                 best_frame = cv2.resize(best_frame, dsize=(width, height), interpolation=cv2.INTER_AREA) | ||||||
|              |  | ||||||
|             if self.camera_config[camera]['snapshots']['show_timestamp']: |  | ||||||
|                 time_to_show = datetime.datetime.fromtimestamp(obj['frame_time']).strftime("%m/%d/%Y %H:%M:%S") |  | ||||||
|                 size = cv2.getTextSize(time_to_show, cv2.FONT_HERSHEY_SIMPLEX, fontScale=1, thickness=2) |  | ||||||
|                 text_width = size[0][0] |  | ||||||
|                 text_height = size[0][1] |  | ||||||
|                 desired_size = max(200, 0.33*best_frame.shape[1]) |  | ||||||
|                 font_scale = desired_size/text_width |  | ||||||
|                 cv2.putText(best_frame, time_to_show, (5, best_frame.shape[0]-7), cv2.FONT_HERSHEY_SIMPLEX, fontScale=font_scale, color=(255, 255, 255), thickness=2) |  | ||||||
|  |  | ||||||
|             ret, jpg = cv2.imencode('.jpg', best_frame) |             ret, jpg = cv2.imencode('.jpg', best_frame) | ||||||
|             if ret: |             if ret: | ||||||
|                 jpg_bytes = jpg.tobytes() |                 jpg_bytes = jpg.tobytes() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user