Create a job

A JOB

POST https://api.playment.io/v1/projects/:project_id/jobs

This endpoint allows you to create a job

Path Parameters

Headers

Request Body

{
  "data": {
    "job_id": "3f3e8675-ca69-46d7-aa34-96f90fcbb732",
    "reference_id": "001",
    "work_flow_id": "2aae1234-acac-1234-eeff-12a22a237bbc"
  },
  "success": true
}

Payload

{
  "reference_id": "001",
  "data": {
    "sensor_data": {
      "sensors": [
        {
          "sensor_id": "lidar",
          "data_url": "https://xyz.s3.com/123.pcd",
          "sensor_pose": {
            "position": {
              "x": 0,
              "y": 0,
              "z": 0
            },
            "heading": {
              "w": 1,
              "x": 0,
              "y": 0,
              "z": 0
            }
          }
        },
        {
          "sensor_id": "18158562",
          "data_url": "https://xyz.s3.com/123.jpg",
          "sensor_pose": {
            "position": {
              "x": -0.81,
              "y": 1.64,
              "z": -1.52
            },
            "heading": {
              "w": 0.68,
              "x": 0.66,
              "y": -0.21,
              "z": 0.19
            }
          }
        }
      ],
      "ego_pose": {
        "position": {
          "x": 0,
          "y": 0,
          "z": 0
        },
        "heading": {
          "w": 1,
          "x": 0,
          "y": 0,
          "z": 0
        }
      },
      "sensor_meta": [
        {
          "id": "lidar",
          "name": "lidar",
          "state": "editable",
          "modality": "lidar",
          "primary_view": true
        },
        {
          "id": "18158562",
          "name": "18158562",
          "state": "editable",
          "modality": "camera",
          "camera_model": "brown_conrady",
          "primary_view": false,
          "intrinsics": {
            "cx": 600,
            "cy": 400,
            "fx": 1200,
            "fy": 800,
            "k1": 0,
            "k2": 0,
            "k3": 0,
            "k4": 0,
            "p1": 0,
            "p2": 0,
            "skew": 0,
            "scale_factor": 1
          }
        }
      ]
    }
  },
  "work_flow_id": "2aae1234-acac-1234-eeff-12a22a237bbc"
}

Please share point clouds in ascii encoded PCD format

PCD format Specification: https://pcl.readthedocs.io/projects/tutorials/en/latest/pcd_file_format.html

# .PCD v0.7 - Point Cloud Data file format 
VERSION 0.7
FIELDS x y z
SIZE 4 4 4
TYPE F F F
COUNT 1 1 1
WIDTH 47286
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 47286
DATA ascii
5075.773 3756.887 107.923
5076.011 3756.876 107.865
5076.116 3756.826 107.844
5076.860 3756.975 107.648
5077.045 3756.954 107.605
5077.237 3756.937 107.559
5077.441 3756.924 107.511
5077.599 3756.902 107.474
5077.780 3756.885 107.432
5077.955 3756.862 107.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 format
VERSION 0.7
FIELDS x y z intensity
SIZE 4 4 4 4
TYPE F F F F
COUNT 1 1 1 1
WIDTH 33345
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 33345
DATA ascii
6.381713394829211 20.46125301261318 -2.413081058852035 0.02745098
5.28544895349773 16.913142630625543 -2.283128795562235 0.023529412
4.50899949078274 14.40011307442226 -2.1906859549297164 0.023529412
3.90763970412707 12.453374568477361 -2.108260110209615 0.023529412
2.9475040373348147 11.063306463789342 -2.0292308745898255 0.03137255
2.648762017271138 9.92654497521169 -1.991709336214386 0.03529412
3.4192604688595 9.368384486158 -1.99749275125155 0.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 json
import requests
from copy import deepcopy

## Functions
def create_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:
        raise Exception(f"Something went wrong at Playment's end {response.status_code}")
    if 400 <= response.status_code < 500:
        raise Exception(f"{response_data['error']['message']} {response.status_code}")
    print(response_data)
    return response_data

def Upload_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:
        raise Exception(f"Something went wrong at Playment's end {response.status_code}")
    if 400 <= response.status_code < 500:
        raise Exception(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 playment side
# BATCH_ID ->> The batch in which JOB needed to be created

PROJECT_ID = ''
CLIENT_KEY = ''
WORK_FLOW_ID = ''
BATCH_ID = ''


## Job creation payload structure

payload_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 sensor
    for camera_sensor_id, camer_sensor_urls in camera_data.items():
        assert len(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 jobs
    for i in range(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)

Last updated