import numpy as np
import common . transformations . orientation as orient
from selfdrive . hardware import TICI
## -- hardcoded hardware params --
eon_f_focal_length = 910.0
eon_d_focal_length = 650.0
tici_f_focal_length = 2648.0
tici_e_focal_length = tici_d_focal_length = 567.0 # probably wrong? magnification is not consistent across frame
eon_f_frame_size = ( 1164 , 874 )
eon_d_frame_size = ( 816 , 612 )
tici_f_frame_size = tici_e_frame_size = tici_d_frame_size = ( 1928 , 1208 )
# aka 'K' aka camera_frame_from_view_frame
eon_fcam_intrinsics = np . array ( [
[ eon_f_focal_length , 0.0 , float ( eon_f_frame_size [ 0 ] ) / 2 ] ,
[ 0.0 , eon_f_focal_length , float ( eon_f_frame_size [ 1 ] ) / 2 ] ,
[ 0.0 , 0.0 , 1.0 ] ] )
eon_intrinsics = eon_fcam_intrinsics # xx
eon_dcam_intrinsics = np . array ( [
[ eon_d_focal_length , 0.0 , float ( eon_d_frame_size [ 0 ] ) / 2 ] ,
[ 0.0 , eon_d_focal_length , float ( eon_d_frame_size [ 1 ] ) / 2 ] ,
[ 0.0 , 0.0 , 1.0 ] ] )
tici_fcam_intrinsics = np . array ( [
[ tici_f_focal_length , 0.0 , float ( tici_f_frame_size [ 0 ] ) / 2 ] ,
[ 0.0 , tici_f_focal_length , float ( tici_f_frame_size [ 1 ] ) / 2 ] ,
[ 0.0 , 0.0 , 1.0 ] ] )
tici_dcam_intrinsics = np . array ( [
[ tici_d_focal_length , 0.0 , float ( tici_d_frame_size [ 0 ] ) / 2 ] ,
[ 0.0 , tici_d_focal_length , float ( tici_d_frame_size [ 1 ] ) / 2 ] ,
[ 0.0 , 0.0 , 1.0 ] ] )
tici_ecam_intrinsics = tici_dcam_intrinsics
# aka 'K_inv' aka view_frame_from_camera_frame
eon_fcam_intrinsics_inv = np . linalg . inv ( eon_fcam_intrinsics )
eon_intrinsics_inv = eon_fcam_intrinsics_inv # xx
tici_fcam_intrinsics_inv = np . linalg . inv ( tici_fcam_intrinsics )
tici_ecam_intrinsics_inv = np . linalg . inv ( tici_ecam_intrinsics )
if not TICI :
FULL_FRAME_SIZE = eon_f_frame_size
FOCAL = eon_f_focal_length
fcam_intrinsics = eon_fcam_intrinsics
else :
FULL_FRAME_SIZE = tici_f_frame_size
FOCAL = tici_f_focal_length
fcam_intrinsics = tici_fcam_intrinsics
W , H = FULL_FRAME_SIZE [ 0 ] , FULL_FRAME_SIZE [ 1 ]
# device/mesh : x->forward, y-> right, z->down
# view : x->right, y->down, z->forward
device_frame_from_view_frame = np . array ( [
[ 0. , 0. , 1. ] ,
[ 1. , 0. , 0. ] ,
[ 0. , 1. , 0. ]
] )
view_frame_from_device_frame = device_frame_from_view_frame . T
def get_calib_from_vp ( vp ) :
vp_norm = normalize ( vp )
yaw_calib = np . arctan ( vp_norm [ 0 ] )
pitch_calib = - np . arctan ( vp_norm [ 1 ] * np . cos ( yaw_calib ) )
roll_calib = 0
return roll_calib , pitch_calib , yaw_calib
# aka 'extrinsic_matrix'
# road : x->forward, y -> left, z->up
def get_view_frame_from_road_frame ( roll , pitch , yaw , height ) :
device_from_road = orient . rot_from_euler ( [ roll , pitch , yaw ] ) . dot ( np . diag ( [ 1 , - 1 , - 1 ] ) )
view_from_road = view_frame_from_device_frame . dot ( device_from_road )
return np . hstack ( ( view_from_road , [ [ 0 ] , [ height ] , [ 0 ] ] ) )
# aka 'extrinsic_matrix'
def get_view_frame_from_calib_frame ( roll , pitch , yaw , height ) :
device_from_calib = orient . rot_from_euler ( [ roll , pitch , yaw ] )
view_from_calib = view_frame_from_device_frame . dot ( device_from_calib )
return np . hstack ( ( view_from_calib , [ [ 0 ] , [ height ] , [ 0 ] ] ) )
def vp_from_ke ( m ) :
"""
Computes the vanishing point from the product of the intrinsic and extrinsic
matrices C = KE .
The vanishing point is defined as lim x - > infinity C ( x , 0 , 0 , 1 ) . T
"""
return ( m [ 0 , 0 ] / m [ 2 , 0 ] , m [ 1 , 0 ] / m [ 2 , 0 ] )
def vp_from_rpy ( rpy , intrinsics = fcam_intrinsics ) :
e = get_view_frame_from_road_frame ( rpy [ 0 ] , rpy [ 1 ] , rpy [ 2 ] , 1.22 )
ke = np . dot ( intrinsics , e )
return vp_from_ke ( ke )
def roll_from_ke ( m ) :
# note: different from calibration.h/RollAnglefromKE: i think that one's just wrong
return np . arctan2 ( - ( m [ 1 , 0 ] - m [ 1 , 1 ] * m [ 2 , 0 ] / m [ 2 , 1 ] ) ,
- ( m [ 0 , 0 ] - m [ 0 , 1 ] * m [ 2 , 0 ] / m [ 2 , 1 ] ) )
def normalize ( img_pts , intrinsics = fcam_intrinsics ) :
# normalizes image coordinates
# accepts single pt or array of pts
intrinsics_inv = np . linalg . inv ( intrinsics )
img_pts = np . array ( img_pts )
input_shape = img_pts . shape
img_pts = np . atleast_2d ( img_pts )
img_pts = np . hstack ( ( img_pts , np . ones ( ( img_pts . shape [ 0 ] , 1 ) ) ) )
img_pts_normalized = img_pts . dot ( intrinsics_inv . T )
img_pts_normalized [ ( img_pts < 0 ) . any ( axis = 1 ) ] = np . nan
return img_pts_normalized [ : , : 2 ] . reshape ( input_shape )
def denormalize ( img_pts , intrinsics = fcam_intrinsics , width = np . inf , height = np . inf ) :
# denormalizes image coordinates
# accepts single pt or array of pts
img_pts = np . array ( img_pts )
input_shape = img_pts . shape
img_pts = np . atleast_2d ( img_pts )
img_pts = np . hstack ( ( img_pts , np . ones ( ( img_pts . shape [ 0 ] , 1 ) , dtype = img_pts . dtype ) ) )
img_pts_denormalized = img_pts . dot ( intrinsics . T )
if np . isfinite ( width ) :
img_pts_denormalized [ img_pts_denormalized [ : , 0 ] > width ] = np . nan
img_pts_denormalized [ img_pts_denormalized [ : , 0 ] < 0 ] = np . nan
if np . isfinite ( height ) :
img_pts_denormalized [ img_pts_denormalized [ : , 1 ] > height ] = np . nan
img_pts_denormalized [ img_pts_denormalized [ : , 1 ] < 0 ] = np . nan
return img_pts_denormalized [ : , : 2 ] . reshape ( input_shape )
def device_from_ecef ( pos_ecef , orientation_ecef , pt_ecef ) :
# device from ecef frame
# device frame is x -> forward, y-> right, z -> down
# accepts single pt or array of pts
input_shape = pt_ecef . shape
pt_ecef = np . atleast_2d ( pt_ecef )
ecef_from_device_rot = orient . rotations_from_quats ( orientation_ecef )
device_from_ecef_rot = ecef_from_device_rot . T
pt_ecef_rel = pt_ecef - pos_ecef
pt_device = np . einsum ( ' jk,ik->ij ' , device_from_ecef_rot , pt_ecef_rel )
return pt_device . reshape ( input_shape )
def img_from_device ( pt_device ) :
# img coordinates from pts in device frame
# first transforms to view frame, then to img coords
# accepts single pt or array of pts
input_shape = pt_device . shape
pt_device = np . atleast_2d ( pt_device )
pt_view = np . einsum ( ' jk,ik->ij ' , view_frame_from_device_frame , pt_device )
# This function should never return negative depths
pt_view [ pt_view [ : , 2 ] < 0 ] = np . nan
pt_img = pt_view / pt_view [ : , 2 : 3 ]
return pt_img . reshape ( input_shape ) [ : , : 2 ]
def get_camera_frame_from_calib_frame ( camera_frame_from_road_frame , intrinsics = fcam_intrinsics ) :
camera_frame_from_ground = camera_frame_from_road_frame [ : , ( 0 , 1 , 3 ) ]
calib_frame_from_ground = np . dot ( intrinsics ,
get_view_frame_from_road_frame ( 0 , 0 , 0 , 1.22 ) ) [ : , ( 0 , 1 , 3 ) ]
ground_from_calib_frame = np . linalg . inv ( calib_frame_from_ground )
camera_frame_from_calib_frame = np . dot ( camera_frame_from_ground , ground_from_calib_frame )
return camera_frame_from_calib_frame