
    /j8                        d dl mZ d dlmZ d dlmZ d dl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 d d	lmZ  G d
 de
          ZdS )    )annotations)Path)AnyN)DetectionValidator)LOGGERops)
OBBMetricsbatch_probiou)TorchNMS)plot_imagesc                  v     e Zd ZdZd&d' fdZd( fd
Zd)dZd* fdZd+dZd,dZ	d-dZ
d.d"Zd/d#Zd0d%Z xZS )1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 for evaluation against ground truth.
        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="yolo26n-obb.pt", data="dota8.yaml")
        >>> validator = OBBValidator(args=args)
        >>> validator(model=args["model"])
    N
_callbacksdict | NonereturnNonec                    t                                          ||||           d| j        _        t	                      | _        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.
            args (dict, optional): Arguments containing validation parameters.
            _callbacks (dict, optional): Dictionary of callback functions to be called during validation.
        obbN)super__init__argstaskr	   metrics)self
dataloadersave_dirr   r   	__class__s        d/home/longshao/multi-rider-rag/.venv/lib/python3.11/site-packages/ultralytics/models/yolo/obb/val.pyr   zOBBValidator.__init__.   s;     	XtZ@@@	!||    modeltorch.nn.Modulec                    t                                          |           | j                            | j        j        d          }t          |t                    od|v | _        d| j	        _
        dS )zInitialize evaluation metrics for YOLO obb validation.

        Args:
            model (torch.nn.Module): Model to validate.
         DOTAr   N)r   init_metricsdatagetr   split
isinstancestris_dotaconfusion_matrixr   )r   r    valr   s      r   r%   zOBBValidator.init_metrics>   sa     	U###immDIOR00!#s++=#%*"""r   predsdict[str, torch.Tensor]batchdict[str, np.ndarray]c                   |d         j         d         dk    s|d         j         d         dk    r5dt          j        |d         j         d         | j        ft                    iS t          |d         |d                   }d|                     |d         |d         |                                                                          iS )a  Compute the correct prediction matrix for a batch of detections and ground truth bounding boxes.

        Args:
            preds (dict[str, torch.Tensor]): Prediction dictionary containing 'cls' and 'bboxes' keys with detected
                class labels and bounding boxes.
            batch (dict[str, torch.Tensor]): Batch dictionary containing 'cls' and 'bboxes' keys with ground truth class
                labels and bounding boxes.

        Returns:
            (dict[str, np.ndarray]): Dictionary containing 'tp' key with the correct prediction matrix as a numpy array
                with shape (N, 10), which includes 10 IoU levels for each detection, indicating the accuracy of
                predictions compared to the ground truth.

        Examples:
            >>> preds = {"cls": torch.randint(0, 5, (100,)), "bboxes": torch.rand(100, 5)}
            >>> batch = {"cls": torch.randint(0, 5, (50,)), "bboxes": torch.rand(50, 5)}
            >>> correct_matrix = validator._process_batch(preds, batch)
        clsr   tpdtypebboxes)	shapenpzerosniouboolr
   match_predictionscpunumpy)r   r.   r0   ious       r   _process_batchzOBBValidator._process_batchI   s    & <a A%%u);A)>!)C)C"(E%L$6q$949#ETRRRSSE(OU8_==d,,U5\5<MMQQSSYY[[\\r   torch.Tensorlist[dict[str, torch.Tensor]]c                    t                                          |          }|D ]6}t          j        |d         |                    d          gd          |d<   7|S )zPostprocess OBB predictions.

        Args:
            preds (torch.Tensor): Raw predictions from the model.

        Returns:
            (list[dict[str, torch.Tensor]]): Processed predictions with angle information concatenated to bboxes.
        r7   extradim)r   postprocesstorchcatpop)r   r.   predr   s      r   rI   zOBBValidator.postprocessa   sb     ##E** 	T 	TD"YX8I8I'JPRSSSDNNr   siintdict[str, Any]c                   |d         |k    }|d         |                              d          }|d         |         }|d         |         }|d         j        dd         }|d	         |         }|j        d
         r@|dddf                             t          j        || j                  g d                    ||||||d         |         dS )a~  Prepare batch data for OBB validation with proper scaling and formatting.

        Args:
            si (int): Sample index within the batch.
            batch (dict[str, Any]): 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

        Returns:
            (dict[str, Any]): Prepared batch data with scaled bounding boxes and metadata.
        	batch_idxr3   rF   r7   	ori_shapeimg   N	ratio_padr   .   )device)   r   rY   r   im_file)r3   r7   rS   imgszrV   rZ   )squeezer8   mul_rJ   tensorrX   )	r   rN   r0   idxr3   bboxrS   r[   rV   s	            r   _prepare_batchzOBBValidator._prepare_batcho   s      K B&El3''++Xs#+&r*	e"122&+&r*	9Q< 	VbqbMu|E$+FFF|||TUUU""Y'+
 
 	
r   nic           	     8   sdS t                    D ]%\  }}t          j        |d                   |z  |d<   &d                                         }fd|D             }t	          |d         ||d         | j        d| d	z  | j        | j        
           dS )a  Plot predicted bounding boxes on input images and save the result.

        Args:
            batch (dict[str, Any]): Batch data containing images, file paths, and other metadata.
            preds (list[dict[str, torch.Tensor]]): List of prediction dictionaries 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 = [{"bboxes": torch.rand(10, 5), "cls": torch.zeros(10), "conf": torch.rand(10)}]
            >>> validator.plot_predictions(batch, preds, 0)
        NconfrR   r   c                X    i | ]%t          j        fd D             d          &S )c                     g | ]
}|         S  rg   ).0xks     r   
<listcomp>z<OBBValidator.plot_predictions.<locals>.<dictcomp>.<listcomp>   s    &;&;&;qt&;&;&;r   r   rG   )rJ   rK   )rh   rj   r.   s    @r   
<dictcomp>z1OBBValidator.plot_predictions.<locals>.<dictcomp>   s@    RRREI&;&;&;&;U&;&;&;CCCRRRr   rT   rZ   	val_batchz	_pred.jpg)imageslabelspathsfnamenameson_plot)	enumeraterJ   	ones_likekeysr   r   rr   rs   )r   r0   r.   rb   irM   rv   batched_predss     `     r   plot_predictionszOBBValidator.plot_predictions   s      	F '' 	B 	BGAt %V = = ADQx}}RRRRTRRR< 	"-";b";";";;*L	
 	
 	
 	
 	
 	
r   prednpbatchc           
        t          |d                   }|j        }|                                rt          |          n|}|d         }t	          j        |                              dd          }t          |                                |                                |d                                         |d                                                   D ]g\  }}	}
}| j	        
                    ||j        | j        t          |                   t          |
d          d |D             d	 |	D             d
           hdS )a  Convert YOLO predictions to COCO JSON format with rotated bounding box information.

        Args:
            predn (dict[str, torch.Tensor]): Prediction dictionary containing 'bboxes', 'conf', and 'cls' keys with
                bounding box coordinates, confidence scores, and class predictions.
            pbatch (dict[str, Any]): Batch dictionary containing 'imgsz', 'ori_shape', 'ratio_pad', and 'im_file'.

        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.
        rZ   r7   rF      rd   r3      c                .    g | ]}t          |d           S    roundrh   ri   s     r   rk   z-OBBValidator.pred_to_json.<locals>.<listcomp>        444QU1a[[444r   c                .    g | ]}t          |d           S r   r   r   s     r   rk   z-OBBValidator.pred_to_json.<locals>.<listcomp>   r   r   )image_id	file_namecategory_idscorerboxpolyN)r   stem	isnumericrO   r   xywhr2xyxyxyxyviewziptolistjdictappendname	class_mapr   )r   rz   r{   pathr   r   r   r   rbscs               r   pred_to_jsonzOBBValidator.pred_to_json   s4    F9%&&y $ 0 0:3t999dX!$'',,R33dkkmmT[[]]E&M<P<P<R<RTYZ_T`TgTgTiTijj 
	 
	JAq!QJ (!%#'>#a&&#9"1a[[44!44444!444 	 	 	 	
	 
	r   	save_confr<   r8   tuple[int, int]filer   c                P   ddl }ddlm}  | |j        |d         |d         f|j                  d| j        t          j        |d         |d                             d          |d	                             d          gd
                    	                    ||           dS )a  Save YOLO OBB detections to a text file in normalized coordinates.

        Args:
            predn (dict[str, torch.Tensor]): Prediction dictionary containing 'bboxes', 'conf', and 'cls' keys with
                bounding box coordinates (including angle), confidence scores, and class predictions.
            save_conf (bool): Whether to save confidence scores in the text file.
            shape (tuple[int, int]): Original image shape in format (height, width).
            file (Path): Output file path to save detections.

        Examples:
            >>> validator = OBBValidator()
            >>> predn = {
            ...     "bboxes": torch.tensor([[100, 100, 50, 30, 45]]),
            ...     "conf": torch.tensor([0.9]),
            ...     "cls": torch.tensor([0]),
            ... }
            >>> validator.save_one_txt(predn, True, (640, 480), Path("detection.txt"))
        r   N)ResultsrY   r5   r7   rd   rF   r3   rG   )r   rr   r   )r   )
r?   ultralytics.engine.resultsr   r:   uint8rr   rJ   rK   	unsqueezesave_txt)r   rz   r   r8   r   r9   r   s          r   save_one_txtzOBBValidator.save_one_txt   s    & 	666666BHeAha):::*	5?E&M,C,CB,G,GuI_I_`bIcIcdjklll		
 	
 	

 (49(
-
-
-
-
-r   c           	         i |dt          j        |d         |d                                         |d         |d         d          iS )z.Scales predictions to the original image size.r7   r[   rS   rV   T)rV   xywh)r   scale_boxesclone)r   rz   r{   s      r   scale_predszOBBValidator.scale_preds   s`    

cowx!6!6!8!8&:MY_`kYlsw  
 
 	
r   statsc                	   | j         j        r| j        rt          | j                  rddl}ddl}ddlm} | j	        dz  }| j	        dz  }|
                    dd           |                    t          |                    }t          j        d| d	           |D ]}|d
         }	|d         }
| j        |d         dz
                               dd          }|d         }t          |d| z   ddd          5 }|                    |	 d|
 d|d          d|d          d|d          d|d          d|d          d|d          d|d          d|d          d           ddd           n# 1 swxY w Y   | j	        dz  }|
                    dd            |t$                    }t          j        d| d	           |D ]}|d
                             dd          d         }	|                    d           }d! |                    ||d
                   d                             d"          D             \  }}|d#         |d         |d         dz
  }}
}|dxx         |z  cc<   |dxx         |z  cc<   |                    |
|g           ||	                             |           |                                D ](\  }	}t3          j        |          }t3          j        |ddddf                                                   dz  }|ddddf         |z  }|dddf         }|ddddf                                         }|ddddfxx         |z  cc<   t=          j        ||d$t@          %          }||         }tC          j"        |ddddf                   #                    d&d'          }t3          j$        ||ddddf         gd&(          %                                D ]}| j        tM          |d&                                                dd          }d) |dd*         D             }tO          |d*         d          }
t          |d| z   ddd          5 }|                    |	 d|
 d|d          d|d          d|d          d|d          d|d          d|d          d|d          d|d          d           ddd           n# 1 swxY w Y   *|S )+zEvaluate YOLO output in JSON format and save predictions in DOTA format.

        Args:
            stats (dict[str, Any]): Performance statistics dictionary.

        Returns:
            (dict[str, Any]): Updated performance statistics.
        r   N)defaultdictzpredictions.jsonpredictions_txtT)parentsexist_okz'Saving predictions with DOTA format to z...r   r   r   rY    -r   Task1_z.txtazutf-8)encodingrU   r   rW   r~         
predictions_merged_txtz.Saving merged predictions with DOTA format to __z	\d+___\d+c              3  4   K   | ]}t          |          V  d S )N)rO   )rh   r   s     r   	<genexpr>z)OBBValidator.eval_json.<locals>.<genexpr>  s(      [[1A[[[[[[r   ___r   g333333?)iou_funcrF   r}   rG   c                .    g | ]}t          |d           S r   r   )rh   rw   s     r   rk   z*OBBValidator.eval_json.<locals>.<listcomp>+  s     555q!555r   )(r   	save_jsonr+   lenr   jsonrecollectionsr   r   mkdirloadopenr   inforr   replace
writelineslistr(   compilefindallextendr   itemsrJ   r^   maxitemr   r   fast_nmsr
   r   r   r   rK   r   rO   r   )r   r   r   r   r   	pred_jsonpred_txtr&   dr   r   	classnamepfpred_merged_txtmerged_resultspatternri   yr`   r3   max_whr   scoresr   rw   s                             r   	eval_jsonzOBBValidator.eval_json   sP    9 4	v4< 4	vC
OO 4	vKKKIII//////(::I}'88HNN4$N77799T)__--DKO(OOOPPP r rZ='
 Jq'7!';<DDS#NN	fIX(<(<(<<BBBCRYZZZ r^_LLH!p!pu!p!pqt!p!pad!p!pQqT!p!pAaD!p!pSTUVSW!p!pZ[\]Z^!p!pabcdae!p!phijkhl!p!p!pqqqr r r r r r r r r r r r r r r #m.FFO!!$!>>>([..NK]]]]^^^ 6 6Z=..tQ77:**\22[[

7AjM(J(J1(M(S(STY(Z(Z[[[1#$V9aj!M:JQ:NSeQ1Q1UCL)))x(//5555"0"6"6"8"8 v v$|D))42A2;//4466:AaCL6)aaadBQBK%%''!!!RaR%A%a}MMMAw&tAAArrE{3388Q??AtAAAqsF|#4"===DDFF v vA $
3qu:: 6 > >sC H HI55af555A!!B%OOE3GI3G3G!GMMMs]deee vij%t%t5%t%t1Q4%t%t!A$%t%t1%t%tPQRSPT%t%tWXYZW[%t%t^_`a^b%t%tefghei%t%tlmnolp%t%t%tuuuv v v v v v v v v v v v v v vv s&   ?A$E//E3	6E3	/A$SS#&S#)NNNN)r   r   r   r   )r    r!   r   r   )r.   r/   r0   r/   r   r1   )r.   rB   r   rC   )rN   rO   r0   rP   r   rP   )r0   rP   r.   rC   rb   rO   r   r   )rz   r/   r{   rP   r   r   )
rz   r/   r   r<   r8   r   r   r   r   r   )rz   r/   r{   rP   r   r/   )r   rP   r   rP   )__name__
__module____qualname____doc__r   r%   rA   rI   ra   ry   r   r   r   r   __classcell__)r   s   @r   r   r      s        6$ $ $ $ $ $ $ 	+ 	+ 	+ 	+ 	+ 	+] ] ] ]0     
 
 
 
B
 
 
 
:   <. . . .<
 
 
 
? ? ? ? ? ? ? ?r   r   )
__future__r   pathlibr   typingr   r?   r9   rJ   ultralytics.models.yolo.detectr   ultralytics.utilsr   r   ultralytics.utils.metricsr	   r
   ultralytics.utils.nmsr   ultralytics.utils.plottingr   r   rg   r   r   <module>r      s    # " " " " "                  = = = = = = ) ) ) ) ) ) ) ) ? ? ? ? ? ? ? ? * * * * * * 2 2 2 2 2 2_ _ _ _ _% _ _ _ _ _r   