Spaces:
Running on Zero
Running on Zero
Promote inference helpers to public API
Browse files- app.py +28 -29
- infer.py +56 -53
- instruct_particulate/utils/inference_utils.py +7 -3
- instruct_particulate/utils/inference_visualization_utils.py +2 -1
app.py
CHANGED
|
@@ -43,17 +43,18 @@ except ImportError:
|
|
| 43 |
spaces = None
|
| 44 |
|
| 45 |
from infer import (
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
|
|
|
| 57 |
)
|
| 58 |
from instruct_particulate.model import Particulate2ArticulationModel
|
| 59 |
from instruct_particulate.utils.auto_kinematics_utils import (
|
|
@@ -2860,7 +2861,7 @@ def _up_dir_slug(up_dir: str) -> str:
|
|
| 2860 |
return up_dir.replace("+", "pos").replace("-", "neg")
|
| 2861 |
|
| 2862 |
|
| 2863 |
-
def
|
| 2864 |
from PIL import Image, ImageDraw, ImageFont
|
| 2865 |
|
| 2866 |
placeholder_path = OUTPUT_ROOT / "_ui" / "upright_orientation_rendering.png"
|
|
@@ -2891,11 +2892,11 @@ def _upright_rendering_gallery_item() -> list[tuple[str, str]]:
|
|
| 2891 |
font=small_font,
|
| 2892 |
)
|
| 2893 |
image.save(placeholder_path)
|
| 2894 |
-
return
|
| 2895 |
|
| 2896 |
|
| 2897 |
def _upright_rendering_preview_paths() -> list[str]:
|
| 2898 |
-
placeholder_path =
|
| 2899 |
return [placeholder_path for _ in UP_DIR_CHOICES]
|
| 2900 |
|
| 2901 |
|
|
@@ -4052,8 +4053,8 @@ class InstructParticulateApp:
|
|
| 4052 |
.numpy()
|
| 4053 |
.astype(np.int32)
|
| 4054 |
)
|
| 4055 |
-
query_points =
|
| 4056 |
-
query_normals =
|
| 4057 |
batch["query_point_normals"][0],
|
| 4058 |
dtype=np.float32,
|
| 4059 |
)
|
|
@@ -4130,7 +4131,7 @@ class InstructParticulateApp:
|
|
| 4130 |
]
|
| 4131 |
batch = payload["batch"]
|
| 4132 |
visualization_link_point_prompts_world, visualization_link_point_prompt_ids = (
|
| 4133 |
-
|
| 4134 |
args=args,
|
| 4135 |
batch=batch,
|
| 4136 |
links=links_for_query_visualization,
|
|
@@ -4144,7 +4145,7 @@ class InstructParticulateApp:
|
|
| 4144 |
query_face_indices = np.asarray(payload["query_face_indices"], dtype=np.int64)
|
| 4145 |
early_visualization_path = save_predicted_point_query_rest_visualization(
|
| 4146 |
output_dir,
|
| 4147 |
-
query_points=
|
| 4148 |
query_points,
|
| 4149 |
center=mesh_geometry.center,
|
| 4150 |
scale=mesh_geometry.scale,
|
|
@@ -4155,7 +4156,7 @@ class InstructParticulateApp:
|
|
| 4155 |
link_point_prompt_ids=visualization_link_point_prompt_ids,
|
| 4156 |
links=links_for_query_visualization,
|
| 4157 |
)
|
| 4158 |
-
face_part_ids, face_part_ids_unrefined =
|
| 4159 |
mesh_geometry.normalized_mesh,
|
| 4160 |
point_part_ids=point_part_ids,
|
| 4161 |
point_part_probabilities=np.asarray(
|
|
@@ -4212,7 +4213,7 @@ class InstructParticulateApp:
|
|
| 4212 |
mesh_geometry = self._prepare_geometry(mesh_path, canonical_up)
|
| 4213 |
batch = _to_device_payload(payload["batch"], device)
|
| 4214 |
face_part_ids = np.asarray(payload["face_part_ids"], dtype=np.int32)
|
| 4215 |
-
motion_artifacts =
|
| 4216 |
args,
|
| 4217 |
model=model,
|
| 4218 |
batch=batch,
|
|
@@ -4323,9 +4324,7 @@ class InstructParticulateApp:
|
|
| 4323 |
)
|
| 4324 |
|
| 4325 |
def _prepare_geometry(self, mesh_path: Path, up_dir: str):
|
| 4326 |
-
|
| 4327 |
-
|
| 4328 |
-
return _prepare_mesh_geometry(input_path=mesh_path, up_dir=up_dir)
|
| 4329 |
|
| 4330 |
def _segmentation_num_query_points(
|
| 4331 |
self,
|
|
@@ -4468,7 +4467,7 @@ class InstructParticulateApp:
|
|
| 4468 |
face_part_ids = prediction["face_part_ids"]
|
| 4469 |
query_points = prediction["query_points"]
|
| 4470 |
|
| 4471 |
-
|
| 4472 |
output_dir,
|
| 4473 |
face_part_ids=face_part_ids,
|
| 4474 |
query_points=query_points,
|
|
@@ -4495,7 +4494,7 @@ class InstructParticulateApp:
|
|
| 4495 |
revolute_parameter_valid=motion_arrays_normalized["revolute_parameter_valid"],
|
| 4496 |
prismatic_parameter_valid=motion_arrays_normalized["prismatic_parameter_valid"],
|
| 4497 |
)
|
| 4498 |
-
overparam_visualization_path =
|
| 4499 |
output_dir,
|
| 4500 |
kinematic_records=predicted_kinematic,
|
| 4501 |
visualization_records=None,
|
|
@@ -4506,7 +4505,7 @@ class InstructParticulateApp:
|
|
| 4506 |
center=mesh_geometry.center,
|
| 4507 |
scale=mesh_geometry.scale,
|
| 4508 |
)
|
| 4509 |
-
unique_part_ids =
|
| 4510 |
args,
|
| 4511 |
output_dir=output_dir,
|
| 4512 |
original_mesh=mesh_geometry.original_mesh,
|
|
@@ -4536,7 +4535,7 @@ class InstructParticulateApp:
|
|
| 4536 |
link_names=link_names,
|
| 4537 |
)
|
| 4538 |
|
| 4539 |
-
metadata =
|
| 4540 |
args,
|
| 4541 |
mode="mesh",
|
| 4542 |
input_path=mesh_path,
|
|
@@ -4570,11 +4569,11 @@ class InstructParticulateApp:
|
|
| 4570 |
"reoriented_to_canonical_z_up": bool(up_dir != "+Z"),
|
| 4571 |
"rotation_matrix": mesh_geometry.up_dir_rotation.tolist(),
|
| 4572 |
},
|
| 4573 |
-
} |
|
| 4574 |
joint_refit_sampling,
|
| 4575 |
num_links=len(link_names),
|
| 4576 |
)
|
| 4577 |
-
|
| 4578 |
output_dir=output_dir,
|
| 4579 |
metadata=metadata,
|
| 4580 |
checkpoint_path=self.checkpoint_path,
|
|
|
|
| 43 |
spaces = None
|
| 44 |
|
| 45 |
from infer import (
|
| 46 |
+
build_base_metadata,
|
| 47 |
+
build_joint_refit_metadata,
|
| 48 |
+
compute_motion_prediction_artifacts,
|
| 49 |
+
decode_face_part_ids,
|
| 50 |
+
denormalize_points,
|
| 51 |
+
prepare_mesh_geometry,
|
| 52 |
+
resolve_visualized_batch_link_point_prompts,
|
| 53 |
+
save_articulated_mesh_outputs,
|
| 54 |
+
tensor_to_numpy,
|
| 55 |
+
write_kinematic_and_overparam_visualization,
|
| 56 |
+
write_mesh_like_prediction_files,
|
| 57 |
+
write_metadata_and_summary,
|
| 58 |
)
|
| 59 |
from instruct_particulate.model import Particulate2ArticulationModel
|
| 60 |
from instruct_particulate.utils.auto_kinematics_utils import (
|
|
|
|
| 2861 |
return up_dir.replace("+", "pos").replace("-", "neg")
|
| 2862 |
|
| 2863 |
|
| 2864 |
+
def _upright_rendering_placeholder_path() -> str:
|
| 2865 |
from PIL import Image, ImageDraw, ImageFont
|
| 2866 |
|
| 2867 |
placeholder_path = OUTPUT_ROOT / "_ui" / "upright_orientation_rendering.png"
|
|
|
|
| 2892 |
font=small_font,
|
| 2893 |
)
|
| 2894 |
image.save(placeholder_path)
|
| 2895 |
+
return str(placeholder_path)
|
| 2896 |
|
| 2897 |
|
| 2898 |
def _upright_rendering_preview_paths() -> list[str]:
|
| 2899 |
+
placeholder_path = _upright_rendering_placeholder_path()
|
| 2900 |
return [placeholder_path for _ in UP_DIR_CHOICES]
|
| 2901 |
|
| 2902 |
|
|
|
|
| 4053 |
.numpy()
|
| 4054 |
.astype(np.int32)
|
| 4055 |
)
|
| 4056 |
+
query_points = tensor_to_numpy(batch["query_points"][0], dtype=np.float32)
|
| 4057 |
+
query_normals = tensor_to_numpy(
|
| 4058 |
batch["query_point_normals"][0],
|
| 4059 |
dtype=np.float32,
|
| 4060 |
)
|
|
|
|
| 4131 |
]
|
| 4132 |
batch = payload["batch"]
|
| 4133 |
visualization_link_point_prompts_world, visualization_link_point_prompt_ids = (
|
| 4134 |
+
resolve_visualized_batch_link_point_prompts(
|
| 4135 |
args=args,
|
| 4136 |
batch=batch,
|
| 4137 |
links=links_for_query_visualization,
|
|
|
|
| 4145 |
query_face_indices = np.asarray(payload["query_face_indices"], dtype=np.int64)
|
| 4146 |
early_visualization_path = save_predicted_point_query_rest_visualization(
|
| 4147 |
output_dir,
|
| 4148 |
+
query_points=denormalize_points(
|
| 4149 |
query_points,
|
| 4150 |
center=mesh_geometry.center,
|
| 4151 |
scale=mesh_geometry.scale,
|
|
|
|
| 4156 |
link_point_prompt_ids=visualization_link_point_prompt_ids,
|
| 4157 |
links=links_for_query_visualization,
|
| 4158 |
)
|
| 4159 |
+
face_part_ids, face_part_ids_unrefined = decode_face_part_ids(
|
| 4160 |
mesh_geometry.normalized_mesh,
|
| 4161 |
point_part_ids=point_part_ids,
|
| 4162 |
point_part_probabilities=np.asarray(
|
|
|
|
| 4213 |
mesh_geometry = self._prepare_geometry(mesh_path, canonical_up)
|
| 4214 |
batch = _to_device_payload(payload["batch"], device)
|
| 4215 |
face_part_ids = np.asarray(payload["face_part_ids"], dtype=np.int32)
|
| 4216 |
+
motion_artifacts = compute_motion_prediction_artifacts(
|
| 4217 |
args,
|
| 4218 |
model=model,
|
| 4219 |
batch=batch,
|
|
|
|
| 4324 |
)
|
| 4325 |
|
| 4326 |
def _prepare_geometry(self, mesh_path: Path, up_dir: str):
|
| 4327 |
+
return prepare_mesh_geometry(input_path=mesh_path, up_dir=up_dir)
|
|
|
|
|
|
|
| 4328 |
|
| 4329 |
def _segmentation_num_query_points(
|
| 4330 |
self,
|
|
|
|
| 4467 |
face_part_ids = prediction["face_part_ids"]
|
| 4468 |
query_points = prediction["query_points"]
|
| 4469 |
|
| 4470 |
+
write_mesh_like_prediction_files(
|
| 4471 |
output_dir,
|
| 4472 |
face_part_ids=face_part_ids,
|
| 4473 |
query_points=query_points,
|
|
|
|
| 4494 |
revolute_parameter_valid=motion_arrays_normalized["revolute_parameter_valid"],
|
| 4495 |
prismatic_parameter_valid=motion_arrays_normalized["prismatic_parameter_valid"],
|
| 4496 |
)
|
| 4497 |
+
overparam_visualization_path = write_kinematic_and_overparam_visualization(
|
| 4498 |
output_dir,
|
| 4499 |
kinematic_records=predicted_kinematic,
|
| 4500 |
visualization_records=None,
|
|
|
|
| 4505 |
center=mesh_geometry.center,
|
| 4506 |
scale=mesh_geometry.scale,
|
| 4507 |
)
|
| 4508 |
+
unique_part_ids = save_articulated_mesh_outputs(
|
| 4509 |
args,
|
| 4510 |
output_dir=output_dir,
|
| 4511 |
original_mesh=mesh_geometry.original_mesh,
|
|
|
|
| 4535 |
link_names=link_names,
|
| 4536 |
)
|
| 4537 |
|
| 4538 |
+
metadata = build_base_metadata(
|
| 4539 |
args,
|
| 4540 |
mode="mesh",
|
| 4541 |
input_path=mesh_path,
|
|
|
|
| 4569 |
"reoriented_to_canonical_z_up": bool(up_dir != "+Z"),
|
| 4570 |
"rotation_matrix": mesh_geometry.up_dir_rotation.tolist(),
|
| 4571 |
},
|
| 4572 |
+
} | build_joint_refit_metadata(
|
| 4573 |
joint_refit_sampling,
|
| 4574 |
num_links=len(link_names),
|
| 4575 |
)
|
| 4576 |
+
write_metadata_and_summary(
|
| 4577 |
output_dir=output_dir,
|
| 4578 |
metadata=metadata,
|
| 4579 |
checkpoint_path=self.checkpoint_path,
|
infer.py
CHANGED
|
@@ -23,9 +23,6 @@ from instruct_particulate.utils.auto_kinematics_utils import (
|
|
| 23 |
)
|
| 24 |
from instruct_particulate.utils.export_utils import export_urdf
|
| 25 |
from instruct_particulate.utils.inference_utils import (
|
| 26 |
-
_range_forward_masks_by_child_link,
|
| 27 |
-
_suppress_unforwarded_joint_ranges,
|
| 28 |
-
_zero_unforwarded_link_ranges,
|
| 29 |
axis_point_to_plucker_torch,
|
| 30 |
build_predicted_joint_records_from_links_and_joints,
|
| 31 |
build_predicted_kinematic_records,
|
|
@@ -43,13 +40,16 @@ from instruct_particulate.utils.inference_utils import (
|
|
| 43 |
prepare_inference_batch_from_meta_root,
|
| 44 |
prismatic_directions_from_plucker,
|
| 45 |
prompt_for_link_names_and_joints,
|
|
|
|
| 46 |
resolve_checkpoint_path,
|
| 47 |
resolve_input_mode,
|
| 48 |
resolve_inference_sampling_config,
|
| 49 |
resolve_num_query_points,
|
| 50 |
run_joint_refit_from_face_seg,
|
| 51 |
run_batched_model_inference,
|
|
|
|
| 52 |
write_json,
|
|
|
|
| 53 |
)
|
| 54 |
from instruct_particulate.utils.meta_root_utils import (
|
| 55 |
is_supported_meta_root,
|
|
@@ -61,11 +61,11 @@ from instruct_particulate.utils.saved_auto_kinematics_utils import (
|
|
| 61 |
load_saved_auto_kinematics_root,
|
| 62 |
)
|
| 63 |
from instruct_particulate.utils.inference_visualization_utils import (
|
| 64 |
-
|
| 65 |
print_inference_summary,
|
| 66 |
-
save_predicted_point_query_visualization,
|
| 67 |
save_joint_overparam_visualization_from_model_output,
|
| 68 |
save_point_query_visualization,
|
|
|
|
| 69 |
save_segmented_visualizations,
|
| 70 |
select_visualized_link_point_prompts,
|
| 71 |
)
|
|
@@ -334,16 +334,18 @@ def parse_args() -> argparse.Namespace:
|
|
| 334 |
return args
|
| 335 |
|
| 336 |
|
| 337 |
-
def
|
|
|
|
| 338 |
return tensor.detach().cpu().numpy().astype(dtype, copy=False)
|
| 339 |
|
| 340 |
|
| 341 |
-
def
|
| 342 |
points: np.ndarray,
|
| 343 |
*,
|
| 344 |
center: np.ndarray | tuple[float, float, float],
|
| 345 |
scale: float,
|
| 346 |
) -> np.ndarray:
|
|
|
|
| 347 |
return (
|
| 348 |
np.asarray(points, dtype=np.float32) / np.float32(scale)
|
| 349 |
+ np.asarray(center, dtype=np.float32)
|
|
@@ -1391,7 +1393,7 @@ def _apply_confidence_weighted_overparam_joint_voting(
|
|
| 1391 |
return weighted_motion_output
|
| 1392 |
|
| 1393 |
|
| 1394 |
-
def
|
| 1395 |
refit_sampling: dict[str, np.ndarray] | None,
|
| 1396 |
*,
|
| 1397 |
num_links: int,
|
|
@@ -1432,13 +1434,13 @@ def _query_visualization_part_confidences_from_motion_output(
|
|
| 1432 |
if joint_decoding_link_ids is None or joint_decoding_confidences is None:
|
| 1433 |
return None
|
| 1434 |
|
| 1435 |
-
return
|
| 1436 |
-
query_link_ids=
|
| 1437 |
-
query_confidences=
|
| 1438 |
)
|
| 1439 |
|
| 1440 |
|
| 1441 |
-
def
|
| 1442 |
mesh: Any,
|
| 1443 |
*,
|
| 1444 |
point_part_ids: np.ndarray,
|
|
@@ -1466,7 +1468,7 @@ def _decode_face_part_ids(
|
|
| 1466 |
return face_part_ids, face_part_ids_unrefined
|
| 1467 |
|
| 1468 |
|
| 1469 |
-
def
|
| 1470 |
args: argparse.Namespace,
|
| 1471 |
*,
|
| 1472 |
model: Particulate2ArticulationModel,
|
|
@@ -1590,7 +1592,7 @@ def _save_query_predictions(
|
|
| 1590 |
) -> None:
|
| 1591 |
"""Writes first-pass query predictions plus optional joint-refit debug arrays."""
|
| 1592 |
payload: dict[str, np.ndarray] = {
|
| 1593 |
-
"query_points":
|
| 1594 |
query_points,
|
| 1595 |
center=center,
|
| 1596 |
scale=scale,
|
|
@@ -1605,7 +1607,7 @@ def _save_query_predictions(
|
|
| 1605 |
if joint_refit_sampling is not None:
|
| 1606 |
payload.update(
|
| 1607 |
{
|
| 1608 |
-
"joint_refit_query_points":
|
| 1609 |
joint_refit_sampling["query_points"],
|
| 1610 |
center=center,
|
| 1611 |
scale=scale,
|
|
@@ -1634,7 +1636,7 @@ def _missing_link_ids(num_links: int, unique_part_ids: np.ndarray) -> list[int]:
|
|
| 1634 |
)
|
| 1635 |
|
| 1636 |
|
| 1637 |
-
def
|
| 1638 |
*,
|
| 1639 |
args: argparse.Namespace,
|
| 1640 |
batch: dict[str, Any],
|
|
@@ -1647,8 +1649,8 @@ def _resolve_visualized_batch_link_point_prompts(
|
|
| 1647 |
if link_point_prompts is None:
|
| 1648 |
return np.zeros((0, 3), dtype=np.float32), np.zeros((0,), dtype=np.int64)
|
| 1649 |
|
| 1650 |
-
link_point_prompts_world =
|
| 1651 |
-
|
| 1652 |
center=center,
|
| 1653 |
scale=scale,
|
| 1654 |
)
|
|
@@ -1656,7 +1658,7 @@ def _resolve_visualized_batch_link_point_prompts(
|
|
| 1656 |
dropout_eligible_np = (
|
| 1657 |
None
|
| 1658 |
if dropout_eligible is None
|
| 1659 |
-
else
|
| 1660 |
)
|
| 1661 |
return select_visualized_link_point_prompts(
|
| 1662 |
link_point_prompts=link_point_prompts_world,
|
|
@@ -1666,7 +1668,7 @@ def _resolve_visualized_batch_link_point_prompts(
|
|
| 1666 |
)
|
| 1667 |
|
| 1668 |
|
| 1669 |
-
def
|
| 1670 |
args: argparse.Namespace,
|
| 1671 |
*,
|
| 1672 |
mode: str,
|
|
@@ -1679,6 +1681,7 @@ def _base_metadata(
|
|
| 1679 |
joint_refit_num_query_points: int,
|
| 1680 |
sharp_point_ratio: float,
|
| 1681 |
) -> dict[str, Any]:
|
|
|
|
| 1682 |
return {
|
| 1683 |
"mode": mode,
|
| 1684 |
"input_path": str(input_path),
|
|
@@ -1704,7 +1707,7 @@ def _base_metadata(
|
|
| 1704 |
}
|
| 1705 |
|
| 1706 |
|
| 1707 |
-
def
|
| 1708 |
*,
|
| 1709 |
output_dir: Path,
|
| 1710 |
metadata: dict[str, Any],
|
|
@@ -1879,7 +1882,7 @@ def _prepare_saved_auto_kinematics_mesh_batch(
|
|
| 1879 |
)
|
| 1880 |
|
| 1881 |
|
| 1882 |
-
def
|
| 1883 |
*,
|
| 1884 |
input_path: Path,
|
| 1885 |
up_dir: str,
|
|
@@ -2004,7 +2007,7 @@ def _run_mesh_like_prediction(
|
|
| 2004 |
point_part_ids = (
|
| 2005 |
output["segmentation_logits"].argmax(dim=-1)[0].detach().cpu().numpy().astype(np.int32)
|
| 2006 |
)
|
| 2007 |
-
face_part_ids, face_part_ids_unrefined =
|
| 2008 |
normalized_mesh,
|
| 2009 |
point_part_ids=point_part_ids,
|
| 2010 |
point_part_probabilities=point_part_probabilities,
|
|
@@ -2015,7 +2018,7 @@ def _run_mesh_like_prediction(
|
|
| 2015 |
getattr(args, "enforce_connectivity_per_part", False)
|
| 2016 |
),
|
| 2017 |
)
|
| 2018 |
-
motion_artifacts =
|
| 2019 |
args,
|
| 2020 |
model=model,
|
| 2021 |
batch=batch,
|
|
@@ -2027,8 +2030,8 @@ def _run_mesh_like_prediction(
|
|
| 2027 |
scale=scale,
|
| 2028 |
)
|
| 2029 |
return {
|
| 2030 |
-
"query_points":
|
| 2031 |
-
"query_normals":
|
| 2032 |
"point_part_ids": point_part_ids,
|
| 2033 |
"face_part_ids": face_part_ids,
|
| 2034 |
"face_part_ids_unrefined": face_part_ids_unrefined,
|
|
@@ -2036,7 +2039,7 @@ def _run_mesh_like_prediction(
|
|
| 2036 |
}
|
| 2037 |
|
| 2038 |
|
| 2039 |
-
def
|
| 2040 |
output_dir: Path,
|
| 2041 |
*,
|
| 2042 |
face_part_ids: np.ndarray,
|
|
@@ -2064,7 +2067,7 @@ def _write_mesh_like_prediction_files(
|
|
| 2064 |
)
|
| 2065 |
|
| 2066 |
|
| 2067 |
-
def
|
| 2068 |
output_dir: Path,
|
| 2069 |
*,
|
| 2070 |
kinematic_records: dict[str, Any],
|
|
@@ -2082,14 +2085,14 @@ def _write_kinematic_and_overparam_visualization(
|
|
| 2082 |
kinematic_records if visualization_records is None else visualization_records
|
| 2083 |
)
|
| 2084 |
if joint_refit_sampling is None:
|
| 2085 |
-
overparam_visualization_query_points =
|
| 2086 |
query_points,
|
| 2087 |
center=np.asarray(center, dtype=np.float32),
|
| 2088 |
scale=scale,
|
| 2089 |
)
|
| 2090 |
overparam_visualization_link_ids = np.asarray(point_part_ids, dtype=np.int32)
|
| 2091 |
else:
|
| 2092 |
-
overparam_visualization_query_points =
|
| 2093 |
joint_refit_sampling["query_points"],
|
| 2094 |
center=np.asarray(center, dtype=np.float32),
|
| 2095 |
scale=scale,
|
|
@@ -2110,7 +2113,7 @@ def _write_kinematic_and_overparam_visualization(
|
|
| 2110 |
)
|
| 2111 |
|
| 2112 |
|
| 2113 |
-
def
|
| 2114 |
args: argparse.Namespace,
|
| 2115 |
*,
|
| 2116 |
output_dir: Path,
|
|
@@ -2192,7 +2195,7 @@ def run_mesh_inference(
|
|
| 2192 |
mesh_input_path = saved_auto_root.mesh_path
|
| 2193 |
mesh_input_up_dir = saved_auto_root.mesh_up_dir
|
| 2194 |
mode = "saved_auto_kinematics_root"
|
| 2195 |
-
mesh_geometry =
|
| 2196 |
input_path=mesh_input_path,
|
| 2197 |
up_dir=mesh_input_up_dir,
|
| 2198 |
)
|
|
@@ -2249,7 +2252,7 @@ def run_mesh_inference(
|
|
| 2249 |
face_part_ids_unrefined = prediction["face_part_ids_unrefined"]
|
| 2250 |
query_points = prediction["query_points"]
|
| 2251 |
|
| 2252 |
-
|
| 2253 |
output_dir,
|
| 2254 |
face_part_ids=face_part_ids,
|
| 2255 |
query_points=query_points,
|
|
@@ -2276,7 +2279,7 @@ def run_mesh_inference(
|
|
| 2276 |
prismatic_parameter_valid=motion_arrays_normalized["prismatic_parameter_valid"],
|
| 2277 |
)
|
| 2278 |
visualization_link_point_prompts_world, visualization_link_point_prompt_ids = (
|
| 2279 |
-
|
| 2280 |
args=args,
|
| 2281 |
batch=mesh_batch.batch,
|
| 2282 |
links=predicted_kinematic["links"],
|
|
@@ -2286,7 +2289,7 @@ def run_mesh_inference(
|
|
| 2286 |
)
|
| 2287 |
visualization_path = save_predicted_point_query_visualization(
|
| 2288 |
output_dir,
|
| 2289 |
-
query_points=
|
| 2290 |
query_points,
|
| 2291 |
center=mesh_geometry.center,
|
| 2292 |
scale=mesh_geometry.scale,
|
|
@@ -2301,7 +2304,7 @@ def run_mesh_inference(
|
|
| 2301 |
motion_output
|
| 2302 |
),
|
| 2303 |
)
|
| 2304 |
-
overparam_visualization_path =
|
| 2305 |
output_dir,
|
| 2306 |
kinematic_records=predicted_kinematic,
|
| 2307 |
visualization_records=None,
|
|
@@ -2312,7 +2315,7 @@ def run_mesh_inference(
|
|
| 2312 |
center=mesh_geometry.center,
|
| 2313 |
scale=mesh_geometry.scale,
|
| 2314 |
)
|
| 2315 |
-
unique_part_ids =
|
| 2316 |
args,
|
| 2317 |
output_dir=output_dir,
|
| 2318 |
original_mesh=mesh_geometry.original_mesh,
|
|
@@ -2344,7 +2347,7 @@ def run_mesh_inference(
|
|
| 2344 |
prismatic_range=motion_arrays_normalized["prismatic_range"],
|
| 2345 |
)
|
| 2346 |
|
| 2347 |
-
metadata =
|
| 2348 |
args,
|
| 2349 |
mode=mode,
|
| 2350 |
input_path=input_path,
|
|
@@ -2382,13 +2385,13 @@ def run_mesh_inference(
|
|
| 2382 |
"reoriented_to_canonical_z_up": bool(mesh_input_up_dir != "+Z"),
|
| 2383 |
"rotation_matrix": mesh_geometry.up_dir_rotation.tolist(),
|
| 2384 |
},
|
| 2385 |
-
} |
|
| 2386 |
joint_refit_sampling,
|
| 2387 |
num_links=len(mesh_batch.link_names),
|
| 2388 |
)
|
| 2389 |
if mesh_batch.auto_kinematics_metadata:
|
| 2390 |
metadata["auto_kinematics"] = mesh_batch.auto_kinematics_metadata
|
| 2391 |
-
|
| 2392 |
output_dir=output_dir,
|
| 2393 |
metadata=metadata,
|
| 2394 |
checkpoint_path=checkpoint_path,
|
|
@@ -2465,20 +2468,20 @@ def run_meta_root_inference(
|
|
| 2465 |
(
|
| 2466 |
gt_revolute_range_forward_mask,
|
| 2467 |
gt_prismatic_range_forward_mask,
|
| 2468 |
-
) =
|
| 2469 |
meta_info["sorted_joints"],
|
| 2470 |
num_links=len(meta_info["link_names"]),
|
| 2471 |
)
|
| 2472 |
-
forwarded_revolute_range_world =
|
| 2473 |
motion_arrays_world["revolute_range"],
|
| 2474 |
forward_mask=gt_revolute_range_forward_mask,
|
| 2475 |
)
|
| 2476 |
-
forwarded_prismatic_range_world =
|
| 2477 |
motion_arrays_world["prismatic_range"],
|
| 2478 |
forward_mask=gt_prismatic_range_forward_mask,
|
| 2479 |
)
|
| 2480 |
output_dir = _resolve_output_dir(args, meta_root)
|
| 2481 |
-
|
| 2482 |
output_dir,
|
| 2483 |
face_part_ids=face_part_ids,
|
| 2484 |
query_points=query_points,
|
|
@@ -2502,7 +2505,7 @@ def run_meta_root_inference(
|
|
| 2502 |
revolute_parameter_valid=motion_arrays_normalized["revolute_parameter_valid"],
|
| 2503 |
prismatic_parameter_valid=motion_arrays_normalized["prismatic_parameter_valid"],
|
| 2504 |
)
|
| 2505 |
-
predicted_kinematic["joints"] =
|
| 2506 |
predicted_kinematic["joints"],
|
| 2507 |
revolute_range_forward_mask=gt_revolute_range_forward_mask,
|
| 2508 |
prismatic_range_forward_mask=gt_prismatic_range_forward_mask,
|
|
@@ -2518,13 +2521,13 @@ def run_meta_root_inference(
|
|
| 2518 |
revolute_parameter_valid=motion_arrays_normalized["revolute_parameter_valid"],
|
| 2519 |
prismatic_parameter_valid=motion_arrays_normalized["prismatic_parameter_valid"],
|
| 2520 |
)
|
| 2521 |
-
predicted_joint_records["joints"] =
|
| 2522 |
predicted_joint_records["joints"],
|
| 2523 |
revolute_range_forward_mask=gt_revolute_range_forward_mask,
|
| 2524 |
prismatic_range_forward_mask=gt_prismatic_range_forward_mask,
|
| 2525 |
)
|
| 2526 |
visualization_link_point_prompts_world, visualization_link_point_prompt_ids = (
|
| 2527 |
-
|
| 2528 |
args=args,
|
| 2529 |
batch=batch,
|
| 2530 |
links=predicted_joint_records["links"],
|
|
@@ -2532,7 +2535,7 @@ def run_meta_root_inference(
|
|
| 2532 |
scale=scale,
|
| 2533 |
)
|
| 2534 |
)
|
| 2535 |
-
overparam_visualization_path =
|
| 2536 |
output_dir,
|
| 2537 |
kinematic_records=predicted_kinematic,
|
| 2538 |
visualization_records=predicted_joint_records,
|
|
@@ -2548,7 +2551,7 @@ def run_meta_root_inference(
|
|
| 2548 |
(int(joint["parent_link_id"]), int(joint["child_link_id"]))
|
| 2549 |
for joint in meta_info["sorted_joints"]
|
| 2550 |
]
|
| 2551 |
-
unique_part_ids =
|
| 2552 |
args,
|
| 2553 |
output_dir=output_dir,
|
| 2554 |
original_mesh=original_mesh,
|
|
@@ -2590,7 +2593,7 @@ def run_meta_root_inference(
|
|
| 2590 |
|
| 2591 |
visualization_path = save_point_query_visualization(
|
| 2592 |
output_dir,
|
| 2593 |
-
query_points=
|
| 2594 |
query_points,
|
| 2595 |
center=np.asarray(center, dtype=np.float32),
|
| 2596 |
scale=scale,
|
|
@@ -2608,7 +2611,7 @@ def run_meta_root_inference(
|
|
| 2608 |
gt_joints=meta_info["sorted_joints"],
|
| 2609 |
)
|
| 2610 |
|
| 2611 |
-
metadata =
|
| 2612 |
args,
|
| 2613 |
mode="meta_root",
|
| 2614 |
input_path=meta_root,
|
|
@@ -2644,7 +2647,7 @@ def run_meta_root_inference(
|
|
| 2644 |
"center": np.asarray(center, dtype=np.float32).tolist(),
|
| 2645 |
"scale": float(scale),
|
| 2646 |
},
|
| 2647 |
-
} |
|
| 2648 |
joint_refit_sampling,
|
| 2649 |
num_links=len(meta_info["link_names"]),
|
| 2650 |
)
|
|
@@ -2655,7 +2658,7 @@ def run_meta_root_inference(
|
|
| 2655 |
metadata["legacy_meta_path"] = str(meta_root / "meta.npz")
|
| 2656 |
metadata["legacy_link_axes_plucker_path"] = str(meta_root / "link_axes_plucker.npz")
|
| 2657 |
metadata["legacy_link_range_path"] = str(meta_root / "link_range.npz")
|
| 2658 |
-
|
| 2659 |
output_dir=output_dir,
|
| 2660 |
metadata=metadata,
|
| 2661 |
checkpoint_path=checkpoint_path,
|
|
|
|
| 23 |
)
|
| 24 |
from instruct_particulate.utils.export_utils import export_urdf
|
| 25 |
from instruct_particulate.utils.inference_utils import (
|
|
|
|
|
|
|
|
|
|
| 26 |
axis_point_to_plucker_torch,
|
| 27 |
build_predicted_joint_records_from_links_and_joints,
|
| 28 |
build_predicted_kinematic_records,
|
|
|
|
| 40 |
prepare_inference_batch_from_meta_root,
|
| 41 |
prismatic_directions_from_plucker,
|
| 42 |
prompt_for_link_names_and_joints,
|
| 43 |
+
range_forward_masks_by_child_link,
|
| 44 |
resolve_checkpoint_path,
|
| 45 |
resolve_input_mode,
|
| 46 |
resolve_inference_sampling_config,
|
| 47 |
resolve_num_query_points,
|
| 48 |
run_joint_refit_from_face_seg,
|
| 49 |
run_batched_model_inference,
|
| 50 |
+
suppress_unforwarded_joint_ranges,
|
| 51 |
write_json,
|
| 52 |
+
zero_unforwarded_link_ranges,
|
| 53 |
)
|
| 54 |
from instruct_particulate.utils.meta_root_utils import (
|
| 55 |
is_supported_meta_root,
|
|
|
|
| 61 |
load_saved_auto_kinematics_root,
|
| 62 |
)
|
| 63 |
from instruct_particulate.utils.inference_visualization_utils import (
|
| 64 |
+
compute_link_geometric_mean_confidences,
|
| 65 |
print_inference_summary,
|
|
|
|
| 66 |
save_joint_overparam_visualization_from_model_output,
|
| 67 |
save_point_query_visualization,
|
| 68 |
+
save_predicted_point_query_visualization,
|
| 69 |
save_segmented_visualizations,
|
| 70 |
select_visualized_link_point_prompts,
|
| 71 |
)
|
|
|
|
| 334 |
return args
|
| 335 |
|
| 336 |
|
| 337 |
+
def tensor_to_numpy(tensor: torch.Tensor, *, dtype: np.dtype[Any] | type) -> np.ndarray:
|
| 338 |
+
"""Converts a tensor to a CPU NumPy array with the requested dtype."""
|
| 339 |
return tensor.detach().cpu().numpy().astype(dtype, copy=False)
|
| 340 |
|
| 341 |
|
| 342 |
+
def denormalize_points(
|
| 343 |
points: np.ndarray,
|
| 344 |
*,
|
| 345 |
center: np.ndarray | tuple[float, float, float],
|
| 346 |
scale: float,
|
| 347 |
) -> np.ndarray:
|
| 348 |
+
"""Converts normalized model-space points back to mesh-space coordinates."""
|
| 349 |
return (
|
| 350 |
np.asarray(points, dtype=np.float32) / np.float32(scale)
|
| 351 |
+ np.asarray(center, dtype=np.float32)
|
|
|
|
| 1393 |
return weighted_motion_output
|
| 1394 |
|
| 1395 |
|
| 1396 |
+
def build_joint_refit_metadata(
|
| 1397 |
refit_sampling: dict[str, np.ndarray] | None,
|
| 1398 |
*,
|
| 1399 |
num_links: int,
|
|
|
|
| 1434 |
if joint_decoding_link_ids is None or joint_decoding_confidences is None:
|
| 1435 |
return None
|
| 1436 |
|
| 1437 |
+
return compute_link_geometric_mean_confidences(
|
| 1438 |
+
query_link_ids=tensor_to_numpy(joint_decoding_link_ids[0], dtype=np.int64),
|
| 1439 |
+
query_confidences=tensor_to_numpy(joint_decoding_confidences[0], dtype=np.float32),
|
| 1440 |
)
|
| 1441 |
|
| 1442 |
|
| 1443 |
+
def decode_face_part_ids(
|
| 1444 |
mesh: Any,
|
| 1445 |
*,
|
| 1446 |
point_part_ids: np.ndarray,
|
|
|
|
| 1468 |
return face_part_ids, face_part_ids_unrefined
|
| 1469 |
|
| 1470 |
|
| 1471 |
+
def compute_motion_prediction_artifacts(
|
| 1472 |
args: argparse.Namespace,
|
| 1473 |
*,
|
| 1474 |
model: Particulate2ArticulationModel,
|
|
|
|
| 1592 |
) -> None:
|
| 1593 |
"""Writes first-pass query predictions plus optional joint-refit debug arrays."""
|
| 1594 |
payload: dict[str, np.ndarray] = {
|
| 1595 |
+
"query_points": denormalize_points(
|
| 1596 |
query_points,
|
| 1597 |
center=center,
|
| 1598 |
scale=scale,
|
|
|
|
| 1607 |
if joint_refit_sampling is not None:
|
| 1608 |
payload.update(
|
| 1609 |
{
|
| 1610 |
+
"joint_refit_query_points": denormalize_points(
|
| 1611 |
joint_refit_sampling["query_points"],
|
| 1612 |
center=center,
|
| 1613 |
scale=scale,
|
|
|
|
| 1636 |
)
|
| 1637 |
|
| 1638 |
|
| 1639 |
+
def resolve_visualized_batch_link_point_prompts(
|
| 1640 |
*,
|
| 1641 |
args: argparse.Namespace,
|
| 1642 |
batch: dict[str, Any],
|
|
|
|
| 1649 |
if link_point_prompts is None:
|
| 1650 |
return np.zeros((0, 3), dtype=np.float32), np.zeros((0,), dtype=np.int64)
|
| 1651 |
|
| 1652 |
+
link_point_prompts_world = denormalize_points(
|
| 1653 |
+
tensor_to_numpy(link_point_prompts[0], dtype=np.float32),
|
| 1654 |
center=center,
|
| 1655 |
scale=scale,
|
| 1656 |
)
|
|
|
|
| 1658 |
dropout_eligible_np = (
|
| 1659 |
None
|
| 1660 |
if dropout_eligible is None
|
| 1661 |
+
else tensor_to_numpy(dropout_eligible[0], dtype=np.bool_)
|
| 1662 |
)
|
| 1663 |
return select_visualized_link_point_prompts(
|
| 1664 |
link_point_prompts=link_point_prompts_world,
|
|
|
|
| 1668 |
)
|
| 1669 |
|
| 1670 |
|
| 1671 |
+
def build_base_metadata(
|
| 1672 |
args: argparse.Namespace,
|
| 1673 |
*,
|
| 1674 |
mode: str,
|
|
|
|
| 1681 |
joint_refit_num_query_points: int,
|
| 1682 |
sharp_point_ratio: float,
|
| 1683 |
) -> dict[str, Any]:
|
| 1684 |
+
"""Builds the metadata fields common to mesh and meta-root inference."""
|
| 1685 |
return {
|
| 1686 |
"mode": mode,
|
| 1687 |
"input_path": str(input_path),
|
|
|
|
| 1707 |
}
|
| 1708 |
|
| 1709 |
|
| 1710 |
+
def write_metadata_and_summary(
|
| 1711 |
*,
|
| 1712 |
output_dir: Path,
|
| 1713 |
metadata: dict[str, Any],
|
|
|
|
| 1882 |
)
|
| 1883 |
|
| 1884 |
|
| 1885 |
+
def prepare_mesh_geometry(
|
| 1886 |
*,
|
| 1887 |
input_path: Path,
|
| 1888 |
up_dir: str,
|
|
|
|
| 2007 |
point_part_ids = (
|
| 2008 |
output["segmentation_logits"].argmax(dim=-1)[0].detach().cpu().numpy().astype(np.int32)
|
| 2009 |
)
|
| 2010 |
+
face_part_ids, face_part_ids_unrefined = decode_face_part_ids(
|
| 2011 |
normalized_mesh,
|
| 2012 |
point_part_ids=point_part_ids,
|
| 2013 |
point_part_probabilities=point_part_probabilities,
|
|
|
|
| 2018 |
getattr(args, "enforce_connectivity_per_part", False)
|
| 2019 |
),
|
| 2020 |
)
|
| 2021 |
+
motion_artifacts = compute_motion_prediction_artifacts(
|
| 2022 |
args,
|
| 2023 |
model=model,
|
| 2024 |
batch=batch,
|
|
|
|
| 2030 |
scale=scale,
|
| 2031 |
)
|
| 2032 |
return {
|
| 2033 |
+
"query_points": tensor_to_numpy(batch["query_points"][0], dtype=np.float32),
|
| 2034 |
+
"query_normals": tensor_to_numpy(batch["query_point_normals"][0], dtype=np.float32),
|
| 2035 |
"point_part_ids": point_part_ids,
|
| 2036 |
"face_part_ids": face_part_ids,
|
| 2037 |
"face_part_ids_unrefined": face_part_ids_unrefined,
|
|
|
|
| 2039 |
}
|
| 2040 |
|
| 2041 |
|
| 2042 |
+
def write_mesh_like_prediction_files(
|
| 2043 |
output_dir: Path,
|
| 2044 |
*,
|
| 2045 |
face_part_ids: np.ndarray,
|
|
|
|
| 2067 |
)
|
| 2068 |
|
| 2069 |
|
| 2070 |
+
def write_kinematic_and_overparam_visualization(
|
| 2071 |
output_dir: Path,
|
| 2072 |
*,
|
| 2073 |
kinematic_records: dict[str, Any],
|
|
|
|
| 2085 |
kinematic_records if visualization_records is None else visualization_records
|
| 2086 |
)
|
| 2087 |
if joint_refit_sampling is None:
|
| 2088 |
+
overparam_visualization_query_points = denormalize_points(
|
| 2089 |
query_points,
|
| 2090 |
center=np.asarray(center, dtype=np.float32),
|
| 2091 |
scale=scale,
|
| 2092 |
)
|
| 2093 |
overparam_visualization_link_ids = np.asarray(point_part_ids, dtype=np.int32)
|
| 2094 |
else:
|
| 2095 |
+
overparam_visualization_query_points = denormalize_points(
|
| 2096 |
joint_refit_sampling["query_points"],
|
| 2097 |
center=np.asarray(center, dtype=np.float32),
|
| 2098 |
scale=scale,
|
|
|
|
| 2113 |
)
|
| 2114 |
|
| 2115 |
|
| 2116 |
+
def save_articulated_mesh_outputs(
|
| 2117 |
args: argparse.Namespace,
|
| 2118 |
*,
|
| 2119 |
output_dir: Path,
|
|
|
|
| 2195 |
mesh_input_path = saved_auto_root.mesh_path
|
| 2196 |
mesh_input_up_dir = saved_auto_root.mesh_up_dir
|
| 2197 |
mode = "saved_auto_kinematics_root"
|
| 2198 |
+
mesh_geometry = prepare_mesh_geometry(
|
| 2199 |
input_path=mesh_input_path,
|
| 2200 |
up_dir=mesh_input_up_dir,
|
| 2201 |
)
|
|
|
|
| 2252 |
face_part_ids_unrefined = prediction["face_part_ids_unrefined"]
|
| 2253 |
query_points = prediction["query_points"]
|
| 2254 |
|
| 2255 |
+
write_mesh_like_prediction_files(
|
| 2256 |
output_dir,
|
| 2257 |
face_part_ids=face_part_ids,
|
| 2258 |
query_points=query_points,
|
|
|
|
| 2279 |
prismatic_parameter_valid=motion_arrays_normalized["prismatic_parameter_valid"],
|
| 2280 |
)
|
| 2281 |
visualization_link_point_prompts_world, visualization_link_point_prompt_ids = (
|
| 2282 |
+
resolve_visualized_batch_link_point_prompts(
|
| 2283 |
args=args,
|
| 2284 |
batch=mesh_batch.batch,
|
| 2285 |
links=predicted_kinematic["links"],
|
|
|
|
| 2289 |
)
|
| 2290 |
visualization_path = save_predicted_point_query_visualization(
|
| 2291 |
output_dir,
|
| 2292 |
+
query_points=denormalize_points(
|
| 2293 |
query_points,
|
| 2294 |
center=mesh_geometry.center,
|
| 2295 |
scale=mesh_geometry.scale,
|
|
|
|
| 2304 |
motion_output
|
| 2305 |
),
|
| 2306 |
)
|
| 2307 |
+
overparam_visualization_path = write_kinematic_and_overparam_visualization(
|
| 2308 |
output_dir,
|
| 2309 |
kinematic_records=predicted_kinematic,
|
| 2310 |
visualization_records=None,
|
|
|
|
| 2315 |
center=mesh_geometry.center,
|
| 2316 |
scale=mesh_geometry.scale,
|
| 2317 |
)
|
| 2318 |
+
unique_part_ids = save_articulated_mesh_outputs(
|
| 2319 |
args,
|
| 2320 |
output_dir=output_dir,
|
| 2321 |
original_mesh=mesh_geometry.original_mesh,
|
|
|
|
| 2347 |
prismatic_range=motion_arrays_normalized["prismatic_range"],
|
| 2348 |
)
|
| 2349 |
|
| 2350 |
+
metadata = build_base_metadata(
|
| 2351 |
args,
|
| 2352 |
mode=mode,
|
| 2353 |
input_path=input_path,
|
|
|
|
| 2385 |
"reoriented_to_canonical_z_up": bool(mesh_input_up_dir != "+Z"),
|
| 2386 |
"rotation_matrix": mesh_geometry.up_dir_rotation.tolist(),
|
| 2387 |
},
|
| 2388 |
+
} | build_joint_refit_metadata(
|
| 2389 |
joint_refit_sampling,
|
| 2390 |
num_links=len(mesh_batch.link_names),
|
| 2391 |
)
|
| 2392 |
if mesh_batch.auto_kinematics_metadata:
|
| 2393 |
metadata["auto_kinematics"] = mesh_batch.auto_kinematics_metadata
|
| 2394 |
+
write_metadata_and_summary(
|
| 2395 |
output_dir=output_dir,
|
| 2396 |
metadata=metadata,
|
| 2397 |
checkpoint_path=checkpoint_path,
|
|
|
|
| 2468 |
(
|
| 2469 |
gt_revolute_range_forward_mask,
|
| 2470 |
gt_prismatic_range_forward_mask,
|
| 2471 |
+
) = range_forward_masks_by_child_link(
|
| 2472 |
meta_info["sorted_joints"],
|
| 2473 |
num_links=len(meta_info["link_names"]),
|
| 2474 |
)
|
| 2475 |
+
forwarded_revolute_range_world = zero_unforwarded_link_ranges(
|
| 2476 |
motion_arrays_world["revolute_range"],
|
| 2477 |
forward_mask=gt_revolute_range_forward_mask,
|
| 2478 |
)
|
| 2479 |
+
forwarded_prismatic_range_world = zero_unforwarded_link_ranges(
|
| 2480 |
motion_arrays_world["prismatic_range"],
|
| 2481 |
forward_mask=gt_prismatic_range_forward_mask,
|
| 2482 |
)
|
| 2483 |
output_dir = _resolve_output_dir(args, meta_root)
|
| 2484 |
+
write_mesh_like_prediction_files(
|
| 2485 |
output_dir,
|
| 2486 |
face_part_ids=face_part_ids,
|
| 2487 |
query_points=query_points,
|
|
|
|
| 2505 |
revolute_parameter_valid=motion_arrays_normalized["revolute_parameter_valid"],
|
| 2506 |
prismatic_parameter_valid=motion_arrays_normalized["prismatic_parameter_valid"],
|
| 2507 |
)
|
| 2508 |
+
predicted_kinematic["joints"] = suppress_unforwarded_joint_ranges(
|
| 2509 |
predicted_kinematic["joints"],
|
| 2510 |
revolute_range_forward_mask=gt_revolute_range_forward_mask,
|
| 2511 |
prismatic_range_forward_mask=gt_prismatic_range_forward_mask,
|
|
|
|
| 2521 |
revolute_parameter_valid=motion_arrays_normalized["revolute_parameter_valid"],
|
| 2522 |
prismatic_parameter_valid=motion_arrays_normalized["prismatic_parameter_valid"],
|
| 2523 |
)
|
| 2524 |
+
predicted_joint_records["joints"] = suppress_unforwarded_joint_ranges(
|
| 2525 |
predicted_joint_records["joints"],
|
| 2526 |
revolute_range_forward_mask=gt_revolute_range_forward_mask,
|
| 2527 |
prismatic_range_forward_mask=gt_prismatic_range_forward_mask,
|
| 2528 |
)
|
| 2529 |
visualization_link_point_prompts_world, visualization_link_point_prompt_ids = (
|
| 2530 |
+
resolve_visualized_batch_link_point_prompts(
|
| 2531 |
args=args,
|
| 2532 |
batch=batch,
|
| 2533 |
links=predicted_joint_records["links"],
|
|
|
|
| 2535 |
scale=scale,
|
| 2536 |
)
|
| 2537 |
)
|
| 2538 |
+
overparam_visualization_path = write_kinematic_and_overparam_visualization(
|
| 2539 |
output_dir,
|
| 2540 |
kinematic_records=predicted_kinematic,
|
| 2541 |
visualization_records=predicted_joint_records,
|
|
|
|
| 2551 |
(int(joint["parent_link_id"]), int(joint["child_link_id"]))
|
| 2552 |
for joint in meta_info["sorted_joints"]
|
| 2553 |
]
|
| 2554 |
+
unique_part_ids = save_articulated_mesh_outputs(
|
| 2555 |
args,
|
| 2556 |
output_dir=output_dir,
|
| 2557 |
original_mesh=original_mesh,
|
|
|
|
| 2593 |
|
| 2594 |
visualization_path = save_point_query_visualization(
|
| 2595 |
output_dir,
|
| 2596 |
+
query_points=denormalize_points(
|
| 2597 |
query_points,
|
| 2598 |
center=np.asarray(center, dtype=np.float32),
|
| 2599 |
scale=scale,
|
|
|
|
| 2611 |
gt_joints=meta_info["sorted_joints"],
|
| 2612 |
)
|
| 2613 |
|
| 2614 |
+
metadata = build_base_metadata(
|
| 2615 |
args,
|
| 2616 |
mode="meta_root",
|
| 2617 |
input_path=meta_root,
|
|
|
|
| 2647 |
"center": np.asarray(center, dtype=np.float32).tolist(),
|
| 2648 |
"scale": float(scale),
|
| 2649 |
},
|
| 2650 |
+
} | build_joint_refit_metadata(
|
| 2651 |
joint_refit_sampling,
|
| 2652 |
num_links=len(meta_info["link_names"]),
|
| 2653 |
)
|
|
|
|
| 2658 |
metadata["legacy_meta_path"] = str(meta_root / "meta.npz")
|
| 2659 |
metadata["legacy_link_axes_plucker_path"] = str(meta_root / "link_axes_plucker.npz")
|
| 2660 |
metadata["legacy_link_range_path"] = str(meta_root / "link_range.npz")
|
| 2661 |
+
write_metadata_and_summary(
|
| 2662 |
output_dir=output_dir,
|
| 2663 |
metadata=metadata,
|
| 2664 |
checkpoint_path=checkpoint_path,
|
instruct_particulate/utils/inference_utils.py
CHANGED
|
@@ -49,15 +49,17 @@ def resolve_num_query_points(
|
|
| 49 |
|
| 50 |
|
| 51 |
def write_json(path: Path, payload: Any) -> None:
|
|
|
|
| 52 |
with path.open("w", encoding="utf-8") as fh:
|
| 53 |
json.dump(payload, fh, indent=2)
|
| 54 |
|
| 55 |
|
| 56 |
-
def
|
| 57 |
joints: Sequence[dict[str, Any]],
|
| 58 |
*,
|
| 59 |
num_links: int,
|
| 60 |
) -> tuple[np.ndarray, np.ndarray]:
|
|
|
|
| 61 |
revolute_range_forward_mask = np.zeros((num_links,), dtype=np.bool_)
|
| 62 |
prismatic_range_forward_mask = np.zeros((num_links,), dtype=np.bool_)
|
| 63 |
for joint in joints:
|
|
@@ -73,12 +75,13 @@ def _range_forward_masks_by_child_link(
|
|
| 73 |
return revolute_range_forward_mask, prismatic_range_forward_mask
|
| 74 |
|
| 75 |
|
| 76 |
-
def
|
| 77 |
joints: Sequence[dict[str, Any]],
|
| 78 |
*,
|
| 79 |
revolute_range_forward_mask: np.ndarray,
|
| 80 |
prismatic_range_forward_mask: np.ndarray,
|
| 81 |
) -> list[dict[str, Any]]:
|
|
|
|
| 82 |
suppressed_joints: list[dict[str, Any]] = []
|
| 83 |
for joint in joints:
|
| 84 |
child_link_id = int(joint["child_link_id"])
|
|
@@ -91,11 +94,12 @@ def _suppress_unforwarded_joint_ranges(
|
|
| 91 |
return suppressed_joints
|
| 92 |
|
| 93 |
|
| 94 |
-
def
|
| 95 |
link_ranges: np.ndarray,
|
| 96 |
*,
|
| 97 |
forward_mask: np.ndarray,
|
| 98 |
) -> np.ndarray:
|
|
|
|
| 99 |
masked_ranges = np.asarray(link_ranges, dtype=np.float32).copy()
|
| 100 |
if masked_ranges.shape != (len(forward_mask), 2):
|
| 101 |
raise ValueError(
|
|
|
|
| 49 |
|
| 50 |
|
| 51 |
def write_json(path: Path, payload: Any) -> None:
|
| 52 |
+
"""Writes a JSON payload with stable indentation."""
|
| 53 |
with path.open("w", encoding="utf-8") as fh:
|
| 54 |
json.dump(payload, fh, indent=2)
|
| 55 |
|
| 56 |
|
| 57 |
+
def range_forward_masks_by_child_link(
|
| 58 |
joints: Sequence[dict[str, Any]],
|
| 59 |
*,
|
| 60 |
num_links: int,
|
| 61 |
) -> tuple[np.ndarray, np.ndarray]:
|
| 62 |
+
"""Builds masks for links whose joint ranges are present in metadata."""
|
| 63 |
revolute_range_forward_mask = np.zeros((num_links,), dtype=np.bool_)
|
| 64 |
prismatic_range_forward_mask = np.zeros((num_links,), dtype=np.bool_)
|
| 65 |
for joint in joints:
|
|
|
|
| 75 |
return revolute_range_forward_mask, prismatic_range_forward_mask
|
| 76 |
|
| 77 |
|
| 78 |
+
def suppress_unforwarded_joint_ranges(
|
| 79 |
joints: Sequence[dict[str, Any]],
|
| 80 |
*,
|
| 81 |
revolute_range_forward_mask: np.ndarray,
|
| 82 |
prismatic_range_forward_mask: np.ndarray,
|
| 83 |
) -> list[dict[str, Any]]:
|
| 84 |
+
"""Returns joint records with non-forwarded ranges removed."""
|
| 85 |
suppressed_joints: list[dict[str, Any]] = []
|
| 86 |
for joint in joints:
|
| 87 |
child_link_id = int(joint["child_link_id"])
|
|
|
|
| 94 |
return suppressed_joints
|
| 95 |
|
| 96 |
|
| 97 |
+
def zero_unforwarded_link_ranges(
|
| 98 |
link_ranges: np.ndarray,
|
| 99 |
*,
|
| 100 |
forward_mask: np.ndarray,
|
| 101 |
) -> np.ndarray:
|
| 102 |
+
"""Zeros per-link ranges that were not forwarded from source metadata."""
|
| 103 |
masked_ranges = np.asarray(link_ranges, dtype=np.float32).copy()
|
| 104 |
if masked_ranges.shape != (len(forward_mask), 2):
|
| 105 |
raise ValueError(
|
instruct_particulate/utils/inference_visualization_utils.py
CHANGED
|
@@ -24,11 +24,12 @@ from instruct_particulate.utils.visualization_utils import (
|
|
| 24 |
)
|
| 25 |
|
| 26 |
|
| 27 |
-
def
|
| 28 |
*,
|
| 29 |
query_link_ids: np.ndarray,
|
| 30 |
query_confidences: np.ndarray,
|
| 31 |
) -> dict[int, float]:
|
|
|
|
| 32 |
query_link_ids = np.asarray(query_link_ids, dtype=np.int64)
|
| 33 |
query_confidences = np.asarray(query_confidences, dtype=np.float32)
|
| 34 |
if query_link_ids.shape != query_confidences.shape:
|
|
|
|
| 24 |
)
|
| 25 |
|
| 26 |
|
| 27 |
+
def compute_link_geometric_mean_confidences(
|
| 28 |
*,
|
| 29 |
query_link_ids: np.ndarray,
|
| 30 |
query_confidences: np.ndarray,
|
| 31 |
) -> dict[int, float]:
|
| 32 |
+
"""Computes per-link geometric mean confidence for query visualizations."""
|
| 33 |
query_link_ids = np.asarray(query_link_ids, dtype=np.int64)
|
| 34 |
query_confidences = np.asarray(query_confidences, dtype=np.float32)
|
| 35 |
if query_link_ids.shape != query_confidences.shape:
|