edgetpu.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import os
  2. import datetime
  3. import multiprocessing as mp
  4. import numpy as np
  5. import SharedArray as sa
  6. import tflite_runtime.interpreter as tflite
  7. from tflite_runtime.interpreter import load_delegate
  8. from frigate.util import EventsPerSecond
  9. def load_labels(path, encoding='utf-8'):
  10. """Loads labels from file (with or without index numbers).
  11. Args:
  12. path: path to label file.
  13. encoding: label file encoding.
  14. Returns:
  15. Dictionary mapping indices to labels.
  16. """
  17. with open(path, 'r', encoding=encoding) as f:
  18. lines = f.readlines()
  19. if not lines:
  20. return {}
  21. if lines[0].split(' ', maxsplit=1)[0].isdigit():
  22. pairs = [line.split(' ', maxsplit=1) for line in lines]
  23. return {int(index): label.strip() for index, label in pairs}
  24. else:
  25. return {index: line.strip() for index, line in enumerate(lines)}
  26. class ObjectDetector():
  27. def __init__(self, model_file):
  28. edge_tpu_delegate = None
  29. try:
  30. edge_tpu_delegate = load_delegate('libedgetpu.so.1.0')
  31. except ValueError:
  32. print("No EdgeTPU detected. Falling back to CPU.")
  33. if edge_tpu_delegate is None:
  34. self.interpreter = tflite.Interpreter(
  35. model_path=model_file)
  36. else:
  37. self.interpreter = tflite.Interpreter(
  38. model_path=model_file,
  39. experimental_delegates=[edge_tpu_delegate])
  40. self.interpreter.allocate_tensors()
  41. self.tensor_input_details = self.interpreter.get_input_details()
  42. self.tensor_output_details = self.interpreter.get_output_details()
  43. def detect_raw(self, tensor_input):
  44. self.interpreter.set_tensor(self.tensor_input_details[0]['index'], tensor_input)
  45. self.interpreter.invoke()
  46. boxes = np.squeeze(self.interpreter.get_tensor(self.tensor_output_details[0]['index']))
  47. label_codes = np.squeeze(self.interpreter.get_tensor(self.tensor_output_details[1]['index']))
  48. scores = np.squeeze(self.interpreter.get_tensor(self.tensor_output_details[2]['index']))
  49. detections = np.zeros((20,6), np.float32)
  50. for i, score in enumerate(scores):
  51. detections[i] = [label_codes[i], score, boxes[i][0], boxes[i][1], boxes[i][2], boxes[i][3]]
  52. return detections
  53. class EdgeTPUProcess():
  54. def __init__(self, model):
  55. # TODO: see if we can use the plasma store with a queue and maintain the same speeds
  56. try:
  57. sa.delete("frame")
  58. except:
  59. pass
  60. try:
  61. sa.delete("detections")
  62. except:
  63. pass
  64. self.input_frame = sa.create("frame", shape=(1,300,300,3), dtype=np.uint8)
  65. self.detections = sa.create("detections", shape=(20,6), dtype=np.float32)
  66. self.detect_lock = mp.Lock()
  67. self.detect_ready = mp.Event()
  68. self.frame_ready = mp.Event()
  69. self.fps = mp.Value('d', 0.0)
  70. self.avg_inference_speed = mp.Value('d', 10.0)
  71. def run_detector(model, detect_ready, frame_ready, fps, avg_speed):
  72. print(f"Starting detection process: {os.getpid()}")
  73. object_detector = ObjectDetector(model)
  74. input_frame = sa.attach("frame")
  75. detections = sa.attach("detections")
  76. fps_tracker = EventsPerSecond()
  77. fps_tracker.start()
  78. while True:
  79. # wait until a frame is ready
  80. frame_ready.wait()
  81. start = datetime.datetime.now().timestamp()
  82. # signal that the process is busy
  83. frame_ready.clear()
  84. detections[:] = object_detector.detect_raw(input_frame)
  85. # signal that the process is ready to detect
  86. detect_ready.set()
  87. fps_tracker.update()
  88. fps.value = fps_tracker.eps()
  89. duration = datetime.datetime.now().timestamp()-start
  90. avg_speed.value = (avg_speed.value*9 + duration)/10
  91. self.detect_process = mp.Process(target=run_detector, args=(model, self.detect_ready, self.frame_ready, self.fps, self.avg_inference_speed))
  92. self.detect_process.daemon = True
  93. self.detect_process.start()
  94. class RemoteObjectDetector():
  95. def __init__(self, labels, detect_lock, detect_ready, frame_ready):
  96. self.labels = load_labels(labels)
  97. self.input_frame = sa.attach("frame")
  98. self.detections = sa.attach("detections")
  99. self.detect_lock = detect_lock
  100. self.detect_ready = detect_ready
  101. self.frame_ready = frame_ready
  102. def detect(self, tensor_input, threshold=.4):
  103. detections = []
  104. with self.detect_lock:
  105. self.input_frame[:] = tensor_input
  106. # unset detections and signal that a frame is ready
  107. self.detect_ready.clear()
  108. self.frame_ready.set()
  109. # wait until the detection process is finished,
  110. self.detect_ready.wait()
  111. for d in self.detections:
  112. if d[1] < threshold:
  113. break
  114. detections.append((
  115. self.labels[int(d[0])],
  116. float(d[1]),
  117. (d[2], d[3], d[4], d[5])
  118. ))
  119. return detections