Browse Source

代码更新

main
hesuicong 2 weeks ago
parent
commit
dcc9a27cc2
  1. 525
      compute_print_net.py
  2. 594
      compute_print_net_out.py
  3. 4
      config.py
  4. 87
      general.py
  5. 4
      point_cloud_layout.py
  6. 56
      print_show_weight_max_obj.py
  7. 3
      test_load_json.py

525
compute_print_net.py

@ -3,352 +3,14 @@ import numpy as np
import copy import copy
import time import time
import argparse import argparse
import os
from general import * from general import *
from compute_print_net_out import get_volume_centroid
# ------------------------ 开始:对外接口,获取bbox数据 -------------------- from compute_print_net_out import get_lowest_position_of_z_ext
from compute_print_net_out import get_lowest_position_of_z_ext
""" from compute_print_net_out import compute_bbox_ext
对外部提供的获取bbox数据的接口 from compute_print_net_out import voxel_size
compute_bbox_out
参数:
obj_path, 模型数据路径
返回:
total_matrix: 旋转矩阵, 16位浮点型, 例如, [[ 0.13644984 0.99064698 0. -49.71074343]
[ -0.99064698 0.13644984 0. -28.80249299]
[ 0. 0. 1. 3.26326203]
[ 0. 0. 0. 1. ]]
z_max : z最高点, 1位浮点型, 例如, 1.0
min_bound : bbox最低点, 3位浮点型, 例如, [-1.0, -1.0, 0.0]
max_bound : bbox最低点, 3位浮点型, 例如, [0.0, 0.0, 1.0]
ply_name : ply的名字, 字符串, 例如, 857420_268473_P85240_5cm_x1=9.41+49.997+49.997.ply
"""
def compute_bbox_out(mesh_obj):
return compute_bbox_ext(mesh_obj)
# -------------------------- 结束:对外接口,获取bbox数据 ----------------
# -------------------------- 开始:获取z值最低 --------------------------
def get_lowest_position_of_z_ext(mesh_obj):
total_matrix = np.eye(4)
voxel_size = 3
# print(f"obj_path={obj_path}, get_lowest_position_of_center voxel_size={voxel_size}")
start_time1 = time.time()
vertices = np.asarray(mesh_obj.vertices)
# 确保网格有顶点
if len(vertices) == 0:
# raise ValueError(f"Mesh has no vertices: {obj_path}")
print(f"Warning: Mesh has no vertices: {mesh_obj}")
return None
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(vertices)
# print("voxel_size",voxel_size,obj_path, len(pcd.points), len(mesh_obj.vertices))
# 对点云进行下采样(体素网格法)
#"""
pcd_downsampled = down_sample(pcd, voxel_size)
pcd_downsampled.paint_uniform_color([0, 0, 1])
if len(np.asarray(pcd_downsampled.points)) <= 0:
bbox = pcd.get_axis_aligned_bounding_box()
volume = bbox.volume()
# print(f"len(pcd.points)={len(pcd.points)}, volume={volume}")
# 处理体积为零的情况
if volume <= 0:
# 计算点云的实际范围
points = np.asarray(pcd.points)
if len(points) > 0:
min_bound = np.min(points, axis=0)
max_bound = np.max(points, axis=0)
extent = max_bound - min_bound
# 确保最小维度至少为0.01
min_dimension = max(0.01, np.min(extent))
volume = min_dimension ** 3
else:
volume = 1.0 # 最后的安全回退
print(f"Warning: Zero volume detected, using approximated volume {volume:.6f} for {obj_path}")
# 安全计算密度 - 防止除零错误
if len(pcd.points) > 0 and volume > 0:
original_density = len(pcd.points) / volume
voxel_size = max(0.01, min(10.0, 0.5 / (max(1e-6, original_density) ** 0.33)))
else:
# 当点数为0或体积为0时使用默认体素大小
voxel_size = 1.0 # 默认值
print(f"Recalculated voxel_size: {voxel_size} for {obj_path}")
pcd_downsampled = down_sample(pcd, voxel_size)
pcd_downsampled.paint_uniform_color([0, 0, 1])
original_num = len(pcd.points)
target_samples = 1000
num_samples = min(target_samples, original_num)
# print("get_lowest_position_of_center1 time", time.time()-start_time1)
start_time2 = time.time()
# 确保下采样后有点云
if len(np.asarray(pcd_downsampled.points)) == 0:
# 使用原始点云作为后备
pcd_downsampled = pcd
print(f"Warning: Using original point cloud for {obj_path} as downsampling produced no points")
points = np.asarray(pcd_downsampled.points)
# 初始化最小重心Y的值
max_z_of_mass_y = float('inf')
best_angle_x, best_angle_y, best_angle_z = 0, 0, 0
best_angle_x, best_angle_y, best_angle_z, max_z_of_mass_y = parallel_rotation(points, angle_step=3)
# 使用最佳角度进行旋转并平移obj
pcd_transformed = copy.deepcopy(mesh_obj)
# 最佳角度旋转
R_x = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([1, 0, 0]) * np.radians(best_angle_x))
pcd_transformed.rotate(R_x)
R_y = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * np.radians(best_angle_y))
pcd_transformed.rotate(R_y)
R_z = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 0, 1]) * np.radians(best_angle_z))
pcd_transformed.rotate(R_z)
T_x = np.eye(4)
T_x[:3, :3] = R_x
center_point = compute_mesh_center(mesh_obj.vertices)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
T_rot_center = T_origin_to_center @ T_x @ T_center_to_origin
total_matrix = T_rot_center @ total_matrix
T_y = np.eye(4)
T_y[:3, :3] = R_y
center_point = compute_mesh_center(mesh_obj.vertices)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
T_rot_center = T_origin_to_center @ T_y @ T_center_to_origin
total_matrix = T_rot_center @ total_matrix
T_z = np.eye(4)
T_z[:3, :3] = R_z
center_point = compute_mesh_center(mesh_obj.vertices)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
T_rot_center = T_origin_to_center @ T_z @ T_center_to_origin
total_matrix = T_rot_center @ total_matrix
#试着旋转180,让脸朝上
vertices = np.asarray(pcd_transformed.vertices)
# 计算平移向量,将最小Y值平移到0
min_z = np.min(vertices[:, 2])
translation_vector = np.array([0,0,-min_z,])
pcd_transformed.translate(translation_vector)
T_trans1 = np.eye(4)
T_trans1[:3, 3] = translation_vector
total_matrix = T_trans1 @ total_matrix
# 计算 z 坐标均值
vertices = np.asarray(pcd_transformed.vertices)
z_mean1 = np.mean(vertices[:, 2])
z_max1 = np.max(vertices[:, 2])
volume_centroid = get_volume_centroid(pcd_transformed)
z_volume_center1 = volume_centroid[2]
angle_rad = np.pi
#print("旋转前质心:", pcd_transformed.get_center())
#print("旋转前点示例:", np.asarray(pcd_transformed.vertices)[:3])
R_y = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * angle_rad)
pcd_transformed.translate(-center_point)
pcd_transformed.rotate(R_y, center=(0, 0, 0))
pcd_transformed.translate(center_point)
aabb = pcd_transformed.get_axis_aligned_bounding_box()
# center_point = aabb.get_center()
center_point = compute_mesh_center(mesh_obj.vertices)
# 构建绕中心点旋转的变换矩阵[3](@ref)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
R_y180 = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * angle_rad)
T_rotate = np.eye(4)
T_rotate[:3, :3] = R_y180
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
T_rot_center = T_origin_to_center @ T_rotate @ T_center_to_origin
total_matrix = T_rot_center @ total_matrix
#print("旋转后质心:", pcd_transformed.get_center())
#print("旋转后点示例:", np.asarray(pcd_transformed.vertices)[:3])
#
vertices = np.asarray(pcd_transformed.vertices)
# 计算平移向量,将最小Y值平移到0
min_z = np.min(vertices[:, 2])
max_z = np.max(vertices[:, 2])
# print("min_z1", min_z, obj_path)
translation_vector = np.array([0,0,-min_z,])
# translation_vector = np.array([0,0,-min_z + (min_z-max_z),])
# print("translation_vector1",translation_vector)
pcd_transformed.translate(translation_vector)
T_trans2 = np.eye(4)
T_trans2[:3, 3] = translation_vector
translation = total_matrix[:3, 3]
# print("translation_vector2",translation_vector)
# print(1,translation)
total_matrix = T_trans2 @ total_matrix
translation = total_matrix[:3, 3]
# print(2,translation)
# 计算 z 坐标均值
vertices = np.asarray(pcd_transformed.vertices)
z_mean2 = np.mean(vertices[:, 2])
z_max2 = np.max(vertices[:, 2])
volume_centroid = get_volume_centroid(pcd_transformed)
z_volume_center2 = volume_centroid[2]
# print(f"get_lowest_position_of_center z_max1={z_max1}, z_max2={z_max2}, len={len(pcd_transformed.vertices)}, obj_path={obj_path}")
# print(f"z_mean1={z_mean1}, z_mean2={z_mean2}")
# if (z_mean2 > z_mean1):
# print(f"z_volume_center1={z_volume_center1}, z_volume_center2={z_volume_center2}")
if (z_volume_center2 > z_volume_center1):
R_y = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * -angle_rad)
centroid = pcd_transformed.get_center()
aabb = pcd_transformed.get_axis_aligned_bounding_box()
# center_point = aabb.get_center()
center_point = compute_mesh_center(mesh_obj.vertices)
pcd_transformed.translate(-center_point)
pcd_transformed.rotate(R_y, center=(0, 0, 0))
pcd_transformed.translate(center_point)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
# 构建反向旋转矩阵
R_y = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * -angle_rad)
T_rotate_inv = np.eye(4)
T_rotate_inv[:3, :3] = R_y
# 完整的反向绕中心旋转矩阵
T_rot_center_inv = T_origin_to_center @ T_rotate_inv @ T_center_to_origin
total_matrix = T_rot_center_inv @ total_matrix
vertices = np.asarray(pcd_transformed.vertices)
# 计算平移向量,将最小Y值平移到0
min_z = np.min(vertices[:, 2])
# print("min_z2", min_z, obj_path)
translation_vector = np.array([0,0,-min_z,])
pcd_transformed.translate(translation_vector)
T_trans3 = np.eye(4)
T_trans3[:3, 3] = translation_vector
total_matrix = T_trans3 @ total_matrix
# z_mean_min = min(z_mean1, z_mean2)
z_max = min(z_max1, z_max2)
# print("get_lowest_position_of_center2 time", time.time()-start_time2)
return total_matrix, z_max
def get_lowest_position_of_center_ext(mesh_obj, total_matrix):
print(f"get_lowest_position_of_center_ext mesh_obj={mesh_obj}")
temp_matrix, z_max = get_lowest_position_of_z_ext(mesh_obj)
total_matrix = temp_matrix @ total_matrix
return total_matrix, z_max
def calculate_rotation_and_top_of_mass(angle_x, angle_y, angle_z, points):
"""计算某一组旋转角度后的重心"""
# 计算绕X轴、Y轴和Z轴的旋转矩阵
R_x = np.array([
[1, 0, 0],
[0, np.cos(np.radians(angle_x)), -np.sin(np.radians(angle_x))],
[0, np.sin(np.radians(angle_x)), np.cos(np.radians(angle_x))]
])
R_y = np.array([
[np.cos(np.radians(angle_y)), 0, np.sin(np.radians(angle_y))],
[0, 1, 0],
[-np.sin(np.radians(angle_y)), 0, np.cos(np.radians(angle_y))]
])
R_z = np.array([
[np.cos(np.radians(angle_z)), -np.sin(np.radians(angle_z)), 0],
[np.sin(np.radians(angle_z)), np.cos(np.radians(angle_z)), 0],
[0, 0, 1]
])
# 综合旋转矩阵
R = R_z @ R_y @ R_x
# 执行旋转
rotated_points = points @ R.T
# 计算最小z值
min_z = np.min(rotated_points[:, 2])
# 计算平移向量,将最小Z值平移到0
translation_vector = np.array([0, 0, -min_z])
rotated_points += translation_vector
top_of_mass = np.max(rotated_points, axis=0)
return top_of_mass[2], angle_x, angle_y, angle_z
def parallel_rotation(points, angle_step=4):
"""仅绕 Y 轴旋转(假设 X/Z 轴不影响目标函数)"""
max_top = float('inf')
for angle_x in range(-90, 90, angle_step):
for angle_y in range(0, 360, angle_step):
max_z, ax, ay, _ = calculate_rotation_and_top_of_mass(angle_x, angle_y, 0, points)
if max_z < max_top:
max_top = max_z
best_angle_x = ax
best_angle_y = ay
return (best_angle_x, best_angle_y, 0, max_top)
def compute_mesh_center(vertices):
if len(vertices) == 0:
raise ValueError("顶点数组不能为空")
# 确保vertices是NumPy数组
vertices_np = np.asarray(vertices)
# 使用NumPy的mean函数直接计算均值(向量化操作)
centroid = np.mean(vertices_np, axis=0)
return centroid
# -------------------------- 结束:获取z值最低 --------------------------
# -------------------------- 开始:bbox -------------------------- # -------------------------- 开始:bbox --------------------------
@ -439,12 +101,23 @@ def compute_bbox_all(dict_mesh_obj,is_downsample):
return dict_total_matrix,all_models return dict_total_matrix,all_models
def compute_bbox(mesh_obj, obj_name, is_downsample=True):
def compute_bbox(mesh_obj, obj_name="", is_downsample=True):
# return compute_bbox_ext(mesh_obj, obj_name, is_downsample) # return compute_bbox_ext(mesh_obj, obj_name, is_downsample)
mesh_obj_origin = copy.deepcopy(mesh_obj) mesh_obj_origin = copy.deepcopy(mesh_obj)
total_matrix, z_max, min_bound, max_bound, ply_name = compute_bbox_ext(mesh_obj, obj_name, is_downsample) total_matrix, z_max, min_bound, max_bound, ply_name = compute_bbox_ext(mesh_obj, obj_name, is_downsample)
# print(f"compute_bbox_ext total_matrix = {total_matrix}, ply_name = {ply_name}")
"""
# 从网络上获取数据
printId = ""
match = re.search(r"P(\d+)", obj_name) # 匹配 "P" 后的连续数字
if match:
printId = match.group(1)
total_matrix, z_max, min_bound, max_bound, ply_name = compute_bbox_net(printId)
ply_name = f"{os.path.splitext(obj_name)[0]}={ply_name.split('=')[1]}"
# print(f"compute_bbox_net printId = {printId}, total_matrix = {total_matrix}, ply_name = {ply_name}")
"""
transformed_vertices = mesh_transform_by_matrix(np.asarray(mesh_obj_origin.vertices), total_matrix) transformed_vertices = mesh_transform_by_matrix(np.asarray(mesh_obj_origin.vertices), total_matrix)
@ -458,141 +131,33 @@ def compute_bbox(mesh_obj, obj_name="", is_downsample=True):
return total_matrix, pcd_fix, ply_name return total_matrix, pcd_fix, ply_name
def compute_bbox_ext(mesh_obj, obj_name="", is_downsample=True): import requests
import ast
total_matrix = np.eye(4) def compute_bbox_net(printId):
total_matrix, z_max= get_lowest_position_of_center_ext(mesh_obj, total_matrix)
transformed_vertices = mesh_transform_by_matrix(np.asarray(mesh_obj.vertices), total_matrix)
obj_transformed = copy.deepcopy(mesh_obj)
obj_transformed.vertices = o3d.utility.Vector3dVector(transformed_vertices)
voxel_size = 3 # 设置体素的大小,决定下采样的密度 url = f"https://mp.api.suwa3d.com/api/printOrder/infoByPrintId?printId={printId}"
# 将点云摆正和X轴平衡 res = requests.get(url)
obj_transformed_second,total_matrix = arrange_box_correctly(obj_transformed,voxel_size,total_matrix)
total_matrix, min_bound, max_bound, ply_name, pcd_fix = get_new_bbox(obj_transformed_second,obj_name,voxel_size,is_downsample,total_matrix) datas = res.json()["data"]["layout"]
# print("datas=", datas)
del obj_transformed
del obj_transformed_second
# return total_matrix, z_max, min_bound, max_bound, ply_name, pcd_fix homo_matrix_str = datas.get("homo_matrix")
return total_matrix, z_max, min_bound, max_bound, ply_name # print("homo_matrix_str=", homo_matrix_str)
def arrange_box_correctly(obj_transformed, voxel_size,total_matrix):
vertices = np.asarray(obj_transformed.vertices)
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(vertices)
# 降采样与特征计算 try:
# pcd_downsampled = down_sample(pcd, voxel_size) matrix_list = ast.literal_eval(homo_matrix_str) # 直接转换为二维列表
# points = np.asarray(pcd_downsampled.points) reconstructed_matrix = np.array(matrix_list, dtype=float)
points = np.asarray(pcd.points) print("矩阵形状:", reconstructed_matrix.shape) # 应该是 (4, 4)
except (ValueError, SyntaxError) as e:
cov = np.cov(points.T) print(f"解析错误: {e}")
center = obj_transformed.get_center() layout_z = datas.get("layout_z", 0)
max_bound = datas.get("max_bound",0)
eigen_vals, eigen_vecs = np.linalg.eigh(cov) min_bound = datas.get("min_bound",0)
max_axis = eigen_vecs[:, np.argmax(eigen_vals)] ply_name = datas.get("ply_name",0)
# print(f"layout_z={layout_z}, max_bound={max_bound}, min_bound={min_bound}, ply_name={ply_name}, ")
# print("max_axis", max_axis)
# 强制主方向向量X分量为正(指向右侧)
if max_axis[0] < 0 or (max_axis[0] == 0 and max_axis[1] < 0):
max_axis = -max_axis
target_dir = np.array([1, 0]) # 目标方向为X正轴
current_dir = max_axis[:2] / np.linalg.norm(max_axis[:2])
dot_product = np.dot(current_dir, target_dir)
# print("dot_product", dot_product) return reconstructed_matrix, layout_z, max_bound, min_bound, ply_name
if dot_product < 0.8: # 阈值控制方向敏感性(建议0.6~0.9)
max_axis = -max_axis # 强制翻转方向
# 计算旋转角度
angle_z = np.arctan2(max_axis[1], max_axis[0]) % (2 * np.pi)
if max_axis[0] <= 0 and max_axis[1] <= 0:
angle_z += np.pi
R = o3d.geometry.get_rotation_matrix_from_axis_angle([0, 0, -angle_z])
T = np.eye(4)
T[:3, :3] = R
T[:3, 3] = center - R.dot(center) # 保持中心不变
obj_transformed.transform(T)
total_matrix = T @ total_matrix
return obj_transformed, total_matrix
def get_new_bbox(obj_transformed_second,obj_name,voxel_size,is_downsample,total_matrix):
# 计算点云的边界
points = np.asarray(obj_transformed_second.vertices)
min_bound = np.min(points, axis=0) # 获取点云的最小边界
max_bound = np.max(points, axis=0) # 获取点云的最大边界
# print(f"get_new_bbox1: min_bound={min_bound}, max_bound={max_bound}")
# 确保包围盒的Y坐标不低于0
min_bound[2] = max(min_bound[2], 0) # 确保Y坐标的最小值不低于0
# 重新计算包围盒的中心和半长轴
bbox_center = (min_bound + max_bound) / 2 # 计算包围盒的中心点
bbox_extent = (max_bound - min_bound) # 计算包围盒的半长轴(尺寸)
# 创建包围盒,确保尺寸正确
new_bbox = o3d.geometry.OrientedBoundingBox(center=bbox_center,
R=np.eye(3), # 旋转矩阵,默认没有旋转
extent=bbox_extent)
# 获取包围盒的长、宽和高
x_length = round(bbox_extent[0],3) # X 方向的长
y_length = round(bbox_extent[1],3) # Y 方向的宽
z_length = round(bbox_extent[2],3) # Z 方向的高
bbox_points = np.array([
[min_bound[0], min_bound[1], min_bound[2]],
[max_bound[0], min_bound[1], min_bound[2]],
[max_bound[0], max_bound[1], min_bound[2]],
[min_bound[0], max_bound[1], min_bound[2]],
[min_bound[0], min_bound[1], max_bound[2]],
[max_bound[0], min_bound[1], max_bound[2]],
[max_bound[0], max_bound[1], max_bound[2]],
[min_bound[0], max_bound[1], max_bound[2]]
])
first_corner = bbox_points[2]
translation_vector = -first_corner
obj_transformed_second.translate(translation_vector)
T_trans = np.eye(4)
T_trans[:3, 3] = translation_vector # 设置平移分量 [2,3](@ref)
total_matrix = T_trans @ total_matrix # 矩阵乘法顺序:最新变换左乘[4,5](@ref)
new_bbox.translate(translation_vector)
vertices = np.asarray(obj_transformed_second.vertices)
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(vertices)
if is_downsample:
pcd_downsampled = down_sample(pcd, voxel_size, False)
pcd_fix = pcd_downsampled
else:
pcd_fix = pcd
min_bound = np.min(pcd.points, axis=0) # 获取点云的最小边界
max_bound = np.max(pcd.points, axis=0) # 获取点云的最大边界
# print(f"get_new_bbox2: min_bound={min_bound}, max_bound={max_bound}")
if (not obj_name == ""):
ply_print_pid = obj_name.replace(".obj","")
ply_name = f"{ply_print_pid}={z_length}+{y_length}+{x_length}.ply"
else:
ply_name = ""
return total_matrix, min_bound, max_bound, ply_name, pcd_fix
class Platform: class Platform:
def __init__(self, width, depth, height): def __init__(self, width, depth, height):
@ -782,13 +347,3 @@ class Platform:
return self.placed_models, self.unplaced_models return self.placed_models, self.unplaced_models
# -------------------------- 结束:bbox -------------------------- # -------------------------- 结束:bbox --------------------------
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("--obj_path", type=str, required=True, help="batchobj_path_id")
args = parser.parse_args()
obj_path = args.obj_path
max, z = get_lowest_position_of_z_ext(obj_path)

594
compute_print_net_out.py

@ -0,0 +1,594 @@
import open3d as o3d
import numpy as np
import copy
import time
import argparse
import os
# ------------------------ 开始:对外接口,获取bbox数据 --------------------
"""
对外部提供的获取bbox数据的接口
compute_bbox_out
参数:
obj_path: 模型数据路径
返回:
total_matrix: 旋转矩阵, 16位浮点型, 例如, [[ 0.13644984 0.99064698 0. -49.71074343]
[ -0.99064698 0.13644984 0. -28.80249299]
[ 0. 0. 1. 3.26326203]
[ 0. 0. 0. 1. ]]
z_max : z最高点, 1位浮点型, 例如, 1.0
min_bound : bbox最低点, 3位浮点型, 例如, [-1.0, -1.0, 0.0]
max_bound : bbox最低点, 3位浮点型, 例如, [0.0, 0.0, 1.0]
ply_name : ply的名字, 字符串, 例如, 857420_268473_P85240_5cm_x1=9.41+49.997+49.997.ply
"""
def compute_bbox_out(obj_path):
obj_name = os.path.basename(obj_path)
mesh_obj = read_mesh(obj_path)
return compute_bbox_ext(mesh_obj, obj_name)
# -------------------------- 结束:对外接口,获取bbox数据 ----------------
# -------------------------- 开始:获取z值最低 --------------------------
def get_lowest_position_of_z_ext(mesh_obj):
total_matrix = np.eye(4)
voxel_size = 3
# print(f"obj_path={obj_path}, get_lowest_position_of_center voxel_size={voxel_size}")
start_time1 = time.time()
vertices = np.asarray(mesh_obj.vertices)
# 确保网格有顶点
if len(vertices) == 0:
# raise ValueError(f"Mesh has no vertices: {obj_path}")
print(f"Warning: Mesh has no vertices: {mesh_obj}")
return None
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(vertices)
# print("voxel_size",voxel_size,obj_path, len(pcd.points), len(mesh_obj.vertices))
# 对点云进行下采样(体素网格法)
#"""
pcd_downsampled = down_sample(pcd, voxel_size)
pcd_downsampled.paint_uniform_color([0, 0, 1])
if len(np.asarray(pcd_downsampled.points)) <= 0:
bbox = pcd.get_axis_aligned_bounding_box()
volume = bbox.volume()
# print(f"len(pcd.points)={len(pcd.points)}, volume={volume}")
# 处理体积为零的情况
if volume <= 0:
# 计算点云的实际范围
points = np.asarray(pcd.points)
if len(points) > 0:
min_bound = np.min(points, axis=0)
max_bound = np.max(points, axis=0)
extent = max_bound - min_bound
# 确保最小维度至少为0.01
min_dimension = max(0.01, np.min(extent))
volume = min_dimension ** 3
else:
volume = 1.0 # 最后的安全回退
print(f"Warning: Zero volume detected, using approximated volume {volume:.6f} for {obj_path}")
# 安全计算密度 - 防止除零错误
if len(pcd.points) > 0 and volume > 0:
original_density = len(pcd.points) / volume
voxel_size = max(0.01, min(10.0, 0.5 / (max(1e-6, original_density) ** 0.33)))
else:
# 当点数为0或体积为0时使用默认体素大小
voxel_size = 1.0 # 默认值
print(f"Recalculated voxel_size: {voxel_size} for {obj_path}")
pcd_downsampled = down_sample(pcd, voxel_size)
pcd_downsampled.paint_uniform_color([0, 0, 1])
original_num = len(pcd.points)
target_samples = 1000
num_samples = min(target_samples, original_num)
# print("get_lowest_position_of_center1 time", time.time()-start_time1)
start_time2 = time.time()
# 确保下采样后有点云
if len(np.asarray(pcd_downsampled.points)) == 0:
# 使用原始点云作为后备
pcd_downsampled = pcd
print(f"Warning: Using original point cloud for {obj_path} as downsampling produced no points")
points = np.asarray(pcd_downsampled.points)
# 初始化最小重心Y的值
max_z_of_mass_y = float('inf')
best_angle_x, best_angle_y, best_angle_z = 0, 0, 0
best_angle_x, best_angle_y, best_angle_z, max_z_of_mass_y = parallel_rotation(points, angle_step=3)
# 使用最佳角度进行旋转并平移obj
pcd_transformed = copy.deepcopy(mesh_obj)
# 最佳角度旋转
R_x = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([1, 0, 0]) * np.radians(best_angle_x))
pcd_transformed.rotate(R_x)
R_y = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * np.radians(best_angle_y))
pcd_transformed.rotate(R_y)
R_z = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 0, 1]) * np.radians(best_angle_z))
pcd_transformed.rotate(R_z)
T_x = np.eye(4)
T_x[:3, :3] = R_x
center_point = compute_mesh_center(mesh_obj.vertices)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
T_rot_center = T_origin_to_center @ T_x @ T_center_to_origin
total_matrix = T_rot_center @ total_matrix
T_y = np.eye(4)
T_y[:3, :3] = R_y
center_point = compute_mesh_center(mesh_obj.vertices)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
T_rot_center = T_origin_to_center @ T_y @ T_center_to_origin
total_matrix = T_rot_center @ total_matrix
T_z = np.eye(4)
T_z[:3, :3] = R_z
center_point = compute_mesh_center(mesh_obj.vertices)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
T_rot_center = T_origin_to_center @ T_z @ T_center_to_origin
total_matrix = T_rot_center @ total_matrix
#试着旋转180,让脸朝上
vertices = np.asarray(pcd_transformed.vertices)
# 计算平移向量,将最小Y值平移到0
min_z = np.min(vertices[:, 2])
translation_vector = np.array([0,0,-min_z,])
pcd_transformed.translate(translation_vector)
T_trans1 = np.eye(4)
T_trans1[:3, 3] = translation_vector
total_matrix = T_trans1 @ total_matrix
# 计算 z 坐标均值
vertices = np.asarray(pcd_transformed.vertices)
z_mean1 = np.mean(vertices[:, 2])
z_max1 = np.max(vertices[:, 2])
volume_centroid = get_volume_centroid(pcd_transformed)
z_volume_center1 = volume_centroid[2]
angle_rad = np.pi
#print("旋转前质心:", pcd_transformed.get_center())
#print("旋转前点示例:", np.asarray(pcd_transformed.vertices)[:3])
R_y = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * angle_rad)
pcd_transformed.translate(-center_point)
pcd_transformed.rotate(R_y, center=(0, 0, 0))
pcd_transformed.translate(center_point)
aabb = pcd_transformed.get_axis_aligned_bounding_box()
# center_point = aabb.get_center()
center_point = compute_mesh_center(mesh_obj.vertices)
# 构建绕中心点旋转的变换矩阵[3](@ref)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
R_y180 = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * angle_rad)
T_rotate = np.eye(4)
T_rotate[:3, :3] = R_y180
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
T_rot_center = T_origin_to_center @ T_rotate @ T_center_to_origin
total_matrix = T_rot_center @ total_matrix
#print("旋转后质心:", pcd_transformed.get_center())
#print("旋转后点示例:", np.asarray(pcd_transformed.vertices)[:3])
#
vertices = np.asarray(pcd_transformed.vertices)
# 计算平移向量,将最小Y值平移到0
min_z = np.min(vertices[:, 2])
max_z = np.max(vertices[:, 2])
# print("min_z1", min_z, obj_path)
translation_vector = np.array([0,0,-min_z,])
# translation_vector = np.array([0,0,-min_z + (min_z-max_z),])
# print("translation_vector1",translation_vector)
pcd_transformed.translate(translation_vector)
T_trans2 = np.eye(4)
T_trans2[:3, 3] = translation_vector
translation = total_matrix[:3, 3]
# print("translation_vector2",translation_vector)
# print(1,translation)
total_matrix = T_trans2 @ total_matrix
translation = total_matrix[:3, 3]
# print(2,translation)
# 计算 z 坐标均值
vertices = np.asarray(pcd_transformed.vertices)
z_mean2 = np.mean(vertices[:, 2])
z_max2 = np.max(vertices[:, 2])
volume_centroid = get_volume_centroid(pcd_transformed)
z_volume_center2 = volume_centroid[2]
# print(f"get_lowest_position_of_center z_max1={z_max1}, z_max2={z_max2}, len={len(pcd_transformed.vertices)}, obj_path={obj_path}")
# print(f"z_mean1={z_mean1}, z_mean2={z_mean2}")
# if (z_mean2 > z_mean1):
# print(f"z_volume_center1={z_volume_center1}, z_volume_center2={z_volume_center2}")
if (z_volume_center2 > z_volume_center1):
R_y = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * -angle_rad)
centroid = pcd_transformed.get_center()
aabb = pcd_transformed.get_axis_aligned_bounding_box()
# center_point = aabb.get_center()
center_point = compute_mesh_center(mesh_obj.vertices)
pcd_transformed.translate(-center_point)
pcd_transformed.rotate(R_y, center=(0, 0, 0))
pcd_transformed.translate(center_point)
T_center_to_origin = np.eye(4)
T_center_to_origin[:3, 3] = -center_point
T_origin_to_center = np.eye(4)
T_origin_to_center[:3, 3] = center_point
# 构建反向旋转矩阵
R_y = pcd_transformed.get_rotation_matrix_from_axis_angle(np.array([0, 1, 0]) * -angle_rad)
T_rotate_inv = np.eye(4)
T_rotate_inv[:3, :3] = R_y
# 完整的反向绕中心旋转矩阵
T_rot_center_inv = T_origin_to_center @ T_rotate_inv @ T_center_to_origin
total_matrix = T_rot_center_inv @ total_matrix
vertices = np.asarray(pcd_transformed.vertices)
# 计算平移向量,将最小Y值平移到0
min_z = np.min(vertices[:, 2])
# print("min_z2", min_z, obj_path)
translation_vector = np.array([0,0,-min_z,])
pcd_transformed.translate(translation_vector)
T_trans3 = np.eye(4)
T_trans3[:3, 3] = translation_vector
total_matrix = T_trans3 @ total_matrix
# z_mean_min = min(z_mean1, z_mean2)
z_max = min(z_max1, z_max2)
# print("get_lowest_position_of_center2 time", time.time()-start_time2)
return total_matrix, z_max
def get_lowest_position_of_center_ext(mesh_obj, total_matrix):
# print(f"get_lowest_position_of_center_ext mesh_obj={mesh_obj}")
temp_matrix, z_max = get_lowest_position_of_z_ext(mesh_obj)
total_matrix = temp_matrix @ total_matrix
return total_matrix, z_max
def calculate_rotation_and_top_of_mass(angle_x, angle_y, angle_z, points):
"""计算某一组旋转角度后的重心"""
# 计算绕X轴、Y轴和Z轴的旋转矩阵
R_x = np.array([
[1, 0, 0],
[0, np.cos(np.radians(angle_x)), -np.sin(np.radians(angle_x))],
[0, np.sin(np.radians(angle_x)), np.cos(np.radians(angle_x))]
])
R_y = np.array([
[np.cos(np.radians(angle_y)), 0, np.sin(np.radians(angle_y))],
[0, 1, 0],
[-np.sin(np.radians(angle_y)), 0, np.cos(np.radians(angle_y))]
])
R_z = np.array([
[np.cos(np.radians(angle_z)), -np.sin(np.radians(angle_z)), 0],
[np.sin(np.radians(angle_z)), np.cos(np.radians(angle_z)), 0],
[0, 0, 1]
])
# 综合旋转矩阵
R = R_z @ R_y @ R_x
# 执行旋转
rotated_points = points @ R.T
# 计算最小z值
min_z = np.min(rotated_points[:, 2])
# 计算平移向量,将最小Z值平移到0
translation_vector = np.array([0, 0, -min_z])
rotated_points += translation_vector
top_of_mass = np.max(rotated_points, axis=0)
return top_of_mass[2], angle_x, angle_y, angle_z
def parallel_rotation(points, angle_step=4):
"""仅绕 Y 轴旋转(假设 X/Z 轴不影响目标函数)"""
max_top = float('inf')
for angle_x in range(-90, 90, angle_step):
for angle_y in range(0, 360, angle_step):
max_z, ax, ay, _ = calculate_rotation_and_top_of_mass(angle_x, angle_y, 0, points)
if max_z < max_top:
max_top = max_z
best_angle_x = ax
best_angle_y = ay
return (best_angle_x, best_angle_y, 0, max_top)
def compute_mesh_center(vertices):
if len(vertices) == 0:
raise ValueError("顶点数组不能为空")
# 确保vertices是NumPy数组
vertices_np = np.asarray(vertices)
# 使用NumPy的mean函数直接计算均值(向量化操作)
centroid = np.mean(vertices_np, axis=0)
return centroid
# -------------------------- 结束:获取z值最低 --------------------------
# -------------------------- 开始:bbox --------------------------
def compute_bbox_ext(mesh_obj, obj_name="", is_downsample=True):
total_matrix = np.eye(4)
total_matrix, z_max= get_lowest_position_of_center_ext(mesh_obj, total_matrix)
transformed_vertices = mesh_transform_by_matrix(np.asarray(mesh_obj.vertices), total_matrix)
obj_transformed = copy.deepcopy(mesh_obj)
obj_transformed.vertices = o3d.utility.Vector3dVector(transformed_vertices)
voxel_size = 3 # 设置体素的大小,决定下采样的密度
# 将点云摆正和X轴平衡
obj_transformed_second,total_matrix = arrange_box_correctly(obj_transformed,voxel_size,total_matrix)
total_matrix, min_bound, max_bound, ply_name, pcd_fix = get_new_bbox(obj_transformed_second,obj_name,voxel_size,is_downsample,total_matrix)
del obj_transformed
del obj_transformed_second
# return total_matrix, z_max, min_bound, max_bound, ply_name, pcd_fix
return total_matrix, z_max, min_bound, max_bound, ply_name
def arrange_box_correctly(obj_transformed, voxel_size,total_matrix):
vertices = np.asarray(obj_transformed.vertices)
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(vertices)
# 降采样与特征计算
# pcd_downsampled = down_sample(pcd, voxel_size)
# points = np.asarray(pcd_downsampled.points)
points = np.asarray(pcd.points)
cov = np.cov(points.T)
center = obj_transformed.get_center()
eigen_vals, eigen_vecs = np.linalg.eigh(cov)
max_axis = eigen_vecs[:, np.argmax(eigen_vals)]
# print("max_axis", max_axis)
# 强制主方向向量X分量为正(指向右侧)
if max_axis[0] < 0 or (max_axis[0] == 0 and max_axis[1] < 0):
max_axis = -max_axis
target_dir = np.array([1, 0]) # 目标方向为X正轴
current_dir = max_axis[:2] / np.linalg.norm(max_axis[:2])
dot_product = np.dot(current_dir, target_dir)
# print("dot_product", dot_product)
if dot_product < 0.8: # 阈值控制方向敏感性(建议0.6~0.9)
max_axis = -max_axis # 强制翻转方向
# 计算旋转角度
angle_z = np.arctan2(max_axis[1], max_axis[0]) % (2 * np.pi)
if max_axis[0] <= 0 and max_axis[1] <= 0:
angle_z += np.pi
R = o3d.geometry.get_rotation_matrix_from_axis_angle([0, 0, -angle_z])
T = np.eye(4)
T[:3, :3] = R
T[:3, 3] = center - R.dot(center) # 保持中心不变
obj_transformed.transform(T)
total_matrix = T @ total_matrix
return obj_transformed, total_matrix
def get_new_bbox(obj_transformed_second,obj_name,voxel_size,is_downsample,total_matrix):
# 计算点云的边界
points = np.asarray(obj_transformed_second.vertices)
min_bound = np.min(points, axis=0) # 获取点云的最小边界
max_bound = np.max(points, axis=0) # 获取点云的最大边界
# print(f"get_new_bbox1: obj_name={obj_name}, min_bound={min_bound}, max_bound={max_bound}")
# 确保包围盒的Y坐标不低于0
min_bound[2] = max(min_bound[2], 0) # 确保Y坐标的最小值不低于0
# 重新计算包围盒的中心和半长轴
bbox_center = (min_bound + max_bound) / 2 # 计算包围盒的中心点
bbox_extent = (max_bound - min_bound) # 计算包围盒的半长轴(尺寸)
# 创建包围盒,确保尺寸正确
new_bbox = o3d.geometry.OrientedBoundingBox(center=bbox_center,
R=np.eye(3), # 旋转矩阵,默认没有旋转
extent=bbox_extent)
# 获取包围盒的长、宽和高
x_length = round(bbox_extent[0],3) # X 方向的长
y_length = round(bbox_extent[1],3) # Y 方向的宽
z_length = round(bbox_extent[2],3) # Z 方向的高
bbox_points = np.array([
[min_bound[0], min_bound[1], min_bound[2]],
[max_bound[0], min_bound[1], min_bound[2]],
[max_bound[0], max_bound[1], min_bound[2]],
[min_bound[0], max_bound[1], min_bound[2]],
[min_bound[0], min_bound[1], max_bound[2]],
[max_bound[0], min_bound[1], max_bound[2]],
[max_bound[0], max_bound[1], max_bound[2]],
[min_bound[0], max_bound[1], max_bound[2]]
])
first_corner = bbox_points[2]
translation_vector = -first_corner
obj_transformed_second.translate(translation_vector)
T_trans = np.eye(4)
T_trans[:3, 3] = translation_vector # 设置平移分量 [2,3](@ref)
total_matrix = T_trans @ total_matrix # 矩阵乘法顺序:最新变换左乘[4,5](@ref)
new_bbox.translate(translation_vector)
vertices = np.asarray(obj_transformed_second.vertices)
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(vertices)
if is_downsample:
pcd_downsampled = down_sample(pcd, voxel_size, False)
pcd_fix = pcd_downsampled
else:
pcd_fix = pcd
min_bound = np.min(pcd.points, axis=0) # 获取点云的最小边界
max_bound = np.max(pcd.points, axis=0) # 获取点云的最大边界
# print(f"get_new_bbox2: min_bound={min_bound}, max_bound={max_bound}")
if (not obj_name == ""):
ply_print_pid = obj_name.replace(".obj","")
ply_name = f"{ply_print_pid}={z_length}+{y_length}+{x_length}.ply"
else:
ply_name = ""
return total_matrix, min_bound, max_bound, ply_name, pcd_fix
# -------------------------- 结束:bbox --------------------------
# -------------------------- 开始:general --------------------------
def down_sample(pcd, voxel_size, farthest_sample = False):
original_num = len(pcd.points)
target_samples = 1500 # 1000
num_samples = min(target_samples, original_num)
# 第一步:使用体素下采样快速减少点数量
# voxel_size = 3
if farthest_sample:
pcd_voxel = pcd.farthest_point_down_sample(num_samples=num_samples)
else:
pcd_voxel = pcd.voxel_down_sample(voxel_size)
down_num = len(pcd_voxel.points)
# print(f"original_num={original_num}, down_num={down_num}")
# 第二步:仅在必要时进行最远点下采样
if len(pcd_voxel.points) > target_samples and False:
pcd_downsampled = pcd_voxel.farthest_point_down_sample(num_samples=num_samples)
else:
pcd_downsampled = pcd_voxel
return pcd_downsampled
def read_mesh(obj_path, enable_post_processing=False):
mesh_obj = o3d.io.read_triangle_mesh(obj_path, enable_post_processing)
return mesh_obj
def mesh_transform_by_matrix(vertices, transform_matrix):
"""
手动实现网格变换对每个顶点应用齐次变换矩阵
参数:
vertices: 网格顶点数组 (N, 3)
transform_matrix: 4x4 齐次变换矩阵
返回:
变换后的顶点数组 (N, 3)
"""
# 1. 顶点转齐次坐标 (N, 3) → (N, 4)
homogeneous_vertices = np.hstack((vertices, np.ones((vertices.shape[0], 1))))
# 2. 应用变换矩阵:矩阵乘法 (4x4) * (4xN) → (4xN)
transformed_homogeneous = transform_matrix @ homogeneous_vertices.T
# 3. 转回非齐次坐标 (3xN) → (N, 3)
transformed_vertices = transformed_homogeneous[:3, :].T
del homogeneous_vertices
del transformed_homogeneous
return transformed_vertices
def get_volume_centroid(mesh):
"""向量化版本的体积重心计算"""
vertices = np.asarray(mesh.vertices)
triangles = np.asarray(mesh.triangles)
# 一次性获取所有三角形的顶点 [n_triangles, 3, 3]
tri_vertices = vertices[triangles]
# 分别提取三个顶点
v0 = tri_vertices[:, 0, :] # [n, 3]
v1 = tri_vertices[:, 1, :] # [n, 3]
v2 = tri_vertices[:, 2, :] # [n, 3]
# 向量化计算叉积和点积
cross_vec = np.cross(v1, v2) # [n, 3]
dot_results = np.einsum('ij,ij->i', v0, cross_vec) # 批量点积 [n]
# 计算每个四面体体积 [n]
tetra_volumes = np.abs(dot_results) / 6.0
# 计算每个四面体重心 [n, 3]
tetra_centers = (v0 + v1 + v2) / 4.0
# 总体积和加权重心
total_volume = np.sum(tetra_volumes)
if total_volume > 0:
weighted_center = np.sum(tetra_volumes[:, np.newaxis] * tetra_centers, axis=0) / total_volume
return weighted_center
else:
return np.mean(vertices, axis=0)
voxel_size = 3
# -------------------------- 结束:general --------------------------
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("--obj_path", type=str, required=True, help="obj 路径")
args = parser.parse_args()
obj_path = args.obj_path
total_matrix, z_max, min_bound, max_bound, ply_name = compute_bbox_out(obj_path)
print(f"total_matrix={total_matrix}, z_max={z_max}, min_bound={min_bound}, max_bound={max_bound}, ply_name={ply_name}")

4
config.py

File diff suppressed because one or more lines are too long

87
general.py

@ -3,6 +3,10 @@ import numpy as np
import re import re
from config import * from config import *
from compute_print_net_out import mesh_transform_by_matrix
from compute_print_net_out import down_sample
from compute_print_net_out import voxel_size
# -------------------------- 开始:运行 ---------------------------------- # -------------------------- 开始:运行 ----------------------------------
def is_run_local_data(): def is_run_local_data():
@ -23,64 +27,6 @@ def is_use_debug_oss():
# -------------------------- 结束:运行 ---------------------------------- # -------------------------- 结束:运行 ----------------------------------
# -------------------------- 开始:模型 ---------------------------------- # -------------------------- 开始:模型 ----------------------------------
def read_mesh(obj_path, enable_post_processing=False):
mesh_obj = o3d.io.read_triangle_mesh(obj_path, enable_post_processing)
return mesh_obj
def down_sample(pcd, voxel_size, farthest_sample = False):
original_num = len(pcd.points)
target_samples = 1500 # 1000
num_samples = min(target_samples, original_num)
# 第一步:使用体素下采样快速减少点数量
# voxel_size = 3
if farthest_sample:
pcd_voxel = pcd.farthest_point_down_sample(num_samples=num_samples)
else:
pcd_voxel = pcd.voxel_down_sample(voxel_size)
down_num = len(pcd_voxel.points)
# print(f"original_num={original_num}, down_num={down_num}")
# 第二步:仅在必要时进行最远点下采样
if len(pcd_voxel.points) > target_samples and False:
pcd_downsampled = pcd_voxel.farthest_point_down_sample(num_samples=num_samples)
else:
pcd_downsampled = pcd_voxel
return pcd_downsampled
def get_volume_centroid(mesh):
"""向量化版本的体积重心计算"""
vertices = np.asarray(mesh.vertices)
triangles = np.asarray(mesh.triangles)
# 一次性获取所有三角形的顶点 [n_triangles, 3, 3]
tri_vertices = vertices[triangles]
# 分别提取三个顶点
v0 = tri_vertices[:, 0, :] # [n, 3]
v1 = tri_vertices[:, 1, :] # [n, 3]
v2 = tri_vertices[:, 2, :] # [n, 3]
# 向量化计算叉积和点积
cross_vec = np.cross(v1, v2) # [n, 3]
dot_results = np.einsum('ij,ij->i', v0, cross_vec) # 批量点积 [n]
# 计算每个四面体体积 [n]
tetra_volumes = np.abs(dot_results) / 6.0
# 计算每个四面体重心 [n, 3]
tetra_centers = (v0 + v1 + v2) / 4.0
# 总体积和加权重心
total_volume = np.sum(tetra_volumes)
if total_volume > 0:
weighted_center = np.sum(tetra_volumes[:, np.newaxis] * tetra_centers, axis=0) / total_volume
return weighted_center
else:
return np.mean(vertices, axis=0)
def mesh_tranform_to_pcd(mesh, transform_matrix): def mesh_tranform_to_pcd(mesh, transform_matrix):
vertices = np.asarray(mesh.vertices) vertices = np.asarray(mesh.vertices)
@ -101,29 +47,6 @@ def mesh_to_pcd(mesh, is_down_sample=True):
return pcd_downsampled return pcd_downsampled
else: else:
return pcd return pcd
def mesh_transform_by_matrix(vertices, transform_matrix):
"""
手动实现网格变换对每个顶点应用齐次变换矩阵
参数:
vertices: 网格顶点数组 (N, 3)
transform_matrix: 4x4 齐次变换矩阵
返回:
变换后的顶点数组 (N, 3)
"""
# 1. 顶点转齐次坐标 (N, 3) → (N, 4)
homogeneous_vertices = np.hstack((vertices, np.ones((vertices.shape[0], 1))))
# 2. 应用变换矩阵:矩阵乘法 (4x4) * (4xN) → (4xN)
transformed_homogeneous = transform_matrix @ homogeneous_vertices.T
# 3. 转回非齐次坐标 (3xN) → (N, 3)
transformed_vertices = transformed_homogeneous[:3, :].T
del homogeneous_vertices
del transformed_homogeneous
return transformed_vertices
import os import os
@ -240,8 +163,6 @@ def transform_save_o3d(layout_data, original_obj_pid_dir):
mesh.compute_vertex_normals() mesh.compute_vertex_normals()
o3d.io.write_triangle_mesh(obj_path_arrange_obj, mesh,write_triangle_uvs=True) o3d.io.write_triangle_mesh(obj_path_arrange_obj, mesh,write_triangle_uvs=True)
voxel_size = 3
def is_multi_obj(obj_name): def is_multi_obj(obj_name):
pattern = r'_x(\d+)' pattern = r'_x(\d+)'
match = re.search(pattern, obj_name) match = re.search(pattern, obj_name)

4
point_cloud_layout.py

@ -11,12 +11,13 @@ from plyfile import PlyData, PlyElement
from general import mesh_tranform_to_pcd from general import mesh_tranform_to_pcd
from general import need_upload_result from general import need_upload_result
from general import read_mesh
from general import extend_dist_min_collision from general import extend_dist_min_collision
from compute_print_net import arrange_models_on_platform from compute_print_net import arrange_models_on_platform
from compute_print_net import compute_bbox_all from compute_print_net import compute_bbox_all
from compute_print_net_out import read_mesh
def make_bbox_for_print(base_original_obj_dir,dict_bad,dict_origin,is_downsample): def make_bbox_for_print(base_original_obj_dir,dict_bad,dict_origin,is_downsample):
"""获取需要的盒子大小""" """获取需要的盒子大小"""
start_time = time.time() start_time = time.time()
@ -61,6 +62,7 @@ def get_dict_pcd(dict_mesh_obj,dict_total_matrix,all_models):
dict_ply_name = {} dict_ply_name = {}
for model in all_models: for model in all_models:
ply_name = model['name'] ply_name = model['name']
# print(f"get_dict_pcd {ply_name.split("=")[0]}.obj, {ply_name}")
dict_ply_name[f"{ply_name.split("=")[0]}.obj"] = ply_name dict_ply_name[f"{ply_name.split("=")[0]}.obj"] = ply_name
dict_pcd_fix = get_pcd_by_matrix(dict_mesh_obj,dict_total_matrix,dict_ply_name) dict_pcd_fix = get_pcd_by_matrix(dict_mesh_obj,dict_total_matrix,dict_ply_name)

56
print_show_weight_max_obj.py

@ -17,7 +17,7 @@ from multiprocessing import Pool, RawArray
import ctypes import ctypes
import itertools import itertools
from compute_print_net import down_sample from compute_print_net_out import down_sample
def make_pcd_plane(): def make_pcd_plane():
# 创建Y=0的平面点云 # 创建Y=0的平面点云
@ -80,57 +80,6 @@ def calculate_rotation_and_center_of_mass(angle_x, angle_y, angle_z, points):
return center_of_mass[2], angle_x, angle_y, angle_z return center_of_mass[2], angle_x, angle_y, angle_z
# def parallel_rotation(points, angle_step=3):
# """并行计算最优旋转角度"""
# # 记录最优结果的初始化
# min_center_of_mass_y = float('inf')
# best_angle_x, best_angle_y, best_angle_z = 0, 0, 0
#
# # 计算每个角度的组合
# angles_x = range(0, 360, angle_step)
# angles_y = range(0, 360, angle_step)
# angles_z = range(0, 360, angle_step)
#
# # 创建一个进程池并行处理
# with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
# results = []
#
# # 提交任务
# for angle_x in angles_x:
# for angle_y in angles_y:
# for angle_z in angles_z:
# results.append(
# pool.apply_async(calculate_rotation_and_center_of_mass, (angle_x, angle_y, angle_z, points)))
#
# # 获取所有结果
# for result in results:
# center_of_mass_z, angle_x, angle_y, angle_z = result.get()
#
# # 更新最优旋转角度
# if center_of_mass_z < min_center_of_mass_y:
# min_center_of_mass_y = center_of_mass_z
# best_angle_x, best_angle_y, best_angle_z = angle_x, angle_y, angle_z
#
# return best_angle_x, best_angle_y, best_angle_z, min_center_of_mass_y
def parallel_rotation(points, angle_step=3):
"""顺序计算最优旋转角度(单线程)"""
min_center_of_mass_y = float('inf')
best_angle_x, best_angle_y, best_angle_z = 0, 0, 0
# 遍历所有角度组合
for angle_x in range(0, 360, angle_step):
for angle_y in range(0, 360, angle_step):
for angle_z in range(0, 360, angle_step):
center_of_mass_z, ax, ay, az = calculate_rotation_and_center_of_mass(
angle_x, angle_y, angle_z, points
)
if center_of_mass_z < min_center_of_mass_y:
min_center_of_mass_y = center_of_mass_z
best_angle_x, best_angle_y, best_angle_z = ax, ay, az
return best_angle_x, best_angle_y, best_angle_z, min_center_of_mass_y
#""" #"""
@njit @njit
def safe_min(arr): def safe_min(arr):
@ -465,9 +414,6 @@ def get_lowest_position_of_center(obj_path,voxel_size,dict_origin,total_matrix):
best_angle_x, best_angle_y, best_angle_z = 0, 0, 0 best_angle_x, best_angle_y, best_angle_z = 0, 0, 0
start_time = time.time() start_time = time.time()
# 旋转并计算最优角度:绕X、Y、Z轴进行每度的旋转 # 旋转并计算最优角度:绕X、Y、Z轴进行每度的旋转
# best_angle_x, best_angle_y, best_angle_z, min_center_of_mass_y = parallel_rotation(points, angle_step=3)
# best_angle_x, best_angle_y, best_angle_z, min_center_of_mass_y = parallel_rotation2(points, angle_step=3)
# best_angle_x, best_angle_y, best_angle_z, min_center_of_mass_y = parallel_rotation3(points, angle_step=3)
best_angle_x, best_angle_y, best_angle_z, min_center_of_mass_y = parallel_rotation4(points, angle_step=3) best_angle_x, best_angle_y, best_angle_z, min_center_of_mass_y = parallel_rotation4(points, angle_step=3)
print("get_lowest_position_of_center", obj_path, best_angle_x,best_angle_y,best_angle_z,"time",time.time()-start_time) print("get_lowest_position_of_center", obj_path, best_angle_x,best_angle_y,best_angle_z,"time",time.time()-start_time)

3
test_load_json.py

@ -10,9 +10,10 @@ from config import print_data_dir
from config import test_print_max from config import test_print_max
from general import mesh_transform_by_matrix from general import mesh_transform_by_matrix
from general import read_mesh
from general import get_blank_path from general import get_blank_path
from compute_print_net_out import read_mesh
def load_and_transform_models(base_path, dict_origin, json_name): def load_and_transform_models(base_path, dict_origin, json_name):
meshes = [] # 存储所有变换后的网格 meshes = [] # 存储所有变换后的网格

Loading…
Cancel
Save