feat: show bitrate, fps, latency in tracking mode

This commit is contained in:
Sebastian Fitt 2023-04-29 15:48:29 +02:00
parent 2efa3c3589
commit 61637442c6
2 changed files with 63 additions and 37 deletions

View File

@ -53,6 +53,7 @@ class Camera:
self.last_frame_time = time.time() self.last_frame_time = time.time()
self.frame_number = 0 self.frame_number = 0
self.fps = 0 self.fps = 0
self.bps = 0
self.start = True self.start = True
self.buffer = b'' self.buffer = b''
@ -128,6 +129,7 @@ class Camera:
raise RuntimeError("Problem while getting frame") raise RuntimeError("Problem while getting frame")
frame_number = self.wired_camera.get(cv2.CAP_PROP_POS_FRAMES) frame_number = self.wired_camera.get(cv2.CAP_PROP_POS_FRAMES)
self.fps = self.wired_camera.get(cv2.CAP_PROP_FPS) self.fps = self.wired_camera.get(cv2.CAP_PROP_FPS)
self.bps = image.nbytes
if should_push: if should_push:
self.push_image_to_queue(image, frame_number, self.fps) self.push_image_to_queue(image, frame_number, self.fps)
except: except:
@ -156,10 +158,11 @@ class Camera:
return jpeg return jpeg
def get_serial_camera_picture(self, should_push): def get_serial_camera_picture(self, should_push):
if self.serial_connection is None: conn = self.serial_connection
if conn is None:
return return
try: try:
if self.serial_connection.in_waiting: if conn.in_waiting:
jpeg = self.get_next_jpeg_frame() jpeg = self.get_next_jpeg_frame()
if jpeg: if jpeg:
# Create jpeg frame from byte string # Create jpeg frame from byte string
@ -169,9 +172,9 @@ class Camera:
return return
# Discard the serial buffer. This is due to the fact that it # Discard the serial buffer. This is due to the fact that it
# may build up some outdated frames. A bit of a workaround here tbh. # may build up some outdated frames. A bit of a workaround here tbh.
if self.serial_connection.in_waiting > 32768: if conn.in_waiting >= 32768:
print(f"{Fore.CYAN}[INFO] Discarding the serial buffer ({self.serial_connection.in_waiting} bytes{Fore.RESET}") print(f"{Fore.CYAN}[INFO] Discarding the serial buffer ({conn.in_waiting} bytes){Fore.RESET}")
self.serial_connection.reset_input_buffer() conn.reset_input_buffer()
self.buffer = b'' self.buffer = b''
# Calculate the fps. # Calculate the fps.
current_frame_time = time.time() current_frame_time = time.time()
@ -179,13 +182,13 @@ class Camera:
self.last_frame_time = current_frame_time self.last_frame_time = current_frame_time
if delta_time > 0: if delta_time > 0:
self.fps = 1 / delta_time self.fps = 1 / delta_time
# print(f'FPS: {int(self.fps)}') self.bps = len(jpeg) / delta_time
self.frame_number = self.frame_number + 1 self.frame_number = self.frame_number + 1
if should_push: if should_push:
self.push_image_to_queue(image, self.frame_number, self.fps) self.push_image_to_queue(image, self.frame_number, self.fps)
except Exception: except Exception:
print(f"{Fore.YELLOW}[WARN] Serial capture source problem, assuming camera disconnected, waiting for reconnect.{Fore.RESET}") print(f"{Fore.YELLOW}[WARN] Serial capture source problem, assuming camera disconnected, waiting for reconnect.{Fore.RESET}")
self.serial_connection.close() conn.close()
self.camera_status = CameraState.DISCONNECTED self.camera_status = CameraState.DISCONNECTED
pass pass
@ -208,7 +211,7 @@ class Camera:
dsrdtr=False, dsrdtr=False,
rtscts=False) rtscts=False)
# Set explicit buffer size for serial. # Set explicit buffer size for serial.
conn.set_buffer_size(rx_size = 65536, tx_size = 65536) conn.set_buffer_size(rx_size = 32768, tx_size = 32768)
print(f"{Fore.CYAN}[INFO] ETVR Serial Tracker device connected on {port}{Fore.RESET}") print(f"{Fore.CYAN}[INFO] ETVR Serial Tracker device connected on {port}{Fore.RESET}")
self.serial_connection = conn self.serial_connection = conn

View File

@ -1,6 +1,7 @@
import PySimpleGUI as sg import PySimpleGUI as sg
from config import EyeTrackConfig from config import EyeTrackConfig
from config import EyeTrackSettingsConfig from config import EyeTrackSettingsConfig
from collections import deque
from threading import Event, Thread from threading import Event, Thread
from eye_processor import EyeProcessor, EyeInfoOrigin from eye_processor import EyeProcessor, EyeInfoOrigin
from enum import Enum from enum import Enum
@ -24,6 +25,8 @@ class CameraWidget:
self.gui_save_tracking_button = f"-SAVETRACKINGBUTTON{widget_id}-" self.gui_save_tracking_button = f"-SAVETRACKINGBUTTON{widget_id}-"
self.gui_tracking_layout = f"-TRACKINGLAYOUT{widget_id}-" self.gui_tracking_layout = f"-TRACKINGLAYOUT{widget_id}-"
self.gui_tracking_image = f"-IMAGE{widget_id}-" self.gui_tracking_image = f"-IMAGE{widget_id}-"
self.gui_tracking_fps = f"-TRACKINGFPS{widget_id}-"
self.gui_tracking_bps = f"-TRACKINGBPS{widget_id}-"
self.gui_output_graph = f"-OUTPUTGRAPH{widget_id}-" self.gui_output_graph = f"-OUTPUTGRAPH{widget_id}-"
self.gui_restart_calibration = f"-RESTARTCALIBRATION{widget_id}-" self.gui_restart_calibration = f"-RESTARTCALIBRATION{widget_id}-"
self.gui_stop_calibration = f"-STOPCALIBRATION{widget_id}-" self.gui_stop_calibration = f"-STOPCALIBRATION{widget_id}-"
@ -46,6 +49,35 @@ class CameraWidget:
else: else:
raise RuntimeError("\033[91m[WARN] Cannot have a camera widget represent both eyes!\033[0m") raise RuntimeError("\033[91m[WARN] Cannot have a camera widget represent both eyes!\033[0m")
self.cancellation_event = Event()
# Set the event until start is called, otherwise we can block if shutdown is called.
self.cancellation_event.set()
self.capture_event = Event()
self.capture_queue = Queue()
self.roi_queue = Queue()
self.image_queue = Queue()
self.ransac = EyeProcessor(
self.config,
self.settings_config,
self.cancellation_event,
self.capture_event,
self.capture_queue,
self.image_queue,
self.eye_id,
)
self.camera_status_queue = Queue()
self.camera = Camera(
self.config,
0,
self.cancellation_event,
self.capture_event,
self.camera_status_queue,
self.capture_queue,
)
self.roi_layout = [ self.roi_layout = [
[ [
sg.Graph( sg.Graph(
@ -82,6 +114,8 @@ class CameraWidget:
[ [
sg.Text("Mode:", background_color='#424042'), sg.Text("Mode:", background_color='#424042'),
sg.Text("Calibrating", key=self.gui_mode_readout, background_color='#424042'), sg.Text("Calibrating", key=self.gui_mode_readout, background_color='#424042'),
sg.Text("", key=self.gui_tracking_fps, background_color='#424042'),
sg.Text("", key=self.gui_tracking_bps, background_color='#424042'),
# sg.Checkbox( # sg.Checkbox(
# "Circle crop:", # "Circle crop:",
# default=self.config.gui_circular_crop, # default=self.config.gui_circular_crop,
@ -123,40 +157,23 @@ class CameraWidget:
], ],
] ]
self.cancellation_event = Event()
# Set the event until start is called, otherwise we can block if shutdown is called.
self.cancellation_event.set()
self.capture_event = Event()
self.capture_queue = Queue()
self.roi_queue = Queue()
self.image_queue = Queue()
self.ransac = EyeProcessor(
self.config,
self.settings_config,
self.cancellation_event,
self.capture_event,
self.capture_queue,
self.image_queue,
self.eye_id,
)
self.camera_status_queue = Queue()
self.camera = Camera(
self.config,
0,
self.cancellation_event,
self.capture_event,
self.camera_status_queue,
self.capture_queue,
)
self.x0, self.y0 = None, None self.x0, self.y0 = None, None
self.x1, self.y1 = None, None self.x1, self.y1 = None, None
self.figure = None self.figure = None
self.is_mouse_up = True self.is_mouse_up = True
self.in_roi_mode = False self.in_roi_mode = False
self.movavg_fps_queue = deque(maxlen=120)
self.movavg_bps_queue = deque(maxlen=120)
def _movavg_fps(self, next_fps):
self.movavg_fps_queue.append(next_fps)
fps = round(sum(self.movavg_fps_queue) / len(self.movavg_fps_queue))
millisec = round((1 / fps if fps else 0) * 1000)
return f"{fps} Fps {millisec} ms"
def _movavg_bps(self, next_bps):
self.movavg_bps_queue.append(next_bps)
return f"{sum(self.movavg_bps_queue) / len(self.movavg_bps_queue) * 0.001 * 0.001 * 8:.3f} Mbps"
def started(self): def started(self):
return not self.cancellation_event.is_set() return not self.cancellation_event.is_set()
@ -261,6 +278,10 @@ class CameraWidget:
needs_roi_set = self.config.roi_window_h <= 0 or self.config.roi_window_w <= 0 needs_roi_set = self.config.roi_window_h <= 0 or self.config.roi_window_w <= 0
# TODO: Refactor if statements below...
window[self.gui_tracking_fps].update('')
window[self.gui_tracking_bps].update('')
if self.config.capture_source is None or self.config.capture_source == "": if self.config.capture_source is None or self.config.capture_source == "":
window[self.gui_mode_readout].update("Waiting for camera address") window[self.gui_mode_readout].update("Waiting for camera address")
window[self.gui_roi_message].update(visible=False) window[self.gui_roi_message].update(visible=False)
@ -275,6 +296,8 @@ class CameraWidget:
window[self.gui_mode_readout].update("Calibration") window[self.gui_mode_readout].update("Calibration")
else: else:
window[self.gui_mode_readout].update("Tracking") window[self.gui_mode_readout].update("Tracking")
window[self.gui_tracking_fps].update(self._movavg_fps(self.camera.fps))
window[self.gui_tracking_bps].update(self._movavg_bps(self.camera.bps))
if self.in_roi_mode: if self.in_roi_mode:
try: try: