2024-12-23 11:31:20 +08:00
|
|
|
import os
|
2025-01-06 16:02:26 +08:00
|
|
|
import time
|
2024-12-23 11:31:20 +08:00
|
|
|
import logging
|
2024-12-28 11:06:03 +08:00
|
|
|
from typing import Dict, Tuple
|
|
|
|
import pandas as pd
|
2025-01-04 17:54:03 +08:00
|
|
|
import numpy as np
|
|
|
|
from osgeo import gdal
|
2025-04-11 17:22:11 +08:00
|
|
|
import docker
|
2025-01-04 17:54:03 +08:00
|
|
|
|
2025-01-06 15:50:11 +08:00
|
|
|
|
2024-12-23 11:31:20 +08:00
|
|
|
class ODMProcessMonitor:
|
2024-12-28 11:06:03 +08:00
|
|
|
"""ODM处理监控器"""
|
2024-12-23 11:31:20 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
def __init__(self, output_dir: str, mode: str = "三维模式"):
|
2024-12-28 11:06:03 +08:00
|
|
|
self.output_dir = output_dir
|
2024-12-23 11:31:20 +08:00
|
|
|
self.logger = logging.getLogger('UAV_Preprocess.ODMMonitor')
|
|
|
|
self.mode = mode
|
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
def run_odm_with_monitor(self, grid_dir: str, grid_id: tuple) -> Tuple[bool, str]:
|
2024-12-26 15:30:50 +08:00
|
|
|
"""运行ODM命令"""
|
2024-12-31 21:37:44 +08:00
|
|
|
self.logger.info(f"开始处理网格 ({grid_id[0]},{grid_id[1]})")
|
2025-01-06 19:48:27 +08:00
|
|
|
success = False
|
|
|
|
error_msg = ""
|
2025-01-04 17:54:03 +08:00
|
|
|
max_retries = 3
|
|
|
|
current_try = 0
|
2025-02-18 10:30:49 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
# 初始化 Docker 客户端
|
|
|
|
client = docker.from_env()
|
2024-12-26 11:32:46 +08:00
|
|
|
|
2025-01-04 17:54:03 +08:00
|
|
|
while current_try < max_retries:
|
|
|
|
current_try += 1
|
2025-01-06 15:50:11 +08:00
|
|
|
self.logger.info(
|
|
|
|
f"第 {current_try} 次尝试处理网格 ({grid_id[0]},{grid_id[1]})")
|
2025-01-02 20:11:47 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
# 构建 Docker 容器运行参数
|
|
|
|
grid_dir = grid_dir[0].lower(
|
|
|
|
) + grid_dir[1:].replace('\\', '/')
|
|
|
|
volumes = {
|
|
|
|
grid_dir: {'bind': '/datasets', 'mode': 'rw'}
|
|
|
|
}
|
|
|
|
command = (
|
|
|
|
f"--project-path /datasets project "
|
|
|
|
f"--max-concurrency 15 "
|
|
|
|
f"--force-gps "
|
|
|
|
f"--use-exif "
|
|
|
|
f"--use-hybrid-bundle-adjustment "
|
|
|
|
f"--optimize-disk-space "
|
|
|
|
f"--orthophoto-cutline "
|
|
|
|
f"--feature-type sift "
|
|
|
|
f"--orthophoto-resolution 8 "
|
|
|
|
)
|
2025-03-17 16:34:01 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
if self.mode == "快拼模式":
|
|
|
|
command += (
|
|
|
|
f"--fast-orthophoto "
|
|
|
|
f"--skip-3dmodel "
|
|
|
|
)
|
|
|
|
else: # 三维模式参数
|
|
|
|
command += (
|
|
|
|
f"--dsm "
|
|
|
|
f"--dtm "
|
|
|
|
)
|
2025-01-04 17:54:03 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
command += "--rerun-all"
|
2025-01-06 15:50:11 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
self.logger.info(f"Docker 命令: {command}")
|
2024-12-26 11:20:55 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
# 运行 Docker 容器
|
|
|
|
container = client.containers.run(
|
|
|
|
image="opendronemap/odm:gpu",
|
|
|
|
command=command,
|
|
|
|
volumes=volumes,
|
|
|
|
detach=True,
|
|
|
|
remove=False,
|
|
|
|
runtime="nvidia", # 使用 GPU
|
|
|
|
)
|
|
|
|
# 等待容器运行完成
|
|
|
|
exit_status = container.wait()
|
|
|
|
if exit_status["StatusCode"] != 0:
|
|
|
|
self.logger.error(
|
|
|
|
f"容器运行失败,退出状态码: {exit_status['StatusCode']}")
|
|
|
|
# 获取容器的错误日志
|
|
|
|
error_msg = container.logs(
|
|
|
|
stderr=True).decode("utf-8").splitlines()
|
|
|
|
self.logger.error("容器运行失败的详细错误日志:")
|
|
|
|
for line in error_msg:
|
|
|
|
self.logger.error(line)
|
|
|
|
else:
|
|
|
|
# 获取所有日志
|
|
|
|
logs = container.logs().decode("utf-8").splitlines()
|
2025-01-06 15:50:11 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
# 输出最后 50 行日志
|
|
|
|
self.logger.info("容器运行完成,以下是最后 50 行日志:")
|
|
|
|
for line in logs[-50:]:
|
|
|
|
self.logger.info(line)
|
|
|
|
success = True
|
|
|
|
error_msg = ""
|
|
|
|
break
|
2025-01-04 17:54:03 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
# 删除容器
|
|
|
|
container.remove()
|
|
|
|
time.sleep(5)
|
2025-01-06 15:50:11 +08:00
|
|
|
|
2025-01-06 19:48:27 +08:00
|
|
|
return success, error_msg
|
2025-01-04 17:54:03 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
def process_all_grids(self, grid_points: Dict[tuple, pd.DataFrame]) -> list:
|
2025-01-18 10:45:56 +08:00
|
|
|
"""处理所有网格
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Dict[tuple, pd.DataFrame]: 成功处理的网格点数据字典
|
|
|
|
"""
|
2024-12-28 11:06:03 +08:00
|
|
|
self.logger.info("开始执行网格处理")
|
2025-04-11 17:22:11 +08:00
|
|
|
successful_grid_lt = []
|
2025-01-04 17:54:03 +08:00
|
|
|
failed_grids = []
|
2025-01-18 10:45:56 +08:00
|
|
|
|
|
|
|
for grid_id, points in grid_points.items():
|
|
|
|
grid_dir = os.path.join(
|
|
|
|
self.output_dir, f'grid_{grid_id[0]}_{grid_id[1]}'
|
|
|
|
)
|
|
|
|
|
|
|
|
try:
|
|
|
|
success, error_msg = self.run_odm_with_monitor(
|
|
|
|
grid_dir=grid_dir,
|
|
|
|
grid_id=grid_id,
|
|
|
|
)
|
|
|
|
|
|
|
|
if success:
|
2025-04-11 17:22:11 +08:00
|
|
|
successful_grid_lt.append(grid_id)
|
2025-01-18 10:45:56 +08:00
|
|
|
else:
|
2025-01-06 15:50:11 +08:00
|
|
|
self.logger.error(
|
2025-01-18 10:45:56 +08:00
|
|
|
f"网格 ({grid_id[0]},{grid_id[1]}) 处理失败: {error_msg}")
|
2025-01-04 17:54:03 +08:00
|
|
|
failed_grids.append((grid_id, error_msg))
|
2025-01-06 15:50:11 +08:00
|
|
|
|
2025-01-18 10:45:56 +08:00
|
|
|
except Exception as e:
|
|
|
|
error_msg = str(e)
|
|
|
|
self.logger.error(
|
|
|
|
f"处理网格 ({grid_id[0]},{grid_id[1]}) 时发生异常: {error_msg}")
|
|
|
|
failed_grids.append((grid_id, error_msg))
|
|
|
|
|
2025-01-04 17:54:03 +08:00
|
|
|
# 汇总处理结果
|
|
|
|
total_grids = len(grid_points)
|
|
|
|
failed_count = len(failed_grids)
|
2025-04-11 17:22:11 +08:00
|
|
|
success_count = len(successful_grid_lt)
|
2025-01-06 15:50:11 +08:00
|
|
|
|
|
|
|
self.logger.info(
|
|
|
|
f"网格处理完成。总计: {total_grids}, 成功: {success_count}, 失败: {failed_count}")
|
2025-01-04 17:54:03 +08:00
|
|
|
if failed_grids:
|
|
|
|
self.logger.error("失败的网格:")
|
|
|
|
for grid_id, error_msg in failed_grids:
|
2025-01-06 15:50:11 +08:00
|
|
|
self.logger.error(
|
|
|
|
f"网格 ({grid_id[0]},{grid_id[1]}): {error_msg}")
|
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
if len(successful_grid_lt) == 0:
|
2025-01-04 17:54:03 +08:00
|
|
|
raise Exception("所有网格处理都失败,无法继续处理")
|
2024-12-28 11:06:03 +08:00
|
|
|
|
2025-04-11 17:22:11 +08:00
|
|
|
return successful_grid_lt
|