修改容错代码
This commit is contained in:
parent
9935d8f789
commit
a3b03de856
@ -18,7 +18,6 @@ from utils.grid_divider import GridDivider
|
|||||||
from utils.logger import setup_logger
|
from utils.logger import setup_logger
|
||||||
from utils.visualizer import FilterVisualizer
|
from utils.visualizer import FilterVisualizer
|
||||||
from post_pro.merge_tif import MergeTif
|
from post_pro.merge_tif import MergeTif
|
||||||
from tools.test_docker_run import run_docker_command
|
|
||||||
from post_pro.merge_obj import MergeObj
|
from post_pro.merge_obj import MergeObj
|
||||||
from post_pro.merge_laz import MergePly
|
from post_pro.merge_laz import MergePly
|
||||||
|
|
||||||
@ -69,6 +68,7 @@ class ImagePreprocessor:
|
|||||||
config.output_dir, mode=config.mode)
|
config.output_dir, mode=config.mode)
|
||||||
self.visualizer = FilterVisualizer(config.output_dir)
|
self.visualizer = FilterVisualizer(config.output_dir)
|
||||||
|
|
||||||
|
# TODO 给出警告!
|
||||||
def _clean_output_dir(self):
|
def _clean_output_dir(self):
|
||||||
"""清理输出目录"""
|
"""清理输出目录"""
|
||||||
try:
|
try:
|
||||||
@ -303,7 +303,7 @@ if __name__ == "__main__":
|
|||||||
filter_dense_distance_threshold=10,
|
filter_dense_distance_threshold=10,
|
||||||
filter_time_threshold=timedelta(minutes=5),
|
filter_time_threshold=timedelta(minutes=5),
|
||||||
|
|
||||||
grid_size=1000,
|
grid_size=800,
|
||||||
grid_overlap=0.05,
|
grid_overlap=0.05,
|
||||||
|
|
||||||
|
|
||||||
|
134
tools/gps_selector.py
Normal file
134
tools/gps_selector.py
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from matplotlib.widgets import RectangleSelector
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
# 添加项目根目录到系统路径
|
||||||
|
project_root = str(Path(__file__).parent.parent)
|
||||||
|
sys.path.append(project_root)
|
||||||
|
|
||||||
|
from utils.gps_extractor import GPSExtractor
|
||||||
|
|
||||||
|
class GPSSelector:
|
||||||
|
def __init__(self, image_dir: str, output_dir: str = None):
|
||||||
|
self.image_dir = image_dir
|
||||||
|
self.output_dir = output_dir
|
||||||
|
self.gps_points = None
|
||||||
|
self.selected_points = []
|
||||||
|
self.fig, self.ax = plt.subplots(figsize=(12, 8))
|
||||||
|
self.scatter = None
|
||||||
|
self.rs = None
|
||||||
|
self.setup_plot()
|
||||||
|
|
||||||
|
def extract_gps(self):
|
||||||
|
"""提取GPS数据"""
|
||||||
|
extractor = GPSExtractor(self.image_dir)
|
||||||
|
self.gps_points = extractor.extract_all_gps()
|
||||||
|
print(f"成功提取 {len(self.gps_points)} 个GPS点")
|
||||||
|
|
||||||
|
def setup_plot(self):
|
||||||
|
"""设置绘图"""
|
||||||
|
self.ax.set_title('GPS Points - 使用鼠标拖动选择要删除的点')
|
||||||
|
self.ax.set_xlabel('Longitude')
|
||||||
|
self.ax.set_ylabel('Latitude')
|
||||||
|
self.ax.grid(True)
|
||||||
|
|
||||||
|
# 设置矩形选择器
|
||||||
|
self.rs = RectangleSelector(
|
||||||
|
self.ax, self.on_select,
|
||||||
|
interactive=True,
|
||||||
|
useblit=True,
|
||||||
|
button=[1], # 只响应左键
|
||||||
|
props=dict(facecolor='red', alpha=0.3)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 添加按钮回调
|
||||||
|
self.fig.canvas.mpl_connect('key_press_event', self.on_key_press)
|
||||||
|
|
||||||
|
def plot_gps_points(self):
|
||||||
|
"""绘制GPS点"""
|
||||||
|
if self.scatter is not None:
|
||||||
|
self.scatter.remove()
|
||||||
|
|
||||||
|
self.scatter = self.ax.scatter(
|
||||||
|
self.gps_points['lon'],
|
||||||
|
self.gps_points['lat'],
|
||||||
|
c='blue',
|
||||||
|
s=20,
|
||||||
|
alpha=0.6
|
||||||
|
)
|
||||||
|
self.fig.canvas.draw_idle()
|
||||||
|
|
||||||
|
def on_select(self, eclick, erelease):
|
||||||
|
"""矩形选择回调"""
|
||||||
|
x1, y1 = eclick.xdata, eclick.ydata
|
||||||
|
x2, y2 = erelease.xdata, erelease.ydata
|
||||||
|
|
||||||
|
# 获取选中区域内的点
|
||||||
|
mask = (
|
||||||
|
(self.gps_points['lon'] >= min(x1, x2)) &
|
||||||
|
(self.gps_points['lon'] <= max(x1, x2)) &
|
||||||
|
(self.gps_points['lat'] >= min(y1, y2)) &
|
||||||
|
(self.gps_points['lat'] <= max(y1, y2))
|
||||||
|
)
|
||||||
|
|
||||||
|
selected = self.gps_points[mask]
|
||||||
|
self.selected_points.extend(selected['file'].tolist())
|
||||||
|
|
||||||
|
# 从数据中移除选中的点
|
||||||
|
self.gps_points = self.gps_points[~mask]
|
||||||
|
|
||||||
|
# 更新绘图
|
||||||
|
self.plot_gps_points()
|
||||||
|
print(f"选中 {len(selected)} 个点,剩余 {len(self.gps_points)} 个点")
|
||||||
|
|
||||||
|
def on_key_press(self, event):
|
||||||
|
"""键盘事件回调"""
|
||||||
|
if event.key == 'enter':
|
||||||
|
self.save_results()
|
||||||
|
plt.close()
|
||||||
|
elif event.key == 'escape':
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
def save_results(self):
|
||||||
|
"""保存结果"""
|
||||||
|
if not self.output_dir:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 创建输出目录
|
||||||
|
os.makedirs(self.output_dir, exist_ok=True)
|
||||||
|
removed_dir = os.path.join(self.output_dir, "removed_images")
|
||||||
|
os.makedirs(removed_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# 移动被删除的图像
|
||||||
|
for img_name in self.selected_points:
|
||||||
|
src = os.path.join(self.image_dir, img_name)
|
||||||
|
dst = os.path.join(removed_dir, img_name)
|
||||||
|
shutil.move(src, dst)
|
||||||
|
|
||||||
|
# 保存剩余点的信息
|
||||||
|
self.gps_points.to_csv(
|
||||||
|
os.path.join(self.output_dir, "remaining_points.csv"),
|
||||||
|
index=False
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"已移动 {len(self.selected_points)} 张图片到 {removed_dir}")
|
||||||
|
print(f"保留 {len(self.gps_points)} 个点")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""运行选择器"""
|
||||||
|
self.extract_gps()
|
||||||
|
self.plot_gps_points()
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 使用示例
|
||||||
|
selector = GPSSelector(
|
||||||
|
image_dir=r"E:\datasets\UAV\1619\project\images",
|
||||||
|
output_dir=r"E:\datasets\UAV\1619\filtered"
|
||||||
|
)
|
||||||
|
selector.run()
|
@ -1,22 +0,0 @@
|
|||||||
import open3d as o3d
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
# 读取第一个PLY文件
|
|
||||||
pcd1 = o3d.io.read_point_cloud("path_to_first_file.ply")
|
|
||||||
|
|
||||||
# 读取第二个PLY文件
|
|
||||||
pcd2 = o3d.io.read_point_cloud("path_to_second_file.ply")
|
|
||||||
|
|
||||||
# 可选:如果需要调整坐标系,可以通过平移、旋转来对齐点云
|
|
||||||
# 例如,平移第二个点云
|
|
||||||
offset = np.array([1000, 2000, 3000])
|
|
||||||
pcd2.translate(offset)
|
|
||||||
|
|
||||||
# 合并点云
|
|
||||||
combined_pcd = pcd1 + pcd2
|
|
||||||
|
|
||||||
# 保存合并后的点云为PLY文件
|
|
||||||
o3d.io.write_point_cloud("merged_output.ply", combined_pcd)
|
|
||||||
|
|
||||||
# 可视化
|
|
||||||
o3d.visualization.draw_geometries([combined_pcd])
|
|
@ -13,26 +13,6 @@ class NotOverlapError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DockerNotRunError(Exception):
|
|
||||||
"""Docker未启动异常"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class DockerShareError(Exception):
|
|
||||||
"""Docker目录共享异常"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class OutOfMemoryError(Exception):
|
|
||||||
"""内存不足异常"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class StrangeValuesError(Exception):
|
|
||||||
"""异常值异常"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ODMProcessMonitor:
|
class ODMProcessMonitor:
|
||||||
"""ODM处理监控器"""
|
"""ODM处理监控器"""
|
||||||
|
|
||||||
@ -121,6 +101,8 @@ class ODMProcessMonitor:
|
|||||||
return False, "快拼模式下无法生成DEM,请调整生产参数"
|
return False, "快拼模式下无法生成DEM,请调整生产参数"
|
||||||
|
|
||||||
self.logger.info(f"开始处理网格 ({grid_id[0]},{grid_id[1]})")
|
self.logger.info(f"开始处理网格 ({grid_id[0]},{grid_id[1]})")
|
||||||
|
success = False
|
||||||
|
error_msg = ""
|
||||||
max_retries = 3
|
max_retries = 3
|
||||||
current_try = 0
|
current_try = 0
|
||||||
use_lowest_quality = True # 初始使用lowest quality
|
use_lowest_quality = True # 初始使用lowest quality
|
||||||
@ -146,7 +128,7 @@ class ODMProcessMonitor:
|
|||||||
if use_lowest_quality:
|
if use_lowest_quality:
|
||||||
docker_command += f"--feature-quality lowest "
|
docker_command += f"--feature-quality lowest "
|
||||||
|
|
||||||
docker_command += f"--orthophoto-resolution 10 "
|
docker_command += f"--orthophoto-resolution 8 "
|
||||||
|
|
||||||
if produce_dem:
|
if produce_dem:
|
||||||
docker_command += (
|
docker_command += (
|
||||||
@ -177,11 +159,12 @@ class ODMProcessMonitor:
|
|||||||
self.logger.error(f"docker run指令执行失败")
|
self.logger.error(f"docker run指令执行失败")
|
||||||
self.logger.error(f"==========stderr==========: {stderr}")
|
self.logger.error(f"==========stderr==========: {stderr}")
|
||||||
if "error during connect" in stderr or "The system cannot find the file specified" in stderr:
|
if "error during connect" in stderr or "The system cannot find the file specified" in stderr:
|
||||||
raise DockerNotRunError
|
error_msg = "Docker没有启动,请启动Docker"
|
||||||
elif "user declined directory sharing" in stderr:
|
elif "user declined directory sharing" in stderr:
|
||||||
raise DockerShareError
|
error_msg = "Docker无法访问目录,请检查目录权限和共享设置"
|
||||||
else:
|
else:
|
||||||
raise Exception(f"Docker运行失败,需要人工排查错误")
|
error_msg = "Docker运行失败,需要人工排查错误"
|
||||||
|
break
|
||||||
# TODO 处理时间组删除,删多了的情况
|
# TODO 处理时间组删除,删多了的情况
|
||||||
else:
|
else:
|
||||||
self.logger.info("docker run指令执行成功")
|
self.logger.info("docker run指令执行成功")
|
||||||
@ -190,49 +173,37 @@ class ODMProcessMonitor:
|
|||||||
if self._check_success(grid_dir):
|
if self._check_success(grid_dir):
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
f"网格 ({grid_id[0]},{grid_id[1]}) 处理成功")
|
f"网格 ({grid_id[0]},{grid_id[1]}) 处理成功")
|
||||||
return True, ""
|
success = True
|
||||||
|
error_msg = ""
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
self.logger.error(
|
self.logger.error(
|
||||||
f"虽然ODM处理完成,但是生产产品质量可能不合格,需要人工检查")
|
f"虽然ODM处理完成,但是生产产品质量可能不合格,需要人工检查")
|
||||||
raise Exception(f"虽然ODM处理完成,但是生产产品质量可能不合格,需要人工检查")
|
raise NotOverlapError
|
||||||
|
# TODO 先写成这样,后面这三种情况可能处理不一样
|
||||||
elif "enough overlap" in last_lines:
|
elif "enough overlap" in last_lines:
|
||||||
raise NotOverlapError
|
raise NotOverlapError
|
||||||
elif "out of memory" in last_lines:
|
elif "out of memory" in last_lines:
|
||||||
raise OutOfMemoryError
|
raise NotOverlapError
|
||||||
elif "strange values" in last_lines:
|
elif "strange values" in last_lines:
|
||||||
raise StrangeValuesError
|
raise NotOverlapError
|
||||||
else:
|
else:
|
||||||
raise Exception(f"ODM处理失败,需要人工排查错误")
|
raise NotOverlapError
|
||||||
|
|
||||||
except NotOverlapError:
|
except NotOverlapError:
|
||||||
if use_lowest_quality:
|
if use_lowest_quality:
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
"检测到not overlap错误,移除lowest quality参数后重试")
|
"检测到not overlap错误,移除lowest quality参数后重试")
|
||||||
use_lowest_quality = False
|
use_lowest_quality = False
|
||||||
|
time.sleep(10)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
self.logger.error(
|
self.logger.error(
|
||||||
"即使移除lowest quality参数后仍然出现not overlap错误")
|
"即使移除lowest quality参数后仍然出现错误")
|
||||||
return False, "图像重叠度不足,请检查数据集的采样间隔情况"
|
error_msg = "图像重叠度不足,需要人工检查数据集的采样间隔情况"
|
||||||
|
break
|
||||||
|
|
||||||
except DockerNotRunError:
|
return success, error_msg
|
||||||
self.logger.error("Docker服务未启动")
|
|
||||||
return False, "Docker没有启动,请启动Docker"
|
|
||||||
|
|
||||||
except DockerShareError:
|
|
||||||
self.logger.error("Docker无法访问目录")
|
|
||||||
return False, "Docker无法访问数据目录或输出目录,请检查目录权限和共享设置"
|
|
||||||
|
|
||||||
except OutOfMemoryError:
|
|
||||||
self.logger.error("内存不足,请减少输入图像的数量")
|
|
||||||
return False, "内存不足"
|
|
||||||
except StrangeValuesError:
|
|
||||||
self.logger.error("重建过程中出现异常值")
|
|
||||||
return False, "检测到异常值,请检查输入数据集的采样间隔情况"
|
|
||||||
|
|
||||||
time.sleep(10)
|
|
||||||
|
|
||||||
return False, f"网格 ({grid_id[0]},{grid_id[1]}) 处理失败"
|
|
||||||
|
|
||||||
def process_all_grids(self, grid_points: Dict[tuple, pd.DataFrame], produce_dem: bool) -> Dict[tuple, pd.DataFrame]:
|
def process_all_grids(self, grid_points: Dict[tuple, pd.DataFrame], produce_dem: bool) -> Dict[tuple, pd.DataFrame]:
|
||||||
"""处理所有网格
|
"""处理所有网格
|
||||||
|
Loading…
Reference in New Issue
Block a user