chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1 @@
|
||||
dataset/**
|
||||
@@ -0,0 +1,63 @@
|
||||
<!--[metadata]
|
||||
title = "Dicom MRI"
|
||||
tags = ["Tensor", "MRI", "DICOM"]
|
||||
thumbnail = "https://static.rerun.io/dicom-mri/d5a434f92504e8dda8af6c7f4eded2a9d662c991/480w.png"
|
||||
thumbnail_dimensions = [480, 480]
|
||||
channel = "main"
|
||||
include_in_manifest = true
|
||||
-->
|
||||
|
||||
Visualize a [DICOM](https://en.wikipedia.org/wiki/DICOM) MRI scan. This demonstrates the flexible tensor slicing capabilities of the Rerun viewer.
|
||||
|
||||
<picture data-inline-viewer="examples/dicom_mri">
|
||||
<source media="(max-width: 480px)" srcset="https://static.rerun.io/dicom_mri/e39f34a1b1ddd101545007f43a61783e1d2e5f8e/480w.png">
|
||||
<source media="(max-width: 768px)" srcset="https://static.rerun.io/dicom_mri/e39f34a1b1ddd101545007f43a61783e1d2e5f8e/768w.png">
|
||||
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/dicom_mri/e39f34a1b1ddd101545007f43a61783e1d2e5f8e/1024w.png">
|
||||
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/dicom_mri/e39f34a1b1ddd101545007f43a61783e1d2e5f8e/1200w.png">
|
||||
<img src="https://static.rerun.io/dicom_mri/e39f34a1b1ddd101545007f43a61783e1d2e5f8e/full.png" alt="">
|
||||
</picture>
|
||||
|
||||
## Used Rerun types
|
||||
[`Tensor`](https://www.rerun.io/docs/reference/types/archetypes/tensor), [`TextDocument`](https://www.rerun.io/docs/reference/types/archetypes/text_document)
|
||||
|
||||
## Background
|
||||
Digital Imaging and Communications in Medicine (DICOM) serves as a technical standard for the digital storage and transmission of medical images. In this instance, an MRI scan is visualized using Rerun.
|
||||
|
||||
## Logging and visualizing with Rerun
|
||||
|
||||
The visualizations in this example were created with just the following line.
|
||||
```python
|
||||
rr.log("tensor", rr.Tensor(voxels_volume_u16, dim_names=["right", "back", "up"]))
|
||||
```
|
||||
|
||||
A `numpy.array` named `voxels_volume_u16` representing volumetric MRI intensities with a shape of `(512, 512, 512)`.
|
||||
To visualize this data effectively in Rerun, we can log the `numpy.array` as [`Tensor`](https://www.rerun.io/docs/reference/types/archetypes/tensor) to the `tensor` entity.
|
||||
|
||||
In the Rerun Viewer you can also inspect the data in detail. The `dim_names` provided in the above call to `rr.log` help to
|
||||
give semantic meaning to each axis. After selecting the tensor view, you can adjust various settings in the Blueprint
|
||||
settings on the right-hand side. For example, you can adjust the color map, the brightness, which dimensions to show as
|
||||
an image and which to select from, and more.
|
||||
|
||||
## Run the code
|
||||
To run this example, make sure you have the Rerun repository checked out and the latest SDK installed:
|
||||
```bash
|
||||
pip install --upgrade rerun-sdk # install the latest Rerun SDK
|
||||
git clone git@github.com:rerun-io/rerun.git # Clone the repository
|
||||
cd rerun
|
||||
git checkout latest # Check out the commit matching the latest SDK release
|
||||
```
|
||||
|
||||
Install the necessary libraries specified in the requirements file:
|
||||
```bash
|
||||
pip install -e examples/python/dicom_mri
|
||||
```
|
||||
To experiment with the provided example, simply execute the main Python script:
|
||||
```bash
|
||||
python -m dicom_mri # run the example
|
||||
```
|
||||
|
||||
If you wish to customize it, explore additional features, or save it, use the CLI with the `--help` option for guidance:
|
||||
|
||||
```bash
|
||||
python -m dicom_mri --help
|
||||
```
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Example using MRI scan data in the DICOM format."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import os
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Final
|
||||
|
||||
import dicom_numpy
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
import pydicom as dicom
|
||||
import requests
|
||||
|
||||
import rerun as rr # pip install rerun-sdk
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
|
||||
DESCRIPTION = """
|
||||
# Dicom MRI
|
||||
This example visualizes an MRI scan using Rerun.
|
||||
|
||||
The visualization of the data consists of just the following line
|
||||
```python
|
||||
rr.log("tensor", rr.Tensor(voxels_volume_u16, dim_names=["right", "back", "up"]))
|
||||
```
|
||||
|
||||
The full source code for this example is available
|
||||
[on GitHub](https://github.com/rerun-io/rerun/blob/latest/examples/python/dicom_mri).
|
||||
"""
|
||||
|
||||
DATASET_DIR: Final = Path(os.path.dirname(__file__)) / "dataset"
|
||||
DATASET_URL: Final = "https://storage.googleapis.com/rerun-example-datasets/dicom.zip"
|
||||
|
||||
|
||||
def extract_voxel_data(
|
||||
dicom_files: Iterable[Path],
|
||||
) -> tuple[npt.NDArray[np.int16], npt.NDArray[np.float32]]:
|
||||
slices = [dicom.read_file(f) for f in dicom_files] # type: ignore[misc]
|
||||
voxel_ndarray, ijk_to_xyz = dicom_numpy.combine_slices(slices)
|
||||
|
||||
return voxel_ndarray, ijk_to_xyz
|
||||
|
||||
|
||||
def list_dicom_files(dir: Path) -> Iterable[Path]:
|
||||
for path, _, files in os.walk(dir):
|
||||
for f in files:
|
||||
if f.endswith(".dcm"):
|
||||
yield Path(path) / f
|
||||
|
||||
|
||||
def read_and_log_dicom_dataset(dicom_files: Iterable[Path]) -> None:
|
||||
rr.log("description", rr.TextDocument(DESCRIPTION, media_type=rr.MediaType.MARKDOWN), static=True)
|
||||
|
||||
voxels_volume, _ = extract_voxel_data(dicom_files)
|
||||
|
||||
# the data is i16, but in range [0, 536].
|
||||
voxels_volume_u16: npt.NDArray[np.uint16] = np.require(voxels_volume, np.uint16)
|
||||
|
||||
rr.log("tensor", rr.Tensor(voxels_volume_u16, dim_names=["right", "back", "up"]))
|
||||
|
||||
|
||||
def ensure_dataset_downloaded() -> Iterable[Path]:
|
||||
dicom_files = list(list_dicom_files(DATASET_DIR))
|
||||
if dicom_files:
|
||||
return dicom_files
|
||||
print("downloading dataset…")
|
||||
os.makedirs(DATASET_DIR.absolute(), exist_ok=True)
|
||||
resp = requests.get(DATASET_URL, stream=True)
|
||||
z = zipfile.ZipFile(io.BytesIO(resp.content))
|
||||
z.extractall(DATASET_DIR.absolute())
|
||||
|
||||
return list_dicom_files(DATASET_DIR)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Example using MRI scan data in the DICOM format.")
|
||||
rr.script_add_args(parser)
|
||||
args = parser.parse_args()
|
||||
rr.script_setup(args, "rerun_example_dicom_mri")
|
||||
dicom_files = ensure_dataset_downloaded()
|
||||
read_and_log_dicom_dataset(dicom_files)
|
||||
rr.script_teardown(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,20 @@
|
||||
[project]
|
||||
name = "dicom_mri"
|
||||
version = "0.1.0"
|
||||
# requires-python = "<3.12"
|
||||
readme = "README.md"
|
||||
dependencies = [
|
||||
"dicom_numpy==0.6.2",
|
||||
"numpy",
|
||||
"pydicom==2.4.5",
|
||||
"requests>=2.31,<3",
|
||||
"rerun-sdk",
|
||||
"types-requests>=2.31,<3",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
dicom_mri = "dicom_mri:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
Reference in New Issue
Block a user