Skip to content

Commit

Permalink
Merge pull request #774 from schorschinho/develop
Browse files Browse the repository at this point in the history
Update to version 2.7.0
  • Loading branch information
HJZollner authored Aug 15, 2024
2 parents f8738e7 + 92b5308 commit 765b30b
Show file tree
Hide file tree
Showing 14 changed files with 395 additions and 65 deletions.
5 changes: 4 additions & 1 deletion GUI/Osprey.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
%
% HISTORY:
% 2019-07-11: First version of the code.
%% Get version
VersionStruct = getCurrentVersion;

%% Check for available add-ons
[~,~] = osp_Toolbox_Check ('OspreyGUI',0);
%% Set up Layout
Expand All @@ -30,7 +33,7 @@
logoFcn = @()imread('osprey.png', 'BackgroundColor', gui.colormap.Background);
logoBanner = uiw.utility.loadIcon(logoFcn);
% Here the intro banner is created
gui.d = uiw.dialog.About('Name', 'Osprey','Version','2.6.0','Date', 'July 15, 2024',...
gui.d = uiw.dialog.About('Name', 'Osprey','Version',VersionStruct.Version,'Date', VersionStruct.Date,...
'Timeout', 3,'CustomText', 'Osprey is provided by Johns Hopkins University.',...
'ContactInfo', 'gabamrs@gmail.com','LogoCData', logoBanner);

Expand Down
4 changes: 2 additions & 2 deletions GUI/osp_Toolbox_Check.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
% HISTORY:
% 2020-05-15: First version of the code.
%% % 1. SAVE OSPREY VERSION%%%
%%% 1. SAVE OSPREY VERSION%%%
OspreyVersion = 'Osprey 2.6.0';
VersionStruct = getCurrentVersion;
OspreyVersion = ['Osprey ' VersionStruct.Version];
fprintf(['Timestamp %s ' OspreyVersion ' ' Module '\n'], datestr(now,'mmmm dd, yyyy HH:MM:SS'));
hasSPM = 1; % For the compiled GUI
%% % 2. GET SPMPATH AND TOOLBOXES%%%
Expand Down
4 changes: 2 additions & 2 deletions docs_source/05-tutorial_cmd.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ MRSCont = OspreyJob('Path/To/Job/File');
MRSCont will now contain the options and file locations for your data, as specified in the job file. Next, the data can be loaded:

```octave
MRSCont = OspreyLoad(MRScont);
MRSCont = OspreyLoad(MRSCont);
```

The substructure, MRSCont.raw, now contains the raw MRS data, as extracted from their native format. We may now preprocess these data:
Expand Down Expand Up @@ -56,4 +56,4 @@ At any point during a command-line analysis, it is possible to visualize the dat

```octave
OspreyGUI(MRSCont);
```
```
23 changes: 22 additions & 1 deletion job/OspreyJob.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

%%% 1. INITIALISE DATA CONTAINER WITH DEFAULT SETTINGS
[MRSCont] = OspreySettings;
VersionStruct = getCurrentVersion;

%%% 2. CHECK JOB INPUT FILE FORMAT %%%
[~,~,ext] = fileparts(jobFile);
Expand Down Expand Up @@ -210,6 +211,16 @@
fprintf('Adding macromolecule and lipid basis functions to the fit (default). Please indicate otherwise in the csv-file or the GUI \n');
MRSCont.opts.fit.fitMM = 1;
end
if isfield(jobStruct,'RelaxationAtlas')
MRSCont.opts.quantify.RelaxationAtlas = jobStruct(1).RelaxationAtlas;
else
MRSCont.opts.quantify.RelaxationAtlas = 0;
end
if isfield(jobStruct,'RelaxationAtlasAge')
MRSCont.opts.quantify.RelaxationAtlasAge = jobStruct(1).RelaxationAtlasAge;
else
MRSCont.opts.quantify.RelaxationAtlasAge = 0;
end
if isfield(jobStruct,'deface')
MRSCont.opts.img.deface = jobStruct.deface;
else
Expand Down Expand Up @@ -397,6 +408,16 @@
else
MRSCont.opts.fit.fitMM = 1;
end
if isfield(jobStruct,'RelaxationAtlas')
MRSCont.opts.quantify.RelaxationAtlas = jobStruct.RelaxationAtlas;
else
MRSCont.opts.quantify.RelaxationAtlas = 0;
end
if isfield(jobStruct,'RelaxationAtlasAge')
MRSCont.opts.quantify.RelaxationAtlasAge = jobStruct.RelaxationAtlasAge;
else
MRSCont.opts.quantify.RelaxationAtlasAge = 0;
end
if isfield(jobStruct,'basisSet')
if isfolder(jobStruct.basisSet)
opts.fit.basissetFolder = jobStruct.basisSet;
Expand Down Expand Up @@ -781,7 +802,7 @@
%%% 7. SET FLAGS AND VERSION %%%
MRSCont.flags.didJob = 1;
MRSCont.loadedJob = jobFile;
MRSCont.ver.Osp = 'Osprey 2.6.0';
MRSCont.ver.Osp = ['Osprey ' VersionStruct.Version];


%%% 8. CHECK IF OUTPUT STRUCTURE ALREADY EXISTS IN OUTPUT FOLDER %%%
Expand Down
108 changes: 85 additions & 23 deletions libraries/FID-A/inputOutput/io_loadspec_dicom.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,97 @@
%Georg Oeltzschner, Johns Hopkins University 2019.
%
% USAGE:
% out=io_loadspec_dicom(folder);
%
% out=io_loadspec_dicom(source);
%
% DESCRIPTION:
% Loads a DICOM (.dcm, .ima) file into matlab structure format.
%
%
% INPUTS:
% filename = Name of a folder with DICOM (.dcm, .ima) data to load.
% source = Name of a folder (or file) with DICOM (.dcm, .ima) data to load.
%
% OUTPUTS:
% out = Input dataset in FID-A structure format.

function out=io_loadspec_dicom(folder);
function out=io_loadspec_dicom(source);

% If path to a .dcm is provided, then extract the folder location:
if ~isfolder(folder) && isfile(folder)
folder =fileparts(folder);
% ARC170724 : Source may be a folder, or an individual file. We later determine
% how this should be interpreted.
if ~isfolder(source) && isfile(source)
[folder,filename,ext] =fileparts(source);
requested_file=[filename ext];
else
folder=source;
requested_file=[];
end

% Create list of complete filenames (incl. path) in the folder
dirFolder = dir(folder);
filesInFolder = dirFolder(~[dirFolder.isdir]);
hidden = logical(ones(1,length(filesInFolder)));
for jj = 1:length(filesInFolder)
for jj = 1:length(filesInFolder)
if strcmp(filesInFolder(jj).name(1),'.')
hidden(jj) = 0;
end
end
filesInFolder = filesInFolder(hidden);%delete hidden files
filesInFolder = fullfile(folder, {filesInFolder.name});
filesInFolder = filesInFolder(hidden);%delete hidden files

if length(filesInFolder)==0
% No files survived. This will not end well.
error([ 'io_loadspec_dicom did not find any files in ' folder ])
end

requested_file_ix=find(strcmp(requested_file,{filesInFolder.name})); % NB, may be empty

if isfolder(folder)
filesInFolder = fullfile(folder, {filesInFolder.name});
else
% this can happen if the function is called with a wildcard, eg /path/to/abc*dcm
filesInFolder = fullfile(dirname(folder), {filesInFolder.name});
end

% ARC170724 : If a single file is specified (rather than a directory), check
% whether this file should be considered in isolation (pre-averaged data) or
% if it should be combined with other items in the folder. We do this by
% inspecting the Series Number header.

if ~isempty(requested_file_ix)
% check header of the first, last and requested items; if Series Number
% does not match, don't try to combine
check_header_ix = unique([1, requested_file_ix, length(filesInFolder) ]);
encountered_series_numbers = [];
encountered_problems = [];

for ix = check_header_ix
try
dh = dicominfo(filesInFolder{ix});
encountered_series_numbers(end+1) = dh.SeriesNumber;
catch
encountered_problems(end+1) = ix;
end
end

encountered_series_numbers=unique(encountered_series_numbers);

if any(encountered_problems == requested_file_ix)

warning([ 'io_loadspec_dicom could not determine SeriesNumber of the requested file: ' source ]);
% in this case, fall back on default behaviour

elseif length(encountered_series_numbers)>1 || length(encountered_problems)>0

% if we found more than one series, OR we found some unreadable files
% (probably non-DICOM), then just retain that one specific file the
% caller originally asked for

if length(encountered_problems)>0
warning([ 'io_loadspec_dicom encountered some non-DICOM data in ' source ]);
end

filesInFolder={source};
end

% in any other scenario, full back on the default behaviour
end

% Get the header of the first file to make some decisions.
DicomHeader = read_dcm_header(filesInFolder{1});
Expand All @@ -41,7 +103,7 @@
seqorig = DicomHeader.seqorig;
else
% deal with missing seqorig field for dicom data load on Siemens Minnesota
% sequences (Auerbach and Deelchand versions, VB17A & VE11C)
% sequences (Auerbach and Deelchand versions, VB17A & VE11C)
if contains(DicomHeader.sequenceFileName, 'slaser_dkd') %Deelchand/Oz
seqorig = 'CMRR';
elseif contains(DicomHeader.sequenceFileName, 'eja_svs') %Auerbach/Marjanska
Expand Down Expand Up @@ -80,7 +142,7 @@
end
% Collect all FIDs and sort them into fids array
for kk = 1:length(filesInFolder)

% First, attempt to retrieve the FID from the DICOM header:
infoDicom = dicominfo(filesInFolder{kk});
if isfield(infoDicom, 'SpectroscopyData')
Expand All @@ -95,7 +157,7 @@
fids(:,kk) = dicom_get_spectrum_siemens(fd);
fclose(fd);
end

end


Expand All @@ -115,16 +177,16 @@
else
out.flags.averaged = 0;
end

% Currently, the DICOM recon of the universal sequence is flawed.
% Kick out empty lines here and see if data can be reconstructed.
if strcmp(seqorig, 'Universal') && out.flags.averaged == 0
fids(:,size(fids,2)/2+1:end) = [];
end

% Rearrange into subspecs
fids = reshape(fids,[size(fids,1) size(fids,2)/2 2]);

elseif strcmp(seqtype,'PRESS') || strcmp(seqtype,'STEAM') || strcmp(seqtype,'sLASER')
% If the number of stored FIDs does not match the number of averages
% stored in the DICOM header, the data are averaged.
Expand All @@ -137,9 +199,9 @@

elseif strcmp(seqtype,'HERMES')

out.flags.averaged = 0;
out.flags.averaged = 0;
% Currently, the DICOM recon of the universal sequence is flawed.
% Kick out empty lines here and see if data can be reconstructed.
% Kick out empty lines here and see if data can be reconstructed.
if strcmp(seqorig, 'Universal') && out.flags.averaged == 0
fids(:,size(fids,2)/2+1:end) = [];
end
Expand Down Expand Up @@ -222,7 +284,7 @@

%Find the number of averages. 'averages' will specify the current number
%of averages in the dataset as it is processed, which may be subject to
%change. 'rawAverages' will specify the original number of acquired
%change. 'rawAverages' will specify the original number of acquired
%averages in the dataset, which is unchangeable.
if dims.subSpecs ~=0
if dims.averages~=0
Expand All @@ -244,7 +306,7 @@

%Find the number of subspecs. 'subspecs' will specify the current number
%of subspectra in the dataset as it is processed, which may be subject to
%change. 'rawSubspecs' will specify the original number of acquired
%change. 'rawSubspecs' will specify the original number of acquired
%subspectra in the dataset, which is unchangeable.
if dims.subSpecs ~=0
subspecs=sz(dims.subSpecs);
Expand Down Expand Up @@ -288,8 +350,8 @@
out.fids=fids;
out.specs=specs;
out.sz=sz;
out.ppm=ppm;
out.t=t;
out.ppm=ppm;
out.t=t;
out.spectralwidth=spectralwidth;
out.dwelltime=dwelltime;
out.txfrq=txfrq;
Expand Down
8 changes: 4 additions & 4 deletions libraries/FID-A/inputOutput/io_loadspec_twix.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@
isjnseq=~isempty(strfind(sequence,'jn_')); %Is this another one of Jamie Near's sequences?
isWIP529=~isempty(strfind(sequence,'edit_529'));%Is this WIP 529 (MEGA-PRESS)?
ismodWIP=((~isempty(strfind(sequence,'\svs_edit'))||...
~isempty(strfind(sequence,'\wip_svs_edit'))) && isempty(strfind(sequence,'edit_859'))); %Modified WIP
~isempty(strfind(sequence,'\wip_svs_edit'))) && ...
(isempty(strfind(sequence,'edit_859')) && isempty(strfind(sequence,'univ')))); %Modified WIP
isWIP859=~isempty(strfind(sequence,'edit_859'))||...;%Is this WIP 859 (MEGA-PRESS)?
~isempty(strfind(sequence,'WIP_859'));%Is this WIP 859 (MEGA-PRESS)? Other naming
isTLFrei=~isempty(strfind(sequence,'md_svs_edit')) ||... %Is Thomas Lange's MEGA-PRESS sequence
Expand Down Expand Up @@ -353,9 +354,8 @@
else
% GO 6/2024: Encountered a VD13 Siemens product sequence that had
% transients in Set, not in Ave...
if strcmp(sqzDims,'Ave')
dims.averages=find(strcmp(sqzDims,'Ave'));
else
dims.averages=find(strcmp(sqzDims,'Ave'));
if isempty(dims.averages)
dims.averages=find(strcmp(sqzDims,'Set'));
end
end
Expand Down
12 changes: 6 additions & 6 deletions process/OspreyProcess.m
Original file line number Diff line number Diff line change
Expand Up @@ -745,18 +745,18 @@
end
end
if MRSCont.flags.hasRef
MRSCont.QM.SNR.ref(ref_ll,kk) = op_getSNR(MRSCont.processed.ref{kk});
MRSCont.QM.FWHM.ref(ref_ll,kk) = op_getLW(MRSCont.processed.ref{kk},4.2,5.2);
MRSCont.QM.SNR.ref(ref_ll,kk) = op_getSNR(MRSCont.processed.ref{kk},3.7,5.7);
MRSCont.QM.FWHM.ref(ref_ll,kk) = op_getLW(MRSCont.processed.ref{kk},3.7,5.7);
MRSCont.processed.ref{kk}.QC_names = {'water'};
end
if MRSCont.flags.hasWater
MRSCont.QM.SNR.w(w_ll,kk) = op_getSNR(MRSCont.processed.w{kk});
MRSCont.QM.FWHM.w(w_ll,kk) = op_getLW(MRSCont.processed.w{kk},4.2,5.2);
MRSCont.QM.SNR.w(w_ll,kk) = op_getSNR(MRSCont.processed.w{kk},3.7,5.7);
MRSCont.QM.FWHM.w(w_ll,kk) = op_getLW(MRSCont.processed.w{kk},3.7,5.7);
MRSCont.processed.w{kk}.QC_names = {'water'};
end
if MRSCont.flags.hasMMRef
MRSCont.QM.SNR.mm_ref(mm_ref_ll,kk) = op_getSNR(MRSCont.processed.mm_ref{kk});
MRSCont.QM.FWHM.mm_ref(mm_ref_ll,kk) = op_getLW(MRSCont.processed.mm_ref{kk},4.2,5.2);
MRSCont.QM.SNR.mm_ref(mm_ref_ll,kk) = op_getSNR(MRSCont.processed.mm_ref{kk},3.7,5.7);
MRSCont.QM.FWHM.mm_ref(mm_ref_ll,kk) = op_getLW(MRSCont.processed.mm_ref{kk},3.7,5.7);
MRSCont.processed.mm_ref{kk}.QC_names = {'water'};
end
end
Expand Down
Loading

0 comments on commit 765b30b

Please sign in to comment.