From 25d1ce2459e4f5c5959ee54ebcd5f860d70d4df6 Mon Sep 17 00:00:00 2001 From: YunLiu <55491388+KumoLiu@users.noreply.github.com> Date: Wed, 11 Dec 2024 19:39:13 +0800 Subject: [PATCH] save names Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> --- modules/omniverse/omniverse_integration.ipynb | 85 ++++++++----------- modules/omniverse/utility.py | 45 ++++++---- 2 files changed, 67 insertions(+), 63 deletions(-) diff --git a/modules/omniverse/omniverse_integration.ipynb b/modules/omniverse/omniverse_integration.ipynb index e9e16f867..e545fe380 100644 --- a/modules/omniverse/omniverse_integration.ipynb +++ b/modules/omniverse/omniverse_integration.ipynb @@ -75,19 +75,19 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "MONAI version: 1.4.0+19.gb1e915c3\n", + "MONAI version: 1.4.1rc1\n", "Numpy version: 1.24.4\n", - "Pytorch version: 2.5.0a0+e000cf0ad9.nv24.10\n", - "MONAI flags: HAS_EXT = True, USE_COMPILED = False, USE_META_DICT = False\n", - "MONAI rev id: b1e915c323a8065cfe9e92de3013476f2f67c1b2\n", - "MONAI __file__: /opt/monai/monai/__init__.py\n", + "Pytorch version: 2.5.0a0+872d972e41.nv24.08\n", + "MONAI flags: HAS_EXT = False, USE_COMPILED = False, USE_META_DICT = False\n", + "MONAI rev id: e604d1841fe60c0ffb6978ae4116535ca8d8f34f\n", + "MONAI __file__: /workspace/Code/MONAI/monai/__init__.py\n", "\n", "Optional dependencies:\n", "Pytorch Ignite version: 0.4.11\n", @@ -105,7 +105,7 @@ "pandas version: 2.2.2\n", "einops version: 0.8.0\n", "transformers version: 4.40.2\n", - "mlflow version: 2.18.0\n", + "mlflow version: 2.17.2\n", "pynrrd version: 1.1.1\n", "clearml version: 1.16.5\n", "\n", @@ -122,7 +122,7 @@ "\n", "import vtk\n", "import vtkmodules\n", - "from ipyvtklink.viewer import ViewInteractiveWidget\n", + "# from ipyvtklink.viewer import ViewInteractiveWidget\n", "\n", "from utility import convert_to_mesh, convert_mesh_to_usd\n", "\n", @@ -146,7 +146,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -184,31 +184,18 @@ "name": "stdout", "output_type": "stream", "text": [ - "2024-12-05 06:15:11,403 - INFO - --- input summary of monai.bundle.scripts.download ---\n", - "2024-12-05 06:15:11,403 - INFO - > name: 'maisi_ct_generative'\n", - "2024-12-05 06:15:11,404 - INFO - > bundle_dir: '/workspace/Data'\n", - "2024-12-05 06:15:11,404 - INFO - > source: 'monaihosting'\n", - "2024-12-05 06:15:11,404 - INFO - > remove_prefix: 'monai_'\n", - "2024-12-05 06:15:11,405 - INFO - > progress: True\n", - "2024-12-05 06:15:11,405 - INFO - ---\n", + "2024-12-11 11:31:31,904 - INFO - --- input summary of monai.bundle.scripts.download ---\n", + "2024-12-11 11:31:31,905 - INFO - > name: 'maisi_ct_generative'\n", + "2024-12-11 11:31:31,905 - INFO - > bundle_dir: '/workspace/Data'\n", + "2024-12-11 11:31:31,905 - INFO - > source: 'monaihosting'\n", + "2024-12-11 11:31:31,906 - INFO - > remove_prefix: 'monai_'\n", + "2024-12-11 11:31:31,906 - INFO - > progress: True\n", + "2024-12-11 11:31:31,906 - INFO - ---\n", "\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "maisi_ct_generative_v0.4.5.zip: 13.0GB [09:25, 24.6MB/s] \n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2024-12-05 06:25:02,608 - INFO - Downloaded: /workspace/Data/maisi_ct_generative_v0.4.5.zip\n", - "2024-12-05 06:25:02,615 - INFO - Expected md5 is None, skip md5 check for file /workspace/Data/maisi_ct_generative_v0.4.5.zip.\n", - "2024-12-05 06:25:02,616 - INFO - Writing into directory: /workspace/Data.\n" + "\n", + "2024-12-11 11:31:32,611 - INFO - Expected md5 is None, skip md5 check for file /workspace/Data/maisi_ct_generative_v0.4.5.zip.\n", + "2024-12-11 11:31:32,612 - INFO - File exists: /workspace/Data/maisi_ct_generative_v0.4.5.zip, skipped downloading.\n", + "2024-12-11 11:31:32,612 - INFO - Writing into directory: /workspace/Data.\n" ] } ], @@ -235,19 +222,19 @@ "name": "stdout", "output_type": "stream", "text": [ - "2024-12-05 08:14:54,771 - INFO - Setting logging properties based on config: /workspace/Data/maisi_ct_generative/configs/logging.conf.\n", - "2024-12-05 08:14:54,772 - py.warnings - WARNING - Detected deprecated name 'optional_packages_version' in configuration file, replacing with 'required_packages_version'.\n", + "2024-12-11 11:32:14,010 - INFO - Setting logging properties based on config: /workspace/Data/maisi_ct_generative/configs/logging.conf.\n", + "2024-12-11 11:32:14,011 - py.warnings - WARNING - Detected deprecated name 'optional_packages_version' in configuration file, replacing with 'required_packages_version'.\n", "\n", - "2024-12-05 08:14:54,783 - INFO - --- input summary of monai.bundle.scripts.run ---\n", - "2024-12-05 08:14:54,784 - INFO - > workflow_type: 'inference'\n", - "2024-12-05 08:14:54,784 - INFO - > bundle_root: '/workspace/Data/maisi_ct_generative'\n", - "2024-12-05 08:14:54,784 - INFO - > output_size_xy: 256\n", - "2024-12-05 08:14:54,784 - INFO - > output_size_z: 256\n", - "2024-12-05 08:14:54,785 - INFO - > spacing_xy: 1.5\n", - "2024-12-05 08:14:54,785 - INFO - > spacing_z: 1.5\n", - "2024-12-05 08:14:54,785 - INFO - > autoencoder_def#num_splits: 16\n", - "2024-12-05 08:14:54,785 - INFO - > mask_generation_autoencoder_def#num_splits: 16\n", - "2024-12-05 08:14:54,786 - INFO - ---\n", + "2024-12-11 11:32:14,021 - INFO - --- input summary of monai.bundle.scripts.run ---\n", + "2024-12-11 11:32:14,022 - INFO - > workflow_type: 'inference'\n", + "2024-12-11 11:32:14,022 - INFO - > bundle_root: '/workspace/Data/maisi_ct_generative'\n", + "2024-12-11 11:32:14,022 - INFO - > output_size_xy: 256\n", + "2024-12-11 11:32:14,022 - INFO - > output_size_z: 256\n", + "2024-12-11 11:32:14,022 - INFO - > spacing_xy: 1.5\n", + "2024-12-11 11:32:14,023 - INFO - > spacing_z: 1.5\n", + "2024-12-11 11:32:14,023 - INFO - > autoencoder_def#num_splits: 16\n", + "2024-12-11 11:32:14,023 - INFO - > mask_generation_autoencoder_def#num_splits: 16\n", + "2024-12-11 11:32:14,023 - INFO - ---\n", "\n", "\n" ] @@ -440,6 +427,7 @@ " )\n", " orig_seg = pre_trans({\"label\": input_nii_path})[\"label\"]\n", " all_organ = np.zeros_like(orig_seg, dtype=np.uint8)\n", + " all_label_values = {}\n", "\n", " save_trans = SaveImage(output_ext=\"nii.gz\", output_dtype=np.uint8)\n", " for j, (organ_name, label_val) in enumerate(labels.items(), start=1):\n", @@ -462,6 +450,7 @@ " smoothing_factor=0.5,\n", " reduction_ratio=0.0,\n", " )\n", + " all_label_values[j] = organ_name\n", "\n", " all_organ_filename = os.path.join(output_nii_path, \"all_organs\")\n", " save_trans(all_organ[None], meta_data=orig_seg.meta, filename=all_organ_filename)\n", @@ -469,7 +458,7 @@ " f\"{all_organ_filename}.nii.gz\",\n", " output_obj_path,\n", " \"all_organs.gltf\",\n", - " label_value=list(range(1, 18)),\n", + " label_value=all_label_values,\n", " smoothing_factor=0.6,\n", " reduction_ratio=0.0,\n", " )\n", @@ -593,7 +582,7 @@ ], "metadata": { "kernelspec": { - "display_name": "base", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -607,7 +596,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.20" + "version": "3.10.12" } }, "nbformat": 4, diff --git a/modules/omniverse/utility.py b/modules/omniverse/utility.py index d05354670..a031b680e 100644 --- a/modules/omniverse/utility.py +++ b/modules/omniverse/utility.py @@ -37,12 +37,13 @@ def convert_to_mesh( reader.SetFileName(segmentation_path) reader.Update() - label_values = [label_value] if isinstance(label_value, int) else label_value - if len(label_values) > 1: + label_values = {label_value: None} if isinstance(label_value, int) else label_value + if len(label_values.keys()) > 1: renderer = vtk.vtkRenderer() render_window = vtk.vtkRenderWindow() render_window.AddRenderer(renderer) - for i in label_values: + actor_metadata = {} + for i, name in label_values.items(): # Step 2: Create Closed Surface Representation using vtkDiscreteFlyingEdges3D flying_edges = vtk.vtkDiscreteFlyingEdges3D() flying_edges.SetInputConnection(reader.GetOutputPort()) @@ -82,28 +83,21 @@ def convert_to_mesh( smoothing_filter.NormalizeCoordinatesOn() smoothing_filter.Update() - # Step 5: Generate normals for better shading - # normals_filter = vtk.vtkPolyDataNormals() - # normals_filter.SetInputConnection(smoothing_filter.GetOutputPort()) - # normals_filter.SplittingOff() - # normals_filter.ConsistencyOn() - # normals_filter.Update() - - # Step 6: Decimate the mesh further + # Step 5: Decimate the mesh further decimation = vtk.vtkQuadricDecimation() decimation.SetInputConnection(smoothing_filter.GetOutputPort()) decimation.SetTargetReduction(0.9) # 90% reduction, the same as slicer decimation.VolumePreservationOn() decimation.Update() - # Step 7: Generate normals for better shading + # Step 6: Generate normals for better shading decimatedNormals = vtk.vtkPolyDataNormals() decimatedNormals.SetInputConnection(decimation.GetOutputPort()) decimatedNormals.SplittingOff() decimatedNormals.ConsistencyOn() decimatedNormals.Update() - # Step 8: convert to LPS + # Step 7: convert to LPS ras2lps = vtk.vtkMatrix4x4() ras2lps.SetElement(0, 0, -1) ras2lps.SetElement(1, 1, -1) @@ -114,7 +108,7 @@ def convert_to_mesh( transformer.SetInputConnection(decimatedNormals.GetOutputPort()) transformer.Update() - if len(label_values) > 1: + if len(label_values.keys()) > 1: mapper = vtk.vtkPolyDataMapper() mapper.SetInputData(transformer.GetOutput()) actor = vtk.vtkActor() @@ -128,10 +122,11 @@ def convert_to_mesh( vtk.vtkMath.HSVToRGB(colorHSV, colorRGB) actor.GetProperty().SetColor(colorRGB[0], colorRGB[1], colorRGB[2]) actor.GetProperty().SetInterpolationToGouraud() + actor_metadata[actor] = name renderer.AddActor(actor) output_filename = os.path.join(output_folder, filename) - if len(label_values) > 1: + if len(label_values.keys()) > 1: exporter = vtk.vtkGLTFExporter() exporter.SetFileName(output_filename) exporter.SetRenderWindow(render_window) @@ -146,6 +141,26 @@ def convert_to_mesh( writer.Write() print(f"Mesh successfully exported to {output_filename}") + + if len(label_values.keys()) > 1: + # Modify GLTF to include actor names + with open(output_filename, "r") as f: + gltf_data = json.load(f) + + # Iterate over actors and add names to GLTF nodes + actors = renderer.GetActors() + actors.InitTraversal() + + for i, node in enumerate(gltf_data.get("nodes", [])): + actor = actors.GetNextActor() + if actor in actor_metadata: + node["name"] = actor_metadata[actor] + + # Save the modified GLTF file + modified_output_filename = output_filename.replace(".gltf", "_modified.gltf") + with open(modified_output_filename, "w") as f: + json.dump(gltf_data, f, indent=2) + print(f"Modified GLTF successfully exported to {modified_output_filename}") def convert_mesh_to_usd(input_file, output_file):