mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	update docs and add back benchmark
This commit is contained in:
		
							parent
							
								
									6ef22cf578
								
							
						
					
					
						commit
						e6892d66b8
					
				| @ -55,5 +55,6 @@ RUN wget -q https://storage.googleapis.com/download.tensorflow.org/models/tflite | ||||
| WORKDIR /opt/frigate/ | ||||
| ADD frigate frigate/ | ||||
| COPY detect_objects.py . | ||||
| COPY benchmark.py . | ||||
| 
 | ||||
| CMD ["python3.7", "-u", "detect_objects.py"] | ||||
|  | ||||
							
								
								
									
										76
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								README.md
									
									
									
									
									
								
							| @ -1,14 +1,13 @@ | ||||
| # Frigate - Realtime Object Detection for IP Cameras | ||||
| **Note:** This version requires the use of a [Google Coral USB Accelerator](https://coral.withgoogle.com/products/accelerator/) | ||||
| 
 | ||||
| Uses OpenCV and Tensorflow to perform realtime object detection locally for IP cameras. Designed for integration with HomeAssistant or others via MQTT. | ||||
| 
 | ||||
| - Leverages multiprocessing and threads heavily with an emphasis on realtime over processing every frame | ||||
| - Allows you to define specific regions (squares) in the image to look for objects | ||||
| - No motion detection (for now) | ||||
| - Object detection with Tensorflow runs in a separate thread | ||||
| Use of a [Google Coral USB Accelerator](https://coral.withgoogle.com/products/accelerator/) is optional, but highly recommended. On my Intel i7 processor, I can process 2-3 FPS with the CPU. The Coral can process 100+ FPS with very low CPU load. | ||||
| 
 | ||||
| - Leverages multiprocessing heavily with an emphasis on realtime over processing every frame | ||||
| - Uses a very low overhead motion detection to determine where to run object detection | ||||
| - Object detection with Tensorflow runs in a separate process | ||||
| - Object info is published over MQTT for integration into HomeAssistant as a binary sensor | ||||
| - An endpoint is available to view an MJPEG stream for debugging | ||||
| - An endpoint is available to view an MJPEG stream for debugging, but should not be used continuously | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| @ -22,12 +21,16 @@ Build the container with | ||||
| docker build -t frigate . | ||||
| ``` | ||||
| 
 | ||||
| The `mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite` model is included and used by default. You can use your own model and labels by mounting files in the container at `/frozen_inference_graph.pb` and `/label_map.pbtext`. Models must be compatible with the Coral according to [this](https://coral.withgoogle.com/models/). | ||||
| Models for both CPU and EdgeTPU (Coral) are bundled in the image. You can use your own models with volume mounts: | ||||
| - CPU Model: `/cpu_model.tflite` | ||||
| - EdgeTPU Model: `/edgetpu_model.tflite` | ||||
| - Labels: `/labelmap.txt` | ||||
| 
 | ||||
| Run the container with | ||||
| ``` | ||||
| ```bash | ||||
| docker run --rm \ | ||||
| --privileged \ | ||||
| --shm-size=512m \ # should work for a 2-3 cameras | ||||
| -v /dev/bus/usb:/dev/bus/usb \ | ||||
| -v <path_to_config_dir>:/config:ro \ | ||||
| -v /etc/localtime:/etc/localtime:ro \ | ||||
| @ -37,11 +40,12 @@ frigate:latest | ||||
| ``` | ||||
| 
 | ||||
| Example docker-compose: | ||||
| ``` | ||||
| ```yaml | ||||
|   frigate: | ||||
|     container_name: frigate | ||||
|     restart: unless-stopped | ||||
|     privileged: true | ||||
|     shm_size: '1g' # should work for 5-7 cameras | ||||
|     image: frigate:latest | ||||
|     volumes: | ||||
|       - /dev/bus/usb:/dev/bus/usb | ||||
| @ -57,6 +61,8 @@ A `config.yml` file must exist in the `config` directory. See example [here](con | ||||
| 
 | ||||
| Access the mjpeg stream at `http://localhost:5000/<camera_name>` and the best snapshot for any object type with at `http://localhost:5000/<camera_name>/<object_name>/best.jpg` | ||||
| 
 | ||||
| Debug info is available at `http://localhost:5000/debug/stats` | ||||
| 
 | ||||
| ## Integration with HomeAssistant | ||||
| ``` | ||||
| camera: | ||||
| @ -93,30 +99,34 @@ automation: | ||||
|             photo: | ||||
|               - url: http://<ip>:5000/<camera_name>/person/best.jpg | ||||
|                 caption: A person was detected. | ||||
| 
 | ||||
| sensor: | ||||
|   - platform: rest | ||||
|     name: Frigate Debug | ||||
|     resource: http://localhost:5000/debug/stats | ||||
|     scan_interval: 5 | ||||
|     json_attributes: | ||||
|       - back | ||||
|       - coral | ||||
|     value_template: 'OK'   | ||||
|   - platform: template | ||||
|     sensors: | ||||
|       back_fps:  | ||||
|         value_template: '{{ states.sensor.frigate_debug.attributes["back"]["fps"] }}' | ||||
|         unit_of_measurement: 'FPS' | ||||
|       back_skipped_fps:  | ||||
|         value_template: '{{ states.sensor.frigate_debug.attributes["back"]["skipped_fps"] }}' | ||||
|         unit_of_measurement: 'FPS' | ||||
|       back_detection_fps:  | ||||
|         value_template: '{{ states.sensor.frigate_debug.attributes["back"]["detection_fps"] }}' | ||||
|         unit_of_measurement: 'FPS' | ||||
|       frigate_coral_fps:  | ||||
|         value_template: '{{ states.sensor.frigate_debug.attributes["coral"]["fps"] }}' | ||||
|         unit_of_measurement: 'FPS' | ||||
|       frigate_coral_inference: | ||||
|         value_template: '{{ states.sensor.frigate_debug.attributes["coral"]["inference_speed"] }}'  | ||||
|         unit_of_measurement: 'ms' | ||||
| ``` | ||||
| 
 | ||||
| ## Tips | ||||
| - Lower the framerate of the video feed on the camera to reduce the CPU usage for capturing the feed | ||||
| 
 | ||||
| ## Future improvements | ||||
| - [x] Remove motion detection for now | ||||
| - [x] Try running object detection in a thread rather than a process | ||||
| - [x] Implement min person size again | ||||
| - [x] Switch to a config file | ||||
| - [x] Handle multiple cameras in the same container | ||||
| - [ ] Attempt to figure out coral symlinking | ||||
| - [ ] Add object list to config with min scores for mqtt | ||||
| - [ ] Move mjpeg encoding to a separate process | ||||
| - [ ] Simplify motion detection (check entire image against mask, resize instead of gaussian blur) | ||||
| - [ ] See if motion detection is even worth running | ||||
| - [ ] Scan for people across entire image rather than specfic regions | ||||
| - [ ] Dynamically resize detection area and follow people | ||||
| - [ ] Add ability to turn detection on and off via MQTT | ||||
| - [ ] Output movie clips of people for notifications, etc. | ||||
| - [ ] Integrate with homeassistant push camera | ||||
| - [ ] Merge bounding boxes that span multiple regions | ||||
| - [ ] Implement mode to save labeled objects for training | ||||
| - [ ] Try and reduce CPU usage by simplifying the tensorflow model to just include the objects we care about | ||||
| - [ ] Look into GPU accelerated decoding of RTSP stream | ||||
| - [ ] Send video over a socket and use JSMPEG | ||||
| - [x] Look into neural compute stick | ||||
|  | ||||
							
								
								
									
										20
									
								
								benchmark.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										20
									
								
								benchmark.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,20 +1,18 @@ | ||||
| import statistics | ||||
| import numpy as np | ||||
| from edgetpu.detection.engine import DetectionEngine | ||||
| import time | ||||
| from frigate.edgetpu import ObjectDetector | ||||
| 
 | ||||
| # Path to frozen detection graph. This is the actual model that is used for the object detection. | ||||
| PATH_TO_CKPT = '/frozen_inference_graph.pb' | ||||
| 
 | ||||
| # Load the edgetpu engine and labels | ||||
| engine = DetectionEngine(PATH_TO_CKPT) | ||||
| object_detector = ObjectDetector() | ||||
| 
 | ||||
| frame = np.zeros((300,300,3), np.uint8) | ||||
| flattened_frame = np.expand_dims(frame, axis=0).flatten() | ||||
| input_frame = np.expand_dims(frame, axis=0) | ||||
| 
 | ||||
| detection_times = [] | ||||
| 
 | ||||
| for x in range(0, 1000): | ||||
|     objects = engine.detect_with_input_tensor(flattened_frame, threshold=0.1, top_k=3) | ||||
|     detection_times.append(engine.get_inference_time()) | ||||
| for x in range(0, 100): | ||||
|     start = time.monotonic() | ||||
|     object_detector.detect_raw(input_frame) | ||||
|     detection_times.append(time.monotonic()-start) | ||||
| 
 | ||||
| print("Average inference time: " + str(statistics.mean(detection_times))) | ||||
| print(f"Average inference time: {statistics.mean(detection_times)*1000:.2f}ms") | ||||
| @ -39,8 +39,6 @@ mqtt: | ||||
| #     - -use_wallclock_as_timestamps | ||||
| #     - '1' | ||||
| #   output_args: | ||||
| #     - -vf | ||||
| #     - mpdecimate | ||||
| #     - -f | ||||
| #     - rawvideo | ||||
| #     - -pix_fmt | ||||
| @ -89,12 +87,15 @@ cameras: | ||||
|     # width: 720 | ||||
| 
 | ||||
|     ################ | ||||
|     ## Optional mask. Must be the same dimensions as your video feed. | ||||
|     ## Optional mask. Must be the same aspect ratio as your video feed. | ||||
|     ##  | ||||
|     ## The mask works by looking at the bottom center of the bounding box for the detected | ||||
|     ## person in the image. If that pixel in the mask is a black pixel, it ignores it as a | ||||
|     ## false positive. In my mask, the grass and driveway visible from my backdoor camera  | ||||
|     ## are white. The garage doors, sky, and trees (anywhere it would be impossible for a  | ||||
|     ## person to stand) are black. | ||||
|     ##  | ||||
|     ## Masked areas are also ignored for motion detection. | ||||
|     ################ | ||||
|     # mask: back-mask.bmp | ||||
| 
 | ||||
| @ -106,13 +107,14 @@ cameras: | ||||
|     take_frame: 1 | ||||
| 
 | ||||
|     ################ | ||||
|     # The number of seconds frigate will allow a camera to go without sending a frame before | ||||
|     # assuming the ffmpeg process has a problem and restarting. | ||||
|     # The expected framerate for the camera. Frigate will try and ensure it maintains this framerate | ||||
|     # by dropping frames as necessary. Setting this lower than the actual framerate will allow frigate | ||||
|     # to process every frame at the expense of realtime processing. | ||||
|     ################ | ||||
|     # watchdog_timeout: 300 | ||||
|     fps: 5 | ||||
| 
 | ||||
|     ################ | ||||
|     # Configuration for the snapshot sent over mqtt | ||||
|     # Configuration for the snapshots in the debug view and mqtt | ||||
|     ################ | ||||
|     snapshots: | ||||
|       show_timestamp: True | ||||
| @ -128,21 +130,3 @@ cameras: | ||||
|           min_area: 5000 | ||||
|           max_area: 100000 | ||||
|           threshold: 0.5 | ||||
|      | ||||
|     ################ | ||||
|     # size: size of the region in pixels | ||||
|     # x_offset/y_offset: position of the upper left corner of your region (top left of image is 0,0) | ||||
|     # Tips: All regions are resized to 300x300 before detection because the model is trained on that size. | ||||
|     #       Resizing regions takes CPU power. Ideally, all regions should be as close to 300x300 as possible. | ||||
|     #       Defining a region that goes outside the bounds of the image will result in errors. | ||||
|     ################ | ||||
|     regions: | ||||
|       - size: 350 | ||||
|         x_offset: 0 | ||||
|         y_offset: 300 | ||||
|       - size: 400 | ||||
|         x_offset: 350 | ||||
|         y_offset: 250 | ||||
|       - size: 400 | ||||
|         x_offset: 750 | ||||
|         y_offset: 250 | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								diagram.png
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								diagram.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 283 KiB After Width: | Height: | Size: 132 KiB | 
| @ -350,38 +350,3 @@ def track_camera(name, config, ffmpeg_global_config, global_objects_config, dete | ||||
|         plasma_client.put(frame, plasma.ObjectID(object_id)) | ||||
|         # add to the queue | ||||
|         detected_objects_queue.put((name, frame_time, object_tracker.tracked_objects)) | ||||
| 
 | ||||
|         # if (frames >= 700 and frames <= 1635) or (frames >= 2500): | ||||
|         # if (frames >= 300 and frames <= 600): | ||||
|         # if (frames >= 0): | ||||
|             # row1 = cv2.hconcat([gray, cv2.convertScaleAbs(avg_frame)]) | ||||
|             # row2 = cv2.hconcat([frameDelta, thresh]) | ||||
|             # cv2.imwrite(f"/lab/debug/output/{frames}.jpg", cv2.vconcat([row1, row2])) | ||||
|             # # cv2.imwrite(f"/lab/debug/output/resized-frame-{frames}.jpg", resized_frame) | ||||
|             # for region in motion_regions: | ||||
|             #     cv2.rectangle(frame, (region[0], region[1]), (region[2], region[3]), (255,128,0), 2) | ||||
|             # for region in object_regions: | ||||
|             #     cv2.rectangle(frame, (region[0], region[1]), (region[2], region[3]), (0,128,255), 2) | ||||
|             # for region in merged_regions: | ||||
|             #     cv2.rectangle(frame, (region[0], region[1]), (region[2], region[3]), (0,255,0), 2) | ||||
|             # for box in motion_boxes: | ||||
|             #     cv2.rectangle(frame, (box[0], box[1]), (box[2], box[3]), (255,0,0), 2) | ||||
|             # for detection in detections: | ||||
|             #     box = detection[2] | ||||
|             #     draw_box_with_label(frame, box[0], box[1], box[2], box[3], detection[0], f"{detection[1]*100}%") | ||||
|             # for obj in object_tracker.tracked_objects.values(): | ||||
|             #     box = obj['box'] | ||||
|             #     draw_box_with_label(frame, box[0], box[1], box[2], box[3], obj['label'], obj['id'], thickness=1, color=(0,0,255), position='bl') | ||||
|             # cv2.putText(frame, str(total_detections), (10, 10), cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.5, color=(0, 0, 0), thickness=2) | ||||
|             # cv2.putText(frame, str(frame_detections), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.5, color=(0, 0, 0), thickness=2) | ||||
|             # cv2.imwrite(f"/lab/debug/output/frame-{frames}.jpg", frame) | ||||
|             # break | ||||
| 
 | ||||
|     # start a thread to publish object scores | ||||
|     # mqtt_publisher = MqttObjectPublisher(self.mqtt_client, self.mqtt_topic_prefix, self) | ||||
|     # mqtt_publisher.start() | ||||
| 
 | ||||
|     # create a watchdog thread for capture process | ||||
|     # self.watchdog = CameraWatchdog(self) | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user