o
    Ďi                      @   s   d Z dgZddlZddlmZmZ ddlmZ ddlm	Z	 ddl
Zddl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 zdd
lmZ W n eyZ   ddlmZ Y nw ddlmZ ddlmZ ddl m!Z! ddl m"Z" G dd dZ#dS )z%Detector functionality of SpeciesNet.SpeciesNetDetector    N)AnyOptional)logging)format_timespan)	letterbox)non_max_suppression)
xyxy2xywhn)scale_boxes)scale_coords)	Detection)Failure)	ModelInfo)PreprocessedImagec                   @   s   e Zd ZdZdZdZdZdeddfdd	Zd
e	e
jj de	e fddZdee dee fddZded
e	e deeef fddZdS )r   z!Detector component of SpeciesNet.i   @   g{Gz?
model_namereturnNc                 C   s  t   }t|| _tj rd| _ntjj rd| _nd| _| jdkr7tj	| jj
| jdd}|d  | _ntj	| jj
dd}|d  | j| _| j  | j D ]}d|_qU| j D ]}t|tjjrqt|dsqd	|_q`t   }td
t|| | j  d	S )a   Loads the detector resources.

        Code adapted from: https://github.com/agentmorris/MegaDetector
        which was released under the MIT License:
        https://github.com/agentmorris/MegaDetector/blob/main/LICENSE

        Args:
            model_name:
                String value identifying the model to be loaded. It can be a Kaggle
                identifier (starting with `kaggle:`), a HuggingFace identifier (starting
                with `hf:`) or a local folder to load the model from.
        cudampscpuF)map_locationweights_onlymodel)r   recompute_scale_factorNz&Loaded SpeciesNetDetector in %s on %s.)timer   
model_infotorchr   is_availabledevicebackendsr   loaddetectorfloatr   toeval
parametersrequires_gradmodules
isinstancennUpsamplehasattrr   r   infor   upper)selfr   
start_time
checkpointparammend_time r4   O/home/jeff/fluffinator/venv/lib/python3.10/site-packages/speciesnet/detector.py__init__5   s:   




zSpeciesNetDetector.__init__imgc                 C   s:   |du rdS t t|tjtjddd }t||j|jS )a  Preprocesses an image according to this detector's needs.

        Args:
            img:
                PIL image to preprocess. If `None`, no preprocessing is performed.

        Returns:
            A preprocessed image, or `None` if no PIL image was provided initially.
        NT)	new_shapestrideautor   )	yolov5_letterboxnpasarrayr   IMG_SIZESTRIDEr   widthheight)r.   r7   img_arrr4   r4   r5   
preprocessm   s   zSpeciesNetDetector.preprocess
yolo_xywhnc                 C   s0   |\}}}}||d  }||d  }||||gS )ag  Converts bbox XYWHN coordinates from YOLO's to MegaDetector's format.

        Args:
            yolo_xywhn:
                List of bbox coordinates in YOLO format, i.e.
                [x_center, y_center, width, height].

        Returns:
            List of bbox coordinates in MegaDetector format, i.e.
            [x_min, y_min, width, height].
        g       @r4   )r.   rD   x_centery_centerr@   rA   x_miny_minr4   r4   r5   _convert_yolo_xywhn_to_md_xywhn   s   z2SpeciesNetDetector._convert_yolo_xywhn_to_md_xywhnfilepathc                 C   s  |du r|t jjgdS t|jd }|g d}t|d }|	| j
}| j|ddd }| j
dkr;| }t|tjd	}|d }g }t|jd
d |ddddf |j|jf |ddddf< |D ]\}|dd }|j}	|	dkr|dddf }t||j|jd}
|	dkr|
d }
| |
 }|d  }tt|d  d }t|}|du rtd| qk| ||j!||d qkt"|dd dd}||dS )a(  Runs inference on a given preprocessed image.

        Code adapted from: https://github.com/agentmorris/MegaDetector
        which was released under the MIT License:
        https://github.com/agentmorris/MegaDetector/blob/main/LICENSE

        Args:
            filepath:
                Location of image to run inference on. Used for reporting purposes only,
                and not for loading the image.
            img:
                Preprocessed image to run inference on. If `None`, a failure message is
                reported back.

        Returns:
            A dict containing either the detections above a fixed confidence threshold
            for the given image (in decreasing order of confidence scores), or a failure
            message if no preprocessed image was provided.
        N)rJ   failures   )   r      r   F)augmentr   )
prediction
conf_thresrM      rN   )wh   zInvalid detection class: %s)categorylabelconfbboxc                 S   s   | d S )NrX   r4   )detr4   r4   r5   <lambda>   s    z,SpeciesNetDetector.predict.<locals>.<lambda>T)keyreverse)rJ   
detections)#r   DETECTORnamer   
from_numpyarrpermute	unsqueezer"   r#   r   r   r   yolov5_non_max_suppressionr   DETECTION_THRESHOLDyolov5_scale_boxesshapeorig_height
orig_widthroundndimyolov5_xyxy2xywhnrI   tolistitemstrintr   from_categoryr   errorappendvaluesorted)r.   rJ   r7   
img_tensorbatch_tensorresultsr^   resultxyxyndimsxywhnrY   rX   rV   rW   r4   r4   r5   predict   sd   



zSpeciesNetDetector.predict)__name__
__module____qualname____doc__r>   r?   rf   rp   r6   r   PILImager   rC   listr"   rI   dictr   r~   r4   r4   r4   r5   r   .   s    8
)$r   __all__r   typingr   r   abslr   humanfriendlyr   numpyr<   	PIL.Imager   r   torch.backendstorch.backends.mpsyolov5.utils.augmentationsr   r;   yolov5.utils.generalr   re   r	   rm   r
   rg   ImportErrorr   speciesnet.constantsr   r   speciesnet.utilsr   r   r   r4   r4   r4   r5   <module>   s2   