"""Extract diffusion MRI parameters.
"""
# Copyright (c) 2013-2024 Erling Andersen, Haukeland University Hospital, Bergen, Norway
import numpy as np
import pandas as pd
from pydicom import Dataset
from typing import SupportsFloat
from ..series import Series
Number = type[SupportsFloat]
[docs]
def get_g_vectors(img):
"""Get diffusion gradient vectors
Extracting diffusion gradient vectors has been tested on MRI data from some major vendors.
Args:
img (imagedata.Series): Series object.
Returns:
pd.DataFrame: Diffusion gradient vectors, columns b, z, y, x.
Raises:
IndexError: when no gradient vector is present in dataset.
Examples:
>>> from imagedata import Series
>>> from imagedata.apps.diffusion import get_g_vectors
>>> im = Series('data', 'b', opts={'accept_duplicate_tag': 'True'})
>>> g = get_g_vectors(im)
>>> print(g)
b z y x
0 0 NaN NaN NaN
1 500 -0.706399 0.000000 0.707814
2 500 -0.706399 0.000000 -0.707814
3 500 -0.706399 -0.707814 0.000000
4 500 0.707814 -0.706399 0.000000
5 500 0.000000 -0.707107 0.707107
6 500 0.000000 -0.707107 -0.707107
7 1000 -0.706752 0.000000 0.707461
8 1000 -0.706752 0.000000 -0.707461
9 1000 -0.706753 -0.707460 0.000000
10 1000 0.707460 -0.706754 0.000000
11 1000 0.001414 -0.707106 0.707106
12 1000 0.001414 -0.707106 -0.707106
13 2500 -0.706824 0.000000 0.707390
"""
def get_DICOM_g_vector(ds):
# Attempt to address standard DICOM attributes
return ds['DiffusionGradientOrientation'].value
def get_Siemens_g_vector(ds):
block = ds.private_block(0x0019, 'SIEMENS MR HEADER')
return block[0x0e].value
def get_GEMS_g_vector(ds):
block = ds.private_block(0x0019, 'GEMS_ACQU_01')
return [block[0xbb].value, block[0xbc].value, block[0xbd].value]
_v = []
# Extract pydicom dataset for first slice and each tag
_dwi_weighted = False
for tag in range(img.shape[0]):
_b = get_b_value(img, tag)
_dwi_weighted = _dwi_weighted or not np.isnan(_b)
_G = [np.nan, np.nan, np.nan]
_ds: Dataset = img.dicomTemplate
for _method in [get_DICOM_g_vector, get_Siemens_g_vector, get_GEMS_g_vector]:
try:
_G = _method(_ds)
break
except KeyError:
pass
_v.append({'b': _b, 'z': _G[2], 'y': _G[1], 'x': _G[0]})
if _dwi_weighted:
return pd.DataFrame(_v)
else:
raise IndexError('No b values found in dataset')
[docs]
def get_b_value(img: Series) -> float:
"""Get diffusion b value
Extracting diffusion b value has been tested on MRI data from some major vendors.
Args:
img (imagedata.Series): Series object.
Returns:
float: b value. Returns NaN when no b value is present in dataset.
"""
# Extract pydicom dataset for given slice and tag
_ds: Dataset = img.dicomTemplate
return get_ds_b_value(_ds)
[docs]
def get_ds_b_value(ds: Dataset) -> float:
"""Get diffusion b value from Dataset
Setting diffusion b value has been tested on MRI data from some major vendors.
Args:
ds: Input dataset
Returns:
b value
"""
def get_DICOM_b_value(_ds):
# Attempt to address standard DICOM attribute
return _ds['DiffusionBValue'].value
def get_Siemens_b_value(_ds):
block = _ds.private_block(0x0019, 'SIEMENS MR HEADER')
return block[0x0c].value
def get_GEMS_b_value(_ds):
block = _ds.private_block(0x0043, 'GEMS_PARM_01')
return block[0x39].value
for _method in [get_DICOM_b_value, get_Siemens_b_value, get_GEMS_b_value]:
try:
return float(_method(ds))
except (KeyError, IndexError):
pass
raise IndexError('Cannot get b value')
[docs]
def set_ds_b_value(ds: Dataset, value: Number):
"""Set diffusion b value
Setting diffusion b value has been tested on MRI data from some major vendors.
Args:
ds (pydicom.Dataset): Dataset
value: b value
"""
def set_DICOM_b_value(_ds, _value):
# Attempt to address standard DICOM attribute
_ds.DiffusionBValue = _value
def set_Siemens_b_value(_ds, _value):
block = _ds.private_block(0x0019, 'SIEMENS MR HEADER')
block[0x0c].value = _value
def set_GEMS_b_value(_ds, _value):
block = _ds.private_block(0x0043, 'GEMS_PARM_01')
block[0x39].value = _value
for _method in [set_DICOM_b_value, set_Siemens_b_value, set_GEMS_b_value]:
try:
_method(ds, value)
return
except (KeyError, IndexError):
pass
raise IndexError('Cannot set b value')