http.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import datetime
  2. import logging
  3. import os
  4. import time
  5. from functools import reduce
  6. import cv2
  7. import numpy as np
  8. from flask import (Blueprint, Flask, Response, current_app, jsonify,
  9. make_response, request)
  10. from peewee import SqliteDatabase, operator
  11. from playhouse.shortcuts import model_to_dict
  12. from frigate.models import Event
  13. bp = Blueprint('frigate', __name__)
  14. def create_app(frigate_config, database: SqliteDatabase, camera_metrics, detectors, detected_frames_processor):
  15. app = Flask(__name__)
  16. log = logging.getLogger('werkzeug')
  17. log.setLevel(logging.ERROR)
  18. @app.before_request
  19. def _db_connect():
  20. database.connect()
  21. @app.teardown_request
  22. def _db_close(exc):
  23. if not database.is_closed():
  24. database.close()
  25. app.frigate_config = frigate_config
  26. app.camera_metrics = camera_metrics
  27. app.detectors = detectors
  28. app.detected_frames_processor = detected_frames_processor
  29. app.register_blueprint(bp)
  30. return app
  31. @bp.route('/')
  32. def is_healthy():
  33. return "Frigate is running. Alive and healthy!"
  34. @bp.route('/events')
  35. def events():
  36. limit = request.args.get('limit', 100)
  37. camera = request.args.get('camera')
  38. label = request.args.get('label')
  39. zone = request.args.get('zone')
  40. after = request.args.get('after', type=int)
  41. before = request.args.get('before', type=int)
  42. clauses = []
  43. if camera:
  44. clauses.append((Event.camera == camera))
  45. if label:
  46. clauses.append((Event.label == label))
  47. if zone:
  48. clauses.append((Event.zones.cast('text') % f"*\"{zone}\"*"))
  49. if after:
  50. clauses.append((Event.start_time >= after))
  51. if before:
  52. clauses.append((Event.start_time <= before))
  53. if len(clauses) == 0:
  54. clauses.append((1 == 1))
  55. events = (Event.select()
  56. .where(reduce(operator.and_, clauses))
  57. .order_by(Event.start_time.desc())
  58. .limit(limit))
  59. return jsonify([model_to_dict(e) for e in events])
  60. @bp.route('/debug/stats')
  61. def stats():
  62. camera_metrics = current_app.camera_metrics
  63. stats = {}
  64. total_detection_fps = 0
  65. for name, camera_stats in camera_metrics.items():
  66. total_detection_fps += camera_stats['detection_fps'].value
  67. stats[name] = {
  68. 'camera_fps': round(camera_stats['camera_fps'].value, 2),
  69. 'process_fps': round(camera_stats['process_fps'].value, 2),
  70. 'skipped_fps': round(camera_stats['skipped_fps'].value, 2),
  71. 'detection_fps': round(camera_stats['detection_fps'].value, 2),
  72. 'pid': camera_stats['process'].pid,
  73. 'capture_pid': camera_stats['capture_process'].pid
  74. }
  75. stats['detectors'] = {}
  76. for name, detector in current_app.detectors.items():
  77. stats['detectors'][name] = {
  78. 'inference_speed': round(detector.avg_inference_speed.value*1000, 2),
  79. 'detection_start': detector.detection_start.value,
  80. 'pid': detector.detect_process.pid
  81. }
  82. stats['detection_fps'] = round(total_detection_fps, 2)
  83. return jsonify(stats)
  84. @bp.route('/<camera_name>/<label>/best.jpg')
  85. def best(camera_name, label):
  86. if camera_name in current_app.frigate_config.cameras:
  87. best_object = current_app.detected_frames_processor.get_best(camera_name, label)
  88. best_frame = best_object.get('frame')
  89. if best_frame is None:
  90. best_frame = np.zeros((720,1280,3), np.uint8)
  91. else:
  92. best_frame = cv2.cvtColor(best_frame, cv2.COLOR_YUV2BGR_I420)
  93. crop = bool(request.args.get('crop', 0, type=int))
  94. if crop:
  95. region = best_object.get('region', [0,0,300,300])
  96. best_frame = best_frame[region[1]:region[3], region[0]:region[2]]
  97. height = int(request.args.get('h', str(best_frame.shape[0])))
  98. width = int(height*best_frame.shape[1]/best_frame.shape[0])
  99. best_frame = cv2.resize(best_frame, dsize=(width, height), interpolation=cv2.INTER_AREA)
  100. ret, jpg = cv2.imencode('.jpg', best_frame)
  101. response = make_response(jpg.tobytes())
  102. response.headers['Content-Type'] = 'image/jpg'
  103. return response
  104. else:
  105. return "Camera named {} not found".format(camera_name), 404
  106. @bp.route('/<camera_name>')
  107. def mjpeg_feed(camera_name):
  108. fps = int(request.args.get('fps', '3'))
  109. height = int(request.args.get('h', '360'))
  110. if camera_name in current_app.frigate_config.cameras:
  111. # return a multipart response
  112. return Response(imagestream(current_app.detected_frames_processor, camera_name, fps, height),
  113. mimetype='multipart/x-mixed-replace; boundary=frame')
  114. else:
  115. return "Camera named {} not found".format(camera_name), 404
  116. @bp.route('/<camera_name>/latest.jpg')
  117. def latest_frame(camera_name):
  118. if camera_name in current_app.frigate_config.cameras:
  119. # max out at specified FPS
  120. frame = current_app.detected_frames_processor.get_current_frame(camera_name)
  121. if frame is None:
  122. frame = np.zeros((720,1280,3), np.uint8)
  123. height = int(request.args.get('h', str(frame.shape[0])))
  124. width = int(height*frame.shape[1]/frame.shape[0])
  125. frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_AREA)
  126. ret, jpg = cv2.imencode('.jpg', frame)
  127. response = make_response(jpg.tobytes())
  128. response.headers['Content-Type'] = 'image/jpg'
  129. return response
  130. else:
  131. return "Camera named {} not found".format(camera_name), 404
  132. def imagestream(detected_frames_processor, camera_name, fps, height):
  133. while True:
  134. # max out at specified FPS
  135. time.sleep(1/fps)
  136. frame = detected_frames_processor.get_current_frame(camera_name, draw=True)
  137. if frame is None:
  138. frame = np.zeros((height,int(height*16/9),3), np.uint8)
  139. width = int(height*frame.shape[1]/frame.shape[0])
  140. frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_LINEAR)
  141. ret, jpg = cv2.imencode('.jpg', frame)
  142. yield (b'--frame\r\n'
  143. b'Content-Type: image/jpeg\r\n\r\n' + jpg.tobytes() + b'\r\n\r\n')