From 8999b49de5e9f78661b7df0a173f77e96e8f15f2 Mon Sep 17 00:00:00 2001 From: weixin_46229132 Date: Tue, 11 Feb 2025 16:05:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0merge=5Fobj=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 2 +- post_pro/merge_obj.py | 255 +++++++++++------------------------------- 2 files changed, 68 insertions(+), 189 deletions(-) diff --git a/main.py b/main.py index a51cd62..526a90f 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,6 @@ import argparse from datetime import timedelta -from odm_preprocess import PreprocessConfig, ImagePreprocessor +from odm_preprocess_fast import PreprocessConfig, ImagePreprocessor def parse_args(): parser = argparse.ArgumentParser(description='ODM预处理工具') diff --git a/post_pro/merge_obj.py b/post_pro/merge_obj.py index 1a34688..df87ca5 100644 --- a/post_pro/merge_obj.py +++ b/post_pro/merge_obj.py @@ -20,7 +20,8 @@ class MergeObj: self.max_east = float('-inf') self.max_north = float('-inf') # 初始化UTM到WGS84的转换器 - self.transformer = Transformer.from_crs("EPSG:32649", "EPSG:4326", always_xy=True) + self.transformer = Transformer.from_crs( + "EPSG:32649", "EPSG:4326", always_xy=True) def read_obj(self, file_path): """读取.obj文件,返回顶点、纹理坐标、法线、面的列表和MTL文件名""" @@ -111,81 +112,6 @@ class MergeObj: face_str += "/" file.write(face_str + "\n") - def merge_two_objs(self, obj1_path: str, obj2_path: str, output_path: str, grid_id1: tuple, grid_id2: tuple): - """合并两个OBJ文件""" - try: - self.logger.info(f"开始合并OBJ模型:\n输入1: {obj1_path}\n输入2: {obj2_path}") - - # 读取两个obj文件 - vertices1, tex_coords1, normals1, faces1, face_materials1, mtl1 = self.read_obj( - obj1_path) - vertices2, tex_coords2, normals2, faces2, face_materials2, mtl2 = self.read_obj( - obj2_path) - - # 读取MTL文件内容以获取正确的材质名称 - src_dir1 = os.path.dirname(obj1_path) - src_dir2 = os.path.dirname(obj2_path) - mtl1_path = os.path.join(src_dir1, mtl1) - mtl2_path = os.path.join(src_dir2, mtl2) - - # 读取并更新材质内容 - materials1 = self.read_mtl(mtl1_path) - materials2 = self.read_mtl(mtl2_path) - - # 创建材质名称映射(使用与MTL文件相同的命名格式) - material_map1 = {} - material_map2 = {} - - # 处理第一个模型的材质映射 - for old_name in materials1.keys(): - if "grid_0_0" in obj1_path: - material_map1[old_name] = f"material_{grid_id1[0]}_{grid_id1[1]}_{old_name}" - else: - # 更新完一次后,之后就不用再更新了 - material_map1[old_name] = old_name - - # 处理第二个模型的材质映射 - for old_name in materials2.keys(): - material_map2[old_name] = f"material_{grid_id2[0]}_{grid_id2[1]}_{old_name}" - - # 计算偏移量 - v_offset = len(vertices1) - vt_offset = len(tex_coords1) - vn_offset = len(normals1) - - # 合并顶点、纹理坐标和法线 - all_vertices = vertices1 + vertices2 - all_tex_coords = tex_coords1 + tex_coords2 - all_normals = normals1 + normals2 - - # 调整第二个模型的面索引和材质名称 - all_faces = faces1.copy() - all_face_materials = [] - - # 更新第一个模型的材质名称 - for material in face_materials1: - all_face_materials.append(material_map1.get(material)) - - # 更新第二个模型的面索引和材质名称 - for face, material in zip(faces2, face_materials2): - new_face_v = [f + v_offset for f in face[0]] - new_face_vt = [ - f + vt_offset for f in face[1]] if face[1] else [] - new_face_vn = [ - f + vn_offset for f in face[2]] if face[2] else [] - all_faces.append((new_face_v, new_face_vt, new_face_vn)) - all_face_materials.append(material_map2.get(material)) - - # 写入合并后的obj文件,使用与MTL文件相同的名称 - mtl_filename = "textured_model.mtl" # 使用固定的MTL文件名 - self.write_obj(output_path, all_vertices, all_tex_coords, all_normals, - all_faces, all_face_materials, mtl_filename) - 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[tuple, pd.DataFrame]) -> Tuple[float, float]: """合并所有网格的OBJ模型 Args: @@ -205,18 +131,26 @@ class MergeObj: f"grid_{grid_id[0]}_{grid_id[1]}", "project" ) - log_file = os.path.join(base_dir, "odm_orthophoto", "odm_orthophoto_log.txt") + log_file = os.path.join( + base_dir, "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) - # 获取所有有效的网格文件 - grid_files = {} - grid_centers = [] # 用于存储每个grid的中心点坐标 + # 收集所有grid的数据 + all_vertices = [] # 所有顶点 + all_tex_coords = [] # 所有纹理坐标 + all_normals = [] # 所有法线 + all_faces = [] # 所有面 + all_face_materials = [] # 所有面的材质 + all_materials = {} # 所有材质信息 + grid_centers = [] # 所有grid的中心点 + + # 处理每个grid for grid_id, points in grid_points.items(): base_dir = os.path.join( self.output_dir, @@ -232,57 +166,64 @@ class MergeObj: f"网格 ({grid_id[0]},{grid_id[1]}) 的文件不存在") continue - # 读取UTM偏移量 - log_file = os.path.join(base_dir, "..", "odm_orthophoto", "odm_orthophoto_log.txt") + # 读取UTM偏移量并修改obj文件的顶点坐标 + log_file = os.path.join( + base_dir, "..", "odm_orthophoto", "odm_orthophoto_log.txt") utm_offset = self.read_utm_offset(log_file) - - # 修改obj文件的顶点坐标 modified_obj = self.modify_obj_coordinates(obj_path, utm_offset) - grid_files[grid_id] = { - 'obj': modified_obj, - 'mtl': mtl_path.replace('.mtl', '_utm.mtl'), - 'dir': base_dir - } + # 读取obj文件内容 + vertices, tex_coords, normals, faces, face_materials, _ = self.read_obj(modified_obj) - # 读取obj文件的顶点坐标并计算当前grid的中心点 - vertices, _, _, _, _, _ = self.read_obj(modified_obj) + # 计算当前grid的中心点 grid_center_lon, grid_center_lat = self.get_center_coordinates(vertices) grid_centers.append((grid_center_lon, grid_center_lat)) - self.logger.info(f"网格 ({grid_id[0]},{grid_id[1]}) 中心点经纬度: ({grid_center_lon}, {grid_center_lat})") + self.logger.info( + f"网格 ({grid_id[0]},{grid_id[1]}) 中心点经纬度: ({grid_center_lon}, {grid_center_lat})") - if not grid_files: - self.logger.error("没有找到有效的文件") - return - - # 收集所有材质和纹理信息 - all_materials = {} - for grid_id, files in grid_files.items(): # 复制并重命名纹理文件 texture_map = self.copy_and_rename_texture( - files['dir'], + base_dir, output_model_dir, grid_id ) - # 读取并更新MTL内容 - materials = self.read_mtl(files['mtl']) - if len(grid_files) == 1: - # 对于单个grid,直接使用update_mtl_content的结果 - updated_materials = self.update_mtl_content( - materials, - texture_map, - grid_id - ) - all_materials.update(updated_materials) - else: - # 对于多个grid,使用原有的处理逻辑 - updated_materials = self.update_mtl_content( - materials, - texture_map, - grid_id - ) - all_materials.update(updated_materials) + # 读取并更新材质内容 + materials = self.read_mtl(mtl_path) + updated_materials = self.update_mtl_content( + materials, + texture_map, + grid_id + ) + all_materials.update(updated_materials) + + # 计算顶点偏移量 + v_offset = len(all_vertices) + vt_offset = len(all_tex_coords) + vn_offset = len(all_normals) + + # 添加顶点、纹理坐标和法线 + all_vertices.extend(vertices) + all_tex_coords.extend(tex_coords) + all_normals.extend(normals) + + # 添加面和材质 + for face, material in zip(faces, face_materials): + # 调整面的索引 + new_face_v = [f + v_offset for f in face[0]] + new_face_vt = [f + vt_offset for f in face[1]] if face[1] else [] + new_face_vn = [f + vn_offset for f in face[2]] if face[2] else [] + all_faces.append((new_face_v, new_face_vt, new_face_vn)) + + # 添加材质前缀 + if material: + all_face_materials.append(f"material_{grid_id[0]}_{grid_id[1]}_{material}") + else: + all_face_materials.append(material) + + if not all_vertices: + self.logger.error("没有找到有效的文件") + return # 写入合并后的MTL文件 final_mtl = os.path.join(output_model_dir, "textured_model.mtl") @@ -293,69 +234,12 @@ class MergeObj: f.write(f"{line}\n") f.write("\n") - # 最终结果 + # 写入合并后的OBJ文件 final_obj = os.path.join(output_model_dir, "textured_model.obj") + self.write_obj(final_obj, all_vertices, all_tex_coords, all_normals, + all_faces, all_face_materials, "textured_model.mtl") - if len(grid_files) == 1: - # 对于单个grid,需要修改obj文件中的材质引用 - grid_id = list(grid_files.keys())[0] - src_obj = grid_files[grid_id]['obj'] - - # 读取源obj文件内容 - vertices, tex_coords, normals, faces, face_materials, _ = self.read_obj(src_obj) - - # 更新材质名称,添加网格前缀 - updated_face_materials = [] - for mat in face_materials: - if mat: # 如果材质名不为空 - updated_face_materials.append(f"material_{grid_id[0]}_{grid_id[1]}_{mat}") - else: - updated_face_materials.append(mat) - - # 写入新的obj文件 - self.write_obj(final_obj, vertices, tex_coords, normals, faces, updated_face_materials, "textured_model.mtl") - else: - # 合并多个OBJ文件 - reference_id = list(grid_files.keys())[0] - merged_obj = grid_files[reference_id]['obj'] - temp_files = [] # 记录所有中间文件 - - for grid_id, files in list(grid_files.items())[1:]: - # 生成临时输出文件名 - temp_output = os.path.join( - output_model_dir, - f"temp_merged_{int(time.time())}.obj" - ) - temp_files.append(temp_output) # 添加到临时文件列表 - - self.merge_two_objs( - merged_obj, files['obj'], temp_output, reference_id, grid_id) - - merged_obj = temp_output - - # 重命名最终文件 - try: - if os.path.exists(final_obj): - os.remove(final_obj) - os.rename(merged_obj, final_obj) - except Exception as e: - self.logger.warning(f"重命名最终文件失败: {str(e)}") - shutil.copy2(merged_obj, final_obj) - try: - os.remove(merged_obj) - except: - pass - - # 清理所有临时文件 - for temp_file in temp_files: - if os.path.exists(temp_file): - try: - os.remove(temp_file) - except Exception as e: - self.logger.warning( - f"删除临时文件失败: {temp_file}, 错误: {str(e)}") - - # 计算所有grid中心点的平均值作为整体中心点 + # 计算整体中心点 center_lon = sum(center[0] for center in grid_centers) / len(grid_centers) center_lat = sum(center[1] for center in grid_centers) / len(grid_centers) self.logger.info(f"模型整体中心点经纬度: ({center_lon}, {center_lat})") @@ -377,15 +261,15 @@ class MergeObj: # 计算相对坐标的边界框 x_coords = [v[0] for v in vertices] y_coords = [v[1] for v in vertices] - + # 计算中心点相对坐标 center_x_relative = (min(x_coords) + max(x_coords)) / 2 center_y_relative = (min(y_coords) + max(y_coords)) / 2 - + # 加回最小UTM坐标得到实际的UTM坐标 center_x_utm = center_x_relative + self.min_east center_y_utm = center_y_relative + self.min_north - + # 转换为WGS84经纬度 lon, lat = self.transformer.transform(center_x_utm, center_y_utm) self.logger.info(f"模型UTM中心点: ({center_x_utm}, {center_y_utm})") @@ -538,11 +422,6 @@ class MergeObj: # 其他行直接写入 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)}")