예제 #1
0
    def get_im_from_list(self, data):
        im = Image(data)
        # set pix dimension
        im.hdr.structarr['pixdim'][1] = self.param_data.axial_res
        im.hdr.structarr['pixdim'][2] = self.param_data.axial_res
        # set the correct orientation
        im.save('im_to_orient.nii.gz')
        # TODO explain this quirk
        im = msct_image.change_orientation(im, 'IRP')
        im = msct_image.change_orientation(im, 'PIL', inverse=True)

        return im
    def get_im_from_list(self, data):
        im = Image(data)
        # set pix dimension
        im.hdr.structarr['pixdim'][1] = self.param_data.axial_res
        im.hdr.structarr['pixdim'][2] = self.param_data.axial_res
        # set the correct orientation
        im.save('im_to_orient.nii.gz')
        # TODO explain this quirk
        im = msct_image.change_orientation(im, 'IRP')
        im = msct_image.change_orientation(im, 'PIL', inverse=True)

        return im
def _call_viewer_centerline(fname_in, interslice_gap=20.0):
    from spinalcordtoolbox.gui.base import AnatomicalParams
    from spinalcordtoolbox.gui.centerline import launch_centerline_dialog

    im_data = Image(fname_in)

    # Get the number of slice along the (IS) axis
    im_tmp = msct_image.change_orientation(im_data, 'RPI')
    _, _, nz, _, _, _, pz, _ = im_tmp.dim
    del im_tmp

    params = AnatomicalParams()
    # setting maximum number of points to a reasonable value
    params.num_points = np.ceil(nz * pz / interslice_gap) + 2
    params.interval_in_mm = interslice_gap
    params.starting_slice = 'top'

    im_mask_viewer = msct_image.zeros_like(im_data)
    controller = launch_centerline_dialog(im_data, im_mask_viewer, params)
    fname_labels_viewer = sct.add_suffix(fname_in, '_viewer')

    if not controller.saved:
        sct.log.error(
            'The viewer has been closed before entering all manual points. Please try again.'
        )
        sys.exit(1)
    # save labels
    controller.as_niftii(fname_labels_viewer)

    return fname_labels_viewer
예제 #4
0
def test_change_nd_orientation(fake_4dimage_sct):
    import sct_image

    im_src = fake_4dimage_sct.copy()
    path_tmp = sct.tmp_create(basename="test_reorient")
    im_src.save(os.path.join(path_tmp, "src.nii"), mutable=True)

    print(im_src.orientation, im_src.data.shape)

    def orient2shape(orient):
        # test-data-specific thing
        letter2dim = dict(
         L=2,
         R=2,
         A=3,
         P=3,
         I=4,
         S=4,
        )
        return tuple([letter2dim[x] for x in orient] + [5])

    orientation = im_src.orientation
    assert orientation == "LPI"
    assert im_src.header.get_best_affine()[:3,3].tolist() == [0,0,0]

    im_dst = msct_image.change_orientation(im_src, "RPI")
    assert im_dst.orientation == "RPI"
    assert im_dst.data.shape == orient2shape("RPI")
    assert im_dst.header.get_best_affine()[:3,3].tolist() == [2-1,0,0]
예제 #5
0
def test_change_nd_orientation(fake_4dimage_sct):
    im_src = fake_4dimage_sct.copy()
    path_tmp = tmp_create(basename="test_reorient")
    im_src.save(os.path.join(path_tmp, "src.nii"), mutable=True)

    print(im_src.orientation, im_src.data.shape)

    def orient2shape(orient):
        # test-data-specific thing
        letter2dim = dict(
            L=2,
            R=2,
            A=3,
            P=3,
            I=4,
            S=4,
        )
        return tuple([letter2dim[x] for x in orient] + [5])

    orientation = im_src.orientation
    assert orientation == "LPI"
    assert im_src.header.get_best_affine()[:3, 3].tolist() == [0, 0, 0]

    im_dst = msct_image.change_orientation(im_src, "RPI")
    assert im_dst.orientation == "RPI"
    assert im_dst.data.shape == orient2shape("RPI")
    assert im_dst.header.get_best_affine()[:3, 3].tolist() == [2 - 1, 0, 0]
def resample_image(fname, suffix='_resampled.nii.gz', binary=False, npx=0.3, npy=0.3, thr=0.0, interpolation='spline'):
    """
    Resampling function: add a padding, resample, crop the padding
    :param fname: name of the image file to be resampled
    :param suffix: suffix added to the original fname after resampling
    :param binary: boolean, image is binary or not
    :param npx: new pixel size in the x direction
    :param npy: new pixel size in the y direction
    :param thr: if the image is binary, it will be thresholded at thr (default=0) after the resampling
    :param interpolation: type of interpolation used for the resampling
    :return: file name after resampling (or original fname if it was already in the correct resolution)
    """
    im_in = Image(fname)
    orientation = im_in.orientation
    if orientation != 'RPI':
        im_in.change_orientation('RPI')
        fname = add_suffix(im_in.absolutepath, "_rpi")
        im_in.save(path=fname, mutable=True)

    nx, ny, nz, nt, px, py, pz, pt = im_in.dim

    if np.round(px, 2) != np.round(npx, 2) or np.round(py, 2) != np.round(npy, 2):
        name_resample = extract_fname(fname)[1] + suffix
        if binary:
            interpolation = 'nn'

        if nz == 1:
            # when data is 2d: we convert it to a 3d image in order to avoid conversion problem with 2d data
            # TODO: check if this above problem is still present (now that we are using nibabel instead of nipy)
            run_proc(['sct_image', '-i', ','.join([fname, fname]), '-concat', 'z', '-o', fname])

        run_proc(['sct_resample', '-i', fname, '-mm', str(npx) + 'x' + str(npy) + 'x' + str(pz), '-o', name_resample, '-x', interpolation])

        if nz == 1:  # when input data was 2d: re-convert data 3d-->2d
            run_proc(['sct_image', '-i', name_resample, '-split', 'z'])
            im_split = Image(name_resample.split('.nii.gz')[0] + '_Z0000.nii.gz')
            im_split.save(name_resample)

        if binary:
            img = Image(name_resample)
            img.data = binarize(img.data, thr)
            img.save()

        if orientation != 'RPI':
            img = Image(name_resample)
            img.change_orientation(orientation)
            name_resample = add_suffix(img.absolutepath, "_{}".format(orientation.lower()))
            img.save(path=name_resample, mutable=True)

        return name_resample
    else:
        if orientation != 'RPI':
            fname = add_suffix(fname, "_RPI")
            im_in = change_orientation(im_in, orientation).save(fname)

        printv('Image resolution already ' + str(npx) + 'x' + str(npy) + 'xpz')
        return fname
def resample_image(fname, suffix='_resampled.nii.gz', binary=False, npx=0.3, npy=0.3, thr=0.0, interpolation='spline'):
    """
    Resampling function: add a padding, resample, crop the padding
    :param fname: name of the image file to be resampled
    :param suffix: suffix added to the original fname after resampling
    :param binary: boolean, image is binary or not
    :param npx: new pixel size in the x direction
    :param npy: new pixel size in the y direction
    :param thr: if the image is binary, it will be thresholded at thr (default=0) after the resampling
    :param interpolation: type of interpolation used for the resampling
    :return: file name after resampling (or original fname if it was already in the correct resolution)
    """
    im_in = Image(fname)
    orientation = im_in.orientation
    if orientation != 'RPI':
        fname = im_in.change_orientation(im_in, 'RPI', generate_path=True).save().absolutepath

    nx, ny, nz, nt, px, py, pz, pt = im_in.dim

    if np.round(px, 2) != np.round(npx, 2) or np.round(py, 2) != np.round(npy, 2):
        name_resample = sct.extract_fname(fname)[1] + suffix
        if binary:
            interpolation = 'nn'

        if nz == 1:  # when data is 2d: we convert it to a 3d image in order to avoid nipy problem of conversion nifti-->nipy with 2d data
            sct.run(['sct_image', '-i', ','.join([fname, fname]), '-concat', 'z', '-o', fname])

        sct.run(['sct_resample', '-i', fname, '-mm', str(npx) + 'x' + str(npy) + 'x' + str(pz), '-o', name_resample, '-x', interpolation])

        if nz == 1:  # when input data was 2d: re-convert data 3d-->2d
            sct.run(['sct_image', '-i', name_resample, '-split', 'z'])
            im_split = Image(name_resample.split('.nii.gz')[0] + '_Z0000.nii.gz')
            im_split.save(name_resample)

        if binary:
            sct.run(['sct_maths', '-i', name_resample, '-bin', str(thr), '-o', name_resample])

        if orientation != 'RPI':
            name_resample = Image(name_resample) \
             .change_orientation(orientation, generate_path=True) \
             .save() \
             .absolutepath

        return name_resample
    else:
        if orientation != 'RPI':
            fname = sct.add_suffix(fname, "_RPI")
            im_in = msct_image.change_orientation(im_in, orientation).save(fname)

        sct.printv('Image resolution already ' + str(npx) + 'x' + str(npy) + 'xpz')
        return fname
def resample_image(fname, suffix='_resampled.nii.gz', binary=False, npx=0.3, npy=0.3, thr=0.0, interpolation='spline'):
    """
    Resampling function: add a padding, resample, crop the padding
    :param fname: name of the image file to be resampled
    :param suffix: suffix added to the original fname after resampling
    :param binary: boolean, image is binary or not
    :param npx: new pixel size in the x direction
    :param npy: new pixel size in the y direction
    :param thr: if the image is binary, it will be thresholded at thr (default=0) after the resampling
    :param interpolation: type of interpolation used for the resampling
    :return: file name after resampling (or original fname if it was already in the correct resolution)
    """
    im_in = Image(fname)
    orientation = im_in.orientation
    if orientation != 'RPI':
        fname = im_in.change_orientation(im_in, 'RPI', generate_path=True).save().absolutepath

    nx, ny, nz, nt, px, py, pz, pt = im_in.dim

    if np.round(px, 2) != np.round(npx, 2) or np.round(py, 2) != np.round(npy, 2):
        name_resample = sct.extract_fname(fname)[1] + suffix
        if binary:
            interpolation = 'nn'

        if nz == 1:  # when data is 2d: we convert it to a 3d image in order to avoid nipy problem of conversion nifti-->nipy with 2d data
            sct.run(['sct_image', '-i', ','.join([fname, fname]), '-concat', 'z', '-o', fname])

        sct.run(['sct_resample', '-i', fname, '-mm', str(npx) + 'x' + str(npy) + 'x' + str(pz), '-o', name_resample, '-x', interpolation])

        if nz == 1:  # when input data was 2d: re-convert data 3d-->2d
            sct.run(['sct_image', '-i', name_resample, '-split', 'z'])
            im_split = Image(name_resample.split('.nii.gz')[0] + '_Z0000.nii.gz')
            im_split.save(name_resample)

        if binary:
            sct.run(['sct_maths', '-i', name_resample, '-bin', str(thr), '-o', name_resample])

        if orientation != 'RPI':
            name_resample = Image(name_resample) \
             .change_orientation(orientation, generate_path=True) \
             .save() \
             .absolutepath

        return name_resample
    else:
        if orientation != 'RPI':
            fname = sct.add_suffix(fname, "_RPI")
            im_in = msct_image.change_orientation(im_in, orientation).save(fname)

        sct.printv('Image resolution already ' + str(npx) + 'x' + str(npy) + 'xpz')
        return fname
예제 #9
0
def main(args=None):

    # initializations
    output_type = None
    param = Param()
    dim_list = ['x', 'y', 'z', 't']

    # check user arguments
    if not args:
        args = sys.argv[1:]

    # Get parser info
    parser = get_parser()
    arguments = parser.parse(args)
    fname_in = arguments["-i"]
    n_in = len(fname_in)
    verbose = int(arguments.get('-v'))
    sct.init_sct(log_level=verbose, update=True)  # Update log level

    if "-o" in arguments:
        fname_out = arguments["-o"]
    else:
        fname_out = None

    # Open file(s)
    # im_in_list = [Image(fn) for fn in fname_in]

    # run command
    if "-concat" in arguments:
        dim = arguments["-concat"]
        assert dim in dim_list
        dim = dim_list.index(dim)
        im_out = [concat_data(fname_in, dim)]  # TODO: adapt to fname_in

    elif "-copy-header" in arguments:
        im_in = Image(fname_in[0])
        im_dest = Image(arguments["-copy-header"])
        im_dest_new = im_in.copy()
        im_dest_new.data = im_dest.data.copy()
        # im_dest.header = im_in.header
        im_dest_new.absolutepath = im_dest.absolutepath
        im_out = [im_dest_new]
        fname_out = arguments["-copy-header"]

    elif '-display-warp' in arguments:
        im_in = fname_in[0]
        visualize_warp(im_in, fname_grid=None, step=3, rm_tmp=True)
        im_out = None

    elif "-getorient" in arguments:
        im_in = Image(fname_in[0])
        orient = im_in.orientation
        im_out = None

    elif '-keep-vol' in arguments:
        index_vol = arguments['-keep-vol']
        im_in = Image(fname_in[0])
        im_out = [remove_vol(im_in, index_vol, todo='keep')]

    elif '-mcs' in arguments:
        im_in = Image(fname_in[0])
        if n_in != 1:
            sct.printv(parser.usage.generate(error='ERROR: -mcs need only one input'))
        if len(im_in.data.shape) != 5:
            sct.printv(parser.usage.generate(error='ERROR: -mcs input need to be a multi-component image'))
        im_out = multicomponent_split(im_in)

    elif '-omc' in arguments:
        im_ref = Image(fname_in[0])
        for fname in fname_in:
            im = Image(fname)
            if im.data.shape != im_ref.data.shape:
                sct.printv(parser.usage.generate(error='ERROR: -omc inputs need to have all the same shapes'))
            del im
        im_out = [multicomponent_merge(fname_in)]  # TODO: adapt to fname_in

    elif "-pad" in arguments:
        im_in = Image(fname_in[0])
        ndims = len(im_in.data.shape)
        if ndims != 3:
            sct.printv('ERROR: you need to specify a 3D input file.', 1, 'error')
            return

        pad_arguments = arguments["-pad"].split(',')
        if len(pad_arguments) != 3:
            sct.printv('ERROR: you need to specify 3 padding values.', 1, 'error')

        padx, pady, padz = pad_arguments
        padx, pady, padz = int(padx), int(pady), int(padz)
        im_out = [pad_image(im_in, pad_x_i=padx, pad_x_f=padx, pad_y_i=pady,
                            pad_y_f=pady, pad_z_i=padz, pad_z_f=padz)]

    elif "-pad-asym" in arguments:
        im_in = Image(fname_in[0])
        ndims = len(im_in.data.shape)
        if ndims != 3:
            sct.printv('ERROR: you need to specify a 3D input file.', 1, 'error')
            return

        pad_arguments = arguments["-pad-asym"].split(',')
        if len(pad_arguments) != 6:
            sct.printv('ERROR: you need to specify 6 padding values.', 1, 'error')

        padxi, padxf, padyi, padyf, padzi, padzf = pad_arguments
        padxi, padxf, padyi, padyf, padzi, padzf = int(padxi), int(padxf), int(padyi), int(padyf), int(padzi), int(padzf)
        im_out = [pad_image(im_in, pad_x_i=padxi, pad_x_f=padxf, pad_y_i=padyi, pad_y_f=padyf, pad_z_i=padzi, pad_z_f=padzf)]

    elif '-remove-vol' in arguments:
        index_vol = arguments['-remove-vol']
        im_in = Image(fname_in[0])
        im_out = [remove_vol(im_in, index_vol, todo='remove')]

    elif "-setorient" in arguments:
        sct.printv(fname_in[0])
        im_in = Image(fname_in[0])
        im_out = [msct_image.change_orientation(im_in, arguments["-setorient"]).save(fname_out)]

    elif "-setorient-data" in arguments:
        im_in = Image(fname_in[0])
        im_out = [msct_image.change_orientation(im_in, arguments["-setorient-data"], inverse=True).save(fname_out)]

    elif "-split" in arguments:
        dim = arguments["-split"]
        assert dim in dim_list
        im_in = Image(fname_in[0])
        dim = dim_list.index(dim)
        im_out = split_data(im_in, dim)

    elif '-type' in arguments:
        output_type = arguments['-type']
        im_in = Image(fname_in[0])
        im_out = [im_in]  # TODO: adapt to fname_in

    else:
        im_out = None
        sct.printv(parser.usage.generate(error='ERROR: you need to specify an operation to do on the input image'))

    # in case fname_out is not defined, use first element of input file name list
    if fname_out == None:
        fname_out = fname_in[0]

    # Write output
    if im_out is not None:
        sct.printv('Generate output files...', verbose)
        # if only one output
        if len(im_out) == 1 and not '-split' in arguments:
            im_out[0].save(fname_out, dtype=output_type, verbose=verbose)
            sct.display_viewer_syntax([fname_out], verbose=verbose)
        if '-mcs' in arguments:
            # use input file name and add _X, _Y _Z. Keep the same extension
            l_fname_out = []
            for i_dim in range(3):
                l_fname_out.append(sct.add_suffix(fname_out or fname_in[0], '_' + dim_list[i_dim].upper()))
                im_out[i_dim].save(l_fname_out[i_dim], verbose=verbose)
            sct.display_viewer_syntax(fname_out)
        if '-split' in arguments:
            # use input file name and add _"DIM+NUMBER". Keep the same extension
            l_fname_out = []
            for i, im in enumerate(im_out):
                l_fname_out.append(sct.add_suffix(fname_out or fname_in[0], '_' + dim_list[dim].upper() + str(i).zfill(4)))
                im.save(l_fname_out[i])
            sct.display_viewer_syntax(l_fname_out)

    elif "-getorient" in arguments:
        sct.printv(orient)

    elif '-display-warp' in arguments:
        sct.printv('Warping grid generated.', verbose, 'info')
예제 #10
0
def test_more_change_orientation(fake_3dimage_sct, fake_3dimage_sct_vis):
    path_tmp = tmp_create(basename="test_reorient")
    path_tmp = "."

    im_src = fake_3dimage_sct.copy()
    im_src.save(os.path.join(path_tmp, "src.nii"), mutable=True)

    print(im_src.orientation, im_src.data.shape)

    def orient2shape(orient):
        # test-data-specific thing
        letter2dim = dict(
            L=7,
            R=7,
            A=8,
            P=8,
            I=9,
            S=9,
        )
        return tuple([letter2dim[x] for x in orient])

    orientation = im_src.orientation  # LPI
    assert im_src.header.get_best_affine()[:3, 3].tolist() == [0, 0, 0]
    im_dst = msct_image.change_orientation(im_src, "RPI")
    print(im_dst.orientation, im_dst.data.shape)
    assert im_dst.data.shape == orient2shape("RPI")
    assert im_dst.header.get_best_affine()[:3, 3].tolist() == [7 - 1, 0, 0]

    # spot check
    orientation = im_src.orientation  # LPI
    im_dst = msct_image.change_orientation(im_src, "IRP")
    print(im_dst.orientation, im_dst.data.shape)
    assert im_dst.data.shape == orient2shape("IRP")

    # to & fro
    im_dst2 = msct_image.change_orientation(im_dst, orientation)
    print(im_dst2.orientation, im_dst2.data.shape)
    assert im_dst2.orientation == im_src.orientation
    assert im_dst2.data.shape == orient2shape(orientation)
    assert (im_dst2.data == im_src.data).all()
    assert np.allclose(im_src.header.get_best_affine(),
                       im_dst2.header.get_best_affine())

    #fn = os.path.join(path_tmp, "pouet.nii")
    im_ref = fake_3dimage_sct.copy()
    im_src = fake_3dimage_sct.copy()
    orientation = im_src.orientation
    im_src.change_orientation("ASR").change_orientation(orientation)
    assert im_src.orientation == im_ref.orientation
    assert (im_dst2.data == im_src.data).all()
    assert np.allclose(im_src.header.get_best_affine(),
                       im_ref.header.get_best_affine())

    im_dst2 = msct_image.change_orientation(im_dst, orientation)
    print(im_dst2.orientation, im_dst2.data.shape)
    assert im_dst2.orientation == im_src.orientation
    assert im_dst2.data.shape == orient2shape(orientation)
    assert (im_dst2.data == im_src.data).all()
    assert np.allclose(im_src.header.get_best_affine(),
                       im_dst2.header.get_best_affine())

    # copy
    im_dst = im_src.copy().change_orientation("IRP")
    assert im_dst.data.shape == orient2shape("IRP")
    print(im_dst.orientation, im_dst.data.shape)

    print("Testing orientation persistence")
    img = im_src.copy()
    orientation = img.orientation
    fn = os.path.join(path_tmp, "pouet.nii")
    img.change_orientation("PIR").save(fn)
    assert img.data.shape == orient2shape("PIR")
    img = msct_image.Image(fn)
    assert img.orientation == "PIR"
    assert img.data.shape == orient2shape("PIR")
    print(img.orientation, img.data.shape)

    # typical pattern
    img = fake_3dimage_sct_vis.copy()
    print(img.header.get_best_affine())
    orientation = img.orientation
    path_tmp = "."
    fn = os.path.join(path_tmp, "vis.nii")
    fn2 = img.save(fn, mutable=True).change_orientation(
        "ALS", generate_path=True).save().absolutepath
    img = msct_image.Image(fn2)
    assert img.orientation == "ALS"
    assert img.data.shape == orient2shape("ALS")
    print(img.header.get_best_affine())

    fn2 = img.save(fn, mutable=True).change_orientation(
        "RAS", generate_path=True).save().absolutepath
    img = msct_image.Image(fn2)
    assert img.orientation == "RAS"
    assert img.data.shape == orient2shape("RAS")
    print(img.header.get_best_affine())

    fn2 = img.save(fn, mutable=True).change_orientation(
        "RPI", generate_path=True).save().absolutepath
    img = msct_image.Image(fn2)
    assert img.orientation == "RPI"
    assert img.data.shape == orient2shape("RPI")
    print(img.header.get_best_affine())

    fn2 = img.save(fn, mutable=True).change_orientation(
        "PLI", generate_path=True).save().absolutepath
    img = msct_image.Image(fn2)
    assert img.orientation == "PLI"
    assert img.data.shape == orient2shape("PLI")
    print(img.header.get_best_affine())

    # print(src.header)
    possibilities = [
        "ASR",
        "SRA",
        "RAS",
    ]
    possibilities = msct_image.all_refspace_strings()
    for orientation in possibilities:
        dst = msct_image.change_orientation(im_src, orientation)
        # dst.save("pouet-{}.nii".format(dst.orientation))
        print(orientation, dst.orientation, dst.data.shape, dst.dim)
        assert orientation == dst.orientation
예제 #11
0
def test_change_orientation(fake_3dimage_sct, fake_3dimage_sct_vis):

    path_tmp = tmp_create(basename="test_reorient")
    path_tmp = "."

    print("Spot-checking that physical coordinates don't change")
    for shape_is in (1, 2, 3):
        shape = (1, 1, shape_is)
        print("Simple image with shape {}".format(shape))

        data = np.ones(shape, order="F")
        data[:, :, shape_is - 1] += 1
        im_src = fake_3dimage_sct_custom(data)
        im_dst = msct_image.change_orientation(im_src, "ASR")
        # Basic check
        assert im_dst.orientation == "ASR"
        # Basic data check
        assert im_dst.data.mean() == im_src.data.mean()
        # Basic header check: check that the same voxel
        # remains at the same physical position
        aff_src = im_src.header.get_best_affine()
        aff_dst = im_dst.header.get_best_affine()

        # Take the extremities "a" & "z"...
        # consider the original LPI position
        pta_src = np.array([[0, 0, 0, 1]]).T
        ptz_src = np.array([[0, 0, shape_is - 1, 1]]).T
        # and the position in ASR
        pta_dst = np.array([[0, shape_is - 1, 0, 1]]).T
        ptz_dst = np.array([[0, 0, 0, 1]]).T
        # The physical positions should be:
        posa_src = np.matmul(aff_src, pta_src)
        posa_dst = np.matmul(aff_dst, pta_dst)
        print("A at src {}".format(posa_src.T))
        print("A at dst {}".format(posa_dst.T))
        posz_src = np.matmul(aff_src, ptz_src)
        posz_dst = np.matmul(aff_dst, ptz_dst)
        # and they should be equal
        assert (posa_src == posa_dst).all()
        assert (posz_src == posz_dst).all()
        fn = "".join(str(x) for x in im_src.data.shape)
        im_src.save("{}-src.nii".format(fn))
        im_dst.save("{}-dst.nii".format(fn))

    np.random.seed(0)

    print("More checking that physical coordinates don't change")
    if 1:
        shape = (7, 8, 9)
        print("Simple image with shape {}".format(shape))

        data = np.ones(shape, order="F") * 10
        data[4, 4, 4] = 4
        data[3, 3, 3] = 3
        data[0, 0, 0] = 0
        values = (0, 3, 4)

        im_ref = fake_3dimage_sct_custom(data)
        im_ref.header.set_xyzt_units("mm", "msec")

        import scipy.linalg

        def rand_rot():
            q, _ = scipy.linalg.qr(np.random.randn(3, 3))
            if scipy.linalg.det(q) < 0:
                q[:, 0] = -q[:, 0]
            return q

        affine = im_ref.header.get_best_affine()
        affine[:3, :3] = rand_rot()
        affine[3, :3] = 0.0
        affine[:3, 3] = np.random.random((3))
        affine[3, 3] = 1.0

        affine[0, 0] *= 2
        im_ref.header.set_sform(affine, code='scanner')

        orientations = msct_image.all_refspace_strings()
        for ori_src in orientations:
            for ori_dst in orientations:
                print("{} -> {}".format(ori_src, ori_dst))
                im_src = msct_image.change_orientation(im_ref, ori_src)
                im_dst = msct_image.change_orientation(im_src, ori_dst)

                assert im_src.orientation == ori_src
                assert im_dst.orientation == ori_dst
                assert im_dst.data.mean() == im_src.data.mean()

                # Basic header check: check that the same voxel
                # remains at the same physical position
                aff_src = im_src.header.get_best_affine()
                aff_dst = im_dst.header.get_best_affine()

                data_src = np.array(im_src.data)
                data_dst = np.array(im_dst.data)

                for value in values:
                    pt_src = np.argwhere(data_src == value)[0]
                    pt_dst = np.argwhere(data_dst == value)[0]

                    pos_src = np.matmul(
                        aff_src,
                        np.hstack((pt_src, [1])).reshape((4, 1)))
                    pos_dst = np.matmul(
                        aff_dst,
                        np.hstack((pt_dst, [1])).reshape((4, 1)))
                    if 0:
                        print("P at src {}".format(pos_src.T))
                        print("P at dst {}".format(pos_dst.T))
                    assert np.allclose(pos_src, pos_dst, atol=1e-3)
예제 #12
0
def main(args=None):

    # initializations
    output_type = None
    param = Param()
    dim_list = ['x', 'y', 'z', 't']

    # check user arguments
    if not args:
        args = sys.argv[1:]

    # Get parser info
    parser = get_parser()
    arguments = parser.parse(args)
    fname_in = arguments["-i"]
    n_in = len(fname_in)
    verbose = int(arguments.get('-v'))
    sct.init_sct(log_level=verbose, update=True)  # Update log level

    if "-o" in arguments:
        fname_out = arguments["-o"]
    else:
        fname_out = None

    # Open file(s)
    # im_in_list = [Image(fn) for fn in fname_in]

    # run command
    if "-concat" in arguments:
        dim = arguments["-concat"]
        assert dim in dim_list
        dim = dim_list.index(dim)
        im_out = [concat_data(fname_in, dim)]  # TODO: adapt to fname_in

    elif "-copy-header" in arguments:
        im_in = Image(fname_in[0])
        im_dest = Image(arguments["-copy-header"])
        im_dest_new = im_in.copy()
        im_dest_new.data = im_dest.data.copy()
        # im_dest.header = im_in.header
        im_dest_new.absolutepath = im_dest.absolutepath
        im_out = [im_dest_new]
        fname_out = arguments["-copy-header"]

    elif '-display-warp' in arguments:
        im_in = fname_in[0]
        visualize_warp(im_in, fname_grid=None, step=3, rm_tmp=True)
        im_out = None

    elif "-getorient" in arguments:
        im_in = Image(fname_in[0])
        orient = im_in.orientation
        im_out = None

    elif '-keep-vol' in arguments:
        index_vol = arguments['-keep-vol']
        im_in = Image(fname_in[0])
        im_out = [remove_vol(im_in, index_vol, todo='keep')]

    elif '-mcs' in arguments:
        im_in = Image(fname_in[0])
        if n_in != 1:
            sct.printv(
                parser.usage.generate(error='ERROR: -mcs need only one input'))
        if len(im_in.data.shape) != 5:
            sct.printv(
                parser.usage.generate(
                    error='ERROR: -mcs input need to be a multi-component image'
                ))
        im_out = multicomponent_split(im_in)

    elif '-omc' in arguments:
        im_ref = Image(fname_in[0])
        for fname in fname_in:
            im = Image(fname)
            if im.data.shape != im_ref.data.shape:
                sct.printv(
                    parser.usage.generate(
                        error=
                        'ERROR: -omc inputs need to have all the same shapes'))
            del im
        im_out = [multicomponent_merge(fname_in)]  # TODO: adapt to fname_in

    elif "-pad" in arguments:
        im_in = Image(fname_in[0])
        ndims = len(im_in.data.shape)
        if ndims != 3:
            sct.printv('ERROR: you need to specify a 3D input file.', 1,
                       'error')
            return

        pad_arguments = arguments["-pad"].split(',')
        if len(pad_arguments) != 3:
            sct.printv('ERROR: you need to specify 3 padding values.', 1,
                       'error')

        padx, pady, padz = pad_arguments
        padx, pady, padz = int(padx), int(pady), int(padz)
        im_out = [
            pad_image(im_in,
                      pad_x_i=padx,
                      pad_x_f=padx,
                      pad_y_i=pady,
                      pad_y_f=pady,
                      pad_z_i=padz,
                      pad_z_f=padz)
        ]

    elif "-pad-asym" in arguments:
        im_in = Image(fname_in[0])
        ndims = len(im_in.data.shape)
        if ndims != 3:
            sct.printv('ERROR: you need to specify a 3D input file.', 1,
                       'error')
            return

        pad_arguments = arguments["-pad-asym"].split(',')
        if len(pad_arguments) != 6:
            sct.printv('ERROR: you need to specify 6 padding values.', 1,
                       'error')

        padxi, padxf, padyi, padyf, padzi, padzf = pad_arguments
        padxi, padxf, padyi, padyf, padzi, padzf = int(padxi), int(padxf), int(
            padyi), int(padyf), int(padzi), int(padzf)
        im_out = [
            pad_image(im_in,
                      pad_x_i=padxi,
                      pad_x_f=padxf,
                      pad_y_i=padyi,
                      pad_y_f=padyf,
                      pad_z_i=padzi,
                      pad_z_f=padzf)
        ]

    elif '-remove-vol' in arguments:
        index_vol = arguments['-remove-vol']
        im_in = Image(fname_in[0])
        im_out = [remove_vol(im_in, index_vol, todo='remove')]

    elif "-setorient" in arguments:
        sct.printv(fname_in[0])
        im_in = Image(fname_in[0])
        im_out = [
            msct_image.change_orientation(
                im_in, arguments["-setorient"]).save(fname_out)
        ]

    elif "-setorient-data" in arguments:
        im_in = Image(fname_in[0])
        im_out = [
            msct_image.change_orientation(im_in,
                                          arguments["-setorient-data"],
                                          inverse=True).save(fname_out)
        ]

    elif "-split" in arguments:
        dim = arguments["-split"]
        assert dim in dim_list
        im_in = Image(fname_in[0])
        dim = dim_list.index(dim)
        im_out = split_data(im_in, dim)

    elif '-type' in arguments:
        output_type = arguments['-type']
        im_in = Image(fname_in[0])
        im_out = [im_in]  # TODO: adapt to fname_in

    else:
        im_out = None
        sct.printv(
            parser.usage.generate(
                error=
                'ERROR: you need to specify an operation to do on the input image'
            ))

    # in case fname_out is not defined, use first element of input file name list
    if fname_out == None:
        fname_out = fname_in[0]

    # Write output
    if im_out is not None:
        sct.printv('Generate output files...', verbose)
        # if only one output
        if len(im_out) == 1 and not '-split' in arguments:
            im_out[0].save(fname_out, dtype=output_type, verbose=verbose)
            sct.display_viewer_syntax([fname_out], verbose=verbose)
        if '-mcs' in arguments:
            # use input file name and add _X, _Y _Z. Keep the same extension
            l_fname_out = []
            for i_dim in range(3):
                l_fname_out.append(
                    sct.add_suffix(fname_out or fname_in[0],
                                   '_' + dim_list[i_dim].upper()))
                im_out[i_dim].save(l_fname_out[i_dim], verbose=verbose)
            sct.display_viewer_syntax(fname_out)
        if '-split' in arguments:
            # use input file name and add _"DIM+NUMBER". Keep the same extension
            l_fname_out = []
            for i, im in enumerate(im_out):
                l_fname_out.append(
                    sct.add_suffix(
                        fname_out or fname_in[0],
                        '_' + dim_list[dim].upper() + str(i).zfill(4)))
                im.save(l_fname_out[i])
            sct.display_viewer_syntax(l_fname_out)

    elif "-getorient" in arguments:
        sct.printv(orient)

    elif '-display-warp' in arguments:
        sct.printv('Warping grid generated.', verbose, 'info')
def deep_segmentation_MSlesion(fname_image, contrast_type, output_folder, ctr_algo='svm', ctr_file=None, brain_bool=True, remove_temp_files=1, verbose=1):
    """Pipeline."""
    path_script = os.path.dirname(__file__)
    path_sct = os.path.dirname(path_script)

    # create temporary folder with intermediate results
    sct.log.info("\nCreating temporary folder...")
    file_fname = os.path.basename(fname_image)
    tmp_folder = sct.TempFolder()
    tmp_folder_path = tmp_folder.get_path()
    fname_image_tmp = tmp_folder.copy_from(fname_image)
    if ctr_algo == 'manual':  # if the ctr_file is provided
        tmp_folder.copy_from(ctr_file)
        file_ctr = os.path.basename(ctr_file)
    else:
        file_ctr = None
    tmp_folder.chdir()

    # orientation of the image, should be RPI
    sct.log.info("\nReorient the image to RPI, if necessary...")
    fname_orient = sct.add_suffix(file_fname, '_RPI')
    im_2orient = Image(file_fname)
    original_orientation = im_2orient.orientation
    if original_orientation != 'RPI':
        im_orient = msct_image.change_orientation(im_2orient, 'RPI').save(fname_orient)
    else:
        im_orient = im_2orient
        sct.copy(fname_image_tmp, fname_orient)

    input_resolution = im_orient.dim[4:7]
    del im_2orient, im_orient

    # find the spinal cord centerline - execute OptiC binary
    sct.log.info("\nFinding the spinal cord centerline...")
    contrast_type_ctr = contrast_type.split('_')[0]
    fname_res, centerline_filename = find_centerline(algo=ctr_algo,
                                                    image_fname=fname_orient,
                                                    path_sct=path_sct,
                                                    contrast_type=contrast_type_ctr,
                                                    brain_bool=brain_bool,
                                                    folder_output=tmp_folder_path,
                                                    remove_temp_files=remove_temp_files,
                                                    centerline_fname=file_ctr)
    im_nii, ctr_nii = Image(fname_res), Image(centerline_filename)

    # crop image around the spinal cord centerline
    sct.log.info("\nCropping the image around the spinal cord...")
    fname_crop = sct.add_suffix(fname_res, '_crop')
    crop_size = 48
    X_CROP_LST, Y_CROP_LST, im_crop_nii = crop_image_around_centerline(im_in=im_nii,
                                                                      ctr_in=ctr_nii,
                                                                      crop_size=crop_size)
    del ctr_nii

    # normalize the intensity of the images
    sct.log.info("Normalizing the intensity...")
    im_norm_in = apply_intensity_normalization(img=im_crop_nii, contrast=contrast_type)
    del im_crop_nii

    # resample to 0.5mm isotropic
    fname_norm = sct.add_suffix(fname_orient, '_norm')
    im_norm_in.save(fname_norm)
    fname_res3d = sct.add_suffix(fname_norm, '_resampled3d')
    spinalcordtoolbox.resample.nipy_resample.resample_file(fname_norm, fname_res3d, '0.5x0.5x0.5',
                                                               'mm', 'linear', verbose=0)

    # segment data using 3D convolutions
    sct.log.info("\nSegmenting the MS lesions using deep learning on 3D patches...")
    segmentation_model_fname = os.path.join(path_sct, 'data', 'deepseg_lesion_models', '{}_lesion.h5'.format(contrast_type))
    fname_seg_crop_res = sct.add_suffix(fname_res3d, '_lesionseg')
    segment_3d(model_fname=segmentation_model_fname,
                contrast_type=contrast_type,
                fname_in=fname_res3d,
                fname_out=fname_seg_crop_res)

    # resample to the initial pz resolution
    fname_seg_res2d = sct.add_suffix(fname_seg_crop_res, '_resampled2d')
    initial_2d_resolution = 'x'.join(['0.5', '0.5', str(input_resolution[2])])
    spinalcordtoolbox.resample.nipy_resample.resample_file(fname_seg_crop_res, fname_seg_res2d, initial_2d_resolution,
                                                           'mm', 'linear', verbose=0)
    seg_crop_data = Image(fname_seg_res2d).data

    # reconstruct the segmentation from the crop data
    sct.log.info("\nReassembling the image...")
    seg_uncrop_nii = uncrop_image(ref_in=im_nii,
                                data_crop=seg_crop_data,
                                x_crop_lst=X_CROP_LST,
                                y_crop_lst=Y_CROP_LST)
    fname_seg_res_RPI = sct.add_suffix(file_fname, '_res_RPI_seg')
    seg_uncrop_nii.save(fname_seg_res_RPI)
    del seg_uncrop_nii, im_nii, seg_crop_data

    # resample to initial resolution
    sct.log.info("Resampling the segmentation to the original image resolution...")
    initial_resolution = 'x'.join([str(input_resolution[0]), str(input_resolution[1]), str(input_resolution[2])])
    fname_seg_RPI = sct.add_suffix(file_fname, '_RPI_seg')
    spinalcordtoolbox.resample.nipy_resample.resample_file(fname_seg_res_RPI, fname_seg_RPI, initial_resolution,
                                                           'mm', 'linear', verbose=0)
    seg_initres_nii = Image(fname_seg_RPI)

    # binarize the resampled image to remove interpolation effects
    sct.log.info("\nBinarizing the segmentation to avoid interpolation effects...")
    thr = 0.1
    seg_initres_nii.data[np.where(seg_initres_nii.data >= thr)] = 1
    seg_initres_nii.data[np.where(seg_initres_nii.data < thr)] = 0

    # reorient to initial orientation
    sct.log.info("\nReorienting the segmentation to the original image orientation...")
    fname_seg = sct.add_suffix(file_fname, '_seg')
    if original_orientation != 'RPI':
        out_nii = msct_image.change_orientation(seg_initres_nii, original_orientation)
    
    seg_initres_nii.save(fname_seg)
    del seg_initres_nii

    tmp_folder.chdir_undo()

    # copy image from temporary folder into output folder
    sct.copy(os.path.join(tmp_folder_path, fname_seg), output_folder)

    # remove temporary files
    if remove_temp_files:
        sct.log.info("\nRemove temporary files...")
        tmp_folder.cleanup()

    return os.path.join(output_folder, fname_seg)
예제 #14
0
def main(args=None):
    """
    Main function
    :param args:
    :return:
    """
    # initializations
    output_type = None
    dim_list = ['x', 'y', 'z', 't']

    # Get parser args
    if args is None:
        args = None if sys.argv[1:] else ['--help']
    parser = get_parser()
    arguments = parser.parse_args(args=args)
    fname_in = arguments.i
    n_in = len(fname_in)
    verbose = arguments.v
    sct.init_sct(log_level=verbose, update=True)  # Update log level

    if arguments.o is not None:
        fname_out = arguments.o
    else:
        fname_out = None

    # Run command
    # Arguments are sorted alphabetically (not according to the usage order)
    if arguments.concat is not None:
        dim = arguments.concat
        assert dim in dim_list
        dim = dim_list.index(dim)
        im_out = [concat_data(fname_in, dim)]  # TODO: adapt to fname_in

    elif arguments.copy_header is not None:
        im_in = Image(fname_in[0])
        im_dest = Image(arguments.copy_header)
        im_dest_new = im_in.copy()
        im_dest_new.data = im_dest.data.copy()
        # im_dest.header = im_in.header
        im_dest_new.absolutepath = im_dest.absolutepath
        im_out = [im_dest_new]
        fname_out = arguments.copy_header

    elif arguments.display_warp:
        im_in = fname_in[0]
        visualize_warp(im_in, fname_grid=None, step=3, rm_tmp=True)
        im_out = None

    elif arguments.getorient:
        im_in = Image(fname_in[0])
        orient = im_in.orientation
        im_out = None

    elif arguments.keep_vol is not None:
        index_vol = (arguments.keep_vol).split(',')
        for iindex_vol, vol in enumerate(index_vol):
            index_vol[iindex_vol] = int(vol)
        im_in = Image(fname_in[0])
        im_out = [remove_vol(im_in, index_vol, todo='keep')]

    elif arguments.mcs:
        im_in = Image(fname_in[0])
        if n_in != 1:
            sct.printv(parser.error('ERROR: -mcs need only one input'))
        if len(im_in.data.shape) != 5:
            sct.printv(
                parser.error(
                    'ERROR: -mcs input need to be a multi-component image'))
        im_out = multicomponent_split(im_in)

    elif arguments.omc:
        im_ref = Image(fname_in[0])
        for fname in fname_in:
            im = Image(fname)
            if im.data.shape != im_ref.data.shape:
                sct.printv(
                    parser.error(
                        'ERROR: -omc inputs need to have all the same shapes'))
            del im
        im_out = [multicomponent_merge(fname_in)]  # TODO: adapt to fname_in

    elif arguments.pad is not None:
        im_in = Image(fname_in[0])
        ndims = len(im_in.data.shape)
        if ndims != 3:
            sct.printv('ERROR: you need to specify a 3D input file.', 1,
                       'error')
            return

        pad_arguments = arguments.pad.split(',')
        if len(pad_arguments) != 3:
            sct.printv('ERROR: you need to specify 3 padding values.', 1,
                       'error')

        padx, pady, padz = pad_arguments
        padx, pady, padz = int(padx), int(pady), int(padz)
        im_out = [
            pad_image(im_in,
                      pad_x_i=padx,
                      pad_x_f=padx,
                      pad_y_i=pady,
                      pad_y_f=pady,
                      pad_z_i=padz,
                      pad_z_f=padz)
        ]

    elif arguments.pad_asym is not None:
        im_in = Image(fname_in[0])
        ndims = len(im_in.data.shape)
        if ndims != 3:
            sct.printv('ERROR: you need to specify a 3D input file.', 1,
                       'error')
            return

        pad_arguments = arguments.pad_asym.split(',')
        if len(pad_arguments) != 6:
            sct.printv('ERROR: you need to specify 6 padding values.', 1,
                       'error')

        padxi, padxf, padyi, padyf, padzi, padzf = pad_arguments
        padxi, padxf, padyi, padyf, padzi, padzf = int(padxi), int(padxf), int(
            padyi), int(padyf), int(padzi), int(padzf)
        im_out = [
            pad_image(im_in,
                      pad_x_i=padxi,
                      pad_x_f=padxf,
                      pad_y_i=padyi,
                      pad_y_f=padyf,
                      pad_z_i=padzi,
                      pad_z_f=padzf)
        ]

    elif arguments.remove_vol is not None:
        index_vol = (arguments.remove_vol).split(',')
        for iindex_vol, vol in enumerate(index_vol):
            index_vol[iindex_vol] = int(vol)
        im_in = Image(fname_in[0])
        im_out = [remove_vol(im_in, index_vol, todo='remove')]

    elif arguments.setorient is not None:
        sct.printv(fname_in[0])
        im_in = Image(fname_in[0])
        im_out = [msct_image.change_orientation(im_in, arguments.setorient)]

    elif arguments.setorient_data is not None:
        im_in = Image(fname_in[0])
        im_out = [
            msct_image.change_orientation(im_in,
                                          arguments.setorient_data,
                                          data_only=True)
        ]

    elif arguments.split is not None:
        dim = arguments.split
        assert dim in dim_list
        im_in = Image(fname_in[0])
        dim = dim_list.index(dim)
        im_out = split_data(im_in, dim)

    elif arguments.type is not None:
        output_type = arguments.type
        im_in = Image(fname_in[0])
        im_out = [im_in]  # TODO: adapt to fname_in

    elif arguments.to_fsl is not None:
        space_files = arguments.to_fsl
        if len(space_files) > 2 or len(space_files) < 1:
            sct.printv(parser.error('ERROR: -to-fsl expects 1 or 2 arguments'))
            return
        spaces = [Image(s) for s in space_files]
        if len(spaces) < 2:
            spaces.append(None)
        im_out = [
            displacement_to_abs_fsl(Image(fname_in[0]), spaces[0], spaces[1])
        ]

    else:
        im_out = None
        sct.printv(
            parser.error(
                'ERROR: you need to specify an operation to do on the input image'
            ))

    # in case fname_out is not defined, use first element of input file name list
    if fname_out is None:
        fname_out = fname_in[0]

    # Write output
    if im_out is not None:
        sct.printv('Generate output files...', verbose)
        # if only one output
        if len(im_out) == 1 and not '-split' in arguments:
            im_out[0].save(fname_out, dtype=output_type, verbose=verbose)
            sct.display_viewer_syntax([fname_out], verbose=verbose)
        if arguments.mcs:
            # use input file name and add _X, _Y _Z. Keep the same extension
            l_fname_out = []
            for i_dim in range(3):
                l_fname_out.append(
                    sct.add_suffix(fname_out or fname_in[0],
                                   '_' + dim_list[i_dim].upper()))
                im_out[i_dim].save(l_fname_out[i_dim], verbose=verbose)
            sct.display_viewer_syntax(fname_out)
        if arguments.split is not None:
            # use input file name and add _"DIM+NUMBER". Keep the same extension
            l_fname_out = []
            for i, im in enumerate(im_out):
                l_fname_out.append(
                    sct.add_suffix(
                        fname_out or fname_in[0],
                        '_' + dim_list[dim].upper() + str(i).zfill(4)))
                im.save(l_fname_out[i])
            sct.display_viewer_syntax(l_fname_out)

    elif arguments.getorient:
        sct.printv(orient)

    elif arguments.display_warp:
        sct.printv('Warping grid generated.', verbose, 'info')
예제 #15
0
def test_more_change_orientation(fake_3dimage_sct, fake_3dimage_sct_vis):
    path_tmp = sct.tmp_create(basename="test_reorient")
    path_tmp = "."

    im_src = fake_3dimage_sct.copy()
    im_src.save(os.path.join(path_tmp, "src.nii"), mutable=True)

    print(im_src.orientation, im_src.data.shape)

    def orient2shape(orient):
        # test-data-specific thing
        letter2dim = dict(
         L=7,
         R=7,
         A=8,
         P=8,
         I=9,
         S=9,
        )
        return tuple([letter2dim[x] for x in orient])

    orientation = im_src.orientation # LPI
    assert im_src.header.get_best_affine()[:3,3].tolist() == [0,0,0]
    im_dst = msct_image.change_orientation(im_src, "RPI")
    print(im_dst.orientation, im_dst.data.shape)
    assert im_dst.data.shape == orient2shape("RPI")
    assert im_dst.header.get_best_affine()[:3,3].tolist() == [7-1,0,0]

    # spot check
    orientation = im_src.orientation # LPI
    im_dst = msct_image.change_orientation(im_src, "IRP")
    print(im_dst.orientation, im_dst.data.shape)
    assert im_dst.data.shape == orient2shape("IRP")

    # to & fro
    im_dst2 = msct_image.change_orientation(im_dst, orientation)
    print(im_dst2.orientation, im_dst2.data.shape)
    assert im_dst2.orientation == im_src.orientation
    assert im_dst2.data.shape == orient2shape(orientation)
    assert (im_dst2.data == im_src.data).all()
    assert np.allclose(im_src.header.get_best_affine(), im_dst2.header.get_best_affine())


    #fn = os.path.join(path_tmp, "pouet.nii")
    im_ref = fake_3dimage_sct.copy()
    im_src = fake_3dimage_sct.copy()
    orientation = im_src.orientation
    im_src.change_orientation("ASR").change_orientation(orientation)
    assert im_src.orientation == im_ref.orientation
    assert (im_dst2.data == im_src.data).all()
    assert np.allclose(im_src.header.get_best_affine(), im_ref.header.get_best_affine())


    im_dst2 = msct_image.change_orientation(im_dst, orientation)
    print(im_dst2.orientation, im_dst2.data.shape)
    assert im_dst2.orientation == im_src.orientation
    assert im_dst2.data.shape == orient2shape(orientation)
    assert (im_dst2.data == im_src.data).all()
    assert np.allclose(im_src.header.get_best_affine(), im_dst2.header.get_best_affine())



    # copy
    im_dst = im_src.copy().change_orientation("IRP")
    assert im_dst.data.shape == orient2shape("IRP")
    print(im_dst.orientation, im_dst.data.shape)


    print("Testing orientation persistence")
    img = im_src.copy()
    orientation = img.orientation
    fn = os.path.join(path_tmp, "pouet.nii")
    img.change_orientation("PIR").save(fn)
    assert img.data.shape == orient2shape("PIR")
    img = msct_image.Image(fn)
    assert img.orientation == "PIR"
    assert img.data.shape == orient2shape("PIR")
    print(img.orientation, img.data.shape)

    # typical pattern
    img = fake_3dimage_sct_vis.copy()
    print(img.header.get_best_affine())
    orientation = img.orientation
    path_tmp = "."
    fn = os.path.join(path_tmp, "vis.nii")
    fn2 = img.save(fn, mutable=True).change_orientation("ALS", generate_path=True).save().absolutepath
    img = msct_image.Image(fn2)
    assert img.orientation == "ALS"
    assert img.data.shape == orient2shape("ALS")
    print(img.header.get_best_affine())

    fn2 = img.save(fn, mutable=True).change_orientation("RAS", generate_path=True).save().absolutepath
    img = msct_image.Image(fn2)
    assert img.orientation == "RAS"
    assert img.data.shape == orient2shape("RAS")
    print(img.header.get_best_affine())


    fn2 = img.save(fn, mutable=True).change_orientation("RPI", generate_path=True).save().absolutepath
    img = msct_image.Image(fn2)
    assert img.orientation == "RPI"
    assert img.data.shape == orient2shape("RPI")
    print(img.header.get_best_affine())

    fn2 = img.save(fn, mutable=True).change_orientation("PLI", generate_path=True).save().absolutepath
    img = msct_image.Image(fn2)
    assert img.orientation == "PLI"
    assert img.data.shape == orient2shape("PLI")
    print(img.header.get_best_affine())

    #print(src.header)
    possibilities = [ "ASR", "SRA", "RAS", ]
    possibilities = msct_image.all_refspace_strings()
    for orientation in possibilities:
        dst = msct_image.change_orientation(im_src, orientation)
        #dst.save("pouet-{}.nii".format(dst.orientation))
        print(orientation, dst.orientation, dst.data.shape, dst.dim)
        assert orientation == dst.orientation
예제 #16
0
def main(argv=None):
    """
    Main function
    :param argv:
    :return:
    """
    parser = get_parser()
    arguments = parser.parse_args(argv)
    verbose = arguments.v
    set_loglevel(verbose=verbose)

    # initializations
    output_type = None
    dim_list = ['x', 'y', 'z', 't']

    fname_in = arguments.i

    im_in_list = [Image(fname) for fname in fname_in]
    if len(im_in_list
           ) > 1 and arguments.concat is None and arguments.omc is None:
        parser.error(
            "Multi-image input is only supported for the '-concat' and '-omc' arguments."
        )

    # Apply initialization steps to all input images first
    if arguments.set_sform_to_qform:
        [im.set_sform_to_qform() for im in im_in_list]
    elif arguments.set_qform_to_sform:
        [im.set_qform_to_sform() for im in im_in_list]

    # Most sct_image options don't accept multi-image input, so here we simply separate out the first image
    # TODO: Extend the options so that they iterate through the list of images (to support multi-image input)
    im_in = im_in_list[0]

    if arguments.o is not None:
        fname_out = arguments.o
    else:
        fname_out = None

    # Run command
    # Arguments are sorted alphabetically (not according to the usage order)
    if arguments.concat is not None:
        dim = arguments.concat
        assert dim in dim_list
        dim = dim_list.index(dim)
        im_out = [concat_data(im_in_list, dim)]

    elif arguments.copy_header is not None:
        if fname_out is None:
            raise ValueError("Need to specify output image with -o!")
        im_dest = Image(arguments.copy_header)
        im_dest_new = im_in.copy()
        im_dest_new.data = im_dest.data.copy()
        # im_dest.header = im_in.header
        im_dest_new.absolutepath = im_dest.absolutepath
        im_out = [im_dest_new]

    elif arguments.display_warp:
        visualize_warp(im_warp=im_in, im_grid=None, step=3, rm_tmp=True)
        im_out = None

    elif arguments.getorient:
        orient = im_in.orientation
        im_out = None

    elif arguments.keep_vol is not None:
        index_vol = (arguments.keep_vol).split(',')
        for iindex_vol, vol in enumerate(index_vol):
            index_vol[iindex_vol] = int(vol)
        im_out = [remove_vol(im_in, index_vol, todo='keep')]

    elif arguments.mcs:
        if len(im_in.data.shape) != 5:
            printv(
                parser.error(
                    'ERROR: -mcs input need to be a multi-component image'))
        im_out = multicomponent_split(im_in)

    elif arguments.omc:
        im_ref = im_in_list[0]
        for im in im_in_list:
            if im.data.shape != im_ref.data.shape:
                printv(
                    parser.error(
                        'ERROR: -omc inputs need to have all the same shapes'))
            del im
        im_out = [multicomponent_merge(im_in_list=im_in_list)]

    elif arguments.pad is not None:
        ndims = len(im_in.data.shape)
        if ndims != 3:
            printv('ERROR: you need to specify a 3D input file.', 1, 'error')
            return

        pad_arguments = arguments.pad.split(',')
        if len(pad_arguments) != 3:
            printv('ERROR: you need to specify 3 padding values.', 1, 'error')

        padx, pady, padz = pad_arguments
        padx, pady, padz = int(padx), int(pady), int(padz)
        im_out = [
            pad_image(im_in,
                      pad_x_i=padx,
                      pad_x_f=padx,
                      pad_y_i=pady,
                      pad_y_f=pady,
                      pad_z_i=padz,
                      pad_z_f=padz)
        ]

    elif arguments.pad_asym is not None:
        ndims = len(im_in.data.shape)
        if ndims != 3:
            printv('ERROR: you need to specify a 3D input file.', 1, 'error')
            return

        pad_arguments = arguments.pad_asym.split(',')
        if len(pad_arguments) != 6:
            printv('ERROR: you need to specify 6 padding values.', 1, 'error')

        padxi, padxf, padyi, padyf, padzi, padzf = pad_arguments
        padxi, padxf, padyi, padyf, padzi, padzf = int(padxi), int(padxf), int(
            padyi), int(padyf), int(padzi), int(padzf)
        im_out = [
            pad_image(im_in,
                      pad_x_i=padxi,
                      pad_x_f=padxf,
                      pad_y_i=padyi,
                      pad_y_f=padyf,
                      pad_z_i=padzi,
                      pad_z_f=padzf)
        ]

    elif arguments.remove_vol is not None:
        index_vol = (arguments.remove_vol).split(',')
        for iindex_vol, vol in enumerate(index_vol):
            index_vol[iindex_vol] = int(vol)
        im_out = [remove_vol(im_in, index_vol, todo='remove')]

    elif arguments.setorient is not None:
        printv(im_in.absolutepath)
        im_out = [change_orientation(im_in, arguments.setorient)]

    elif arguments.setorient_data is not None:
        im_out = [
            change_orientation(im_in, arguments.setorient_data, data_only=True)
        ]

    elif arguments.header is not None:
        header = im_in.header
        # Necessary because of https://github.com/nipy/nibabel/issues/480#issuecomment-239227821
        im_file = nib.load(im_in.absolutepath)
        header.structarr['scl_slope'] = im_file.dataobj.slope
        header.structarr['scl_inter'] = im_file.dataobj.inter
        printv(create_formatted_header_string(header=header,
                                              output_format=arguments.header),
               verbose=verbose)
        im_out = None

    elif arguments.split is not None:
        dim = arguments.split
        assert dim in dim_list
        dim = dim_list.index(dim)
        im_out = split_data(im_in, dim)

    elif arguments.type is not None:
        output_type = arguments.type
        im_out = [im_in]

    elif arguments.to_fsl is not None:
        space_files = arguments.to_fsl
        if len(space_files) > 2 or len(space_files) < 1:
            printv(parser.error('ERROR: -to-fsl expects 1 or 2 arguments'))
            return
        spaces = [Image(s) for s in space_files]
        if len(spaces) < 2:
            spaces.append(None)
        im_out = [displacement_to_abs_fsl(im_in, spaces[0], spaces[1])]

    # If these arguments are used standalone, simply pass the input image to the output (the affines were set earlier)
    elif arguments.set_sform_to_qform or arguments.set_qform_to_sform:
        im_out = [im_in]

    else:
        im_out = None
        printv(
            parser.error(
                'ERROR: you need to specify an operation to do on the input image'
            ))

    # in case fname_out is not defined, use first element of input file name list
    if fname_out is None:
        fname_out = fname_in[0]

    # Write output
    if im_out is not None:
        printv('Generate output files...', verbose)
        # if only one output
        if len(im_out) == 1 and arguments.split is None:
            im_out[0].save(fname_out, dtype=output_type, verbose=verbose)
            display_viewer_syntax([fname_out], verbose=verbose)
        if arguments.mcs:
            # use input file name and add _X, _Y _Z. Keep the same extension
            l_fname_out = []
            for i_dim in range(3):
                l_fname_out.append(
                    add_suffix(fname_out or fname_in[0],
                               '_' + dim_list[i_dim].upper()))
                im_out[i_dim].save(l_fname_out[i_dim], verbose=verbose)
            display_viewer_syntax(fname_out)
        if arguments.split is not None:
            # use input file name and add _"DIM+NUMBER". Keep the same extension
            l_fname_out = []
            for i, im in enumerate(im_out):
                l_fname_out.append(
                    add_suffix(fname_out or fname_in[0],
                               '_' + dim_list[dim].upper() + str(i).zfill(4)))
                im.save(l_fname_out[i])
            display_viewer_syntax(l_fname_out)

    elif arguments.getorient:
        printv(orient)

    elif arguments.display_warp:
        printv('Warping grid generated.', verbose, 'info')
def deep_segmentation_spinalcord(fname_image,
                                 contrast_type,
                                 output_folder,
                                 ctr_algo='cnn',
                                 ctr_file=None,
                                 brain_bool=True,
                                 kernel_size='2d',
                                 remove_temp_files=1,
                                 verbose=1):
    """Pipeline."""
    path_script = os.path.dirname(__file__)
    path_sct = os.path.dirname(path_script)

    # create temporary folder with intermediate results
    sct.log.info("Creating temporary folder...")
    file_fname = os.path.basename(fname_image)
    tmp_folder = sct.TempFolder()
    tmp_folder_path = tmp_folder.get_path()
    fname_image_tmp = tmp_folder.copy_from(fname_image)
    if ctr_algo == 'manual':  # if the ctr_file is provided
        tmp_folder.copy_from(ctr_file)
        file_ctr = os.path.basename(ctr_file)
    else:
        file_ctr = None
    tmp_folder.chdir()

    # orientation of the image, should be RPI
    sct.log.info("Reorient the image to RPI, if necessary...")
    fname_orient = sct.add_suffix(file_fname, '_RPI')
    im_2orient = Image(file_fname)
    original_orientation = im_2orient.orientation
    if original_orientation != 'RPI':
        im_orient = msct_image.change_orientation(im_2orient,
                                                  'RPI').save(fname_orient)
    else:
        im_orient = im_2orient
        sct.copy(fname_image_tmp, fname_orient)

    # resampling RPI image
    sct.log.info("Resample the image to 0.5 mm isotropic resolution...")
    fname_res = sct.add_suffix(fname_orient, '_resampled')
    im_2res = im_orient
    input_resolution = im_2res.dim[4:7]
    new_resolution = 'x'.join(['0.5', '0.5', str(input_resolution[2])])
    spinalcordtoolbox.resample.nipy_resample.resample_file(fname_orient,
                                                           fname_res,
                                                           new_resolution,
                                                           'mm',
                                                           'linear',
                                                           verbose=0)

    # find the spinal cord centerline - execute OptiC binary
    sct.log.info("Finding the spinal cord centerline...")
    centerline_filename = find_centerline(algo=ctr_algo,
                                          image_fname=fname_res,
                                          path_sct=path_sct,
                                          contrast_type=contrast_type,
                                          brain_bool=brain_bool,
                                          folder_output=tmp_folder_path,
                                          remove_temp_files=remove_temp_files,
                                          centerline_fname=file_ctr)

    # crop image around the spinal cord centerline
    sct.log.info("Cropping the image around the spinal cord...")
    fname_crop = sct.add_suffix(fname_res, '_crop')
    crop_size = 96 if (kernel_size == '3d' and contrast_type == 't2s') else 64
    X_CROP_LST, Y_CROP_LST = crop_image_around_centerline(
        filename_in=fname_res,
        filename_ctr=centerline_filename,
        filename_out=fname_crop,
        crop_size=crop_size)

    # normalize the intensity of the images
    sct.log.info("Normalizing the intensity...")
    fname_norm = sct.add_suffix(fname_crop, '_norm')
    apply_intensity_normalization(img_path=fname_crop, fname_out=fname_norm)

    if kernel_size == '2d':
        # segment data using 2D convolutions
        sct.log.info(
            "Segmenting the spinal cord using deep learning on 2D patches...")
        segmentation_model_fname = os.path.join(
            path_sct, 'data', 'deepseg_sc_models',
            '{}_sc.h5'.format(contrast_type))
        fname_seg_crop = sct.add_suffix(fname_norm, '_seg')
        seg_crop_data = segment_2d(model_fname=segmentation_model_fname,
                                   contrast_type=contrast_type,
                                   input_size=(crop_size, crop_size),
                                   fname_in=fname_norm,
                                   fname_out=fname_seg_crop)
    elif kernel_size == '3d':
        # resample to 0.5mm isotropic
        fname_res3d = sct.add_suffix(fname_norm, '_resampled3d')
        spinalcordtoolbox.resample.nipy_resample.resample_file(fname_norm,
                                                               fname_res3d,
                                                               '0.5x0.5x0.5',
                                                               'mm',
                                                               'linear',
                                                               verbose=0)

        # segment data using 3D convolutions
        sct.log.info(
            "Segmenting the spinal cord using deep learning on 3D patches...")
        segmentation_model_fname = os.path.join(
            path_sct, 'data', 'deepseg_sc_models',
            '{}_sc_3D.h5'.format(contrast_type))
        fname_seg_crop_res = sct.add_suffix(fname_res3d, '_seg')
        segment_3d(model_fname=segmentation_model_fname,
                   contrast_type=contrast_type,
                   fname_in=fname_res3d,
                   fname_out=fname_seg_crop_res)

        # resample to the initial pz resolution
        fname_seg_res2d = sct.add_suffix(fname_seg_crop_res, '_resampled2d')
        initial_2d_resolution = 'x'.join(
            ['0.5', '0.5', str(input_resolution[2])])
        spinalcordtoolbox.resample.nipy_resample.resample_file(
            fname_seg_crop_res,
            fname_seg_res2d,
            initial_2d_resolution,
            'mm',
            'linear',
            verbose=0)
        seg_crop_data = Image(fname_seg_res2d).data

    # reconstruct the segmentation from the crop data
    sct.log.info("Reassembling the image...")
    fname_seg_res_RPI = sct.add_suffix(file_fname, '_res_RPI_seg')
    uncrop_image(fname_ref=fname_res,
                 fname_out=fname_seg_res_RPI,
                 data_crop=seg_crop_data,
                 x_crop_lst=X_CROP_LST,
                 y_crop_lst=Y_CROP_LST)

    # resample to initial resolution
    sct.log.info(
        "Resampling the segmentation to the original image resolution...")
    fname_seg_RPI = sct.add_suffix(file_fname, '_RPI_seg')
    initial_resolution = 'x'.join([
        str(input_resolution[0]),
        str(input_resolution[1]),
        str(input_resolution[2])
    ])
    spinalcordtoolbox.resample.nipy_resample.resample_file(fname_seg_res_RPI,
                                                           fname_seg_RPI,
                                                           initial_resolution,
                                                           'mm',
                                                           'linear',
                                                           verbose=0)

    # binarize the resampled image to remove interpolation effects
    sct.log.info(
        "Binarizing the segmentation to avoid interpolation effects...")
    thr = '0.0001' if contrast_type in ['t1', 'dwi'] else '0.5'
    sct.run(
        ['sct_maths', '-i', fname_seg_RPI, '-bin', thr, '-o', fname_seg_RPI],
        verbose=0)

    # post processing step to z_regularized
    post_processing_volume_wise(fname_in=fname_seg_RPI)

    # reorient to initial orientation
    sct.log.info(
        "Reorienting the segmentation to the original image orientation...")
    fname_seg = sct.add_suffix(file_fname, '_seg')
    if original_orientation != 'RPI':
        im_seg_orient = msct_image.change_orientation(
            Image(fname_seg_RPI), original_orientation).save(fname_seg)
    else:
        sct.copy(fname_seg_RPI, fname_seg)

    tmp_folder.chdir_undo()

    # copy image from temporary folder into output folder
    sct.copy(os.path.join(tmp_folder_path, fname_seg), output_folder)

    # remove temporary files
    if remove_temp_files:
        sct.log.info("Remove temporary files...")
        tmp_folder.cleanup()

    return os.path.join(output_folder, fname_seg)
예제 #18
0
def test_change_orientation(fake_3dimage_sct, fake_3dimage_sct_vis):

    path_tmp = sct.tmp_create(basename="test_reorient")
    path_tmp = "."

    print("Spot-checking that physical coordinates don't change")
    for shape_is in (1,2,3):
        shape = (1,1,shape_is)
        print("Simple image with shape {}".format(shape))

        data = np.ones(shape, order="F")
        data[:,:,shape_is-1] += 1
        im_src = fake_3dimage_sct_custom(data)
        im_dst = msct_image.change_orientation(im_src, "ASR")
        # Basic check
        assert im_dst.orientation == "ASR"
        # Basic data check
        assert im_dst.data.mean() == im_src.data.mean()
        # Basic header check: check that the same voxel
        # remains at the same physical position
        aff_src = im_src.header.get_best_affine()
        aff_dst = im_dst.header.get_best_affine()

        # Take the extremities "a" & "z"...
        # consider the original LPI position
        pta_src = np.array([[0,0,0,1]]).T
        ptz_src = np.array([[0,0,shape_is-1,1]]).T
        # and the position in ASR
        pta_dst = np.array([[0,shape_is-1,0,1]]).T
        ptz_dst = np.array([[0,0,0,1]]).T
        # The physical positions should be:
        posa_src = np.matmul(aff_src, pta_src)
        posa_dst = np.matmul(aff_dst, pta_dst)
        print("A at src {}".format(posa_src.T))
        print("A at dst {}".format(posa_dst.T))
        posz_src = np.matmul(aff_src, ptz_src)
        posz_dst = np.matmul(aff_dst, ptz_dst)
        # and they should be equal
        assert (posa_src == posa_dst).all()
        assert (posz_src == posz_dst).all()
        fn = "".join(str(x) for x in im_src.data.shape)
        im_src.save("{}-src.nii".format(fn))
        im_dst.save("{}-dst.nii".format(fn))


    np.random.seed(0)

    print("More checking that physical coordinates don't change")
    if 1:
        shape = (7,8,9)
        print("Simple image with shape {}".format(shape))

        data = np.ones(shape, order="F") * 10
        data[4,4,4] = 4
        data[3,3,3] = 3
        data[0,0,0] = 0
        values = (0,3,4)

        im_ref = fake_3dimage_sct_custom(data)
        im_ref.header.set_xyzt_units("mm", "msec")

        import scipy.linalg

        def rand_rot():
            q, _ = scipy.linalg.qr(np.random.randn(3, 3))
            if scipy.linalg.det(q) < 0:
                q[:, 0] = -q[:, 0]
            return q

        affine = im_ref.header.get_best_affine()
        affine[:3,:3] = rand_rot()
        affine[3,:3] = 0.0
        affine[:3,3] = np.random.random((3))
        affine[3,3] = 1.0

        affine[0,0] *= 2
        im_ref.header.set_sform(affine, code='scanner')

        orientations = msct_image.all_refspace_strings()
        for ori_src in orientations:
            for ori_dst in orientations:
                print("{} -> {}".format(ori_src, ori_dst))
                im_src = msct_image.change_orientation(im_ref, ori_src)
                im_dst = msct_image.change_orientation(im_src, ori_dst)

                assert im_src.orientation == ori_src
                assert im_dst.orientation == ori_dst
                assert im_dst.data.mean() == im_src.data.mean()

                # Basic header check: check that the same voxel
                # remains at the same physical position
                aff_src = im_src.header.get_best_affine()
                aff_dst = im_dst.header.get_best_affine()

                data_src = np.array(im_src.data)
                data_dst = np.array(im_dst.data)

                for value in values:
                    pt_src = np.argwhere(data_src == value)[0]
                    pt_dst = np.argwhere(data_dst == value)[0]

                    pos_src = np.matmul(aff_src, np.hstack((pt_src, [1])).reshape((4,1)))
                    pos_dst = np.matmul(aff_dst, np.hstack((pt_dst, [1])).reshape((4,1)))
                    if 0:
                        print("P at src {}".format(pos_src.T))
                        print("P at dst {}".format(pos_dst.T))
                    assert np.allclose(pos_src, pos_dst, atol=1e-3)
예제 #19
0
def main(argv=None):
    """
    Main function
    :param argv:
    :return:
    """
    parser = get_parser()
    arguments = parser.parse_args(argv)
    verbose = arguments.v
    set_global_loglevel(verbose=verbose)

    # initializations
    output_type = None
    dim_list = ['x', 'y', 'z', 't']

    fname_in = arguments.i
    n_in = len(fname_in)
    # TODO: The functions for '-concat', '-omc', and '-display-warp' take in filenames, so they ignore 'im_in'.
    #  Instead, we should harmonize this functionality so that 'im_in' is used everywhere.
    im_in = Image(fname_in[0])

    if arguments.set_sform_to_qform is not None:
        im_in.set_sform_to_qform()

    if arguments.o is not None:
        fname_out = arguments.o
    else:
        fname_out = None

    # Run command
    # Arguments are sorted alphabetically (not according to the usage order)
    if arguments.concat is not None:
        dim = arguments.concat
        assert dim in dim_list
        dim = dim_list.index(dim)
        # TODO: Modify concat_data to take in a list of Image() objects so that 'im_in' can be passed instead
        im_out = [concat_data(fname_in, dim)]

    elif arguments.copy_header is not None:
        if fname_out is None:
            raise ValueError("Need to specify output image with -o!")
        im_dest = Image(arguments.copy_header)
        im_dest_new = im_in.copy()
        im_dest_new.data = im_dest.data.copy()
        # im_dest.header = im_in.header
        im_dest_new.absolutepath = im_dest.absolutepath
        im_out = [im_dest_new]

    elif arguments.display_warp:
        # TODO: Modify visualize_warp to take in an Image() object so that 'im_in' can be passed instead
        visualize_warp(fname_in[0], fname_grid=None, step=3, rm_tmp=True)
        im_out = None

    elif arguments.getorient:
        orient = im_in.orientation
        im_out = None

    elif arguments.keep_vol is not None:
        index_vol = (arguments.keep_vol).split(',')
        for iindex_vol, vol in enumerate(index_vol):
            index_vol[iindex_vol] = int(vol)
        im_out = [remove_vol(im_in, index_vol, todo='keep')]

    elif arguments.mcs:
        if n_in != 1:
            printv(parser.error('ERROR: -mcs need only one input'))
        if len(im_in.data.shape) != 5:
            printv(
                parser.error(
                    'ERROR: -mcs input need to be a multi-component image'))
        im_out = multicomponent_split(im_in)

    elif arguments.omc:
        im_ref = im_in
        for fname in fname_in:
            im = Image(fname)
            if im.data.shape != im_ref.data.shape:
                printv(
                    parser.error(
                        'ERROR: -omc inputs need to have all the same shapes'))
            del im
        # TODO: Modify multicomponent_merge to take in a list of Image() objects so that 'im_in' can be passed instead
        im_out = [multicomponent_merge(fname_in)]  # TODO: adapt to fname_in

    elif arguments.pad is not None:
        ndims = len(im_in.data.shape)
        if ndims != 3:
            printv('ERROR: you need to specify a 3D input file.', 1, 'error')
            return

        pad_arguments = arguments.pad.split(',')
        if len(pad_arguments) != 3:
            printv('ERROR: you need to specify 3 padding values.', 1, 'error')

        padx, pady, padz = pad_arguments
        padx, pady, padz = int(padx), int(pady), int(padz)
        im_out = [
            pad_image(im_in,
                      pad_x_i=padx,
                      pad_x_f=padx,
                      pad_y_i=pady,
                      pad_y_f=pady,
                      pad_z_i=padz,
                      pad_z_f=padz)
        ]

    elif arguments.pad_asym is not None:
        ndims = len(im_in.data.shape)
        if ndims != 3:
            printv('ERROR: you need to specify a 3D input file.', 1, 'error')
            return

        pad_arguments = arguments.pad_asym.split(',')
        if len(pad_arguments) != 6:
            printv('ERROR: you need to specify 6 padding values.', 1, 'error')

        padxi, padxf, padyi, padyf, padzi, padzf = pad_arguments
        padxi, padxf, padyi, padyf, padzi, padzf = int(padxi), int(padxf), int(
            padyi), int(padyf), int(padzi), int(padzf)
        im_out = [
            pad_image(im_in,
                      pad_x_i=padxi,
                      pad_x_f=padxf,
                      pad_y_i=padyi,
                      pad_y_f=padyf,
                      pad_z_i=padzi,
                      pad_z_f=padzf)
        ]

    elif arguments.remove_vol is not None:
        index_vol = (arguments.remove_vol).split(',')
        for iindex_vol, vol in enumerate(index_vol):
            index_vol[iindex_vol] = int(vol)
        im_out = [remove_vol(im_in, index_vol, todo='remove')]

    elif arguments.setorient is not None:
        printv(fname_in[0])
        im_out = [change_orientation(im_in, arguments.setorient)]

    elif arguments.setorient_data is not None:
        im_out = [
            change_orientation(im_in, arguments.setorient_data, data_only=True)
        ]

    elif arguments.split is not None:
        dim = arguments.split
        assert dim in dim_list
        dim = dim_list.index(dim)
        im_out = split_data(im_in, dim)

    elif arguments.type is not None:
        output_type = arguments.type
        im_out = [im_in]  # TODO: adapt to fname_in

    elif arguments.to_fsl is not None:
        space_files = arguments.to_fsl
        if len(space_files) > 2 or len(space_files) < 1:
            printv(parser.error('ERROR: -to-fsl expects 1 or 2 arguments'))
            return
        spaces = [Image(s) for s in space_files]
        if len(spaces) < 2:
            spaces.append(None)
        im_out = [displacement_to_abs_fsl(im_in, spaces[0], spaces[1])]

    # If this argument is used standalone, simply pass the input image to the output (sform was set for im_in earlier)
    elif arguments.set_sform_to_qform is not None:
        im_out = [im_in]

    else:
        im_out = None
        printv(
            parser.error(
                'ERROR: you need to specify an operation to do on the input image'
            ))

    # in case fname_out is not defined, use first element of input file name list
    if fname_out is None:
        fname_out = fname_in[0]

    # Write output
    if im_out is not None:
        printv('Generate output files...', verbose)
        # if only one output
        if len(im_out) == 1 and arguments.split is None:
            im_out[0].save(fname_out, dtype=output_type, verbose=verbose)
            display_viewer_syntax([fname_out], verbose=verbose)
        if arguments.mcs:
            # use input file name and add _X, _Y _Z. Keep the same extension
            l_fname_out = []
            for i_dim in range(3):
                l_fname_out.append(
                    add_suffix(fname_out or fname_in[0],
                               '_' + dim_list[i_dim].upper()))
                im_out[i_dim].save(l_fname_out[i_dim], verbose=verbose)
            display_viewer_syntax(fname_out)
        if arguments.split is not None:
            # use input file name and add _"DIM+NUMBER". Keep the same extension
            l_fname_out = []
            for i, im in enumerate(im_out):
                l_fname_out.append(
                    add_suffix(fname_out or fname_in[0],
                               '_' + dim_list[dim].upper() + str(i).zfill(4)))
                im.save(l_fname_out[i])
            display_viewer_syntax(l_fname_out)

    elif arguments.getorient:
        printv(orient)

    elif arguments.display_warp:
        printv('Warping grid generated.', verbose, 'info')
예제 #20
0
def find_centerline(algo, image_fname, path_sct, contrast_type, brain_bool,
                    folder_output, remove_temp_files, centerline_fname):

    if Image(image_fname).dim[2] == 1:  # isct_spine_detect requires nz > 1
        from sct_image import concat_data
        im_concat = concat_data([image_fname, image_fname], dim=2)
        im_concat.save(sct.add_suffix(image_fname, '_concat'))
        image_fname = sct.add_suffix(image_fname, '_concat')
        bool_2d = True
    else:
        bool_2d = False

    if algo == 'svm':
        # run optic on a heatmap computed by a trained SVM+HoG algorithm
        optic_models_fname = os.path.join(path_sct, 'data', 'optic_models',
                                          '{}_model'.format(contrast_type))
        _, centerline_filename = optic.detect_centerline(
            image_fname=image_fname,
            contrast_type=contrast_type,
            optic_models_path=optic_models_fname,
            folder_output=folder_output,
            remove_temp_files=remove_temp_files,
            output_roi=False,
            verbose=0)
    elif algo == 'cnn':
        # CNN parameters
        dct_patch_ctr = {
            't2': {
                'size': (80, 80),
                'mean': 51.1417,
                'std': 57.4408
            },
            't2s': {
                'size': (80, 80),
                'mean': 68.8591,
                'std': 71.4659
            },
            't1': {
                'size': (80, 80),
                'mean': 55.7359,
                'std': 64.3149
            },
            'dwi': {
                'size': (80, 80),
                'mean': 55.744,
                'std': 45.003
            }
        }
        dct_params_ctr = {
            't2': {
                'features': 16,
                'dilation_layers': 2
            },
            't2s': {
                'features': 8,
                'dilation_layers': 3
            },
            't1': {
                'features': 24,
                'dilation_layers': 3
            },
            'dwi': {
                'features': 8,
                'dilation_layers': 2
            }
        }

        # load model
        ctr_model_fname = os.path.join(path_sct, 'data', 'deepseg_sc_models',
                                       '{}_ctr.h5'.format(contrast_type))
        ctr_model = nn_architecture_ctr(
            height=dct_patch_ctr[contrast_type]['size'][0],
            width=dct_patch_ctr[contrast_type]['size'][1],
            channels=1,
            classes=1,
            features=dct_params_ctr[contrast_type]['features'],
            depth=2,
            temperature=1.0,
            padding='same',
            batchnorm=True,
            dropout=0.0,
            dilation_layers=dct_params_ctr[contrast_type]['dilation_layers'])
        ctr_model.load_weights(ctr_model_fname)

        sct.log.info("Resample the image to 0.5 mm isotropic resolution...")
        fname_res = sct.add_suffix(image_fname, '_resampled')
        input_resolution = Image(image_fname).dim[4:7]
        new_resolution = 'x'.join(['0.5', '0.5', str(input_resolution[2])])

        spinalcordtoolbox.resample.nipy_resample.resample_file(image_fname,
                                                               fname_res,
                                                               new_resolution,
                                                               'mm',
                                                               'linear',
                                                               verbose=0)

        # compute the heatmap
        fname_heatmap = sct.add_suffix(image_fname, "_heatmap")
        img_filename = ''.join(sct.extract_fname(fname_heatmap)[:2])
        fname_heatmap_nii = img_filename + '.nii'
        z_max = heatmap(filename_in=fname_res,
                        filename_out=fname_heatmap_nii,
                        model=ctr_model,
                        patch_shape=dct_patch_ctr[contrast_type]['size'],
                        mean_train=dct_patch_ctr[contrast_type]['mean'],
                        std_train=dct_patch_ctr[contrast_type]['std'],
                        brain_bool=brain_bool)

        # run optic on the heatmap
        centerline_filename = sct.add_suffix(fname_heatmap, "_ctr")
        heatmap2optic(fname_heatmap=fname_heatmap_nii,
                      lambda_value=7 if contrast_type == 't2s' else 1,
                      fname_out=centerline_filename,
                      z_max=z_max if brain_bool else None)

    elif algo == 'viewer':
        centerline_filename = sct.add_suffix(image_fname, "_ctr")
        fname_labels_viewer = _call_viewer_centerline(fname_in=image_fname)
        centerline_filename = extract_centerline(fname_labels_viewer,
                                                 remove_temp_files=True,
                                                 algo_fitting='nurbs',
                                                 nurbs_pts_number=8000)
    elif algo == 'manual':
        centerline_filename = sct.add_suffix(image_fname, "_ctr")
        image_manual_centerline = Image(centerline_fname)
        # Re-orient and Re-sample the manual centerline
        msct_image.change_orientation(image_manual_centerline,
                                      'RPI').save(centerline_filename)
    else:
        sct.log.error(
            'The parameter "-centerline" is incorrect. Please try again.')
        sys.exit(1)

    if algo != 'cnn':
        sct.log.info("Resample the image to 0.5 mm isotropic resolution...")
        fname_res = sct.add_suffix(image_fname, '_resampled')
        input_resolution = Image(image_fname).dim[4:7]
        new_resolution = 'x'.join(['0.5', '0.5', str(input_resolution[2])])

        spinalcordtoolbox.resample.nipy_resample.resample_file(image_fname,
                                                               fname_res,
                                                               new_resolution,
                                                               'mm',
                                                               'linear',
                                                               verbose=0)

        spinalcordtoolbox.resample.nipy_resample.resample_file(
            centerline_filename,
            centerline_filename,
            new_resolution,
            'mm',
            'linear',
            verbose=0)

    if bool_2d:
        from sct_image import split_data
        im_split_lst = split_data(Image(centerline_filename), dim=2)
        im_split_lst[0].save(centerline_filename)

    return fname_res, centerline_filename