
    Ng{                     0    d dl T d dlT  G d d          ZdS )   )*c                   p    e Zd ZdZ	 	 	 	 ddZ	 ddZ	 dd	Z	 dd
Z	 ddZd Z	d Z
	 ddZd Z	 ddZdS )PerImageEvaluationz,Evaluate detection result of a single image.      ?333333?2           c                 L    || _         || _        || _        || _        || _        dS )a  Initialized PerImageEvaluation by evaluation parameters.
        Args:
            num_gt_classes: Number of ground truth object classes
            matching_iou_threshold: A ratio of area intersection to union, which is
                the threshold to consider whether a detection is true positive or not
            nms_iou_threshold: IOU threshold used in Non Maximum Suppression.
            nms_max_output_boxes: Number of maximum output boxes in NMS.
            group_of_weight: Weight of the group-of boxes.
        N)matching_iou_thresholdnms_iou_thresholdnms_max_output_boxesnum_gt_classesgroup_of_weight)selfr   r   r   r   r   s         b/var/www/html/ai-engine/env/lib/python3.11/site-packages/effdet/evaluation/per_image_evaluation.py__init__zPerImageEvaluation.__init__   s2     '=#!2$8!,.    Nc
                     |                      ||||          \  }}}}|                     |||||||||		  	        \  }
}|                     |||||||	          }|
||fS )a	  Evaluates detections as being tp, fp or weighted from a single image.
        The evaluation is done in two stages:
            1. All detections are matched to non group-of boxes; true positives are
               determined and detections matched to difficult boxes are ignored.
            2. Detections that are determined as false positives are matched against
               group-of boxes and weighted if matched.
        Args:
            detected_boxes: A float numpy array of shape [N, 4], representing N
                regions of detected object regions. Each row is of the format [y_min, x_min, y_max, x_max]
            detected_scores: A float numpy array of shape [N, 1], representing the
                confidence scores of the detected N object instances.
            detected_class_labels: A integer numpy array of shape [N, 1], repreneting
                the class labels of the detected N object instances.
            gt_boxes: A float numpy array of shape [M, 4], representing M
                regions of object instances in ground truth
            gt_class_labels: An integer numpy array of shape [M, 1],
                representing M class labels of object instances in ground truth
            gt_is_difficult_list: A boolean numpy array of length M denoting
                whether a ground truth box is a difficult instance or not
            gt_is_group_of_list: A boolean numpy array of length M denoting
                whether a ground truth box has group-of tag
            detected_masks: (optional) A uint8 numpy array of shape [N, height,
                width]. If not None, the metrics will be computed based on masks.
            gt_masks: (optional) A uint8 numpy array of shape [M, height,
                width]. Can have empty masks, i.e. where all values are 0.
        Returns:
            scores: A list of C float numpy arrays. Each numpy array is of
                shape [K, 1], representing K scores detected with object class label c
            tp_fp_labels: A list of C boolean numpy arrays. Each numpy array
                is of shape [K, 1], representing K True/False positive label of
                object instances detected with class label c
            is_class_correctly_detected_in_image: a numpy integer array of
                shape [C, 1], indicating whether the correponding class has a least
                one instance being correctly detected in the image
        )	detected_boxesdetected_scoresdetected_class_labelsgt_boxesgt_class_labelsgt_is_difficult_listgt_is_group_of_listdetected_masksgt_masks)r   r   r   r   r   r   r   )_remove_invalid_boxes_compute_tp_fp_compute_cor_loc)r   r   r   r   r   r   r   r   r   r   scorestp_fp_labels$is_class_correctly_detected_in_images                r    compute_object_detection_metricsz3PerImageEvaluation.compute_object_detection_metrics   s    P &&~H]_mnn 	O)>  $22)+"7+!5 3)  3 	  	  04/D/D)+"7+) 0E 0 0, |%IIIr   c                 ,   ||||t          d          t                              | j        t                    }t          | j                  D ]A}	|                     ||||||||	          \  }
}}}}|                     |||
||          ||	<   B|S )a  Compute CorLoc score for object detection result.
        Args:
            detected_boxes: A float numpy array of shape [N, 4], representing N
                regions of detected object regions. Each row is of the format [y_min, x_min, y_max, x_max]
            detected_scores: A float numpy array of shape [N, 1], representing the
                confidence scores of the detected N object instances.
            detected_class_labels: A integer numpy array of shape [N, 1], repreneting
                the class labels of the detected N object instances.
            gt_boxes: A float numpy array of shape [M, 4], representing M
                regions of object instances in ground truth
            gt_class_labels: An integer numpy array of shape [M, 1],
                representing M class labels of object instances in ground truth
            detected_masks: (optional) A uint8 numpy array of shape [N, height, width].
                If not None, the scores will be computed based on masks.
            gt_masks: (optional) A uint8 numpy array of shape [M, height, width].
        Returns:
            is_class_correctly_detected_in_image: a numpy integer array of
                shape [C, 1], indicating whether the correponding class has a least
                one instance being correctly detected in the image
        Raises:
            ValueError: If detected masks is not None but groundtruth masks are None,
                or the other way around.
        NzIIf `detected_masks` is provided, then `gt_masks` should also be provided.dtype)r   r   r   r   r   )
ValueErrornpzerosr   intrange_get_ith_class_arrays-_compute_is_class_correctly_detected_in_image)r   r   r   r   r   r   r   r   r#   igt_boxes_at_ith_classgt_masks_at_ith_classdetected_boxes_at_ith_classdetected_scores_at_ith_classdetected_masks_at_ith_classs                  r   r    z#PerImageEvaluation._compute_cor_loc]   s    4 &8+;&8+?[] ] ] 02xxs 08 0, 0,,t*++ 	5 	5A -1,F,F%x-$ -$*"$9(*F(
 BB#>$@2#>2 C 4 4 133 43r   c                 R   |j         dk    r|j         dk    rt                              |          }d}||d}|rst          t                              ||         d          t                              ||         d                    }t          ||          }	t          ||	          }
nRt          t                              ||ddf         d                    }t          |          }	t          ||	          }
t                              |
          | j	        k    rdS dS )a  Compute CorLoc score for a single class.
        Args:
            detected_boxes: A numpy array of shape [N, 4] representing detected box coordinates
            detected_scores: A 1-d numpy array of length N representing classification score
            gt_boxes: A numpy array of shape [M, 4] representing ground truth box coordinates
            detected_masks: (optional) A np.uint8 numpy array of shape [N, height, width].
                If not None, the scores will be computed based on masks.
            gt_masks: (optional) A np.uint8 numpy array of shape [M, height, width].
        Returns:
            is_class_correctly_detected_in_image: An integer 1 or 0 denoting whether a
                class is correctly detected in the image or not
            FNTaxisbox_data	mask_datar   )
sizer)   argmaxMaskListexpand_dimsiou_masklistBoxListiou_boxlistmaxr   )r   r   r   r   r   r   max_score_id	mask_modedetected_boxlist
gt_boxlistious              r   r.   z@PerImageEvaluation._compute_is_class_correctly_detected_in_image   s,    ""}q  !yy99!	!-(2F $I 	D'/!#|0LST!U!U"$..1MTU."V"V(X (X (X$ "*8x!P!P!PJ&'7DDCC'.r~~n\[\[\[\_>]de~/f/f'g'g$!(!2!2J%&6
CCC66#;;$"===1qr   c
                    ||	t          d          ||	t          d          g }
g }t          | j                  D ]}|||k             }|||k             }|                     ||||||	||          \  }}}}}|                     |||||||          \  }}|
                    |           |                    |           |
|fS )a  Labels true/false positives of detections of an image across all classes.
        Args:
            detected_boxes: A float numpy array of shape [N, 4], representing N
                regions of detected object regions. Each row is of the format [y_min, x_min, y_max, x_max]
            detected_scores: A float numpy array of shape [N, 1], representing the
                confidence scores of the detected N object instances.
            detected_class_labels: A integer numpy array of shape [N, 1], representing
                the class labels of the detected N object instances.
            gt_boxes: A float numpy array of shape [M, 4], representing M
                regions of object instances in ground truth
            gt_class_labels: An integer numpy array of shape [M, 1],
                representing M class labels of object instances in ground truth
            gt_is_difficult_list: A boolean numpy array of length M denoting
                whether a ground truth box is a difficult instance or not
            gt_is_group_of_list: A boolean numpy array of length M denoting
                whether a ground truth box has group-of tag
            detected_masks: (optional) A np.uint8 numpy array of shape [N, height,
                width]. If not None, the scores will be computed based on masks.
            gt_masks: (optional) A np.uint8 numpy array of shape [M, height, width].
        Returns:
            result_scores: A list of float numpy arrays. Each numpy array is of
                 shape [K, 1], representing K scores detected with object class label c
            result_tp_fp_labels: A list of boolean numpy array. Each numpy array is of
                shape [K, 1], representing K True/False positive label of object
                instances detected with class label c
        Raises:
            ValueError: If detected masks is not None but groundtruth masks are None,
                or the other way around.
        Nz9Detected masks is available but groundtruth masks is not.z9Groundtruth masks is available but detected masks is not.)r   r   r   r   r   r   r   )r(   r,   r   r-   _compute_tp_fp_for_single_classappend)r   r   r   r   r   r   r   r   r   r   result_scoresresult_tp_fp_labelsr/   !gt_is_difficult_list_at_ith_class gt_is_group_of_list_at_ith_classr0   r1   r2   r3   r4   r!   r"   s                         r   r   z!PerImageEvaluation._compute_tp_fp   sD   @ %(*:KM M M!h&:KM M M  t*++ 	5 	5A$_%9: . $Oq$89 - -1,F,F%x-$ -$*"$9(*F( $(#G#G: <.%F$D:. $H $0 $0 FL   (((&&|4444111r   c                    t          ||          }|                    d|           t          || j        | j                  }t          ||          ||                    }t          ||         ||                   }	t          ||          }
t                              t          |	|                    }|	                    d          }|
                                }|
|||fS )a  Computes overlaps and scores between detected and groudntruth masks.
        Args:
            detected_boxes: A numpy array of shape [N, 4] representing detected box coordinates
            detected_scores: A 1-d numpy array of length N representing classification score
            detected_masks: A uint8 numpy array of shape [N, height, width]. If not
                None, the scores will be computed based on masks.
            gt_boxes: A numpy array of shape [M, 4] representing ground truth box coordinates
            gt_masks: A uint8 numpy array of shape [M, height, width].
            gt_is_group_of_list: A boolean numpy array of length M denoting
                whether a ground truth box has group-of tag. If a groundtruth box is
                group-of box, every detection matching this box is ignored.
        Returns:
            iou: A float numpy array of size [num_detected_boxes, num_gt_boxes]. If
                gt_non_group_of_boxlist.num_boxes() == 0 it will be None.
            ioa: A float numpy array of size [num_detected_boxes, num_gt_boxes]. If
                gt_group_of_boxlist.num_boxes() == 0 it will be None.
            scores: The score of the detected boxlist.
            num_boxes: Number of non-maximum suppressed detected boxes.
        r9   r!   )r>   	add_fieldnon_max_suppressionr   r   r@   r)   	transposeioa_masklist	get_field	num_boxes)r   r   r   r   r   r   r   rF   gt_non_group_of_boxlistgt_group_of_boxlistiou_bioa_br!   rV   s                 r   "_get_overlaps_and_scores_mask_modez5PerImageEvaluation._get_overlaps_and_scores_mask_mode   s    , $^~VVV""8_===./?AZ\`\rss"*223xI\H\?]#_ #_ #_&12hGZ>[] ] ]-/FGG\*=?OPPQQ!++H55$..00	eVY..r   c                    t          |          }|                    d|           t          || j        | j                  }t          ||                    }t          ||                   }t          ||          }t                              t          ||                    }	|	                    d          }
|
                                }||	|
|fS )a+  Computes overlaps and scores between detected and groudntruth boxes.
        Args:
            detected_boxes: A numpy array of shape [N, 4] representing detected box coordinates
            detected_scores: A 1-d numpy array of length N representing classification score
            gt_boxes: A numpy array of shape [M, 4] representing ground truth box coordinates
            gt_is_group_of_list: A boolean numpy array of length M denoting
                whether a ground truth box has group-of tag. If a groundtruth box is
                group-of box, every detection matching this box is ignored.
        Returns:
            iou: A float numpy array of size [num_detected_boxes, num_gt_boxes]. If
                gt_non_group_of_boxlist.num_boxes() == 0 it will be None.
            ioa: A float numpy array of size [num_detected_boxes, num_gt_boxes]. If
                gt_group_of_boxlist.num_boxes() == 0 it will be None.
            scores: The score of the detected boxlist.
            num_boxes: Number of non-maximum suppressed detected boxes.
        r!   )rA   rQ   rR   r   r   rB   r)   rS   ioa_boxlistrU   rV   )r   r   r   r   r   rF   rW   rX   rY   rZ   r!   rV   s               r   !_get_overlaps_and_scores_box_modez4PerImageEvaluation._get_overlaps_and_scores_box_mode  s    $ #>22""8_===./?AZ\`\rss")(4G3G*H"I"I%h/B&CDD,.EFF[)<>NOOPP!++H55$..00	eVY..r   c           
      ,	    |j         dk    rBt                              g t                    t                              g t                    fS d}||d}t                              ddg          }	t                              ddg          }
t                              ddg          }t                              ddg          }|rt                              |d          dk    }                     |||||ddf         ||ddf         ||                   \  }}t          |          t          |          k     r0 	                    |||| ddf         ||          	          \  }	}
}|j
        d         nDt                              |j
        t                    } 	                    ||||	          \  }	}
|j         dk    r#t                              t                    fS t                              t                    t                              t                    t                              t                    t                              t                     fd
} fd}|j
        d         dk    r%||         }||         } ||||          d           t                              dgt                    }t                              dgt                    }|j
        d         dk    r ||d          \  }}|	j
        d         dk    r'||          }||          } ||	||          d           t                              dgt                    }t                              dgt                    }|
j
        d         dk    r ||
d          \  }}|rg  z   z  }t                              |         |f          t                              |                             t                    |f          fS   z  }t                              |         |f          t                              |                             t                    |f          fS )a  Labels boxes detected with the same class from the same image as tp/fp.
        Args:
            detected_boxes: A numpy array of shape [N, 4] representing detected box coordinates
            detected_scores: A 1-d numpy array of length N representing classification score
            gt_boxes: A numpy array of shape [M, 4] representing ground truth box coordinates
            gt_is_difficult_list: A boolean numpy array of length M denoting
                whether a ground truth box is a difficult instance or not. If a
                groundtruth box is difficult, every detection matching this box is ignored.
            gt_is_group_of_list: A boolean numpy array of length M denoting
                whether a ground truth box has group-of tag. If a groundtruth box is
                group-of box, every detection matching this box is ignored.
            detected_masks: (optional) A uint8 numpy array of shape [N, height,
                width]. If not None, the scores will be computed based on masks.
            gt_masks: (optional) A uint8 numpy array of shape [M, height, width].
        Returns:
            Two arrays of the same size, containing all boxes that were evaluated as
            being true positives or false positives; if a box matched to a difficult
            box or to a group-of box, it is ignored.
            scores: A numpy array representing the detection scores.
            tp_fp_labels: a boolean numpy array indicating whether a detection is a true positive.
        r6   r&   FNT)r      r7   )r   r   r   r   r   r   )r   r   r   r   c                 v   t                               | d          }t                               | j        d         t                    }t                    D ]_}||         }|          o$	|          o| ||f         j        k    o
|          }|r%||         s||         sd|<   d||<   ||<   Zd	|<   `dS )a  Computes TP/FP for non group-of box matching.
            The function updates the following local variables:
                tp_fp_labels - if a box is matched to group-of
                is_matched_to_difficult - the detections that were processed at this are
                    matched to difficult box.
                is_matched_to_box - the detections that were processed at this stage are marked as is_box.
            Args:
                iou_matrix: intersection-over-union matrix [num_gt_boxes]x[num_det_boxes].
                gt_nongroup_of_is_difficult_list: boolean that specifies if gt box is difficult.
                is_box: boolean that specifies if currently boxes or masks are processed.
            r   r7   r&   TN)r)   r=   r*   shapeboolr,   r   )
iou_matrix gt_nongroup_of_is_difficult_listis_boxmax_overlap_gt_idsis_gt_detectedr/   gt_idis_evaluatableis_matched_to_boxis_matched_to_difficultis_matched_to_group_ofnum_detected_boxesr   r"   s           r   compute_match_iouzMPerImageEvaluation._compute_tp_fp_for_single_class.<locals>.compute_match_iou{  s     "$:A!>!>XXj&6q&9XFFN-.. : :*1-$Q' 2/222q%x(D,GG2 /q11	 
 " :;EB :-e4 :.2LO48N5139-a059/2: :r   c                 T   t                               | j        d         t                    }j        t                               | j        d         t                    z  }t                               | d          }t                    D ]c}||         }|          o$
|          o| ||f         j        k    o|          }|r)d|<   |	|<   t          ||         |                   ||<   dt           
                    |dk    |dk    z            }||         }||         }||fS )a  Computes TP/FP for group-of box matching.
            The function updates the following local variables:
                is_matched_to_group_of - if a box is matched to group-of
                is_matched_to_box - the detections that were processed at this stage are marked as is_box.
            Args:
                ioa_matrix: intersection-over-area matrix [num_gt_boxes]x[num_det_boxes].
                is_box: boolean that specifies if currently boxes or masks are processed.
            Returns:
                scores_group_of: of detections matched to group-of boxes[num_groupof_matched].
                tp_fp_labels_group_of: boolean array of size [num_groupof_matched], all values are True.
            r   r&   r7   Tr6   )r)   r*   rb   floatr   onesr=   r,   r   rC   where)
ioa_matrixrf   scores_group_oftp_fp_labels_group_ofmax_overlap_group_of_gt_idsr/   ri   rj   selectorrk   rl   rm   rn   r!   r   r"   s            r   compute_match_ioazMPerImageEvaluation._compute_tp_fp_for_single_class.<locals>.compute_match_ioa  sQ    !hhz'7':%hHHO$($8277:CSTUCV^c7;d;d$d!*,))JQ)*G*G'-.. 
T 
T3A6$Q' 2/222q%x(D,GG2 /q11	 
 " T04*1-+1%a(-01GPQ-S-SOE*xx1!49NQR9R STTH-h7O$9($C!"$999r   r   )rf   )r<   r)   arrayrq   rc   ndarraysumr[   lenr^   rb   r*   concatenateastype) r   r   r   r   r   r   r   r   rE   rY   rZ   iou_mioa_mmask_presence_indicator_ro   ry   gt_is_difficult_mask_listgt_is_group_of_mask_listscores_mask_group_oftp_fp_labels_mask_group_ofgt_is_difficult_box_listgt_is_group_of_box_listscores_box_group_oftp_fp_labels_box_group_ofvalid_entriesrk   rl   rm   rn   r!   r"   s    `                         @@@@@@r   rJ   z2PerImageEvaluation._compute_tp_fp_for_single_class1  s   0 !##88Be8,,bhhrh.F.FFF	%(*>I

Aq6""

Aq6""

Aq6""

Aq6"" 	9
 (*vvhVv'D'Dq'H#7;7^7^- /-!"9111"<=!"9111"<=$78O$P 8_ 8R 8R4E5&"4 *++c2I.J.JJJ6:6\6\#1$3%'>&>&AB(;=T<T(U	 7] 7W 7W3ua!3
 "0!5a!8&(hh/B/HPTh&U&U#7;7]7]- /!$7	 8^ 89 894E5&"4 =A288$6d8CCCCxx 2$x??HH%7tHDD"$((+=T("J"J!#*<D!I!I	: 	: 	: 	: 	: 	: 	: 	: 	: 	:<	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	:F ;q>A(<=T(U%':;R'S$e%>@X?X%Ybghhhh!zz1#Uz;;%'ZZ5Z%A%A";q>A?P?PQV_d?e?e?e< "< ;q>A';=T<T'U$&9;R:R&S#e%=?V>V%W`deeee jj!Ej::$&JJs%J$@$@!;q>A=N=Nu]a=b=b=b:!: 	j559O8OOSdRddM>>6-#8:N"OPP>><#>#E#Ee#L#LNh"ijjk k 659O8OOM>>6-#8:M"NOO>><#>#E#Ee#L#LNg"hiij jr   c	                     ||k    }	||	         }
|	||	         }nd}||k    }||         }||         }|	||         }nd}|
||||fS )a  Returns numpy arrays belonging to class with index `class_index`.
        Args:
            detected_boxes: A numpy array containing detected boxes.
            detected_scores: A numpy array containing detected scores.
            detected_masks: A numpy array containing detected masks.
            detected_class_labels: A numpy array containing detected class labels.
            gt_boxes: A numpy array containing groundtruth boxes.
            gt_masks: A numpy array containing groundtruth masks.
            gt_class_labels: A numpy array containing groundtruth class labels.
            class_index: An integer index.
        Returns:
            gt_boxes_at_ith_class: A numpy array containing groundtruth boxes labeled as ith class.
            gt_masks_at_ith_class: A numpy array containing groundtruth masks labeled as ith class.
            detected_boxes_at_ith_class: A numpy array containing detected boxes corresponding to the ith class.
            detected_scores_at_ith_class: A numpy array containing detected scores corresponding to the ith class.
            detected_masks_at_ith_class: A numpy array containing detected masks corresponding to the ith class.
        N )r   r   r   r   r   r   r   r   class_indexselected_groundtruthr0   r1   selected_detectionsr2   r3   r4   s                   r   r-   z(PerImageEvaluation._get_ith_class_arrays  s    ( !0; > ()= >$,-A$B!!$(!4C&45H&I#'67J'K$%*89L*M''*.'%'<+-I+- 	-r   c                     t                               |dddf         |dddf         k     |dddf         |dddf         k               }||         }||         }||         }|||         }||||gS )a  Removes entries with invalid boxes.
        A box is invalid if either its xmax is smaller than its xmin, or its ymax is smaller than its ymin.
        Args:
            detected_boxes: A float numpy array of size [num_boxes, 4] containing box
                coordinates in [ymin, xmin, ymax, xmax] format.
            detected_scores: A float numpy array of size [num_boxes].
            detected_class_labels: A int32 numpy array of size [num_boxes].
            detected_masks: A uint8 numpy array of size [num_boxes, height, width].
        Returns:
            valid_detected_boxes: A float numpy array of size [num_valid_boxes, 4]
                containing box coordinates in [ymin, xmin, ymax, xmax] format.
            valid_detected_scores: A float numpy array of size [num_valid_boxes].
            valid_detected_class_labels: A int32 numpy array of size [num_valid_boxes].
            valid_detected_masks: A uint8 numpy array of size [num_valid_boxes, height, width].
        Nr6   r`   r      )r)   logical_and)r   r   r   r   r   valid_indicess         r   r   z(PerImageEvaluation._remove_invalid_boxes   s    " 111a4 >!!!Q$#7719MP^_`_`_`bc_cPd9df f'6)-8 5m D%+M:N1FWWr   )r   r   r   r	   )NN)N)__name__
__module____qualname____doc__r   r$   r    r.   r   r[   r^   rJ   r-   r   r   r   r   r   r      s"       66 ),#&&(!$/ / / /0 +/>J >J >J >JD FJ04 04 04 04f \`       H qu>2 >2 >2 >2@!/ !/ !/F/ / /> VZhj hj hj hjT#- #- #-L Z^X X X X X Xr   r   N)np_mask_listmetricsr   r   r   r   <module>r      sc           SX SX SX SX SX SX SX SX SX SXr   