Skip to content

Commit

Permalink
Small changes
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Apr 15, 2015
1 parent 49c086f commit 8e1ad63
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 50 deletions.
115 changes: 115 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
##### About

dcm2nii is a designed to convert neuroimaging data from the NIfTI format to the DICOM format. For details and compiled versions visit the [NITRC wiki](http://www.nitrc.org/plugins/mwiki/index.php/dcm2nii:MainPage)

##### Versions

2-Feb-2015
- Support for Visual Studio
- Remove dependency on zlib (now uses miniz)

1-Jan-2015
- Images separated based on TE (fieldmaps)
- Support for JPEG2000 using OpenJPEG or Jasper libraries
- Support for JPEG using NanoJPEG library
- Support for lossless JPEG using custom library

24-Nov-2014
- Support for CT scans with gantry tilt and varying distance between slices

11-Oct-2014
- Initial public release

Building command line version:

This requires a C compiler. With a terminal, change directory to the 'conosle' folder and run the following:

##### DEFAULT BUILD

- g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -o dcm2niix

##### ZLIB BUILD
If we have zlib, we can use it (-lz) and disable [miniz](https://code.google.com/p/miniz/) (-myDisableMiniZ)

- g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -o dcm2niix -lz -DmyDisableMiniZ

##### MINGW BUILD

If you use the (osbsolete) compiler MinGW on Windows you will want to include the rare libgcc libraries with your executable so others can use it. Here I also demonstrate the optional "-DmyDisableZLib" to remove zip support.

- g++ -O3 -s -DmyDisableOpenJPEG -DmyDisableZLib -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix -static-libgcc


##### JPEG2000 BUILD

If you want to build this with JPEG2000 decompression support using OpenJPEG. You will need to have the OpenJPEG 2.1 libraries installed (https://code.google.com/p/openjpeg/wiki/Installation). I suggest building static libraries...
svn checkout http://openjpeg.googlecode.com/svn/trunk/ openjpeg-read-only
cmake -DBUILD_SHARED_LIBS:bool=off .
make
sudo make install
You should then be able to run then run:

- g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix -lopenjp2

But in my experience this works best if you explicitly tell the software how to find the libraries, so your compile will probably look like one of these two options:

- g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix -I/usr/local/include /usr/local/lib/libopenjp2.a

- g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix -I/usr/local/lib /usr/local/lib/libopenjp2.a

If you want to build this with JPEG2000 decompression support using Jasper: You will need to have the Jasper (http://www.ece.uvic.ca/~frodo/jasper/) and libjpeg (http://www.ijg.org) libraries installed which for Linux users may be as easy as running 'sudo apt-get install libjasper-dev' (otherwise, see http://www.ece.uvic.ca/~frodo/jasper/#doc). You can then run:

- g++ -O3 -DmyDisableOpenJPEG -DmyEnableJasper -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -s -o dcm2niix -ljasper -ljpeg

##### VISUAL STUDIO BUILD

You should be able to click on the Visual Studio icons to open and build this code. Here are links for for building with [Windows XP support](http://blogs.msdn.com/b/vcblog/archive/2012/10/08/windows-xp-targeting-with-c-in-visual-studio-2012.aspx) and [64-bit support](https://msdn.microsoft.com/en-us/library/9yb4317s.aspx).

##### OSX BUILD WITH BOTH 32 AND 64-BIT SUPPORT

Building command line version universal binary from OSX 64 bit system:
This requires a C compiler. With a terminal, change directory to the 'conosle' folder and run the following:

- g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -arch i386 -o dcm2niix32

- g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -o dcm2niix64

- lipo -create dcm2niix32 dcm2niix64 -o dcm2niix

To validate that the resulting executable supports both architectures type

- file ./dcm2niix

##### OSX GRAPHICAL INTERFACE BUILD

Building OSX graphical user interface using XCode:
Copy contents of "console" folder to /xcode/dcm2/core
Open and compile "dcm2.xcodeproj" with XCode 4.6 or later

##### THE QT AND wxWIDGETS GUIs ARE NOT YET SUPPORT - FOLLOWING LINES FOR FUTURE VERSIONS

Building QT graphical user interface:
Open "dcm2.pro" with QTCreator. This should work on OSX and Linux. On Windows the printf information is not redirected to the user interface
If compile gives you grief look at the .pro file which has notes for different operating systems.

Building using wxWidgets
wxWdigets makefiles are pretty complex and specific for your operating system. For simplicity, we will build the "clipboard" example that comes with wxwidgets and then substitute our own code. The process goes something like this.
a.) Install wxwdigets
b.) successfully "make" the samples/clipboard program
c.) DELETE console/makefile. WE DO NOT WANT TO OVERWRITE the WX MAKEFILE
d.) with the exception of "makefile", copy the contents of console to /samples/clipboard
e.) overwrite the original /samples/clipboard.cpp with the dcm2niix file of the same name
f.) Older XCodes have problems with .cpp files, whereas wxWidgets's makefiles do not compile with "-x cpp". So the core files are called '.c' but we will rename them to .cpp for wxWidgets:
rename 's/\.c$/\.cpp/' *
g.) edit the /samples/clipboard makefile: Add "nii_dicom.o nifti1_io_core.o nii_ortho.o nii_dicom_batch.o \" to CLIPBOARD_OBJECTS:
CLIPBOARD_OBJECTS = \
nii_dicom.o nifti1_io_core.o nii_ortho.o nii_dicom_batch.o \
$(__clipboard___win32rc) \
$(__clipboard_os2_lib_res) \
clipboard_clipboard.o
h.) edit the /samples/clipboard makefile: With wxWidgets we will capture std::cout comments, not printf, so we need to add "-DDmyUseCOut" to CXXFLAGS:
CXXFLAGS = -DmyUseCOut -DWX_PRECOMP ....
i.) For a full refresh
rm clipboard
rm *.o
make
74 changes: 51 additions & 23 deletions nii_batch12.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,43 @@ function nii_batch12 (p)
%Examples

resliceMM = 3; %resolution for reslicing data
[fmriname, t1name, TRsec, slice_order, phase, magn, prefix] = validatePreprocSub(p);
%0.) set origin
%setOriginSub(strvcat(t1name, fmriname, phase, magn), 1); %#ok<REMFF1> align images to MNI space
%1.) motion correct, used fieldmap if specifiedclass
[meanname, prefix] = mocoFMSub(prefix, fmriname, phase, magn);
%2.) brain extact mean (for better coregistration)
meanname = betSub(meanname); %brain extract mean image for better coreg
%3.) slice-time correction
prefix = slicetimeSub(prefix, fmriname, TRsec, slice_order); %slice-time correct
%4.) estimate normalization, coregister and reslice fMRI
prefix = normNewSegSub(t1name, meanname, prefix, fmriname, resliceMM);
%5.) blur data
prefix = smoothSub(8, prefix, fmriname); %smooth images
%-- get rid of images we don't need
deleteImagesSub(prefix, fmriname); %delete intermediate images
[fmriname, t1name, TRsec, slice_order, phase, magn] = validatePreprocSub(p);
prefix = CheckExistingPreprocess(fmriname);
if isempty(prefix) %preprocessing not yet run
%0.) set origin
%setOriginSub(strvcat(t1name, fmriname, phase, magn), 1); %#ok<REMFF1> align images to MNI space
%1.) motion correct, used fieldmap if specifiedclass
[meanname, prefix] = mocoFMSub(prefix, fmriname, phase, magn);
%2.) brain extact mean (for better coregistration)
meanname = betSub(meanname); %brain extract mean image for better coreg
%3.) slice-time correction
prefix = slicetimeSub(prefix, fmriname, TRsec, slice_order); %slice-time correct
%4.) estimate normalization, coregister and reslice fMRI
prefix = normNewSegSub(t1name, meanname, prefix, fmriname, resliceMM);
%5.) blur data
prefix = smoothSub(8, prefix, fmriname); %smooth images
%-- get rid of images we don't need
deleteImagesSub(prefix, fmriname); %delete intermediate images
%6.) compute statistics
end;
if ~isfield(p,'onsets'), return; end; %only if user provides details
stat_1st_levelSub (prefix, fmriname, TRsec, p);
%end nii_batch()

%---------- LOCAL FUNCTIONS FOLLOW
function prefix = CheckExistingPreprocess(fmriname) %originally '', if 'swa' it means we have smoothed, warped, aligned data
prefix = '';
nsessions = length(fmriname(:,1));
isSWA = true;
isSW = true;
for s = 1 : nsessions
[pth,nam,ext,~] = spm_fileparts( deblank (fmriname(s,:)));
if ~exist(fullfile(pth,['swa', nam, ext]),'file'), isSWA = false; end;
if ~exist(fullfile(pth,['sw', nam, ext]), 'file'), isSW = false; end;
end
if isSW, prefix = 'sw'; end;
if isSWA, prefix = 'swa'; end;
%end

function [meanname, prefix] = mocoFMSub(prefix, fmriname, phase, magn) %motion correct with field map
if isempty(phase) || isempty(magn)
Expand Down Expand Up @@ -180,8 +196,15 @@ function FieldMapSub(fmriname, phase, magnitude)
prefix = normSub( meanname, prefix, fmriname, resliceMM);
return;
end
newSegSub(t1); %normalize images
extractSub(0.01, t1, prefixSub('c1', t1), prefixSub('c2', t1));
[p, n] = fileparts(t1);
matname = fullfile(p, ['e' n '_seg8.mat']);
if exist(matname, 'file')
fprintf('skipping normalization, using %s\n', matname);
extractSub(0.01, t1, prefixSub('c1e', t1), prefixSub('c2e', t1));
else
matname = newSegSub(t1); %normalize images
extractSub(0.01, t1, prefixSub('c1', t1), prefixSub('c2', t1));
end
coregEstSub(prefixSub('render', t1), meanname, prefix, fmriname); %make sure fMRI is aligned with T1
newSegWriteSub(t1, prefixSub('render', t1), '', 0.9); %reslice anatomical with 0.9mm isotropic
newSegWriteSub(t1, meanname, '', resliceMM);
Expand Down Expand Up @@ -261,9 +284,12 @@ function FieldMapSub(fmriname, phase, magnitude)
%reslice img using pre-existing new-segmentation deformation field
if isempty(warpname) || isempty(t1name), return; end;
[pth,nam,ext, vol] = spm_fileparts(t1name);
defname = fullfile(pth,['y_' nam ext]);
defname = fullfile(pth,['y_e' nam ext]);
if ~exist(defname,'file')
error('Unable to find new-segment deformation image %s',defname);
defname = fullfile(pth,['y_' nam ext]);
if ~exist(defname,'file')
error('Unable to find new-segment deformation image %s',defname);
end
end
warpses = getsesvolsSubFlat(prefix, warpname);
matlabbatch{1}.spm.spatial.normalise.write.subj.def = {defname};
Expand All @@ -275,7 +301,7 @@ function FieldMapSub(fmriname, phase, magnitude)
prefix = ['w' prefix];
%end newsegwritesub()

function newSegSub(t1, t2)
function matname = newSegSub(t1, t2)
%apply new segment - return name of warping matrix
template = fullfile(spm('Dir'),'tpm','TPM.nii');
if ~exist(template,'file')
Expand Down Expand Up @@ -369,7 +395,7 @@ function coregEstSub(t1, meanfmri, prefix, fmriname)

%end coregEstSub()

function [fmriname, t1name, TRsec, slice_order, phase, magn, prefix] = validatePreprocSub(p)
function [fmriname, t1name, TRsec, slice_order, phase, magn] = validatePreprocSub(p)
%check all inputs
if exist('spm','file')~=2; fprintf('%s requires SPM\n',which(mfilename)); return; end;
isSPM12orNewerSub; %check recent SPM
Expand Down Expand Up @@ -695,13 +721,15 @@ function stat_1st_levelSub (prefix, basefmriname, kTR, s)
statpth = fullfile(pth, statdirname);
if exist(statpth, 'file') ~= 7; mkdir(statpth); end;
fprintf(' SPM.mat file saved in %s\n',statdirname);
temporalderiv = false;
hpf = 128;
if (min([s.duration{:}]) > 5) && (max([s.duration{:}]) < 32);
hpf = mean([s.duration{:}]) * 4;
temporalderiv = false;
fprintf('Block design : using %.1fs high pass filter with no temporal derivative.\n',hpf);
elseif kTR > 5.0
fprintf('Sparse design : using %.1fs high pass filter without a temporal derivative.\n',hpf);
else
temporalderiv = true;
hpf = 128;
fprintf('Event-related design : using %.1fs high pass filter with a temporal derivative.\n',hpf);
end;
% MODEL SPECIFICATION
Expand Down
28 changes: 22 additions & 6 deletions nii_clip2bb.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,23 @@ function nii_clip2bb(vols, bb, clipZ, overwrite, evenXY)
if (mod(i,2) == 1), mmi(1) = bb(2,1); end
if (mod(i-1,4) < 2), mmi(2) = bb(2,2); end;
if (mod(i-1,8) < 4), mmi(3) = bb(2,3); end;
mm(i,:) = mmi;
mm(i,:) = mmi; %#ok<AGROW>
end
hdr = spm_vol([fname,',1']); %read header of 1st volume
v2m = hdr.mat; %voxel2mm transform
m2v=inv(v2m); %mm2voxel transform
for i=1:size(mm,1)
vox(i,1:3)=mm(i,:)*m2v(1:3,1:3)' + m2v(1:3,4)';
vox(i,1:3)=mm(i,:)*m2v(1:3,1:3)' + m2v(1:3,4)'; %#ok<AGROW>
end
mn = floor(min(vox));
mx = ceil(max(vox));
if ~clipZ %do not clip in Z-dimension - preserve number of slices
mn(3) = 1;
mx(3) = hdr.dim(3);
end

mxD = min(hdr.dim, mx);
mnD = max([1 1 1], mn);
if evenXY %force even number of rows and columns
for i = 1: 2
if mod(mxD(i)-mnD(i)+1,2) && mnD(i) > 1
Expand All @@ -62,8 +65,6 @@ function nii_clip2bb(vols, bb, clipZ, overwrite, evenXY)
fprintf('Warning: odd number of rows/columns/slices may confuse topup: %s\n', fname);
end
end %if evenXY
mxD = min(hdr.dim, mx);
mnD = max([1 1 1], mn);
if (max(mnD) == 1) && (min(hdr.dim == mxD) == 1)
fprintf('%s :No need to crop image\n', mfilename);
return;
Expand All @@ -72,13 +73,28 @@ function nii_clip2bb(vols, bb, clipZ, overwrite, evenXY)
vx = (mxD(1)-mnD(1)+1)*(mxD(2)-mnD(2)+1)*(mxD(3)-mnD(3)+1);
if vx <= 1, error('image not coregistered'); end;
pct = 100* vx/(hdr.dim(1)*hdr.dim(2)*hdr.dim(3));
fprintf('%s cropping image from %dx%dx%d -> %dx%dx%d (%g%%)\n', mfilename, hdr.dim(1), hdr.dim(2), hdr.dim(3), mxD(1)-mnD(1)+1,mxD(2)-mnD(2)+1, mxD(3)-mnD(3)+1, pct);
h.dim = hdr.dim;
fprintf('%s cropping image from %dx%dx%d -> %dx%dx%d (%g%%)\n', mfilename, h.dim(1), h.dim(2), h.dim(3), mxD(1)-mnD(1)+1,mxD(2)-mnD(2)+1, mxD(3)-mnD(3)+1, pct);
for v = 1 : numel(vols) %apply parameters from first session to others
[pth,nam,ext, ~] = spm_fileparts(deblank(vols{v}));
fname = fullfile(pth,[nam ext]); %strip volume label
hdr = spm_vol([fname,',1']); %read header of 1st volume
if (h.dim(1) ~= hdr.dim(1)) || (h.dim(2) ~= hdr.dim(2)) || (h.dim(3) ~= hdr.dim(3))
error('%s error: Image dimensions do not match %dx%dx%d ~= %dx%dx%d %s %s', mfilename, ...
h.dim(1),h.dim(2),h.dim(3), hdr.dim(1),hdr.dim(2),hdr.dim(3), deblank(vols{1}), deblank(vols{v}));

end
end
for v = 1 : numel(vols) %apply parameters from first session to others
[pth,nam,ext, ~] = spm_fileparts(deblank(vols{v}));
fname = fullfile(pth,[nam ext]); %strip volume label
hdr = spm_vol([fname]); %read header - this time 4D if specified
hdr = spm_vol(fname); %read header - this time 4D if specified
img = spm_read_vols(hdr); %load image
hdr = spm_vol([fname,',1']); %read header of 1st volume
if (h.dim(1) ~= hdr.dim(1)) || (h.dim(2) ~= hdr.dim(2)) || (h.dim(3) ~= hdr.dim(3))
error('%s error: Image dimensions do not match %s %s', mfilename, deblank(vols{1}), deblank(vols{v}));

end
img = img(mnD(1):mxD(1), mnD(2):mxD(2), mnD(3):mxD(3), :); %clip image dimensions
origin= mnD*v2m(1:3,1:3)' + v2m(1:3,4)';
hdr.mat(1:3,4) = origin;
Expand Down
12 changes: 8 additions & 4 deletions nii_mean_stdev.m
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
function nii_mean_stdev (fnms, normBrightness)
function nii_mean_stdev (fnms, normBrightness, outname)
%Given multiple volumes, generate mean, standard deviation, SNR maps and report unusual images. Useful for quality assurance
% fnms : filenames to average (optional)
% normBrightness : if false (0) raw intensity is used. if true (1) image intensity
% scaled so minimum is 0 and median of non-zero voxels is 1
% outname : optional prefix appended to output image name
%Chris Rorden, 2014
% http://opensource.org/licenses/BSD-2-Clause
%SNR is mean/stdev http://www.ncbi.nlm.nih.gov/pubmed/17126038
Expand All @@ -17,6 +18,9 @@ function nii_mean_stdev (fnms, normBrightness)
if ~exist('normBrightness','var') %no files
normBrightness = str2double(cell2mat(inputdlg('Scale image intensity to normalize brightness? (0=no,1=yes):', 'Adjust brightness', 1,{'0'})));
end;
if ~exist('outname', 'var')
outname = '';
end
if size(fnms,1) < 1
return;
elseif size(fnms,1) == 1 %4D: compute mean and stDev using inbuilt Matlab functions
Expand All @@ -28,9 +32,9 @@ function nii_mean_stdev (fnms, normBrightness)
error('Not enough images to estimate mean and stdev');
end
%save statistical images (optional)
saveImgSub(['mean_of_' num2str(n) '.nii'],hdr,meanImg);
saveImgSub(['stdev_of_' num2str(n) '.nii'],hdr,sdImg);
saveImgSub(['snr_of_' num2str(n) '.nii'],hdr,meanImg ./ sdImg);
saveImgSub([outname 'mean_of_' num2str(n) '.nii'],hdr,meanImg);
saveImgSub([outname 'stdev_of_' num2str(n) '.nii'],hdr,sdImg);
saveImgSub([outname 'snr_of_' num2str(n) '.nii'],hdr,meanImg ./ sdImg);
%report mean z-score for each image
if size(fnms,1) == 1
reportZSub4D(meanImg, sdImg, normBrightness, fnms)
Expand Down
Loading

0 comments on commit 8e1ad63

Please sign in to comment.