From 6f973cb96a8f75f10a6a120d140370e49269ba8b Mon Sep 17 00:00:00 2001
From: Pawel
Date: Wed, 26 Jan 2022 12:04:42 +0000
Subject: [PATCH 01/14] slight output modification for bias field corr
---
niftypet/nimpa/prc/prc.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/niftypet/nimpa/prc/prc.py b/niftypet/nimpa/prc/prc.py
index 87f70141..f96c35dc 100644
--- a/niftypet/nimpa/prc/prc.py
+++ b/niftypet/nimpa/prc/prc.py
@@ -1286,6 +1286,8 @@ def bias_field_correction(fmr, fimout='', outpath='', fcomment='_N4bias', execut
if len(outdct['fim']) == 1:
outdct['fim'] = outdct['fim'][0]
+ outdct['fmsk'] = outdct['fmsk'][0]
+
return outdct
From 18999106b0557d4e99aaada4382266af60187243 Mon Sep 17 00:00:00 2001
From: Pawel
Date: Wed, 16 Feb 2022 00:33:34 +0000
Subject: [PATCH 02/14] added institution to DICOM properties to be extracted
---
niftypet/nimpa/prc/imio.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/niftypet/nimpa/prc/imio.py b/niftypet/nimpa/prc/imio.py
index 81b60ab9..00495245 100644
--- a/niftypet/nimpa/prc/imio.py
+++ b/niftypet/nimpa/prc/imio.py
@@ -183,6 +183,11 @@ def dcminfo(dcmvar, Cnt=None, output='detail', t1_name='mprage'):
cmmnt = dhdr[0x0020, 0x4000].value
log.debug(' Comments: {}'.format(cmmnt))
+ # > institution
+ inst = ''
+ if [0x008, 0x080] in dhdr:
+ inst = dhdr[0x008, 0x080].value
+
prtcl = ''
if [0x18, 0x1030] in dhdr:
prtcl = dhdr[0x18, 0x1030].value
@@ -297,7 +302,7 @@ def dcminfo(dcmvar, Cnt=None, output='detail', t1_name='mprage'):
if validTs:
mrdct = {
- 'series': srs, 'protocol': prtcl, 'units': unt, 'study_time': study_time,
+ 'series': srs, 'protocol': prtcl, 'units': unt, 'study_time': study_time, 'inst':inst,
'series_time': series_time, 'acq_time': acq_time, 'scanner_id': scanner_id, 'TR': TR,
'TE': TE}
# ---------------------------------------------
@@ -324,7 +329,7 @@ def dcminfo(dcmvar, Cnt=None, output='detail', t1_name='mprage'):
elif isPET:
petdct = {
'series': srs, 'protocol': prtcl, 'study_time': study_time, 'series_time': series_time,
- 'acq_time': acq_time, 'scanner_id': scanner_id, 'type': srs_type, 'units': unt,
+ 'inst':inst, 'acq_time': acq_time, 'scanner_id': scanner_id, 'type': srs_type, 'units': unt,
'recon': recon, 'decay_corr': decay_corr, 'dcf': dcf, 'attenuation': atten,
'scatter': scat, 'scf': scf, 'randoms': rand, 'dose_calib': dscf, 'dead_time': dt,
'tracer': tracer, 'total_dose': tdose, 'half_life': hlife, 'positron_fract': pfract,
From 3c8d14f3053a0996c5277417a190815e26dee312 Mon Sep 17 00:00:00 2001
From: Pawel
Date: Wed, 9 Mar 2022 00:38:16 +0000
Subject: [PATCH 03/14] added MGH image file support
---
niftypet/nimpa/__init__.py | 4 +-
niftypet/nimpa/prc/__init__.py | 4 +-
niftypet/nimpa/prc/imio.py | 109 +++++++++++++++++++++++++++++++++
niftypet/nimpa/prc/prc.py | 3 +-
4 files changed, 117 insertions(+), 3 deletions(-)
diff --git a/niftypet/nimpa/__init__.py b/niftypet/nimpa/__init__.py
index dc036549..128a3988 100644
--- a/niftypet/nimpa/__init__.py
+++ b/niftypet/nimpa/__init__.py
@@ -30,7 +30,7 @@
'centre_mass_img', 'centre_mass_corr', 'coreg_spm', 'coreg_vinci',
'create_dir', 'create_mask', 'ct2mu',
'dcm2im', 'dcm2nii', 'dcmanonym', 'dcminfo', 'dcmsort',
- 'dice_coeff', 'dice_coeff_multiclass', 'fwhm2sig', 'getnii',
+ 'dice_coeff', 'dice_coeff_multiclass', 'fwhm2sig', 'getmgh', 'getnii', 'mgh2nii'
'getnii_descr', 'im_cut', 'imfill', 'imsmooth', 'iyang', 'motion_reg', 'nii_gzip',
'nii_modify', 'nii_ugzip', 'niisort', 'orientnii', 'pet2pet_rigid', 'pick_t1w',
'psf_gaussian', 'psf_measured', 'pvc_iyang', 'realign_mltp_spm', 'resample_fsl',
@@ -68,6 +68,8 @@
dice_coeff,
dice_coeff_multiclass,
fwhm2sig,
+ getmgh,
+ mgh2nii,
getnii,
getnii_descr,
im_cut,
diff --git a/niftypet/nimpa/prc/__init__.py b/niftypet/nimpa/prc/__init__.py
index a3d36665..d1859359 100644
--- a/niftypet/nimpa/prc/__init__.py
+++ b/niftypet/nimpa/prc/__init__.py
@@ -2,7 +2,7 @@
__all__ = [
# imio
'array2nii', 'create_dir', 'dcm2im', 'dcm2nii', 'dcmanonym', 'dcminfo', 'dcmsort', 'fwhm2sig',
- 'getnii', 'getnii_descr', 'nii_gzip', 'nii_ugzip', 'niisort', 'orientnii', 'pick_t1w',
+ 'mgh2nii', 'getmgh', 'getnii', 'getnii_descr', 'nii_gzip', 'nii_ugzip', 'niisort', 'orientnii', 'pick_t1w',
'time_stamp',
# prc
'bias_field_correction', 'centre_mass_img', 'centre_mass_corr', 'ct2mu', 'im_cut',
@@ -26,7 +26,9 @@
dcminfo,
dcmsort,
fwhm2sig,
+ mgh2nii,
getnii,
+ getmgh,
getnii_descr,
nii_gzip,
nii_ugzip,
diff --git a/niftypet/nimpa/prc/imio.py b/niftypet/nimpa/prc/imio.py
index 00495245..50699f1c 100644
--- a/niftypet/nimpa/prc/imio.py
+++ b/niftypet/nimpa/prc/imio.py
@@ -5,6 +5,7 @@
import pathlib
import re
import shutil
+import numbers
from subprocess import run
from textwrap import dedent
@@ -17,6 +18,7 @@
from miutil.imio.nii import nii_ugzip # NOQA: F401 # yapf: disable
from miutil.imio.nii import niisort # NOQA: F401 # yapf: disable
+
# > NiftyPET resources
from .. import resources as rs
@@ -50,6 +52,113 @@ def fwhm2sig(fwhm, voxsize=2.0):
return (fwhm/voxsize) / (2 * (2 * np.log(2))**.5)
+
+def mgh2nii(fim, fout=None, output=None):
+ ''' Convert `*.mgh` or `*.mgz` FreeSurfer image to NIfTI.
+ Arguments:
+ fim: path to the input MGH file
+ fout: path to the output NIfTI file, if None then
+ creates based on `fim`
+ output: if not None and an applicable string it will
+ output a dictionary or an array (see below)
+ Return:
+ None: returns nothing
+ 'image' or 'im': outputs just the image
+ 'affine': outputs just the affine matrix
+ 'all': outputs all as a dictionary
+ '''
+
+ if not os.path.isfile(fim):
+ raise ValueError('The input path is incorrect!')
+
+ # > get the image dictionary
+ mghd = getmgh(fim, output='all')
+ im = mghd['im']
+
+ # > sort out the output
+ if fout is None:
+ fout = fim.parent / (fim.name.split('.')[0]+'.nii.gz')
+
+ out = fout
+ if output=='image' or output=='im':
+ out = fout, im
+ elif output=='affine':
+ out = fout, mghd['affine']
+ elif output=='all':
+ out = mghd
+ out.update(dict(fout=fout))
+
+ array2nii(
+ mghd['im'],
+ mghd['affine'],
+ fout,
+ trnsp = (mghd['transpose'].index(0), mghd['transpose'].index(1), mghd['transpose'].index(2)),
+ flip = mghd['flip'])
+
+ return out
+
+
+def getmgh(fim, nan_replace=None, output='image'):
+ '''
+ Get image from `*.mgz` or `*.mgh` file (FreeSurfer).
+ Arguments:
+ fim: input file name for the MGH/Z image
+ output: option for choosing output: 'image', 'affine' matrix or
+ 'all' for a dictionary with all the info.
+ Return:
+ 'image': outputs just the image
+ 'affine': outputs just the affine matrix
+ 'all': outputs all as a dictionary
+ '''
+
+ if not os.path.isfile(fim):
+ raise ValueError('The input path is incorrect!')
+
+ mgh = nib.freesurfer.load(str(fim))
+
+ if output == 'image' or output == 'all':
+
+ imr = np.asanyarray(mgh.dataobj)
+ # replace NaNs if requested
+ if isinstance(nan_replace, numbers.Number):
+ imr[np.isnan(imr)] = nan_replace
+
+ imr = np.squeeze(imr)
+ dimno = imr.ndim
+
+ # > get orientations from the affine
+ ornt = nib.io_orientation(mgh.affine)
+ trnsp = tuple(np.flip(np.argsort(ornt[:, 0])))
+ flip = tuple(np.int8(ornt[:, 1]))
+
+ # > flip y-axis and z-axis and then transpose
+ if dimno == 4: # dynamic
+ imr = np.transpose(imr[::-flip[0], ::-flip[1], ::-flip[2], :], (3,) + trnsp)
+ elif dimno == 3: # static
+ imr = np.transpose(imr[::-flip[0], ::-flip[1], ::-flip[2]], trnsp)
+
+
+ # # > voxel size
+ # voxsize = mgh.header.get('pixdim')[1:mgh.header.get('dim')[0] + 1]
+ # # > rearrange voxel size according to the orientation
+ # voxsize = voxsize[np.array(trnsp)]
+
+
+ if output == 'all':
+ out = {
+ 'im': imr, 'affine': mgh.affine, 'fim': fim, 'dtype': mgh.get_data_dtype(), 'shape': imr.shape,
+ 'hdr': mgh.header, 'transpose': trnsp, 'flip': flip}
+ elif output == 'image':
+ out = imr
+ elif output == 'affine':
+ out = mgh.affine
+ else:
+ raise NameError("Unrecognised output request!")
+
+ return out
+
+
+
def getnii_descr(fim):
'''Extracts the custom description header field to dictionary'''
nim = nib.load(fim)
diff --git a/niftypet/nimpa/prc/prc.py b/niftypet/nimpa/prc/prc.py
index f96c35dc..e7e1c218 100644
--- a/niftypet/nimpa/prc/prc.py
+++ b/niftypet/nimpa/prc/prc.py
@@ -1286,7 +1286,8 @@ def bias_field_correction(fmr, fimout='', outpath='', fcomment='_N4bias', execut
if len(outdct['fim']) == 1:
outdct['fim'] = outdct['fim'][0]
- outdct['fmsk'] = outdct['fmsk'][0]
+ if 'fmsk' in outdct:
+ outdct['fmsk'] = outdct['fmsk'][0]
return outdct
From 12cb849556ed4e0ddf6c3bb7e1e1500d9c550679 Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Tue, 15 Mar 2022 11:56:25 +0000
Subject: [PATCH 04/14] bump ninst
---
pyproject.toml | 2 +-
setup.cfg | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 0a28fa3c..2d988c72 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[build-system]
requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4",
- "ninst>=0.8.0", "cuvec>=2.8.0", "miutil[cuda]>=0.4.0",
+ "ninst>=0.9.0", "cuvec>=2.8.0", "miutil[cuda]>=0.4.0",
"scikit-build>=0.11.0", "cmake>=3.18", "ninja"]
[tool.setuptools_scm]
diff --git a/setup.cfg b/setup.cfg
index d0a5c3f2..842a0746 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -39,7 +39,7 @@ setup_requires=
setuptools>=42
wheel
setuptools_scm[toml]
- ninst>=0.8.0
+ ninst>=0.9.0
scikit-build>=0.11.0
cmake>=3.18
ninja
From c8fe89b84d05f37df2bbed8a4ed5334b6482fe56 Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Mon, 9 May 2022 05:23:29 +0100
Subject: [PATCH 05/14] rename pydcm2niix => dcm2niix
- as per https://github.com/rordenlab/dcm2niix/pull/605
---
setup.cfg | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.cfg b/setup.cfg
index 842a0746..6c08b63b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -47,7 +47,7 @@ setup_requires=
miutil[cuda]>=0.4.0
install_requires=
cuvec>=2.3.1
- pydcm2niix>=1.0.20220116
+ dcm2niix>=1.0.20220116
dipy>=1.3.0
miutil[nii]>=0.10.0
nibabel>=2.4.0
From 21b3e14e787e959d7e4da0a7dee1b8b2e7e114be Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Mon, 9 May 2022 07:52:50 +0100
Subject: [PATCH 06/14] lint
---
niftypet/nimpa/__init__.py | 4 +--
niftypet/nimpa/prc/__init__.py | 8 +++---
niftypet/nimpa/prc/imio.py | 47 +++++++++++++++-------------------
niftypet/nimpa/prc/prc.py | 2 +-
4 files changed, 27 insertions(+), 34 deletions(-)
diff --git a/niftypet/nimpa/__init__.py b/niftypet/nimpa/__init__.py
index 128a3988..6c3cd3d9 100644
--- a/niftypet/nimpa/__init__.py
+++ b/niftypet/nimpa/__init__.py
@@ -30,7 +30,7 @@
'centre_mass_img', 'centre_mass_corr', 'coreg_spm', 'coreg_vinci',
'create_dir', 'create_mask', 'ct2mu',
'dcm2im', 'dcm2nii', 'dcmanonym', 'dcminfo', 'dcmsort',
- 'dice_coeff', 'dice_coeff_multiclass', 'fwhm2sig', 'getmgh', 'getnii', 'mgh2nii'
+ 'dice_coeff', 'dice_coeff_multiclass', 'fwhm2sig', 'getmgh', 'getnii', 'mgh2nii',
'getnii_descr', 'im_cut', 'imfill', 'imsmooth', 'iyang', 'motion_reg', 'nii_gzip',
'nii_modify', 'nii_ugzip', 'niisort', 'orientnii', 'pet2pet_rigid', 'pick_t1w',
'psf_gaussian', 'psf_measured', 'pvc_iyang', 'realign_mltp_spm', 'resample_fsl',
@@ -69,7 +69,6 @@
dice_coeff_multiclass,
fwhm2sig,
getmgh,
- mgh2nii,
getnii,
getnii_descr,
im_cut,
@@ -77,6 +76,7 @@
imsmooth,
isub,
iyang,
+ mgh2nii,
motion_reg,
nii_gzip,
nii_modify,
diff --git a/niftypet/nimpa/prc/__init__.py b/niftypet/nimpa/prc/__init__.py
index d1859359..57463c04 100644
--- a/niftypet/nimpa/prc/__init__.py
+++ b/niftypet/nimpa/prc/__init__.py
@@ -2,8 +2,8 @@
__all__ = [
# imio
'array2nii', 'create_dir', 'dcm2im', 'dcm2nii', 'dcmanonym', 'dcminfo', 'dcmsort', 'fwhm2sig',
- 'mgh2nii', 'getmgh', 'getnii', 'getnii_descr', 'nii_gzip', 'nii_ugzip', 'niisort', 'orientnii', 'pick_t1w',
- 'time_stamp',
+ 'mgh2nii', 'getmgh', 'getnii', 'getnii_descr', 'nii_gzip', 'nii_ugzip', 'niisort', 'orientnii',
+ 'pick_t1w', 'time_stamp',
# prc
'bias_field_correction', 'centre_mass_img', 'centre_mass_corr', 'ct2mu', 'im_cut',
'imsmooth', 'imtrimup',
@@ -26,10 +26,10 @@
dcminfo,
dcmsort,
fwhm2sig,
- mgh2nii,
- getnii,
getmgh,
+ getnii,
getnii_descr,
+ mgh2nii,
nii_gzip,
nii_ugzip,
niisort,
diff --git a/niftypet/nimpa/prc/imio.py b/niftypet/nimpa/prc/imio.py
index 50699f1c..79327c5d 100644
--- a/niftypet/nimpa/prc/imio.py
+++ b/niftypet/nimpa/prc/imio.py
@@ -1,11 +1,11 @@
"""image input/output functionalities."""
import datetime
import logging
+import numbers
import os
import pathlib
import re
import shutil
-import numbers
from subprocess import run
from textwrap import dedent
@@ -18,7 +18,6 @@
from miutil.imio.nii import nii_ugzip # NOQA: F401 # yapf: disable
from miutil.imio.nii import niisort # NOQA: F401 # yapf: disable
-
# > NiftyPET resources
from .. import resources as rs
@@ -52,13 +51,12 @@ def fwhm2sig(fwhm, voxsize=2.0):
return (fwhm/voxsize) / (2 * (2 * np.log(2))**.5)
-
def mgh2nii(fim, fout=None, output=None):
''' Convert `*.mgh` or `*.mgz` FreeSurfer image to NIfTI.
Arguments:
fim: path to the input MGH file
fout: path to the output NIfTI file, if None then
- creates based on `fim`
+ creates based on `fim`
output: if not None and an applicable string it will
output a dictionary or an array (see below)
Return:
@@ -77,23 +75,21 @@ def mgh2nii(fim, fout=None, output=None):
# > sort out the output
if fout is None:
- fout = fim.parent / (fim.name.split('.')[0]+'.nii.gz')
+ fout = fim.parent / (fim.name.split('.')[0] + '.nii.gz')
out = fout
- if output=='image' or output=='im':
+ if output == 'image' or output == 'im':
out = fout, im
- elif output=='affine':
+ elif output == 'affine':
out = fout, mghd['affine']
- elif output=='all':
+ elif output == 'all':
out = mghd
- out.update(dict(fout=fout))
+ out['fout'] = fout
array2nii(
- mghd['im'],
- mghd['affine'],
- fout,
- trnsp = (mghd['transpose'].index(0), mghd['transpose'].index(1), mghd['transpose'].index(2)),
- flip = mghd['flip'])
+ mghd['im'], mghd['affine'], fout,
+ trnsp=(mghd['transpose'].index(0), mghd['transpose'].index(1), mghd['transpose'].index(2)),
+ flip=mghd['flip'])
return out
@@ -103,7 +99,7 @@ def getmgh(fim, nan_replace=None, output='image'):
Get image from `*.mgz` or `*.mgh` file (FreeSurfer).
Arguments:
fim: input file name for the MGH/Z image
- output: option for choosing output: 'image', 'affine' matrix or
+ output: option for choosing output: 'image', 'affine' matrix or
'all' for a dictionary with all the info.
Return:
'image': outputs just the image
@@ -117,7 +113,7 @@ def getmgh(fim, nan_replace=None, output='image'):
mgh = nib.freesurfer.load(str(fim))
if output == 'image' or output == 'all':
-
+
imr = np.asanyarray(mgh.dataobj)
# replace NaNs if requested
if isinstance(nan_replace, numbers.Number):
@@ -137,17 +133,15 @@ def getmgh(fim, nan_replace=None, output='image'):
elif dimno == 3: # static
imr = np.transpose(imr[::-flip[0], ::-flip[1], ::-flip[2]], trnsp)
-
# # > voxel size
# voxsize = mgh.header.get('pixdim')[1:mgh.header.get('dim')[0] + 1]
# # > rearrange voxel size according to the orientation
# voxsize = voxsize[np.array(trnsp)]
-
if output == 'all':
out = {
- 'im': imr, 'affine': mgh.affine, 'fim': fim, 'dtype': mgh.get_data_dtype(), 'shape': imr.shape,
- 'hdr': mgh.header, 'transpose': trnsp, 'flip': flip}
+ 'im': imr, 'affine': mgh.affine, 'fim': fim, 'dtype': mgh.get_data_dtype(),
+ 'shape': imr.shape, 'hdr': mgh.header, 'transpose': trnsp, 'flip': flip}
elif output == 'image':
out = imr
elif output == 'affine':
@@ -158,7 +152,6 @@ def getmgh(fim, nan_replace=None, output='image'):
return out
-
def getnii_descr(fim):
'''Extracts the custom description header field to dictionary'''
nim = nib.load(fim)
@@ -411,7 +404,7 @@ def dcminfo(dcmvar, Cnt=None, output='detail', t1_name='mprage'):
if validTs:
mrdct = {
- 'series': srs, 'protocol': prtcl, 'units': unt, 'study_time': study_time, 'inst':inst,
+ 'series': srs, 'protocol': prtcl, 'units': unt, 'study_time': study_time, 'inst': inst,
'series_time': series_time, 'acq_time': acq_time, 'scanner_id': scanner_id, 'TR': TR,
'TE': TE}
# ---------------------------------------------
@@ -438,11 +431,11 @@ def dcminfo(dcmvar, Cnt=None, output='detail', t1_name='mprage'):
elif isPET:
petdct = {
'series': srs, 'protocol': prtcl, 'study_time': study_time, 'series_time': series_time,
- 'inst':inst, 'acq_time': acq_time, 'scanner_id': scanner_id, 'type': srs_type, 'units': unt,
- 'recon': recon, 'decay_corr': decay_corr, 'dcf': dcf, 'attenuation': atten,
- 'scatter': scat, 'scf': scf, 'randoms': rand, 'dose_calib': dscf, 'dead_time': dt,
- 'tracer': tracer, 'total_dose': tdose, 'half_life': hlife, 'positron_fract': pfract,
- 'radio_start_time': ttime0, 'radio_stop_time': ttime1}
+ 'inst': inst, 'acq_time': acq_time, 'scanner_id': scanner_id, 'type': srs_type,
+ 'units': unt, 'recon': recon, 'decay_corr': decay_corr, 'dcf': dcf,
+ 'attenuation': atten, 'scatter': scat, 'scf': scf, 'randoms': rand, 'dose_calib': dscf,
+ 'dead_time': dt, 'tracer': tracer, 'total_dose': tdose, 'half_life': hlife,
+ 'positron_fract': pfract, 'radio_start_time': ttime0, 'radio_stop_time': ttime1}
out = ['pet', tracer.lower(), srs_type.lower(), scanner_id, petdct]
diff --git a/niftypet/nimpa/prc/prc.py b/niftypet/nimpa/prc/prc.py
index e7e1c218..c96c7c26 100644
--- a/niftypet/nimpa/prc/prc.py
+++ b/niftypet/nimpa/prc/prc.py
@@ -1288,7 +1288,7 @@ def bias_field_correction(fmr, fimout='', outpath='', fcomment='_N4bias', execut
outdct['fim'] = outdct['fim'][0]
if 'fmsk' in outdct:
outdct['fmsk'] = outdct['fmsk'][0]
-
+
return outdct
From aeba6d9a289169c1e4e7ddc11c980be2ae1c0728 Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Mon, 9 May 2022 07:53:11 +0100
Subject: [PATCH 07/14] no install_tools
---
setup.cfg | 3 ++-
setup.py | 36 ------------------------------------
2 files changed, 2 insertions(+), 37 deletions(-)
diff --git a/setup.cfg b/setup.cfg
index 6c08b63b..1bb95103 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -47,7 +47,6 @@ setup_requires=
miutil[cuda]>=0.4.0
install_requires=
cuvec>=2.3.1
- dcm2niix>=1.0.20220116
dipy>=1.3.0
miutil[nii]>=0.10.0
nibabel>=2.4.0
@@ -68,6 +67,8 @@ dev=
pytest-timeout
pytest-xdist
plot=miutil[plot]
+dcm2niix=dcm2niix>=1.0.20220116
+niftyreg=niftyreg
[flake8]
max_line_length=99
diff --git a/setup.py b/setup.py
index d8af94a4..bda42974 100755
--- a/setup.py
+++ b/setup.py
@@ -50,42 +50,6 @@
resources = cs.get_resources()
# get the current setup, if any
Cnt = resources.get_setup()
-# check the installation of tools
-chck_tls = tls.check_version(Cnt, chcklst=["RESPATH", "REGPATH"])
-
-# -------------------------------------------
-# NiftyPET tools:
-# -------------------------------------------
-if "sdist" not in sys.argv or any(i in sys.argv for i in ["build", "bdist", "wheel"]):
- # NiftyReg
- if not chck_tls["REGPATH"] or not chck_tls["RESPATH"]:
- reply = True
- if not gpuarch:
- try:
- reply = tls.query_yesno(
- "q> the latest compatible version of NiftyReg seems to be missing.\n"
- " Do you want to install it?")
- except BaseException:
- pass
-
- if reply:
- log.info(
- dedent("""\
- --------------------------------------------------------------
- Installing NiftyReg ...
- --------------------------------------------------------------"""))
- Cnt = tls.install_tool("niftyreg", Cnt)
- log.info(
- dedent("""\
- --------------------------------------------------------------
- Installation of NiftyPET-tools is done.
- --------------------------------------------------------------"""))
-else:
- log.info(
- dedent("""\
- --------------------------------------------------------------
- Skipping installation of NiftyPET-tools.
- --------------------------------------------------------------"""))
build_ver = ".".join(__version__.split('.')[:3]).split(".dev")[0]
setup_kwargs = {
From e33f9f0a975a54d556017a79eda493eb88d3d991 Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Mon, 9 May 2022 08:18:15 +0100
Subject: [PATCH 08/14] document optional deps
---
README.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.rst b/README.rst
index 4598b356..7e55b4ca 100644
--- a/README.rst
+++ b/README.rst
@@ -34,6 +34,8 @@ It's also recommended (but not required) to use `conda`.
ipykernel numpy scipy scikit-image matplotlib ipywidgets
pip install "nimpa>=2"
+For optional `dcm2niix `_ and/or `niftyreg `_ support, use ``pip install nimpa[dcm2niix,niftyreg]>=2``.
+
External CMake Projects
~~~~~~~~~~~~~~~~~~~~~~~
From 8b3de3180f7755f036e95953f52ae8da41a0ff2c Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Mon, 9 May 2022 08:46:53 +0100
Subject: [PATCH 09/14] niftyreg package detection
---
niftypet/nimpa/prc/prc.py | 1 -
niftypet/nimpa/prc/regseg.py | 26 +++++++++++++++-----------
2 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/niftypet/nimpa/prc/prc.py b/niftypet/nimpa/prc/prc.py
index c96c7c26..fd6d586d 100644
--- a/niftypet/nimpa/prc/prc.py
+++ b/niftypet/nimpa/prc/prc.py
@@ -727,7 +727,6 @@ def pvc_iyang(
ft1w,
outpath=os.path.join(outpath, 'PET', 'positioning'),
fcomment=fcomment,
- executable=Cnt['REGPATH'],
omp=multiprocessing.cpu_count() / 2,
rigOnly=True,
affDirect=False,
diff --git a/niftypet/nimpa/prc/regseg.py b/niftypet/nimpa/prc/regseg.py
index d1dcb51b..e89b252f 100644
--- a/niftypet/nimpa/prc/regseg.py
+++ b/niftypet/nimpa/prc/regseg.py
@@ -7,6 +7,7 @@
import os
import shutil
import sys
+from os import fspath
from subprocess import call
from textwrap import dedent
@@ -276,7 +277,7 @@ def affine_niftyreg(
fname_aff='',
pickname='ref',
fcomment='',
- executable='',
+ executable=None,
omp=1,
rigOnly=False,
affDirect=False,
@@ -294,10 +295,13 @@ def affine_niftyreg(
fthrsh=0.05,
verbose=True,
):
-
- # check if the executable exists:
+ if not executable:
+ executable = getattr(rs, 'REGPATH', None)
+ if not executable:
+ from niftyreg import bin_path
+ executable = fspath(next(bin_path.glob("reg_aladin*")))
if not os.path.isfile(executable):
- raise IOError('Incorrect path to executable file for registration.')
+ raise IOError(f"executable not found:{executable}")
# create a folder for images registered to ref
if outpath != '':
@@ -377,16 +381,16 @@ def resample_niftyreg(
fcomment='',
pickname='ref',
intrp=1,
- executable='',
+ executable=None,
verbose=True,
):
-
- # check if the executable exists:
- # if executable=='' and 'RESPATH' in Cnt and os.path.isfile(Cnt['RESPATH']):
- # executable = Cnt['RESPATH']
-
+ if not executable:
+ executable = getattr(rs, 'RESPATH', None)
+ if not executable:
+ from niftyreg import bin_path
+ executable = fspath(next(bin_path.glob("reg_resample*")))
if not os.path.isfile(executable):
- raise IOError('Incorrect path to executable file for registration.')
+ raise IOError(f"executable not found:{executable}")
# > output path
if outpath == '' and fimout != '':
From 243d73cd3d7970eb2ae5a93b1ec49efe20012f81 Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Tue, 10 May 2022 06:25:00 +0100
Subject: [PATCH 10/14] make CuVec optional
---
niftypet/nimpa/__init__.py | 5 ++++-
pyproject.toml | 3 ++-
setup.cfg | 16 ++--------------
setup.py | 25 ++++++++-----------------
4 files changed, 16 insertions(+), 33 deletions(-)
diff --git a/niftypet/nimpa/__init__.py b/niftypet/nimpa/__init__.py
index 6c3cd3d9..d29a243a 100644
--- a/niftypet/nimpa/__init__.py
+++ b/niftypet/nimpa/__init__.py
@@ -37,7 +37,10 @@
'resample_mltp_spm', 'resample_niftyreg', 'resample_spm', 'resample_vinci', 'resample_dipy',
'time_stamp'] # yapf: disable
-from numcu import add, div, mul
+try:
+ from numcu import add, div, mul
+except ImportError:
+ pass
from pkg_resources import resource_filename
from niftypet.ninst import cudasetup as cs
diff --git a/pyproject.toml b/pyproject.toml
index 2d988c72..6582a23d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,7 @@
[build-system]
+# cuvec>=2.8.0
requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4",
- "ninst>=0.9.0", "cuvec>=2.8.0", "miutil[cuda]>=0.4.0",
+ "ninst>=0.9.0", "cuvec-base", "miutil[cuda]>=0.4.0",
"scikit-build>=0.11.0", "cmake>=3.18", "ninja"]
[tool.setuptools_scm]
diff --git a/setup.cfg b/setup.cfg
index 1bb95103..20b20fc5 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -43,21 +43,9 @@ setup_requires=
scikit-build>=0.11.0
cmake>=3.18
ninja
- cuvec>=2.8.0
+ cuvec-base
miutil[cuda]>=0.4.0
-install_requires=
- cuvec>=2.3.1
- dipy>=1.3.0
- miutil[nii]>=0.10.0
- nibabel>=2.4.0
- ninst>=0.4.0
- numcu
- numpy>=1.14
- pydicom>=1.0.2
- scipy
- setuptools
- spm12
- # SimpleITK>=1.2.0
+# cuvec>=2.8.0
python_requires=>=3.6
[options.extras_require]
dev=
diff --git a/setup.py b/setup.py
index bda42974..063b36b2 100755
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,6 @@
import re
import sys
from pathlib import Path
-from textwrap import dedent
from setuptools import find_packages, setup
from setuptools_scm import get_version
@@ -24,26 +23,12 @@
tls.check_platform()
ext = tls.check_depends() # external dependencies
-if not ext["git"]:
- raise SystemError(
- dedent("""\
- --------------------------------------------------------------
- Git is not installed but is required for tools installation.
- --------------------------------------------------------------"""))
-
cs.resources_setup(gpu=False) # install resources.py
try:
- gpuarch = cs.dev_setup() # update resources.py with a supported GPU device
+ cs.dev_setup() # update resources.py with a supported GPU device
except Exception as exc:
log.error("could not set up CUDA:\n%s", exc)
- gpuarch = None
-# First install third party apps for NiftyPET tools
-log.info(
- dedent("""\
- --------------------------------------------------------------
- Setting up NiftyPET tools ...
- --------------------------------------------------------------"""))
# get the local path to NiftyPET resources.py
path_resources = cs.path_niftypet_local()
# if exists, import the resources and get the constants
@@ -54,13 +39,18 @@
build_ver = ".".join(__version__.split('.')[:3]).split(".dev")[0]
setup_kwargs = {
"use_scm_version": True, "packages": find_packages(exclude=["tests"]),
- "package_data": {"niftypet": ["nimpa/auxdata/*"]}}
+ "package_data": {"niftypet": ["nimpa/auxdata/*"]}, "install_requires": [
+ 'dipy>=1.3.0', 'miutil[nii]>=0.10.0', 'nibabel>=2.4.0', 'ninst>=0.4.0', 'numpy>=1.14',
+ 'pydicom>=1.0.2', 'scipy', 'setuptools', 'spm12']}
+# 'SimpleITK>=1.2.0'
cmake_args = [
f"-DNIMPA_BUILD_VERSION={build_ver}", f"-DPython3_ROOT_DIR={sys.prefix}",
f"-DNIMPA_KERNEL_RADIUS={getattr(resources, 'RSZ_PSF_KRNL', 8)}"]
try:
+ import cuvec as cu
from skbuild import setup as sksetup
+ assert cu.include_path.is_dir()
nvcc_arches = {"{2:d}{3:d}".format(*i) for i in dinf.gpuinfo() if i[2:4] >= (3, 5)}
if nvcc_arches:
cmake_args.append("-DCMAKE_CUDA_ARCHITECTURES=" + ";".join(sorted(nvcc_arches)))
@@ -68,6 +58,7 @@
log.warning("Import or CUDA device detection error:\n%s", exc)
setup(**setup_kwargs)
else:
+ setup_kwargs['install_requires'].extend(["cuvec>=2.3.1", "numcu"])
for i in (Path(__file__).resolve().parent / "_skbuild").rglob("CMakeCache.txt"):
i.write_text(re.sub("^//.*$\n^[^#].*pip-build-env.*$", "", i.read_text(), flags=re.M))
sksetup(cmake_source_dir="niftypet", cmake_languages=("C", "CXX", "CUDA"),
From c06190a455b9c391d401ace81a4fe4e1bda53543 Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Tue, 10 May 2022 06:29:38 +0100
Subject: [PATCH 11/14] cuda option (for nipet)
---
setup.cfg | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.cfg b/setup.cfg
index 20b20fc5..0ea1fbed 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -45,7 +45,6 @@ setup_requires=
ninja
cuvec-base
miutil[cuda]>=0.4.0
-# cuvec>=2.8.0
python_requires=>=3.6
[options.extras_require]
dev=
@@ -55,6 +54,7 @@ dev=
pytest-timeout
pytest-xdist
plot=miutil[plot]
+cuda=cuvec>=2.3.1; numcu
dcm2niix=dcm2niix>=1.0.20220116
niftyreg=niftyreg
From 34f48805331ea421e72b9a9e705d1e0daf317f6d Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Tue, 10 May 2022 06:32:23 +0100
Subject: [PATCH 12/14] better installation note
---
README.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.rst b/README.rst
index 7e55b4ca..666b6701 100644
--- a/README.rst
+++ b/README.rst
@@ -34,7 +34,7 @@ It's also recommended (but not required) to use `conda`.
ipykernel numpy scipy scikit-image matplotlib ipywidgets
pip install "nimpa>=2"
-For optional `dcm2niix `_ and/or `niftyreg `_ support, use ``pip install nimpa[dcm2niix,niftyreg]>=2``.
+For optional `dcm2niix `_ and/or `niftyreg `_ support, simply install them separately (``conda install dcm2niix`` and/or ``pip install niftyreg``).
External CMake Projects
~~~~~~~~~~~~~~~~~~~~~~~
From 9aa5dcb58f6655ae8018745b887a56eeef822710 Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Tue, 10 May 2022 06:39:41 +0100
Subject: [PATCH 13/14] drop PATHTOOLS
---
.github/workflows/test.yml | 2 --
README.rst | 12 ++++--------
2 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 82a69e61..038ab33c 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -69,8 +69,6 @@ jobs:
gpg_key: ${{ secrets.GPG_KEY }}
password: ${{ secrets.PYPI_TOKEN }}
upload: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags') }}
- env:
- PATHTOOLS: ${{ github.workspace }}/NiftyPET_tools
- id: meta
name: Changelog
run: |
diff --git a/README.rst b/README.rst
index 666b6701..c9c09f67 100644
--- a/README.rst
+++ b/README.rst
@@ -21,20 +21,16 @@ In order to facilitate these operations, NIMPA relies on third-party software fo
Quick Install
~~~~~~~~~~~~~
-Note that installation prompts for setting the path to ``NiftyPET_tools``.
-This can be avoided by setting the environment variables ``PATHTOOLS``.
-It's also recommended (but not required) to use `conda`.
+Note that it's recommended (but not required) to use `conda`.
.. code:: sh
- # optional (Linux syntax) to avoid prompts
- export PATHTOOLS=$HOME/NiftyPET_tools
# cross-platform install
conda install -c conda-forge python=3 \
- ipykernel numpy scipy scikit-image matplotlib ipywidgets
+ ipykernel numpy scipy scikit-image matplotlib ipywidgets dcm2niix
pip install "nimpa>=2"
-For optional `dcm2niix `_ and/or `niftyreg `_ support, simply install them separately (``conda install dcm2niix`` and/or ``pip install niftyreg``).
+For optional `dcm2niix `_ and/or `niftyreg `_ support, simply install them separately (``pip install dcm2niix niftyreg``).
External CMake Projects
~~~~~~~~~~~~~~~~~~~~~~~
@@ -70,7 +66,7 @@ Licence
Copyright 2018-21
- `Pawel J. Markiewicz `__ @ University College London
-- `Casper O. da Costa-Luis `__ @ King's College London
+- `Casper O. da Costa-Luis `__ @ University College London/King's College London
- `Contributors `__
.. |Docs| image:: https://readthedocs.org/projects/niftypet/badge/?version=latest
From 35384a97021c5d24115037a7d7808111979195af Mon Sep 17 00:00:00 2001
From: Casper da Costa-Luis
Date: Tue, 10 May 2022 08:29:01 +0100
Subject: [PATCH 14/14] another comment
---
README.rst | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/README.rst b/README.rst
index c9c09f67..e529f29e 100644
--- a/README.rst
+++ b/README.rst
@@ -14,8 +14,6 @@ The upsampling is needed for more accurate extraction (sampling) of PET data usi
PVC is needed to correct for the spill-in and spill-out of PET signal from defined ROIs (specific for any given application).
-In order to facilitate these operations, NIMPA relies on third-party software for image conversion from DICOM to NIfTI (dcm2niix) and image registration (NiftyReg). The additional software is installed automatically to a user specified location.
-
**Documentation with installation manual and tutorials**: https://niftypet.readthedocs.io/
Quick Install
@@ -30,7 +28,7 @@ Note that it's recommended (but not required) to use `conda`.
ipykernel numpy scipy scikit-image matplotlib ipywidgets dcm2niix
pip install "nimpa>=2"
-For optional `dcm2niix `_ and/or `niftyreg `_ support, simply install them separately (``pip install dcm2niix niftyreg``).
+For optional `dcm2niix `_ (image conversion from DICOM to NIfTI) and/or `niftyreg `_ (image registration) support, simply install them separately (``pip install dcm2niix niftyreg``).
External CMake Projects
~~~~~~~~~~~~~~~~~~~~~~~