o
    oi                     @  s   d Z ddlmZ ddlmZ ddlZddlmZmZm	Z	 ddl
mZmZ ddlmZ d%ddZd&d'ddZd(d)ddZd*d+ddZd(d,d#d$ZdS )-zImplementation of "differentiable spatial to numerical" (soft-argmax) operations.

As described in the paper "Numerical Coordinate Regression with Convolutional Neural Networks" by Nibali et al.
    )annotations)OptionalN)TensorconcatenatesoftmaxKORNIA_CHECK_IS_TENSORKORNIA_CHECK_SHAPE)create_meshgridtensorr   returnNonec                 C  s   t |  t| g d d S )N)BCHWr   )r    r   O/home/ubuntu/.local/lib/python3.10/site-packages/kornia/geometry/subpix/dsnt.py$_validate_batched_image_tensor_input"   s   r   inputtemperatureOptional[Tensor]c                 C  sh   t |  | j\}}}}|du rtd}|j| j| jd}| ||d}t|| dd}|||||S )a2  Apply the Softmax function over features in each image channel.

    Note that this function behaves differently to :py:class:`torch.nn.Softmax2d`, which
    instead applies Softmax over features at each spatial location.

    Args:
        input: the input tensor with shape :math:`(B, N, H, W)`.
        temperature: factor to apply to input, adjusting the "smoothness" of the output distribution.

    Returns:
       a 2D probability distribution per image channel with shape :math:`(B, N, H, W)`.

    Examples:
        >>> heatmaps = torch.tensor([[[
        ... [0., 0., 0.],
        ... [0., 0., 0.],
        ... [0., 1., 2.]]]])
        >>> spatial_softmax2d(heatmaps)
        tensor([[[[0.0585, 0.0585, 0.0585],
                  [0.0585, 0.0585, 0.0585],
                  [0.0585, 0.1589, 0.4319]]]])

    Ng      ?)devicedtype)dim)	r   shapetorchr   tor   r   viewr   )r   r   
batch_sizechannelsheightwidthxx_softr   r   r   spatial_softmax2d'   s   
r&   Tnormalized_coordinatesboolc                 C  s   t |  | j\}}}}t|||| j}|| j}|d d}|d d}| ||d}	tj	||	 ddd}
tj	||	 ddd}t
||
gd}|||dS )a  Compute the expectation of coordinate values using spatial probabilities.

    The input heatmap is assumed to represent a valid spatial probability distribution,
    which can be achieved using :func:`~kornia.geometry.subpixel.spatial_softmax2d`.

    Args:
        input: the input tensor representing dense spatial probabilities with shape :math:`(B, N, H, W)`.
        normalized_coordinates: whether to return the coordinates normalized in the range
          of :math:`[-1, 1]`. Otherwise, it will return the coordinates in the range of the input shape.

    Returns:
       expected value of the 2D coordinates with shape :math:`(B, N, 2)`. Output order of the coordinates is (x, y).

    Examples:
        >>> heatmaps = torch.tensor([[[
        ... [0., 0., 0.],
        ... [0., 0., 0.],
        ... [0., 1., 0.]]]])
        >>> spatial_expectation2d(heatmaps, False)
        tensor([[[1., 2.]]])

    .r   r   .   Tkeepdim   )r   r   r
   r   r   r   reshaper   r   sumr   )r   r'   r    r!   r"   r#   gridpos_xpos_y
input_flat
expected_y
expected_xoutputr   r   r   spatial_expectation2dL   s   r8   3#I9	numeratordenominatorepsfloatc                 C  s   | t j||d S )N)min)r   clamp)r:   r;   r<   r   r   r   _safe_zero_divisiony   s   r@   meanstdsizetuple[int, int]c                 C  s   |j | j kr|j| jkstd|\}}t|||| j}|| j }|d ||}|d ||}|| d  d }	|| d  d }
dt|d  }dt|d  }t|	| }t|
| }|| }|j	dd	d
j	dd	d
}t
||}|S )a  Render the PDF of a 2D Gaussian distribution.

    Args:
        mean: the mean location of the Gaussian to render, :math:`(\mu_x, \mu_y)`. Shape: :math:`(*, 2)`.
        std: the standard deviation of the Gaussian to render, :math:`(\sigma_x, \sigma_y)`.
          Shape :math:`(*, 2)`. Should be able to be broadcast with `mean`.
        size: the (height, width) of the output image.
        normalized_coordinates: whether ``mean`` and ``std`` are assumed to use coordinates normalized
          in the range of :math:`[-1, 1]`. Otherwise, coordinates are assumed to be in the range of the output shape.

    Returns:
        tensor including rendered points with shape :math:`(*, H, W)`.

    z1Expected inputs to have the same dtype and devicer)   r*   ).r   NNr.   ).r+   NNg      Tr,   r   )r   r   	TypeErrorr
   r   r   r   
reciprocalexpr0   r@   )rA   rB   rC   r'   r"   r#   r1   r2   r3   dist_xdist_yk_xk_yexps_xexps_ygaussval_sumr   r   r   render_gaussian2d}   s"   
rQ   )r   r   r   r   )N)r   r   r   r   r   r   )T)r   r   r'   r(   r   r   )r9   )r:   r   r;   r   r<   r=   r   r   )
rA   r   rB   r   rC   rD   r'   r(   r   r   )__doc__
__future__r   typingr   r   kornia.corer   r   r   kornia.core.checkr   r	   kornia.utils.gridr
   r   r&   r8   r@   rQ   r   r   r   r   <module>   s   
%-