196 lines
5.7 KiB
Python
196 lines
5.7 KiB
Python
|
|
import numpy as np
|
|
import open3d as o3d
|
|
from sklearn.cluster import KMeans
|
|
|
|
|
|
def transform_points(points, transform_matrix):
|
|
# 确保输入的点是一个 Nx3 的数组
|
|
assert points.shape[1] == 3, "输入的点必须是 Nx3 的数组"
|
|
assert transform_matrix.shape == (4, 4), "变换矩阵必须是 4x4 的"
|
|
|
|
# 将点扩展为齐次坐标 (N x 4)
|
|
ones = np.ones((points.shape[0], 1))
|
|
points_homogeneous = np.hstack((points, ones))
|
|
|
|
# 应用变换矩阵
|
|
transformed_points_homogeneous = points_homogeneous @ transform_matrix.T
|
|
|
|
# 转换回非齐次坐标 (N x 3)
|
|
transformed_points = transformed_points_homogeneous[:, :3]
|
|
|
|
return transformed_points
|
|
|
|
|
|
|
|
|
|
def random_point(points,num):
|
|
# 随机选择三个不同的点
|
|
random_indices = np.random.choice(points.shape[0], num, replace=False)
|
|
random_points = points[random_indices]
|
|
|
|
# 计算选中点坐标的均值
|
|
x_mean = np.mean(random_points[:, 0])
|
|
y_mean = np.mean(random_points[:, 1])
|
|
z_mean = np.mean(random_points[:, 2])
|
|
selected_points = np.array([x_mean, y_mean, z_mean])
|
|
return selected_points
|
|
|
|
|
|
def farthest_point_sampling(pc, num_points):
|
|
"""
|
|
Given a point cloud, sample num_points points that are the farthest apart.
|
|
Use o3d the farthest point sampling.
|
|
"""
|
|
assert pc.ndim == 2 and pc.shape[1] == 3, "pc must be a (N, 3) numpy array"
|
|
pcd = o3d.geometry.PointCloud()
|
|
pcd.points = o3d.utility.Vector3dVector(pc)
|
|
downpcd_farthest = pcd.farthest_point_down_sample(num_points)
|
|
return np.asarray(downpcd_farthest.points)
|
|
|
|
|
|
|
|
|
|
def get_bott_up_point(points,obj_size,descending,):
|
|
|
|
# 按照 Z 值从小到大排序
|
|
ascending_indices = np.argsort(points[:, 2])
|
|
if descending:
|
|
# 反转索引实现降序
|
|
ascending_indices = ascending_indices[::-1]
|
|
sorted_points = points[ascending_indices]
|
|
# print("sorted_points",sorted_points)
|
|
threshold = 0.03* obj_size
|
|
z_m = sorted_points[0][-1] #
|
|
while True:
|
|
top_surface_points = sorted_points[np.abs(sorted_points[:, 2] - z_m) < threshold]
|
|
if len(top_surface_points) >= 15:
|
|
break
|
|
# 增加阈值以获取更多点
|
|
threshold += 0.01 * obj_size
|
|
# 获取顶部/底部表面的点
|
|
top_surface_points = sorted_points[np.abs(sorted_points[:, 2] - z_m) < threshold]
|
|
# print("sorted_points",len(top_surface_points))
|
|
|
|
# # 使用 KMeans 进行聚类,以保证点的均匀分布
|
|
kmeans = KMeans(n_clusters=10)
|
|
kmeans.fit(top_surface_points[:, :2]) # 仅使用 X 和 Y 坐标进行聚类
|
|
# 获取每个聚类中心最近的点
|
|
centers = kmeans.cluster_centers_
|
|
selected_points = []
|
|
|
|
for center in centers:
|
|
# 计算每个中心点到所有点的距离
|
|
distances = np.linalg.norm(top_surface_points[:, :2] - center, axis=1)
|
|
# 找到最近的点
|
|
closest_point_idx = np.argmin(distances)
|
|
selected_points.append(top_surface_points[closest_point_idx])
|
|
selected_points = np.array(selected_points)
|
|
selected_points[:, 2] = z_m
|
|
# modify
|
|
return selected_points
|
|
|
|
|
|
# ===============================================
|
|
# = optimization utils
|
|
# ===============================================
|
|
def normalize_vars(vars, og_bounds):
|
|
"""
|
|
Given 1D variables and bounds, normalize the variables to [-1, 1] range.
|
|
"""
|
|
normalized_vars = np.empty_like(vars)
|
|
for i, (b_min, b_max) in enumerate(og_bounds):
|
|
if b_max != b_min:
|
|
normalized_vars[i] = (vars[i] - b_min) / (b_max - b_min) * 2 - 1
|
|
else:
|
|
# 处理 b_max 等于 b_min 的情况
|
|
normalized_vars[i] = 0 # 或者其他合适的默认值
|
|
return normalized_vars
|
|
|
|
|
|
def unnormalize_vars(normalized_vars, og_bounds):
|
|
"""
|
|
Given 1D variables in [-1, 1] and original bounds, denormalize the variables to the original range.
|
|
"""
|
|
vars = np.empty_like(normalized_vars)
|
|
# import pdb;pdb.set_trace()
|
|
for i, (b_min, b_max) in enumerate(og_bounds):
|
|
vars[i] = (normalized_vars[i] + 1) / 2.0 * (b_max - b_min) + b_min
|
|
return vars
|
|
|
|
|
|
def euler2quat(euler):
|
|
"""
|
|
Converts euler angles into quaternion form
|
|
|
|
Args:
|
|
euler (np.array): (r,p,y) angles
|
|
|
|
Returns:
|
|
np.array: (x,y,z,w) float quaternion angles
|
|
|
|
Raises:
|
|
AssertionError: [Invalid input shape]
|
|
"""
|
|
return R.from_euler("xyz", euler).as_quat()
|
|
|
|
|
|
def quat2euler(quat):
|
|
"""
|
|
Converts euler angles into quaternion form
|
|
|
|
Args:
|
|
quat (np.array): (x,y,z,w) float quaternion angles
|
|
|
|
Returns:
|
|
np.array: (r,p,y) angles
|
|
|
|
Raises:
|
|
AssertionError: [Invalid input shape]
|
|
"""
|
|
return R.from_quat(quat).as_euler("xyz")
|
|
|
|
|
|
def quat2mat(quaternion):
|
|
"""
|
|
Converts given quaternion to matrix.
|
|
|
|
Args:
|
|
quaternion (np.array): (..., 4) (x,y,z,w) float quaternion angles
|
|
|
|
Returns:
|
|
np.array: (..., 3, 3) rotation matrix
|
|
"""
|
|
return R.from_quat(quaternion).as_matrix()
|
|
|
|
|
|
def pose2mat(pose):
|
|
"""
|
|
Converts pose to homogeneous matrix.
|
|
|
|
Args:
|
|
pose (2-tuple): a (pos, orn) tuple where pos is vec3 float cartesian, and
|
|
orn is vec4 float quaternion.
|
|
|
|
Returns:
|
|
np.array: 4x4 homogeneous matrix
|
|
"""
|
|
|
|
if isinstance(pose[0], np.ndarray):
|
|
translation = pose[0]
|
|
else:
|
|
raise TypeError("Unsupported data type for translation")
|
|
|
|
if isinstance(pose[1], np.ndarray):
|
|
quaternion = pose[1]
|
|
else:
|
|
raise TypeError("Unsupported data type for quaternion")
|
|
|
|
homo_pose_mat = np.zeros((4, 4), dtype=translation.dtype)
|
|
homo_pose_mat[:3, :3] = quat2mat(quaternion)
|
|
homo_pose_mat[:3, 3] = translation
|
|
homo_pose_mat[3, 3] = 1.0
|
|
|
|
return homo_pose_mat
|
|
|