欢迎光临
我们一直在努力

【Python开源-单目测距】单目无人机多视角测距:DJI RTK图像 → 地面目标3D坐标与距离,平均RE仅2.12%

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

摘要:本文介绍一个开源的单目多视角测距项目,基于 DJI RTK 无人机图像,通过多视角三角测量恢复地面目标的 ECEF 三维坐标,进而计算目标间实际距离。实测 DJI Mavic 3E,25 样本,MAE 0.084m,平均相对误差 2.12%。项目包含核心算法库、Flask Web 演示应用、标定工具及完整文档,MIT 开源。


请添加图片描述

目录

  • 项目背景
  • 核心原理
  • 实测精度
  • 项目结构
  • 快速开始
  • 核心 API
  • 标定工具
  • 约束说明
  • 项目地址

![户外场景实测](https://i-blog.csdnimg.cn/direct/ab9aef2af64d4a589f17046e719d5b8c.jpeg

一、项目背景

在无人机外业作业中,有一个高频需求:

从航拍图像中,测量地面两个目标之间的实际距离。

现有方案的痛点:

方案局限
双目相机 成本高,DJI 工业机多为单目
激光测距 只能测相机到目标的距离,无法直接测目标间距
人工 RTK 打点 需要到达目标位置,部分场景无法靠近
GSD 推算 依赖精确 GSD,精度有限,只适合水平面目标

本项目的思路:DJI RTK 无人机在拍摄时已记录厘米级精度的位置(经纬高)与姿态(偏航/俯仰/横滚),结合像素坐标,多视角三角测量可以完整恢复目标的三维坐标。


二、核心原理

核心思路:同一个目标在不同位置拍摄时,每张图产生一条空间射线,多条射线的交点就是目标的 3D 坐标。为什么需要RTK?因为我们需要有一个世界坐标系来构建世界坐标系下的通过目标点的射线方程,RTK坐标系是一个非常精确的坐标系,非常适合用来做测距系统的世界坐标系,2个视角下通过同一个目标点的射线方程相交就可以计算出目标点在RTK坐标系下的精确3D坐标。 测距基本思想

2.1 整体流程

像素坐标 (u, v)
↓ 相机内参 + 去畸变
↓ 归一化相机坐标系射线
↓ RTK 姿态变换(camera → NED → ECEF)
↓ 射线方向 d_i + 光心位置 O_i(ECEF)
↓ 多视角最小二乘三角测量
→ 3D ECEF 坐标 X
→ 两点欧氏距离 ‖X_a – X_b‖ = 目标间距

2.2 坐标变换

射线方向变换到 ECEF:

d

i

=

R

e

c

e

f

←

n

e

d

(

l

a

t

,

l

o

n

)

⋅

R

n

e

d

←

b

o

d

y

(

y

a

w

,

p

i

t

c

h

,

r

o

l

l

)

⋅

R

c

a

m

←

b

o

d

y

⋅

d

c

a

m

\\mathbf{d}_i = R_{ecef\\leftarrow ned}(lat,lon) \\cdot R_{ned\\leftarrow body}(yaw,pitch,roll) \\cdot R_{cam\\leftarrow body} \\cdot \\mathbf{d}_{cam}

di​=Recef←ned​(lat,lon)⋅Rned←body​(yaw,pitch,roll)⋅Rcam←body​⋅dcam​

相机光心 ECEF 坐标:

O

i

=

ECEF

(

l

a

t

i

,

 

l

o

n

i

,

 

a

l

t

i

)

+

[

d

X

,

 

d

Y

,

 

d

Z

]

T

\\mathbf{O}_i = \\text{ECEF}(lat_i,\\ lon_i,\\ alt_i) + [dX,\\ dY,\\ dZ]^T

Oi​=ECEF(lati​, loni​, alti​)+[dX, dY, dZ]T

其中

[

d

X

,

d

Y

,

d

Z

]

[dX, dY, dZ]

[dX,dY,dZ] 为外参偏置,用于补偿云台安装误差。

2.3 最小二乘三角测量

每条观测构造一行方程:

(

I

−

d

i

d

i

T

)

X

=

(

I

−

d

i

d

i

T

)

O

i

(I – \\mathbf{d}_i\\mathbf{d}_i^T)\\mathbf{X} = (I – \\mathbf{d}_i\\mathbf{d}_i^T)\\mathbf{O}_i

(I−di​diT​)X=(I−di​diT​)Oi​

将

N

N

N 条观测堆叠为:

A

X

=

b

A\\mathbf{X} = b

AX=b

使用 numpy.linalg.lstsq 求解三维点

X

\\mathbf{X}

X。

2.4 测距

D

=

∥

X

a

−

X

b

∥

2

D = \\|\\mathbf{X}_a – \\mathbf{X}_b\\|_2

D=∥Xa​−Xb​∥2​


三、实测精度

测试平台:DJI Mavic 3E 可见光广角 样本数:25 真值范围:2.00m ~ 6.01m 基线范围:0.053m ~ 9.904m

汇总结果

机型NMAE(m)RMSE(m)平均 RE(%)Bias(m)
DJI Mavic 3E 25 0.084 0.126 2.120 +0.052

补充:最小 AE = 0.0002m,最大 AE = 0.363m;最小 RE = 0.006%,最大 RE = 6.05%。

分目标结果

观测点 IDNMAE(m)RMSE(m)平均 RE(%)Bias(m)
0 13 0.024 0.032 0.879 -0.012
1 3 0.158 0.176 2.628 +0.068
2 4 0.240 0.257 4.006 +0.240
3 5 0.071 0.075 3.533 +0.060

四、项目结构

MMVDMS/
├── src/
│ └── mvtriangulation/ # 核心算法库
│ ├── __init__.py # 公开 API 入口
│ ├── triangulator.py # CameraTriangulator
│ ├── transforms.py # 坐标变换
│ ├── pipeline.py # triangulate_dataframe
│ ├── models.py # 数据模型
│ ├── exceptions.py
│ ├── parsers/
│ │ └── dji_xmp.py # DJI EXIF/XMP 元数据解析
│ └── calibration/
│ ├── intrinsics_zhang.py # 张正友内参标定
│ └── extrinsics.py # 外参鲁棒拟合
├── apps/
│ └── flask_demo/ # Web 演示应用
├── examples/
│ ├── minimal_usage.py # 最小化完整示例
│ ├── fit_intrinsics_zhang.py # 内参标定示例
│ └── fit_extrinsics_robust.py # 外参拟合示例
├── docs/
│ ├── zh/ # 中文文档
│ └── en/ # 英文文档
├── requirements.txt
└── LICENSE


五、快速开始

环境要求:Python >= 3.8

git clone https://github.com/BRAIN-INSPIRED-TECHNOLOGY/MMVDMS.git
cd MMVDMS
pip install -r requirements.txt

5.1 运行最小化 Demo

# 使用内置 demo_csv 数据,默认 Mavic 3E 内参
python examples/minimal_usage.py \\
–points-csv examples/demo_csv/keypoints_observation2.csv \\
–image-dir examples/demo_images \\
–camera-model m3e

# 指定机型和关键点对
python examples/minimal_usage.py \\
–points-csv examples/demo_csv/keypoints_observation2.csv \\
–image-dir examples/demo_images \\
–camera-model m3t –pair 1-2

# 其他机型,传入自定义内参 JSON
python examples/minimal_usage.py \\
–points-csv examples/demo_csv/keypoints_observation2.csv \\
–image-dir examples/demo_images \\
–camera-model others \\
–intrinsics-json path/to/camera_intrinsics.json

5.2 启动 Web 演示应用

# 默认 Mavic 3E
python -m apps.flask_demo

# 指定机型
python -m apps.flask_demo –camera-model M3T

浏览器访问 http://localhost:5000,流程:导入图像 → 标注关键点 → 三角测量 → 查看距离 → 导出。


六、核心 API

三角测量

from mvtriangulation import (
CameraTriangulator,
triangulate_dataframe,
build_camera_arrays,
)

# 方式一:直接调用 pipeline
# 先构建相机参数(内参 + 外参偏置)
camera_matrix, dist_coeffs, extr_cfg = build_camera_arrays(intrinsics, extrinsics)
# df_xy 包含像素坐标 + 从原图 XMP 提取的位姿字段(lat/lon/alt/gimbal_pitch/yaw/roll)
result_df = triangulate_dataframe(df_xy, camera_matrix, dist_coeffs, extr_cfg)

# 方式二:使用 CameraTriangulator 直接三角测量
triangulator = CameraTriangulator()
point_3d = triangulator.triangulate(origins, directions)

元数据解析

from mvtriangulation import extract_dji_metadata_from_jpeg_bytes

with open("image.JPG", "rb") as f:
metadata = extract_dji_metadata_from_jpeg_bytes(f.read())
# 返回:纬度、经度、椭球高、偏航、俯仰、横滚


七、标定工具

7.1 张正友内参标定

python examples/fit_intrinsics_zhang.py \\
–images "data/calib/*.jpg" \\
–board-cols 9 \\
–board-rows 6 \\
–square-size 0.025 \\
–out "data/camera_intrinsics.json"

输出格式:

{
"camera_matrix": [[fx, 0, cx], [0, fy, cy], [0, 0, 1]],
"distortion_coefficients": [[k1, k2, p1, p2, k3]]
}

7.2 外参偏置拟合

用于补偿云台安装角误差:

python examples/fit_extrinsics_robust.py \\
–intrinsics "data/camera_intrinsics.json" \\
–fit-csv "data/obs_fit.csv" \\
–test-csv "data/obs_test.csv" \\
–out "data/camera_extrinsic_params.json" \\
–with-xyz-offset

7.3 内置默认内参(DJI Mavic 3E / 3T)

无标定文件时可直接使用内置参数快速启动:

机型分辨率fxfycxcy
DJI Mavic 3E 5280×3956 3660.0 3660.0 2640.0 1978.0
DJI Mavic 3T 8000×6000 5500.0 5500.0 4000.0 3000.0

注:默认内参为估算值,高精度场景请执行棋盘格标定。


八、约束说明

约束说明
必须 RTK 算法依赖厘米级位置与姿态,普通 GPS 精度不足
仅支持 DJI 元数据 其他厂商需自行实现解析接口
最少 2 帧观测 每个关键点至少需要 2 条有效射线
基线几何敏感 射线近平行时深度方向不稳定,精度下降
演示应用内存存储 重启后数据清空,非生产级

九、项目地址

  • GitHub:https://github.com/BRAIN-INSPIRED-TECHNOLOGY/MMVDMS.git
  • License:MIT
  • 文档:中英文均有(docs/zh/ 和 docs/en/)
  • Python 版本:>= 3.8

欢迎提交 Issue 或 PR。Bug 报告请附上复现步骤、Python 版本和报错日志;功能建议请先开 Issue 讨论。


如果本文对你有帮助,欢迎点赞收藏,也欢迎 GitHub Star 支持开源。

赞(0)
未经允许不得转载:171主机测评 » 【Python开源-单目测距】单目无人机多视角测距:DJI RTK图像 → 地面目标3D坐标与距离,平均RE仅2.12%
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址