U
    h0                     @   s   d Z ddlmZ ddlmZ ddlmZ ddlZddlZddlmZm	Z	 dd Z
d	d
 Zdd Zdd Zdd Zd'ddZdd Zd(ddZd)ddZdd Zdd  Zd!d" Zd#d$ Zd%d& ZdS )*a[  
Functions about transforming mesh(changing the position: modify vertices).
1. forward: transform(transform, camera, project).
2. backward: estimate transform matrix from correspondences.

Preparation knowledge:
transform&camera model:
https://cs184.eecs.berkeley.edu/lecture/transforms-2
Part I: camera geometry and single view geometry in MVGCV
    )absolute_import)division)print_functionN)cossinc                 C   s   t | d t | d t | d   }}}t dddgdt|t| gdt|t|gg}t t|dt|gdddgt| dt|gg}t t|t| dgt|t|dgdddgg}|||}|t jS )a7   get rotation matrix from three rotation angles(degree). right-handed.
    Args:
        angles: [3,]. x, y, z angles
        x: pitch. positive for looking down.
        y: yaw. positive for looking left. 
        z: roll. positive for tilting head right. 
    Returns:
        R: [3, 3]. rotation matrix.
    r         )npdeg2radarrayr   r   dotastypefloat32anglesxyzZRxZRyZRzR r   V/tmp/pip-unpacked-wheel-5oclok7i/insightface/thirdparty/face3d/mesh_numpy/transform.pyangle2matrix   s    
.r   c                 C   s   | d | d | d   }}}t dddgdt|t|gdt| t|gg}t t|dt| gdddgt|dt|gg}t t|t|dgt| t|dgdddgg}|||}|t jS )z get rotation matrix from three rotation angles(radian). The same as in 3DDFA.
    Args:
        angles: [3,]. x, y, z angles
        x: pitch.
        y: yaw. 
        z: roll. 
    Returns:
        R: 3x3. rotation matrix.
    r   r   r   )r	   r   r   r   r   r   r   r   r   r   r   angle2matrix_3ddfa/   s    r   c                 C   s   t |}| |j}|S )a?   rotate vertices. 
    X_new = R.dot(X). X: 3 x 1   
    Args:
        vertices: [nver, 3]. 
        rx, ry, rz: degree angles
        rx: pitch. positive for looking down 
        ry: yaw. positive for looking left
        rz: roll. positive for tilting head right
    Returns:
        rotated vertices: [nver, 3]
    )r   r   T)verticesr   r   Zrotated_verticesr   r   r   rotateN   s    r   c                 C   s<   t t j|t jd}|| |j |t jddf  }|S )a9   similarity transform. dof = 7.
    3D: s*R.dot(X) + t
    Homo: M = [[sR, t],[0^T, 1]].  M.dot(X)
    Args:(float32)
        vertices: [nver, 3]. 
        s: [1,]. scale factor.
        R: [3,3]. rotation matrix.
        t3d: [3,]. 3d translation vector.
    Returns:
        transformed vertices: [nver, 3]
    dtypeN)r	   Zsqueezer   r   r   r   newaxis)r   sr   Zt3dtransformed_verticesr   r   r   similarity_transform_   s    "r!   c                 C   s0   d}t t j| d dd}t ||}| | S )Ng-q=r   r   )Zaxis)r	   sqrtsummaximum)r   epsilonnormr   r   r   	normalizes   s    r'   c           	      C   s   |dkrt dddgt j}|dkr8t dddgt j}t |t j}t |t j}t||  }tt ||}t ||}t |||f}| | }||j}|S )a   'look at' transformation: from world space to camera space
    standard camera space: 
        camera located at the origin. 
        looking down negative z-axis. 
        vertical vector is y-axis.
    Xcam = R(X - C)
    Homo: [[R, -RC], [0, 1]]
    Args:
      vertices: [nver, 3] 
      eye: [3,] the XYZ world space position of the camera.
      at: [3,] a position along the center of the camera's gaze.
      up: [3,] up direction 
    Returns:
      transformed_vertices: [nver, 3]
    Nr   r   )	r	   r   r   r   r'   crossstackr   r   )	r   ZeyeatZupZz_aixsZx_aixsZy_axisr   r    r   r   r   lookat_cameray   s    r+   c                 C   s   |   S )a   scaled orthographic projection(just delete z)
        assumes: variations in depth over the object is small relative to the mean distance from camera to object
        x -> x*f/z, y -> x*f/z, z -> f.
        for point i,j. zi~=zj. so just delete z
        ** often used in face
        Homo: P = [[1,0,0,0], [0,1,0,0], [0,0,1,0]]
    Args:
        vertices: [nver, 3]
    Returns:
        projected_vertices: [nver, 3] if isKeepZ=True. [nver, 2] if isKeepZ=False.
    copy)r   r   r   r   orthographic_project   s    r.         ?皙?     @@c              
   C   s   t |}|t | }| }|| }| }t || dddgd|| ddgdd||  ||  d| | ||  gddddgg}	t | t | jd dff}
|
|	j}||ddddf  }|ddddf }|dddf  |dddf< |S )a:   perspective projection.
    Args:
        vertices: [nver, 3]
        fovy: vertical angular field of view. degree.
        aspect_ratio : width / height of field of view
        near : depth of near clipping plane
        far : depth of far clipping plane
    Returns:
        projected_vertices: [nver, 3] 
    r   r   N   r   )	r	   r
   tanr   hstackonesshaper   r   )r   ZfovyZaspect_ratioZnearZfartopZbottomrightleftPZvertices_homoZprojected_verticesr   r   r   perspective_project   s     
(
r=   Fc                 C   s   |   }|rT|dddf | d |dddf< |dddf | d |dddf< |dddf |d  |dddf< |dddf |d  |dddf< ||dddf  d |dddf< |S )a*   change vertices to image coord system
    3d system: XYZ, center(0, 0, 0)
    2d image: x(u), y(v). center(w/2, h/2), flip y-axis. 
    Args:
        vertices: [nver, 3]
        h: height of the rendering
        w : width of the rendering
    Returns:
        projected_vertices: [nver, 3]  
    Nr   r   r   r,   )r   hwZis_perspectiveZimage_verticesr   r   r   to_image   s    $$$$$r@   c                 C   s6   t | t | jd dgf}t j||d j}|S )z Using least-squares solution 
    Args:
        X: [n, 3]. 3d points(fixed)
        Y: [n, 3]. corresponding 3d points(moving). Y = PX
    Returns:
        P_Affine: (3, 4). Affine camera matrix (the third row is [0, 0, 0, 1]).
    r   r   )r	   r6   r7   r8   linalgZlstsqr   )XYX_homor<   r   r   r   estimate_affine_matrix_3d23d   s    rE   c                 C   s  | j } |j }|jd | jd ks$t|jd }|dks:tt|d}|t|ddtjf d|g }ttt|d d}td| }|| }tj	dtj
d}| |d< |d	< | | |dddf< d|d
< t| td|ff}t| d}| t|ddtjf d|g } |ddddf |  }ttt| d d}td| }||  } tj	dtj
d}	| |	d<  |	d	< |	d
< | | |	dddf< d|	d< tj	|d dftj
d}
t| td|ffj }||
d|ddf< ||
|dddf< t|ddg}tj|
|}tj	dtj
d}|dddf |dddf< |dddf |dddf< d|d< tj|||	}|S )a   Using Golden Standard Algorithm for estimating an affine camera
        matrix P from world to image correspondences.
        See Alg.7.2. in MVGCV 
        Code Ref: https://github.com/patrikhuber/eos/blob/master/include/eos/fitting/affine_camera_estimation.hpp
        x_homo = X_homo.dot(P_Affine)
    Args:
        X: [n, 3]. corresponding 3d points(fixed)
        x: [n, 2]. n>=4. 2d points(moving). x = PX
    Returns:
        P_Affine: [3, 4]. Affine camera matrix
    r      Nr   r   )r4   r4   r   r   r   r   r   r   r   r4   )rF   rF      r3   )r4   rF   )r3   r3   )r   r8   AssertionErrorr	   meanZtiler   r"   r#   zerosr   Zvstackr7   ZreshaperA   Zpinvr   inv)rB   r   nrL   Zaverage_normZscaler   rD   mUAbZp_8r<   ZP_Affiner   r   r   estimate_affine_matrix_3d22d   sJ     
""rT   c           	      C   s   | dddf }| ddddf }| ddddf }t j|t j| d }|t j| }|t j| }t ||}t |||fd}|||fS )z decompositing camera matrix P
    Args: 
        P: (3, 4). Affine Camera Matrix.
    Returns:
        s: scale factor.
        R: (3, 3). rotation matrix.
        t: (3,). translation. 
    Nr4   r   r   r   g       @)r	   rA   r&   r(   Zconcatenate)	r<   tZR1ZR2r   Zr1Zr2Zr3r   r   r   r   P2sRt/  s    	rV   c                 C   s>   t | }t || }t jd| jd}t j|| }|dk S )zN checks if a matrix is a valid rotation matrix(whether orthogonal or not)
    r4   r   ư>)r	   Z	transposer   identityr   rA   r&   )r   ZRtZshouldBeIdentityIrO   r   r   r   isRotationMatrixD  s
    
rZ   c           	      C   s   t stt| d | d  | d | d   }|dk }|svt| d | d }t| d  |}t| d | d }n,t| d  | d }t| d  |}d	}|d
 tj |d
 tj |d
 tj   }}}|||fS )z get three Euler angles from Rotation Matrix
    Args:
        R: (3,3). rotation matrix
    Returns:
        x: pitch
        y: yaw
        z: roll
    rG   )r   r   rW   )r   r   rI   )r   r   )r   r   rH   r      )rZ   rK   mathr"   atan2r	   pi)	r   ZsyZsingularr   r   r   rxZryZrzr   r   r   matrix2angleM  s    	&.r`   )NN)r/   r0   r1   )F)__doc__
__future__r   r   r   Znumpyr	   r\   r   r   r   r   r   r!   r'   r+   r.   r=   r@   rE   rT   rV   rZ   r`   r   r   r   r   <module>   s(   
"
#
>	