Volumes (DICOM)
In this tutorial we will focus on working with volumes using Supervisely SDK.
You will learn how to:
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 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 os
from dotenv import load_dotenv
from pprint import pprint
import supervisely as sly
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()
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 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
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
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
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}")
Setanonymize=True
if you want to anonymize DICOM series and hidePatientID
andPatientName
fields.
Output:
# DICOM volume has been uploaded to Supervisely with ID: 18630608
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]


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]
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
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
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.
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 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 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)
✅ 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
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)
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)
save_dir = "src/download/"
slice_path = os.path.join(save_dir, 'slice.nrrd')
nrrd.write(slice_path, image_np, index_order='C')
Last modified 2mo ago