更新笛卡尔坐标

This commit is contained in:
along 2024-12-31 20:37:35 +08:00
parent b63927b3ea
commit 466bc06b47
5 changed files with 195 additions and 101 deletions

View File

@ -208,7 +208,11 @@ class ImagePreprocessor:
self.gps_points, grid_size=self.config.grid_size
)
grid_points = grid_divider.assign_to_grids(self.gps_points, grids)
self.logger.info(f"成功划分为 {len(grid_points)} 个网格")
# 将grid_divider添加到grid_points中
grid_points['grid_divider'] = grid_divider
self.logger.info(f"成功划分为 {len(grid_points)-1} 个网格") # -1是因为包含了grid_divider
# 生成image_groups.txt文件
try:

View File

@ -10,50 +10,89 @@ class MergeObj:
self.output_dir = output_dir
self.logger = logging.getLogger('UAV_Preprocess.MergeObj')
def merge_two_objs(self, obj1_path: str, obj2_path: str, output_path: str):
"""使用Open3D合并两个OBJ文件"""
try:
self.logger.info("开始合并OBJ模型")
self.logger.info(f"输入模型1: {obj1_path}")
self.logger.info(f"输入模型2: {obj2_path}")
self.logger.info(f"输出模型: {output_path}")
def read_obj(self, file_path):
"""读取.obj文件返回顶点列表和面列表"""
vertices = []
faces = []
with open(file_path, 'r') as file:
for line in file:
parts = line.split()
if len(parts) == 0:
continue
if parts[0] == 'v': # 顶点
vertices.append([float(parts[1]), float(parts[2]), float(parts[3])])
elif parts[0] == 'f': # 面
faces.append([int(parts[1].split('/')[0]), int(parts[2].split('/')[0]), int(parts[3].split('/')[0])])
return vertices, faces
def write_obj(self, file_path, vertices, faces):
"""将修改后的顶点和面列表写入到.obj文件"""
with open(file_path, 'w') as file:
for vertex in vertices:
file.write(f"v {vertex[0]} {vertex[1]} {vertex[2]}\n")
for face in faces:
file.write(f"f {face[0]} {face[1]} {face[2]}\n")
def translate_vertices(self, vertices, translation):
"""平移顶点"""
return [[v[0] + translation[0], v[1] + translation[1], v[2] + translation[2]] for v in vertices]
def merge_two_objs(self, obj1_path: str, obj2_path: str, output_path: str, translation):
"""合并两个OBJ文件"""
try:
self.logger.info(f"开始合并OBJ模型:\n输入1: {obj1_path}\n输入2: {obj2_path}")
# 检查输入文件是否存在
if not os.path.exists(obj1_path) or not os.path.exists(obj2_path):
raise FileNotFoundError("输入模型文件不存在")
# 读取OBJ文件
mesh1 = o3d.io.read_triangle_mesh(obj1_path)
mesh2 = o3d.io.read_triangle_mesh(obj2_path)
if mesh1.is_empty() or mesh2.is_empty():
raise ValueError("无法读取OBJ文件或文件为空")
# # 计算并对齐中心点
# center1 = mesh1.get_center()
# center2 = mesh2.get_center()
# translation_vector = center2 - center1
# mesh2.translate(translation_vector)
# 不对齐,直接合并网格
combined_mesh = mesh1 + mesh2
# 优化合并后的网格
combined_mesh.remove_duplicated_vertices()
combined_mesh.remove_duplicated_triangles()
combined_mesh.compute_vertex_normals()
# 保存合并后的模型
if not o3d.io.write_triangle_mesh(output_path, combined_mesh):
raise RuntimeError("保存合并后的模型失败")
# 读取两个obj文件
vertices1, faces1 = self.read_obj(obj1_path)
vertices2, faces2 = self.read_obj(obj2_path)
# 平移第二个模型的顶点
vertices2_translated = self.translate_vertices(vertices2, translation)
# 合并顶点和面
all_vertices = vertices1 + vertices2_translated
all_faces = faces1 + [[f[0] + len(vertices1), f[1] + len(vertices1), f[2] + len(vertices1)] for f in faces2]
# 写入合并后的obj文件
self.write_obj(output_path, all_vertices, all_faces)
self.logger.info(f"模型合并成功,已保存至: {output_path}")
except Exception as e:
self.logger.error(f"合并OBJ模型时发生错误: {str(e)}", exc_info=True)
raise
def merge_grid_obj(self, grid_points: Dict[int, pd.DataFrame]):
def calculate_translation(self, grid_idx: int, grid_points: Dict[int, pd.DataFrame], grid_size: float) -> tuple:
"""根据网格索引和大小计算平移量"""
# 从grid_points中获取网格划分器
grid_divider = grid_points.get('grid_divider', None)
if grid_divider is None:
# 如果没有grid_divider使用默认的计算方式
row = grid_idx // 2
col = grid_idx % 2
else:
# 使用grid_divider获取正确的网格坐标
row, col = grid_divider.get_grid_coordinates(grid_idx)
# 计算平移量,考虑到重叠
overlap_factor = 0.9 # 重叠因子与grid_divider中的overlap对应
x_translation = col * grid_size * overlap_factor
y_translation = row * grid_size * overlap_factor
self.logger.info(
f"网格 {grid_idx} 的位置: 行={row}, 列={col}"
)
return (x_translation, y_translation, 0) # z轴不需要平移
def merge_grid_obj(self, grid_points: Dict[int, pd.DataFrame], grid_size: float = 500):
"""合并所有网格的OBJ模型"""
self.logger.info("开始合并所有网格的OBJ模型")
@ -66,17 +105,19 @@ class MergeObj:
try:
for grid_idx, points in grid_points.items():
if grid_idx == 'grid_divider': # 跳过grid_divider对象
continue
grid_obj = os.path.join(
self.output_dir,
f"grid_{grid_idx + 1}",
"project",
"odm_texturing_25d",
"odm_texturing",
"odm_textured_model_geo.obj"
)
if not os.path.exists(grid_obj):
self.logger.warning(
f"网格 {grid_idx + 1} 的OBJ文件不存在: {grid_obj}")
self.logger.warning(f"网格 {grid_idx + 1} 的OBJ文件不存在: {grid_obj}")
continue
if input_obj1 is None:
@ -84,25 +125,31 @@ class MergeObj:
self.logger.info(f"设置第一个输入OBJ: {input_obj1}")
else:
input_obj2 = grid_obj
output_obj = os.path.join(
self.output_dir, "merged_model.obj")
output_obj = os.path.join(self.output_dir, f"merged_model_{merge_count}.obj")
# 计算当前网格的平移量
translation = self.calculate_translation(grid_idx, grid_points, grid_size)
self.logger.info(
f"开始合并第 {merge_count + 1} 次:\n"
f"输入1: {input_obj1}\n"
f"输入2: {input_obj2}\n"
f"平移量: {translation}\n"
f"输出: {output_obj}"
)
self.merge_two_objs(input_obj1, input_obj2, output_obj)
self.merge_two_objs(input_obj1, input_obj2, output_obj, translation)
merge_count += 1
input_obj1 = output_obj
input_obj2 = None
# 最后的结果重命名为merged_model.obj
final_output = os.path.join(self.output_dir, "merged_model.obj")
if os.path.exists(input_obj1) and input_obj1 != final_output:
os.rename(input_obj1, final_output)
self.logger.info(
f"OBJ模型合并完成共执行 {merge_count} 次合并,"
f"最终输出文件: {input_obj1}"
f"最终输出文件: {final_output}"
)
except Exception as e:

View File

@ -1,34 +0,0 @@
import open3d as o3d
import numpy as np
# 读取 .obj 文件
def load_obj(file_path):
mesh = o3d.io.read_triangle_mesh(file_path)
if not mesh.is_empty():
return mesh
else:
raise ValueError(f"Failed to load {file_path}")
# 合并两个网格
def merge_meshes(mesh1, mesh2):
# 直接合并网格
combined_mesh = mesh1 + mesh2
return combined_mesh
# 保存合并后的网格
def save_merged_mesh(mesh, output_path):
o3d.io.write_triangle_mesh(output_path, mesh)
print(f"Saved merged mesh to {output_path}")
# 示例用法
mesh1 = load_obj("model1.obj")
mesh2 = load_obj("model2.obj")
# 合并两个网格
merged_mesh = merge_meshes(mesh1, mesh2)
# 保存合并后的网格
save_merged_mesh(merged_mesh, "merged_model.obj")
# 可视化合并后的网格
o3d.visualization.draw_geometries([merged_mesh])

65
tools/merge_two_obj.py Normal file
View File

@ -0,0 +1,65 @@
def read_obj(file_path):
"""
读取.obj文件返回顶点列表和面列表
"""
vertices = []
faces = []
with open(file_path, 'r') as file:
for line in file:
parts = line.split()
if len(parts) == 0:
continue
if parts[0] == 'v': # 顶点
vertices.append([float(parts[1]), float(parts[2]), float(parts[3])])
elif parts[0] == 'f': # 面
faces.append([int(parts[1].split('/')[0]), int(parts[2].split('/')[0]), int(parts[3].split('/')[0])])
return vertices, faces
def write_obj(file_path, vertices, faces):
"""
将修改后的顶点和面列表写入到.obj文件
"""
with open(file_path, 'w') as file:
for vertex in vertices:
file.write(f"v {vertex[0]} {vertex[1]} {vertex[2]}\n")
for face in faces:
file.write(f"f {face[0]} {face[1]} {face[2]}\n")
def translate_vertices(vertices, translation):
"""
平移顶点translation 是一个三维向量例如 (500, 0, 0) 会沿 X 轴平移 500
"""
return [[v[0] + translation[0], v[1] + translation[1], v[2] + translation[2]] for v in vertices]
def merge_objs(obj1_path, obj2_path, output_path, translation=(500, 0, 0)):
"""
合并两个.obj文件并对第二个文件的顶点进行平移
obj1_path obj2_path 是输入的.obj文件路径
output_path 是输出的合并后的.obj文件路径
translation 是平移向量默认为沿 X 轴平移 500
"""
# 读取第一个 obj 文件
vertices1, faces1 = read_obj(obj1_path)
# 读取第二个 obj 文件
vertices2, faces2 = read_obj(obj2_path)
# 平移第二个 obj 文件的顶点
vertices2_translated = translate_vertices(vertices2, translation)
# 合并顶点和面
all_vertices = vertices1 + vertices2_translated
all_faces = faces1 + [[f[0] + len(vertices1), f[1] + len(vertices1), f[2] + len(vertices1)] for f in faces2]
# 写入合并后的 obj 文件
write_obj(output_path, all_vertices, all_faces)
print(f"合并完成,结果保存在 {output_path}")
# 示例调用
obj1_path = 'model1.obj' # 第一个 .obj 文件
obj2_path = 'model2.obj' # 第二个 .obj 文件
output_path = 'merged_model.obj' # 输出合并后的 .obj 文件
merge_objs(obj1_path, obj2_path, output_path, translation=(500, 0, 0))

View File

@ -12,10 +12,12 @@ class GridDivider:
self.output_dir = output_dir
self.logger = logging.getLogger('UAV_Preprocess.GridDivider')
self.logger.info(f"初始化网格划分器,重叠率: {overlap}")
self.num_grids_width = 0 # 添加网格数量属性
self.num_grids_height = 0
def divide_grids(self, points_df, grid_size=500):
"""计算边界框并划分九宫"""
self.logger.info("开始划分九宫")
"""计算边界框并划分"""
self.logger.info("开始划分")
min_lat, max_lat = points_df['lat'].min(), points_df['lat'].max()
min_lon, max_lon = points_df['lon'].min(), points_df['lon'].max()
@ -24,45 +26,55 @@ class GridDivider:
width = geodesic((min_lat, min_lon), (min_lat, max_lon)).meters
height = geodesic((min_lat, min_lon), (max_lat, min_lon)).meters
self.logger.info(
f"区域宽度: {width:.2f}米, 高度: {height:.2f}"
)
self.logger.info(f"区域宽度: {width:.2f}米, 高度: {height:.2f}")
# 计算需要划分的网格数量
num_grids_width = int(
width / grid_size) if int(width / grid_size) > 0 else 1
num_grids_height = int(
height / grid_size) if int(height / grid_size) > 0 else 1
self.num_grids_width = max(int(width / grid_size), 1)
self.num_grids_height = max(int(height / grid_size), 1)
# 计算每个网格对应的经纬度步长
lat_step = (max_lat - min_lat) / num_grids_height
lon_step = (max_lon - min_lon) / num_grids_width
lat_step = (max_lat - min_lat) / self.num_grids_height
lon_step = (max_lon - min_lon) / self.num_grids_width
grids = []
for i in range(num_grids_height):
for j in range(num_grids_width):
grid_min_lat = min_lat + i * lat_step - self.overlap * lat_step
grid_max_lat = min_lat + \
(i + 1) * lat_step + self.overlap * lat_step
grid_min_lon = min_lon + j * lon_step - self.overlap * lon_step
grid_max_lon = min_lon + \
(j + 1) * lon_step + self.overlap * lon_step
grids.append((grid_min_lat, grid_max_lat,
grid_min_lon, grid_max_lon))
grid_indices = {} # 存储网格的二维索引
grid_idx = 0
for i in range(self.num_grids_height):
for j in range(self.num_grids_width):
grid_min_lat = min_lat + i * lat_step - self.overlap * lat_step
grid_max_lat = min_lat + (i + 1) * lat_step + self.overlap * lat_step
grid_min_lon = min_lon + j * lon_step - self.overlap * lon_step
grid_max_lon = min_lon + (j + 1) * lon_step + self.overlap * lon_step
grids.append((grid_min_lat, grid_max_lat, grid_min_lon, grid_max_lon))
grid_indices[grid_idx] = (i, j) # 存储每个网格的行列索引
self.logger.debug(
f"网格[{i},{j}]: 纬度[{grid_min_lat:.6f}, {grid_max_lat:.6f}], "
f"网格[{i},{j}] (索引{grid_idx}): 纬度[{grid_min_lat:.6f}, {grid_max_lat:.6f}], "
f"经度[{grid_min_lon:.6f}, {grid_max_lon:.6f}]"
)
grid_idx += 1
self.logger.info(
f"成功划分为 {len(grids)} 个网格 ({num_grids_width}x{num_grids_height})")
f"成功划分为 {len(grids)} 个网格 ({self.num_grids_width}x{self.num_grids_height})")
# 保存网格索引信息
self.grid_indices = grid_indices
# 添加可视化调用
self.visualize_grids(points_df, grids)
return grids
def get_grid_coordinates(self, grid_idx):
"""获取网格的二维坐标"""
return self.grid_indices.get(grid_idx, (0, 0))
def get_grid_dimensions(self):
"""获取网格的维度"""
return self.num_grids_width, self.num_grids_height
def assign_to_grids(self, points_df, grids):
"""将点分配到对应网格"""
self.logger.info(f"开始将 {len(points_df)} 个点分配到网格中")