#
Image upload
Here is an example of creating a new dataset and uploading images to it with categories and annotations.
#
Create a dataset
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
#
Create a category
When using the API to upload images from categories, you will need to create the categories you need in advance so that when you upload images, you provide the correct id of the categories used in the dataset.
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
#
Upload
#
Start and end of upload
You must start the upload manually. The dataset will then be locked and you will be able to upload photos. Once you have finished uploading photos, you need to stop uploading to unlock the dataset. If you forget to do this, the dataset will automatically unlock itself after a certain period of time of not receiving new photos.
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)
#
Send images
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)
Photos are sent as multipart/form-data
, which must include:
- DatasetID
- DatasetUploadID
- ImagesMetadata - containing data such as:
- name
- annotationType
- annotation
- classifyCategoryId
- ImagesFles
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
#
Get image metadata
To make it easier to manage uploaded images, you can break down information about a photo by uploading classifications and annotations to it.
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
#
Add categories to upload
In this example, we use the parent folder to assign the classification.
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
#
Add .xml annotation to upload
The .xml files require that the metadata for the images include a valid annotationType
so that the server will know how to decode the information it has. The .xml file should be uploaded as a encoded string in base64.
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
#
Example
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()
------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]>