o
    ߥi&4                     @   s  d Z ddlZddlZddlZddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZmZ ddlmZ d	d
lmZ dd Zdd Zdd Zd?dejdefddZ				d@dejdedededef
ddZ		dAdejdejdefddZ	dBd ejd!ejd"ejdejd#ejd$ejd%efd&d'Z	(	)dCd$ejdejd*ej d+ej d,ejd-ed.e!d/e"d0e"d1efd2d3Z#d4e$d5e"d6e"d7e"fd8d9Z%d4e$d:ej d;e&d<e"d0e"d1ed5e"d6e"d7e"fd=d>Z'dS )Dzx
Part of the implementation is borrowed and modified from LaMa, publicly available at
https://github.com/saic-mdal/lama
    N)gaussian_blur2d)resizeerosion)
functional)SGDAdam)tqdm   )FFCResnetBlockc                    s|   t | tjr|  S t| r|  S t | ttfr% fdd| D S t | tr5 fdd| 	 D S t
dt|  )Nc                    s   g | ]}t | qS  move_to_device).0eldevicer   d/home/ubuntu/.local/lib/python3.10/site-packages/modelscope/models/cv/image_inpainting/refinement.py
<listcomp>       z"move_to_device.<locals>.<listcomp>c                    s   i | ]
\}}|t | qS r   r   )r   namevalr   r   r   
<dictcomp>   s    z"move_to_device.<locals>.<dictcomp>zUnexpected type )
isinstancennModuletotorch	is_tensortuplelistdictitems
ValueErrortype)objr   r   r   r   r      s   



r   c                 C   s    | | dkr| S | | d | S )Nr   r
   r   )xmodr   r   r   ceil_modulo   s   r(   c                 C   sB   | j \}}}}t||}t||}tj| d|| d|| fddS )Nr   reflect)padmode)shaper(   Fr*   )imgr'   
batch_sizechannelsheightwidth
out_height	out_widthr   r   r   pad_tensor_to_modulo%   s   

r5   imdownsizec                 C   s^   |du r| j d d | j d d f}| j d dksJ dt| ddd} tj| |d	d
d} | S )zdownscale the imageN      r
   z5Expected shape for the input to be (n,3,height,width)   r;         ?r=   kernel_sizesigmabilinearFsizer+   align_cornersr,   r   r-   interpolate)r6   r7   r   r   r   _pyrdown/   s   rG   :0yE>Tmaskeps	blur_maskround_upc                 C   s   |du r| j d d | j d d f}| j d dksJ d|du r2t| ddd	} tj| |d
dd} n	tj| |d
dd} |rKd| | |k< d| | |k < | S d| | d| k< d| | d| k < | S )av  downscale the mask tensor

    Parameters
    ----------
    mask : torch.Tensor
        mask of size (B, 1, H, W)
    downsize : tuple, optional
        size to downscale to. If None, image is downscaled to half, by default None
    eps : float, optional
        threshold value for binarizing the mask, by default 1e-8
    blur_mask : bool, optional
        if True, apply gaussian filter before downscaling, by default True
    round_up : bool, optional
        if True, values above eps are marked 1, else, values below 1-eps are marked 0, by default True

    Returns
    -------
    torch.Tensor
        downscaled mask
    Nr8   r9   r
   z5Expected shape for the input to be (n,1,height,width)Tr:   r<   r>   rA   FrB   r   r=   rE   )rI   r7   rJ   rK   rL   r   r   r   _pyrdown_mask:   s0   rM   ekernelc                 C   s6   |durt | |} d| | d| k< d| | d| k < | S )z(erode the mask, and set gray pixels to 0Nr
   r=   r   r   )rI   rN   rJ   r   r   r   _erode_maskh   s
   
rO   predpred_downscaledrefmask_downscaledimageon_predc              	   C   sT   t t | |dk  ||dk   }|r(|t t ||dk ||dk  7 }|S )zAl1 loss on src pixels, and downscaled predictions if on_pred=TruerH   )r   meanabs)rP   rQ   rR   rI   rS   rT   rU   lossr   r   r   _l1_losss   s   $
rY      Mb`?forward_frontforward_rearsref_lower_res
orig_shapedevices	scale_indn_iterslrc
              
   C   s  | d|  }
t j|
|gdd}
|dddd}|dur| }t   ||
\}}W d   n1 s4w   Y  ||d }t ttj	d
t }||d }| |d } | |d | |d }}d\|_|_t||g|	d	}tt|d
d}|D ]}|  ||f}t|D ].\}}||}|t|d k r|\}}|||d  |||d  }}||f}q|}q|du r nsi }t|ddddd|d d|d f }t|ddddd|d d|d f d
d
d}t||d}|dddd}t|||||| dd|d< t| }|d|d ||  ||d k r=|  |  ~~~q|| d| |   }|  }|S )a{  Performs inference with refinement at a given scale.

    Parameters
    ----------
    image : torch.Tensor
        input image to be inpainted, of size (1,3,H,W)
    mask : torch.Tensor
        input inpainting mask, of size (1,1,H,W)
    forward_front : nn.Module
        the front part of the inpainting network
    forward_rears : nn.Module
        the rear part of the inpainting network
    ref_lower_res : torch.Tensor
        the inpainting at previous scale, used as reference image
    orig_shape : tuple
        shape of the original input image before padding
    devices : list
        list of available devices
    scale_ind : int
        the scale index
    n_iters : int, optional
        number of iterations of refinement, by default 15
    lr : float, optional
        learning rate, by default 0.002

    Returns
    -------
    torch.Tensor
        inpainted image
    r
   )dimr9   N)rZ   rZ   r   )TT)rc   F)leave)rK   rL   )rN   T)rU   ms_l1z8Refining scale {} using scale {} ...current loss: {:.4f}) r   catrepeatdetachno_gradr   
from_numpycv2getStructuringElementMORPH_ELLIPSEastypeboolfloatrequires_gradr   r	   range	zero_grad	enumeratelenrG   rM   rO   rY   sumvaluesset_descriptionformatitembackwardstepcpu)rT   rI   r\   r]   r^   r_   r`   ra   rb   rc   masked_imagez1z2rN   	optimizerpbaridi
input_featiddforward_rearoutput_featmidz1midz2rP   lossesrQ   rS   rX   	inpaintedr   r   r   _infer   s   (
&

,&
	r   batchmin_side
max_scales	px_budgetc              
   C   s  | d j d dksJ d| d \}}|d  |d  }}| d dd|d|f }| d dd|d|f }|| |krt|t||  }||}	}
t|| t|| }}td	|	|
f d
||f d t|||fddd}t|||fddd}d||dk< t||}tdtt	t
dt||  |}g }g }|| || t|d D ]}t|d }t|d }|| || q|ddd |ddd fS )a  Build the image mask pyramid

    Parameters
    ----------
    batch : dict
        batch containing image, mask, etc
    min_side : int
        minimum side length to limit the number of scales of the pyramid
    max_scales : int
        maximum number of scales allowed
    px_budget : int
        the product H*W cannot exceed this budget, because of resource constraints

    Returns
    -------
    tuple
        image-mask pyramid in the form of list of images and list of masks
    rT   r   r
   z(refiner works on only batches of size 1!unpad_to_size.NrI   z2Original image too large for refinement! Resizing z to z...rA   F)interpolationrD   rH   re   )r,   r|   npsqrtrr   intprintr   minroundmaxlog2appendrt   rG   rM   )r   r   r   r   hwrT   rI   ratioh_origw_origbreadthn_scales	ls_imagesls_masks_image_pmask_pr   r   r   _get_image_mask_pyramid   sN   

 


r   	inpaintergpu_idsmoduloc	                 C   sF  |j }|jrJ |jrJ |jsJ dd |dddD }d}	d}
d}tt|jj D ]}t	|jj | t
r@|	d7 }	d	}q.|sF|
d7 }
q.|	t| }d
d |D }|jj d|
 }||d  g }tt|D ]8}|t|d k r||jj |
||  |
||d     n||jj |
||  d  || ||  qkt| |||\}}d}tt||D ]j\}\}}|jdd }t||}t||}d||dk< d||dk < t||d t||d }}|durt||d }t||||||||||
}|ddddd|d d|d f }|  }|  }q|S )af  Refines the inpainting of the network

    Parameters
    ----------
    batch : dict
        image-mask batch, currently we assume the batchsize to be 1
    inpainter : nn.Module
        the inpainting neural network
    gpu_ids : str
        the GPU ids of the machine to use. If only single GPU, use: "0,"
    modulo : int
        pad the image to ensure dimension % modulo == 0
    n_iters : int
        number of iterations of refinement for each scale
    lr : float
        learning rate
    min_side : int
        all sides of image on all scales should be >= min_side / sqrt(2)
    max_scales : int
        max number of downscaling scales for the image-mask pyramid
    px_budget : int
        pixels budget. Any image will be resized to satisfy height*width <= px_budget

    Returns
    -------
    torch.Tensor
        inpainted image of size (1,3,H,W)
    c                 S   s   g | ]}|  rd | qS )zcuda:)isdigit)r   gpuidr   r   r   r   Q  s    z"refine_predict.<locals>.<listcomp>  ,r   Fr
   Tc                 S   s   g | ]}t |qS r   )r   r   )r   gpu_idr   r   r   r   `  r   Nr8   r=   rH   g        re   )modeltrainingadd_noise_kwargsconcat_maskreplacesplitrt   rw   	generatorr   r   r   r   r   rv   zipr,   r5   r   r   rj   r   )r   r   r   r   rb   rc   r   r   r   n_resnet_blocksfirst_resblock_indfound_first_resblockidlresblocks_per_gpur`   r\   r]   r   r   r   image_inpaintedidsrT   rI   r_   r   r   r   refine_predict-  s   






(r   )N)NrH   TT)NrH   )T)rZ   r[   )(__doc__rm   numpyr   r   torch.nnr   kornia.filtersr   kornia.geometry.transformr   kornia.morphologyr   r   r-   torch.optimr   r   r	   modules.ffcr   r   r(   r5   Tensorr   rG   rr   rq   rM   rO   rY   r   r    r   r   r!   r   strr   r   r   r   r   <module>   s    


/




	
n
<