修改合并obj的算法
This commit is contained in:
parent
82fdcdca87
commit
ad6f4fb1ae
2
main.py
2
main.py
@ -1,6 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from odm_preprocess import PreprocessConfig, ImagePreprocessor
|
from odm_preprocess_fast import PreprocessConfig, ImagePreprocessor
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
parser = argparse.ArgumentParser(description='ODM预处理工具')
|
parser = argparse.ArgumentParser(description='ODM预处理工具')
|
||||||
|
@ -18,7 +18,7 @@ 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 post_pro.merge_obj import MergeObj
|
from post_pro.obj_post_pro import ObjPostProcessor
|
||||||
from post_pro.merge_laz import MergePly
|
from post_pro.merge_laz import MergePly
|
||||||
|
|
||||||
|
|
||||||
@ -257,8 +257,8 @@ class ImagePreprocessor:
|
|||||||
def merge_obj(self, grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple]):
|
def merge_obj(self, grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple]):
|
||||||
"""合并所有网格的OBJ模型"""
|
"""合并所有网格的OBJ模型"""
|
||||||
self.logger.info("开始合并OBJ模型")
|
self.logger.info("开始合并OBJ模型")
|
||||||
merger = MergeObj(self.config.output_dir)
|
processor = ObjPostProcessor(self.config.output_dir)
|
||||||
merger.merge_grid_obj(grid_points, translations)
|
processor.process_obj_files()
|
||||||
|
|
||||||
def post_process(self, successful_grid_points: Dict[tuple, pd.DataFrame], grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple]):
|
def post_process(self, successful_grid_points: Dict[tuple, pd.DataFrame], grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple]):
|
||||||
"""后处理:合并或复制处理结果"""
|
"""后处理:合并或复制处理结果"""
|
||||||
|
@ -18,7 +18,7 @@ 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 post_pro.merge_obj import MergeObj
|
from post_pro.obj_post_pro import ObjPostProcessor
|
||||||
from post_pro.merge_laz import MergePly
|
from post_pro.merge_laz import MergePly
|
||||||
|
|
||||||
|
|
||||||
@ -187,6 +187,21 @@ class ImagePreprocessor:
|
|||||||
self.visualizer.visualize_filter_step(
|
self.visualizer.visualize_filter_step(
|
||||||
self.gps_points, previous_points, "3-Time Group Overlap")
|
self.gps_points, previous_points, "3-Time Group Overlap")
|
||||||
|
|
||||||
|
def filter_alternate_images(self):
|
||||||
|
"""按时间顺序隔一个删一个图像来降低密度"""
|
||||||
|
previous_points = self.gps_points.copy()
|
||||||
|
|
||||||
|
# 按时间戳排序
|
||||||
|
self.gps_points = self.gps_points.sort_values('date')
|
||||||
|
|
||||||
|
# 保留索引为偶数的行(即隔一个保留一个)
|
||||||
|
self.gps_points = self.gps_points.iloc[::2].reset_index(drop=True)
|
||||||
|
|
||||||
|
self.visualizer.visualize_filter_step(
|
||||||
|
self.gps_points, previous_points, "4-Alternate Images")
|
||||||
|
|
||||||
|
self.logger.info(f"交替过滤后剩余 {len(self.gps_points)} 个点")
|
||||||
|
|
||||||
def divide_grids(self) -> Tuple[Dict[tuple, pd.DataFrame], Dict[tuple, tuple]]:
|
def divide_grids(self) -> Tuple[Dict[tuple, pd.DataFrame], Dict[tuple, tuple]]:
|
||||||
"""划分网格
|
"""划分网格
|
||||||
Returns:
|
Returns:
|
||||||
@ -220,7 +235,7 @@ class ImagePreprocessor:
|
|||||||
|
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
|
||||||
for point in tqdm(points, desc=f"复制网格 ({grid_id[0]},{grid_id[1]}) 的图像"):
|
for point in points:
|
||||||
src = os.path.join(self.config.image_dir, point["file"])
|
src = os.path.join(self.config.image_dir, point["file"])
|
||||||
dst = os.path.join(output_dir, point["file"])
|
dst = os.path.join(output_dir, point["file"])
|
||||||
shutil.copy(src, dst)
|
shutil.copy(src, dst)
|
||||||
@ -242,8 +257,8 @@ class ImagePreprocessor:
|
|||||||
def merge_obj(self, grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple]):
|
def merge_obj(self, grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple]):
|
||||||
"""合并所有网格的OBJ模型"""
|
"""合并所有网格的OBJ模型"""
|
||||||
self.logger.info("开始合并OBJ模型")
|
self.logger.info("开始合并OBJ模型")
|
||||||
merger = MergeObj(self.config.output_dir)
|
processor = ObjPostProcessor(self.config.output_dir)
|
||||||
merger.merge_grid_obj(grid_points, translations)
|
processor.process_obj_files()
|
||||||
|
|
||||||
def post_process(self, successful_grid_points: Dict[tuple, pd.DataFrame], grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple]):
|
def post_process(self, successful_grid_points: Dict[tuple, pd.DataFrame], grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple]):
|
||||||
"""后处理:合并或复制处理结果"""
|
"""后处理:合并或复制处理结果"""
|
||||||
@ -259,8 +274,8 @@ class ImagePreprocessor:
|
|||||||
self.merge_ply(successful_grid_points)
|
self.merge_ply(successful_grid_points)
|
||||||
self.merge_obj(successful_grid_points, translations)
|
self.merge_obj(successful_grid_points, translations)
|
||||||
else:
|
else:
|
||||||
self.merge_tif(successful_grid_points, self.config.produce_dem)
|
# self.merge_tif(successful_grid_points, self.config.produce_dem)
|
||||||
self.merge_ply(successful_grid_points)
|
# self.merge_ply(successful_grid_points)
|
||||||
self.merge_obj(successful_grid_points, translations)
|
self.merge_obj(successful_grid_points, translations)
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
@ -270,6 +285,7 @@ class ImagePreprocessor:
|
|||||||
self.cluster()
|
self.cluster()
|
||||||
self.filter_isolated_points()
|
self.filter_isolated_points()
|
||||||
self.filter_time_group_overlap()
|
self.filter_time_group_overlap()
|
||||||
|
# self.filter_alternate_images()
|
||||||
grid_points, translations = self.divide_grids()
|
grid_points, translations = self.divide_grids()
|
||||||
# self.copy_images(grid_points)
|
# self.copy_images(grid_points)
|
||||||
self.logger.info("预处理任务完成")
|
self.logger.info("预处理任务完成")
|
||||||
|
182
post_pro/obj_post_pro.py
Normal file
182
post_pro/obj_post_pro.py
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
from typing import List, Tuple
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
class ObjPostProcessor:
|
||||||
|
def __init__(self, output_dir: str):
|
||||||
|
self.output_dir = output_dir
|
||||||
|
self.logger = logging.getLogger('UAV_Preprocess.ObjPostProcessor')
|
||||||
|
# 用于存储所有grid的UTM范围
|
||||||
|
self.min_east = float('inf')
|
||||||
|
self.min_north = float('inf')
|
||||||
|
self.max_east = float('-inf')
|
||||||
|
self.max_north = float('-inf')
|
||||||
|
|
||||||
|
def process_obj_files(self):
|
||||||
|
"""处理所有grid中的obj文件"""
|
||||||
|
try:
|
||||||
|
# 1. 遍历所有grid文件夹
|
||||||
|
grid_dirs = [d for d in os.listdir(
|
||||||
|
self.output_dir) if d.startswith('grid_')]
|
||||||
|
|
||||||
|
# 第一次遍历:获取所有grid的UTM范围
|
||||||
|
for grid_dir in grid_dirs:
|
||||||
|
grid_path = os.path.join(self.output_dir, grid_dir)
|
||||||
|
log_file = os.path.join(
|
||||||
|
grid_path, 'project', 'odm_orthophoto', 'odm_orthophoto_log.txt')
|
||||||
|
east_offset, north_offset = self.read_utm_offset(log_file)
|
||||||
|
|
||||||
|
# 更新UTM范围
|
||||||
|
self.min_east = min(self.min_east, east_offset)
|
||||||
|
self.min_north = min(self.min_north, north_offset)
|
||||||
|
self.max_east = max(self.max_east, east_offset)
|
||||||
|
self.max_north = max(self.max_north, north_offset)
|
||||||
|
|
||||||
|
# 创建osgb输出目录
|
||||||
|
osgb_dir = os.path.join(self.output_dir, 'osgb')
|
||||||
|
os.makedirs(os.path.join(osgb_dir, 'Data'), exist_ok=True)
|
||||||
|
|
||||||
|
# 第二次遍历:处理每个grid
|
||||||
|
for grid_dir in grid_dirs:
|
||||||
|
grid_path = os.path.join(self.output_dir, grid_dir)
|
||||||
|
self.process_single_grid(grid_path, osgb_dir)
|
||||||
|
|
||||||
|
# 创建metadata.xml
|
||||||
|
self.create_metadata_xml(osgb_dir)
|
||||||
|
|
||||||
|
self.logger.info("所有grid处理完成")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"处理obj文件时发生错误: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def process_single_grid(self, grid_path: str, osgb_dir: str):
|
||||||
|
"""处理单个grid的obj文件"""
|
||||||
|
try:
|
||||||
|
# 1. 读取UTM偏移量
|
||||||
|
log_file = os.path.join(
|
||||||
|
grid_path, 'project', 'odm_orthophoto', 'odm_orthophoto_log.txt')
|
||||||
|
utm_offset = self.read_utm_offset(log_file)
|
||||||
|
|
||||||
|
# 2. 修改obj文件的顶点坐标
|
||||||
|
obj_file = os.path.join(
|
||||||
|
grid_path, 'project', 'odm_texturing', 'odm_textured_model_geo.obj')
|
||||||
|
modified_obj = self.modify_obj_coordinates(obj_file, utm_offset)
|
||||||
|
|
||||||
|
# 3. 使用osgconv转换为osgb
|
||||||
|
grid_name = os.path.basename(grid_path)
|
||||||
|
self.convert_to_osgb(modified_obj, grid_name, osgb_dir)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"处理grid {grid_path} 时发生错误: {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def read_utm_offset(self, log_file: str) -> Tuple[float, float]:
|
||||||
|
"""读取UTM偏移量"""
|
||||||
|
try:
|
||||||
|
east_offset = None
|
||||||
|
north_offset = None
|
||||||
|
|
||||||
|
with open(log_file, 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if 'utm_north_offset' in line and i + 1 < len(lines):
|
||||||
|
north_offset = float(lines[i + 1].strip())
|
||||||
|
elif 'utm_east_offset' in line and i + 1 < len(lines):
|
||||||
|
east_offset = float(lines[i + 1].strip())
|
||||||
|
|
||||||
|
if east_offset is None or north_offset is None:
|
||||||
|
raise ValueError("未找到UTM偏移量")
|
||||||
|
|
||||||
|
return east_offset, north_offset
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"读取UTM偏移量时发生错误: {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def modify_obj_coordinates(self, obj_file: str, utm_offset: Tuple[float, float]) -> str:
|
||||||
|
"""修改obj文件中的顶点坐标,使用相对坐标系"""
|
||||||
|
east_offset, north_offset = utm_offset
|
||||||
|
output_obj = obj_file.replace('.obj', '_utm.obj')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(obj_file, 'r') as f_in, open(output_obj, 'w') as f_out:
|
||||||
|
for line in f_in:
|
||||||
|
if line.startswith('v '):
|
||||||
|
# 处理顶点坐标行
|
||||||
|
parts = line.strip().split()
|
||||||
|
# 使用相对于整体最小UTM坐标的偏移
|
||||||
|
x = float(parts[1]) + (east_offset - self.min_east)
|
||||||
|
y = float(parts[2]) + (north_offset - self.min_north)
|
||||||
|
z = float(parts[3])
|
||||||
|
f_out.write(f'v {x:.6f} {y:.6f} {z:.6f}\n')
|
||||||
|
else:
|
||||||
|
# 其他行直接写入
|
||||||
|
f_out.write(line)
|
||||||
|
|
||||||
|
# 复制材质文件
|
||||||
|
mtl_file = obj_file.replace('.obj', '.mtl')
|
||||||
|
if os.path.exists(mtl_file):
|
||||||
|
shutil.copy2(mtl_file, mtl_file.replace('.mtl', '_utm.mtl'))
|
||||||
|
|
||||||
|
return output_obj
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"修改obj坐标时发生错误: {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def convert_to_osgb(self, obj_file: str, grid_name: str, osgb_dir: str):
|
||||||
|
"""使用osgconv将obj转换为osgb"""
|
||||||
|
try:
|
||||||
|
# 创建tile目录
|
||||||
|
tile_dir = os.path.join(osgb_dir, 'Data', grid_name)
|
||||||
|
os.makedirs(tile_dir, exist_ok=True)
|
||||||
|
|
||||||
|
output_osgb = os.path.join(tile_dir, f'{grid_name}.osgb')
|
||||||
|
|
||||||
|
# 构建osgconv命令
|
||||||
|
cmd = [
|
||||||
|
'osgconv',
|
||||||
|
'--compressed',
|
||||||
|
'--smooth',
|
||||||
|
'--fix-transparency',
|
||||||
|
'-o', '0,1,0-0,0,-1',
|
||||||
|
obj_file,
|
||||||
|
output_osgb
|
||||||
|
]
|
||||||
|
|
||||||
|
# 执行命令
|
||||||
|
self.logger.info(f"执行osgconv命令:{cmd}")
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception(f"osgconv执行失败: {result.stderr}")
|
||||||
|
|
||||||
|
self.logger.info(f"转换完成: {output_osgb}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"转换osgb时发生错误: {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def create_metadata_xml(self, osgb_dir: str):
|
||||||
|
"""创建metadata.xml文件,包含UTM偏移信息"""
|
||||||
|
try:
|
||||||
|
# 这里需要将UTM坐标转换为WGS84经纬度坐标
|
||||||
|
# 这里使用示例值,实际应用中需要进行真实的坐标转换
|
||||||
|
metadata_content = f'''<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ModelMetadata version="1">
|
||||||
|
<SRS>EPSG:32649</SRS>
|
||||||
|
<SRSOrigin>{self.min_east:.6f},{self.min_north:.6f},0.000000</SRSOrigin>
|
||||||
|
<Texture>
|
||||||
|
<ColorSource>Visible</ColorSource>
|
||||||
|
</Texture>
|
||||||
|
</ModelMetadata>'''
|
||||||
|
|
||||||
|
with open(os.path.join(osgb_dir, 'metadata.xml'), 'w') as f:
|
||||||
|
f.write(metadata_content)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"创建metadata.xml时发生错误: {str(e)}")
|
||||||
|
raise
|
Loading…
Reference in New Issue
Block a user