Skip to content

Commit

Permalink
Merge pull request #19 from NVIDIA/release_0_2_0
Browse files Browse the repository at this point in the history
Release 0.2.0. See CHANGELOG.md for changes.
  • Loading branch information
AndreasHeumann authored Mar 29, 2022
2 parents 921c7b7 + 7fcef8b commit 2a50325
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
*.nii.gz filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ notebooks/HelloWorld.jpg
notebooks/data/bonsai/*.nhdr
notebooks/data/bonsai/*.raw
notebooks/data/pancreas/*.raw
notebooks/data/OpenSlide/*.tiff
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# clara-viz 0.2.0 (March 29 2022)

## Features

* Add support for rendering multi resolution images used in digital pathology

## Security

* Update Jupyter widget Java code packages to fix vulnerabilities

## Bug Fixes

* Error when using a widget with a renderer using a numpy array (https://github.com/NVIDIA/clara-viz/issues/18)

## Documentation

* Fix typo for `image_type` parameter in the sample code of the readme file
* Extended documentation, added multi resolution image rendering

# clara-viz 0.1.4 (Feb 15 2022)

## Security
Expand Down
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# Clara Viz

NVIDIA Clara Viz is a platform for visualization of 2D/3D medical imaging data. It enables building
applications that leverage powerful volumetric visualization using CUDA-based ray tracing.

<img src="images/rendering.gif" alt="Rendering" style="display: block; margin-left: auto; margin-right: auto; width: 50%"/>
NVIDIA Clara Viz is a platform for visualization of 2D/3D medical imaging data. It enables building applications
that leverage powerful volumetric visualization using CUDA-based ray tracing. It also allows viewing of multi resolution
images used in digital pathology.

<div style="display: flex; width: 100%; justify-content: center;">
<div style="padding: 5px; height: 200px;">
<img src="images/rendering.gif" alt="Volume Rendering"/>
</div>
<div style="padding: 5px; height: 200px;">
<img src="images/pathology.gif" alt="Pathology"/>
</div>
</div>

Clara Viz offers a Python Wrapper for rapid experimentation. It also includes a collection of
visual widgets for performing interactive medical image visualization in Jupyter Lab notebooks.
Expand Down Expand Up @@ -76,7 +84,7 @@ input = input.reshape((512, 256, 256))
renderer = clara.viz.core.Renderer(input)

# render to a raw numpy array
output = renderer.render_image(1024, 768, image_type=clara.viz.core.RAW_RGB_U8_DEPTH_U8)
output = renderer.render_image(1024, 768, image_type=clara.viz.core.ImageType.RAW_RGB_U8_DEPTH_U8)
rgb_data = np.asarray(output)[:, :, :3]

# show with PIL
Expand Down Expand Up @@ -112,4 +120,4 @@ is used in this project.

Apache-2.0 License (see `LICENSE` file).

Copyright (c) 2020-2021, NVIDIA CORPORATION.
Copyright (c) 2020-2021, NVIDIA CORPORATION.
3 changes: 3 additions & 0 deletions images/pathology.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/rendering.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 13 additions & 10 deletions notebooks/Interactive_widget.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"data_definition = DataDefinition()\n",
"data_definition.append('data/bonsai/' + header_filename, 'DXYZ')\n",
"\n",
"print('Density volume {}x{}x{}'.format(data_definition.arrays[0].array.shape[0], data_definition.arrays[0].array.shape[1], data_definition.arrays[0].array.shape[2]))\n",
"print('Density volume {}x{}x{}'.format(data_definition.arrays[0].levels[0].shape[0], data_definition.arrays[0].levels[0].shape[1], data_definition.arrays[0].levels[0].shape[2]))\n",
"\n",
"data_definition.settings = settings"
]
Expand All @@ -54,7 +54,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create a widget and select the data definition, then display the widget"
"## Create a widget and select the data definition"
]
},
{
Expand All @@ -66,15 +66,14 @@
"from clara.viz.widgets import Widget\n",
"\n",
"widget = Widget()\n",
"widget.select_data_definition(data_definition)\n",
"display(widget)"
"widget.select_data_definition(data_definition)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Change render settings\n",
"## Display the widget and change render settings\n",
"Interact from ipywidgets offers us a simple way to interactively control values with a callback function. In this case change the transfer functions (the mapping from the density of the source to the opacity of the visualization).\n",
"All render settings are exposed by the `settings` property of the widget. Settings are applied by calling the `set_settings` method."
]
Expand All @@ -87,18 +86,22 @@
},
"outputs": [],
"source": [
"from ipywidgets import interact, fixed, FloatSlider\n",
"from ipywidgets import interactive, fixed, FloatSlider, Box, VBox\n",
"\n",
"def set_range_min(index, range_min, range_max):\n",
"def set_range(index, range_min, range_max):\n",
" if (range_max <= range_min):\n",
" range_max = range_min + 0.01\n",
" widget.settings['TransferFunction']['components'][index]['range']['min'] = range_min\n",
" widget.settings['TransferFunction']['components'][index]['range']['max'] = range_max\n",
" widget.set_settings()\n",
"\n",
" \n",
"# create one slider for each transfer function component\n",
"range_sliders = []\n",
"for index in range(len(widget.settings['TransferFunction']['components'])):\n",
" interact(set_range_min, index=fixed(index), range_min=FloatSlider(min=0.0, max=0.99, step=0.01, value=widget.settings['TransferFunction']['components'][index]['range']['min']),\n",
" range_max=FloatSlider(min=0.01, max=1.0, step=0.01, value=widget.settings['TransferFunction']['components'][index]['range']['max']))"
" range_sliders.append(interactive(set_range, index=fixed(index), range_min=FloatSlider(min=0.0, max=0.99, step=0.01, value=widget.settings['TransferFunction']['components'][index]['range']['min']),\n",
" range_max=FloatSlider(min=0.01, max=1.0, step=0.01, value=widget.settings['TransferFunction']['components'][index]['range']['max'])))\n",
"\n",
"display(Box([widget, VBox(range_sliders)]))"
]
}
],
Expand Down
77 changes: 77 additions & 0 deletions notebooks/Multi_level_image.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "6d2047f5",
"metadata": {},
"source": [
"# Clara Viz Interactive Rendering of Multi Level Images\n",
"This notebook shows how to load a volume dataset using the DataDefinition class append method. The append method uses ITK to load the dataset from disk.\n",
"The rendering settings are loaded from a JSON file.\n",
"Then the Clara Viz widget is used to display an interactive view of the data."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "02848184-502d-4fba-9127-a4dd73779330",
"metadata": {},
"outputs": [],
"source": [
"# The DataDefinition class is using cuCIM to load the data files, make sure cuCim is available\n",
"!python3 -c \"import cucim\" || python3 -m pip install cucim\n",
"\n",
"from os.path import exists\n",
"from urllib.request import urlretrieve\n",
"\n",
"file_name = \"data/OpenSlide/CMU-1.tiff\"\n",
"if not exists(file_name):\n",
" print(f'Downloading {file_name}')\n",
" urlretrieve(\"http://openslide.cs.cmu.edu/download/openslide-testdata/Generic-TIFF/CMU-1.tiff\", file_name)"
]
},
{
"cell_type": "markdown",
"id": "0dab6d05",
"metadata": {},
"source": [
"## Create and display the widget\n",
"The data to be rendered needs to be defined. Clara Viz provides a support class called `DataDefinition` which supports loading medical data formats and serves as a container for the data."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fc5db1ae",
"metadata": {},
"outputs": [],
"source": [
"from clara.viz.core import DataDefinition\n",
"from clara.viz.widgets import Widget\n",
"\n",
"display(Widget(data_definition=DataDefinition(file_name)))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
2 changes: 1 addition & 1 deletion notebooks/Render_image.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"# define the input data, the renderer expects data in RIP order (Right Inferior Posterior) and the permute_axes and flip_axes values are choosen to transform\n",
"# from the source coordinate system to the renderer coordinate system.\n",
"arrays = []\n",
"arrays.append(clara.viz.core.Array(array=input, dimension_order=\"DXYZ\", permute_axes=[0,3,1,2], flip_axes=[False, True, False, False], element_size=[1.0, 1.16, 1.0, 1.0]))\n",
"arrays.append(clara.viz.core.Array(levels=[input], dimension_order=\"DXYZ\", permute_axes=[0,3,1,2], flip_axes=[False, True, False, False], element_sizes=[[1.0, 1.16, 1.0, 1.0]]))\n",
"renderer.set_arrays(arrays)\n",
"\n",
"# deduce reasonable settings from the defined data\n",
Expand Down
13 changes: 12 additions & 1 deletion notebooks/Slice_rendering.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,23 @@
"outputs": [],
"source": [
"from clara.viz.widgets import Widget\n",
"from ipywidgets import interactive, Dropdown, Box, VBox\n",
"\n",
"# switch to slice view, default is cinematic rendering\n",
"data_definition.settings['Views'][0]['cameraName'] = 'Top'\n",
"data_definition.settings['Views'][0]['mode'] = 'SLICE_SEGMENTATION'\n",
"\n",
"display(Widget(data_definition=data_definition))"
"# create the widget\n",
"widget = Widget(data_definition=data_definition)\n",
"\n",
"# dropdown callback function\n",
"def set_camera(camera_name):\n",
" widget.settings['Views'][0]['cameraName'] = camera_name\n",
" widget.set_settings()\n",
"\n",
"# create a dropdown to select the view and display it alognside to the widget\n",
"camera_dropdown = interactive(set_camera, camera_name=Dropdown(options=['Top', 'Front', 'Right'], value=widget.settings['Views'][0]['cameraName'], description='View'))\n",
"display(Box([widget, camera_dropdown]))"
]
}
],
Expand Down
7 changes: 7 additions & 0 deletions notebooks/data/OpenSlide/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Data source

Data is copied from https://openslide.cs.cmu.edu/download/openslide-testdata/Generic-TIFF/.

## License

https://creativecommons.org/publicdomain/zero/1.0/

0 comments on commit 2a50325

Please sign in to comment.