Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions cpp/mrd/hdf5/protocols.cc
Original file line number Diff line number Diff line change
Expand Up @@ -738,17 +738,39 @@ namespace {
}

[[maybe_unused]] H5::EnumType GetImageTypeHdf5Ddl() {
H5::EnumType t(H5::PredType::NATIVE_INT32);
int32_t i = 1;
H5::EnumType t(H5::PredType::NATIVE_UINT64);
uint64_t i = 1ULL;
t.insert("magnitude", &i);
i = 2;
i = 2ULL;
t.insert("phase", &i);
i = 3;
i = 3ULL;
t.insert("real", &i);
i = 4;
i = 4ULL;
t.insert("imag", &i);
i = 5;
i = 5ULL;
t.insert("complex", &i);
i = 6ULL;
t.insert("rgbaMap", &i);
i = 7ULL;
t.insert("spinDensityMap", &i);
i = 8ULL;
t.insert("t1Map", &i);
i = 9ULL;
t.insert("t2Map", &i);
i = 10ULL;
t.insert("t2starMap", &i);
i = 11ULL;
t.insert("adcMap", &i);
i = 12ULL;
t.insert("b0Map", &i);
i = 13ULL;
t.insert("b1Map", &i);
i = 14ULL;
t.insert("sensitivityMap", &i);
i = 15ULL;
t.insert("gfactorMap", &i);
i = 16ULL;
t.insert("userMap", &i);
return t;
}

Expand Down
44 changes: 44 additions & 0 deletions cpp/mrd/ndjson/protocols.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2542,6 +2542,17 @@ std::unordered_map<std::string, mrd::ImageType> const __ImageType_values = {
{"real", mrd::ImageType::kReal},
{"imag", mrd::ImageType::kImag},
{"complex", mrd::ImageType::kComplex},
{"rgbaMap", mrd::ImageType::kRgbaMap},
{"spinDensityMap", mrd::ImageType::kSpinDensityMap},
{"t1Map", mrd::ImageType::kT1Map},
{"t2Map", mrd::ImageType::kT2Map},
{"t2starMap", mrd::ImageType::kT2starMap},
{"adcMap", mrd::ImageType::kAdcMap},
{"b0Map", mrd::ImageType::kB0Map},
{"b1Map", mrd::ImageType::kB1Map},
{"sensitivityMap", mrd::ImageType::kSensitivityMap},
{"gfactorMap", mrd::ImageType::kGfactorMap},
{"userMap", mrd::ImageType::kUserMap},
};
} //namespace

Expand All @@ -2562,6 +2573,39 @@ void to_json(ordered_json& j, mrd::ImageType const& value) {
case mrd::ImageType::kComplex:
j = "complex";
break;
case mrd::ImageType::kRgbaMap:
j = "rgbaMap";
break;
case mrd::ImageType::kSpinDensityMap:
j = "spinDensityMap";
break;
case mrd::ImageType::kT1Map:
j = "t1Map";
break;
case mrd::ImageType::kT2Map:
j = "t2Map";
break;
case mrd::ImageType::kT2starMap:
j = "t2starMap";
break;
case mrd::ImageType::kAdcMap:
j = "adcMap";
break;
case mrd::ImageType::kB0Map:
j = "b0Map";
break;
case mrd::ImageType::kB1Map:
j = "b1Map";
break;
case mrd::ImageType::kSensitivityMap:
j = "sensitivityMap";
break;
case mrd::ImageType::kGfactorMap:
j = "gfactorMap";
break;
case mrd::ImageType::kUserMap:
j = "userMap";
break;
default:
using underlying_type = typename std::underlying_type<mrd::ImageType>::type;
j = static_cast<underlying_type>(value);
Expand Down
2 changes: 1 addition & 1 deletion cpp/mrd/protocols.cc

Large diffs are not rendered by default.

23 changes: 17 additions & 6 deletions cpp/mrd/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -866,12 +866,23 @@ struct ImageFlags : yardl::BaseFlags<uint64_t, ImageFlags> {
static const ImageFlags kLastInSet;
};

enum class ImageType {
kMagnitude = 1,
kPhase = 2,
kReal = 3,
kImag = 4,
kComplex = 5,
enum class ImageType : uint64_t {
kMagnitude = 1ULL,
kPhase = 2ULL,
kReal = 3ULL,
kImag = 4ULL,
kComplex = 5ULL,
kRgbaMap = 6ULL,
kSpinDensityMap = 7ULL,
kT1Map = 8ULL,
kT2Map = 9ULL,
kT2starMap = 10ULL,
kAdcMap = 11ULL,
kB0Map = 12ULL,
kB1Map = 13ULL,
kSensitivityMap = 14ULL,
kGfactorMap = 15ULL,
kUserMap = 16ULL,
};

template <typename Y>
Expand Down
2 changes: 1 addition & 1 deletion matlab/toolbox/+mrd/+binary/ImageHeaderSerializer.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
field_serializers{14} = yardl.binary.OptionalSerializer(yardl.binary.Uint32Serializer);
field_serializers{15} = yardl.binary.OptionalSerializer(yardl.binary.Uint64Serializer);
field_serializers{16} = yardl.binary.VectorSerializer(yardl.binary.Uint64Serializer);
field_serializers{17} = yardl.binary.EnumSerializer('mrd.ImageType', @mrd.ImageType, yardl.binary.Int32Serializer);
field_serializers{17} = yardl.binary.EnumSerializer('mrd.ImageType', @mrd.ImageType, yardl.binary.Uint64Serializer);
field_serializers{18} = yardl.binary.OptionalSerializer(yardl.binary.Uint32Serializer);
field_serializers{19} = yardl.binary.OptionalSerializer(yardl.binary.Uint32Serializer);
field_serializers{20} = yardl.binary.VectorSerializer(yardl.binary.Int32Serializer);
Expand Down
33 changes: 33 additions & 0 deletions matlab/toolbox/+mrd/ImageType.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,39 @@
function v = COMPLEX
v = mrd.ImageType(5);
end
function v = RGBA_MAP
v = mrd.ImageType(6);
end
function v = SPIN_DENSITY_MAP
v = mrd.ImageType(7);
end
function v = T1_MAP
v = mrd.ImageType(8);
end
function v = T2_MAP
v = mrd.ImageType(9);
end
function v = T2STAR_MAP
v = mrd.ImageType(10);
end
function v = ADC_MAP
v = mrd.ImageType(11);
end
function v = B0_MAP
v = mrd.ImageType(12);
end
function v = B1_MAP
v = mrd.ImageType(13);
end
function v = SENSITIVITY_MAP
v = mrd.ImageType(14);
end
function v = GFACTOR_MAP
v = mrd.ImageType(15);
end
function v = USER_MAP
v = mrd.ImageType(16);
end

function z = zeros(varargin)
elem = mrd.ImageType(0);
Expand Down
2 changes: 1 addition & 1 deletion matlab/toolbox/+mrd/MrdWriterBase.m

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion model/mrd_image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ ImageFlags: !flags
lastInSet: 0x8000

ImageType: !enum
base: uint64
values:
magnitude: 1
phase: 2
real: 3
imag: 4
complex: 5
rgbaMap: 6 # a uint32 image in which channel dimension is R, G, B, alpha

ImageData<Y>: !array
items: Y
Expand Down Expand Up @@ -61,7 +63,7 @@ ImageHeader: !record
repetition: uint?
# Sets of different preparation, e.g. flow encoding, diffusion weighting
set: uint?
# Clock time stamp (e.g. nanoseconds since midnight)
# Clock time stamp (e.g. nanoseconds since midnight)
acquisitionTimeStampNs: uint64?
# Time stamps relative to physiological triggering in nanoseconds, e.g. ECG, pulse oximetry, respiratory
physiologyTimeStampNs: uint64*
Expand Down
31 changes: 29 additions & 2 deletions model/mrd_intermediate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,35 @@ ImageArray: !record
meta: ImageMeta[loc, s, n]
waveforms: WaveformUint32*

# change to record and data field to array
# Generic header
# ndarray store all data
# any structure call metadata
# nadarray header with speicfied
# string for dimension
# high level description=array type
# user comment as string
# NDarray keep as field
# meta field attachted to all arrays
# computed fields:
ArrayType: !enum
base: uint64
values:
spinDensityMap: 1 # in mol/m^3
t1Map: 2 # in s
t2Map: 3 # in s
t2starMap: 4 # in s
adcMap: 5 # in s/m^2
b0Map: 6 # in Hz (offset from Image.head.measurementFreq[0])
b1Map: 7 # in rad/s/V, channel dimension is xmit channels
sensitivityMap: 8 # in Vm^3/mol, channel dimension is rcv channels
gfactorMap: 9 # unaccelerated SNR/(accelerated SNR * sqrt of acceleration factor)
userMap: 10 # custom image type with description at ImageMeta

Array<T>: !array
items: T
NDArray: !record
fields:
data: Array<T>
type: ArrayType

ArrayComplexFloat: Array<complexfloat>

2 changes: 1 addition & 1 deletion python/mrd/binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ def read(self, stream: _binary.CodedInputStream) -> Header:

class ImageHeaderSerializer(_binary.RecordSerializer[ImageHeader]):
def __init__(self) -> None:
super().__init__([("flags", _binary.EnumSerializer(_binary.uint64_serializer, ImageFlags)), ("measurement_uid", _binary.uint32_serializer), ("field_of_view", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("position", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("col_dir", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("line_dir", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("slice_dir", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("patient_table_position", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("average", _binary.OptionalSerializer(_binary.uint32_serializer)), ("slice", _binary.OptionalSerializer(_binary.uint32_serializer)), ("contrast", _binary.OptionalSerializer(_binary.uint32_serializer)), ("phase", _binary.OptionalSerializer(_binary.uint32_serializer)), ("repetition", _binary.OptionalSerializer(_binary.uint32_serializer)), ("set", _binary.OptionalSerializer(_binary.uint32_serializer)), ("acquisition_time_stamp_ns", _binary.OptionalSerializer(_binary.uint64_serializer)), ("physiology_time_stamp_ns", _binary.VectorSerializer(_binary.uint64_serializer)), ("image_type", _binary.EnumSerializer(_binary.int32_serializer, ImageType)), ("image_index", _binary.OptionalSerializer(_binary.uint32_serializer)), ("image_series_index", _binary.OptionalSerializer(_binary.uint32_serializer)), ("user_int", _binary.VectorSerializer(_binary.int32_serializer)), ("user_float", _binary.VectorSerializer(_binary.float32_serializer))])
super().__init__([("flags", _binary.EnumSerializer(_binary.uint64_serializer, ImageFlags)), ("measurement_uid", _binary.uint32_serializer), ("field_of_view", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("position", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("col_dir", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("line_dir", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("slice_dir", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("patient_table_position", _binary.FixedNDArraySerializer(_binary.float32_serializer, (3,))), ("average", _binary.OptionalSerializer(_binary.uint32_serializer)), ("slice", _binary.OptionalSerializer(_binary.uint32_serializer)), ("contrast", _binary.OptionalSerializer(_binary.uint32_serializer)), ("phase", _binary.OptionalSerializer(_binary.uint32_serializer)), ("repetition", _binary.OptionalSerializer(_binary.uint32_serializer)), ("set", _binary.OptionalSerializer(_binary.uint32_serializer)), ("acquisition_time_stamp_ns", _binary.OptionalSerializer(_binary.uint64_serializer)), ("physiology_time_stamp_ns", _binary.VectorSerializer(_binary.uint64_serializer)), ("image_type", _binary.EnumSerializer(_binary.uint64_serializer, ImageType)), ("image_index", _binary.OptionalSerializer(_binary.uint32_serializer)), ("image_series_index", _binary.OptionalSerializer(_binary.uint32_serializer)), ("user_int", _binary.VectorSerializer(_binary.int32_serializer)), ("user_float", _binary.VectorSerializer(_binary.float32_serializer))])

def write(self, stream: _binary.CodedOutputStream, value: ImageHeader) -> None:
if isinstance(value, np.void):
Expand Down
13 changes: 12 additions & 1 deletion python/mrd/ndjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -2406,6 +2406,17 @@ def from_json_to_numpy(self, json_object: object) -> np.void:
"real": ImageType.REAL,
"imag": ImageType.IMAG,
"complex": ImageType.COMPLEX,
"rgbaMap": ImageType.RGBA_MAP,
"spinDensityMap": ImageType.SPIN_DENSITY_MAP,
"t1Map": ImageType.T1_MAP,
"t2Map": ImageType.T2_MAP,
"t2starMap": ImageType.T2STAR_MAP,
"adcMap": ImageType.ADC_MAP,
"b0Map": ImageType.B0_MAP,
"b1Map": ImageType.B1_MAP,
"sensitivityMap": ImageType.SENSITIVITY_MAP,
"gfactorMap": ImageType.GFACTOR_MAP,
"userMap": ImageType.USER_MAP,
}
image_type_value_to_name_map = {v: n for n, v in image_type_name_to_value_map.items()}

Expand All @@ -2427,7 +2438,7 @@ def __init__(self) -> None:
self._set_converter = _ndjson.OptionalConverter(_ndjson.uint32_converter)
self._acquisition_time_stamp_ns_converter = _ndjson.OptionalConverter(_ndjson.uint64_converter)
self._physiology_time_stamp_ns_converter = _ndjson.VectorConverter(_ndjson.uint64_converter)
self._image_type_converter = _ndjson.EnumConverter(ImageType, np.int32, image_type_name_to_value_map, image_type_value_to_name_map)
self._image_type_converter = _ndjson.EnumConverter(ImageType, np.uint64, image_type_name_to_value_map, image_type_value_to_name_map)
self._image_index_converter = _ndjson.OptionalConverter(_ndjson.uint32_converter)
self._image_series_index_converter = _ndjson.OptionalConverter(_ndjson.uint32_converter)
self._user_int_converter = _ndjson.VectorConverter(_ndjson.int32_converter)
Expand Down
2 changes: 1 addition & 1 deletion python/mrd/protocols.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion python/mrd/tools/ismrmrd_to_mrd.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ def convert_image(ismrmrd_img: ismrmrd.Image) -> mrd.StreamItem:
# If parsing fails, skip meta
pass

data = ismrmrd_img.data
data = ismrmrd_img.data[:, np.newaxis] # Add singleton frequency dimension as 5th dimension
dtype = data.dtype
if dtype == np.uint16:
img = mrd.Image[np.uint16](head=out_head, data=data.astype(np.uint16), meta=meta)
Expand Down
6 changes: 3 additions & 3 deletions python/mrd/tools/mrd_to_ismrmrd.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ def convert_image(mrd_img) -> ismrmrd.Image:
mrd_head = mrd_img.head
data = mrd_img.data

# Get dimensions: data is (channels, z, y, x)
# Get dimensions: data is (channels, z, y, x, frequency) drop freq dimension
channels = data.shape[0]
z = data.shape[1]
y = data.shape[2]
Expand Down Expand Up @@ -585,9 +585,9 @@ def convert_image(mrd_img) -> ismrmrd.Image:
# Create ISMRMRD image, resize it, and set header
img = ismrmrd.Image()
# Note: resize signature is (nc, nz, ny, nx) - same order as MRD!
img.resize(channels, z, y, x)
img.resize(channels, z, y, x, )
img.setHead(head)
img.data[:] = data
img.data[:] = data[:, np.newaxis] # Drop frequency dimension

# Set attribute_string if present
if attribute_string:
Expand Down
13 changes: 12 additions & 1 deletion python/mrd/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,17 @@ class ImageType(yardl.OutOfRangeEnum):
REAL = 3
IMAG = 4
COMPLEX = 5
RGBA_MAP = 6
SPIN_DENSITY_MAP = 7
T1_MAP = 8
T2_MAP = 9
T2STAR_MAP = 10
ADC_MAP = 11
B0_MAP = 12
B1_MAP = 13
SENSITIVITY_MAP = 14
GFACTOR_MAP = 15
USER_MAP = 16

ImageData = npt.NDArray[Y_NP]

Expand Down Expand Up @@ -2170,7 +2181,7 @@ def _mk_get_dtype():
dtype_map.setdefault(WaveformInformationType, np.dtype([('waveform_name', np.dtype(np.object_)), ('waveform_type', get_dtype(WaveformType)), ('user_parameters', get_dtype(UserParametersType))], align=True))
dtype_map.setdefault(Header, np.dtype([('version', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.int64))], align=True)), ('subject_information', np.dtype([('has_value', np.dtype(np.bool_)), ('value', get_dtype(SubjectInformationType))], align=True)), ('study_information', np.dtype([('has_value', np.dtype(np.bool_)), ('value', get_dtype(StudyInformationType))], align=True)), ('measurement_information', np.dtype([('has_value', np.dtype(np.bool_)), ('value', get_dtype(MeasurementInformationType))], align=True)), ('acquisition_system_information', np.dtype([('has_value', np.dtype(np.bool_)), ('value', get_dtype(AcquisitionSystemInformationType))], align=True)), ('experimental_conditions', get_dtype(ExperimentalConditionsType)), ('encoding', np.dtype(np.object_)), ('sequence_parameters', np.dtype([('has_value', np.dtype(np.bool_)), ('value', get_dtype(SequenceParametersType))], align=True)), ('user_parameters', np.dtype([('has_value', np.dtype(np.bool_)), ('value', get_dtype(UserParametersType))], align=True)), ('waveform_information', np.dtype(np.object_))], align=True))
dtype_map.setdefault(ImageFlags, np.dtype(np.uint64))
dtype_map.setdefault(ImageType, np.dtype(np.int32))
dtype_map.setdefault(ImageType, np.dtype(np.uint64))
dtype_map.setdefault(ImageHeader, np.dtype([('flags', get_dtype(ImageFlags)), ('measurement_uid', np.dtype(np.uint32)), ('field_of_view', np.dtype(np.float32), (3,)), ('position', np.dtype(np.float32), (3,)), ('col_dir', np.dtype(np.float32), (3,)), ('line_dir', np.dtype(np.float32), (3,)), ('slice_dir', np.dtype(np.float32), (3,)), ('patient_table_position', np.dtype(np.float32), (3,)), ('average', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.uint32))], align=True)), ('slice', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.uint32))], align=True)), ('contrast', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.uint32))], align=True)), ('phase', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.uint32))], align=True)), ('repetition', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.uint32))], align=True)), ('set', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.uint32))], align=True)), ('acquisition_time_stamp_ns', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.uint64))], align=True)), ('physiology_time_stamp_ns', np.dtype(np.object_)), ('image_type', get_dtype(ImageType)), ('image_index', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.uint32))], align=True)), ('image_series_index', np.dtype([('has_value', np.dtype(np.bool_)), ('value', np.dtype(np.uint32))], align=True)), ('user_int', np.dtype(np.object_)), ('user_float', np.dtype(np.object_))], align=True))
dtype_map.setdefault(ImageMetaValue, np.dtype(np.object_))
dtype_map.setdefault(Image, lambda type_args: np.dtype([('head', get_dtype(ImageHeader)), ('data', np.dtype(np.object_)), ('meta', np.dtype(np.object_))], align=True))
Expand Down
Loading