o
    Wh6                     @   sd   d dl mZ d dlZd dlmZ d dlmZmZ d dlm	Z	m
Z
 d dlmZmZ G dd deZdS )	    )PathN)DetectionValidator)LOGGERops)
OBBMetricsbatch_probiou)output_to_rotated_targetplot_imagesc                       sf   e Zd ZdZd fdd	Z fddZdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Z  ZS )OBBValidatora  
    A class extending the DetectionValidator class for validation based on an Oriented Bounding Box (OBB) model.

    This validator specializes in evaluating models that predict rotated bounding boxes, commonly used for aerial and
    satellite imagery where objects can appear at various orientations.

    Attributes:
        args (dict): Configuration arguments for the validator.
        metrics (OBBMetrics): Metrics object for evaluating OBB model performance.
        is_dota (bool): Flag indicating whether the validation dataset is in DOTA format.

    Methods:
        init_metrics: Initialize evaluation metrics for YOLO.
        _process_batch: Process batch of detections and ground truth boxes to compute IoU matrix.
        _prepare_batch: Prepare batch data for OBB validation.
        _prepare_pred: Prepare predictions with scaled and padded bounding boxes.
        plot_predictions: Plot predicted bounding boxes on input images.
        pred_to_json: Serialize YOLO predictions to COCO json format.
        save_one_txt: Save YOLO detections to a txt file in normalized coordinates.
        eval_json: Evaluate YOLO output in JSON format and return performance statistics.

    Examples:
        >>> from ultralytics.models.yolo.obb import OBBValidator
        >>> args = dict(model="yolo11n-obb.pt", data="dota8.yaml")
        >>> validator = OBBValidator(args=args)
        >>> validator(model=args["model"])
    Nc                    s0   t  ||||| d| j_t| jdd| _dS )a  
        Initialize OBBValidator and set task to 'obb', metrics to OBBMetrics.

        This constructor initializes an OBBValidator instance for validating Oriented Bounding Box (OBB) models.
        It extends the DetectionValidator class and configures it specifically for the OBB task.

        Args:
            dataloader (torch.utils.data.DataLoader, optional): Dataloader to be used for validation.
            save_dir (str | Path, optional): Directory to save results.
            pbar (bool, optional): Display progress bar during validation.
            args (dict, optional): Arguments containing validation parameters.
            _callbacks (list, optional): List of callback functions to be called during validation.
        obbT)save_dirplotN)super__init__argstaskr   r   metrics)self
dataloaderr   pbarr   
_callbacks	__class__ S/var/www/vscode/kcb/lib/python3.10/site-packages/ultralytics/models/yolo/obb/val.pyr   *   s   zOBBValidator.__init__c                    s6   t  | | j| jjd}t|tod|v | _dS )z'Initialize evaluation metrics for YOLO. DOTAN)	r   init_metricsdatagetr   split
isinstancestris_dota)r   modelvalr   r   r   r   <   s   zOBBValidator.init_metricsc                 C   sR   t |tj|ddddf |ddddf gdd}| |dddf ||S )ao  
        Perform computation of the correct prediction matrix for a batch of detections and ground truth bounding boxes.

        Args:
            detections (torch.Tensor): A tensor of shape (N, 7) representing the detected bounding boxes and associated
                data. Each detection is represented as (x1, y1, x2, y2, conf, class, angle).
            gt_bboxes (torch.Tensor): A tensor of shape (M, 5) representing the ground truth bounding boxes. Each box is
                represented as (x1, y1, x2, y2, angle).
            gt_cls (torch.Tensor): A tensor of shape (M,) representing class labels for the ground truth bounding boxes.

        Returns:
            (torch.Tensor): The correct prediction matrix with shape (N, 10), which includes 10 IoU (Intersection over
                Union) levels for each detection, indicating the accuracy of predictions compared to the ground truth.

        Examples:
            >>> detections = torch.rand(100, 7)  # 100 sample detections
            >>> gt_bboxes = torch.rand(50, 5)  # 50 sample ground truth boxes
            >>> gt_cls = torch.randint(0, 5, (50,))  # 50 ground truth class labels
            >>> correct_matrix = OBBValidator._process_batch(detections, gt_bboxes, gt_cls)

        Note:
            This method relies on `batch_probiou` to calculate IoU between detections and ground truth bounding boxes.
        N   dim   )r   torchcatmatch_predictions)r   
detections	gt_bboxesgt_clsiour   r   r   _process_batchB   s   8zOBBValidator._process_batchc           	      C   s   |d |k}|d |  d}|d | }|d | }|d jdd }|d	 | }t|rM|d
ddf tj|| jdg d  tj||||dd |||||dS )a  
        Prepare batch data for OBB validation with proper scaling and formatting.

        Args:
            si (int): Batch index to process.
            batch (dict): Dictionary containing batch data with keys:
                - batch_idx: Tensor of batch indices
                - cls: Tensor of class labels
                - bboxes: Tensor of bounding boxes
                - ori_shape: Original image shapes
                - img: Batch of images
                - ratio_pad: Ratio and padding information

        This method filters the batch data for a specific batch index, extracts class labels and bounding boxes,
        and scales the bounding boxes to the original image dimensions.
        	batch_idxclsr'   bboxes	ori_shapeimg   N	ratio_pad.r&   )device)   r   r;   r   Tr9   xywh)r4   bboxr6   imgszr9   )	squeezeshapelenmul_r+   tensorr:   r   scale_boxes)	r   sibatchidxr4   r>   r6   r?   r9   r   r   r   _prepare_batch]   s   *zOBBValidator._prepare_batchc                 C   s<   |  }tj|d |ddddf |d |d dd |S )a8  
        Prepare predictions by scaling bounding boxes to original image dimensions.

        This method takes prediction tensors containing bounding box coordinates and scales them from the model's
        input dimensions to the original image dimensions using the provided batch information.

        Args:
            pred (torch.Tensor): Prediction tensor containing bounding box coordinates and other information.
            pbatch (dict): Dictionary containing batch information with keys:
                - imgsz (tuple): Model input image size.
                - ori_shape (tuple): Original image shape.
                - ratio_pad (tuple): Ratio and padding information for scaling.

        Returns:
            (torch.Tensor): Scaled prediction tensor with bounding boxes in original image dimensions.
        r?   Nr&   r6   r9   Tr<   )cloner   rE   )r   predpbatchprednr   r   r   _prepare_predy   s
   &zOBBValidator._prepare_predc                 C   sF   t |d gt|| jjdR |d | jd| d | j| jd dS )aU  
        Plot predicted bounding boxes on input images and save the result.

        Args:
            batch (dict): Batch data containing images, file paths, and other metadata.
            preds (list): List of prediction tensors for each image in the batch.
            ni (int): Batch index used for naming the output file.

        Examples:
            >>> validator = OBBValidator()
            >>> batch = {"img": images, "im_file": paths}
            >>> preds = [torch.rand(10, 7)]  # Example predictions for one image
            >>> validator.plot_predictions(batch, preds, 0)
        r7   )max_detim_file	val_batchz	_pred.jpg)pathsfnamenameson_plotN)r	   r   r   rO   r   rT   rU   )r   rG   predsnir   r   r   plot_predictions   s   zOBBValidator.plot_predictionsc           
   	   C   s   t |j}| rt|n|}tj|ddddf |ddddf gdd}t|dd}t	t
| | D ]0\}\}}	| j|| jt||df   t||df  ddd |D d	d |	D d
 q<dS )a  
        Convert YOLO predictions to COCO JSON format with rotated bounding box information.

        Args:
            predn (torch.Tensor): Prediction tensor containing bounding box coordinates, confidence scores,
                class predictions, and rotation angles with shape (N, 6+) where the last column is the angle.
            filename (str | Path): Path to the image file for which predictions are being processed.

        Notes:
            This method processes rotated bounding box predictions and converts them to both rbox format
            (x, y, w, h, angle) and polygon format (x1, y1, x2, y2, x3, y3, x4, y4) before adding them
            to the JSON dictionary.
        Nr&   r'   r(      r*   c                 S      g | ]}t |d qS    round.0xr   r   r   
<listcomp>       z-OBBValidator.pred_to_json.<locals>.<listcomp>c                 S   rZ   r[   r]   r_   r   r   r   rb      rc   )image_idcategory_idscorerboxpoly)r   stem	isnumericintr+   r,   r   xywhr2xyxyxyxyview	enumerateziptolistjdictappend	class_mapitemr^   )
r   rM   filenameri   rd   rg   rh   irbr   r   r   pred_to_json   s   
2"zOBBValidator.pred_to_jsonc           	      C   s   ddl }ddlm} tj|ddddf |ddddf gdd}tj||ddddf gdd}||j|d |d f|jd	d| j|d
j||d dS )a*  
        Save YOLO OBB (Oriented Bounding Box) detections to a text file in normalized coordinates.

        Args:
            predn (torch.Tensor): Predicted detections with shape (N, 7) containing bounding boxes, confidence scores,
                class predictions, and angles in format (x, y, w, h, conf, cls, angle).
            save_conf (bool): Whether to save confidence scores in the text file.
            shape (tuple): Original image shape in format (height, width).
            file (Path | str): Output file path to save detections.

        Examples:
            >>> validator = OBBValidator()
            >>> predn = torch.tensor([[100, 100, 50, 30, 0.9, 0, 45]])  # One detection: x,y,w,h,conf,cls,angle
            >>> validator.save_one_txt(predn, True, (640, 480), "detection.txt")
        r   N)Resultsr&   r'   r(      r;   )dtype)pathrT   r   )	save_conf)	numpyultralytics.engine.resultsrz   r+   r,   zerosuint8rT   save_txt)	r   rM   r~   rA   filenprz   rboxesr   r   r   r   save_one_txt   s   2"
zOBBValidator.save_one_txtc                 C   s"  | j jr| jrt| jrddl}ddl}ddlm} | j	d }| j	d }|j
ddd |t|}td| d	 |D ]m}|d
 }	|d }
| j|d d  dd}|d }t|d|   dddd;}||	 d|
 d|d  d|d  d|d  d|d  d|d  d|d  d|d  d|d  d W d   n1 sw   Y  q@| j	d }|j
ddd |t}td| d	 |D ]R}|d
 dd }	|d }d!d" |||d
 d d#D \}}|d$ |d |d d }}
}|d  |7  < |d  |7  < ||
|g ||	 | q| D ]\}	}t|}t|ddddf  d }|ddddf | }|dddf }|ddddf  }|ddddf  |7  < t||d%}|| }t |ddddf !d&d'}tj"||ddddf gd&d(# D ]u}| jt$|d&  dd}d)d* |dd+ D }t%|d+ d}
t|d|   dddd;}||	 d|
 d|d  d|d  d|d  d|d  d|d  d|d  d|d  d|d  d W d   n	1 sw   Y  qq |S ),zHEvaluate YOLO output in JSON format and save predictions in DOTA format.r   N)defaultdictzpredictions.jsonpredictions_txtT)parentsexist_okz'Saving predictions with DOTA format to z...rd   rf   re   r;    -rh   Task1_z.txtazutf-8)encodingr8   r\   r&   r*   r{      
predictions_merged_txtz.Saving merged predictions with DOTA format to __z	\d+___\d+c                 s   s    | ]}t |V  qd S )N)rk   )r`   cr   r   r   	<genexpr>  s    z)OBBValidator.eval_json.<locals>.<genexpr>___rg   g333333?r'   rY   r(   c                 S   rZ   r[   r]   )r`   rv   r   r   r   rb     rc   z*OBBValidator.eval_json.<locals>.<listcomp>)&r   	save_jsonr#   rB   rq   jsonrecollectionsr   r   mkdirloadopenr   inforT   replace
writelineslistr    compilefindallextendrr   itemsr+   rD   maxrt   rJ   r   nms_rotatedrl   rm   r,   rp   rk   r^   )r   statsr   r   r   	pred_jsonpred_txtr   drd   rf   	classnamepfpred_merged_txtmerged_resultspatternra   yr>   r4   max_whr   scoresrx   rv   r   r   r   	eval_json   sf   

 h

( 
""* hzOBBValidator.eval_json)NNNNN)__name__
__module____qualname____doc__r   r   r2   rI   rN   rX   ry   r   r   __classcell__r   r   r   r   r
      s    r
   )pathlibr   r+   ultralytics.models.yolo.detectr   ultralytics.utilsr   r   ultralytics.utils.metricsr   r   ultralytics.utils.plottingr   r	   r
   r   r   r   r   <module>   s   