util.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import datetime
  2. import time
  3. import signal
  4. import traceback
  5. import collections
  6. import numpy as np
  7. import cv2
  8. import threading
  9. import matplotlib.pyplot as plt
  10. import hashlib
  11. import pyarrow.plasma as plasma
  12. def draw_box_with_label(frame, x_min, y_min, x_max, y_max, label, info, thickness=2, color=None, position='ul'):
  13. if color is None:
  14. color = (0,0,255)
  15. display_text = "{}: {}".format(label, info)
  16. cv2.rectangle(frame, (x_min, y_min), (x_max, y_max), color, thickness)
  17. font_scale = 0.5
  18. font = cv2.FONT_HERSHEY_SIMPLEX
  19. # get the width and height of the text box
  20. size = cv2.getTextSize(display_text, font, fontScale=font_scale, thickness=2)
  21. text_width = size[0][0]
  22. text_height = size[0][1]
  23. line_height = text_height + size[1]
  24. # set the text start position
  25. if position == 'ul':
  26. text_offset_x = x_min
  27. text_offset_y = 0 if y_min < line_height else y_min - (line_height+8)
  28. elif position == 'ur':
  29. text_offset_x = x_max - (text_width+8)
  30. text_offset_y = 0 if y_min < line_height else y_min - (line_height+8)
  31. elif position == 'bl':
  32. text_offset_x = x_min
  33. text_offset_y = y_max
  34. elif position == 'br':
  35. text_offset_x = x_max - (text_width+8)
  36. text_offset_y = y_max
  37. # make the coords of the box with a small padding of two pixels
  38. textbox_coords = ((text_offset_x, text_offset_y), (text_offset_x + text_width + 2, text_offset_y + line_height))
  39. cv2.rectangle(frame, textbox_coords[0], textbox_coords[1], color, cv2.FILLED)
  40. cv2.putText(frame, display_text, (text_offset_x, text_offset_y + line_height - 3), font, fontScale=font_scale, color=(0, 0, 0), thickness=2)
  41. def calculate_region(frame_shape, xmin, ymin, xmax, ymax, multiplier=2):
  42. # size is larger than longest edge
  43. size = int(max(xmax-xmin, ymax-ymin)*multiplier)
  44. # if the size is too big to fit in the frame
  45. if size > min(frame_shape[0], frame_shape[1]):
  46. size = min(frame_shape[0], frame_shape[1])
  47. # x_offset is midpoint of bounding box minus half the size
  48. x_offset = int((xmax-xmin)/2.0+xmin-size/2.0)
  49. # if outside the image
  50. if x_offset < 0:
  51. x_offset = 0
  52. elif x_offset > (frame_shape[1]-size):
  53. x_offset = (frame_shape[1]-size)
  54. # y_offset is midpoint of bounding box minus half the size
  55. y_offset = int((ymax-ymin)/2.0+ymin-size/2.0)
  56. # if outside the image
  57. if y_offset < 0:
  58. y_offset = 0
  59. elif y_offset > (frame_shape[0]-size):
  60. y_offset = (frame_shape[0]-size)
  61. return (x_offset, y_offset, x_offset+size, y_offset+size)
  62. def intersection(box_a, box_b):
  63. return (
  64. max(box_a[0], box_b[0]),
  65. max(box_a[1], box_b[1]),
  66. min(box_a[2], box_b[2]),
  67. min(box_a[3], box_b[3])
  68. )
  69. def area(box):
  70. return (box[2]-box[0] + 1)*(box[3]-box[1] + 1)
  71. def intersection_over_union(box_a, box_b):
  72. # determine the (x, y)-coordinates of the intersection rectangle
  73. intersect = intersection(box_a, box_b)
  74. # compute the area of intersection rectangle
  75. inter_area = max(0, intersect[2] - intersect[0] + 1) * max(0, intersect[3] - intersect[1] + 1)
  76. if inter_area == 0:
  77. return 0.0
  78. # compute the area of both the prediction and ground-truth
  79. # rectangles
  80. box_a_area = (box_a[2] - box_a[0] + 1) * (box_a[3] - box_a[1] + 1)
  81. box_b_area = (box_b[2] - box_b[0] + 1) * (box_b[3] - box_b[1] + 1)
  82. # compute the intersection over union by taking the intersection
  83. # area and dividing it by the sum of prediction + ground-truth
  84. # areas - the interesection area
  85. iou = inter_area / float(box_a_area + box_b_area - inter_area)
  86. # return the intersection over union value
  87. return iou
  88. def clipped(obj, frame_shape):
  89. # if the object is within 5 pixels of the region border, and the region is not on the edge
  90. # consider the object to be clipped
  91. box = obj[2]
  92. region = obj[4]
  93. if ((region[0] > 5 and box[0]-region[0] <= 5) or
  94. (region[1] > 5 and box[1]-region[1] <= 5) or
  95. (frame_shape[1]-region[2] > 5 and region[2]-box[2] <= 5) or
  96. (frame_shape[0]-region[3] > 5 and region[3]-box[3] <= 5)):
  97. return True
  98. else:
  99. return False
  100. class EventsPerSecond:
  101. def __init__(self, max_events=1000):
  102. self._start = None
  103. self._max_events = max_events
  104. self._timestamps = []
  105. def start(self):
  106. self._start = datetime.datetime.now().timestamp()
  107. def update(self):
  108. self._timestamps.append(datetime.datetime.now().timestamp())
  109. # truncate the list when it goes 100 over the max_size
  110. if len(self._timestamps) > self._max_events+100:
  111. self._timestamps = self._timestamps[(1-self._max_events):]
  112. def eps(self, last_n_seconds=10):
  113. # compute the (approximate) events in the last n seconds
  114. now = datetime.datetime.now().timestamp()
  115. seconds = min(now-self._start, last_n_seconds)
  116. return len([t for t in self._timestamps if t > (now-last_n_seconds)]) / seconds
  117. def print_stack(sig, frame):
  118. traceback.print_stack(frame)
  119. def listen():
  120. signal.signal(signal.SIGUSR1, print_stack)
  121. class PlasmaManager:
  122. def __init__(self, stop_event=None):
  123. self.stop_event = stop_event
  124. self.connect()
  125. def connect(self):
  126. while True:
  127. if self.stop_event != None and self.stop_event.is_set():
  128. return
  129. try:
  130. self.plasma_client = plasma.connect("/tmp/plasma")
  131. return
  132. except:
  133. print(f"TrackedObjectProcessor: unable to connect plasma client")
  134. time.sleep(10)
  135. def get(self, name, timeout_ms=0):
  136. object_id = plasma.ObjectID(hashlib.sha1(str.encode(name)).digest())
  137. while True:
  138. if self.stop_event != None and self.stop_event.is_set():
  139. return
  140. try:
  141. return self.plasma_client.get(object_id, timeout_ms=timeout_ms)
  142. except:
  143. self.connect()
  144. time.sleep(1)
  145. def put(self, name, obj):
  146. object_id = plasma.ObjectID(hashlib.sha1(str.encode(name)).digest())
  147. while True:
  148. if self.stop_event != None and self.stop_event.is_set():
  149. return
  150. try:
  151. self.plasma_client.put(obj, object_id)
  152. return
  153. except Exception as e:
  154. print(f"Failed to put in plasma: {e}")
  155. self.connect()
  156. time.sleep(1)
  157. def delete(self, name):
  158. object_id = plasma.ObjectID(hashlib.sha1(str.encode(name)).digest())
  159. while True:
  160. if self.stop_event != None and self.stop_event.is_set():
  161. return
  162. try:
  163. self.plasma_client.delete([object_id])
  164. return
  165. except:
  166. self.connect()
  167. time.sleep(1)