o
    oizj                  	   @   s6  d dl mZmZmZ d dlZd dlmZmZmZm	Z	m
Z
 d dlmZ d dlmZmZ d dlmZmZ d dlmZ G dd	 d	ZG d
d deZd(dededefddZd(dededefddZdededefddZdedefddZdededefddZdeded edefd!d"Zd)d$ed%ededefd&d'ZdS )*    )IterableListUnionN)DeviceTensoreyestackzerosKORNIA_CHECK_SAME_DEVICE)convert_points_from_homogeneousconvert_points_to_homogeneous)inverse_transformationtransform_points)_torch_inverse_castc                   @   s  e Zd ZdZdededededdf
dd	Zed
ee defddZ	edede
defddZedede
defddZed
ee ddfddZdejfddZedefddZedefddZedefddZedefddZedefdd Zedefd!d"Zedefd#d$Zedefd%d&Zejd'eeef dd fd(d&Zedefd)d*Zejd'eeef dd fd+d*Zedefd,d-Zejd'eeef dd fd.d-Zedefd/d0Z edefd1d2Z!edefd3d4Z"edefd5d6Z#dSd7d8Z$defd9d:Z%d;edd fd<d=Z&d;eeef dd fd>d?Z'd@edefdAdBZ(dCedDedefdEdFZ)e*dGedHedIedJedededKedLedMedNedOe+dPej,dd fdQdRZ-dS )TPinholeCameraae  Class that represents a Pinhole Camera model.

    Args:
        intrinsics: tensor with shape :math:`(B, 4, 4)`
          containing the full 4x4 camera calibration matrix.
        extrinsics: tensor with shape :math:`(B, 4, 4)`
          containing the full 4x4 rotation-translation matrix.
        height: tensor with shape :math:`(B)` containing the image height.
        width: tensor with shape :math:`(B)` containing the image width.

    .. note::
        We assume that the class attributes are in batch form in order to take
        advantage of PyTorch parallelism to boost computing performance.

    
intrinsics
extrinsicsheightwidthreturnNc                 C   sp   |  ||||g | |d | |d | |d | |d | ||||g || _|| _|| _|| _d S )Nr   r   r   r   )_check_valid_check_valid_params_check_valid_shape_check_consistent_devicer   r   _intrinsics_extrinsics)selfr   r   r   r    r   R/home/ubuntu/.local/lib/python3.10/site-packages/kornia/geometry/camera/pinhole.py__init__.   s   
zPinholeCamera.__init__	data_iterc                 C   s   t dd | D stddS )Nc                 s   s    | ]}|j d  V  qdS )r   N)shape).0datar   r   r   	<genexpr>>   s    z-PinholeCamera._check_valid.<locals>.<genexpr>zArguments shapes must matchT)all
ValueError)r!   r   r   r   r   <   s   zPinholeCamera._check_validr$   	data_namec                 C   s:   t | jdvr| jdd  dkrtd| d| j dS )N)      r*   r*   	Argument z< shape must be in the following shape Bx4x4 or BxNx4x4. Got Tlenr"   r'   r$   r(   r   r   r   r   B   s
    z!PinholeCamera._check_valid_paramsc                 C   s(   t | jdkstd| d| j dS )N   r-   z- shape must be in the following shape B. Got Tr.   r0   r   r   r   r   J   s   z PinholeCamera._check_valid_shapec                 C   s    | d }| D ]}t || qd S )Nr   r
   )r!   firstr$   r   r   r   r   P   s   z&PinholeCamera._check_consistent_devicec                 C   s   | j jS )zYReturn the device for camera buffers.

        Returns:
            Device type

        )r   devicer   r   r   r   r3   V   s   zPinholeCamera.devicec                 C      |  | jds	t| jS )zjThe full 4x4 intrinsics matrix.

        Returns:
            tensor of shape :math:`(B, 4, 4)`.

        r   )r   r   AssertionErrorr4   r   r   r   r   _      zPinholeCamera.intrinsicsc                 C   r5   )zjThe full 4x4 extrinsics matrix.

        Returns:
            tensor of shape :math:`(B, 4, 4)`.

        r   )r   r   r6   r4   r   r   r   r   k   r7   zPinholeCamera.extrinsicsc                 C   s   | j jd S )ziReturn the batch size of the storage.

        Returns:
            scalar with the batch size.

        r   )r   r"   r4   r   r   r   
batch_sizew   s   zPinholeCamera.batch_sizec                 C   
   | j d S )zpReturn the focal length in the x-direction.

        Returns:
            tensor of shape :math:`(B)`.

        .r   r   r   r4   r   r   r   fx      
zPinholeCamera.fxc                 C   r9   )zpReturn the focal length in the y-direction.

        Returns:
            tensor of shape :math:`(B)`.

        .r1   r1   r;   r4   r   r   r   fy   r=   zPinholeCamera.fyc                 C   r9   )ztReturn the x-coordinate of the principal point.

        Returns:
            tensor of shape :math:`(B)`.

        .r      r;   r4   r   r   r   cx   r=   zPinholeCamera.cxc                 C   r9   )ztReturn the y-coordinate of the principal point.

        Returns:
            tensor of shape :math:`(B)`.

        .r1   rA   r;   r4   r   r   r   cy   r=   zPinholeCamera.cyc                 C   r9   )zwReturn the x-coordinate of the translation vector.

        Returns:
            tensor of shape :math:`(B)`.

        .r   r   r4   r   r   r   tx   r=   zPinholeCamera.txvaluec                 C      || j d< | S )zDSet the x-coordinate of the translation vector with the given value.rE   rG   r   rI   r   r   r   rH         
c                 C   r9   )zwReturn the y-coordinate of the translation vector.

        Returns:
            tensor of shape :math:`(B)`.

        .r1   rF   rG   r4   r   r   r   ty   r=   zPinholeCamera.tyc                 C   rJ   )DSet the y-coordinate of the translation vector with the given value.rM   rG   rK   r   r   r   rN      rL   c                 C   r9   )zxReturns the z-coordinate of the translation vector.

        Returns:
            tensor of shape :math:`(B)`.

        .rA   rF   rG   r4   r   r   r   tz   r=   zPinholeCamera.tzc                 C   rJ   )rO   rP   rG   rK   r   r   r   rQ      rL   c                 C   s   | j dddddf S )zvReturn the 3x4 rotation-translation matrix.

        Returns:
            tensor of shape :math:`(B, 3, 4)`.

        .Nr)   r*   rG   r4   r   r   r   	rt_matrix      zPinholeCamera.rt_matrixc                 C      | j dddddf S )zReturn the 3x3 camera matrix containing the intrinsics.

        Returns:
            tensor of shape :math:`(B, 3, 3)`.

        .Nr)   r;   r4   r   r   r   camera_matrix   rS   zPinholeCamera.camera_matrixc                 C   rT   )z~Return the 3x3 rotation matrix from the extrinsics.

        Returns:
            tensor of shape :math:`(B, 3, 3)`.

        .Nr)   rG   r4   r   r   r   rotation_matrix   rS   zPinholeCamera.rotation_matrixc                 C   s   | j dddddf S )z}Return the translation vector from the extrinsics.

        Returns:
            tensor of shape :math:`(B, 3, 1)`.

        .Nr)   rF   rG   r4   r   r   r   translation_vector   rS   z PinholeCamera.translation_vectorc                 C   s6   | j  }| j }| j }| j }t||||S )z2Return a deep copy of the current object instance.)r   cloner   r   r   r   )r   r   r   r   r   r   r   r   rX     s
   



zPinholeCamera.clonec                 C   s
   | j  S )z{Return the inverse of the 4x4 instrisics matrix.

        Returns:
            tensor of shape :math:`(B, 4, 4)`.

        )r   inverser4   r   r   r   intrinsics_inverse	  s   
z PinholeCamera.intrinsics_inversescale_factorc                 C   sv   | j  }|d  |9  < |d  |9  < |d  |9  < |d  |9  < || j  }|| j  }t|| j||S )a/  Scale the pinhole model.

        Args:
            scale_factor: a tensor with the scale factor. It has
              to be broadcastable with class members. The expected shape is
              :math:`(B)` or :math:`(1)`.

        Returns:
            the camera model with scaled parameters.

        r:   r>   r@   rC   )r   rX   r   r   r   r   )r   r[   r   r   r   r   r   r   scale  s   
zPinholeCamera.scalec                 C   sh   | j d  |9  < | j d  |9  < | j d  |9  < | j d  |9  < |  j|9  _|  j|9  _| S )a8  Scale the pinhole model in-place.

        Args:
            scale_factor: a tensor with the scale factor. It has
              to be broadcastable with class members. The expected shape is
              :math:`(B)` or :math:`(1)`.

        Returns:
            the camera model with scaled parameters.

        r:   r>   r@   rC   )r   r   r   )r   r[   r   r   r   scale_)  s   zPinholeCamera.scale_point_3dc                 C   s   | j | j }tt||S )a  Project a 3d point in world coordinates onto the 2d camera plane.

        Args:
            point_3d: tensor containing the 3d points to be projected
                to the camera plane. The shape of the tensor can be :math:`(*, 3)`.

        Returns:
            tensor of (u, v) cam coordinates with shape :math:`(*, 2)`.

        Example:
            >>> _ = torch.manual_seed(0)
            >>> X = torch.rand(1, 3)
            >>> K = torch.eye(4)[None]
            >>> E = torch.eye(4)[None]
            >>> h = torch.ones(1)
            >>> w = torch.ones(1)
            >>> pinhole = kornia.geometry.camera.PinholeCamera(K, E, h, w)
            >>> pinhole.project(X)
            tensor([[5.6088, 8.6827]])

        )r   r   r   r   )r   r^   Pr   r   r   project?  s   zPinholeCamera.projectpoint_2ddepthc                 C   s&   | j | j }t|}t|t|| S )a  Unproject a 2d point in 3d.

        Transform coordinates in the pixel frame to the world frame.

        Args:
            point_2d: tensor containing the 2d to be projected to
                world coordinates. The shape of the tensor can be :math:`(*, 2)`.
            depth: tensor containing the depth value of each 2d
                points. The tensor shape must be equal to point2d :math:`(*, 1)`.
            normalize: whether to normalize the pointcloud. This
                must be set to `True` when the depth is represented as the Euclidean
                ray length from the camera position.

        Returns:
            tensor of (x, y, z) world coordinates with shape :math:`(*, 3)`.

        Example:
            >>> _ = torch.manual_seed(0)
            >>> x = torch.rand(1, 2)
            >>> depth = torch.ones(1, 1)
            >>> K = torch.eye(4)[None]
            >>> E = torch.eye(4)[None]
            >>> h = torch.ones(1)
            >>> w = torch.ones(1)
            >>> pinhole = kornia.geometry.camera.PinholeCamera(K, E, h, w)
            >>> pinhole.unproject(x, depth)
            tensor([[0.4963, 0.7682, 1.0000]])

        )r   r   r   r   r   )r   ra   rb   r_   P_invr   r   r   	unprojectX  s   zPinholeCamera.unprojectr<   r?   rB   rD   rH   rN   rQ   r8   r3   dtypec                 C   s  t |
dd||d}|d  |7  < |d  |7  < |d  |7  < |d  |7  < |d  d7  < |d	  d7  < td||d|
d
d
}|d  |7  < |d  |7  < |d  |	7  < t |
||d}|d  |7  < t |
||d}|d  |7  < | ||||S )Nr*   r3   re   r:   r>   r@   rC   ).rA   rA         ?).r)   r)   r1   rE   rM   rP   .r   )r	   r   repeat)r   r<   r?   rB   rD   r   r   rH   rN   rQ   r8   r3   re   r   r   
height_tmp	width_tmpr   r   r   from_parameters{  s    zPinholeCamera.from_parameters)r   r   ).__name__
__module____qualname____doc__r   r    staticmethodr   boolr   strr   r   r   r   torchr3   propertyr   r   intr8   r<   r?   rB   rD   rH   setterr   floatrN   rQ   rR   rU   rV   rW   rX   rZ   r\   r]   r`   rd   classmethodr   re   rl   r   r   r   r   r      s    												
		#	
r   c                   @   s`   e Zd ZdZdee ddfddZdee dd fdd	Zede	fd
dZ
de	defddZdS )PinholeCamerasListam  Class that represents a list of pinhole cameras.

    The class inherits from :class:`~kornia.PinholeCamera` meaning that
    it will keep the same class properties but with an extra dimension.

    .. note::
        The underlying data tensor will be stacked in the first dimension.
        That's it, given a list of two camera instances, the intrinsics tensor
        will have a shape :math:`(B, N, 4, 4)` where :math:`B` is the batch
        size and :math:`N` is the numbers of cameras (in this case two).

    Args:
        pinholes_list: a python tuple or list containing a set of `PinholeCamera` instances.

    pinholes_listr   Nc                 C   s   |  | d S )N)_initialize_parameters)r   r{   r   r   r   r      s   zPinholeCamerasList.__init__pinholesc                 C   s   t |ttfstdt| g g }}g g }}|D ](}t |ts,tdt| ||j ||j ||j	 ||j
 qt|dd| _t|dd| _t|dd| _t|dd| _| S )z5Initialise the class attributes given a cameras list.z(pinhole must of type list or tuple. Got z6Argument pinhole must be from type PinholeCamera. Got r1   dim)
isinstancelisttuple	TypeErrortyper   appendr   r   r   r   r   r   r   )r   r}   r   r   r   r   pinholer   r   r   r|     s    


z)PinholeCamerasList._initialize_parametersc                 C   s"   d}| j durt| j jd }|S )z0Return the number of pinholes cameras per batch.rF   Nr1   )r   rv   r"   )r   num_camerasr   r   r   r     s   
zPinholeCamerasList.num_camerasidxc                 C   sN   | j d|f }| jd|f }| jdd|f }| jdd|f }t||||S )z<Return a PinholeCamera object with parameters such as Bx4x4..N)r   r   r   r   r   )r   r   r   r   r   r   r   r   r   get_pinhole  s
   zPinholeCamerasList.get_pinhole)rm   rn   ro   rp   r   r   r    r|   ru   rv   r   r   r   r   r   r   rz     s    rz   ư>r}   epsr   c                 C   s   t | jdkr| jd dkst| jtj| dddf ddd\}}}}td| j| jd| }|ddd	| jd	 dd}||dd	d	df< ||dd	dd
f< ||ddddf< ||dddd
f< |S )aL  Return the pinhole matrix from a pinhole model.

    .. note::
        This method is going to be deprecated in version 0.2 in favour of
        :attr:`kornia.PinholeCamera.camera_matrix`.

    Args:
        pinholes: tensor of pinhole models.
        eps: epsilon for numerical stability.

    Returns:
        tensor of pinhole matrices.

    Shape:
        - Input: :math:`(N, 12)`
        - Output: :math:`(N, 4, 4)`

    Example:
        >>> rng = torch.manual_seed(0)
        >>> pinhole = torch.rand(1, 12)    # Nx12
        >>> pinhole_matrix(pinhole)  # Nx4x4
        tensor([[[4.9626e-01, 1.0000e-06, 8.8477e-02, 1.0000e-06],
                 [1.0000e-06, 7.6822e-01, 1.3203e-01, 1.0000e-06],
                 [1.0000e-06, 1.0000e-06, 1.0000e+00, 1.0000e-06],
                 [1.0000e-06, 1.0000e-06, 1.0000e-06, 1.0000e+00]]])

    rA   r1      .Nr*   r~   rf   r   r)   
r/   r"   r6   rt   chunkr   r3   re   viewri   )r}   r   r<   r?   rB   rD   kr   r   r   pinhole_matrix  s   
$r   r   c                 C   s   t | jdkr| jd dkst| jtj| dddf ddd\}}}}td| j| jd}|ddd	| jd	 dd}d
||  |dd	d	df< d
||  |ddddf< d| ||  |dd	ddf< d| ||  |ddddf< |S )a<  Return the inverted pinhole matrix from a pinhole model.

    .. note::
        This method is going to be deprecated in version 0.2 in favour of
        :attr:`kornia.PinholeCamera.intrinsics_inverse()`.

    Args:
        pinhole: tensor with pinhole models.
        eps: epsilon for numerical stability.

    Returns:
        tensor of inverted pinhole matrices.

    Shape:
        - Input: :math:`(N, 12)`
        - Output: :math:`(N, 4, 4)`

    Example:
        >>> rng = torch.manual_seed(0)
        >>> pinhole = torch.rand(1, 12)  # Nx12
        >>> inverse_pinhole_matrix(pinhole)  # Nx4x4
        tensor([[[ 2.0151,  0.0000, -0.1783,  0.0000],
                 [ 0.0000,  1.3017, -0.1719,  0.0000],
                 [ 0.0000,  0.0000,  1.0000,  0.0000],
                 [ 0.0000,  0.0000,  0.0000,  1.0000]]])

    rA   r1   r   .Nr*   r~   rf   r   rg   g      r)   r   )r   r   r<   r?   rB   rD   r   r   r   r   inverse_pinhole_matrix  s   
$r   r\   c                 C   sp   t | jdkr| jd dkst| jt |jdkrt|j|  }| dddf |d |dddf< |S )a  Scale the pinhole matrix for each pinhole model.

    .. note::
        This method is going to be deprecated in version 0.2 in favour of
        :attr:`kornia.PinholeCamera.scale()`.

    Args:
        pinholes: tensor with the pinhole model.
        scale: tensor of scales.

    Returns:
        tensor of scaled pinholes.

    Shape:
        - Input: :math:`(N, 12)` and :math:`(N, 1)`
        - Output: :math:`(N, 12)`

    Example:
        >>> rng = torch.manual_seed(0)
        >>> pinhole_i = torch.rand(1, 12)  # Nx12
        >>> scales = 2.0 * torch.ones(1)   # N
        >>> scale_pinhole(pinhole_i, scales)  # Nx12
        tensor([[0.9925, 1.5364, 0.1770, 0.2641, 0.6148, 1.2682, 0.4901, 0.8964, 0.4556,
                 0.6323, 0.3489, 0.4017]])

    rA   r1   r   .N   rF   )r/   r"   r6   rX   	unsqueeze)r}   r\   pinholes_scaledr   r   r   scale_pinhole5  s   

&r   c                 C   s*   t | jdkr| jd dkst| jt)a  Compute extrinsic transformation matrices for pinholes.

    Args:
        pinholes: tensor of form [fx fy cx cy h w rx ry rz tx ty tz]
                           of size (N, 12).

    Returns:
        tensor of extrinsic transformation matrices of size (N, 4, 4).

    rA   r1   r   )r/   r"   r6   NotImplementedError)r}   r   r   r   get_optical_pose_base\  s   
r   	pinhole_ipinhole_refc                 C   sx   t | jdkr| jd dkst| j| j|jkrt|jt| }t|}t|t|}tt| t|t|S )a  Homography from reference to ith pinhole.

    .. note::
        The pinhole model is represented in a single vector as follows:

        .. math::
            pinhole = (f_x, f_y, c_x, c_y, height, width,
            r_x, r_y, r_z, t_x, t_y, t_z)

        where:
            :math:`(r_x, r_y, r_z)` is the rotation vector in angle-axis
            convention.

            :math:`(t_x, t_y, t_z)` is the translation vector.

    .. math::

        H_{ref}^{i} = K_{i} * T_{ref}^{i} * K_{ref}^{-1}

    Args:
        pinhole_i: tensor with pinhole model for ith frame.
        pinhole_ref: tensor with pinhole model for reference frame.

    Returns:
        tensors that convert depth points (u, v, d) from pinhole_ref to pinhole_i.

    Shape:
        - Input: :math:`(N, 12)` and :math:`(N, 12)`
        - Output: :math:`(N, 4, 4)`

    Example:
        pinhole_i = torch.rand(1, 12)    # Nx12
        pinhole_ref = torch.rand(1, 12)  # Nx12
        homography_i_H_ref(pinhole_i, pinhole_ref)  # Nx4x4

    rA   r1   r   )	r/   r"   r6   r   rt   matmulr   r   r   )r   r   i_pose_baseref_pose_base
i_pose_refr   r   r   homography_i_H_refr  s   &

r   rb   intrinsics_invpixel_coordsc                 C   s   t | jdks| jd dkrtd| j t |jdks%td|j t |jdks;|jd dkr;td|j t|dddf |}|| dd	dd S )
a  Transform coordinates in the pixel frame to the camera frame.

    Args:
        depth: the source depth maps. Shape must be Bx1xHxW.
        intrinsics_inv: the inverse intrinsics camera matrix. Shape must be Bx4x4.
        pixel_coords: the grid with (u, v, 1) pixel coordinates. Shape must be BxHxWx3.

    Returns:
        tensor of shape BxHxWx3 with (x, y, z) cam coordinates.

    r*   r1   z3Input depth has to be in the shape of Bx1xHxW. Got r)   z:Input intrinsics_inv has to be in the shape of Bx4x4. Got z:Input pixel_coords has to be in the shape of BxHxWx3. Got Nr   rA   )r/   r"   r'   r   permute)rb   r   r   
cam_coordsr   r   r   	pixel2cam  s   r   -q=cam_coords_srcdst_proj_srcc           
      C   s   t | jdks| jd dkrtd| j t |jdks.|jdd dkr.td|j t|dddf | }|d }|d	 }|d
 }|||  }|||  }t||gdd}	|	S )a  Transform coordinates in the camera frame to the pixel frame.

    Args:
        cam_coords_src: (x, y, z) coordinates defined in the first camera coordinates system. Shape must be BxHxWx3.
        dst_proj_src: the projection matrix between the
          reference and the non reference camera frame. Shape must be Bx4x4.
        eps: small value to avoid division by zero error.

    Returns:
        tensor of shape BxHxWx2 with (u, v) pixel coordinates.

    r*   r)   z<Input cam_coords_src has to be in the shape of BxHxWx3. Got r+   Nr,   z8Input dst_proj_src has to be in the shape of Bx4x4. Got rh   ).r1   ).rA   rF   r~   )r/   r"   r'   r   r   )
r   r   r   point_coordsx_coordy_coordz_coordu_coordv_coordpixel_coords_dstr   r   r   	cam2pixel  s    r   )r   )r   )typingr   r   r   rt   kornia.corer   r   r   r   r	   kornia.core.checkr   kornia.geometry.conversionsr   r   kornia.geometry.linalgr   r   kornia.utils.helpersr   r   rz   rx   r   r   r   r   r   r   r   r   r   r   r   <module>   s(      9..'4!