修改瓦片的偏移

This commit is contained in:
weixin_46229132 2025-02-06 19:01:19 +08:00
parent a3951c47d0
commit 971517c145
3 changed files with 137 additions and 28 deletions

View File

@ -298,8 +298,8 @@ class ImagePreprocessor:
self.cluster() self.cluster()
self.filter_isolated_points() self.filter_isolated_points()
self.filter_time_group_overlap() self.filter_time_group_overlap()
center_lat, center_lon = self.calculate_center_coordinates()
# self.filter_alternate_images() # self.filter_alternate_images()
center_lat, center_lon = self.calculate_center_coordinates()
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("预处理任务完成")

View File

@ -4,10 +4,7 @@ from datetime import timedelta
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict, Tuple from typing import Dict, Tuple
import psutil import psutil
import matplotlib.pyplot as plt
import pandas as pd import pandas as pd
from tqdm import tqdm
from filter.cluster_filter import GPSCluster from filter.cluster_filter import GPSCluster
from filter.time_group_overlap_filter import TimeGroupOverlapFilter from filter.time_group_overlap_filter import TimeGroupOverlapFilter
@ -20,6 +17,7 @@ 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.merge_obj import MergeObj
from post_pro.merge_laz import MergePly from post_pro.merge_laz import MergePly
from post_pro.conv_obj import ConvertOBJ
@dataclass @dataclass
@ -187,6 +185,28 @@ 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 calculate_center_coordinates(self):
"""计算剩余点的中心经纬度坐标"""
mean_lat = self.gps_points['lat'].mean()
mean_lon = self.gps_points['lon'].mean()
self.logger.info(f"区域中心坐标:纬度 {mean_lat:.6f}, 经度 {mean_lon:.6f}")
return mean_lat, mean_lon
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 +240,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)
@ -245,7 +265,13 @@ class ImagePreprocessor:
merger = MergeObj(self.config.output_dir) merger = MergeObj(self.config.output_dir)
merger.merge_grid_obj(grid_points, translations) merger.merge_grid_obj(grid_points, translations)
def post_process(self, successful_grid_points: Dict[tuple, pd.DataFrame], grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple]): def convert_obj(self, grid_points: Dict[tuple, pd.DataFrame], center_lat: float, center_lon: float):
"""转换OBJ模型"""
self.logger.info("开始转换OBJ模型")
converter = ConvertOBJ(self.config.output_dir, center_lat, center_lon)
converter.convert_grid_obj(grid_points)
def post_process(self, successful_grid_points: Dict[tuple, pd.DataFrame], grid_points: Dict[tuple, pd.DataFrame], translations: Dict[tuple, tuple], center_lat: float, center_lon: float):
"""后处理:合并或复制处理结果""" """后处理:合并或复制处理结果"""
if len(successful_grid_points) < len(grid_points): if len(successful_grid_points) < len(grid_points):
self.logger.warning( self.logger.warning(
@ -256,12 +282,14 @@ class ImagePreprocessor:
if self.config.mode == "快拼模式": if self.config.mode == "快拼模式":
self.merge_tif(successful_grid_points, self.config.produce_dem) self.merge_tif(successful_grid_points, self.config.produce_dem)
elif self.config.mode == "三维模式": elif self.config.mode == "三维模式":
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)
self.convert_obj(successful_grid_points, center_lat, center_lon)
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)
self.convert_obj(successful_grid_points, center_lat, center_lon)
def process(self): def process(self):
"""执行完整的预处理流程""" """执行完整的预处理流程"""
@ -270,15 +298,17 @@ class ImagePreprocessor:
self.cluster() self.cluster()
self.filter_isolated_points() self.filter_isolated_points()
self.filter_time_group_overlap() self.filter_time_group_overlap()
center_lat, center_lon = self.calculate_center_coordinates()
# 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("预处理任务完成")
# successful_grid_points = self.odm_monitor.process_all_grids( # successful_grid_points = self.odm_monitor.process_all_grids(
# grid_points, self.config.produce_dem) # grid_points, self.config.produce_dem)
successful_grid_points = grid_points successful_grid_points = grid_points
self.post_process(successful_grid_points, self.post_process(successful_grid_points,
grid_points, translations) grid_points, translations, center_lat, center_lon)
except Exception as e: except Exception as e:
self.logger.error(f"处理过程中发生错误: {str(e)}", exc_info=True) self.logger.error(f"处理过程中发生错误: {str(e)}", exc_info=True)

View File

@ -13,17 +13,19 @@ class ConvertOBJ:
def convert_grid_obj(self, grid_points): def convert_grid_obj(self, grid_points):
"""转换每个网格的OBJ文件为OSGB格式""" """转换每个网格的OBJ文件为OSGB格式"""
os.makedirs(os.path.join(self.output_dir, "osgb"), exist_ok=True) os.makedirs(os.path.join(self.output_dir, "osgb", "Data"), exist_ok=True)
tile_infos = []
for grid_id in grid_points.keys(): for grid_id in grid_points.keys():
try: try:
self._convert_single_grid(grid_id) tile_info = self._convert_single_grid(grid_id, grid_points)
tile_infos.append(tile_info)
except Exception as e: except Exception as e:
self.logger.error(f"网格 {grid_id} 转换失败: {str(e)}") self.logger.error(f"网格 {grid_id} 转换失败: {str(e)}")
# 在所有网格处理完成后创建总的metadata.xml self._create_merged_metadata(tile_infos)
self._create_merged_metadata()
def _convert_single_grid(self, grid_id): def _convert_single_grid(self, grid_id, grid_points):
"""转换单个网格的OBJ文件""" """转换单个网格的OBJ文件"""
# 1. 构建相关路径 # 1. 构建相关路径
grid_name = f"grid_{grid_id[0]}_{grid_id[1]}" grid_name = f"grid_{grid_id[0]}_{grid_id[1]}"
@ -40,9 +42,24 @@ class ConvertOBJ:
self.logger.info(f"开始转换网格 {grid_id} 的OBJ文件") self.logger.info(f"开始转换网格 {grid_id} 的OBJ文件")
output_osgb = os.path.join(texturing_dir, "Tile.osgb") output_osgb = os.path.join(texturing_dir, "Tile.osgb")
# 计算当前网格相对于中心点的偏移
grid_data = grid_points[grid_id]
lats = [point['lat'] for point in grid_data]
lons = [point['lon'] for point in grid_data]
min_lat = min(lats)
min_lon = min(lons)
# 计算偏移量(米)
offset_x = self._calculate_distance(self.center_lat, self.center_lon, self.center_lat, min_lon)
offset_y = self._calculate_distance(self.center_lat, self.center_lon, min_lat, self.center_lon)
# 修改转换命令,使用正确的参数格式
cmd = ( cmd = (
f"osgconv --compressed --smooth --fix-transparency -o 0,1,0-0,0,-1 " f"osgconv {obj_file} {output_osgb} "
f"{obj_file} {output_osgb}" f"--compressed --smooth --fix-transparency "
f"-t {offset_x},{offset_y},0 " # 使用 -t 参数进行平移
f"-o 0,1,0-0,0,-1"
) )
try: try:
@ -65,20 +82,82 @@ class ConvertOBJ:
target_osgb = os.path.join(tile_dir, f"Tile_{grid_id[0]}_{grid_id[1]}.osgb") target_osgb = os.path.join(tile_dir, f"Tile_{grid_id[0]}_{grid_id[1]}.osgb")
shutil.copy2(output_osgb, target_osgb) shutil.copy2(output_osgb, target_osgb)
self.logger.info(f"网格 {grid_id} 转换完成") # 计算当前网格的边界框
grid_data = grid_points[grid_id]
# 假设grid_data是一个列表每个元素都是包含lat和lon的字典
lats = [point['lat'] for point in grid_data]
lons = [point['lon'] for point in grid_data]
def _create_merged_metadata(self): min_lat = min(lats)
max_lat = max(lats)
min_lon = min(lons)
max_lon = max(lons)
# 计算相对于中心点的偏移
offset_x = self._calculate_distance(self.center_lat, self.center_lon, self.center_lat, min_lon)
offset_y = self._calculate_distance(self.center_lat, self.center_lon, min_lat, self.center_lon)
tile_info = {
'id': f"{grid_id[0]}_{grid_id[1]}",
'bounds': {
'min_lat': min_lat,
'max_lat': max_lat,
'min_lon': min_lon,
'max_lon': max_lon
},
'offset': (offset_x, offset_y)
}
return tile_info
def _calculate_distance(self, lat1, lon1, lat2, lon2):
"""计算两点间的距离(米)"""
from math import sin, cos, sqrt, atan2, radians
R = 6371000 # 地球半径(米)
lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
dlat = lat2 - lat1
dlon = lon2 - lon1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
return R * c
def _create_merged_metadata(self, tile_infos):
"""创建合并后的metadata.xml文件""" """创建合并后的metadata.xml文件"""
metadata_content = f"""<?xml version="1.0" encoding="utf-8"?> metadata_content = f"""<?xml version="1.0" encoding="utf-8"?>
<ModelMetadata version="1"> <ModelMetadata version="1">
<!--Spatial Reference System-->
<SRS>EPSG:4326</SRS> <SRS>EPSG:4326</SRS>
<!--Origin in Spatial Reference System-->
<SRSOrigin>{self.center_lon},{self.center_lat},0.000000</SRSOrigin> <SRSOrigin>{self.center_lon},{self.center_lat},0.000000</SRSOrigin>
<TileStructure>
<RootNode>
<BoundingBox>
<MinLat>{min([t['bounds']['min_lat'] for t in tile_infos])}</MinLat>
<MaxLat>{max([t['bounds']['max_lat'] for t in tile_infos])}</MaxLat>
<MinLon>{min([t['bounds']['min_lon'] for t in tile_infos])}</MinLon>
<MaxLon>{max([t['bounds']['max_lon'] for t in tile_infos])}</MaxLon>
</BoundingBox>
<Tiles>"""
for tile in tile_infos:
metadata_content += f"""
<Tile id="{tile['id']}">
<Offset>{tile['offset'][0]},{tile['offset'][1]},0</Offset>
<BoundingBox>
<MinLat>{tile['bounds']['min_lat']}</MinLat>
<MaxLat>{tile['bounds']['max_lat']}</MaxLat>
<MinLon>{tile['bounds']['min_lon']}</MinLon>
<MaxLon>{tile['bounds']['max_lon']}</MaxLon>
</BoundingBox>
</Tile>"""
metadata_content += """
</Tiles>
</RootNode>
</TileStructure>
<Texture> <Texture>
<ColorSource>Visible</ColorSource> <ColorSource>Visible</ColorSource>
</Texture> </Texture>
</ModelMetadata>""" </ModelMetadata>"""
metadata_file = os.path.join(self.output_dir, "osgb", "metadata.xml") metadata_file = os.path.join(self.output_dir, "osgb", "metadata.xml")
with open(metadata_file, 'w', encoding='utf-8') as f: with open(metadata_file, 'w', encoding='utf-8') as f: