需求:

  1. 自建类似谷歌地球的微型服务器:用于管理、展示空间数据(如无人机影像);
  2. 将无人机照片 + RTK 点位等外业数据统一管理和展示:方便查看、浏览与组织外业成果。

工作流程

  1. 外业采集阶段:
    • 使用 RTK 采集点位 + 拍摄无人机照片(包含 EXIF GPS);
    • 同步照片、日志、点位文件(如 CSV/GPX/GeoJSON);
  2. 数据处理阶段:
    • 使用 WebODM 或 ODM 处理照片,输出正射图 / DSM / 点云;
    • 将 RTK 点位导入 PostGIS,统一坐标系统,加入属性信息;
    • 将生成的栅格图层(GeoTIFF)发布到 GeoServer;
  3. 可视化展示阶段:
    • 搭建 CesiumJS 页面或部署 TerriaMap;
    • 加载你发布的图层与点位,实现 Google Earth 类的展示体验;
    • 如果有拍摄照片的缩略图,也可以点击点位弹出原图(Pop-up);

WebODM + Cesium

功能与环境

能将无人机影像处理成果(正射影像、点云、DSM、RTK点)以 Google Earth 类方式展示。

  1. 在本地搭建 WebODM(用于无人机影像处理);

  2. 使用 CesiumJS 加载并三维展示处理成果(正射影像、DSM、高程、RTK点位);

  3. 整体构建一个类似 Google Earth 的微型数据管理和展示平台。

🖥️ 服务器系统

  • 操作系统:Debian +**
  • 内存推荐:≥16GB(大图像处理消耗资源)
  • 安装路径:建议统一放在 ~/uav-platform/

Part 1: 安装 WebODM

(无人机影像处理平台)

使用官方 Docker 版本(推荐)

# 1. 安装 Docker
# https://docs.docker.com/engine/install/ubuntu/

# 2. 克隆 WebODM
git clone https://github.com/OpenDroneMap/WebODM.git
cd WebODM

# 3. 启动 WebODM(首次运行会下载大量依赖)
./webodm.sh start

👉 默认会在本地运行 http://localhost:8000

手动安装 Docker Compose v2

错误
 ./webodm.sh start 
Checking for docker...   OK
Checking for docker compose... not found, we'll attempt to install it
#####################                                         19.2%curl: (92) HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)

🔍 步骤 1:确认 Docker 版本

docker --version

Docker 版本 ≥ 20.10 支持集成的 docker compose 子命令。

然后确认是否已有 Compose:

docker compose version

如果你得到 docker: 'compose' is not a docker command.,说明未安装 compose 插件。


🧩 步骤 2:安装 Docker Compose 插件

✅ 对于 Linux(Ubuntu、WSL2)

mkdir -p ~/.docker/cli-plugins/
curl -SL https://github.com/docker/compose/releases/download/v2.24.2/docker-compose-linux-x86_64 \
    -o ~/.docker/cli-plugins/docker-compose
chmod +x ~/.docker/cli-plugins/docker-compose

然后确认安装成功:

docker compose version

🔒如果你被防火墙或代理限制了 GitHub 下载,可以用以下国内镜像地址:

https://ghproxy.com/https://github.com/docker/compose/releases/download/...

🧪 步骤 3:重新启动 WebODM

cd WebODM
./webodm.sh start

此时应该不再尝试 curl 安装 compose,系统也能正确启动 WebODM 容器。

docker compose -f docker-compose.yml -f docker-compose.nodeodm.yml up --scale node-odm=1
[+] Running 5/5
 ✘ broker Error                      15.9s
 ✘ node-odm Error                    15.9s
 ✘ db Error                          15.9s
 ✘ worker Error                      15.9s
 ✘ webapp Error                      15.9s
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

使用代理访问 Docker Hub

如果你使用的是单位/校园网络,Docker 无法访问外网,可以使用代理转发:

1. 设置系统 HTTP 代理:

编辑 Docker 的 systemd 服务文件:

bash复制编辑sudo mkdir -p /etc/systemd/system/docker.service.d
sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf

填入你的代理地址:

ini复制编辑[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"

然后执行:

sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl restart docker

你也可以在运行 webodm.sh start 时设置环境变量:

HTTP_PROXY=http://127.0.0.1:7890 ./webodm.sh start

📁 成果数据结构

  • 处理成果通常包括:
    • odm_orthophoto/odm_orthophoto.tif(正射影像)
    • odm_georeferencing/odm_georeferenced_model.laz(点云)
    • odm_texturing/odm_textured_model.obj(三维模型)

Part 2: 安装 CesiumJS

(前端三维展示平台)

本地 Node.js + Cesium

# 安装 Node.js(推荐用 nvm)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
source ~/.bashrc
nvm install --lts

# 创建 Cesium 项目
mkdir ~/cesium-demo && cd ~/cesium-demo
npm init -y
npm install cesium

添加基本项目结构

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>海洋工程环境观测技术学科外业</title>
    <!-- 引入 Cesium 样式与主库 -->
    <script src="Cesium/Build/Cesium/Cesium.js"></script>
    <link href="Cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
    <!-- 自定义样式 -->
    <link href="css/style.css" rel="stylesheet">
</head>
<body>
    <!-- Cesium 容器 -->
    <div id="cesiumContainer" style="width: 100%; height: 100vh;"></div>

    <!-- 设置 Cesium Ion Access Token
    <script>
        Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxYjkzZWRlYi0zMGMwLTQzMjAtOTY1Ny0wMjY0Y2EwNTNjZmUiLCJpZCI6MzI2MzU0LCJpYXQiOjE3NTM3NTE0NjV9.VlmifFkdXPWiZxhWhboqQuubajCj1rRwRVF-uAzkNzYn8';
    </script>
    -->
    <!-- 加载主应用逻辑 -->
    <script src="js/app.js"></script>
</body>
</html>

CesiumTerrainProvider问题

CesiumJS v1.83 开始,createWorldTerrain() 被移到了 Cesium.Terrain 命名空间下,在新版打包方式中如果你直接加载 Build/Cesium/Cesium.js,默认不会带上 createWorldTerrain() 方法,除非你明确打包 Terrain.js 模块,如terrainProvider: new Cesium.CesiumTerrainProvider({ url: Cesium.IonResource.fromAssetId(1) // 世界地形(Cesium World Terrain)AssetId = 1

✅ 最简单修复方式

请将 terrainProvider 行替换成如下代码:

const viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProvider: new Cesium.CesiumTerrainProvider({
        url: Cesium.IonResource.fromAssetId(1)  // 世界地形(Cesium World Terrain)AssetId = 1
    }),
    imageryProvider: new Cesium.UrlTemplateImageryProvider({
        url: './data/ortho.tms/{z}/{x}/{y}.png',
        tilingScheme: new Cesium.WebMercatorTilingScheme(),
        maximumLevel: 20
    }),
    baseLayerPicker: false
});

这行代码将直接用 CesiumTerrainProvider 手动加载 Cesium Ion 上的世界地形(无需 createWorldTerrain())。

局域网访问

启动服务器

绑定到局域网 IP(不是 127.0.0.1)

以最常见的开发方式举例:

👉 Python(推荐,轻量):

cd your_project_folder
python -m http.server 8000 --bind 0.0.0.0
  • 然后在其他设备浏览器访问:

    http://192.168.1.100:8000
    

👉 Node.js(http-server):

npm install -g http-server
http-server -p 8000 -a 0.0.0.0

然后其他设备访问 http://<你电脑IP>:端口

如果局域网打不开

step1. 查看是否启用了防火墙

sudo ufw status

如果看到是 inactive,说明没启用。

如果启用,请添加规则:

sudo ufw allow 7101/tcp

step 2:确认网络连接

  • 在服务器上运行:
curl http://localhost:7101
  • 然后在 局域网中另一台电脑打开浏览器:
http://<服务器局域网IP>:7101

例如:

http://192.168.1.10:7101

如果能访问说明配置成功。

如你还想让公网用户也能访问,还需:

  1. 有公网 IP(或者配置内网穿透工具如 frp/ngrok)。
  2. 路由器开放端口并设置端口映射。
  3. 可使用域名绑定(可选)。

总结

1. 项目结构

├── Cesium
│   ├── Apps
│   ├── Build
│   ├── Cesium-1.131.zip
│   ├── CHANGES.md
│   ├── eslint.config.js
│   ├── favicon.ico
│   ├── gulpfile.js
│   ├── index.cjs
│   ├── index.html
│   ├── LICENSE.md
│   ├── package.json
│   ├── packages
│   ├── README.md
│   ├── scripts
│   ├── server.js
│   ├── Source
│   ├── Specs
│   ├── ThirdParty
│   └── web.config
├── css
│   └── style.css
├── data
│   └── rtk_points.geojson
├── index.html
└── js
    ├── app.js
    ├── app.js.old
    ├── app.js.old1
    └── app.js.old2

2. index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>海洋工程环境观测技术学科外业</title>
    <!-- 引入 Cesium 样式与主库 -->
    <script src="Cesium/Build/Cesium/Cesium.js"></script>
    <link href="Cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
    <!-- 自定义样式 -->
    <link href="css/style.css" rel="stylesheet">
</head>
<body>
    <!-- Cesium 容器 -->
    <div id="cesiumContainer" style="width: 100%; height: 100vh;"></div>

    <!-- 设置 Cesium Ion Access Token
    <script>
        Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxYjkzZWRlYi0zMGMwLTQzMjAtOTY1Ny0wMjY0Y2EwNTNjZmUiLCJpZCI6MzI2MzU0LCJpYXQiOjE3NTM3NTE0NjV9.VlmifFkdXPWiZxhWhboqQuubajCj1rRwRVF-uAzkNzYn8';
    </script>
    -->
    <!-- 加载主应用逻辑 -->
    <script src="js/app.js"></script>
</body>
</html>

3. app.js

// 创建 Cesium Viewer,设置 ESRI World Imagery 为基础图层
const viewer = new Cesium.Viewer('cesiumContainer', {
    imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
        url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
    }),
//    terrainProvider: new Cesium.CesiumTerrainProvider(),
//    baseLayerPicker: false
});

// 加载本地 ortho.tms 影像图层(叠加图层)
const orthoLayer = new Cesium.ImageryLayer(
    new Cesium.UrlTemplateImageryProvider({
        url: './data/ortho.tms/{z}/{x}/{y}.png',
        tilingScheme: new Cesium.WebMercatorTilingScheme(),
        maximumLevel: 20
    })
);
viewer.imageryLayers.add(orthoLayer);  // 添加为覆盖层

// 加载 GeoJSON 数据并飞行至数据区域
Cesium.GeoJsonDataSource.load('./data/rtk_points.geojson', {
    markerSize: 20,
    stroke: Cesium.Color.YELLOW,
    fill: Cesium.Color.CYAN.withAlpha(0.6)
}).then(dataSource => {
    viewer.dataSources.add(dataSource);
    viewer.flyTo(dataSource);
});

// 修复 Home 按钮不能飞到全球视图的问题
viewer.scene.camera.setView({
    destination: Cesium.Cartesian3.fromDegrees(0.0, 20.0, 20000000.0) // 初始视角设为全球
});

4. rtk_points.geojson

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": { "name": "RTK点1" },
      "geometry": {
        "type": "Point",
        "coordinates": [110.3401, 18.2512]
      }
    },
    {
      "type": "Feature",
      "properties": { "name": "RTK点2" },
      "geometry": {
        "type": "Point",
        "coordinates": [110.3420, 18.2520]
      }
    }
  ]
}

5. 启动服务

python

python3 -m http.server 71001 --bind 0.0.0.0

npm

sudo npm install -g http-server
http-server -p 71001 -a 0.0.0.0

6. 网络访问

本地访问

localhost:71001

局域网访问

192.168.0.100:71001

外网访问:使用 FRP + 自有 VPS + 自定义域名

🧱 网络结构示意图

公网用户 → yourdomain.com:7101
         ↓
    [公网 VPS:frps]
         ↓
[家庭内网服务器:frpc → 127.0.0.1:7101]

🛠️ 配置步骤详解

✅ 第一步:准备工作

  1. 确认 VPS 开放端口:
    • 确保你的 VPS 可以开放如 710170007500(frps监听端口)
    • 如果有防火墙(如 ufw 或云服务安全组),请放行这些端口
  2. 购买或已有域名(如 yourdomain.com),并在 DNS 提供商(如 Cloudflare)处控制解析

✅ 第二步:VPS 端部署 frps(服务端)

  1. 安装 frp
cd ~
wget https://github.com/fatedier/frp/releases/download/v0.58.0/frp_0.58.0_linux_amd64.tar.gz
tar -xzf frp_0.58.0_linux_amd64.tar.gz
cd frp_0.58.0_linux_amd64
  1. 编辑 frps.ini
[common]
bind_port = 7000            # FRP通信端口
dashboard_port = 7500       # 控制面板(可选)
dashboard_user = admin      # 控制台账号
dashboard_pwd = admin
vhost_http_port = 8080      # 若要穿透 HTTP 服务
vhost_https_port = 8443     # 可用于 HTTPS
  1. 启动 frps
./frps -c frps.ini

✅ 建议设置为 systemd 服务,保持开机自启(我可帮你写好 .service 文件)

✅ 第三步:内网客户端部署 frpc

你的家庭服务器(局域网那台)上部署客户端。

  1. 下载 frp 同版本

https://github.com/fatedier/frp/releases 下载对应操作系统版本。

  1. 编辑 frpc.ini
[common]
server_addr = <你的VPS公网IP>
server_port = 7000

[my-http]
type = http
local_ip = 127.0.0.1
local_port = 7101
custom_domains = my.yourdomain.com

你也可以用 tcp

[my-tcp]
type = tcp
local_ip = 127.0.0.1
local_port = 7101
remote_port = 7101
  1. 启动 frpc
./frpc -c frpc.ini

✅ 第四步:域名绑定与 DNS 设置

  1. 登录你的 DNS 服务提供商(如 Cloudflare)
  2. 添加一条 A 记录:
类型 主机记录(名称) 内容 代理状态
A my <VPS公网IP> 关闭(灰色云朵)
  1. 等 DNS 生效后,可以访问:
http://my.yourdomain.com   # 如果用 HTTP 类型穿透
或
http://<VPS_IP>:7101       # 如果用 TCP 端口穿透

🛡️ 安全建议

  • 使用域名 + HTTPS:可通过 Nginx + Let’s Encrypt 部署反向代理
  • frps 设置密码认证和 TLS
  • VPS 设置防火墙,仅开放必要端口

Part 3: WebODM 导入 Cesium

将无人机拍摄的 GeoTIFF 文件转换为 Cesium 可加载的瓦片形式({z}/{x}/{y}.png 结构):

0. 准备工具环境

你需要以下工具支持:

工具 说明
GDAL 用于地理数据转换,支持 gdal2tiles.py 工具
Node.js + Express 启动静态瓦片服务(你项目已具备)
GeoTIFF 文件 无人机拍摄的 .tif 文件(需带地理参考)

使用 gdalwarp 进行投影转换

确实正确!在将 .tif 影像切片为瓦片前,必须确保其为 Web Mercator 投影(EPSG:3857),这也是在线地图(如Cesium、Google Maps等)使用的标准投影系统。

1. 完整流程说明

  1. 原始 .tif 为 CGCS2000 投影(如 EPSG:4490)
  2. 使用 gdalwarp 进行重投影为 Web Mercator(EPSG:3857)
  3. gdal2tiles.py 将其切片为 {z}/{x}/{y}.png 瓦片
  4. 通过本地服务器发布该瓦片目录data/fie1.tms/
  5. 在 Cesium 中用 UrlTemplateImageryProvider 加载

2. 投影及其转换

使用 gdalwarp 进行投影转换

gdalwarp -t_srs EPSG:3857 -r bilinear -of GTiff -co COMPRESS=DEFLATE -co TILED=YES result.tif result_3857.tif
参数 说明
-t_srs EPSG:3857 目标投影是 Web Mercator
-r bilinear 重采样方式
-co TILED=YES 输出更适合瓦片切割
输出文件为 `result_3857.tif

常用 EPSG代码:

名称 代码 意义 基准面
WGS 84 (World Geodetic System 1984) EPSG:4326 使用经纬度表示 (longitude, latitude)。GPS、国际地图服务(如Google Earth)、Web前端地图库(Leaflet, OpenLayers)的基础坐标系。 全球通用坐标系(大地基准面)
Web Mercator / Pseudo-Mercator EPSG:3857 基于WGS 84的球形墨卡托投影。单位为米。几乎所有在线地图切片服务(Google Maps, OpenStreetMap, Bing Maps, Mapbox, ArcGIS Online)使用的标准投影。用于地图可视化。 全球通用坐标系(大地基准面)
CGCS2000 (China Geodetic Coordinate System 2000) EPSG:4490 使用经纬度表示 (longitude, latitude)。中国国家大地坐标系,2000国家大地坐标系。国内测绘和GIS项目的官方标准基准面。 中国常用坐标系(大地基准面)
EPSG:4479 CGCS2000 的3D版本(包含椭球高)
注意:CGCS2000与WGS84在定义和实现上非常接近,但在中国境内进行高精度测量和法定测绘时,必须使用CGCS2000。 ….
UTM (Universal Transverse Mercator) Zones - WGS84 EPSG:326XX 北半球UTM带(XX为带号) 投影坐标系(Projected - 单位为米)
EPSG:32650 WGS84 / UTM zone 50N (东经114°-120°) 投影坐标系
EPSG:32651 WGS84 / UTM zone 51N (东经120°-126°) (覆盖中国东部大部分地区) 投影坐标系
UTM Zones - CGCS2000 EPSG:449X CGCS2000的UTM投影正在逐步标准化,具体代码需查表。常见做法是先使用CGCS2000地理坐标系(4490),再进行投影转换。 投影坐标系
Gauss-Kruger (GK) / Transverse Mercator Zones - CGCS2000 (3°带) EPSG:451X 中国官方定义的CGCS2000高斯-克吕格投影分带(3度带) 投影坐标系
EPSG:4513 CGCS2000 / 3-degree Gauss-Kruger CM 75E (中央经线75°E) 投影坐标系
EPSG:4514 CGCS2000 / 3-degree Gauss-Kruger CM 78E 投影坐标系
EPSG:4522 CGCS2000 / 3-degree Gauss-Kruger CM 135E 投影坐标系
国内地形图、工程测量常用投影) 投影坐标系
Albers Equal Area Conic (China) 102025 (非官方但常用) 或 CGCS2000/Albers 中国全境或区域使用的等积圆锥投影,适合面积量算分析。标准参数(双标准纬线25°N, 47°N,中央经线105°E,原点0°N)。 投影坐标系
EGM2008 geoid EPSG:3855 全球重力大地水准面模型。用于将WGS84椭球高转换为近似海拔高(正高) 垂向基准
Yellow Sea 1985 EPSG:5730 中国常用的高程基准(验潮站平均海平面定义)。用于表示海拔高。 垂向基准

EPSG 选择依据

使用场景 首选EPSG代码 备注
全球数据交换/GPS 4326 (WGS84地理) 通用标准
Web地图显示 3857 (Web墨卡托) 在线地图标准
中国法定测绘/GIS 4490 (CGCS2000地理) 国家基准面
中国地形图/工程图(投影) 451X系列 (CGCS2000/GK) 4518(中央经线111°E)
中国区域面积分析 102025 (Albers中国) 需确认具体定义
国内在线地图(实际坐标) GCJ-02/BD-09 非标!需用专门SDK转换
海拔高程 5730 (黄海85) 或 3855 国内用5730,全球近似用3855

重要提示:

  1. 转换是关键: 不同坐标系间转换需使用精确参数可靠软件(如PROJ库、ArcGIS、QGIS、GDAL)。简单平移旋转无法满足精度要求。
  2. 中国特殊性: 国内数据处理务必注意GCJ-02/BD-09偏移问题。公开地图服务返回的坐标通常已偏移。
  3. 查证来源: 遇到不熟悉的EPSG代码,使用 epsg.io 网站查询详细定义。
  4. CGCS2000优先: 在中国进行新项目,强烈推荐使用CGCS2000 (4490或投影451X)作为基准。

3. 将 GeoTIFF 切片为 Web 瓦片(XYZ 瓦片)

使用 gdal2tiles.py 命令将 GeoTIFF 切为 {z}/{x}/{y}.png 的标准 XYZ 结构:

gdal2tiles.py -z 0-18 -r bilinear -w none path/to/your_image.tif path/to/output_tiles/

例如:

gdal2tiles.py -z 0-18 -r bilinear -w none --processes=4 reproj_3857.tif ../repo/cesium-dem/data/dan3.tms

参数解释:

参数 说明
-z 0-18 生成 0 到 18 级的瓦片(等级越大越清晰)
-r bilinear 使用双线性插值(也可换成 nearcubic
-w none 不生成 HTML 或 Google Maps 示例
–processes=4 加快切片速度
path/to/your_image.tif 原始无人机 GeoTIFF 文件路径
path/to/output_tiles/ 输出的瓦片文件夹路径(例如 public/uploads/tiles

转换成功后,会生成如下结构:

output_tiles/
├── 0/
│   └── 0/
│       └── 0.png
├── 1/
│   └── 0/
│       └── 0.png
├── ...
└── 18/
    └── ...

使用 gdal2tiles.pyGeoTIFF (result.tif) 转换为了 Web Mercator 格式的瓦片,并在本地生成了一个标准的 {z}/{x}/{y}.png 结构。这是展示无人机影像在 Cesium 中的标准方式之一。
但是 Cesium 默认采用的是 Google Maps / XYZ 瓦片格式(右上角为原点)。

关键:调整为 XYZ 格式

在使用 gdal2tiles.py 时增加 --xyz 参数:

gdal2tiles.py --xyz -z 0-18 -r bilinear -w none result.tif ../output_tiles/

这样生成的瓦片就是 Cesium 兼容的 {z}/{x}/{y}.png 结构(XYZ格式,右上角为原点)。

4. 前端 Cesium 中加载瓦片

// 加载本地 dan1.tms 影像图层(叠加图层)
const orthoProvider = new Cesium.UrlTemplateImageryProvider({
    url: './data/dan1.tms/{z}/{x}/{y}.png',
    tilingScheme: new Cesium.WebMercatorTilingScheme(),
    maximumLevel: 18,
    credit: "Drone Imagery"
});

const orthoLayer = new Cesium.ImageryLayer(orthoProvider);
viewer.imageryLayers.add(orthoLayer); // add dan1

// 加载 dan3.tif 转换的瓦片
const dan3Provider = new Cesium.UrlTemplateImageryProvider({
    url: "./data/dan3.tms/{z}/{x}/{y}.png",
    tilingScheme: new Cesium.WebMercatorTilingScheme(),
    maximumLevel: 18,
    credit: "Haian Imagery"
});
const dan3Layer = new Cesium.ImageryLayer(dan3Provider);
viewer.imageryLayers.add(dan3Layer); // add dan3

确保你已经在 .tif 切片时提供了 maximumLevel: 18 等级。

5.常见问题排查

问题 原因 解决方式
瓦片不显示 没有地理参考 gdalinfo your.tif 检查投影坐标系统
加载偏移或坐标不对 不是 Web Mercator 投影 使用 gdalwarp 先转为 EPSG:3857
Cesium 加载报错 路径错误或跨域 确保路径、端口、CORS 设置正确

可选:提前投影为 Web Mercator

gdalwarp -t_srs EPSG:3857 input.tif warped.tif

点云 / 三维模型(可选)

  • WebODM 生成的 .obj 可以使用 obj2gltf 转换为 .gltf,Cesium 原生支持。
npm install -g obj2gltf
obj2gltf -i odm_texturing/odm_textured_model.obj -o model.gltf

然后用以下方式加载:

viewer.scene.primitives.add(
  Cesium.Model.fromGltf({
    url: "./model.gltf",
    modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(
      Cesium.Cartesian3.fromDegrees(110.311, 18.311, 10)
    ),
    scale: 1.0,
  })
);