Search code examples
deep-learningdrawingimage-segmentationyoloyolov8

YOLOv8 plotting labels issue, satellite imagery data


I have an issue with the YOLOv8 training output (from ultralytics), specifically the drawing of the labels (not the predictions). I do have a dataset of satellite imagery, where there is (segmentation) polygons on building roof and we want the model to predict the segmentation of building roofs. The issue is the YOLOv8 output of the labels plotting looks weird. I do have the data as polygons only in json, and I extracted/created the bbox from the polygons (since YOLO requires the bbox coord. in the labels) and then I put the labels in YOLO structure. I'm afraid if I m missing something in the processing of the data, however my own visualization are correct and shows the labels perfectly.

My visualizations:

https://i2.paste.pics/QVOMT.png?trs=34b121c874955a5f596553548b231034c39f8b8d551235cecc2ff5cd0ae61711&rand=sQfTxn57Xc

YOLO visualizations (diff image but same issue on all images):

https://i2.paste.pics/QVON6.png?trs=34b121c874955a5f596553548b231034c39f8b8d551235cecc2ff5cd0ae61711&rand=uRbqAVPmSc

The original polygons in json file looks something like this:

"polygon": [[0.6005, 0.0844], [0.432, 0.3742], [0.2131, 0.2514], [0.3691, 0.0], [0.4462, 0.0]]

the YOLO label txt file looks like this:

{label_clss}{x_center}{y_center}{bbox_width}{bbox_height}{polygon_coord}
3 0.4068 0.1871 0.3874 0.3742 0.6005 0.0844 0.4320 0.3742 0.2131 0.2514 0.3691 0.0000 0.4462 0.0000
1 0.2420 0.2840 0.0817 0.0602 0.2161 0.2539 0.2012 0.2784 0.2693 0.3141 0.2829 0.2921
3 0.4968 0.5071 0.3422 0.3051 0.4035 0.3587 0.3257 0.4908 0.4726 0.5833 0.4476 0.6200 0.5621 0.6597 0.6679 0.4923 0.4484 0.3546 0.4329 0.3777

the function that I used to get the bbox from polygons:

def get_bounding_box(polygon):
    # Extract x and y coordinates separately
    x_coords = [point[0] for point in polygon]
    y_coords = [point[1] for point in polygon]

    # Determine the bounding box corners
    min_x, max_x = min(x_coords), max(x_coords)
    min_y, max_y = min(y_coords), max(y_coords)

    # Calculate center, width, and height
    x_center = (min_x + max_x) / 2
    y_center = (min_y + max_y) / 2
    width = max_x - min_x
    height = max_y - min_y

    return x_center, y_center, width, height

This is the method that I use to generate YOLO txt files:

def export_yolo_labels(json_data, folder_path="yolo_labels"):
    os.makedirs(folder_path, exist_ok=True)
    for anno in json_data:
        img_size = (anno["image_size"]["width"],anno["image_size"]["height"])
        img_name = anno["image_name"]
        label_name = f"{img_name.replace('.png', '.txt')}" 
        file = open(os.path.join(folder_path,label_name), "a")
        for label in anno["labels"]:
            label_class = label["label_class"]
            polygon = label["polygon"]
            x_center, y_center, bbox_width, bbox_height = get_bounding_box(polygon)
            flat_polygon = flatten_polygon(polygon)
            yolo_text_format = f"{label_class} {x_center:.4f} {y_center:.4f} {bbox_width:.4f} {bbox_height:.4f} {flat_polygon}"
            file.write(yolo_text_format + '\n')
        file.close()

am I missing something? what could be the issue? how to resolve it? Thank you!

The labels are in the correct format of YOLOv8


Solution

  • For the object segmentation task, the required labeling format for Yolov8 is the following (https://docs.ultralytics.com/datasets/segment/#ultralytics-yolo-format):

    <class-index> <x1> <y1> <x2> <y2> ... <xn> <yn>
    

    You need to keep normalized segment coordinates {label_clss}{polygon_coord} and get rid of the redundant bbox part {x_center}{y_center}{bbox_width}{bbox_height}, as it is needed only for the object detection task. In the case of object segmentation, the yolov8 program code will easily calculate bbox coordinates out of the provided segment coordinates.

    So in your case, I suspect, the model accepts the bbox coordinates in a label as a part of the segment and plots this distorted result.