UAV/utils/odm_monitor.py

156 lines
5.3 KiB
Python
Raw Normal View History

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
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:
"""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 = "三维模式"):
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-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)
2025-04-12 22:48:07 +08:00
container.remove()
time.sleep(5)
2025-04-11 17:22:11 +08:00
else:
# 获取所有日志
logs = container.logs().decode("utf-8").splitlines()
# 输出最后 50 行日志
self.logger.info("容器运行完成,以下是最后 50 行日志:")
for line in logs[-50:]:
self.logger.info(line)
success = True
error_msg = ""
2025-04-12 22:48:07 +08:00
container.remove()
2025-04-11 17:22:11 +08:00
break
2025-01-04 17:54:03 +08:00
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]: 成功处理的网格点数据字典
"""
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("所有网格处理都失败,无法继续处理")
2025-04-11 17:22:11 +08:00
return successful_grid_lt