o
    €o™iôi  ã                   @  sj  d dl mZ d dlZd dlZd dlm  mZ d dlm	Z	m
Z
 d dlmZ d dlmZmZmZmZ d dlmZ d dlmZmZmZ d dlmZ d d	lmZ d d
lmZmZmZ ddgZ dDdd„Z!dDdd„Z"dEdd„Z#dFdd„Z$dEdd „Z%dEd!d"„Z&dGd$d%„Z'dHd(d)„Z(dHd*d+„Z)dId.d/„Z*dJd1d2„Z+dKd6d7„Z,dLd;d<„Z-dMd?d@„Z.e		dNdOdBd„ƒZ/G dCd„ deƒZ0dS )Pé    )ÚannotationsN)Úrgb_to_ycbcrÚycbcr_to_rgb)Úpi)ÚDeviceÚDtypeÚ	ParameterÚTensor)ÚImageModule)ÚKORNIA_CHECKÚKORNIA_CHECK_IS_TENSORÚKORNIA_CHECK_SHAPE©Úrescale)Úperform_keep_shape_image)Údifferentiable_clippingÚdifferentiable_polynomial_floorÚ"differentiable_polynomial_roundingÚJPEGCodecDifferentiableÚjpeg_codec_differentiableÚdevicer   Údtyper   Úreturnr	   c              
   C  s@   t jg d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g| |d	S )
z1Generate default Quantization table of Y channel.)é   é   é
   r   é   é(   é3   é=   )é   r    é   é   é   é:   é<   é7   )r!   é   r   r   r   é9   éE   é8   )r!   é   é   é   r   éW   éP   é>   )é   r,   é%   r*   éD   ém   ég   éM   )r   é#   r&   é@   éQ   éh   éq   é\   )é1   r8   éN   r.   r5   éy   éx   ée   )éH   r<   é_   éb   ép   éd   r5   éc   ©r   r   ©ÚtorchÚtensorrH   © rL   úG/home/ubuntu/.local/lib/python3.10/site-packages/kornia/enhance/jpeg.pyÚ_get_default_qt_y-   ó   ø
ôrN   c              
   C  s@   t jg d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g| |dS )z2Generate default Quantization table of C channels.)r+   r1   r   é/   rG   rG   rG   rG   )r1   é   r#   éB   rG   rG   rG   rG   )r   r#   r*   rG   rG   rG   rG   rG   )rP   rR   rG   rG   rG   rG   rG   rG   )rG   rG   rG   rG   rG   rG   rG   rG   rH   rI   rH   rL   rL   rM   Ú_get_default_qt_c?   rO   rS   Úinputc                 C  sD   | j \}}}|  ||d d|d d¡ ddddd¡ |ddd¡}|S )zïExtract non-overlapping 8 x 8 patches from the given input image.

    Args:
        input (Tensor): Input image of the shape :math:`(B, H, W)`.

    Returns:
        output (Tensor): Image patchify of the shape :math:`(B, N, 8, 8)`.

    é   r   é   é   é   é   éÿÿÿÿ©ÚshapeÚviewÚpermuteÚreshape)rT   ÚBÚHÚWÚoutputrL   rL   rM   Ú_patchify_8x8Q   s   4rd   ra   Úintrb   c                 C  sH   | j dd… \}}|  ||d |d dd¡ ddddd¡ |||¡}|S )a"  Reverse non-overlapping 8 x 8 patching.

    Args:
        input (Tensor): Input image of the shape :math:`(B, N, 8, 8)`.
        H: height of resulting tensor.
        W: width of resulting tensor.

    Returns:
        output (Tensor): Image patchify of the shape :math:`(B, H, W)`.

    NrX   rU   r   rV   rW   rY   r[   )rT   ra   rb   r`   Ú_Nrc   rL   rL   rM   Ú_unpatchify_8x8b   s   2rg   c                 C  s²   | j }| j}tjd||d}t ||||¡\}}}}d| d | t d  ¡ d| d | t d  ¡  }tjd||d}	d|	d< t d|	|	¡d	 }
|
d
 t 	| d |¡ }|S )úèPerform an 8 x 8 discrete cosine transform.

    Args:
        input (Tensor): Patched input tensor of the shape :math:`(B, N, 8, 8)`.

    Returns:
        output (Tensor): DCT output tensor of the shape :math:`(B, N, 8, 8)`.

    rU   ©r   r   ç       @ç      ð?ç      0@çÌ;fž æ?r   z
i, j -> ijç      Ð?©NNç      `@)
r   r   rJ   ÚarangeÚmeshgridr   ÚcosÚonesÚeinsumÚ	tensordot)rT   r   r   ÚindexÚxÚyÚuÚvÚ
dct_tensorÚalphaÚ	dct_scalerc   rL   rL   rM   Ú_dct_8x8u   s   8r   c                 C  s¸   | j }| j}tjd||d}d|d< t ||¡}| |d  } tjd||d}t ||||¡\}}}}	d| d | t d  ¡ d|	 d | t d  ¡  }
d	tj	| |
d
d d }|S )rh   rU   ri   rm   r   ro   rj   rk   rl   rn   rX   )Údimsrp   )
r   r   rJ   rt   Úouterrq   rr   r   rs   rv   )rT   r   r   r}   r~   rw   rx   ry   rz   r{   Úidct_tensorrc   rL   rL   rM   Ú	_idct_8x8Ž   s   8rƒ   Úcompression_strengthc                 C  s&   t t | dk d|  dd|   ¡ƒ}|S )a  Convert a given JPEG quality to the scaling factor.

    Args:
        compression_strength (Tensor): Compression strength ranging from 0 to 100. Any shape is supported.

    Returns:
        scale (Tensor): Scaling factor to be applied to quantization matrix. Same shape as input.

    é2   g     ˆ³@g      i@rj   )r   rJ   Úwhere)r„   ÚscalerL   rL   rM   Ú_jpeg_quality_to_scale©   s   
ýÿrˆ   Újpeg_qualityÚquantization_tablec                 C  sT   |dd…df t |ƒdd…dddf  }tt|d d ddƒƒ}| | }t|ƒ}|S )a–  Perform quantization.

    Args:
        input (Tensor): Input tensor of the shape :math:`(B, N, 8, 8)`.
        jpeg_quality (Tensor): Compression strength to be applied, shape is :math:`(B)`.
        quantization_table (Tensor): Quantization table of the shape :math:`(1, 8, 8)` or :math:`(B, 8, 8)`.

    Returns:
        output (Tensor): Quantized output tensor of the shape :math:`(B, N, 8, 8)`.

    Nç      I@ç      Y@rV   éÿ   )rˆ   r   r   r   ©rT   r‰   rŠ   Úquantization_table_scaledrc   rL   rL   rM   Ú	_quantizeÀ   s   &ÿÿr   c                 C  sH   |dd…df t |ƒdd…dddf  }| tt|d d ddƒƒ }|S )a˜  Perform dequantization.

    Args:
        input (Tensor): Input tensor of the shape :math:`(B, N, 8, 8)`.
        jpeg_quality (Tensor): Compression strength to be applied, shape is :math:`(B)`.
        quantization_table (Tensor): Quantization table of the shape :math:`(1, 8, 8)` or :math:`(B, 8, 8)`.

    Returns:
        output (Tensor): Quantized output tensor of the shape :math:`(B, N, 8, 8)`.

    Nr‹   rŒ   rV   r   )rˆ   r   r   rŽ   rL   rL   rM   Ú_dequantizeÞ   s   &ÿÿr‘   Úinput_ycbcrútuple[Tensor, Tensor, Tensor]c                 C  sŽ   | dd…df }| dd…df }| dd…df }t |dd…df ddddd	}t |dd…df ddddd	}||dd…df |dd…df fS )
aŸ  Implement chroma subsampling.

    Args:
        input_ycbcr (Tensor): YCbCr input tensor of the shape :math:`(B, 3, H, W)`.

    Returns:
        output_y (Tensor): Y component (not-subsampled), shape is :math:`(B, H, W)`.
        output_cb (Tensor): Cb component (subsampled), shape is :math:`(B, H // 2, W // 2)`.
        output_cr (Tensor): Cr component (subsampled), shape is :math:`(B, H // 2, W // 2)`.

    Nr   rV   rX   g      à?ÚbilinearFT©ÚfactorÚinterpolationÚalign_cornersÚ	antialiasr   )r’   Úoutput_yÚ	output_cbÚ	output_crrL   rL   rM   Ú_chroma_subsamplingù   s$   ûû"r   Úinput_cc                 C  s.   t | dd…df ddddd}|dd…df S )z÷Perform chroma upsampling.

    Args:
        input_c (Tensor): Cb or Cr component to be upsampled of the shape :math:`(B, H, W)`.

    Returns:
        output_c (Tensor): Upsampled C(b or r) component of the shape :math:`(B, H * 2, W * 2)`.

    Nrj   r”   Fr•   r   r   )rž   Úoutput_crL   rL   rM   Ú_chroma_upsampling  s   ûr    Ú	image_rgbÚquantization_table_yÚquantization_table_cc                 C  sˆ   t | ƒ}d| }t|ƒ\}}}t|ƒt|ƒt|ƒ}}}t|ƒ}ttj||fddƒ}	t|||ƒ}
t|	||ƒjddd\}}|
||fS )ac  Perform JPEG encoding.

    Args:
        image_rgb (Tensor): RGB input images of the shape :math:`(B, 3, H, W)`.
        jpeg_quality (Tensor): Compression strength of the shape :math:`(B)`.
        quantization_table_y (Tensor): Quantization table for Y channel.
        quantization_table_c (Tensor): Quantization table for C channels.

    Returns:
        y_encoded (Tensor): Encoded Y component of the shape :math:`(B, N, 8, 8)`.
        cb_encoded (Tensor): Encoded Cb component of the shape :math:`(B, N, 8, 8)`.
        cr_encoded (Tensor): Encoded Cr component of the shape :math:`(B, N, 8, 8)`.

    ç     ào@rV   ©ÚdimrX   )r   r   rd   r   rJ   Úcatr   Úchunk)r¡   r‰   r¢   r£   Úimage_ycbcrÚinput_yÚinput_cbÚinput_crÚdct_yÚ	dct_cb_crÚ	y_encodedÚ
cb_encodedÚ
cr_encodedrL   rL   rM   Ú_jpeg_encode0  s,   
ýýý
ü
r²   rª   r«   r¬   c                 C  s¬   t | ||ƒ} t tj||fdd||ƒ}t| ƒ}	t|ƒjddd\}
}t|	||ƒ}t|
|d |d ƒ}t||d |d ƒ}t|ƒ}t|ƒ}tj|||fddd }t|ƒ}|S )a½  Perform JPEG decoding.

    Args:
        input_y (Tensor): Compressed Y component of the shape :math:`(B, N, 8, 8)`.
        input_cb (Tensor): Compressed Cb component of the shape :math:`(B, N, 8, 8)`.
        input_cr (Tensor): Compressed Cr component of the shape :math:`(B, N, 8, 8)`.
        jpeg_quality (Tensor): Compression strength of the shape :math:`(B)`.
        H (int): Original image height.
        W (int): Original image width.
        quantization_table_y (Tensor): Quantization table for Y channel.
        quantization_table_c (Tensor): Quantization table for C channels.

    Returns:
        rgb_decoded (Tensor): Decompressed RGB image of the shape :math:`(B, 3, H, W)`.

    rV   r¥   rX   r¤   )	r‘   rJ   r§   rƒ   r¨   rg   r    Ústackr   )rª   r«   r¬   r‰   ra   rb   r¢   r£   Úinput_cb_crÚidct_yÚidct_cbÚidct_crÚimage_yÚimage_cbÚimage_crr©   Úrgb_decodedrL   rL   rM   Ú_jpeg_decode_  s(   ýýr¼   Úimageútuple[Tensor, int, int]c                 C  s^   | j dd… \}}t |d ¡d | }t |d ¡d | }t | d|d|fd¡}|||fS )a?  Pad a given image to be dividable by 16.

    Args:
        image: Image of the shape :math:`(*, 3, H, W)`.

    Returns:
        image_padded: Padded image of the shape :math:`(*, 3, H_{new}, W_{new})`.
        h_pad: Padded pixels along the horizontal axis.
        w_pad: Padded pixels along the vertical axis.

    éþÿÿÿNr   r   Ú	replicate)r\   ÚmathÚceilÚFÚpad)r½   ra   rb   Úh_padÚw_padÚimage_paddedrL   rL   rM   Ú_perform_padding•  s
   
rÈ   úTensor | Nonec              
   C  sf  t | ƒ t |ƒ | j}| j}|du rt||ƒn|}|du r"t||ƒn|}t |ƒ t |ƒ t| g d¢ƒ t|dgƒ |jdkrD|jdd}|jdkrO|jdd}t|g d¢ƒ t|g d¢ƒ t| 	¡  
¡ dkom| ¡  
¡ d	kd
| 	¡  
¡ › d| ¡  
¡ › dƒ t| ƒ\} }}| jdd… \}}	|jd dkr°t|jd | jd kd| jd › d|jd › dƒ |jd dkrÑt|jd | jd kd| jd › d|jd › dƒ |jd dkròt|jd | jd kd| jd › d|jd › dƒ | ||¡}| ||¡}| ||¡}t| |||d\}
}}t|
|||||	||d}t|ddd}|dd|| …d|	| …f }|S )a  Differentiable JPEG encoding-decoding module.

    Based on :cite:`reich2024` :cite:`shin2017`, we perform differentiable JPEG encoding-decoding as follows:

    .. image:: _static/img/jpeg_codec_differentiable.png

    .. math::

        \text{JPEG}_{\text{diff}}(I, q, QT_{y}, QT_{c}) = \hat{I}

    Where:
       - :math:`I` is the original image to be coded.
       - :math:`q` is the JPEG quality controlling the compression strength.
       - :math:`QT_{y}` is the luma quantization table.
       - :math:`QT_{c}` is the chroma quantization table.
       - :math:`\hat{I}` is the resulting JPEG encoded-decoded image.

    .. note:::
        The input (and output) pixel range is :math:`[0, 1]`. In case you want to handle normalized images you are
        required to first perform denormalization followed by normalizing the output images again.

        Note, that this implementation models the encoding-decoding mapping of JPEG in a differentiable setting,
        however, does not allow the excess of the JPEG-coded byte file itself.
        For more details please refer to :cite:`reich2024`.

        This implementation is not meant for data loading. For loading JPEG images please refer to `kornia.io`.
        There we provide an optimized Rust implementation for fast JPEG loading.

    Args:
        image_rgb: the RGB image to be coded.
        jpeg_quality: JPEG quality in the range :math:`[0, 100]` controlling the compression strength.
        quantization_table_y: quantization table for Y channel. Default: `None`, which will load the standard
          quantization table.
        quantization_table_c: quantization table for C channels. Default: `None`, which will load the standard
          quantization table.

    Shape:
        - image_rgb: :math:`(*, 3, H, W)`.
        - jpeg_quality: :math:`(1)` or :math:`(B)` (if used batch dim. needs to match w/ image_rgb).
        - quantization_table_y: :math:`(8, 8)` or :math:`(B, 8, 8)` (if used batch dim. needs to match w/ image_rgb).
        - quantization_table_c: :math:`(8, 8)` or :math:`(B, 8, 8)` (if used batch dim. needs to match w/ image_rgb).

    Return:
        JPEG coded image of the shape :math:`(B, 3, H, W)`

    Example:
        To perform JPEG coding with the standard quantization tables just provide a JPEG quality

        >>> img = torch.rand(3, 3, 64, 64, requires_grad=True, dtype=torch.float)
        >>> jpeg_quality = torch.tensor((99.0, 25.0, 1.0), requires_grad=True)
        >>> img_jpeg = jpeg_codec_differentiable(img, jpeg_quality)
        >>> img_jpeg.sum().backward()

        You also have the option to provide custom quantization tables

        >>> img = torch.rand(3, 3, 64, 64, requires_grad=True, dtype=torch.float)
        >>> jpeg_quality = torch.tensor((99.0, 25.0, 1.0), requires_grad=True)
        >>> quantization_table_y = torch.randint(1, 256, size=(3, 8, 8), dtype=torch.float)
        >>> quantization_table_c = torch.randint(1, 256, size=(3, 8, 8), dtype=torch.float)
        >>> img_jpeg = jpeg_codec_differentiable(img, jpeg_quality, quantization_table_y, quantization_table_c)
        >>> img_jpeg.sum().backward()

        In case you want to control the quantization purly base on the quantization tables use a JPEG quality of 99.5.
        Setting the JPEG quality to 99.5 leads to a QT scaling of 1, see Eq. 2 of :cite:`reich2024` for details.

        >>> img = torch.rand(3, 3, 64, 64, requires_grad=True, dtype=torch.float)
        >>> jpeg_quality = torch.ones(3) * 99.5
        >>> quantization_table_y = torch.randint(1, 256, size=(3, 8, 8), dtype=torch.float)
        >>> quantization_table_c = torch.randint(1, 256, size=(3, 8, 8), dtype=torch.float)
        >>> img_jpeg = jpeg_codec_differentiable(img, jpeg_quality, quantization_table_y, quantization_table_c)
        >>> img_jpeg.sum().backward()

    N)Ú*Ú3ra   rb   r`   rX   r   r¥   )r`   Ú8rÌ   g        rŒ   z?JPEG quality is out of range. Expected range is [0, 100], got [z, z"]. Consider clipping jpeg_quality.r¿   rV   z#Batch dimensions do not match. Got z images and z quantization tables (Y).z quantization tables (C).z JPEG qualities.)r¡   r‰   r£   r¢   )rª   r«   r¬   r‰   ra   rb   r£   r¢   r¤   )rT   Úmin_valÚmax_val.)r   r   r   rN   rS   r   ÚndimÚ	unsqueezer   ÚaminÚitemÚamaxrÈ   r\   Útor²   r¼   r   )r¡   r‰   r¢   r£   r   r   rÅ   rÆ   ra   rb   r¯   r°   r±   Úimage_rgb_jpegrL   rL   rM   r   «  s–   Q


ÿ
ÿþÿÿþÿÿþÿÿþüøc                      s2   e Zd ZdZ		dd‡ fdd	„Zddd„Z‡  ZS )r   a_  Differentiable JPEG encoding-decoding module.

    Based on :cite:`reich2024` :cite:`shin2017`, we perform differentiable JPEG encoding-decoding as follows:

    .. math::

        \text{JPEG}_{\text{diff}}(I, q, QT_{y}, QT_{c}) = \hat{I}

    Where:
       - :math:`I` is the original image to be coded.
       - :math:`q` is the JPEG quality controlling the compression strength.
       - :math:`QT_{y}` is the luma quantization table.
       - :math:`QT_{c}` is the chroma quantization table.
       - :math:`\hat{I}` is the resulting JPEG encoded-decoded image.

    .. image:: _static/img/jpeg_codec_differentiable.png

    .. note::
        The input (and output) pixel range is :math:`[0, 1]`. In case you want to handle normalized images you are
        required to first perform denormalization followed by normalizing the output images again.

        Note, that this implementation models the encoding-decoding mapping of JPEG in a differentiable setting,
        however, does not allow the excess of the JPEG-coded byte file itself.
        For more details please refer to :cite:`reich2024`.

        This implementation is not meant for data loading. For loading JPEG images please refer to `kornia.io`.
        There we provide an optimized Rust implementation for fast JPEG loading.

    Args:
        quantization_table_y: quantization table for Y channel. Default: `None`, which will load the standard
          quantization table.
        quantization_table_c: quantization table for C channels. Default: `None`, which will load the standard
          quantization table.

    Shape:
        - quantization_table_y: :math:`(8, 8)` or :math:`(B, 8, 8)` (if used batch dim. needs to match w/ image_rgb).
        - quantization_table_c: :math:`(8, 8)` or :math:`(B, 8, 8)` (if used batch dim. needs to match w/ image_rgb).
        - image_rgb: :math:`(*, 3, H, W)`.
        - jpeg_quality: :math:`(1)` or :math:`(B)` (if used batch dim. needs to match w/ image_rgb).

    Example:
        You can use the differentiable JPEG module with standard quantization tables by

        >>> diff_jpeg_module = JPEGCodecDifferentiable()
        >>> img = torch.rand(2, 3, 32, 32, requires_grad=True, dtype=torch.float)
        >>> jpeg_quality = torch.tensor((99.0, 1.0), requires_grad=True)
        >>> img_jpeg = diff_jpeg_module(img, jpeg_quality)
        >>> img_jpeg.sum().backward()

        You can also specify custom quantization tables to be used by

        >>> quantization_table_y = torch.randint(1, 256, size=(2, 8, 8), dtype=torch.float)
        >>> quantization_table_c = torch.randint(1, 256, size=(2, 8, 8), dtype=torch.float)
        >>> diff_jpeg_module = JPEGCodecDifferentiable(quantization_table_y, quantization_table_c)
        >>> img = torch.rand(2, 3, 32, 32, requires_grad=True, dtype=torch.float)
        >>> jpeg_quality = torch.tensor((99.0, 1.0), requires_grad=True)
        >>> img_jpeg = diff_jpeg_module(img, jpeg_quality)
        >>> img_jpeg.sum().backward()

        In case you want to learn the quantization tables just pass parameters `nn.Parameter`

        >>> quantization_table_y = torch.nn.Parameter(torch.randint(1, 256, size=(2, 8, 8), dtype=torch.float))
        >>> quantization_table_c = torch.nn.Parameter(torch.randint(1, 256, size=(2, 8, 8), dtype=torch.float))
        >>> diff_jpeg_module = JPEGCodecDifferentiable(quantization_table_y, quantization_table_c)
        >>> img = torch.rand(2, 3, 32, 32, requires_grad=True, dtype=torch.float)
        >>> jpeg_quality = torch.tensor((99.0, 1.0), requires_grad=True)
        >>> img_jpeg = diff_jpeg_module(img, jpeg_quality)
        >>> img_jpeg.sum().backward()

    Nr¢   úTensor | Parameter | Noner£   r   ÚNonec                   s„   t ƒ  ¡  |d u rtd d ƒn|}|d u rtd d ƒn|}t|tƒr'|  d|¡ n|  d|¡ t|tƒr:|  d|¡ d S |  d|¡ d S )Nr¢   r£   )ÚsuperÚ__init__rN   rS   Ú
isinstancer   Úregister_parameterÚregister_buffer)Úselfr¢   r£   ©Ú	__class__rL   rM   rÙ   “  s   


z JPEGCodecDifferentiable.__init__r¡   r	   r‰   c                 C  s<   |j }|j}| j ||¡}| j ||¡}t||||d}|S )N)r‰   r£   r¢   )r   r   r¢   rÔ   r£   r   )rÝ   r¡   r‰   r   r   r¢   r£   rÕ   rL   rL   rM   Úforward¥  s   üzJPEGCodecDifferentiable.forwardro   )r¢   rÖ   r£   rÖ   r   r×   )r¡   r	   r‰   r	   r   r	   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rÙ   rà   Ú__classcell__rL   rL   rÞ   rM   r   K  s    Iý)r   r   r   r   r   r	   )rT   r	   r   r	   )rT   r	   ra   re   rb   re   r   r	   )r„   r	   r   r	   )rT   r	   r‰   r	   rŠ   r	   r   r	   )r’   r	   r   r“   )rž   r	   r   r	   )
r¡   r	   r‰   r	   r¢   r	   r£   r	   r   r“   )rª   r	   r«   r	   r¬   r	   r‰   r	   ra   re   rb   re   r¢   r	   r£   r	   r   r	   )r½   r	   r   r¾   ro   )
r¡   r	   r‰   r	   r¢   rÉ   r£   rÉ   r   r	   )1Ú
__future__r   rÁ   rJ   Útorch.nn.functionalÚnnÚ
functionalrÃ   Úkornia.colorr   r   Úkornia.constantsr   Úkornia.corer   r   r   r	   r
   ÚModuleÚkornia.core.checkr   r   r   Ú!kornia.geometry.transform.affwarpr   Úkornia.utils.imager   Úkornia.utils.miscr   r   r   Ú__all__rN   rS   rd   rg   r   rƒ   rˆ   r   r‘   r   r    r²   r¼   rÈ   r   r   rL   rL   rL   rM   Ú<module>   sB   










"

/
6ü  