import cv2 import numpy as np import supervision as sv from PIL import Image MIN_AREA = 100 def load_image(image_path: str): return Image.open(image_path).convert("RGB") def draw_image(image_rgb, masks, xyxy, probs, labels): box_annotator = sv.BoxCornerAnnotator() label_annotator = sv.LabelAnnotator() mask_annotator = sv.MaskAnnotator() # Create class_id for each unique label unique_labels = list(set(labels)) class_id_map = {label: idx for idx, label in enumerate(unique_labels)} class_id = [class_id_map[label] for label in labels] # Add class_id to the Detections object detections = sv.Detections( xyxy=xyxy, mask=masks.astype(bool), confidence=probs, class_id=np.array(class_id), ) annotated_image = box_annotator.annotate(scene=image_rgb.copy(), detections=detections) annotated_image = label_annotator.annotate(scene=annotated_image, detections=detections, labels=labels) annotated_image = mask_annotator.annotate(scene=annotated_image, detections=detections) return annotated_image def get_contours(mask): if len(mask.shape) > 2: mask = np.squeeze(mask, 0) mask = mask.astype(np.uint8) mask *= 255 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) effContours = [] for c in contours: area = cv2.contourArea(c) if area > MIN_AREA: effContours.append(c) return effContours def contour_to_points(contour): pointsNum = len(contour) contour = contour.reshape(pointsNum, -1).astype(np.float32) points = [point.tolist() for point in contour] return points def generate_labelme_json(binary_masks, labels, image_size, image_path=None): """Generate a LabelMe format JSON file from binary mask tensor. Args: binary_masks: Binary mask tensor of shape [N, H, W]. labels: List of labels for each mask. image_size: Tuple of (height, width) for the image size. image_path: Path to the image file (optional). Returns: A dictionary representing the LabelMe JSON file. """ num_masks = binary_masks.shape[0] binary_masks = binary_masks.numpy() json_dict = { "version": "4.5.6", "imageHeight": image_size[0], "imageWidth": image_size[1], "imagePath": image_path, "flags": {}, "shapes": [], "imageData": None, } # Loop through the masks and add them to the JSON dictionary for i in range(num_masks): mask = binary_masks[i] label = labels[i] effContours = get_contours(mask) for effContour in effContours: points = contour_to_points(effContour) shape_dict = { "label": label, "line_color": None, "fill_color": None, "points": points, "shape_type": "polygon", } json_dict["shapes"].append(shape_dict) return json_dict