Регулировка (центр и вращение) ориентированной ограничивающей коробки, чтобы наилучшие точки подбораPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Регулировка (центр и вращение) ориентированной ограничивающей коробки, чтобы наилучшие точки подбора

Сообщение Anonymous »

У меня есть 3D -точки от шумного обнаружения одной плоской поверхности. Я хочу установить ориентированную рамку для этих точек. Я приблизительно фильтрую его по интенсивности, чтобы получить только точки близко к краям. Но обнаружение довольно шумно, есть также некоторые поверхности и лидарные шум по краям, так что это делает ориентированную ограничивающую коробку немного смещенной и немного повернутой. < /P>
Я хочу применить процедуру оптимизации. Сдвинуть и повернуть эту оригинальную оценку, чтобы она подходила как можно больше граничных точек. Тем не менее, я испытываю проблемы, создавая такую ​​оптимизацию. Я использую scipy.optimize.minimize , а ограничивающая коробка, кажется, просто случайно только повсюду, с конечным результатом, не соответствующей интересующей структуре, если я использую метод Пауэлла, и просто не перемещаю ограничительную коробку и оставался При исходной оценке, если я использую метод непреднамеренного. Оба случайного шума в структуре + некоторая соседняя структура;

Код: Выделить всё

import open3d as o3d

def generate_noisy_boundary_pcd(center, width, height, depth, margin, noise_level, num_points):
"""
Generate a 3D Open3D point cloud with noisy points only on the boundary of a 3D rectangle.

Args:
center (tuple): Center of the rectangle (x, y, z).
width (float): Width of the rectangle in the X direction.
height (float): Height of the rectangle in the Y direction.
depth (float): Thickness of the rectangle in the Z direction.
margin (float): Thickness of the boundary region to retain.
noise_level (float): Standard deviation of Gaussian noise.
num_points (int): Number of points to generate.

Returns:
open3d.geometry.PointCloud: Open3D point cloud containing only noisy boundary points.
"""
# Generate rectangle points in 3D space
x_vals = np.linspace(-width / 2, width / 2, int(np.sqrt(num_points)))
y_vals = np.linspace(-height / 2, height / 2, int(np.sqrt(num_points)))
x_grid, y_grid = np.meshgrid(x_vals, y_vals)

# Front and back face at ±depth/2
z_front = np.full_like(x_grid, depth / 2)
z_back = np.full_like(x_grid, -depth / 2)

# Create front and back faces
rect_points = np.column_stack((x_grid.ravel(), y_grid.ravel(), z_front.ravel()))

# Filter only boundary points (margin region)
boundary_mask = (
(np.abs(x_grid) >= (width / 2 - margin)) |  # Vertical boundary
(np.abs(y_grid) >= (height / 2 - margin))    # Horizontal boundary
)

boundary_points = rect_points[boundary_mask.ravel()]

# Apply noise
noise = np.random.normal(0, noise_level, boundary_points.shape)
noisy_boundary_points = boundary_points + noise

# Shift to the desired center
noisy_boundary_points += np.array(center)

# Convert to Open3D point cloud
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(noisy_boundary_points)

return pcd

# Generate noisy boundary point cloud
pcd_noisy_boundary = generate_noisy_boundary_pcd(center=(0, 0, 0), width=0.8, height=1.0, depth=0.1, margin=0.1, noise_level=0.02, num_points=500)

# Visualize with Open3D
o3d.visualization.draw_geometries([pcd_noisy_boundary])

def apply_random_shift_and_rotation(obb, max_shift=0.05, max_rotation=np.radians(5)):
"""
Apply a small random shift and rotation to an oriented bounding box.

Args:
obb (o3d.geometry.OrientedBoundingBox): The original oriented bounding box.
max_shift (float): Maximum translation shift in each direction.
max_rotation (float): Maximum rotation in radians for each axis.

Returns:
o3d.geometry.OrientedBoundingBox: The transformed OBB.
"""
# Generate a small random shift
shift = np.random.uniform(-max_shift, max_shift, 3)

# Generate small random rotations around each axis
delta_angle_x = np.random.uniform(-max_rotation, max_rotation)
delta_angle_y = np.random.uniform(-max_rotation, max_rotation)
delta_angle_z = np.random.uniform(-max_rotation, max_rotation)

# Compute the new rotation matrix
delta_Rx = o3d.geometry.get_rotation_matrix_from_xyz((delta_angle_x, 0, 0))
delta_Ry = o3d.geometry.get_rotation_matrix_from_xyz((0, delta_angle_y, 0))
delta_Rz = o3d.geometry.get_rotation_matrix_from_xyz((0, 0, delta_angle_z))

# Apply rotation perturbation on top of existing rotation
R_new = obb.R @ (delta_Rz @ delta_Ry @ delta_Rx)

# Apply translation shift
center_new = obb.center + shift

# Create the transformed OBB
transformed_obb = o3d.geometry.OrientedBoundingBox(center_new, R_new, obb.extent)

return transformed_obb

# Compute the initial oriented bounding box from the noisy boundary point cloud
obb_original = o3d.geometry.OrientedBoundingBox.create_from_points(pcd_noisy_boundary.points)
obb_original.color = (1, 0, 0)  # Red for original

# Apply random shift and rotation
obb_transformed = apply_random_shift_and_rotation(obb_original)
obb_transformed.color = (0, 1, 0)  # Green for transformed

# Visualize both original and transformed bounding boxes
o3d.visualization.draw_geometries([pcd_noisy_with_cluster, obb_original, obb_transformed])
< /code>
Все выше - это просто генерация данных о игрушках.  Ниже приведен код, который я пытаюсь для оптимизации: < /p>
from scipy.optimize import minimize

def fit_obb_to_points(params, pcd, obb, margin=0.1):
"""
Optimize the OBB center and refine its rotation so that it encloses the most points.

Args:
params (list): [cx, cy, cz, delta_angle_x, delta_angle_y, delta_angle_z].
pcd (o3d.geometry.PointCloud): Input 3D point cloud.
obb (o3d.geometry.OrientedBoundingBox): Initial OBB.
expand_factor (float): Factor to expand the bounding box slightly.

Returns:
int: Negative count of points inside the OBB (to be minimized).
"""
# Extract parameters
cx, cy, cz, delta_angle_x, delta_angle_y, delta_angle_z = params
center = np.array([cx, cy, cz])

# Compute refined rotation by applying small delta angles to the existing rotation
delta_Rx = o3d.geometry.get_rotation_matrix_from_xyz((delta_angle_x, 0, 0))
delta_Ry = o3d.geometry.get_rotation_matrix_from_xyz((0, delta_angle_y, 0))
delta_Rz = o3d.geometry.get_rotation_matrix_from_xyz((0, 0, delta_angle_z))

# Apply small rotation adjustments on top of the original OBB rotation
R_new = obb.R @ (delta_Rz @ delta_Ry @ delta_Rx)

expanded_obb = o3d.geometry.OrientedBoundingBox(center, R_new, [obb.extent[0] + margin, obb.extent[1] + margin, obb.extent[2]])

o3d.visualization.draw_geometries([expanded_obb, pcd])

# Count inliers inside both bounding boxes
inliers_large = expanded_obb.get_point_indices_within_bounding_box(pcd.points)

# Compute number of boundary inliers
boundary_inliers = len(inliers_large)
print(boundary_inliers)
return -boundary_inliers

def optimize_bounding_box(pcd, initial_obb):
"""
Adjusts the center and fine-tunes the rotation of the OBB so that it fits as many points as possible.

Args:
pcd (o3d.geometry.PointCloud): The point cloud.
initial_obb (o3d.geometry.OrientedBoundingBox): Initial bounding box (rotation should be preserved).

Returns:
o3d.geometry.OrientedBoundingBox: Optimized OBB.
"""
# Initial parameters: [center_x, center_y, center_z, delta_angle_x, delta_angle_y, delta_angle_z]
initial_params = [
*initial_obb.center,
0, 0, 0  # Start with no change to rotation
]

# Optimize the bounding box parameters
result = minimize(
fit_obb_to_points, initial_params,
args=(pcd, initial_obb),
# method="Powell"
)

# Extract optimized parameters
optimized_center = np.array(result.x[:3])
delta_angles = result.x[3:]

# Compute the final refined rotation
delta_Rx = o3d.geometry.get_rotation_matrix_from_xyz((delta_angles[0], 0, 0))
delta_Ry = o3d.geometry.get_rotation_matrix_from_xyz((0, delta_angles[1], 0))
delta_Rz = o3d.geometry.get_rotation_matrix_from_xyz((0, 0, delta_angles[2]))
optimized_rotation = initial_obb.R @ (delta_Rz @ delta_Ry @ delta_Rx)

# Create the final optimized OBB
optimized_obb = o3d.geometry.OrientedBoundingBox(optimized_center, optimized_rotation, initial_obb.extent)

return optimized_obb

optimized_obb = optimize_bounding_box(pcd_noisy_with_cluster, obb_transformed)
obb_transformed.color = (255, 0, 0)
optimized_obb.color = (0, 255, 0)
o3d.visualization.draw_geometries([pcd_noisy_with_cluster, obb_transformed, optimized_obb])
Если вы оставите o3d.visualization.draw_geometries ([expedicated_obb, pcd]) Как это происходит в коде оптимизации, вы увидите, что любое ограничительное поле сильно прыгает, Иногда даже полностью от любых точек (метод Пауэлла) или просто застрял для метода, не являющегося беремейным, < /p>
кажется ясным, что этот метод на самом деле не подходит. Но я не могу придумать какую -то альтернативу. На 2D -изображении я бы применил некоторые методы поиска контуров, но я не могу найти что -то для 3D -точек. Конечно, есть методы обнаружения плоскости в Open3d , но именно от этого я получаю свою первоначальную непроблемную оценку от. Однако я хочу найти какой -то метод для уточнения оценки на основе того, что было обнаружено, которые были обнаружены с помощью методов Open3d < /code>. < /P>

Можно ли исправить подход Я использую?>

Подробнее здесь: https://stackoverflow.com/questions/793 ... fit-points
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»