5 changed files with 52 additions and 782 deletions
@ -1,754 +0,0 @@
@@ -1,754 +0,0 @@
|
||||
import os.path |
||||
import shutil |
||||
|
||||
import open3d as o3d |
||||
import numpy as np |
||||
import copy |
||||
from tqdm import tqdm |
||||
import time |
||||
import multiprocessing |
||||
import oss2 |
||||
from joblib import Parallel, delayed |
||||
import itertools |
||||
from numba import njit, prange |
||||
#import bpy |
||||
from plyfile import PlyData, PlyElement |
||||
from multiprocessing import Pool, RawArray |
||||
import ctypes |
||||
import itertools |
||||
|
||||
from compute_print_net_out import down_sample |
||||
|
||||
def make_pcd_plane(): |
||||
# 创建Y=0的平面点云 |
||||
width = 60.0 # 平面的宽度 |
||||
height = 60.0 # 平面的高度 |
||||
resolution = 50 # 点云的分辨率,越高越密集 |
||||
|
||||
# 生成平面点云 |
||||
x = np.linspace(-width / 2, width / 2, resolution) |
||||
y = np.linspace(-height / 2, height / 2, resolution) |
||||
xv, yv = np.meshgrid(x, y) |
||||
zv = np.zeros_like(xv) # Y 坐标恒为 0 |
||||
|
||||
# 将网格转换为点云的顶点数组 |
||||
points_plane = np.vstack((xv.flatten(), yv.flatten(), zv.flatten())).T |
||||
|
||||
# 创建Open3D点云对象 |
||||
pcd_plane = o3d.geometry.PointCloud() |
||||
pcd_plane.points = o3d.utility.Vector3dVector(points_plane) |
||||
pcd_plane.paint_uniform_color([0, 1, 0]) |
||||
return pcd_plane |
||||
|
||||
|
||||
def calculate_rotation_and_center_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 |
||||
|
||||
# 计算重心 |
||||
center_of_mass = np.mean(rotated_points, axis=0) |
||||
|
||||
return center_of_mass[2], angle_x, angle_y, angle_z |
||||
|
||||
#""" |
||||
@njit |
||||
def safe_min(arr): |
||||
if arr.size == 0: |
||||
return np.inf |
||||
return np.min(arr) |
||||
|
||||
# 核心计算函数(支持Numba加速) |
||||
@njit(fastmath=True, cache=True) |
||||
def calculate_rotation_z(angle_x, angle_y, angle_z, points, cos_cache, sin_cache, angle_step): |
||||
#计算单个旋转组合后的重心Z坐标(无显式平移) |
||||
|
||||
if points.shape[0] == 0: |
||||
return np.inf # 返回极大值避免干扰最优解 |
||||
|
||||
# 获取预计算的三角函数值 |
||||
idx_x = angle_x // angle_step |
||||
idx_y = angle_y // angle_step |
||||
idx_z = angle_z // angle_step |
||||
|
||||
cos_x = cos_cache[idx_x] |
||||
sin_x = sin_cache[idx_x] |
||||
cos_y = cos_cache[idx_y] |
||||
sin_y = sin_cache[idx_y] |
||||
cos_z = cos_cache[idx_z] |
||||
sin_z = sin_cache[idx_z] |
||||
|
||||
# 构造旋转矩阵(展开矩阵乘法优化) |
||||
# R = Rz @ Ry @ Rx |
||||
# 计算矩阵元素(手动展开矩阵乘法) |
||||
m00 = cos_z * cos_y |
||||
m01 = cos_z * sin_y * sin_x - sin_z * cos_x |
||||
m02 = cos_z * sin_y * cos_x + sin_z * sin_x |
||||
|
||||
m10 = sin_z * cos_y |
||||
m11 = sin_z * sin_y * sin_x + cos_z * cos_x |
||||
m12 = sin_z * sin_y * cos_x - cos_z * sin_x |
||||
|
||||
m20 = -sin_y |
||||
m21 = cos_y * sin_x |
||||
m22 = cos_y * cos_x |
||||
|
||||
# 计算所有点的Z坐标 |
||||
z_values = np.empty(points.shape[0], dtype=np.float64) |
||||
for i in prange(points.shape[0]): |
||||
x, y, z = points[i, 0], points[i, 1], points[i, 2] |
||||
# 应用旋转矩阵 |
||||
rotated_z = m20 * x + m21 * y + m22 * z |
||||
z_values[i] = rotated_z |
||||
|
||||
# 计算重心Z(等效于平移后的重心) |
||||
# min_z = np.min(z_values) |
||||
min_z = safe_min(z_values) |
||||
avg_z = np.mean(z_values) |
||||
return avg_z - min_z # 等效于平移后的重心Z坐标 |
||||
|
||||
@njit(parallel=True, fastmath=True) |
||||
def _process_batch(batch, points, cos_cache, sin_cache, angle_step, results): |
||||
for i in prange(len(batch)): |
||||
ax, ay, az = batch[i] |
||||
results[i] = calculate_rotation_z( |
||||
ax, ay, az, points, |
||||
cos_cache, sin_cache, angle_step |
||||
) |
||||
|
||||
|
||||
def parallel_rotation2(points, angle_step=3): |
||||
|
||||
#参数: |
||||
#points : numpy.ndarray (N,3) - 三维点云 |
||||
#angle_step : int - 角度搜索步长(度数) |
||||
|
||||
#返回: |
||||
#(best_angle_x, best_angle_y, best_angle_z, min_z) |
||||
|
||||
points_np = np.asarray(points) |
||||
points_float64 = points_np.astype(np.float64) |
||||
points = np.ascontiguousarray(points_float64) |
||||
|
||||
# points = np.ascontiguousarray(points.astype(np.float64)) |
||||
|
||||
# 生成所有可能角度 |
||||
angles = np.arange(0, 360, angle_step) |
||||
n_angles = len(angles) |
||||
|
||||
# 预计算三角函数值(大幅减少重复计算) |
||||
rads = np.radians(angles) |
||||
cos_cache = np.cos(rads).astype(np.float64) |
||||
sin_cache = np.sin(rads).astype(np.float64) |
||||
|
||||
# 生成所有角度组合(内存优化版) |
||||
total_combinations = n_angles ** 3 |
||||
# print(f"Total combinations: {total_combinations:,}") |
||||
|
||||
# 分块处理以避免内存溢出 |
||||
best_z = np.inf |
||||
best_angles = (0, 0, 0) |
||||
batch_size = 10 ** 6 # 根据可用内存调整 |
||||
|
||||
for x_chunk in range(0, n_angles, max(1, n_angles // 4)): |
||||
angles_x = angles[x_chunk:x_chunk + max(1, n_angles // 4)] |
||||
for y_chunk in range(0, n_angles, max(1, n_angles // 4)): |
||||
angles_y = angles[y_chunk:y_chunk + max(1, n_angles // 4)] |
||||
|
||||
# 生成当前分块的所有组合 |
||||
xx, yy, zz = np.meshgrid(angles_x, angles_y, angles) |
||||
current_batch = np.stack([xx.ravel(), yy.ravel(), zz.ravel()], axis=1) |
||||
|
||||
# 处理子批次 |
||||
for i in range(0, len(current_batch), batch_size): |
||||
batch = current_batch[i:i + batch_size] |
||||
results = np.zeros(len(batch), dtype=np.float64) |
||||
_process_batch(batch, points, cos_cache, sin_cache, angle_step, results) |
||||
|
||||
# 更新最佳结果 |
||||
min_idx = np.argmin(results) |
||||
if results[min_idx] < best_z: |
||||
best_z = results[min_idx] |
||||
best_angles = tuple(batch[min_idx]) |
||||
# print(f"New best: {best_angles} -> Z={best_z:.4f}") |
||||
|
||||
return (*best_angles, best_z) |
||||
#""" |
||||
|
||||
#""" |
||||
def rotate_x(angle): |
||||
theta = np.radians(angle) |
||||
return np.array([ |
||||
[1, 0, 0], |
||||
[0, np.cos(theta), -np.sin(theta)], |
||||
[0, np.sin(theta), np.cos(theta)] |
||||
]) |
||||
|
||||
def rotate_y(angle): |
||||
theta = np.radians(angle) |
||||
return np.array([ |
||||
[np.cos(theta), 0, np.sin(theta)], |
||||
[0, 1, 0], |
||||
[-np.sin(theta), 0, np.cos(theta)] |
||||
]) |
||||
|
||||
def rotate_z(angle): |
||||
theta = np.radians(angle) |
||||
return np.array([ |
||||
[np.cos(theta), -np.sin(theta), 0], |
||||
[np.sin(theta), np.cos(theta), 0], |
||||
[0, 0, 1] |
||||
]) |
||||
|
||||
def compute_z_height_and_center(rotated_points): |
||||
z_min, z_max = rotated_points[:, 2].min(), rotated_points[:, 2].max() |
||||
y_min, y_max = rotated_points[:, 1].min(), rotated_points[:, 1].max() |
||||
return (z_max - z_min), (y_min + y_max) / 2 |
||||
|
||||
def init_worker(shared_array, shape, dtype): |
||||
global global_points |
||||
global_points = np.frombuffer(shared_array, dtype=dtype).reshape(shape) |
||||
|
||||
def compute_rotation(args): |
||||
angle_x, angle_y, angle_z = args |
||||
R = rotate_z(angle_z) @ rotate_y(angle_y) @ rotate_x(angle_x) |
||||
rotated_points = global_points @ R.T |
||||
z_height, center_y = compute_z_height_and_center(rotated_points) |
||||
return (angle_x, angle_y, angle_z, z_height, center_y) |
||||
|
||||
def parallel_rotation3(points, angle_step=5): |
||||
# 生成所有旋转角度组合 |
||||
angles = itertools.product( |
||||
np.arange(0, 360, angle_step), |
||||
np.arange(0, 360, angle_step), |
||||
np.arange(0, 360, angle_step) |
||||
) |
||||
|
||||
# 共享内存初始化 |
||||
shape, dtype = points.shape, points.dtype |
||||
shared_array = RawArray(ctypes.c_double, points.size) |
||||
shared_points = np.frombuffer(shared_array, dtype=dtype).reshape(shape) |
||||
np.copyto(shared_points, points) |
||||
|
||||
# 多进程计算 |
||||
with Pool(initializer=init_worker, initargs=(shared_array, shape, dtype)) as pool: |
||||
results = pool.imap_unordered(compute_rotation, angles, chunksize=100) |
||||
|
||||
# 寻找最优解 |
||||
best_angle = (0, 0, 0) |
||||
min_z_height = float('inf') |
||||
min_center_y = 0 |
||||
for result in results: |
||||
if result[3] < min_z_height: |
||||
best_angle = result[:3] |
||||
min_z_height = result[3] |
||||
min_center_y = result[4] |
||||
|
||||
return (*best_angle, min_center_y) |
||||
#""" |
||||
|
||||
#""" |
||||
def parallel_rotation4(points, angle_step=4): |
||||
"""仅绕 Y 轴旋转(假设 X/Z 轴不影响目标函数)""" |
||||
min_center = float('inf') |
||||
best_angle = 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 |
||||
|
||||
""" |
||||
#""" |
||||
for angle_x in range(-45, 45, angle_step): |
||||
for angle_y in range(0, 360, angle_step): |
||||
center_z, ax, ay, _ = calculate_rotation_and_center_of_mass(angle_x, angle_y, 0, points) |
||||
if center_z < min_center: |
||||
min_center = center_z |
||||
best_angle_x = ax |
||||
best_angle_y = ay |
||||
#""" |
||||
return (best_angle_x, best_angle_y, 0, min_center) |
||||
|
||||
#""" |
||||
|
||||
def compute_mesh_center(vertices): |
||||
""" |
||||
计算网格质心 |
||||
|
||||
参数: |
||||
vertices: 顶点坐标数组,形状为(N, 3)的NumPy数组或列表 |
||||
|
||||
返回: |
||||
centroid: 质心坐标的NumPy数组 [x, y, z] |
||||
""" |
||||
if len(vertices) == 0: |
||||
raise ValueError("顶点数组不能为空") |
||||
|
||||
n = len(vertices) # 顶点数量 |
||||
# 初始化坐标累加器 |
||||
sum_x, sum_y, sum_z = 0.0, 0.0, 0.0 |
||||
|
||||
# 遍历所有顶点累加坐标值 |
||||
for vertex in vertices: |
||||
sum_x += vertex[0] |
||||
sum_y += vertex[1] |
||||
sum_z += vertex[2] |
||||
|
||||
# 计算各坐标轴的平均值 |
||||
centroid = np.array([sum_x / n, sum_y / n, sum_z / n]) |
||||
return centroid |
||||
|
||||
def get_lowest_position_of_center(obj_path,voxel_size,dict_origin,total_matrix): |
||||
|
||||
mesh_obj = read_mesh(obj_path) |
||||
dict_origin[obj_path] = mesh_obj |
||||
# dict_origin[obj_path] = copy.deepcopy(mesh_obj) |
||||
|
||||
#o3d.visualization.draw_geometries([mesh_obj]) |
||||
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: {obj_path}") |
||||
return None |
||||
|
||||
pcd = o3d.geometry.PointCloud() |
||||
pcd.points = o3d.utility.Vector3dVector(vertices) |
||||
# o3d.visualization.draw_geometries([pcd]) |
||||
# pcd = o3d.io.read_point_cloud(ply_file_path) |
||||
|
||||
# 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) |
||||
|
||||
# 确保下采样后有点云 |
||||
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的值 |
||||
min_center_of_mass_y = float('inf') |
||||
best_angle_x, best_angle_y, best_angle_z = 0, 0, 0 |
||||
start_time = time.time() |
||||
# 旋转并计算最优角度:绕X、Y、Z轴进行每度的旋转 |
||||
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) |
||||
|
||||
""" |
||||
# if best_angle_x >= 180: |
||||
if best_angle_x >= 155 and best_angle_x <= 325: |
||||
best_angle_x += 180 |
||||
if best_angle_y >= 180: |
||||
best_angle_y += 180 |
||||
if best_angle_z >= 180: |
||||
best_angle_z += 180 |
||||
#""" |
||||
|
||||
# 记录结束时间 |
||||
end_time = time.time() |
||||
elapsed_time = end_time - start_time |
||||
# print(f"Time taken: {elapsed_time:.2f} seconds") |
||||
# 输出最佳的旋转角度 |
||||
# print(f"Best Rotation Angles: angle_x = {best_angle_x}, angle_y = {best_angle_y}, angle_z = {best_angle_z}") |
||||
# print(f"Minimum Y Center of Mass: {min_center_of_mass_y}") |
||||
#time.sleep(1000) |
||||
|
||||
# 使用最佳角度进行旋转并平移obj |
||||
pcd_transformed = copy.deepcopy(mesh_obj) |
||||
#""" |
||||
center = pcd_transformed.get_center() |
||||
#arrow = o3d.geometry.TriangleMesh.create_arrow(0.05, 0.1) |
||||
#arrow.translate(center) |
||||
#o3d.visualization.draw_geometries([pcd_transformed, arrow]) |
||||
|
||||
# 最佳角度旋转 |
||||
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) |
||||
|
||||
# centroid = pcd.get_center() |
||||
centroid = pcd_transformed.get_center() |
||||
# z_mean1 = centroid[2] |
||||
|
||||
T_x = np.eye(4) |
||||
T_x[:3, :3] = R_x |
||||
aabb = pcd_transformed.get_axis_aligned_bounding_box() |
||||
# center_point = aabb.get_center() |
||||
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 |
||||
aabb = pcd_transformed.get_axis_aligned_bounding_box() |
||||
# center_point = aabb.get_center() |
||||
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 |
||||
aabb = pcd_transformed.get_axis_aligned_bounding_box() |
||||
# center_point = aabb.get_center() |
||||
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 |
||||
|
||||
#arrow = o3d.geometry.TriangleMesh.create_arrow(0.05, 0.1) |
||||
#arrow.translate(center) |
||||
#o3d.visualization.draw_geometries([pcd_transformed, arrow]) |
||||
#""" |
||||
|
||||
#""" |
||||
#试着旋转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]) |
||||
|
||||
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) |
||||
centroid = pcd_transformed.get_center() |
||||
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]) |
||||
|
||||
# centroid = pcd.get_center() |
||||
centroid = pcd_transformed.get_center() |
||||
# z_mean2 = centroid[2] |
||||
|
||||
# |
||||
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]) |
||||
|
||||
# print("z_mean",z_mean1,z_mean2,len(pcd_transformed.vertices),obj_path) |
||||
|
||||
if (z_mean2 > z_mean1): |
||||
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 |
||||
|
||||
translation = total_matrix[:3, 3] |
||||
# print(3,translation) |
||||
|
||||
return pcd_transformed, total_matrix |
||||
|
||||
def axis_angle_to_rotation_matrix(axis, angle): |
||||
"""手动生成旋转矩阵""" |
||||
axis = axis / np.linalg.norm(axis) # 单位化 |
||||
cos_a = np.cos(angle) |
||||
sin_a = np.sin(angle) |
||||
return np.array([ |
||||
[cos_a + axis[0]**2*(1-cos_a), |
||||
axis[0]*axis[1]*(1-cos_a) - axis[2]*sin_a, |
||||
axis[0]*axis[2]*(1-cos_a) + axis[1]*sin_a], |
||||
[axis[1]*axis[0]*(1-cos_a) + axis[2]*sin_a, |
||||
cos_a + axis[1]**2*(1-cos_a), |
||||
axis[1]*axis[2]*(1-cos_a) - axis[0]*sin_a], |
||||
[axis[2]*axis[0]*(1-cos_a) - axis[1]*sin_a, |
||||
axis[2]*axis[1]*(1-cos_a) + axis[0]*sin_a, |
||||
cos_a + axis[2]**2*(1-cos_a)] |
||||
]) |
||||
|
||||
def load_obj_data(get_pid,base_out_dir): |
||||
"""下载obj文件""" |
||||
access_key_id = os.getenv('OSS_TEST_ACCESS_KEY_ID', 'LTAI5tBWbfkZntfJij4Fg9gz') |
||||
access_key_secret = os.getenv('OSS_TEST_ACCESS_KEY_SECRET', 'sYDps1i9NSge6hn130EgpPJezKM6Gx') |
||||
bucket_name = os.getenv('OSS_TEST_BUCKET', 'suwa3d-securedata') |
||||
endpoint = os.getenv('OSS_TEST_ENDPOINT', 'https://oss-cn-shanghai.aliyuncs.com') |
||||
bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name) |
||||
# if not os.path.exists(base_out_dir): |
||||
# os.makedirs(base_out_dir) |
||||
prefix = f"objs/print/{get_pid}/" |
||||
out_pid_dir = os.path.join(base_out_dir,str(get_pid)) |
||||
for obj in oss2.ObjectIterator(bucket, prefix=prefix): |
||||
# 如果迭代器至少返回一个对象,那么表示该"文件夹"存在 |
||||
if not os.path.exists(out_pid_dir): |
||||
os.makedirs(out_pid_dir) |
||||
#print("Folder exists.") |
||||
filename = obj.key[len(prefix):] |
||||
if get_pid not in filename: |
||||
continue |
||||
print("获取的文件名称",filename) |
||||
local_path = os.path.join(out_pid_dir, filename) |
||||
# 下载对象到本地文件 |
||||
try: |
||||
bucket.get_object_to_file(obj.key, local_path) |
||||
print(f"Downloaded {obj.key} to {local_path}") |
||||
except: |
||||
print("下载错误",get_pid) |
||||
record_text = "./error_load.txt" |
||||
with open(record_text, 'a') as f: |
||||
f.write(get_pid + '\n') |
||||
|
||||
else: |
||||
# 如果迭代器没有返回任何对象,那么表示该"文件夹"不存在 |
||||
print("ossFolder does not exist.",get_pid) |
||||
|
||||
import re |
||||
def copy_obj_2x(base_obj_dir): |
||||
obj_list = [aa for aa in os.listdir(base_obj_dir) if aa.endswith(".obj")] |
||||
for obj_name in obj_list: |
||||
if "_F" in obj_name: |
||||
continue |
||||
obj_count = obj_name.split("x")[-1].replace(".obj","") |
||||
if not obj_count.isnumeric(): |
||||
match = re.search(r"x(\d+)", obj_name) |
||||
if match: |
||||
obj_count = match.group(1) |
||||
else: |
||||
print("未找到 x 后的数字") |
||||
|
||||
obj_count_num = int(obj_count) |
||||
if obj_count_num!=1: |
||||
for i in range(obj_count_num-1): |
||||
origin_path = os.path.join(base_obj_dir,obj_name) |
||||
dis_path = os.path.join(base_obj_dir,obj_name.replace(".obj",f"_F{i+1}.obj")) |
||||
if not os.path.exists(dis_path): |
||||
shutil.copy(origin_path,dis_path) |
||||
print(dis_path,"复制成功") |
||||
|
||||
def save_mesh_with_blender(obj_transformed, obj_path, apply_transform=True): |
||||
# o3d.io.write_triangle_mesh(obj_path, obj_transformed,write_triangle_uvs=True) |
||||
# return |
||||
"""使用 Blender 导出变换后的网格""" |
||||
# 创建新网格对象 |
||||
mesh = bpy.data.meshes.new("TempMesh") |
||||
mesh.from_pydata( |
||||
np.asarray(obj_transformed.vertices), |
||||
[], |
||||
np.asarray(obj_transformed.triangles).tolist() |
||||
) |
||||
obj = bpy.data.objects.new("TempObject", mesh) |
||||
|
||||
# 链接到场景 |
||||
bpy.context.collection.objects.link(obj) |
||||
|
||||
# 设置上下文 |
||||
original_selection = bpy.context.selected_objects.copy() |
||||
original_active = bpy.context.view_layer.objects.active |
||||
bpy.ops.object.select_all(action='DESELECT') |
||||
obj.select_set(True) |
||||
bpy.context.view_layer.objects.active = obj |
||||
|
||||
# 应用变换 |
||||
if apply_transform: |
||||
bpy.ops.object.transform_apply( |
||||
location=True, |
||||
rotation=True, |
||||
scale=True |
||||
) |
||||
|
||||
# 配置导出参数 |
||||
export_settings = { |
||||
'filepath': obj_path, |
||||
'export_selected_objects': True, |
||||
'export_triangulated_mesh': True, |
||||
'forward_axis': 'Y', |
||||
'up_axis': 'Z', |
||||
'global_scale': 1.0 |
||||
} |
||||
|
||||
# 执行导出 |
||||
try: |
||||
bpy.ops.wm.obj_export(**export_settings) |
||||
finally: |
||||
# 清理临时对象 |
||||
bpy.data.objects.remove(obj, do_unlink=True) |
||||
bpy.data.meshes.remove(mesh) |
||||
|
||||
# 恢复原始上下文 |
||||
bpy.ops.object.select_all(action='DESELECT') |
||||
for o in original_selection: |
||||
o.select_set(True) |
||||
bpy.context.view_layer.objects.active = original_active |
||||
|
||||
if __name__ == '__main__': |
||||
out_dir = "/data/datasets_20t/type_setting_test_data/" |
||||
base_out_dir = f"{out_dir}/8/" |
||||
weight_fix_out_dir = f"{out_dir}/print_weight_fix_data_obj" |
||||
weight_fix_out_ply_dir = f"{out_dir}/print_weight_fix_data_ply" |
||||
copy_obj_2x(base_out_dir) |
||||
Loading…
Reference in new issue