|
34 | 34 | from app.core.history import HistoryService |
35 | 35 | from app.core.manual_reference_recognition import ManualReferenceRecognizer |
36 | 36 | from app.core.multi_object_dispatch import ( |
| 37 | + _foreground_fragments_same_object, |
37 | 38 | evaluate_foreground_multi_object_dispatch, |
38 | 39 | evaluate_single_class_dispatch, |
39 | 40 | foreground_object_clusters, |
@@ -897,6 +898,7 @@ def _multi_object_split_candidates( |
897 | 898 | operator_label=f"Vật {index} - cần tách riêng", |
898 | 899 | ) |
899 | 900 | ) |
| 901 | + matches = self._merge_split_same_label_multi_object_matches(matches) |
900 | 902 | logger.info( |
901 | 903 | "foreground split multi-object frame into {}", |
902 | 904 | [match.cls_name for match in matches], |
@@ -965,6 +967,31 @@ def _model_detection_for_cluster( |
965 | 967 | return None |
966 | 968 | return max(candidates, key=lambda item: item[0])[1] |
967 | 969 |
|
| 970 | + @staticmethod |
| 971 | + def _merge_split_same_label_multi_object_matches( |
| 972 | + detections: list[Detection], |
| 973 | + ) -> list[Detection]: |
| 974 | + clusters: list[list[Detection]] = [] |
| 975 | + for detection in detections: |
| 976 | + for cluster in clusters: |
| 977 | + same_label = all( |
| 978 | + item.cls_name == detection.cls_name |
| 979 | + and item.operator_label == detection.operator_label |
| 980 | + for item in cluster |
| 981 | + ) |
| 982 | + if same_label and any( |
| 983 | + _foreground_fragments_same_object(detection.xyxy, item.xyxy) |
| 984 | + for item in cluster |
| 985 | + ): |
| 986 | + cluster.append(detection) |
| 987 | + break |
| 988 | + else: |
| 989 | + clusters.append([detection]) |
| 990 | + return [ |
| 991 | + cluster[0] if len(cluster) == 1 else _merge_detection_cluster(cluster) |
| 992 | + for cluster in clusters |
| 993 | + ] |
| 994 | + |
968 | 995 | def _stabilize_multi_object_display( |
969 | 996 | self, |
970 | 997 | frame_bgr: np.ndarray, |
|
0 commit comments