How to export annotation data in COCO format?

In GT Studio, you can also export the annotated in COCO format by modifying the export submission code from project settings.

On the submission code section, you can paste the below code and save it. Now, all the new submissions will be generated in the COCO format. To learn how to create submissions, you can have a look here: Export Jobs

If you make any changes to the submission code, you'll have to send jobs back for rework to a manual step and push it again to the end step.

import json
import pandas as pd
import requests
from PIL import Image
from io import BytesIO
import re


def natural_sort(l):
    """
    natural sort a list of strings
    :param l:
    :return:
    """
    convert = lambda text: int(text) if text.isdigit() else text.lower()
    alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
    return sorted(l, key=alphanum_key)

def get_dimensions(image_url):
    res = requests.get(image_url)
    if res.status_code == 200:
        image = Image.open(BytesIO(res.content))
        width, height = image.size
        return width, height
    else:
        raise ValueError("Image url not accessible")


def mini_maxi(coor, key):
    mini, maxi = float('inf'), -float('inf')
    for each in coor:
        mini = min(mini, each[key])
        maxi = max(maxi, each[key])
    return mini, maxi


def get_bbox(coor, w, h):
    x, y = coor[0]['x'], coor[0]['y']
    x = round(x * w, 4)
    y = round(y * h, 4)

    x_mini, x_maxi = mini_maxi(coor, 'x')
    y_mini, y_maxi = mini_maxi(coor, 'y')

    x_diff = round((x_maxi - x_mini) * w, 4)
    y_diff = round((y_maxi - y_mini) * h, 4)

    temp = [x, y, x_diff, y_diff]
    return temp

def get_polygon(edge, points, w, h):
    coco = []
    point_list = natural_sort(list(points.keys()))
    for p in point_list:
        coco+= [points[p]['x'] * w, points[p]['y'] * h]
    coco += [points[point_list[0]]['x'] *w,points[point_list[0]]['y']*h]
    return [coco]

def get_polygon_bbox(polygon):
    x_min = min(polygon[::2])
    y_min = min(polygon[1::2])
    x_max = max(polygon[::2])
    y_max = max(polygon[1::2])
    x_diff = round((x_max - x_min) , 4)
    y_diff = round((y_max - y_min) , 4)
    return [x_min, y_min , x_diff, y_diff]


# Ask for the support of external library.

# Code starts with main function
def main(fn, build, meta):
    """
    :param fn: Will be used for custom logging. Ignore it for now
    :param build: Flu build
    :param meta: Flu meta present in feed_line except the build.
    :return: Will return updated flu build
    """
    # Tip: spaces are better than tabs

    ref = meta['reference_id']

    data = {"images": [], "category": [], "annotations": []}

    image_id = ref
    image_name = ref.split("/")[-1]

    
    width, height = get_dimensions(build['image_url_original'])

    image_data = {"id": image_id, "name": image_name, "width": width, "height": height,
                  "license": None, "date_captured": None}
    data['images'].append(image_data)

    for ann in build['maker_response']['rectangles']['data']:
        ann_data = {"id": ann['_id'],"attributes": ann["attributes"], "category_id": ann['label'], 'image_id': image_id,'bbox': get_bbox(ann['coordinates'],
                                                                                           width, height)}
        data['annotations'].append(ann_data)
    
    for ann in build['maker_response']['polygons']['data']:
        ann_data = {"id": ann['_id'], "category_id": ann['label'], 'image_id': image_id,
                    'segmentation': get_polygon(ann['edges'],ann['points'],width, height) , 
                    "attributes": ann["attributes"]}
        ann_data['bbox'] = get_polygon_bbox(ann_data['segmentation'][0])                                         
        data['annotations'].append(ann_data)



    # code here
    image_id = image_id + '.json'
    image_name = image_name
    return {
        "export_data": [{
            "type": "JSON",
            "data": data,
            "key": image_name,
            "path": image_id
        }]
    }


Original GT Studio Conversion Scirpt

In case you want to go back to the GT Studio JSON format, you can paste the below code in the submission code section and save it.

# Ask for the support of external library.

# Code starts with main function
def main(fn, build, meta):
    """
    :param fn: Will be used for custom logging. Ignore it for now
    :param build: Flu build
    :param meta: Flu meta present in feed_line except the build.
    :return: Will return updated flu build
    """
    # Tip: spaces are better than tabs

    # code here
    return {
        "export_data": [{
            "type": "JSON",
            "data": {
                "annotations": {
                    "rectangles": build['maker_response']['rectangles']['data'],
                    "lines": build['maker_response']['lines']['data'],
                    "landmarks": build['maker_response']['landmarks']['data'],
                    "cuboids": build['maker_response']['cuboids']['data'],
                    "polygons": build['maker_response']['polygons']['data']
                },
                "image_url": build['image_url']
            },
            "key": "data"
        }]
    }

Last updated