Spaces:
Build error
Build error
| from threading import Thread | |
| from datetime import datetime | |
| import cv2 | |
| import uvicorn | |
| import contextlib | |
| import threading | |
| import time | |
| import requests | |
| class Server(uvicorn.Server): | |
| ''' | |
| Use this Server class to server a uvicorn in a separate thread, | |
| so to proceed to gradio UI launch | |
| https://github.com/encode/uvicorn/issues/742 | |
| A couple of other links for reference -- | |
| https://stackoverflow.com/questions/61577643/python-how-to-use-fastapi-and-uvicorn-run-without-blocking-the-thread | |
| https://stackoverflow.com/questions/76142431/how-to-run-another-application-within-the-same-running-event-loop/76148361#76148361 | |
| ''' | |
| def install_signal_handlers(self): | |
| pass | |
| def run_in_thread(self): | |
| thread = threading.Thread(target=self.run) | |
| thread.start() | |
| try: | |
| while not self.started: | |
| time.sleep(1e-3) | |
| yield | |
| finally: | |
| self.should_exit = True | |
| thread.join() | |
| class CountsPerSec: | |
| """ | |
| Class that tracks the number of occurrences ("counts") of an | |
| arbitrary event and returns the frequency in occurrences | |
| (counts) per second. The caller must increment the count. | |
| """ | |
| def __init__(self): | |
| self._start_time = None | |
| self._num_occurrences = 0 | |
| def start(self): | |
| self._start_time = datetime.now() | |
| return self | |
| def increment(self): | |
| self._num_occurrences += 1 | |
| def countsPerSec(self): | |
| elapsed_time = (datetime.now() - self._start_time).total_seconds() | |
| return self._num_occurrences / elapsed_time if elapsed_time > 0 else 0 | |
| class VideoGet: | |
| """ | |
| Class that continuously gets frames from a VideoCapture object | |
| with a dedicated thread. | |
| """ | |
| def __init__(self, src=0): | |
| self.stream = cv2.VideoCapture(src) | |
| (self.grabbed, self.frame) = self.stream.read() | |
| self.tn = Thread(target=self.get, args=()) | |
| self.stopped = False | |
| def start(self): | |
| self.tn.start() | |
| return self | |
| def get(self): | |
| while not self.stopped: | |
| if not self.grabbed: | |
| self.stop() | |
| else: | |
| (self.grabbed, self.frame) = self.stream.read() | |
| def stop(self): | |
| self.tn.join() | |
| self.stopped = True | |
| class VideoShow: | |
| """ | |
| Class that continuously shows a frame using a dedicated thread. | |
| """ | |
| def __init__(self, frame=None): | |
| self.frame = frame | |
| self.tn = Thread(target=self.show, args=()) | |
| self.stopped = False | |
| def start(self): | |
| self.tn.start() | |
| return self | |
| def show(self): | |
| while not self.stopped: | |
| cv2.imshow("Video", self.frame) | |
| if cv2.waitKey(1) == ord("q"): | |
| self.stopped = True | |
| def stop(self): | |
| self.tn.join() | |
| self.stopped = True | |
| def show_fps(frame, iterations_per_sec): | |
| """ | |
| Add iterations per second text to lower-left corner of a frame. | |
| """ | |
| cv2.putText( | |
| img=frame, | |
| text="{:.0f} fps".format(iterations_per_sec), | |
| org=(1000, 50), | |
| fontFace=cv2.FONT_HERSHEY_SIMPLEX, | |
| fontScale=0.8, | |
| color=(0, 255, 255), | |
| thickness=1, | |
| lineType=cv2.LINE_AA | |
| ) | |
| cv2.putText( | |
| img=frame, # annotated_frame, | |
| text=datetime.now().strftime("%m/%d/%Y %H:%M:%S"), | |
| org=(500, 50), | |
| fontFace=cv2.FONT_HERSHEY_SIMPLEX, | |
| fontScale=0.8, | |
| color=(0, 255, 255), | |
| thickness=1, | |
| lineType=cv2.LINE_AA | |
| ) | |
| return frame | |
| def draw_text( | |
| img, | |
| text, | |
| pos=(0, 0), | |
| font=cv2.FONT_HERSHEY_SIMPLEX, | |
| font_scale=1, | |
| font_thickness=2, | |
| line_type=cv2.LINE_AA, | |
| text_color=(0, 255, 0), | |
| text_color_bg=(0, 0, 0) | |
| ) -> None: | |
| """draw a text with background color on image frame | |
| Args: | |
| img (_type_): _description_ | |
| text (_type_): _description_ | |
| pos (tuple, optional): _description_. Defaults to (0, 0). | |
| font (_type_, optional): _description_. Defaults to cv2.FONT_HERSHEY_SIMPLEX. | |
| font_scale (int, optional): _description_. Defaults to 1. | |
| font_thickness (int, optional): _description_. Defaults to 2. | |
| line_type (_type_, optional): _description_. Defaults to cv2.LINE_AA. | |
| text_color (tuple, optional): _description_. Defaults to (0, 255, 0). | |
| text_color_bg (tuple, optional): _description_. Defaults to (0, 0, 0). | |
| Returns: | |
| _type_: _description_ | |
| """ | |
| x, y = pos | |
| text_size, _ = cv2.getTextSize(text, font, font_scale, font_thickness) | |
| text_w, text_h = text_size | |
| cv2.rectangle(img, (x, y + 10), (x + text_w, max(0, y - text_h - 10)), text_color_bg, -1) | |
| cv2.putText( | |
| img=img, | |
| text=text, | |
| org=pos, | |
| fontFace=font, | |
| fontScale=font_scale, | |
| color=text_color, | |
| thickness=font_thickness, | |
| lineType=line_type | |
| ) | |
| return text_size | |
| def try_site(youtube_url: str) -> bool: | |
| """Check if a youtube url is playable | |
| Args: | |
| youtube_url (str): a given url for testing | |
| Returns: | |
| bool: whether or not that youtube_url is playable | |
| """ | |
| pattern = '"playabilityStatus":{"status":"ERROR","reason":"Video unavailable"' | |
| request = requests.get(youtube_url) | |
| return False if pattern in request.text else True | |
| def make_table_from_dict(obj: dict, selected_key: str) -> list: | |
| table = [] | |
| for k, v in obj.items(): | |
| if k == selected_key: | |
| # print(k, v, selected_key) | |
| table.append({"name": k, "value": v, "selected": True}) | |
| else: | |
| table.append({"name": k, "value": v, "selected": False}) | |
| return table | |
| def make_table_from_dict_multiselect( | |
| obj: dict, selected_vals: list[int] | |
| ) -> list: | |
| table = [] | |
| for k, v in obj.items(): | |
| if v in selected_vals: | |
| # print(k, v, selected_key) | |
| table.append({"name": k, "value": v, "selected": True}) | |
| else: | |
| table.append({"name": k, "value": v, "selected": False}) | |
| return table | |