ID of the project in which you want to create the job
Headers
Name
Type
Description
x-api-key
string
API key for authentication
Request Body
Name
Type
Description
batch_id
string
A batch is a way to organize multiple jobs under one batch_id. You can create new batches from the dashboard or by using the batch creation API.
If batch_id is left empty or the key is not present, the job is created in the Default batch in your project.
work_flow_id
string
The ID of the workflow inside which you want to create the job
data
object
The data object contains all the information and attachments required to label a job. The data object is defined below
Contains a sensors list, ego_pose object and sensor metadata list
Object
data.sensor_data.sensor_meta
Contains a list of all the sensors with each having metadata information like
id : id of sensor
name : name of sensor
modality : lidar / camera
If the sensor is a camera, you can add the camera intrinsic values as well as the camera_model. These values are used along with the sensor_pose to create projections between sensors.
camera_model: one of brown_conrady or fisheye
If this key doesn't exist or is null, the tool will assume brown_conrady.
The intrinsics object contains the following keys:
cx: principal point x value
cy: principal point y value
fx: focal length in x-axis
fy: focal length in y-axis
k1, k2, k3, k4, k5, k6: Radial distortion coefficients
p1, p2: Tangential distortion coefficients
skew: camera skew coefficient
scale_factor: The factor by which the image has been downscaled (For example, scale_factor will be 2 if the original image is twice as large as the downscaled image)
If the camera_model is brown_conrady then the distortion coefficients should be one of the following combinations:
k1, k2, p1, p2
k1, k2, p1, p2, k3
k1, k2, p1, p2, k3, k4, k5, k6
If the camera_model is fisheye then the distortion coefficients should be the following combination:
k1, k2, k3, k4
The remaining coefficients can be ignored or be assigned a value of 0
Contains the pose of a fixed point on the ego vehicle in the world frame of reference in the form of position (in (x, y, z)) and orientation (as quaternion (w, x, y, z))
In case the pose of the ego vehicle is available in the world frame of reference, The tool can allow annotators to mark objects as stationary and toggle APC (Aggregated point cloud) mode.
Usually, if a vehicle is equipped with an IMU or Odometry sensor, then it is possible to get the pose of the ego-vehicle in the world frame of reference.
Object
data.sensor_data.sensors
List of all the sensors associated with this particular frame with each having:
sensor_id : id of the sensor. This is a foreign key to the sensor id mentioned in the sensor_meta of the sequence data
data_url : A URL to the file containing the data captured from the sensor for this frame. In order to annotate lidar data, please share point clouds in ascii encoded PCD format.
sensor_pose : This key specifies the pose of respective sensors in a common frame of reference.
If the ego_pose is available in the world frame of reference, then you should specify the sensor_pose of individual sensors in the same world frame of reference. In such cases, the pose might change in every frame, as the vehicle moves.
If the ego_pose is not available, then all sensor_pose can be specified with respect to a fixed point on the vehicle. In such cases, the pose will not change between frames.
List
Please share point clouds in ascii encoded PCD format
# .PCD v0.7- Point Cloud Data file format VERSION 0.7FIELDS x y zSIZE 444TYPE F F FCOUNT 111WIDTH 47286HEIGHT 1VIEWPOINT 0001000POINTS 47286DATA ascii5075.7733756.887107.9235076.0113756.876107.8655076.1163756.826107.8445076.8603756.975107.6485077.0453756.954107.6055077.2373756.937107.5595077.4413756.924107.5115077.5993756.902107.4745077.7803756.885107.4325077.9553756.862107.391...
Visualizing intensity/reflectivity information
You can send additional data like Intensity or reflectivity values for each point in the PCD file. This can help annotators segment reflective surfaces like lane markings.
You can refer to a sample PCD structure below.
# .PCD v0.7- Point Cloud Data file formatVERSION 0.7FIELDS x y z intensitySIZE 4444TYPE F F F FCOUNT 1111WIDTH 33345HEIGHT 1VIEWPOINT 0001000POINTS 33345DATA ascii6.38171339482921120.46125301261318-2.4130810588520350.027450985.2854489534977316.913142630625543-2.2831287955622350.0235294124.5089994907827414.40011307442226-2.19068595492971640.0235294123.9076397041270712.453374568477361-2.1082601102096150.0235294122.947504037334814711.063306463789342-2.02923087458982550.031372552.6487620172711389.92654497521169-1.9917093362143860.035294123.41926046885959.368384486158-1.997492751251550.03137255...
Once you share the data with the above format, annotators can utilize it to view point-cloud colors based on the intesity. It'll look like this:
Helper Python script to create jobs
import jsonimport requestsfrom copy import deepcopy## Functionsdefcreate_batch(BATCH_NAME): base_url =f"https://api.playment.io/v1/projects/{PROJECT_ID}/batch" DATA ={"name":BATCH_NAME} response = requests.post(base_url, headers={'x-api-key': CLIENT_KEY}, json=DATA) response_data = response.json()if response.status_code >=500:raiseException(f"Something went wrong at Playment's end {response.status_code}")if400<= response.status_code <500:raiseException(f"{response_data['error']['message']}{response.status_code}")print(response_data)return response_datadefUpload_jobs(DATA): base_url =f"https://api.playment.io/v1/projects/{PROJECT_ID}/jobs" response = requests.post(base_url, headers={'x-api-key': CLIENT_KEY}, json=DATA) response_data = response.json()if response.status_code >=500:raiseException(f"Something went wrong at Playment's end {response.status_code}")if400<= response.status_code <500:raiseException(f"{response_data['error']['message']}{response.status_code}")print(response_data)return response_data## Set project details# Details for creating JOBS,# PROJECT_ID ->> ID of project in which job needed to be created# CLIENT_KEY ->> secret client key to create JOBS# WORK_FLOW_ID ->> You can ask this from TELUS International side# BATCH_ID ->> The batch in which JOB needed to be createdPROJECT_ID =''CLIENT_KEY =''WORK_FLOW_ID =''BATCH_ID =''## Job creation payload structurepayload_data_structure ={"reference_id":"",# reference_id is the unique reference id for the job"data":{"sensor_data":{"sensors": [],"ego_pose":{# ego_pose is the ego vehicle's pose"position":{# ego vehicle's position"x":0,"y":0,"z":0},"heading":{# ego vehicle's heading in quaternion format"w":1,"x":0,"y":0,"z":0}},"sensor_meta": [] # sensor_meta contains meta data for lidar and camera sensors}},"work_flow_id":"",# this is the id of the workflow in which the jobs are to be created"batch_id":""# this is the batch_id of the batch in which jobs are to be created}sensor_data_structure ={"sensor_id":"",# This is the sensor's id"data_url":"",# sensor's data's URL"sensor_pose":{# This are the sensor's extrinsic values"position":{# sensor's position"x":0,"y":0,"z":0},"heading":{# sensor's heading in quaternion format"w":1,"x":0,"y":0,"z":0}}}lidar_sensor_meta_structure ={# lidar sensor's metadata. There can only be one lidar sesnor"id":"",# lidar sensor's ID"name":"",# should be kept same as lidar sensor's ID"state":"editable",# should be kept as editable only"modality":"lidar",# moality specifies the type of sensor [lidar/camera]"primary_view":True# should be kept True for lidar sensor}camera_sensor_meta_structure ={# camer sensor's metadata. There can be multiple camera sensors"id":"",# camera sensor's ID"name":"",# should be kept same as camera sensor's ID"state":"editable",# should be kept as editable only "modality":"camera",# moality specifies the type of sensor [lidar/camera]"camera_model":"brown_conrady",# specifies the model of camera"primary_view":False,# should be kept as False for all camera sensors"intrinsics":{# camera sensor's intrinsic values"cx":0,"cy":0,"fx":0,"fy":0,"k1":0,"k2":0,"k3":0,"k4":0,"p1":0,"p2":0,"skew":0,"scale_factor":1}}if__name__=="__main__":## Set sensor id and data url (Only 1 lidar can be present per job)# Here lidar's sensor_id is the key and pcd file for each job is in the list lidar_data = ["https://example.com/pcd_url_1","https://example.com/pcd_url_2" ]## Set camera sensor ids and data urls (1 or more cameras can be present per job)# Here camera's sensor_id is the key and image url for each job is in the list corresponding to that camera camera_data ={'camera_1': ["https://example.com/image_url_1","https://example.com/image_url_2" ],"camera_2": ["https://example.com/image_url_3","https://example.com/image_url_4" ]} lidar_sensor_id ='lidar'# set your lidar sensor id# validate the number of urls are equal for each sensorfor camera_sensor_id, camer_sensor_urls in camera_data.items():assertlen(camer_sensor_urls)==len(lidar_data),f"Number of URLs are not equal for {camera_sensor_id}"# get number of jobs numer_of_jobs =len(lidar_data)# create the jobsfor i inrange(numer_of_jobs):# define the payload for job creation payload_data =deepcopy(payload_data_structure) payload_data['reference_id'] = lidar_data[i].replace('.pcd', '') # you can set unique reference id as per your wish
payload_data['work_flow_id']= WORK_FLOW_ID payload_data['batch_id']= BATCH_ID# define lidar sensor meta and add it to payload data lidar_sensor_meta =deepcopy(lidar_sensor_meta_structure) lidar_sensor_meta['id']= lidar_sensor_id lidar_sensor_meta['name']= lidar_sensor_id payload_data['data']['sensor_data']['sensor_meta'].append(lidar_sensor_meta)# define lidar sensor data and add it to payload data lidar_sensor_data =deepcopy(sensor_data_structure) lidar_sensor_data['sensor_id']= lidar_sensor_id lidar_sensor_data['data_url']= lidar_data[i]# set appropriate lidar position and heading, corrently defaulted it to (0,0,0),(1,0,0,0) lidar_sensor_data['sensor_pose']['position']['x'] =0 lidar_sensor_data['sensor_pose']['position']['y'] =0 lidar_sensor_data['sensor_pose']['position']['z'] =0 lidar_sensor_data['sensor_pose']['heading']['w'] =1 lidar_sensor_data['sensor_pose']['heading']['x'] =0 lidar_sensor_data['sensor_pose']['heading']['y'] =0 lidar_sensor_data['sensor_pose']['heading']['z'] =0 payload_data['data']['sensor_data']['sensors'].append(lidar_sensor_data)for camera_sensor_id, camera_sensor_urls in camera_data.items():# define camera sensor meta and add it to payload camera_sensor_meta =deepcopy(camera_sensor_meta_structure) camera_sensor_meta['id']= camera_sensor_id camera_sensor_meta['name']= camera_sensor_id payload_data['data']['sensor_data']['sensor_meta'].append(camera_sensor_meta)# define camera sensor data and add it to payload data camera_sensor_data =deepcopy(sensor_data_structure) camera_sensor_data['sensor_id']= camera_sensor_id camera_sensor_data['data_url']= camera_sensor_urls[i]# set appropriate camera position and heading, corrently defaulted it to (0,0,0),(1,0,0,0) camera_sensor_data['sensor_pose']['position']['x'] =0 camera_sensor_data['sensor_pose']['position']['y'] =0 camera_sensor_data['sensor_pose']['position']['z'] =0 camera_sensor_data['sensor_pose']['heading']['w'] =1 camera_sensor_data['sensor_pose']['heading']['x'] =0 camera_sensor_data['sensor_pose']['heading']['y'] =0 camera_sensor_data['sensor_pose']['heading']['z'] =0 payload_data['data']['sensor_data']['sensors'].append(camera_sensor_data)#print(json.dumps(payload_data))Upload_jobs(payload_data)