U
    eք                     @   sb   d Z ddlZddlZddlZddlZddlmZmZm	Z	 ddl
T G dd dZG dd	 d	e	ZdS )
z
The source code is adapted from https://github.com/aliaksandr960/segment-anything-eo. Credit to the author Aliaksandr Hancharenka.
    N)sam_model_registrySamAutomaticMaskGeneratorSamPredictor   )*c                   @   s   e Zd ZdZd;ddZd<d	d
Zd=ddZd>ddZd?ddZd@ddZ	dAddZ
ddejddfddZdBddZdddd i fd!d"ZdCd$d%ZdDd)d*Zd+d, Zd-d. Zd/d0 ZdEd1d2ZdFd3d4ZdGd5d6ZdHd7d8ZdId9d:ZdS )JSamGeozThe main class for segmenting geospatial data with the Segment Anything Model (SAM). See
    https://github.com/facebookresearch/segment-anything for details.
    vit_hTNc           	      K   s  d}d|kr8|d }t j|s,t|||}|d nt|||}|dkrptj rZdnd}|dkrptj  || _	|| _
|| _|| _d| _d| _d| _d| _d| _d| _d| _d| _t| j
 | j	d| _| jj| jd | jdk	r| jni }|rt| jf|| _nt| jf|| _dS )a  Initialize the class.

        Args:
            model_type (str, optional): The model type. It can be one of the following: vit_h, vit_l, vit_b.
                Defaults to 'vit_h'. See https://bit.ly/3VrpxUh for more details.
            automatic (bool, optional): Whether to use the automatic mask generator or input prompts. Defaults to True.
                The automatic mask generator will segment the entire image, while the input prompts will segment selected objects.
            device (str, optional): The device to use. It can be one of the following: cpu, cuda.
                Defaults to None, which will use cuda if available.
            checkpoint_dir (str, optional): The path to the model checkpoint. It can be one of the following:
                sam_vit_h_4b8939.pth, sam_vit_l_0b3195.pth, sam_vit_b_01ec64.pth.
                Defaults to None. See https://bit.ly/3VrpxUh for more details.
            sam_kwargs (dict, optional): Optional arguments for fine-tuning the SAM model. Defaults to None.
                The available arguments with default values are listed below. See https://bit.ly/410RV0v for more details.

                points_per_side: Optional[int] = 32,
                points_per_batch: int = 64,
                pred_iou_thresh: float = 0.88,
                stability_score_thresh: float = 0.95,
                stability_score_offset: float = 1.0,
                box_nms_thresh: float = 0.7,
                crop_n_layers: int = 0,
                crop_nms_thresh: float = 0.7,
                crop_overlap_ratio: float = 512 / 1500,
                crop_n_points_downscale_factor: int = 1,
                point_grids: Optional[List[np.ndarray]] = None,
                min_mask_region_area: int = 0,
                output_mode: str = "binary_mask",

        F
checkpointNcudacpu)r	   device)ospathexistsZdownload_checkpointpoptorchr
   is_availableempty_cacher	   
model_typer   
sam_kwargssourceimagemasksobjectsannotations
predictionscoreslogitsr   Zsamtor   mask_generatorr   	predictor)	selfr   Z	automaticr   Zcheckpoint_dirr   kwargsZhqr	    r$   P/home/ankuromar296_gmail_com/.local/lib/python3.8/site-packages/samgeo/samgeo.py__init__   s:    '
zSamGeo.__init__   r(      c                 K   s   |j \}}}| j|}	|r2tj||ftjd}
ntj||ftjd}
tj||ftjd}|	D ]X}|d dktj}|
|7 }
|dk	r^tj	||dd}|dktj}|| }||7 }q^|
dktj}
|dktj}|
| }|| S )a  Generate masks for the input tile. This function originates from the segment-anything-eo repository.
            See https://bit.ly/41pwiHw

        Args:
            image (np.ndarray): The input image as a numpy array.
            foreground (bool, optional): Whether to generate the foreground mask. Defaults to True.
            erosion_kernel (tuple, optional): The erosion kernel for filtering object masks and extract borders. Defaults to (3, 3).
            mask_multiplier (int, optional): The mask multiplier for the output mask, which is usually a binary mask [0, 1].
                You can use this parameter to scale the mask to a larger range, for example [0, 255]. Defaults to 255.
        dtypesegmentationr   Nr   Z
iterations)
shaper    generatenpzerosuint8onesastypecv2erode)r"   r   
foregrounderosion_kernelmask_multiplierr#   hw_r   resulting_maskresulting_bordersmmask
mask_erode	edge_maskZresulting_mask_with_bordersr$   r$   r%   __call__i   s$    
zSamGeo.__call__Fc                 K   s   t |tr|drt|}tj|s8td| d|rjd| _|| _	|| _
t||| f|||d|S t|}	t|	tj}	nt |tjr|}	d}ntd|| _	|	| _| j}
|
|	}|| _
d| _|dk	r| j|||||f| dS )	a  Generate masks for the input image.

        Args:
            source (str | np.ndarray): The path to the input image or the input image as a numpy array.
            output (str, optional): The path to the output image. Defaults to None.
            foreground (bool, optional): Whether to generate the foreground mask. Defaults to True.
            batch (bool, optional): Whether to generate masks for a batch of image tiles. Defaults to False.
            erosion_kernel (tuple, optional): The erosion kernel for filtering object masks and extract borders.
                Such as (3, 3) or (5, 5). Set to None to disable it. Defaults to None.
            mask_multiplier (int, optional): The mask multiplier for the output mask, which is usually a binary mask [0, 1].
                You can use this parameter to scale the mask to a larger range, for example [0, 255]. Defaults to 255.
                The parameter is ignored if unique is True.
            unique (bool, optional): Whether to assign a unique value to each object. Defaults to True.
                The unique value increases from 1 to the number of objects. The larger the number, the larger the object area.

        httpInput path  does not exist.T)r7   r8   r9   Nz4Input source must be either a path or a numpy array.F)
isinstancestr
startswithdownload_filer   r   r   
ValueErrorbatchr   r   Ztiff_to_tiffr5   imreadcvtColorCOLOR_BGR2RGBr0   ndarrayr   r    r/   
save_masks)r"   r   outputr7   rL   r8   r9   uniquer#   r   r    r   r$   r$   r%   r/      sT    




    zSamGeo.generatec                 K   s  | j dkrtd| jj\}}}	| j }
t|
dk r:tj}nt|
dk rNtj}ntj}|rt	|
dd dd}t
|d	 d
 jd	 |d	 d
 jd f}t|D ]\}}|d
 }|d ||< qn|rtj
||f|d}ntj||f|d}tj
||f|d}|
D ]T}|d
 d	k|}||7 }|dk	rtj||dd}|d	k|}|| }||7 }q|d	k|}|d	k|}|| }|| }||}|| _|dk	rt| j|| jf| dS )a  Save the masks to the output path. The output is either a binary mask or a mask of objects with unique values.

        Args:
            output (str, optional): The path to the output image. Defaults to None, saving the masks to SamGeo.objects.
            foreground (bool, optional): Whether to generate the foreground mask. Defaults to True.
            unique (bool, optional): Whether to assign a unique value to each object. Defaults to True.
            erosion_kernel (tuple, optional): The erosion kernel for filtering object masks and extract borders.
                Such as (3, 3) or (5, 5). Set to None to disable it. Defaults to None.
            mask_multiplier (int, optional): The mask multiplier for the output mask, which is usually a binary mask [0, 1].
                You can use this parameter to scale the mask to a larger range, for example [0, 255]. Defaults to 255.

        Nz,No masks found. Please run generate() first.r)   i  c                 S   s   | d S NZarear$   xr$   r$   r%   <lambda>      z#SamGeo.save_masks.<locals>.<lambda>Fkeyreverser   r,   r   r*   r-   )r   rK   r   r.   lenr0   r2   Zuint16Zuint32sortedr1   	enumerater3   r4   r5   r6   r   array_to_imager   )r"   rR   r7   rS   r8   r9   r#   r:   r;   r<   r   r+   Zsorted_masksr   indexannr?   r=   r>   r@   rA   rB   r$   r$   r%   rQ      sN    



zSamGeo.save_masks   
   binary_roffc                 K   sr   ddl m} | jr"t| j| _n| jdkr@| jf d|i| |j|d |j	| j|d |
| |  dS )a  Show the binary mask or the mask of objects with unique values.

        Args:
            figsize (tuple, optional): The figure size. Defaults to (12, 10).
            cmap (str, optional): The colormap. Defaults to "binary_r".
            axis (str, optional): Whether to show the axis. Defaults to "off".
            foreground (bool, optional): Whether to show the foreground mask only. Defaults to True.
            **kwargs: Other arguments for save_masks().
        r   Nr7   figsize)cmap)matplotlib.pyplotpyplotrL   r5   rM   r   r   rQ   figureimshowaxisshow)r"   rh   ri   rn   r7   r#   pltr$   r$   r%   
show_masks.  s    

zSamGeo.show_masksffffff?c                 K   s  ddl m} | j}| jdkr(td dS |dks<t|dkr@dS |j|d || j t|dd dd}	|	 }
|

d	 t|	d d
 jd |	d d
 jd df}d|dddddf< |	D ],}|d
 }ttjd|gg}|||< q|
| d|krd|d< d|krd|d< || |ddddddf d tj| _|dk	r|rvt| j| j|d	d}n| j}t||| j dS )a   Show the annotations (objects with random color) on the input image.

        Args:
            figsize (tuple, optional): The figure size. Defaults to (12, 10).
            axis (str, optional): Whether to show the axis. Defaults to "off".
            alpha (float, optional): The alpha value for the annotations. Defaults to 0.35.
            output (str, optional): The path to the output image. Defaults to None.
            blend (bool, optional): Whether to show the input image. Defaults to True.
        r   NzPlease run generate() first.rg   c                 S   s   | d S rT   r$   rU   r$   r$   r%   rW   i  rX   z"SamGeo.show_anns.<locals>.<lambda>TrY   Fr,   r      r(   Zdpid   Zbbox_inchesZtightr)   )alpharo   )rj   rk   r   r   printr\   rl   rm   r]   ZgcaZset_autoscale_onr0   r3   r.   Zconcatenaterandomrn   r4   r2   r   Zblend_imagesr_   r   )r"   rh   rn   ru   rR   blendr#   rp   annsZsorted_annsZaxZimgra   r?   Z
color_maskarrayr$   r$   r%   	show_annsH  sP    






(
   zSamGeo.show_annsRGBc                 C   s   t |tr^|drt|}tj|s8td| d|| _t	
|}t	|t	j}|| _nt |tjrlntd| jj||d dS )zSet the input image as a numpy array.

        Args:
            image (np.ndarray): The input image as a numpy array.
            image_format (str, optional): The image format, can be RGB or BGR. Defaults to "RGB".
        rD   rE   rF   z3Input image must be either a path or a numpy array.)image_formatN)rG   rH   rI   rJ   r   r   r   rK   r   r5   rM   rN   rO   r   r0   rP   r!   	set_image)r"   r   r}   r$   r$   r%   r~     s    


zSamGeo.set_imagec           	      K   sp   | j dkrtd|dkr(| j jdd}| j| | }|| _t||| jfd|i| |dk	rlt|||d dS )a  Save the predicted mask to the output path.

        Args:
            output (str): The path to the output image.
            index (int, optional): The index of the mask to save. Defaults to None,
                which will save the mask with the highest score.
            mask_multiplier (int, optional): The mask multiplier for the output mask, which is usually a binary mask [0, 1].
            vector (str, optional): The path to the output vector file. Defaults to None.
            dtype (np.dtype, optional): The data type of the output image. Defaults to np.float32.
            simplify_tolerance (float, optional): The maximum allowed geometry displacement.
                The higher this value, the smaller the number of vertices in the resulting geometry.

        Nz1No predictions found. Please run predict() first.r   )rn   r+   )simplify_tolerance)r   rK   Zargmaxr   r   r_   r   raster_to_vector)	r"   rR   r`   r9   r+   Zvectorr   r#   rz   r$   r$   r%   save_prediction  s    
zSamGeo.save_predictionfloat32c                 K   s>  t |tr8t|}|jdk	r(|d}|jjj	 }n8t |t
rpddl}||}tj|dd}|jjj	 }t |trt|}t |t
rt|}t| dr| j}t| dr| j}|dk	r|dk	rt| j||}t |trt|}|dk	r$|dkr
dgt| }nt |tr$|gt| }t |trpt|t|krft|dkr^|t| }ntd	t|}| j}d}t |tr|dk	rt| j||}t|}t |d tr|dddf }n*tj|| jd
}|j || j!j"dd }n@t |tr6|dkr6t|}t |d tr6|dddf }|| _#|dksrt|dksrt|dkrt |d t$rt |trt |d tr|d }|%||||||\}}}n|j&|||dd\}}}|| _'|| _(|| _)|dk	r*|dks t |d ts| j*||	|
|f| n| j+|	||
||d |r:|||fS dS )a  Predict masks for the given input prompts, using the currently set image.

        Args:
            point_coords (str | dict | list | np.ndarray, optional): A Nx2 array of point prompts to the
                model. Each point is in (X,Y) in pixels. It can be a path to a vector file, a GeoJSON
                dictionary, a list of coordinates [lon, lat], or a numpy array. Defaults to None.
            point_labels (list | int | np.ndarray, optional): A length N array of labels for the
                point prompts. 1 indicates a foreground point and 0 indicates a background point.
            point_crs (str, optional): The coordinate reference system (CRS) of the point prompts.
            boxes (list | np.ndarray, optional): A length 4 array given a box prompt to the
                model, in XYXY format.
            mask_input (np.ndarray, optional): A low resolution mask input to the model, typically
                coming from a previous prediction iteration. Has form 1xHxW, where for SAM, H=W=256.
                multimask_output (bool, optional): If true, the model will return three masks.
                For ambiguous input prompts (such as a single click), this will often
                produce better masks than a single prediction. If only a single
                mask is needed, the model's predicted quality score can be used
                to select the best mask. For non-ambiguous prompts, such as multiple
                input prompts, multimask_output=False can give better results.
            return_logits (bool, optional): If true, returns un-thresholded masks logits
                instead of a binary mask.
            output (str, optional): The path to the output image. Defaults to None.
            index (index, optional): The index of the mask to save. Defaults to None,
                which will save the mask with the highest score.
            mask_multiplier (int, optional): The mask multiplier for the output mask, which is usually a binary mask [0, 1].
            dtype (np.dtype, optional): The data type of the output image. Defaults to np.float32.
            return_results (bool, optional): Whether to return the predicted masks, scores, and logits. Defaults to False.

        Nz	epsg:4326r   ZGeoJSON)Zdriverpoint_coordspoint_labelsr   zGThe length of point_labels must be equal to the length of point_coords.r      rs   T)r   r   boxesmultimask_output)	save_args),rG   rH   Zgpd	read_filecrsZto_crsZgeometryZboundsvaluestolistdictjsondumpsZvector_to_geojsonZgeojson_to_coordshasattrr   r   Zcoords_to_xyr   listr0   rz   r\   intrK   r!   Z
bbox_to_xyr   Ztensorr   	transformZapply_boxes_torchr   r.   r   floatpredictZpredict_torchr   r   r   r   tensor_to_numpy)r"   r   r   r   Z	point_crs
mask_inputr   return_logitsrR   r`   r9   r+   Zreturn_resultsr#   gdfr   Zgeojsonr!   Zinput_boxesZcoordsr   r   r   r$   r$   r%   r     s    .















 
6	
    zSamGeo.predictr2   c                 C   s  | j }| j}| j}t|}	|dkr(d}|dd|ddddf }|d}|dksbt|dkrntd dS tj|	d |d}
t	t
||D ]D\}\}}t|tjr|  |}|
|dk|d  |7 }
q|
dk| }
|dk	rt|
|| jfd|i| n|
S dS )a  Convert the predicted masks from tensors to numpy arrays.

        Args:
            index (index, optional): The index of the mask to save. Defaults to None,
                which will save the mask with the highest score.
            output (str, optional): The path to the output image. Defaults to None.
            mask_multiplier (int, optional): The mask multiplier for the output mask, which is usually a binary mask [0, 1].
            dtype (np.dtype, optional): The data type of the output image. Defaults to np.uint8.
            save_args (dict, optional): Optional arguments for saving the output image. Defaults to {}.

        Returns:
            np.ndarray: The predicted mask as a numpy array.
        Nr   r   zNo objects found in the image.).r   r*   r+   )r   r   r   r0   rz   Zsqueezer\   rv   Z
zeros_liker^   ziprG   r   ZTensorr   numpyr4   r_   r   )r"   r`   rR   r9   r+   r   r   r   Z	image_pilZimage_npZmask_overlayiboxr@   r$   r$   r%   r   _  s8    

 
zSamGeo.tensor_to_numpy	SATELLITEc                 K   s   t | f|||d|S )a  Show the interactive map.

        Args:
            basemap (str, optional): The basemap. It can be one of the following: SATELLITE, ROADMAP, TERRAIN, HYBRID.
            repeat_mode (bool, optional): Whether to use the repeat mode for draw control. Defaults to True.
            out_dir (str, optional): The path to the output directory. Defaults to None.

        Returns:
            leafmap.Map: The map object.
        )basemaprepeat_modeout_dir)Zsam_map_gui)r"   r   r   r   r#   r$   r$   r%   show_map  s      zSamGeo.show_mapr   r)   r   r   r   r)      c           	      C   sj   | j dkrtd| j }t||||\}}|| _|| _|| }dgt| dgt|  }|| _|| _dS )a  Show a canvas to collect foreground and background points.

        Args:
            image (str | np.ndarray): The input image.
            fg_color (tuple, optional): The color for the foreground points. Defaults to (0, 255, 0).
            bg_color (tuple, optional): The color for the background points. Defaults to (0, 0, 255).
            radius (int, optional): The radius of the points. Defaults to 5.

        Returns:
            tuple: A tuple of two lists of foreground and background points.
        NzPlease run set_image() first.r   r   )r   rK   show_canvas	fg_points	bg_pointsr\   r   r   )	r"   Zfg_colorZbg_colorZradiusr   r   r   r   r   r$   r$   r%   r     s    
zSamGeo.show_canvasc                 C   s   t j rt j  dS )zClear the CUDA cache.N)r   r
   r   r   )r"   r$   r$   r%   clear_cuda_cache  s    
zSamGeo.clear_cuda_cachec                 K   s   t || f|S N)image_to_image)r"   r   r#   r$   r$   r%   r     s    zSamGeo.image_to_imagec                 C   s(   t ||d |d |d |d ||}|S )Nr   r   )Z	draw_tile)r"   r   Zpt1Zpt2Zzoomdistr   r$   r$   r%   download_tms_as_tiff  s    $zSamGeo.download_tms_as_tiffc                 K   s   t ||fd|i| dS )ag  Save the result to a vector file.

        Args:
            image (str): The path to the image file.
            output (str): The path to the vector file.
            simplify_tolerance (float, optional): The maximum allowed geometry displacement.
                The higher this value, the smaller the number of vertices in the resulting geometry.
        r   Nr   )r"   r   rR   r   r#   r$   r$   r%   r     s    
zSamGeo.raster_to_vectorc                 K   s   t ||fd|i| dS )al  Convert a tiff file to a gpkg file.

        Args:
            tiff_path (str): The path to the tiff file.
            output (str): The path to the vector file.
            simplify_tolerance (float, optional): The maximum allowed geometry displacement.
                The higher this value, the smaller the number of vertices in the resulting geometry.
        r   Nr   r"   Z	tiff_pathrR   r   r#   r$   r$   r%   tiff_to_vector  s    
 zSamGeo.tiff_to_vectorc                 K   s   t ||fd|i| dS )aj  Convert a tiff file to a gpkg file.

        Args:
            tiff_path (str): The path to the tiff file.
            output (str): The path to the gpkg file.
            simplify_tolerance (float, optional): The maximum allowed geometry displacement.
                The higher this value, the smaller the number of vertices in the resulting geometry.
        r   N)Zraster_to_gpkgr   r$   r$   r%   tiff_to_gpkg  s    
 zSamGeo.tiff_to_gpkgc                 K   s   t ||fd|i| dS )aj  Convert a tiff file to a shapefile.

        Args:
            tiff_path (str): The path to the tiff file.
            output (str): The path to the shapefile.
            simplify_tolerance (float, optional): The maximum allowed geometry displacement.
                The higher this value, the smaller the number of vertices in the resulting geometry.
        r   N)Zraster_to_shpr   r$   r$   r%   tiff_to_shp  s    
 zSamGeo.tiff_to_shpc                 K   s   t ||fd|i| dS )ap  Convert a tiff file to a GeoJSON file.

        Args:
            tiff_path (str): The path to the tiff file.
            output (str): The path to the GeoJSON file.
            simplify_tolerance (float, optional): The maximum allowed geometry displacement.
                The higher this value, the smaller the number of vertices in the resulting geometry.
        r   N)Zraster_to_geojsonr   r$   r$   r%   tiff_to_geojson  s    
 zSamGeo.tiff_to_geojson)r   TNNN)Tr'   r)   )NTFNr)   T)NTTNr)   )rb   re   rf   T)rb   rf   rr   NT)r|   )NNNNNTFNNr)   r   F)r   TN)r   r   r   )N)N)N)N)N)__name__
__module____qualname____doc__r&   rC   r/   rQ   rq   r{   r~   r0   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r$   r$   r$   r%   r      s        
Y   
/      
H     
T       
     
G

&            
     
:





r   c                       sD   e Zd Zdd Z fddZd fdd		Zd
d ZdddZ  ZS )SamGeoPredictorc                 C   s$   ddl m} || _||jj| _d S )Nr   )ResizeLongestSide)Z!segment_anything.utils.transformsr   modelZimage_encoderZimg_sizer   )r"   Z	sam_modelr   r$   r$   r%   r&     s    zSamGeoPredictor.__init__c                    s   t t| | d S r   )superr   r~   )r"   r   	__class__r$   r%   r~     s    zSamGeoPredictor.set_imageNTFc	                    s   |r|rd| _ t|}	t|d |d | j |	}
t|d |d | j |	}t|
d |d g}t|
d |d g}t|||}|| _|d |d  | _|d |d  | _t	|| j| j| _
tt| ||||||\}}}|||fS )Nz	EPSG:4326r   r   r   r(   )r   Zget_crsZtransform_coordsr0   rz   Zget_pixel_coordsgeo_boxwidthheightZset_transformgeo_transformr   r   r   )r"   src_fpr   r   r   r   r   r   r   Zdst_crsswneZxsZysr   Ziou_predictionsZlow_res_masksr   r$   r%   r     s*    
     
zSamGeoPredictor.predictc                 C   s(   t |}t|||| j| j| j| j d S r   )Zget_profileZwrite_rasterr   r   r   r   )r"   r   dst_fpr   Zprofiler$   r$   r%   masks_to_geotiff=  s    z SamGeoPredictor.masks_to_geotiffr   c                 C   s   t ||}t|| |S r   )Zget_featuresZwrite_features)r"   r   r   Zbidxr   r$   r$   r%   geotiff_to_geojsonI  s    

z"SamGeoPredictor.geotiff_to_geojson)NNNNNNTF)r   )	r   r   r   r&   r~   r   r   r   __classcell__r$   r$   r   r%   r     s   	        r   )r   r   r5   r   r   r0   Zsegment_anythingr   r   r   commonr   r   r$   r$   r$   r%   <module>   s         
