Volumes (DICOM)
Introduction
In this tutorial we will focus on working with volumes using Supervisely SDK.
You will learn how to:
📗 Everything you need to reproduce this tutorial is on GitHub: source code and demo data.
How to debug this tutorial
Step 1. Prepare ~/supervisely.env
file with credentials. Learn more here.
Step 2. Clone repository with source code and demo data and create Virtual Environment.
git clone https://github.com/supervisely-ecosystem/tutorial-volume.git
cd tutorial-volume
./create_venv.sh
Step 3. Open repository directory in Visual Studio Code.
code -r .
Step 4. Change workspace ID in local.env
file by copying the ID from the context menu of the workspace.
WORKSPACE_ID=654 # ⬅️ change value

Step 5. Download sample volumes
Step 6. Place downloaded files in the project structure as shown below:
tutorial-volume
├── .vscode
├── src
│ ├── upload
│ │ ├── MRHead_dicom <-- sample dicom files
│ │ │ ├── 000000.dcm
│ │ │ ├── 000001.dcm
│ │ │ └── ...
│ │ └── nrrd
│ │ ├── CTACardio.nrrd <-- sample NRRD
│ │ ├── CTChest.nrrd <-- sample NRRD
│ │ └── MRHead.nrrd <-- sample NRRD
│ └── main.py
├── .gitignore
├── create_venv.sh
├── local.env
├── README.md
└── requirements.txt
Step 7. Start debugging src/main.py
.
Import libraries
import os
from dotenv import load_dotenv
from pprint import pprint
import supervisely as sly
Init API client
First, we load environment variables with credentials and init API for communicating with Supervisely Instance.
if sly.is_development():
load_dotenv("local.env")
load_dotenv(os.path.expanduser("~/supervisely.env"))
api = sly.Api()
Get variables from environment
In this tutorial, you will need an workspace ID that you can get from environment variables. Learn more here
workspace_id = sly.env.workspace_id()
Create new project and dataset
Create new project with ProjectType.VOLUMES
type.
Source code:
project = api.project.create(
workspace_id,
"Volume tutorial",
ProjectType.VOLUMES,
change_name_if_conflict=True,
)
print(f"Project ID: {project.id}")
Output:
# Project ID: 16342
Create new dataset.
Source code:
dataset = api.dataset.create(project.id, "dataset_1")
print(f"Dataset ID: {dataset.id}")
Output:
# Dataset ID: 54698
Upload volumes from local directory to Supervisely
Upload NRRD format volume
Source code:
local_path = "src/upload/nrrd/MRHead.nrrd"
nrrd_info = api.volume.upload_nrrd_serie_path(
dataset.id,
"MRHead.nrrd",
local_path,
)
print(f'"{nrrd_info.name}" volume uploaded to Supervisely with ID:{nrrd_info.id}')
Output:
# "NRRD_1.nrrd" volume uploaded to Supervisely with ID:18562981
Upload volume as NumPy array
Source code:
np_volume, meta = sly.volume.read_nrrd_serie_volume_np(local_path)
nrrd_info_np = api.volume.upload_np(
dataset.id,
"MRHead_np.nrrd",
np_volume,
meta,
)
print(f"Volume uploaded as NumPy array to Supervisely with ID:{nrrd_info_np.id}")
Output:
# Volume uploaded as NumPy array to Supervisely with ID:18562982
Upload DICOM series from local directory
Inspect you local directory and collect all dicom series.
Source code:
dicom_dir_name = "src/upload/MRHead_dicom/"
series_infos = sly.volume.inspect_dicom_series(root_dir=dicom_dir_name)
Upload DICOM series from local directory to Supervisely platform.
Source code:
for serie_id, files in series_infos.items():
item_path = files[0]
name = f"{sly.fs.get_file_name(path=item_path)}.nrrd"
dicom_info = api.volume.upload_dicom_serie_paths(
dataset_id=dataset.id,
name=name,
paths=files,
anonymize=True,
)
print(f"DICOM volume has been uploaded to Supervisely with ID: {dicom_info.id}")
Set
anonymize=True
if you want to anonymize DICOM series and hidePatientID
andPatientName
fields.
Output:
# DICOM volume has been uploaded to Supervisely with ID: 18630608
Upload list of volumes from local directory
Source code:
local_dir_name = "src/upload/nrrd/"
all_nrrd_names = os.listdir(local_dir_name)
names = [f"1_{name}" for name in all_nrrd_names]
paths = [os.path.join(local_dir_name, name) for name in all_nrrd_names]
volume_infos = api.volume.upload_nrrd_series_paths(dataset.id, names, paths)
print(f"All volumes has been uploaded with IDs: {[x.id for x in volume_infos]}")
Output:
# All volumes has been uploaded with IDs: [18630605, 18630606, 18630607]

Now you can explore and label it in Supervisely labeling tool:

Get volume info from Supervisely
Get list of volumes infos from current dataset
Source code:
volume_infos = api.volume.get_list(dataset.id)
volumes_ids = [x.id for x in volume_infos]
print(f"List of volumes`s IDs: {volumes_ids}")
Output:
# List of volumes`s IDs: [18562986, 18562987, 18562988, 18562989, 18562990]
Get single volume info by id
Source code:
volume_id = volume_infos[0].id
volume_info_by_id = api.volume.get_info_by_id(id=volume_id)
print(f"Volume name:", volume_info_by_id.name)
Output:
# Volume name: NRRD_1.nrrd
Get single volume info by name
Source code:
volume_info_by_name = api.volume.get_info_by_name(dataset.id, name="MRHead.nrrd")
print(f"Volume name:", volume_info_by_name.name)
Output:
# Volume name: NRRD_1.nrrd
Download volume from Supervisely to local directory
Source code:
volume_id = volume_infos[0].id
volume_info = api.volume.get_info_by_id(id=volume_id)
download_dir_name = "src/download/"
path = os.path.join(download_dir_name, volume_info.name)
if os.path.exists(path):
os.remove(path)
api.volume.download_path(volume_info.id, path)
if os.path.exists(path):
print(f"Volume (ID {volume_info.id}) successfully downloaded.")
Output:
# Volume (ID 18630603) successfully downloaded.
Get volume slices from local directory
Read NRRD file from local directory
Read NRRD file from local directory and get meta and volume (as NumPy array).
Source code:
# read NRRD file from local directory
nrrd_path = os.path.join(download_dir_name, "MRHead.nrrd")
volume_np, meta = sly.volume.read_nrrd_serie_volume_np(nrrd_path)
pprint(meta)
Output:
# {
# 'ACS': 'RAS',
# 'channelsCount': 1,
# 'dimensionsIJK': {'x': 130, 'y': 256, 'z': 256},
# 'directions': (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
# 'intensity': {'max': 279.0, 'min': 0.0},
# 'origin': (-86.64489746093749, -121.07139587402344, -138.21430206298828),
# 'rescaleIntercept': 0,
# 'rescaleSlope': 1,
# 'spacing': (1.2999954223632812, 1.0, 1.0),
# 'windowCenter': 139.5,
# 'windowWidth': 279.0
# }
Get slices from volume
Get slices from current volume. In this example we will get sagittal slices.
Source code:
slices = {}
dimension = volume_np.shape[0] # change index: 0 - sagittal, 1 - coronal, 2 - axial
for batch in sly.batched(list(range(dimension))):
for i in batch:
if i >= dimension:
continue
pixel_data = volume_np[i, :, :] # sagittal
# pixel_data = volume_np[:, i, :] # coronal
# pixel_data = volume_np[:, :, i] # axial
slices[i] = pixel_data
print(f"{len(slices.keys())} slices has been received from current volume.")
Output:
# 130 slices has been received from current volume.
Download slice from Supervisely
Download slice as NumPy from Supervisely by ID
Source code:
slice_index = 60
image_np = api.volume.download_slice_np(
volume_id=volume_id,
slice_index=slice_index,
plane=sly.Plane.SAGITTAL,
)
print(f"Image downloaded as NumPy array. Image shape: {image_np.shape}")
Output:
# Image downloaded as NumPy array. Image shape: (256, 256, 3)
Save slice to local directory
✅ There is a built-in function supervisely.image.write
which reads file extension from path and saves image (slice) with the desired format in local directory.
Example:
import supervisely as sly
sly.image.write("folder/slice.nrrd", image_np) # save as NRRD
sly.image.write("folder/slice.jpg", image_np) # save as JPG
Save slice as NRRD
Recommended way to save slice as NRRD file to preserve image quality (pixel depth)
Source code:
# save slice as NRRD file
save_dir = "src/download/"
nrrd_slice_path = os.path.join(save_dir, 'slice.nrrd')
sly.image.write(nrrd_slice_path, image_np)
Save slice as JPG
Source code:
# save slice as jpg
save_dir = "src/download/"
image_slice_path = os.path.join(save_dir, 'slice.jpg')
sly.image.write(jpg_slice_path, image_np)
Note:
In case you save slice using nrrd
library, it is recommended to use C-order
indexing.
save_dir = "src/download/"
slice_path = os.path.join(save_dir, 'slice.nrrd')
nrrd.write(slice_path, image_np, index_order='C')
Last updated
Was this helpful?