API Introduction
DroneMapper Cloud API is an API for photogrammetric processing of aerial images. The API allows a developer to programatically interact with our Drone Mapping algorithms to generate georeferenced Digital Elevation Models, Orthomosaic Maps and Point Clouds with or without Ground Control Points (GCP).
Getting Started
Processing Imagery
The steps below outline what is required to process imagery via the API into a georeferenced Digital Elevation Model, Orthomosaic Map and Point Cloud.
- Request an API User and Authenticate via API.
- Create a Project.
- Upload Images to Create a Task
- Check for Task progress.
- Download the Digital Elevation Model, Orthomosaic and Point Cloud.
import requests
res = requests.post('https://dronemapper.io/api/token-auth/',
data={'username': 'API-USERNAME',
'password': 'API-PASSWORD'}).json()
token = res['token']
First, we authenticate with DroneMapper API. A token
is returned when authentication is successful.
res = requests.post('https://dronemapper.io/api/projects/',
headers={'Authorization': 'JWT {}'.format(token)},
data={'name': 'My First Project'}).json()
project_id = res['id']
Next we create a Project. We pass our token
via the Authorization
header. If we don’t pass this header, the system will not authenticate us and will refuse to process the request. We also assign a name
to our project.
images = [
('images', ('DJI_0001.JPG', open('DJI_0001.JPG', 'rb'), 'image/jpg')),
('images', ('DJI_0002.JPG', open('DJI_0002.JPG', 'rb'), 'image/jpg')),
# ...
]
options = json.dumps([
{'name': "null", 'value': "null"}
])
res = requests.post('https://dronemapper.io/api/projects/{}/tasks/'.format(project_id),
headers={'Authorization': 'JWT {}'.format(token)},
files=images,
data={
'options': options,
'name': "Optional Task Name"
}).json()
task_id = res['id']
We then create a Task. The only required parameter is a list of multiple, multipart-encoded images
. Processing will start automatically
as soon as a Processing Server is available. It is possible to specify additional options by passing an options
value, which is a JSON-encoded list of name/value pairs. Several other options are available for advanced API users.
while True:
res = requests.get('https://dronemapper.io/api/projects/{}/tasks/{}/'.format(project_id, task_id),
headers={'Authorization': 'JWT {}'.format(token)}).json()
if res['status'] == status_codes.COMPLETED:
print("Task has completed!")
break
elif res['status'] == status_codes.FAILED:
print("Task failed: {}".format(res))
sys.exit(1)
else:
print("Processing, hold on...")
time.sleep(3)
We periodically check for the Task status using a loop.
res = requests.get("https://dronemapper.io/api/projects/{}/tasks/{}/download/ORT-DrnMppr.tif".format(project_id, task_id),
headers={'Authorization': 'JWT {}'.format(token)},
stream=True)
with open("orthophoto.tif", 'wb') as f:
for chunk in res.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
print("Wrote ./orthophoto.tif")
The Orthomosaic, Digital Elevation Model and Point Cloud is ready to be downloaded. A variety of other assets, including Orthomosaic and DSM tiles are also available.
Reference
Authentication
Authentication Basics
Get authentication token:
curl -X POST -d "username=testuser&password=testpass" https://dronemapper.io/api/token-auth/
{"token":"eyJ0eXAiO..."}
Use authentication token:
curl -H "Authorization: JWT <your_token>" https://dronemapper.io/api/projects/
{"count":13, ...}
Use authentication token via querystring (less secure):
curl https://dronemapper.io/api/projects/?jwt=<your_token>
{"count":13, ...}
POST /api/token-auth/
Field | Type | Description |
---|---|---|
username | string | Username |
password | string | Password |
To access the API, you need to provide a valid username and password. You can create users from the DroneMapper API Administration page.
If authentication is successful, a token is issued. All API calls should include the following header:
Header |
---|
Authorization: JWT your_token |
The token expires after a set amount of time. See Token Expiration for more information.
Since applications sometimes do not allow headers to be modified, you can also authenticate by appending the jwt
querystring parameter to a protected URL. This is less secure, so pass the token via header if possible.
Token Expiration
The token expires after a predefined amount of time. The expiration time is dependent on DroneMapper’s settings. You will need to request another token when a token expires.
You know that a token has expired if any API call returns a 403
status code with the JSON body {'detail': 'Signature has expired.'}
.
Project
Example project:
{
"id": 2,
"tasks": [
7,
6,
5
],
"created_at": "2016-12-07T02:09:28.515319Z",
"name": "Test API Project",
"description": "",
"permissions": [
"delete",
"change",
"add",
"view"
]
}
A Project is a collection of Task items.
Field | Type | Description |
---|---|---|
id | int | Unique identifier |
tasks | int[] | List of task IDs associated with this project |
created_at | string | Creation date and time |
name | string | Name of the project |
description | string | A more in-depth description |
permissions | string[] | List of actions that the current user is allowed to perform. See Permissions Values |
Create a project
POST /api/projects/
Parameter | Required | Default | Description |
---|---|---|---|
name | * | “” | Name of the project |
description | “” | A more in-depth description |
Update a project
PATCH /api/projects/{id}/
Parameters are the same as above.
Delete a project
DELETE /api/projects/{id}/
Upon deletion, all Task items associated with the Project are deleted also. The operation is irreversible.
Get single project
GET /api/projects/{id}/
Get list of projects
Project list:
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 2,
"tasks": [
7,
6,
5
],
"created_at": "2016-12-07T02:09:28.515319Z",
"name": "Test API Project",
"description": ""
}
]
}
GET /api/projects/
Parameter | Required | Default | Description |
---|---|---|---|
page | 1 | Page number | |
id | “” | Filter by id | |
name | “” | Filter by name | |
description | “” | Filter by description | |
created_at | “” | Filter by created_at | |
ordering | “” | Ordering field to sort results by |
Example: Filtering by name
GET /api/projects/?name=hello
Retrieves projects that have a name of “hello”.
Example: Sorting
GET /api/projects/?ordering=-id
Sort by project ID, descending order.
Task
Example task:
{
"id": 1,
"project": 3,
"processing_node": 1,
"images_count": 48,
"can_rerun_from": [],
"available_assets": [
"all.zip",
"orthophoto.tif",
"dsm.tif",
"pointcloud.ply"
],
"uuid": "4338d684-91b4-49a2-b907-8ba171894393",
"name": "Task Name",
"processing_time": 2197417,
"auto_processing_node": false,
"status": 40,
"last_error": null,
"options": [],
"ground_control_points": null,
"created_at": "2017-02-18T18:01:55.402551Z",
"pending_action": null
}
A Task is the basic processing unit of DroneMapper. To compute an orthophoto, point cloud and textured model from a set of images, you need to create a Task.
Field | Type | Description |
---|---|---|
id | int | Unique identifier |
project | int | Project ID the task belongs to |
processing_node | int | The ID of the Processing Node this task has been assigned to, or null if no Processing Node has been assigned. |
images_count | int | Number of images |
can_rerun_from | string[] | List of possible “rerun-from” options that this task could restart from, given its currently assigned processing node. If this is an empty list, the task can only be restarted from the start of the pipeline. |
available_assets | string[] | List of assets available for download |
uuid | string | Unique identifier assigned by a Processing Node once processing has started. |
name | string | User defined name for the task |
processing_time | int | Milliseconds that have elapsed since the start of processing, or -1 if no information is available. Useful for displaying a time status report to the user. |
auto_processing_node | boolean | Whether DroneMapper should automatically assign the next available Processing Node to process this Task. A user can set this to false to manually choose a Processing Node. |
status | int | One of Status Codes, or null if no status is available. |
last_error | string | The last error message reported by a Processing Node in case of processing failure. |
options | JSON[] | JSON-encoded list of name/value pairs, where each pair represents a command line option to be passed to a Processing Node. |
ground_control_points | string | Currently unused. |
created_at | string | Creation date and time |
pending_action | int | One of Pending Actions, or null if no pending action is set. |
Create a task
POST /api/projects/{project_id}/tasks/
Parameter | Required | Default | Description |
---|---|---|---|
images[] | * | “” | List of multipart-encoded images (2 minimum) |
processing_node | null | The ID of the Processing Node this Task should be assigned to. If not specified, and auto_processing_node is true , a Processing Node will be automatically assigned. |
|
name | “” | User defined name for the task | |
auto_processing_node | true | Whether DroneMapper should automatically assign the next available Processing Node to process this Task. | |
options | “[]” | JSON-encoded list of name/value pairs, where each pair represents a command line option to be passed to a Processing Node. |
You assign a Task to a Project by passing the proper project_id
path in the URL.
Update a task
PATCH /api/projects/{project_id}/tasks/{task_id}/
Parameters are the same as above.
Get list of tasks
Task list:
[
{
"id": 6,
"project": 2,
"processing_node": 2,
"images_count": 89,
"uuid": "2e8b687d-c269-4e2f-91b3-5a2cd51b5321",
"name": "Test name",
"processing_time": 8402184,
"auto_processing_node": true,
"status": 40,
"last_error": null,
"options": [],
"ground_control_points": null,
"created_at": "2016-12-08T13:32:28.139474Z",
"pending_action": null
}
]
GET /api/projects/{project_id}/tasks/
Retrieves all Task items associated with project_id
.
Download assets
GET /api/projects/{project_id}/tasks/{task_id}/download/{asset}
After a task has been successfully processed, the user can download several assets from this URL. Not all assets are always available. For example if GPS information is missing from the input images, the orthophoto.tif
asset will be missing. You can check the available_assets
property of a Task to see which assets are available for download.
Asset | Description |
---|---|
all.zip | .ZIP of All Processed Products |
orthophoto.tif | Orthomosaic |
dsm.tif | Digital Elevation Model |
pointcloud.ply | Point Cloud |
Download assets (raw path)
GET /api/projects/{project_id}/tasks/{task_id}/assets/{path}
After a task has been successfully processed, its assets are stored in a directory on the file system. This API call allows direct access to the files in that directory (by default: DroneMapper/app/media/project/{project_id}/task/{task_id}/assets
). This can be useful to those applications that want to stream a Potree
dataset, or render a textured 3D model on the fly.
Retrieve console output
Console output example:
curl -H "Authorization: JWT <your_token>" https://dronemapper.io/api/projects/2/tasks/1/output/?line=5
[DEBUG] /var/www/data/e453747f-5fd4-4654-9622-b02727b29fc5/images\n[DEBUG] Loaded DJI_0219.JPG | camera: dji fc300s ...
GET /api/projects/{project_id}/tasks/{task_id}/output/
As a Task is being processed, processing nodes will return an output string that can be used for debugging and informative purposes. Output is only available after processing has started.
Parameter | Required | Default | Description |
---|---|---|---|
line | 0 | Only display the output starting from a certain line number. This can be useful to display output in realtime to the user by keeping track of the number of lines that have been displayed to the user so far and thus avoiding to download all output at every request. |
Cancel task
POST /api/projects/{project_id}/tasks/{task_id}/cancel/
Stop processing a Task. Canceled tasks can be restarted.
Remove task
POST /api/projects/{project_id}/tasks/{task_id}/remove/
All assets associated with it will be destroyed also. If the Task is currently being processed, processing will stop.
Restart task
POST /api/projects/{project_id}/tasks/{task_id}/restart/
If a Task has been canceled or has failed processing, or has completed but the user decided to change processing options, it can be restarted. If the Processing Node assigned to the Task has not changed, processing will happen more quickly compared to creating a new Task, since the Processing Node remembers the uuid
of the Task and will attempt to reuse previous results from the computation pipeline.
Orthomosaic TMS layer
GET /api/projects/{project_id}/tasks/{task_id}/orthophoto/tiles.json
GET /api/projects/{project_id}/tasks/{task_id}/orthophoto/tiles/{Z}/{X}/{Y}.png
After a task has been successfully processed, a TMS layer is made available for inclusion in programs such as Leaflet or Cesium.
Digital Elevation Model TMS layer
GET /api/projects/{project_id}/tasks/{task_id}/dsm/tiles.json
GET /api/projects/{project_id}/tasks/{task_id}/dsm/tiles/{Z}/{X}/{Y}.png
Pending Actions
In some circumstances, a Task can have a pending action that requires some amount of time to be performed.
Pending Action | Code | Description |
---|---|---|
CANCEL | 1 | Task is being canceled |
REMOVE | 2 | Task is being removed |
RESTART | 3 | Task is being restarted |
Status Codes
Status | Code | Description |
---|---|---|
QUEUED | 10 | Task’s files have been uploaded to a Processing Node and are waiting to be processed. |
RUNNING | 20 | Task is currently being processed. |
FAILED | 30 | Task has failed for some reason (not enough images, out of memory, Piero forgot to close a parenthesis, etc.) |
COMPLETED | 40 | Task has completed. Assets are be ready to be downloaded. |
CANCELED | 50 | Task was manually canceled by the user. |
Permissions
DroneMapper comes with a standard model level
permission system. You can
check whether users are logged-in and have privileges to act on things
model-wise.
On top of that, DroneMapper features a powerful row level
permission system. You can specify exactly which things a user has or has not access to, delete, change, etc.
Changes to the permissions of objects can be handled via the Administration
page.
We are planning to make it easier for users and developers to handle permissions via an API. This is a work in progress.
Permission Values
Permission | Description |
---|---|
delete | The object can be deleted |
change | The object can be edited |
add | A related object can be added to the object (a task can be added to the project) |
view | The object can be viewed (read-only) |
Handling Errors
All API calls use the status codes as described in the Django REST Framework’s Status Code Guide, but generally you only need to check for success status codes (200
or 204
), handle the special case of Token Expiration (403
) and report an error otherwise.
Error Status Codes
This is not an exhaustive list, but common error codes are listed below.
Status Code | Description |
---|---|
401 | Unauthenticated |
403 | Forbidden (token expired?) |
400 | Malformed request |
404 | Not found |
For security reasons, sometimes an operation which should return 403
returns 404
to avoid disclosing IDs and other information.