Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow writing complex images and attempt at imagearray writer #21

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion +gadgetron/+external/+readers/read_image_array.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

function meta = read_meta_container(socket)
size = read(socket, 1, 'uint64');
meta = arrayfun(@(~) gadgetron.external.readers.read_string(socket, 'uint64'), 1:size);
meta = arrayfun(@(~) gadgetron.external.readers.read_string(socket, 'uint64'), 1:size,'UniformOutput',false);
end

function waveform = read_optional_waveforms(socket)
Expand Down
89 changes: 40 additions & 49 deletions +gadgetron/+external/+writers/encode_acquisition_headers.m
Original file line number Diff line number Diff line change
@@ -1,57 +1,48 @@
function bytes = encode_acquisition_headers(headers)

nheaders = numel(headers.version);

bytes = zeros(340, nheaders, 'int8');

function bytes = byte_view(array)
bytes = typecast(reshape(array, 1, nheaders, []), 'int8');
function bytes = byte_view(array, width)
bytes = reshape( ...
typecast(squeeze(reshape(array, 1, [])), 'int8'), ...
width, [] ...
);
end

bytes( 1: 2, :) = byte_view(headers.version);
end



function headers = decode_acquisition_headers(bytes, dims)
% Convert from a byte array to a ISMRMRD AcquisitionHeaders
% This conforms to the memory layout of the C-struct

bytes = reshape(bytes, 340, []);
N = size(bytes, 2);
dims = num2cell(dims);

headers.version = reshape(typecast(reshape(bytes( 1: 2, :), 1, 2 * N), 'uint16'), dims{:}, 1); % First unsigned int indicates the version %
headers.flags = reshape(typecast(reshape(bytes( 3: 10, :), 1, 8 * N), 'uint64'), dims{:}, 1); % bit field with flags %
headers.measurement_uid = reshape(typecast(reshape(bytes( 11: 14, :), 1, 4 * N), 'uint32'), dims{:}, 1); % Unique ID for the measurement %
headers.scan_counter = reshape(typecast(reshape(bytes( 15: 18, :), 1, 4 * N), 'uint32'), dims{:}, 1); % Current acquisition number in the measurement %
headers.acquisition_time_stamp = reshape(typecast(reshape(bytes( 19: 22, :), 1, 4 * N), 'uint32'), dims{:}, 1); % Acquisition clock %
headers.physiology_time_stamp = reshape(typecast(reshape(bytes( 23: 34, :), 1, 4 * 3 * N), 'uint32'), dims{:}, 3); % Physiology time stamps, e.g. ecg, breating, etc. %
headers.number_of_samples = reshape(typecast(reshape(bytes( 35: 36, :), 1, 2 * N), 'uint16'), dims{:}, 1); % Number of samples acquired %
headers.available_channels = reshape(typecast(reshape(bytes( 37: 38, :), 1, 2 * N), 'uint16'), dims{:}, 1); % Available coils %
headers.active_channels = reshape(typecast(reshape(bytes( 39: 40, :), 1, 2 * N), 'uint16'), dims{:}, 1); % Active coils on current acquisiton %
headers.channel_mask = reshape(typecast(reshape(bytes( 41:168, :), 1, 8 * 16 * N), 'uint64'), dims{:}, 16); % Mask to indicate which channels are active. Support for 1024 channels %
headers.discard_pre = reshape(typecast(reshape(bytes( 169:170, :), 1, 2 * N), 'uint16'), dims{:}, 1); % Samples to be discarded at the beginning of acquisition %
headers.discard_post = reshape(typecast(reshape(bytes( 171:172, :), 1, 2 * N), 'uint16'), dims{:}, 1); % Samples to be discarded at the end of acquisition %
headers.center_sample = reshape(typecast(reshape(bytes( 173:174, :), 1, 2 * N), 'uint16'), dims{:}, 1); % Sample at the center of k-space %
headers.encoding_space_ref = reshape(typecast(reshape(bytes( 175:176, :), 1, 2 * N), 'uint16'), dims{:}, 1); % Reference to an encoding space, typically only one per acquisition %
headers.trajectory_dimensions = reshape(typecast(reshape(bytes( 177:178, :), 1, 2 * N), 'uint16'), dims{:}, 1); % Indicates the dimensionality of the trajectory vector (0 means no trajectory) %
headers.sample_time_us = reshape(typecast(reshape(bytes( 179:182, :), 1, 4 * N), 'single'), dims{:}, 1); % Time between samples in micro seconds, sampling BW %
headers.position = reshape(typecast(reshape(bytes( 183:194, :), 1, 4 * 3 * N), 'single'), dims{:}, 3); % Three-dimensional spatial offsets from isocenter %
headers.read_dir = reshape(typecast(reshape(bytes( 195:206, :), 1, 4 * 3 * N), 'single'), dims{:}, 3); % Directional cosines of the readout/frequency encoding %
headers.phase_dir = reshape(typecast(reshape(bytes( 207:218, :), 1, 4 * 3 * N), 'single'), dims{:}, 3); % Directional cosines of the phase encoding %
headers.slice_dir = reshape(typecast(reshape(bytes( 219:230, :), 1, 4 * 3 * N), 'single'), dims{:}, 3); % Directional cosines of the slice %
headers.patient_table_position = reshape(typecast(reshape(bytes( 231:242, :), 1, 4 * 3 * N), 'single'), dims{:}, 3); % Patient table off-center %
headers.kspace_encode_step_1 = reshape(typecast(reshape(bytes( 243:244, :), 1, 2 * N), 'uint16'), dims{:}, 1); % phase encoding line number %
headers.kspace_encode_step_2 = reshape(typecast(reshape(bytes( 245:246, :), 1, 2 * N), 'uint16'), dims{:}, 1); % partition encodning number %
headers.average = reshape(typecast(reshape(bytes( 247:248, :), 1, 2 * N), 'uint16'), dims{:}, 1); % signal average number %
headers.slice = reshape(typecast(reshape(bytes( 249:250, :), 1, 2 * N), 'uint16'), dims{:}, 1); % imaging slice number %
headers.contrast = reshape(typecast(reshape(bytes( 251:252, :), 1, 2 * N), 'uint16'), dims{:}, 1); % echo number in multi-echo %
headers.phase = reshape(typecast(reshape(bytes( 253:254, :), 1, 2 * N), 'uint16'), dims{:}, 1); % cardiac phase number %
headers.repetition = reshape(typecast(reshape(bytes( 255:256, :), 1, 2 * N), 'uint16'), dims{:}, 1); % dynamic number for dynamic scanning %
headers.set = reshape(typecast(reshape(bytes( 257:258, :), 1, 2 * N), 'uint16'), dims{:}, 1); % flow encoding set %
headers.segment = reshape(typecast(reshape(bytes( 259:260, :), 1, 2 * N), 'uint16'), dims{:}, 1); % segment number for segmented acquisition %
headers.user = reshape(typecast(reshape(bytes( 261:276, :), 1, 2 * 8 * N), 'uint16'), dims{:}, 8); % Free user parameters %
headers.user_int = reshape(typecast(reshape(bytes( 277:308, :), 1, 4 * 8 * N), 'int32' ), dims{:}, 8); % Free user parameters %
headers.user_float = reshape(typecast(reshape(bytes( 309:340, :), 1, 4 * 8 * N), 'single'), dims{:}, 8); % Free user parameters %
bytes( 1: 2, :) = byte_view(headers.version, 2);
bytes( 3: 10, :) = byte_view(headers.flags, 8);
bytes( 11: 14, :) = byte_view(headers.measurement_uid, 4);
bytes( 15: 18, :) = byte_view(headers.scan_counter, 4);
bytes( 19: 22, :) = byte_view(headers.acquisition_time_stamp, 4);
bytes( 23: 34, :) = byte_view(headers.physiology_time_stamp(:), 4*3);
bytes( 35: 36, :) = byte_view(headers.number_of_samples, 2);
bytes( 37: 38, :) = byte_view(headers.available_channels, 2);
bytes( 39: 40, :) = byte_view(headers.active_channels, 2);
bytes( 41: 168, :) = byte_view(headers.channel_mask, 8*16);
bytes( 169: 170, :) = byte_view(headers.discard_pre, 2);
bytes( 171: 172, :) = byte_view(headers.discard_post, 2);
bytes( 173: 174, :) = byte_view(headers.center_sample, 2);
bytes( 175: 176, :) = byte_view(headers.encoding_space_ref, 2);
bytes( 177: 178, :) = byte_view(headers.trajectory_dimensions, 2);
bytes( 179: 182, :) = byte_view(headers.sample_time_us, 4);
bytes( 183: 194, :) = byte_view(headers.position, 4*3);
bytes( 195: 206, :) = byte_view(headers.read_dir, 4*3);
bytes( 207: 218, :) = byte_view(headers.phase_dir, 4*3);
bytes( 219: 230, :) = byte_view(headers.slice_dir, 4*3);
bytes( 231: 242, :) = byte_view(headers.patient_table_position, 4*3);
bytes( 243: 244, :) = byte_view(headers.kspace_encode_step_1, 2);
bytes( 245: 246, :) = byte_view(headers.kspace_encode_step_2, 2);
bytes( 247: 248, :) = byte_view(headers.average, 2);
bytes( 249: 250, :) = byte_view(headers.slice, 2);
bytes( 251: 252, :) = byte_view(headers.contrast, 2);
bytes( 253: 254, :) = byte_view(headers.phase, 2);
bytes( 255: 256, :) = byte_view(headers.repetition, 2);
bytes( 257: 258, :) = byte_view(headers.set, 2);
bytes( 259: 260, :) = byte_view(headers.segment, 2);
bytes( 261: 276, :) = byte_view(headers.user, 2*8);
bytes( 277: 308, :) = byte_view(headers.user_int, 4*8);
bytes( 309: 340, :) = byte_view(headers.user_float, 4*8);

bytes = reshape(bytes, 1, []);
end
5 changes: 5 additions & 0 deletions +gadgetron/+external/+writers/write_acq_header_array.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function write_acq_header_array(socket, headers)
gadgetron.external.writers.write_vector(socket, size(headers.version));
write(socket, gadgetron.external.writers.encode_acquisition_headers(headers));
end

10 changes: 9 additions & 1 deletion +gadgetron/+external/+writers/write_image.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,13 @@ function write_attribute_string(socket, attribute_string)
end

function write_data(socket, data)
write(socket, reshape(data, 1, []));
if(isreal(data))
output = data;
else
output = zeros([2, size(data)], 'like',data);
output(1, :) = real(data(:));
output(2, :) = imag(data(:));
end
write(socket, reshape(output, 1, []));
% write(socket, reshape(data, 1, []));
end
3 changes: 2 additions & 1 deletion +gadgetron/+external/Connection.m
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ function add_writer(self, writer)
writers = gadgetron.lib.list( ...
gadgetron.external.writers.write_image, ...
gadgetron.external.writers.write_acquisition, ...
gadgetron.external.writers.write_waveform ...
gadgetron.external.writers.write_waveform, ...
gadgetron.external.writers.write_image_array ...
);
end

Expand Down