返回工作笔记
NOTE ARCHIVE现场记录无人机2026-07-08
GIS

WebODM_API流程详解

WebODM_API流程详解

Clark 更新于 2026-08-31 阅读约 6 分钟 阅读 3
阅读导航

适用场景:上传本地 ZIP 文件创建任务 → 轮询进度 → 下载正射影像
官方文档参考:https://docs.webodm.org/reference/


流程总览

Step 1: 获取 Token(身份认证)
   ↓
Step 2: 上传本地 ZIP 文件 → 创建任务 → 获取 task_id
   ↓
Step 3: 轮询任务执行进度(含百分比)
   ↓
Step 4: 任务完成后下载正射影像 .tif 文件

Step 1:获取 Token

接口信息

项目内容
方法POST
路径/api/token-auth/
认证无需
Content-Typeapplication/jsonapplication/x-www-form-urlencoded

请求体

{
  "username": "your_username",
  "password": "your_password"
}

响应体

{
  "token": "[ID已隐藏].eyJ1c2VybmFtZSI6ImFkbWluIn0.xxxxxx"
}

关键字段说明

字段类型说明
tokenstringJWT Token,后续所有请求需在 Header 中携带

注意事项

  • Token 默认 6小时 过期
  • 过期后接口返回 403,响应体为 {"detail": "Signature has expired."},需重新调用此接口获取新 Token
  • 所有后续请求 Header 格式固定为:Authorization: JWT <token>

cURL 示例

curl -X POST http://localhost:8000/api/token-auth/ \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "yourpassword"}'

Step 2:上传 ZIP 文件创建任务

接口信息

项目内容
方法POST
路径/api/projects/{project_id}/tasks/
认证Authorization: JWT <token>
Content-Typemultipart/form-data

{project_id} 为你要创建任务的目标项目 ID(整数)

请求字段(Form-Data)

字段名类型必填说明
imagesfile✅ 是本地 ZIP 文件(服务端会自动解压),字段名必须为 images
namestring任务名称,便于识别
optionsJSON stringODM 处理参数(见下方选项说明)
processing_nodeinteger指定处理节点 ID,不填则自动分配

options 参数说明(JSON 字符串格式)

[
  {"name": "orthophoto-resolution", "value": 5},
  {"name": "dsm", "value": true},
  {"name": "dtm", "value": false},
  {"name": "fast-orthophoto", "value": false}
]

常用 options 参数:

参数名类型默认值说明
orthophoto-resolutionfloat5正射影像分辨率(厘米/像素),值越小精度越高
dsmboolfalse是否生成数字地表模型(DSM)
dtmboolfalse是否生成数字地形模型(DTM)
fast-orthophotoboolfalse是否启用快速正射(精度略低但速度更快)
resize-tointeger2048影像预处理缩放像素大小,-1 为不缩放

响应体(201 Created)

{
  "id": "[ID已隐藏]",
  "project": 1,
  "name": "我的任务",
  "status": null,
  "progress": 0.0,
  "processing_time": -1,
  "images_count": 0,
  "created_at": "2026-04-14T08:00:00Z",
  "options": [
    {"name": "orthophoto-resolution", "value": 5}
  ],
  "available_assets": []
}

关键字段说明

字段类型说明
idstring (UUID)任务 ID,后续查询进度和下载成果必须使用此值
projectinteger所属项目 ID
statusinteger/null初始为 null,处理开始后变为数字状态码
progressfloat初始为 0.0,处理中为 0.0~1.0 的小数

cURL 示例

curl -X POST http://localhost:8000/api/projects/1/tasks/ \
  -H "Authorization: JWT eyJ0eXAi..." \
  -F "images=@/path/to/your/images.zip" \
  -F "name=测试任务" \
  -F 'options=[{"name":"orthophoto-resolution","value":5}]'

Step 3:查询任务执行进度

接口信息

项目内容
方法GET
路径/api/projects/{project_id}/tasks/{task_id}/
认证Authorization: JWT <token>

{task_id} 为 Step 2 响应中获取的 id 字段(UUID 格式)

响应体示例

{
  "id": "[ID已隐藏]",
  "project": 1,
  "name": "我的任务",
  "status": 20,
  "last_error": null,
  "progress": 0.45,
  "processing_time": 125000,
  "images_count": 120,
  "created_at": "2026-04-14T08:00:00Z",
  "available_assets": [],
  "options": [
    {"name": "orthophoto-resolution", "value": 5}
  ]
}

关键字段说明

字段类型说明
statusinteger / null任务状态码(见下方状态码表)
progressfloat任务进度,范围 0.0 ~ 1.0乘以 100 即为百分比
last_errorstring / null失败时的错误信息
processing_timeinteger已处理时长(毫秒),-1 表示尚未开始
available_assetsarray任务完成后可用的成果文件名列表

任务状态码(status 字段)

数值状态名含义
nullNEW任务已创建,尚未排队
10QUEUED已加入队列,等待处理节点
20RUNNING正在处理中,可通过 progress 获取百分比进度
30FAILED处理失败,查看 last_error 获取原因
40COMPLETED处理完成,可下载成果
50CANCELED已取消

进度百分比计算

任务百分比进度 = progress × 100
例:progress = 0.45 → 进度为 45%

轮询建议

  • 建议每 10~30 秒 轮询一次(影像处理耗时较长)
  • status == 40(COMPLETED)时停止轮询并进入 Step 4
  • status == 30(FAILED)时读取 last_error 字段排查原因

cURL 示例

curl http://localhost:8000/api/projects/1/tasks/[ID已隐藏]/ \
  -H "Authorization: JWT eyJ0eXAi..."

Step 4:下载正射影像 TIF 文件

接口信息

项目内容
方法GET
路径/api/projects/{project_id}/tasks/{task_id}/download/orthophoto.tif
认证Authorization: JWT <token>
响应类型二进制文件流(image/tiff

⚠️ 只有当 Step 3 中 status == 40(COMPLETED)且 available_assets 包含 orthophoto.tif 时,此接口才可用

确认可下载(通过 available_assets 判断)

Step 3 响应中,任务完成后 available_assets 字段示例:

{
  "available_assets": [
    "orthophoto.tif",
    "dsm.tif",
    "dtm.tif",
    "point_cloud.las",
    "textured_model.zip",
    "all.zip"
  ]
}

确认列表中存在 "orthophoto.tif" 后再调用下载接口。

完整下载路径

GET /api/projects/{project_id}/tasks/{task_id}/download/orthophoto.tif

cURL 示例

curl -o orthophoto.tif \
  -H "Authorization: JWT eyJ0eXAi..." \
  "http://localhost:8000/api/projects/1/tasks/[ID已隐藏]/download/orthophoto.tif"

完整 Python 代码示例

import requests
import json
import time

# ========== 配置区 ==========
BASE_URL   = "http://localhost:8000"   # WebODM 地址
USERNAME   = "admin"
PASSWORD   = "yourpassword"
PROJECT_ID = 1                          # 目标项目 ID
ZIP_PATH   = "/path/to/images.zip"     # 本地 ZIP 文件路径
OUTPUT_PATH = "orthophoto.tif"          # 下载保存路径
POLL_INTERVAL = 15                      # 轮询间隔(秒)
# ============================

# ---------- Step 1: 获取 Token ----------
print("=== Step 1: 获取 Token ===")
res = requests.post(
    f"{BASE_URL}/api/token-auth/",
    json={"username": USERNAME, "password": PASSWORD}
)
res.raise_for_status()
token = res.json()["token"]
headers = {"Authorization": f"JWT {token}"}
print(f"Token 获取成功")

# ---------- Step 2: 上传 ZIP 创建任务 ----------
print("\n=== Step 2: 上传 ZIP 文件,创建任务 ===")
options = json.dumps([
    {"name": "orthophoto-resolution", "value": 5}
])
with open(ZIP_PATH, "rb") as f:
    res = requests.post(
        f"{BASE_URL}/api/projects/{PROJECT_ID}/tasks/",
        headers=headers,
        files={"images": ("images.zip", f, "application/zip")},
        data={"name": "自动化任务", "options": options}
    )
res.raise_for_status()
task = res.json()
task_id = task["id"]
print(f"任务创建成功,Task ID: {task_id}")

# ---------- Step 3: 轮询任务进度 ----------
print("\n=== Step 3: 轮询任务进度 ===")
STATUS_MAP = {
    None: "NEW(已创建)",
    10:   "QUEUED(排队中)",
    20:   "RUNNING(处理中)",
    30:   "FAILED(失败)",
    40:   "COMPLETED(完成)",
    50:   "CANCELED(已取消)",
}
while True:
    res = requests.get(
        f"{BASE_URL}/api/projects/{PROJECT_ID}/tasks/{task_id}/",
        headers=headers
    )
    res.raise_for_status()
    info   = res.json()
    status = info.get("status")
    progress = info.get("progress", 0.0) or 0.0
    percent = round(progress * 100, 1)
    status_text = STATUS_MAP.get(status, f"未知状态({status})")
    print(f"状态: {status_text} | 进度: {percent}%")

    if status == 40:  # COMPLETED
        print("✅ 任务处理完成!")
        available = info.get("available_assets", [])
        print(f"可用成果文件: {available}")
        break
    elif status == 30:  # FAILED
        error = info.get("last_error", "未知错误")
        print(f"❌ 任务失败,错误信息: {error}")
        exit(1)
    elif status == 50:  # CANCELED
        print("⚠️ 任务已取消")
        exit(1)

    time.sleep(POLL_INTERVAL)

# ---------- Step 4: 下载正射影像 ----------
print("\n=== Step 4: 下载正射影像 TIF ===")
if "orthophoto.tif" not in available:
    print("❌ 正射影像文件不可用,请检查任务配置")
    exit(1)

res = requests.get(
    f"{BASE_URL}/api/projects/{PROJECT_ID}/tasks/{task_id}/download/orthophoto.tif",
    headers=headers,
    stream=True
)
res.raise_for_status()
with open(OUTPUT_PATH, "wb") as f:
    for chunk in res.iter_content(chunk_size=8192):
        if chunk:
            f.write(chunk)
print(f"✅ 正射影像下载完成,保存至: {OUTPUT_PATH}")

错误处理速查

HTTP 状态码原因处理方式
400请求参数错误(如 ZIP 字段名错误)检查 form-data 字段名是否为 images
401未携带 Token添加 Authorization: JWT <token> Header
403Token 过期或无权限重新执行 Step 1 获��新 Token
404project_id / task_id 不存在检查 ID 是否正确
500服务器内部错误检查 WebODM 服务日志

接口汇总速查表

步骤方法接口路径说明
Step 1POST/api/token-auth/获取 JWT Token
Step 2POST/api/projects/{project_id}/tasks/上传 ZIP 创建任务
Step 3GET/api/projects/{project_id}/tasks/{task_id}/查询任务状态和进度
Step 4GET/api/projects/{project_id}/tasks/{task_id}/download/orthophoto.tif下载正射影像