import numpy as np
import pyray as rl
from cereal import messaging
from openpilot . system . ui . widgets . cameraview import CameraView
from msgq . visionipc import VisionStreamType
from openpilot . system . ui . lib . application import gui_app , FontWeight
from openpilot . system . ui . lib . label import gui_label
from openpilot . system . ui . onroad . driver_state import DriverStateRenderer
class DriverCameraView ( CameraView ) :
def __init__ ( self , stream_type : VisionStreamType ) :
super ( ) . __init__ ( " camerad " , stream_type )
self . driver_state_renderer = DriverStateRenderer ( )
def render ( self , rect , sm ) :
super ( ) . render ( rect )
if not self . frame :
gui_label (
rect ,
" camera starting " ,
font_size = 100 ,
font_weight = FontWeight . BOLD ,
alignment = rl . GuiTextAlignment . TEXT_ALIGN_CENTER ,
)
return
self . _draw_face_detection ( rect , sm )
self . driver_state_renderer . draw ( rect , sm )
def _draw_face_detection ( self , rect : rl . Rectangle , sm ) - > None :
driver_state = sm [ " driverStateV2 " ]
is_rhd = driver_state . wheelOnRightProb > 0.5
driver_data = driver_state . rightDriverData if is_rhd else driver_state . leftDriverData
face_detect = driver_data . faceProb > 0.7
if not face_detect :
return
# Get face position and orientation
face_x , face_y = driver_data . facePosition
face_std = max ( driver_data . faceOrientationStd [ 0 ] , driver_data . faceOrientationStd [ 1 ] )
alpha = 0.7
if face_std > 0.15 :
alpha = max ( 0.7 - ( face_std - 0.15 ) * 3.5 , 0.0 )
# use approx instead of distort_points
# TODO: replace with distort_points
fbox_x = int ( 1080.0 - 1714.0 * face_x )
fbox_y = int ( - 135.0 + ( 504.0 + abs ( face_x ) * 112.0 ) + ( 1205.0 - abs ( face_x ) * 724.0 ) * face_y )
box_size = 220
line_color = rl . Color ( 255 , 255 , 255 , int ( alpha * 255 ) )
rl . draw_rectangle_rounded_lines_ex (
rl . Rectangle ( fbox_x - box_size / 2 , fbox_y - box_size / 2 , box_size , box_size ) ,
35.0 / box_size / 2 ,
10 ,
10 ,
line_color ,
)
def _calc_frame_matrix ( self , rect : rl . Rectangle ) - > np . ndarray :
driver_view_ratio = 2.0
# Get stream dimensions
if self . frame :
stream_width = self . frame . width
stream_height = self . frame . height
else :
# Default values if frame not available
stream_width = 1928
stream_height = 1208
yscale = stream_height * driver_view_ratio / stream_width
xscale = yscale * rect . height / rect . width * stream_width / stream_height
return np . array ( [
[ xscale , 0.0 , 0.0 ] ,
[ 0.0 , yscale , 0.0 ] ,
[ 0.0 , 0.0 , 1.0 ]
] )
if __name__ == " __main__ " :
gui_app . init_window ( " Driver Camera View " )
sm = messaging . SubMaster ( [ " selfdriveState " , " driverStateV2 " , " driverMonitoringState " ] )
driver_camera_view = DriverCameraView ( VisionStreamType . VISION_STREAM_DRIVER )
try :
for _ in gui_app . render ( ) :
sm . update ( )
driver_camera_view . render ( rl . Rectangle ( 0 , 0 , gui_app . width , gui_app . height ) , sm )
finally :
driver_camera_view . close ( )