Przesyłanie obrazów

Oto przykład tworzenia nowego zbioru danych i przesyłania do niego obrazów z kategoriami i adnotacjami.

Tworzenie zbioru danych

Python

def create_dataset(dataset_name):
    request = {
        "name": dataset_name
    }
    response = requests.post(url=f'{OSAI_URL}/Datasets', headers=HEADERS, json=request).json()
    dataset_id = response["id"]
    return dataset_id

Tworzenie kategorii

Podczas korzystania z interfejsu API do przesyłania obrazów z kategorii należy wcześniej utworzyć potrzebne kategorie, aby podczas przesyłania obrazów podać prawidłowy identyfikator kategorii używanych w zestawie danych.

Python

def create_category(dataset_id, category_name):
    request = {
        "datasetId": dataset_id,
        "name": category_name
    }
    response = requests.post(
        f'{OSAI_URL}/Categories', headers=HEADERS, json=request
    ).json()
    return respone

Przesyłanie

Rozpoczęcie i zakończenie przesyłania

Przesyłanie należy rozpocząć ręcznie. Zbiór danych zostanie wówczas zablokowany i będzie można przesyłać zdjęcia. Po zakończeniu przesyłania zdjęć należy zatrzymać przesyłanie, aby odblokować zbiór danych. Jeśli zapomnisz tego zrobić, zbiór danych odblokuje się automatycznie po pewnym czasie bez otrzymywania nowych zdjęć.

Python

def start_uploading(dataset_id):
    response = requests.post(
        f'{OSAI_URL}/Datasets/{dataset_id}/StartUploading', headers=HEADERS
    ).json()
    return response


def finish_uploading(dataset_id, upload_id):
    response = requests.post(
        f'{OSAI_URL}/Datasets/{dataset_id}/FinishUploading', headers=HEADERS, params={"datasetUploadId": upload_id}
    )
    print(response)

Wysyłanie obrazów

Python

def send_images(dataset_id, upload_id, path):
    images_data = get_images_data(path)
    categories_id = create_categories_for_images_data(images_data, dataset_id)

    for image in images_data:
        response = upload_image(dataset_id, categories_id, upload_id, image)
        print(response)

Zdjęcia są wysyłane jako multipart/form-data, które muszą zawierać:

  • DatasetID
  • DatasetUploadID
  • ImagesMetadata - zawierające dane takie jak:
    • name
    • annotationType
    • annotation
    • classifyCategoryId
  • ImagesFles

Python

def upload_image(dataset_id, categories_id, upload_id, image):
    annotation = get_annotation(image)
    encoded_content = base64.b64encode(bytes(annotation['content'], 'utf-8'))
    file_name = image['name'] + image['extension']
    file_path= image['path'] + os.sep + file_name
    form_data = {
            'datasetId': dataset_id,
            'datasetUploadId': upload_id,
            'imagesMetadata[0][name]': file_name,
            'imagesMetadata[0][annotationType]': annotation['type'],
            'imagesMetadata[0][annotation]': encoded_content,
            'imagesMetadata[0][classifyCategoryId]': categories_id[image['category']],
        }
    files = {'imagesFiles': (file_name, open(file_path, 'rb'))}
    response = requests.post(
            f'{OSAI_URL}/Images/UploadChunk',headers=HEADERS,
            params={'skipUnsupportedImages': False}, data=form_data, files=files
        )

    return response

Pobieranie metadanych obrazu

Aby ułatwić zarządzanie przesłanymi obrazami, można podzielić informacje o zdjęciu, przesyłając do niego klasyfikacje i adnotacje.

Python

def get_images_data(path):
    image_list =[]
    for root, _dirs, files in os.walk(path):
        for file in files:
            suffix = pathlib.Path(file).suffix
            name = pathlib.Path(file).stem
            if suffix == '.jpg' or suffix == '.png':
                annotation = None
                if  os.path.isfile(root + os.sep + name + '.xml'):
                    annotation = '.xml'
                image_list.append({'path': root, 'name': name, 'extension': suffix, 'category': os.path.basename(root), 'annotation_file':annotation})

    return image_list

Dodawanie kategorii do przesyłania

W tym przykładzie używamy folderu nadrzędnego do przypisania klasyfikacji.

Python

def create_categories_for_images_data(images_data, dataset_id):
    categories = []
    categories_ids = {}
    for image in images_data:
        if image['category'] not in categories:
            categories.append(image['category'])
    for category in categories:
        categories_ids[category] = create_category(dataset_id, category)['id']

    return categories_ids

Dodawanie adnotacji .xml do przesyłanych plików

Pliki .xml wymagają, aby metadane obrazów zawierały prawidłowy typ adnotacji, aby serwer wiedział, jak zdekodować posiadane informacje. Plik .xml powinien zostać przesłany jako zakodowany ciąg znaków w base64.

Python

def get_annotation(image_data):
    annotation = {}
    if image_data['annotation_file'] == '.xml':
        file_path = image_data['path']+ os.sep + image_data['name'] + image_data['annotation_file']
        annotation['type']=0
        with open(file_path) as file:
            annotation['content'] = file.read()
    else:
        annotation['type']=None
        annotation['content'] = ''

    return annotation

Przykład

Python

import requests
import os
import pathlib
import base64

OSAI_URL = 'https://app-eu.onestepai.com/api'
API_TOKEN = 'OUR ACCESS TOKEN GENERATED IN OSAI'
HEADERS = {'Authorization': None}

def main():
    token = sign_in()
    global HEADERS
    HEADERS = {'Authorization': f'Bearer {token.text}'}

    print('------Create dataset------')
    dataset_id = create_dataset('holy_hand_grenade')
    print('-----Uploading------')
    upload_id = start_uploading(dataset_id)
    send_images(dataset_id, upload_id, "zdj")
    finish_uploading(dataset_id, upload_id)


def sign_in():
    response = requests.post(
        url=f'{OSAI_URL}/Users/SignIn', json=API_TOKEN)
    return response


def create_dataset(dataset_name):
    request = {
        'name': dataset_name
    }
    response = requests.post(url=f'{OSAI_URL}/Datasets', headers=HEADERS, json = request).json()
    dataset_id = response['id']
    print(f'Dataset created with id: {dataset_id}')
    return dataset_id


def create_category(dataset_id, category_name):
    request = {
        'datasetId': dataset_id,
        'name': category_name
    }
    response = requests.post(
        f'{OSAI_URL}/Categories', headers=HEADERS, json=request
    ).json()
    return response


def send_images(dataset_id, upload_id, path):
    images_data = get_images_data(path)
    categories_id = create_categories_for_images_data(images_data, dataset_id)

    for image in images_data:
        response = upload_image(dataset_id, categories_id, upload_id, image)
        print(response)


def start_uploading(dataset_id):
    response = requests.post(
        f'{OSAI_URL}/Datasets/{dataset_id}/StartUploading', headers=HEADERS
    ).json()
    return response


def finish_uploading(dataset_id, upload_id):
    response = requests.post(
        f'{OSAI_URL}/Datasets/{dataset_id}/FinishUploading', headers=HEADERS, params={'datasetUploadId': upload_id}
    )
    print(response)


def upload_image(dataset_id, categories_id, upload_id, image):
    annotation = get_annotation(image)
    encoded_content = base64.b64encode(bytes(annotation['content'], 'utf-8'))
    file_name = image['name'] + image['extension']
    file_path= image['path'] + os.sep + file_name
    form_data = {
            'datasetId': dataset_id,
            'datasetUploadId': upload_id,
            'imagesMetadata[0][name]': file_name,
            'imagesMetadata[0][annotationType]': annotation['type'],
            'imagesMetadata[0][annotation]': encoded_content,
            'imagesMetadata[0][classifyCategoryId]': categories_id[image['category']],
        }
    files = {'imagesFiles': (file_name, open(file_path, 'rb'))}
    response = requests.post(
            f'{OSAI_URL}/Images/UploadChunk',headers=HEADERS,
            params={'skipUnsupportedImages': False}, data=form_data, files=files
        )

    return response


def get_annotation(image_data):
    annotation = {}
    if image_data['annotation_file'] == '.xml':
        file_path = image_data['path']+ os.sep + image_data['name'] + image_data['annotation_file']
        annotation['type']=0
        with open(file_path) as file:
            annotation['content'] = file.read()
    else:
        annotation['type']=None
        annotation['content'] = ''

    return annotation


def create_categories_for_images_data(images_data, dataset_id):
    categories = []
    categories_ids = {}
    for image in images_data:
        if image['category'] not in categories:
            categories.append(image['category'])
    for category in categories:
        categories_ids[category] = create_category(dataset_id, category)['id']

    return categories_ids


def get_images_data(path):
    image_list =[]
    for root, _dirs, files in os.walk(path):
        for file in files:
            suffix = pathlib.Path(file).suffix
            name = pathlib.Path(file).stem
            if suffix == '.jpg' or suffix == '.png':
                annotation = None
                if  os.path.isfile(root + os.sep + name + '.xml'):
                    annotation = '.xml'
                image_list.append({'path': root, 'name': name, 'extension': suffix, 'category': os.path.basename(root), 'annotation_file': annotation})

    return image_list


if __name__ == '__main__':
    main()

Example output

------Create dataset------
Dataset created with id: 514
-----Uploading------
<Response [200]>
<Response [200]>
<Response [200]>
<Response [200]>
<Response [200]>
<Response [200]>
<Response [200]>
<Response [200]>
<Response [200]>