更新笛卡尔坐标
This commit is contained in:
parent
b63927b3ea
commit
466bc06b47
@ -208,7 +208,11 @@ class ImagePreprocessor:
|
|||||||
self.gps_points, grid_size=self.config.grid_size
|
self.gps_points, grid_size=self.config.grid_size
|
||||||
)
|
)
|
||||||
grid_points = grid_divider.assign_to_grids(self.gps_points, grids)
|
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文件
|
# 生成image_groups.txt文件
|
||||||
try:
|
try:
|
||||||
|
@ -10,42 +10,58 @@ class MergeObj:
|
|||||||
self.output_dir = output_dir
|
self.output_dir = output_dir
|
||||||
self.logger = logging.getLogger('UAV_Preprocess.MergeObj')
|
self.logger = logging.getLogger('UAV_Preprocess.MergeObj')
|
||||||
|
|
||||||
def merge_two_objs(self, obj1_path: str, obj2_path: str, output_path: str):
|
def read_obj(self, file_path):
|
||||||
"""使用Open3D合并两个OBJ文件"""
|
"""读取.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:
|
try:
|
||||||
self.logger.info("开始合并OBJ模型")
|
self.logger.info(f"开始合并OBJ模型:\n输入1: {obj1_path}\n输入2: {obj2_path}")
|
||||||
self.logger.info(f"输入模型1: {obj1_path}")
|
|
||||||
self.logger.info(f"输入模型2: {obj2_path}")
|
|
||||||
self.logger.info(f"输出模型: {output_path}")
|
|
||||||
|
|
||||||
# 检查输入文件是否存在
|
# 检查输入文件是否存在
|
||||||
if not os.path.exists(obj1_path) or not os.path.exists(obj2_path):
|
if not os.path.exists(obj1_path) or not os.path.exists(obj2_path):
|
||||||
raise FileNotFoundError("输入模型文件不存在")
|
raise FileNotFoundError("输入模型文件不存在")
|
||||||
|
|
||||||
# 读取OBJ文件
|
# 读取两个obj文件
|
||||||
mesh1 = o3d.io.read_triangle_mesh(obj1_path)
|
vertices1, faces1 = self.read_obj(obj1_path)
|
||||||
mesh2 = o3d.io.read_triangle_mesh(obj2_path)
|
vertices2, faces2 = self.read_obj(obj2_path)
|
||||||
|
|
||||||
if mesh1.is_empty() or mesh2.is_empty():
|
# 平移第二个模型的顶点
|
||||||
raise ValueError("无法读取OBJ文件或文件为空")
|
vertices2_translated = self.translate_vertices(vertices2, translation)
|
||||||
|
|
||||||
# # 计算并对齐中心点
|
# 合并顶点和面
|
||||||
# center1 = mesh1.get_center()
|
all_vertices = vertices1 + vertices2_translated
|
||||||
# center2 = mesh2.get_center()
|
all_faces = faces1 + [[f[0] + len(vertices1), f[1] + len(vertices1), f[2] + len(vertices1)] for f in faces2]
|
||||||
# translation_vector = center2 - center1
|
|
||||||
# mesh2.translate(translation_vector)
|
|
||||||
|
|
||||||
# 不对齐,直接合并网格
|
# 写入合并后的obj文件
|
||||||
combined_mesh = mesh1 + mesh2
|
self.write_obj(output_path, all_vertices, all_faces)
|
||||||
|
|
||||||
# 优化合并后的网格
|
|
||||||
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("保存合并后的模型失败")
|
|
||||||
|
|
||||||
self.logger.info(f"模型合并成功,已保存至: {output_path}")
|
self.logger.info(f"模型合并成功,已保存至: {output_path}")
|
||||||
|
|
||||||
@ -53,7 +69,30 @@ class MergeObj:
|
|||||||
self.logger.error(f"合并OBJ模型时发生错误: {str(e)}", exc_info=True)
|
self.logger.error(f"合并OBJ模型时发生错误: {str(e)}", exc_info=True)
|
||||||
raise
|
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模型"""
|
"""合并所有网格的OBJ模型"""
|
||||||
self.logger.info("开始合并所有网格的OBJ模型")
|
self.logger.info("开始合并所有网格的OBJ模型")
|
||||||
|
|
||||||
@ -66,17 +105,19 @@ class MergeObj:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
for grid_idx, points in grid_points.items():
|
for grid_idx, points in grid_points.items():
|
||||||
|
if grid_idx == 'grid_divider': # 跳过grid_divider对象
|
||||||
|
continue
|
||||||
|
|
||||||
grid_obj = os.path.join(
|
grid_obj = os.path.join(
|
||||||
self.output_dir,
|
self.output_dir,
|
||||||
f"grid_{grid_idx + 1}",
|
f"grid_{grid_idx + 1}",
|
||||||
"project",
|
"project",
|
||||||
"odm_texturing_25d",
|
"odm_texturing",
|
||||||
"odm_textured_model_geo.obj"
|
"odm_textured_model_geo.obj"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not os.path.exists(grid_obj):
|
if not os.path.exists(grid_obj):
|
||||||
self.logger.warning(
|
self.logger.warning(f"网格 {grid_idx + 1} 的OBJ文件不存在: {grid_obj}")
|
||||||
f"网格 {grid_idx + 1} 的OBJ文件不存在: {grid_obj}")
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if input_obj1 is None:
|
if input_obj1 is None:
|
||||||
@ -84,25 +125,31 @@ class MergeObj:
|
|||||||
self.logger.info(f"设置第一个输入OBJ: {input_obj1}")
|
self.logger.info(f"设置第一个输入OBJ: {input_obj1}")
|
||||||
else:
|
else:
|
||||||
input_obj2 = grid_obj
|
input_obj2 = grid_obj
|
||||||
output_obj = os.path.join(
|
output_obj = os.path.join(self.output_dir, f"merged_model_{merge_count}.obj")
|
||||||
self.output_dir, "merged_model.obj")
|
|
||||||
|
# 计算当前网格的平移量
|
||||||
|
translation = self.calculate_translation(grid_idx, grid_points, grid_size)
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
f"开始合并第 {merge_count + 1} 次:\n"
|
f"开始合并第 {merge_count + 1} 次:\n"
|
||||||
f"输入1: {input_obj1}\n"
|
f"平移量: {translation}\n"
|
||||||
f"输入2: {input_obj2}\n"
|
|
||||||
f"输出: {output_obj}"
|
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
|
merge_count += 1
|
||||||
|
|
||||||
input_obj1 = output_obj
|
input_obj1 = output_obj
|
||||||
input_obj2 = None
|
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(
|
self.logger.info(
|
||||||
f"OBJ模型合并完成,共执行 {merge_count} 次合并,"
|
f"OBJ模型合并完成,共执行 {merge_count} 次合并,"
|
||||||
f"最终输出文件: {input_obj1}"
|
f"最终输出文件: {final_output}"
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -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
65
tools/merge_two_obj.py
Normal 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))
|
@ -12,10 +12,12 @@ class GridDivider:
|
|||||||
self.output_dir = output_dir
|
self.output_dir = output_dir
|
||||||
self.logger = logging.getLogger('UAV_Preprocess.GridDivider')
|
self.logger = logging.getLogger('UAV_Preprocess.GridDivider')
|
||||||
self.logger.info(f"初始化网格划分器,重叠率: {overlap}")
|
self.logger.info(f"初始化网格划分器,重叠率: {overlap}")
|
||||||
|
self.num_grids_width = 0 # 添加网格数量属性
|
||||||
|
self.num_grids_height = 0
|
||||||
|
|
||||||
def divide_grids(self, points_df, grid_size=500):
|
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_lat, max_lat = points_df['lat'].min(), points_df['lat'].max()
|
||||||
min_lon, max_lon = points_df['lon'].min(), points_df['lon'].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
|
width = geodesic((min_lat, min_lon), (min_lat, max_lon)).meters
|
||||||
height = geodesic((min_lat, min_lon), (max_lat, min_lon)).meters
|
height = geodesic((min_lat, min_lon), (max_lat, min_lon)).meters
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(f"区域宽度: {width:.2f}米, 高度: {height:.2f}米")
|
||||||
f"区域宽度: {width:.2f}米, 高度: {height:.2f}米"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 计算需要划分的网格数量
|
# 计算需要划分的网格数量
|
||||||
num_grids_width = int(
|
self.num_grids_width = max(int(width / grid_size), 1)
|
||||||
width / grid_size) if int(width / grid_size) > 0 else 1
|
self.num_grids_height = max(int(height / grid_size), 1)
|
||||||
num_grids_height = int(
|
|
||||||
height / grid_size) if int(height / grid_size) > 0 else 1
|
|
||||||
|
|
||||||
# 计算每个网格对应的经纬度步长
|
# 计算每个网格对应的经纬度步长
|
||||||
lat_step = (max_lat - min_lat) / num_grids_height
|
lat_step = (max_lat - min_lat) / self.num_grids_height
|
||||||
lon_step = (max_lon - min_lon) / num_grids_width
|
lon_step = (max_lon - min_lon) / self.num_grids_width
|
||||||
|
|
||||||
grids = []
|
grids = []
|
||||||
for i in range(num_grids_height):
|
grid_indices = {} # 存储网格的二维索引
|
||||||
for j in range(num_grids_width):
|
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_min_lat = min_lat + i * lat_step - self.overlap * lat_step
|
||||||
grid_max_lat = min_lat + \
|
grid_max_lat = min_lat + (i + 1) * lat_step + self.overlap * lat_step
|
||||||
(i + 1) * lat_step + self.overlap * lat_step
|
|
||||||
grid_min_lon = min_lon + j * lon_step - self.overlap * lon_step
|
grid_min_lon = min_lon + j * lon_step - self.overlap * lon_step
|
||||||
grid_max_lon = min_lon + \
|
grid_max_lon = min_lon + (j + 1) * lon_step + self.overlap * lon_step
|
||||||
(j + 1) * lon_step + self.overlap * lon_step
|
|
||||||
grids.append((grid_min_lat, grid_max_lat,
|
grids.append((grid_min_lat, grid_max_lat, grid_min_lon, grid_max_lon))
|
||||||
grid_min_lon, grid_max_lon))
|
grid_indices[grid_idx] = (i, j) # 存储每个网格的行列索引
|
||||||
|
|
||||||
self.logger.debug(
|
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}]"
|
f"经度[{grid_min_lon:.6f}, {grid_max_lon:.6f}]"
|
||||||
)
|
)
|
||||||
|
grid_idx += 1
|
||||||
|
|
||||||
self.logger.info(
|
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)
|
self.visualize_grids(points_df, grids)
|
||||||
|
|
||||||
return 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):
|
def assign_to_grids(self, points_df, grids):
|
||||||
"""将点分配到对应网格"""
|
"""将点分配到对应网格"""
|
||||||
self.logger.info(f"开始将 {len(points_df)} 个点分配到网格中")
|
self.logger.info(f"开始将 {len(points_df)} 个点分配到网格中")
|
||||||
|
Loading…
Reference in New Issue
Block a user