Skip to content

Commit

Permalink
Merge branch 'master' into brightness-control
Browse files Browse the repository at this point in the history
* master:
  Implements MTsat function (#1672)
  Keep intermediate temp folder by default (#1694)
  sct_deepseg_sc - Issue when input is .nii instead of .nii.gz (#1634, #1659)
  sct_image: remove file removal kludge (#1688) (#1705)
  Concatenate string to keep previously assigned subtitle field (fixes #1690) (#1692)
  Enable input file with label at a specific disc (#1698)

# Conflicts:
#	spinalcordtoolbox/gui/sagittal.py
  • Loading branch information
jcohenadad committed May 7, 2018
2 parents 862adae + ade1abe commit 66a79b1
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 55 deletions.
2 changes: 1 addition & 1 deletion scripts/msct_register.py
Expand Up @@ -38,7 +38,7 @@ def register_slicewise(fname_src,
paramreg=None,
ants_registration_params=None,
path_qc='./',
remove_temp_files=1,
remove_temp_files=0,
verbose=0):

# create temporary folder
Expand Down
98 changes: 98 additions & 0 deletions scripts/sct_compute_mtsat.py
@@ -0,0 +1,98 @@
#!/usr/bin/env python
# -*- coding: utf-8
#########################################################################################
#
# Compute MT saturation map and T1 map from a PD-weigthed, a T1-weighted and MT-weighted FLASH images
#
# Reference paper:
# Helms G, Dathe H, Kallenberg K, Dechent P. High-resolution maps of magnetization transfer with inherent correction
# for RF inhomogeneity and T1 relaxation obtained from 3D FLASH MRI. Magn Reson Med 2008;60(6):1396-1407.

# ---------------------------------------------------------------------------------------
# Copyright (c) 2018 Polytechnique Montreal <www.neuro.polymtl.ca>
# Author: Julien Cohen-Adad
#
# About the license: see the file LICENSE.TXT
#########################################################################################


import argparse


def get_parser():
parser = argparse.ArgumentParser(
description='Compute MTsat and T1map.'
'Reference: Helms G, Dathe H, Kallenberg K, Dechent P. High-resolution maps of magnetization '
'transfer with inherent correction for RF inhomogeneity and T1 relaxation obtained from 3D FLASH '
'MRI. Magn Reson Med 2008;60(6):1396-1407.')
parser.add_argument("-mt",
help="Image with MT_ON",
required=True)
parser.add_argument("-pd",
help="Image PD weighted (typically, the MT_OFF)",
required=True)
parser.add_argument("-t1",
help="Image T1-weighted",
required=True)
parser.add_argument("-trmt",
help="TR [in ms] for mt image.",
type=float,
required=True)
parser.add_argument("-trpd",
help="TR [in ms] for pd image.",
type=float,
required=True)
parser.add_argument("-trt1",
help="TR [in ms] for t1 image.",
type=float,
required=True)
parser.add_argument("-famt",
help="Flip angle [in deg] for mt image.",
type=float,
required=True)
parser.add_argument("-fapd",
help="Flip angle [in deg] for pd image.",
type=float,
required=True)
parser.add_argument("-fat1",
help="Flip angle [in deg] for t1 image.",
type=float,
required=True)
parser.add_argument("-b1map",
help="B1 map",
default=None)
parser.add_argument("-omtsat",
help="Output file for MTsat. Default is mtsat.nii.gz",
default=None)
parser.add_argument("-ot1map",
help="Output file for T1map. Default is t1map.nii.gz",
default=None)
parser.add_argument("-v",
help="Verbose: 0 = no verbosity, 1 = verbose (default).",
choices=('0', '1'),
type=int,
default=1)
return parser


def run_main(args):
import sct_utils as sct
from spinalcordtoolbox.mtsat import mtsat

sct.start_stream_logger()

fname_mtsat, fname_t1map = mtsat.compute_mtsat_from_file(
args.mt, args.pd, args.t1, args.trmt, args.trpd, args.trt1, args.famt, args.fapd, args.fat1,
fname_b1map=args.b1map, fname_mtsat=args.omtsat, fname_t1map=args.ot1map, verbose=1)

sct.display_viewer_syntax([fname_mtsat, fname_t1map],
colormaps=['gray', 'gray'],
minmax=['-10,10', '0, 3'],
opacities=['1', '1'],
verbose=args.v)


if __name__ == '__main__':
parser = get_parser()
arguments = parser.parse_args()
run_main(arguments)
6 changes: 3 additions & 3 deletions scripts/sct_deepseg_sc.py
Expand Up @@ -99,7 +99,7 @@ def _find_crop_start_end(coord_ctr, crop_size, im_dim):


def crop_image_around_centerline(im_in, ctr_in, im_out, crop_size, x_dim_half, y_dim_half):
im_in, im_ctr = Image(im_in), Image(ctr_in)
im_in, data_ctr = Image(im_in), Image(ctr_in).data

im_new = im_in.copy()
im_new.dim = tuple([crop_size, crop_size, im_in.dim[2]] + list(im_in.dim[3:]))
Expand All @@ -108,7 +108,7 @@ def crop_image_around_centerline(im_in, ctr_in, im_out, crop_size, x_dim_half, y

x_lst, y_lst = [], []
for zz in range(im_in.dim[2]):
x_ctr, y_ctr = center_of_mass(im_ctr.data[:, :, zz])
x_ctr, y_ctr = center_of_mass(np.array(data_ctr[:, :, zz]))

x_start, x_end = _find_crop_start_end(x_ctr, crop_size, im_in.dim[0])
y_start, y_end = _find_crop_start_end(y_ctr, crop_size, im_in.dim[1])
Expand All @@ -128,7 +128,7 @@ def crop_image_around_centerline(im_in, ctr_in, im_out, crop_size, x_dim_half, y

im_new.save()

del im_in, im_ctr
del im_in
del im_new

return x_lst, y_lst
Expand Down
28 changes: 22 additions & 6 deletions scripts/sct_image.py
Expand Up @@ -559,8 +559,17 @@ def multicomponent_merge(fname_list):
return im_out


def orientation(im, ori=None, set=False, get=False, set_data=False, verbose=1, fname_out=''):
def orientation(im, ori=None, set=False, get=False, set_data=False, verbose=1, fname_out=None):
"""
:param fname_out: when set is True, where to save the output file
(default: in cwd, named basename_orientation.ext)
:returns: when get, the orientation; when set, the changed image data (not saved)
"""
verbose = 0 if get else verbose

if fname_out is None:
fname_out = "{}_{}{}".format(im.file_name, ori, im.ext)

printv('Get dimensions of data...', verbose)
nx, ny, nz, nt, px, py, pz, pt = get_dimension(im)

Expand All @@ -580,9 +589,19 @@ def orientation(im, ori=None, set=False, get=False, set_data=False, verbose=1, f
elif set:
# set orientation
printv('Change orientation...', verbose)
tmp_folder = tmp_create(verbose)
curdir = os.getcwd()
os.chdir(tmp_folder)
im_out = set_orientation(im, ori)
os.chdir(curdir)
sct.rmtree(tmp_folder)
elif set_data:
tmp_folder = tmp_create(verbose)
curdir = os.getcwd()
os.chdir(tmp_folder)
im_out = set_orientation(im, ori, True)
os.chdir(curdir)
sct.rmtree(tmp_folder)
else:
im_out = None

Expand Down Expand Up @@ -646,12 +665,9 @@ def orientation(im, ori=None, set=False, get=False, set_data=False, verbose=1, f
os.chdir(curdir)
sct.rmtree(tmp_folder)

if fname_out:
if im_out is not None:
im_out.setFileName(fname_out)
if fname_out != im.file_name + '_' + ori + im.ext:
sct.rm(im.file_name + '_' + ori + im.ext)
else:
im_out.setFileName(im.file_name + '_' + ori + im.ext)

return im_out


Expand Down
69 changes: 29 additions & 40 deletions scripts/sct_label_vertebrae.py
Expand Up @@ -111,6 +111,10 @@ def get_parser():
type_value='file',
description='Initialize labeling by providing a text file which includes either -initz or -initcenter flag.',
mandatory=False)
parser.add_option(name="-initlabel",
type_value='file',
description='Initialize vertebral labeling by providing a nifti file that has a single disc label. An example of such file is a single voxel with value "3", which would be located at the posterior tip of C2-C3 disc. Such label file can be created using: sct_label_utils -i IMAGE_REF -create-viewer 3',
mandatory=False)
parser.add_option(name="-ofolder",
type_value="folder_creation",
description="Output folder.",
Expand Down Expand Up @@ -175,6 +179,9 @@ def main(args=None):
initz = ''
initcenter = ''
initc2 = 'auto'
fname_initlabel = ''
fname_labelz = 'labelz.nii.gz'
initauto = False
param = Param()

# check user arguments
Expand Down Expand Up @@ -213,6 +220,9 @@ def main(args=None):
initz = [int(x) for x in arg_initfile[idx_arg + 1].split(',')]
if arg == '-initcenter':
initcenter = int(arg_initfile[idx_arg + 1])
if '-initlabel' in arguments:
# get absolute path of label
fname_initlabel = os.path.abspath(arguments['-initlabel'])
if '-initc2' in arguments:
initc2 = 'manual'
if '-param' in arguments:
Expand All @@ -235,19 +245,26 @@ def main(args=None):

# create label to identify disc
sct.printv('\nCreate label to identify disc...', verbose)
initauto = False
if initz:
create_label_z('segmentation.nii.gz', initz[0], initz[1]) # create label located at z_center
create_label_z('segmentation.nii.gz', initz[0], initz[1], fname_labelz=fname_labelz) # create label located at z_center
elif initcenter:
# find z centered in FOV
nii = Image('segmentation.nii.gz')
nii.change_orientation('RPI') # reorient to RPI
nx, ny, nz, nt, px, py, pz, pt = nii.dim # Get dimensions
z_center = int(round(nz / 2)) # get z_center
create_label_z('segmentation.nii.gz', z_center, initcenter) # create label located at z_center
create_label_z('segmentation.nii.gz', z_center, initcenter, fname_labelz=fname_labelz) # create label located at z_center
elif fname_initlabel:
import sct_label_utils
# subtract "1" to label value because due to legacy, in this code the disc C2-C3 has value "2", whereas in the
# recent version of SCT it is defined as "3". Therefore, when asking the user to define a label, we point to the
# new definition of labels (i.e., C2-C3 = 3).
sct_label_utils.main(['-i', fname_initlabel, '-add', '-1', '-o', fname_labelz])
# dilate label so that it is not lost when applying warping
import sct_maths
sct_maths.main(['-i', fname_labelz, '-dilate', '3', '-o', fname_labelz])
else:
initauto = True
# printv('\nERROR: You need to initialize the disc detection algorithm using one of these two options: -initz, -initcenter\n', 1, 'error')

# Straighten spinal cord
sct.printv('\nStraighten spinal cord...', verbose)
Expand All @@ -269,8 +286,6 @@ def main(args=None):
# resample to 0.5mm isotropic to match template resolution
sct.printv('\nResample to 0.5mm isotropic...', verbose)
sct.run(['sct_resample', '-i', 'data_straight.nii', '-mm', '0.5x0.5x0.5', '-x', 'linear', '-o', 'data_straightr.nii'], verbose=verbose)
# sct.run('sct_resample -i segmentation.nii.gz -mm 0.5x0.5x0.5 -x linear -o segmentationr.nii.gz', verbose)
# sct.run('sct_resample -i labelz.nii.gz -mm 0.5x0.5x0.5 -x linear -o labelzr.nii', verbose)

# Apply straightening to segmentation
# N.B. Output is RPI
Expand All @@ -283,7 +298,7 @@ def main(args=None):
init_disc = []
else:
# Apply straightening to z-label
sct.printv('\nDilate z-label and apply straightening...', verbose)
sct.printv('\nAnd apply straightening to label...', verbose)
sct.run(['sct_apply_transfo', '-i', 'labelz.nii.gz', '-d', 'data_straightr.nii', '-w', 'warp_curve2straight.nii.gz', '-o', 'labelz_straight.nii.gz', '-x', 'nn'], verbose)
# get z value and disk value to initialize labeling
sct.printv('\nGet z and disc values from straight label...', verbose)
Expand Down Expand Up @@ -411,38 +426,12 @@ def vertebral_detection(fname, fname_seg, contrast, param, init_disc, verbose=1,
:return:
"""
sct.printv('\nLook for template...', verbose)
# if path_template == '':
# # get path of SCT
# from os import path
# path_script = path.dirname(__file__)
# path_sct = (path.dirname(path_script), 1)
# folder_template = 'data/template/'
# path_template = path_sct+folder_template
sct.printv('Path template: ' + path_template, verbose)

# adjust file names if MNI-Poly-AMU template is used
fname_level = get_file_label(os.path.join(path_template, 'template'), 'vertebral', output='filewithpath')
fname_template = get_file_label(os.path.join(path_template, 'template'), contrast.upper() + '-weighted', output='filewithpath')

# if not len(glob.glob(os.path.join(path_template, 'MNI-Poly-AMU*.*'))) == 0:
# contrast = contrast.upper()
# file_level = '*_level.nii.gz'
# else:
# file_level = '*_levels.nii.gz'
#
# # retrieve file_template based on contrast
# try:
# fname_template_list = glob.glob(os.path.join(path_template, '*' + contrast + '.nii.gz'))
# fname_template = fname_template_list[0]
# except IndexError:
# sct.printv('\nERROR: No template found. Please check the provided path.', 1, 'error')
# retrieve disc level from template
# try:
# fname_level_list = glob.glob(os.path.join(path_template, file_level))
# fname_level = fname_level_list[0]
# except IndexError:
# sct.printv('\nERROR: File *_levels.nii.gz not found.', 1, 'error')

# Open template and vertebral levels
sct.printv('\nOpen template and vertebral levels...', verbose)
data_template = Image(fname_template).data
Expand Down Expand Up @@ -660,14 +649,14 @@ def vertebral_detection(fname, fname_seg, contrast, param, init_disc, verbose=1,

# Create label
# ==========================================================================================
def create_label_z(fname_seg, z, value):
def create_label_z(fname_seg, z, value, fname_labelz='labelz.nii.gz'):
"""
Create a label at coordinates x_center, y_center, z
:param fname_seg: segmentation
:param z: int
:return: fname_label
:param fname_labelz: string file name of output label
:return: fname_labelz
"""
fname_label = 'labelz.nii.gz'
nii = Image(fname_seg)
orientation_origin = nii.change_orientation('RPI') # change orientation to RPI
nx, ny, nz, nt, px, py, pz, pt = nii.dim # Get dimensions
Expand All @@ -679,18 +668,18 @@ def create_label_z(fname_seg, z, value):
# dilate label to prevent it from disappearing due to nearestneighbor interpolation
from sct_maths import dilate
nii.data = dilate(nii.data, [3])
nii.setFileName(fname_label)
nii.setFileName(fname_labelz)
nii.change_orientation(orientation_origin) # put back in original orientation
nii.save()
return fname_label
return fname_labelz


# Get z and label value
# ==========================================================================================
def get_z_and_disc_values_from_label(fname_label):
"""
Find z-value and label-value based on labeled image
:param fname_label: image that contains label
Find z-value and label-value based on labeled image in RPI orientation
:param fname_label: image in RPI orientation that contains label
:return: [z_label, value_label] int list
"""
nii = Image(fname_label)
Expand Down
2 changes: 1 addition & 1 deletion scripts/sct_register_to_template.py
Expand Up @@ -140,7 +140,7 @@ def get_parser():
type_value="multiple_choice",
description="""Remove temporary files.""",
mandatory=False,
default_value='1',
default_value='0',
example=['0', '1'])
parser.add_option(name="-v",
type_value="multiple_choice",
Expand Down
4 changes: 2 additions & 2 deletions scripts/sct_utils.py
Expand Up @@ -319,8 +319,8 @@ def display_viewer_syntax(files, colormaps=[], minmax=[], opacities=[], mode='',
sct.display_viewer_syntax([file1, file2], colormaps=['gray', 'red'], minmax=['', '0,1'], opacities=['', '0.7'])
"""
list_viewer = ['fsleyes', 'fslview_deprecated', 'fslview'] # list of known viewers. Can add more.
dict_fslview = {'gray': 'Greyscale', 'red-yellow': 'Red-Yellow', 'blue-lightblue': 'Blue-Lightblue', 'red': 'Red', 'random': 'Random-Rainbow'}
dict_fsleyes = {'gray': 'greyscale', 'red-yellow': 'red-yellow', 'blue-lightblue': 'blue-lightblue', 'red': 'red', 'random': 'random'}
dict_fslview = {'gray': 'Greyscale', 'red-yellow': 'Red-Yellow', 'blue-lightblue': 'Blue-Lightblue', 'red': 'Red', 'random': 'Random-Rainbow', 'hsv': 'hsv'}
dict_fsleyes = {'gray': 'greyscale', 'red-yellow': 'red-yellow', 'blue-lightblue': 'blue-lightblue', 'red': 'red', 'random': 'random', 'hsv': 'hsv'}
selected_viewer = None

# find viewer
Expand Down
4 changes: 2 additions & 2 deletions spinalcordtoolbox/gui/sagittal.py
Expand Up @@ -92,8 +92,8 @@ def launch_sagittal_dialog(input_file, output_file, params):
if not params.vertebraes:
params.vertebraes = [3, 5]
params.input_file_name = input_file.absolutepath
params.subtitle = u'Use Left/Right arrows to navigate the right-left direction' \
'\nUse right click with left/right for brightness and up/down for contrast'
params.subtitle += u'Left/Right arrows: Navigate across slices.' \
'\nRight click: Change brightness (left/right) and contrast (up/down).'
controller = SagittalController(input_file, params, output_file)
controller.reformat_image()

Expand Down
Empty file.

0 comments on commit 66a79b1

Please sign in to comment.