import msgpack cimport constants_inf cdef class Detection: def __init__(self, double x, double y, double w, double h, int cls, double confidence): self.annotation_name = None self.x = x self.y = y self.w = w self.h = h self.cls = cls self.confidence = confidence def __str__(self): return f'{self.cls}: {self.x:.2f} {self.y:.2f} {self.w:.2f} {self.h:.2f}, prob: {(self.confidence*100):.1f}%' def __eq__(self, other): if not isinstance(other, Detection): return False if max(abs(self.x - other.x), abs(self.y - other.y), abs(self.w - other.w), abs(self.h - other.h)) > constants_inf.TILE_DUPLICATE_CONFIDENCE_THRESHOLD: return False return True cdef overlaps(self, Detection det2, float confidence_threshold): cdef double overlap_x = 0.5 * (self.w + det2.w) - abs(self.x - det2.x) cdef double overlap_y = 0.5 * (self.h + det2.h) - abs(self.y - det2.y) cdef double overlap_area = max(0.0, overlap_x) * max(0.0, overlap_y) cdef double min_area = min(self.w * self.h, det2.w * det2.h) return overlap_area / min_area > confidence_threshold cdef class Annotation: def __init__(self, str name, str original_media_name, long ms, list[Detection] detections): self.name = name self.original_media_name = original_media_name self.time = ms self.detections = detections if detections is not None else [] for d in self.detections: d.annotation_name = self.name self.image = b'' def __str__(self): if not self.detections: return f"{self.name}: No detections" detections_str = ", ".join( f"class: {d.cls} {d.confidence * 100:.1f}% ({d.x:.2f}, {d.y:.2f}) ({d.w:.2f}, {d.h:.2f})" for d in self.detections ) return f"{self.name}: {detections_str}" cdef bytes serialize(self): return msgpack.packb({ "n": self.name, "mn": self.original_media_name, "i": self.image, # "i" = image "t": self.time, # "t" = time "d": [ # "d" = detections { "an": det.annotation_name, "x": det.x, "y": det.y, "w": det.w, "h": det.h, "c": det.cls, "p": det.confidence } for det in self.detections ] })