def saveROIFunc(self):
        #save out segmentation
        aff = self.affine2
        outImage = deepcopy(self.segImg)#np.rot90(np.fliplr(self.segImg),-1)
        [x_si,y_si,z_si] = np.shape(outImage)

        #This method works (for fastsegs)... but need more robust
        #for i in range(0,z_si):
        #    outImage[:,:,i] = np.rot90(self.segImg[:,:,z_si-1-i],-1)

        #try new method (more robust to header and affine mix-ups)
        ornt = orx.axcodes2ornt((self.Orx,self.Ory,self.Orz))  
        refOrnt = orx.axcodes2ornt(('R','S','A'))
        newOrnt = orx.ornt_transform(refOrnt,ornt) #reversed these
        outImage= orx.apply_orientation(np.rot90(np.fliplr(outImage),-1),newOrnt)  
        #outImage = orx.apply_orientation(outImage,newOrnt)    
        #outImage = np.rot90(np.fliplr(outImage),-1)



        new_image = nib.Nifti1Image(outImage,aff)

        os.chdir(os.path.dirname(str(self.getFileNAME)))
        self.roiSaveName=QFileDialog.getSaveFileName()
        #nib.save(new_image,fileNAME[:-7]+'_FASTseg_TK_edit.nii.gz')
        nib.save(new_image,str(self.roiSaveName))
Exemple #2
0
def get_affine_trackvis_to_rasmm(header):
    """ Get affine mapping trackvis voxelmm space to RAS+ mm space

    The streamlines in a trackvis file are in 'voxelmm' space, where the
    coordinates refer to the corner of the voxel.

    Compute the affine matrix that will bring them back to RAS+ mm space, where
    the coordinates refer to the center of the voxel.

    Parameters
    ----------
    header : dict or ndarray
        Dict or numpy structured array containing trackvis header.

    Returns
    -------
    aff_tv2ras : shape (4, 4) array
        Affine array mapping coordinates in 'voxelmm' space to RAS+ mm space.
    """
    # TRK's streamlines are in 'voxelmm' space, we will compute the
    # affine matrix that will bring them back to RAS+ and mm space.
    affine = np.eye(4)

    # The affine matrix found in the TRK header requires the points to
    # be in the voxel space.
    # voxelmm -> voxel
    scale = np.eye(4)
    scale[range(3), range(3)] /= header[Field.VOXEL_SIZES]
    affine = np.dot(scale, affine)

    # TrackVis considers coordinate (0,0,0) to be the corner of the
    # voxel whereas streamlines returned assumes (0,0,0) to be the
    # center of the voxel. Thus, streamlines are shifted by half a voxel.
    offset = np.eye(4)
    offset[:-1, -1] -= 0.5
    affine = np.dot(offset, affine)

    # If the voxel order implied by the affine does not match the voxel
    # order in the TRK header, change the orientation.
    # voxel (header) -> voxel (affine)
    vox_order = header[Field.VOXEL_ORDER]
    # Input header can be dict or structured array
    if hasattr(vox_order, 'item'):  # structured array
        vox_order = header[Field.VOXEL_ORDER].item()
    affine_ornt = "".join(aff2axcodes(header[Field.VOXEL_TO_RASMM]))
    header_ornt = axcodes2ornt(vox_order.decode('latin1').upper())
    affine_ornt = axcodes2ornt(affine_ornt)
    ornt = nib.orientations.ornt_transform(header_ornt, affine_ornt)
    M = nib.orientations.inv_ornt_aff(ornt, header[Field.DIMENSIONS])
    affine = np.dot(M, affine)

    # Applied the affine found in the TRK header.
    # voxel -> rasmm
    voxel_to_rasmm = header[Field.VOXEL_TO_RASMM]
    affine_voxmm_to_rasmm = np.dot(voxel_to_rasmm, affine)
    return affine_voxmm_to_rasmm.astype(np.float32)
def get_affine_trackvis_to_rasmm(header):
    """ Get affine mapping trackvis voxelmm space to RAS+ mm space

    The streamlines in a trackvis file are in 'voxelmm' space, where the
    coordinates refer to the corner of the voxel.

    Compute the affine matrix that will bring them back to RAS+ mm space, where
    the coordinates refer to the center of the voxel.

    Parameters
    ----------
    header : dict or ndarray
        Dict or numpy structured array containing trackvis header.

    Returns
    -------
    aff_tv2ras : shape (4, 4) array
        Affine array mapping coordinates in 'voxelmm' space to RAS+ mm space.
    """
    # TRK's streamlines are in 'voxelmm' space, we will compute the
    # affine matrix that will bring them back to RAS+ and mm space.
    affine = np.eye(4)

    # The affine matrix found in the TRK header requires the points to
    # be in the voxel space.
    # voxelmm -> voxel
    scale = np.eye(4)
    scale[range(3), range(3)] /= header[Field.VOXEL_SIZES]
    affine = np.dot(scale, affine)

    # TrackVis considers coordinate (0,0,0) to be the corner of the
    # voxel whereas streamlines returned assumes (0,0,0) to be the
    # center of the voxel. Thus, streamlines are shifted by half a voxel.
    offset = np.eye(4)
    offset[:-1, -1] -= 0.5
    affine = np.dot(offset, affine)

    # If the voxel order implied by the affine does not match the voxel
    # order in the TRK header, change the orientation.
    # voxel (header) -> voxel (affine)
    vox_order = header[Field.VOXEL_ORDER]
    # Input header can be dict or structured array
    if hasattr(vox_order, 'item'):  # structured array
        vox_order = header[Field.VOXEL_ORDER].item()
    affine_ornt = "".join(aff2axcodes(header[Field.VOXEL_TO_RASMM]))
    header_ornt = axcodes2ornt(vox_order.decode('latin1').upper())
    affine_ornt = axcodes2ornt(affine_ornt)
    ornt = nib.orientations.ornt_transform(header_ornt, affine_ornt)
    M = nib.orientations.inv_ornt_aff(ornt, header[Field.DIMENSIONS])
    affine = np.dot(M, affine)

    # Applied the affine found in the TRK header.
    # voxel -> rasmm
    voxel_to_rasmm = header[Field.VOXEL_TO_RASMM]
    affine_voxmm_to_rasmm = np.dot(voxel_to_rasmm, affine)
    return affine_voxmm_to_rasmm.astype(np.float32)
Exemple #4
0
def rescale_centroids(ctd_list, img, voxel_spacing=(1, 1, 1)):
    """rescale centroid coordinates to new spacing in current x-y-z-orientation
    
    Parameters:
    ----------
    ctd_list: list of centroids
    img: nibabel image 
    voxel_spacing: desired spacing
    
    Returns:
    ----------
    out_list: rescaled list of centroids 
    
    """
    ornt_img = nio.io_orientation(img.affine)
    ornt_ctd = nio.axcodes2ornt(ctd_list[0])
    if np.array_equal(ornt_img, ornt_ctd):
        zms = img.header.get_zooms()
    else:
        ornt_trans = nio.ornt_transform(ornt_img, ornt_ctd)
        aff_trans = nio.inv_ornt_aff(ornt_trans, img.dataobj.shape)
        new_aff = np.matmul(img.affine, aff_trans)
        zms = nib.affines.voxel_sizes(new_aff)
    ctd_arr = np.transpose(np.asarray(ctd_list[1:]))
    v_list = ctd_arr[0].astype(int).tolist()  # vertebral labels
    ctd_arr = ctd_arr[1:]
    ctd_arr[0] = np.around(ctd_arr[0] * zms[0] / voxel_spacing[0], decimals=1)
    ctd_arr[1] = np.around(ctd_arr[1] * zms[1] / voxel_spacing[1], decimals=1)
    ctd_arr[2] = np.around(ctd_arr[2] * zms[2] / voxel_spacing[2], decimals=1)
    out_list = [ctd_list[0]]
    ctd_list = np.transpose(ctd_arr).tolist()
    for v, ctd in zip(v_list, ctd_list):
        out_list.append([v] + ctd)
    print("[*] Rescaled centroid coordinates to spacing (x, y, z) =", voxel_spacing, "mm")
    return out_list
Exemple #5
0
def reorient_to(img, axcodes_to=('P', 'I', 'R'), verb=False):
    """Reorients the nifti from its original orientation to another specified orientation
    
    Parameters:
    ----------
    img: nibabel image
    axcodes_to: a tuple of 3 characters specifying the desired orientation
    
    Returns:
    ----------
    newimg: The reoriented nibabel image 
    
    """
    aff = img.affine
    arr = np.asanyarray(img.dataobj, dtype=img.dataobj.dtype)
    ornt_fr = nio.io_orientation(aff)
    ornt_to = nio.axcodes2ornt(axcodes_to)
    ornt_trans = nio.ornt_transform(ornt_fr, ornt_to)
    arr = nio.apply_orientation(arr, ornt_trans)
    aff_trans = nio.inv_ornt_aff(ornt_trans, arr.shape)
    newaff = np.matmul(aff, aff_trans)
    newimg = nib.Nifti1Image(arr, newaff)
    if verb:
        print("[*] Image reoriented from", nio.ornt2axcodes(ornt_fr), "to", axcodes_to)
    return newimg
Exemple #6
0
def read_nifti_series(filename):
    proxy_img = nib.load(filename)
    # less efficent get image data into memory all at once
    # image_data = proxy_img.get_fdata()

    hdr = proxy_img.header
    image_shape = hdr.get_data_shape()
    image_dim = len(image_shape)
    num_images = 1
    if image_dim >= 3:
        num_images = image_shape[2]

    (m, b) = hdr.get_slope_inter()
    axcodes = nib.aff2axcodes(proxy_img.affine)
    # TODO-- There does not seem to be a good NIfti method to obtain the input volume's labels?
    if ((axcodes != ('R', 'A', 'S')) and (axcodes != ('L', 'A', 'S'))
            and (axcodes != ('L', 'P', 'S'))):
        print(
            "Input NIfti series is in unsupported orientation.  Please convert to RAS, LAS, or LPS orientation:"
            + filename)
        sys.exit(1)

    # specifiy LPS for DICOM
    # https://nipy.org/nibabel/dicom/dicom_orientation.html, if we want to apply the formula above to array indices in pixel_array, we first have to apply a column / row flip to the indices.
    codes = ('L', 'P', 'S')
    labels = (('A', 'P'), ('R', 'L'), ('I', 'S'))
    orients = orientations.axcodes2ornt(codes, labels)
    img_reorient = proxy_img.as_reoriented(orients)
    hdr = img_reorient.header
    # We reset m and b here ourselves for downstream rescale/slope
    b = 0
    m = 1
    return img_reorient, hdr, num_images, b, m, axcodes
Exemple #7
0
def write_nifti_mask(img_reorient,
                     axcodes,
                     mask_data,
                     outputdirectory,
                     base_fname,
                     filepattern=".nii"):
    # We only currently support NIfti LAS and RAS orientations
    # TODO--  To support more NIfti orientations add more key/values to nifti_in_codes_labels
    nifti_in_codes_labels = {
        ('L', 'A', 'S'): (('P', 'A'), ('R', 'L'), ('I', 'S')),
        ('R', 'A', 'S'): (('P', 'A'), ('L', 'R'), ('I', 'S')),
        ('L', 'P', 'S'): (('A', 'P'), ('R', 'L'), ('I', 'S'))
    }
    filename = outputdirectory + os.path.sep + base_fname + "_mask1" + filepattern
    new_header = header = img_reorient.header.copy()
    new_header.set_slope_inter(1, 0)  # no scaling
    new_header['cal_min'] = np.min(mask_data)
    new_header['cal_max'] = np.max(mask_data)
    new_header['bitpix'] = 16
    new_header['descrip'] = "NIfti mask volume from Caffe 1.0"

    mask2 = np.zeros(img_reorient.shape, MASK_DTYPE)
    mask2[
        ...,
        0] = mask_data  # Add a 4th dim for Nifti, not sure if last dim is number of channels?
    nifti_mask_img = nib.nifti1.Nifti1Image(mask2,
                                            img_reorient.affine,
                                            header=new_header)

    # Need to xform numpy from supposed DICOM LPS to NIFTI original orientation (i.e. LAS, RAS, etc.)
    orients = orientations.axcodes2ornt(axcodes,
                                        nifti_in_codes_labels[axcodes])
    mask_reorient = nifti_mask_img.as_reoriented(orients)
    nib.save(mask_reorient, filename)
Exemple #8
0
def do_nibabel_transform_to_ras(img):
    print(f'Transforming Images to {DEFAULT_ORIENTATION}.....')
    affine = img.affine
    orig_ornt = nb.io_orientation(affine)
    targ_ornt = axcodes2ornt(DEFAULT_ORIENTATION)
    transform = ornt_transform(orig_ornt, targ_ornt)
    img = img.as_reoriented(transform)
    return img
    def load3DSegFunc(self):
        if self.micos_flag == 1:
            getFileNAME = self.micos_name
            self.micos_flag = 0
            self.roiload_flag = 0
        else:
            getFileNAME = QFileDialog.getOpenFileName()
            self.roiload_flag = 1

        segImgObj = nib.load(str(getFileNAME))
        segImgData = segImgObj.get_data()
        
        ornt = orx.axcodes2ornt((self.Orx,self.Ory,self.Orz))  
        refOrnt = orx.axcodes2ornt(('R','S','A'))
        newOrnt = orx.ornt_transform(ornt,refOrnt)
        segImgData = orx.apply_orientation(segImgData,newOrnt)      
        segImgData = np.fliplr(np.rot90(segImgData,1))
        self.segImg = deepcopy(segImgData)
        self.ui.overlaySeg.setChecked(True)
        self.imshowFunc()  
Exemple #10
0
def save_slices(subject, fname, x, y, z, modality='mri'):
    """ Function to display row of image slices """
    header = nib.load(fname)
    affine = np.array(header.affine, float)
    data = header.get_data()
    images_fol = op.join(MMVT_DIR, subject, 'figures', 'slices')
    utils.make_dir(images_fol)

    clim = np.percentile(data, (1., 99.))
    codes = axcodes2ornt(aff2axcodes(affine))
    order = np.argsort([c[0] for c in codes])
    flips = np.array([c[1] < 0 for c in codes])[order]
    sizes = [data.shape[order] for order in order]
    scalers = voxel_sizes(affine)
    coordinates = np.array([x, y, z])[order].astype(int)

    r = [
        scalers[order[2]] / scalers[order[1]],
        scalers[order[2]] / scalers[order[0]],
        scalers[order[1]] / scalers[order[0]]
    ]
    for ii, xax, yax, ratio, prespective in zip(
        [0, 1, 2], [1, 0, 0], [2, 2, 1], r, ['Sagital', 'Coronal', 'Axial']):
        fig = plt.figure()
        fig.set_size_inches(1. * sizes[xax] / sizes[yax], 1, forward=False)
        ax = plt.Axes(fig, [0., 0., 1., 1.])
        ax.set_axis_off()
        fig.add_axes(ax)

        d = get_image_data(data, order, flips, ii, coordinates)
        ax.imshow(d,
                  vmin=clim[0],
                  vmax=clim[1],
                  aspect=1,
                  cmap='gray',
                  interpolation='nearest',
                  origin='lower')
        lims = [0, sizes[xax], 0, sizes[yax]]
        ax.axis(lims)
        ax.set_aspect(ratio)
        ax.patch.set_visible(False)
        ax.set_frame_on(False)
        ax.axes.get_yaxis().set_visible(False)
        ax.axes.get_xaxis().set_visible(False)

        x, y, z = coordinates
        image_fname = op.join(
            images_fol, '{}_{}_{}_{}_{}.png'.format(modality, prespective, x,
                                                    y, z))
        print('Saving {}'.format(image_fname))
        plt.savefig(image_fname, dpi=sizes[xax])
Exemple #11
0
def reorient_centroids_to(ctd_list, img, decimals=1, verb=False):
    """reorient centroids to image orientation
    
    Parameters:
    ----------
    ctd_list: list of centroids
    img: nibabel image 
    decimals: rounding decimal digits
    
    Returns:
    ----------
    out_list: reoriented list of centroids 
    
    """
    ctd_arr = np.transpose(np.asarray(ctd_list[1:]))
    if len(ctd_arr) == 0:
        print("[#] No centroids present") 
        return ctd_list
    v_list = ctd_arr[0].astype(int).tolist()  # vertebral labels
    ctd_arr = ctd_arr[1:]
    ornt_fr = nio.axcodes2ornt(ctd_list[0])  # original centroid orientation
    axcodes_to = nio.aff2axcodes(img.affine)
    ornt_to = nio.axcodes2ornt(axcodes_to)
    trans = nio.ornt_transform(ornt_fr, ornt_to).astype(int)
    perm = trans[:, 0].tolist()
    shp = np.asarray(img.dataobj.shape)
    ctd_arr[perm] = ctd_arr.copy()
    for ax in trans:
        if ax[1] == -1:
            size = shp[ax[0]]
            ctd_arr[ax[0]] = np.around(size - ctd_arr[ax[0]], decimals)
    out_list = [axcodes_to]
    ctd_list = np.transpose(ctd_arr).tolist()
    for v, ctd in zip(v_list, ctd_list):
        out_list.append([v] + ctd)
    if verb:
        print("[*] Centroids reoriented from", nio.ornt2axcodes(ornt_fr), "to", axcodes_to)
    return out_list
def test_reorientation_backport():
    pixdims = ((1, 1, 1), (2, 2, 3))
    data = np.random.normal(size=(17, 18, 19, 2))

    for pixdim in pixdims:
        # Generate a randomly rotated affine
        angles = np.random.uniform(-np.pi, np.pi, 3) * [1, 0.5, 1]
        rot = nb.eulerangles.euler2mat(*angles)
        scale = np.diag(pixdim)
        translation = np.array((17, 18, 19)) / 2
        affine = nb.affines.from_matvec(rot.dot(scale), translation)

        # Create image
        img = nb.Nifti1Image(data, affine)
        dim_info = {"freq": 0, "phase": 1, "slice": 2}
        img.header.set_dim_info(**dim_info)

        # Find a random, non-identity transform
        targ_ornt = orig_ornt = nb.io_orientation(affine)
        while np.array_equal(targ_ornt, orig_ornt):
            new_code = np.random.choice(_orientations)
            targ_ornt = axcodes2ornt(new_code)

        identity = ornt_transform(orig_ornt, orig_ornt)
        transform = ornt_transform(orig_ornt, targ_ornt)

        # Identity transform returns exact image
        assert img.as_reoriented(identity) is img
        assert _as_reoriented_backport(img, identity) is img

        reoriented_a = img.as_reoriented(transform)
        reoriented_b = _as_reoriented_backport(img, transform)

        flips_only = img.shape == reoriented_a.shape

        # Reorientation changes affine and data array
        assert not np.allclose(img.affine, reoriented_a.affine)
        assert not (flips_only
                    and np.allclose(img.get_fdata(), reoriented_a.get_fdata()))
        # Dimension info changes iff axes are reordered
        assert flips_only == np.array_equal(img.header.get_dim_info(),
                                            reoriented_a.header.get_dim_info())

        # Both approaches produce equivalent images
        assert np.allclose(reoriented_a.affine, reoriented_b.affine)
        assert np.array_equal(reoriented_a.get_fdata(),
                              reoriented_b.get_fdata())
        assert np.array_equal(reoriented_a.header.get_dim_info(),
                              reoriented_b.header.get_dim_info())
Exemple #13
0
def test_reorientation_backport():
    pixdims = ((1, 1, 1), (2, 2, 3))
    data = np.random.normal(size=(17, 18, 19, 2))

    for pixdim in pixdims:
        # Generate a randomly rotated affine
        angles = np.random.uniform(-np.pi, np.pi, 3) * [1, 0.5, 1]
        rot = nb.eulerangles.euler2mat(*angles)
        scale = np.diag(pixdim)
        translation = np.array((17, 18, 19)) / 2
        affine = nb.affines.from_matvec(rot.dot(scale), translation)

        # Create image
        img = nb.Nifti1Image(data, affine)
        dim_info = {'freq': 0, 'phase': 1, 'slice': 2}
        img.header.set_dim_info(**dim_info)

        # Find a random, non-identity transform
        targ_ornt = orig_ornt = nb.io_orientation(affine)
        while np.array_equal(targ_ornt, orig_ornt):
            new_code = np.random.choice(_orientations)
            targ_ornt = axcodes2ornt(new_code)

        identity = ornt_transform(orig_ornt, orig_ornt)
        transform = ornt_transform(orig_ornt, targ_ornt)

        # Identity transform returns exact image
        assert img.as_reoriented(identity) is img
        assert _as_reoriented_backport(img, identity) is img

        reoriented_a = img.as_reoriented(transform)
        reoriented_b = _as_reoriented_backport(img, transform)

        flips_only = img.shape == reoriented_a.shape

        # Reorientation changes affine and data array
        assert not np.allclose(img.affine, reoriented_a.affine)
        assert not (flips_only and
                    np.allclose(img.get_data(), reoriented_a.get_data()))
        # Dimension info changes iff axes are reordered
        assert flips_only == np.array_equal(img.header.get_dim_info(),
                                            reoriented_a.header.get_dim_info())

        # Both approaches produce equivalent images
        assert np.allclose(reoriented_a.affine, reoriented_b.affine)
        assert np.array_equal(reoriented_a.get_data(), reoriented_b.get_data())
        assert np.array_equal(reoriented_a.header.get_dim_info(),
                              reoriented_b.header.get_dim_info())
Exemple #14
0
    def _run_interface(self, runtime):
        import numpy as np
        import nibabel as nb
        from nibabel.orientations import (axcodes2ornt, ornt_transform,
                                          inv_ornt_aff)

        fname = self.inputs.in_file
        orig_img = nb.load(fname)

        # Find transform from current (approximate) orientation to
        # target, in nibabel orientation matrix and affine forms
        orig_ornt = nb.io_orientation(orig_img.affine)
        targ_ornt = axcodes2ornt(self.inputs.orientation)
        transform = ornt_transform(orig_ornt, targ_ornt)
        affine_xfm = inv_ornt_aff(transform, orig_img.shape)

        # Check can be eliminated when minimum nibabel version >= 2.2
        if hasattr(orig_img, 'as_reoriented'):
            reoriented = orig_img.as_reoriented(transform)
        else:
            reoriented = _as_reoriented_backport(orig_img, transform)

        # Image may be reoriented
        if reoriented is not orig_img:
            suffix = '_' + self.inputs.orientation.lower()
            out_name = fname_presuffix(fname,
                                       suffix=suffix,
                                       newpath=runtime.cwd)
            reoriented.to_filename(out_name)
        else:
            out_name = fname

        mat_name = fname_presuffix(fname,
                                   suffix='.mat',
                                   newpath=runtime.cwd,
                                   use_ext=False)
        np.savetxt(mat_name, affine_xfm, fmt='%.08f')

        self._results['out_file'] = out_name
        self._results['transform'] = mat_name

        return runtime
Exemple #15
0
    def _run_interface(self, runtime):
        import numpy as np
        import nibabel as nb
        from nibabel.orientations import (
            axcodes2ornt, ornt_transform, inv_ornt_aff)

        fname = self.inputs.in_file
        orig_img = nb.load(fname)

        # Find transform from current (approximate) orientation to
        # target, in nibabel orientation matrix and affine forms
        orig_ornt = nb.io_orientation(orig_img.affine)
        targ_ornt = axcodes2ornt(self.inputs.orientation)
        transform = ornt_transform(orig_ornt, targ_ornt)
        affine_xfm = inv_ornt_aff(transform, orig_img.shape)

        # Check can be eliminated when minimum nibabel version >= 2.4
        if LooseVersion(nb.__version__) >= LooseVersion('2.4.0'):
            reoriented = orig_img.as_reoriented(transform)
        else:
            reoriented = _as_reoriented_backport(orig_img, transform)

        # Image may be reoriented
        if reoriented is not orig_img:
            suffix = '_' + self.inputs.orientation.lower()
            out_name = fname_presuffix(fname, suffix=suffix,
                                       newpath=runtime.cwd)
            reoriented.to_filename(out_name)
        else:
            out_name = fname

        mat_name = fname_presuffix(fname, suffix='.mat',
                                   newpath=runtime.cwd, use_ext=False)
        np.savetxt(mat_name, affine_xfm, fmt='%.08f')

        self._results['out_file'] = out_name
        self._results['transform'] = mat_name

        return runtime
    def loadDataFunc(self):
        #Function for loading image file
        self.ui.autogray.setCheckState(2)
        self.autoGrayFlag = 1

        getFileNAME = QFileDialog.getOpenFileName()

        if str(getFileNAME)[-4:] == '.avw': #if avw file, do conversion, and then work with nifti file
            MR = loadAVW(str(getFileNAME))
            avw2nifti(str(getFileNAME[:-4]) + 'avw', MR, seg=None)
            getFileNAME = str(getFileNAME[:-4]) + 'avw.nii.gz'
        
        #print getFileNAME
        self.getFileNAME = getFileNAME
        self.ui.displayFileName.setText(str(os.path.basename(str(self.getFileNAME)))) 

        self.z =0
        self.z1 = 0
        self.z2 = 0
        self.rotD = -90
        imgObj2= nib.load(str(getFileNAME))
        imgObj1 = imgObj2
        self.affine2 = imgObj2.get_affine()     
        self.PSx = imgObj1.get_header()['pixdim'][1]
        self.PSy = imgObj1.get_header()['pixdim'][2]
        self.PSz = imgObj1.get_header()['pixdim'][3]
        (x,y,z) = orx.aff2axcodes(self.affine2)
        self.Orx = x
        self.Ory = y
        self.Orz = z
        ornt = orx.axcodes2ornt((x,y,z))  
        refOrnt = orx.axcodes2ornt(('R','S','A')) #was 'R', 'A', 'S'
        newOrnt = orx.ornt_transform(ornt,refOrnt)
        self.ornt = ornt
        self.refOrnt = refOrnt

        self.img_data2 = imgObj2.get_data()       

        self.img_data2 = orx.apply_orientation(self.img_data2,newOrnt)
        
        self.img_data2 = np.fliplr(np.rot90(self.img_data2,1))
        self.img_data1 = self.img_data2
        
        self.imageFile2 = str(getFileNAME) #changed self.ui.T2Image.currentText() to getFileNAME
        self.imageFile1 = self.imageFile2
        indx2 = self.imageFile2.rfind('/')
        indx1 = indx2
        self.filePath1 = self.imageFile1[0:indx1+1]
        self.fileName1 = self.imageFile1[indx1+1:]
        self.filePath2 = self.imageFile2[0:indx2+1]
        self.fileName2 = self.imageFile2[indx2+1:]
        
 
#        sizeT1C = self.img_data1.shape
        try:
            (x1,y1,z1) = self.img_data1.shape
            (x2,y2,z2) = self.img_data2.shape
        except:
            (x1,y1,z1,d1) = self.img_data1.shape
            (x2,y2,z2,d1) = self.img_data2.shape
            self.img_data1 = self.img_data1[:,:,:,0]
            self.img_data2 = self.img_data2[:,:,:,0]
            
        self.sliceNum1 = z1
        self.sliceNum2 = z2
        
        self.shape = self.img_data2.shape

        self.img1 = self.img_data1[:,:,self.z]
        self.img2 = self.img_data2[:,:,self.z]
        
        self.segImg = self.img_data2 * 0
        
        self.imshowFunc()  
        
        (x,y,z) = self.shape

        self.ui.figure3.canvas.ax.clear()
#        self.ui.figure3.canvas.ax.imshow(((self.img_data2[:,round(x/2),:])),cmap=plt.cm.gray)
        self.ui.figure3.canvas.ax.imshow(((self.img_data2[:,round(x/2),:])),cmap=plt.cm.gray)
        #self.ui.figure3.canvas.ax.set_aspect('auto')
        self.ui.figure3.canvas.ax.get_xaxis().set_visible(False)
        self.ui.figure3.canvas.ax.get_yaxis().set_visible(False)
        #self.ui.figure3.canvas.ax.set_title('Sagittal View', color = 'white') #this is where had sagittal view
        self.ui.figure3.canvas.draw()
        
        self.ui.figure4.canvas.ax.clear()
        self.ui.figure4.canvas.ax.imshow(np.rot90((self.img_data2[round(y/2),:,:]),1),cmap=plt.cm.gray)
        #self.ui.figure4.canvas.ax.set_aspect('auto')
        self.ui.figure4.canvas.ax.get_xaxis().set_visible(False)
        self.ui.figure4.canvas.ax.get_yaxis().set_visible(False)
        #self.ui.figure4.canvas.ax.set_title('Axial View', color = 'white')
        self.ui.figure4.canvas.draw()
        
#        self.imhistFunc()
        self.ui.imageSlider.setMinimum(0)
        self.ui.imageSlider.setMaximum(z2-1)
        self.ui.imageSlider.setSingleStep(1)

        self.maxSlice = z2 - 1
            
        (row,col,dep) = self.img_data2.shape
        self.overlayImgAX = np.zeros((row,col))
        
        return 
def MICOS(fileNAME):

	tic = time.clock()

	selfz =0
	selfz1 = 0
	selfz2 = 0
	selfrotD = -90
	imgObj2= nib.load(str(fileNAME))
	imgObj1 = imgObj2
	im = imgObj2
	selfaffine2 = imgObj2.get_affine()  
	selfheaderdtype = imgObj2.get_data_dtype()
	selfPSx = imgObj1.get_header()['pixdim'][1]
	selfPSy = imgObj1.get_header()['pixdim'][2]
	selfPSz = imgObj1.get_header()['pixdim'][3]
	(x,y,z) = orx.aff2axcodes(selfaffine2)
	selfOrx = x
	selfOry = y
	selfOrz = z
	ornt = orx.axcodes2ornt((x,y,z))  
	refOrnt = orx.axcodes2ornt(('R','S','A')) #was 'R', 'A', 'S'
	newOrnt = orx.ornt_transform(ornt,refOrnt)
	selfornt = ornt
	selfrefOrnt = refOrnt

	selfimg_data2 = imgObj2.get_data()       

	selfimg_data2 = orx.apply_orientation(selfimg_data2,newOrnt)

	selfimg_data2 = np.fliplr(np.rot90(selfimg_data2,1))
	im_data = selfimg_data2

	[x_si,y_si,z_si] = np.shape(im_data)

	#do 99% norm to 1000 
	im_data = np.array(im_data,dtype='float')
	im_data = im_data * 1000/np.percentile(im_data,99)
	#print np.shape(im_data)
	initialSeg = im_data.copy() * 0

	#begin user roi drawing...
	#go from middle up...
	for i in xrange(np.round(z_si/2),z_si,3):

		img = (im_data[:,:,i])

		# show the image
		if i > np.round(z_si/2):
			plt.figure(figsize=(ROI1.figwidth,ROI1.figheight))
		plt.imshow(img,cmap='gray')
		plt.colorbar()
		plt.title("outline one kidney, slice = " + str(i))

		# let user draw first ROI
		ROI1 = polydraw(roicolor='r') #let user draw first ROI

		# show the image with the first ROI
		plt.figure(figsize=(ROI1.figwidth,ROI1.figheight))
		plt.imshow(img,cmap='gray')
		plt.colorbar()
		ROI1.displayROI()
		plt.title("outline other kidney, slice = " + str(i))

		# let user draw second ROI
		ROI2 = polydraw(roicolor='b') #let user draw ROI

		initialSeg[:,:,i] = ROI1.getMask(img) + ROI2.getMask(img)


	#go from middle up...
	for i in xrange(np.round(z_si/2)-1,0,-3):

		img = (im_data[:,:,i])

		# show the image
		plt.figure(figsize=(ROI1.figwidth,ROI1.figheight))
		plt.imshow(img,cmap='gray')
		plt.colorbar()
		plt.title("outline one kidney, slice = " + str(i))

		# let user draw first ROI
		ROI1 = polydraw(roicolor='r') #let user draw first ROI

		# show the image with the first ROI
		plt.figure(figsize=(ROI1.figwidth,ROI1.figheight))
		plt.imshow(img,cmap='gray')
		plt.colorbar()
		ROI1.displayROI()
		plt.title("outline other kidney, slice = " + str(i))

		# let user draw second ROI
		ROI2 = polydraw(roicolor='b') #let user draw ROI

		initialSeg[:,:,i] = ROI1.getMask(img) + ROI2.getMask(img)

	toc = time.clock()


	#save out drawn polygon
	aff = selfaffine2
	outImage = deepcopy(initialSeg)#np.rot90(np.fliplr(self.segImg),-1)
	[x_si,y_si,z_si] = np.shape(outImage)
	#print np.shape(outImage)
	#This method works (for fastsegs)... but need more robust
	#for i in range(0,z_si):
	#    outImage[:,:,i] = np.rot90(self.segImg[:,:,z_si-1-i],-1)

	#try new method (more robust to header and affine mix-ups)
	ornt = orx.axcodes2ornt((selfOrx,selfOry,selfOrz))  
	refOrnt = orx.axcodes2ornt(('R','S','A'))
	newOrnt = orx.ornt_transform(refOrnt,ornt) #reversed these
	outImage= orx.apply_orientation(np.rot90(np.fliplr(outImage),-1),newOrnt)  
	#outImage = orx.apply_orientation(outImage,newOrnt)    
	#outImage = np.rot90(np.fliplr(outImage),-1)
	#print np.shape(outImage)
	#outImage = np.array(outImage,dtype=selfheaderdtype)
	new_image = nib.Nifti1Image(outImage,aff)

	nib.save(new_image,fileNAME[:-7]+'_polygon_MICOS.nii.gz')
Exemple #18
0
def to_affine(
    orientation,
    spacing: Sequence[Union[int, float]] = None,
    origin: Sequence[Union[int, float]] = None,
):
    """Convert orientation, spacing, and origin data into affine matrix.

    Args:
        orientation (Sequence[str]): Image orientation in the standard orientation format
            (e.g. ``("LR", "AP", "SI")``).
        spacing (int(s) | float(s)): Number(s) corresponding to pixel spacing of each direction.
            If a single value, same pixel spacing is used for all directions.
            If sequence is less than length of ``orientation``, remaining direction have unit
            spacing (i.e. ``1``). Defaults to unit spacing ``(1, 1, 1)``
        origin (int(s) | float(s)): The ``(x0, y0, z0)`` origin for the scan.
            If a single value, same origin is used for all directions.
            If sequence is less than length of ``orientation``, remaining direction have standard
            origin (i.e. ``0``). Defaults to ``(0, 0, 0)``

    Returns:
        ndarray: A 4x4 ndarray representing the affine matrix.

    Examples:
        >>> to_affine(("SI", "AP", "RL"), spacing=(0.5, 0.5, 1.5), origin=(10, 20, 0))
        array([[-0. , -0. , -1.5,  10. ],
               [-0. , -0.5, -0. ,  20. ],
               [-0.5, -0. , -0. ,  30. ],
               [ 0. ,  0. ,  0. ,   1. ]])

    Note:
        This method assumes all direction follow the standard principal directions in the normative
        patient orientation. Moving along one direction of the array only moves along one fo the
        normative directions.
    """
    def _format_numbers(input, default_val, name, expected_num):
        """Formats (sequence of) numbers (spacing, origin) into standard 3-length tuple."""
        if input is None:
            return (default_val, ) * expected_num
        if isinstance(input, (int, float)):
            return (input, ) * expected_num

        if not isinstance(input,
                          (np.ndarray, Sequence)) or len(input) > expected_num:
            raise ValueError(
                f"`{name}` must be a real number or sequence (length<={expected_num}) "
                f"of real numbers. Got {input}")
        input = tuple(input)

        if len(input) < expected_num:
            input += (default_val, ) * (expected_num - len(input))
        assert len(input) == expected_num

        return input

    if len(orientation) == 2:
        orientation = _infer_orientation(orientation)
    __check_orientation__(orientation)
    spacing = _format_numbers(spacing, 1, "spacing", len(orientation))
    origin = _format_numbers(origin, 0, "origin", len(orientation))

    affine = np.eye(4)
    start_ornt = nibo.io_orientation(affine)
    end_ornt = nibo.axcodes2ornt(orientation_standard_to_nib(orientation))
    ornt = nibo.ornt_transform(start_ornt, end_ornt)

    transpose_idxs = ornt[:, 0].astype(np.int)
    flip_idxs = ornt[:, 1]

    affine[:3] = affine[:3][transpose_idxs]
    affine[:3] *= flip_idxs[..., np.newaxis]
    affine[:3, :3] *= np.asarray(spacing)
    affine[:3, 3] = np.asarray(origin)

    return affine
Exemple #19
0
def MICOS(fileNAME):

	tic = time.clock()

	selfz =0
	selfz1 = 0
	selfz2 = 0
	selfrotD = -90
	imgObj2= nib.load(str(fileNAME))
	imgObj1 = imgObj2
	im = imgObj2
	selfaffine2 = imgObj2.get_affine()  
	selfheaderdtype = imgObj2.get_data_dtype()
	selfPSx = imgObj1.get_header()['pixdim'][1]
	selfPSy = imgObj1.get_header()['pixdim'][2]
	selfPSz = imgObj1.get_header()['pixdim'][3]
	(x,y,z) = orx.aff2axcodes(selfaffine2)
	selfOrx = x
	selfOry = y
	selfOrz = z
	ornt = orx.axcodes2ornt((x,y,z))  
	refOrnt = orx.axcodes2ornt(('R','S','A')) #was 'R', 'A', 'S'
	newOrnt = orx.ornt_transform(ornt,refOrnt)
	selfornt = ornt
	selfrefOrnt = refOrnt

	selfimg_data2 = imgObj2.get_data()       

	selfimg_data2 = orx.apply_orientation(selfimg_data2,newOrnt)

	selfimg_data2 = np.fliplr(np.rot90(selfimg_data2,1))
	im_data = selfimg_data2

	[x_si,y_si,z_si] = np.shape(im_data)

	#do 99% norm to 1000 
	im_data = np.array(im_data,dtype='float')
	im_data = im_data * 1000/np.percentile(im_data,99)
	#print np.shape(im_data)
	initialSeg = im_data.copy() * 0

	#begin user roi drawing...
	#go from middle up...
	for i in xrange(np.round(z_si/2),z_si,3):

		img = (im_data[:,:,i])

		# show the image
		if i > np.round(z_si/2):
			plt.figure(figsize=(ROI1.figwidth,ROI1.figheight))
		plt.imshow(img,cmap='gray')
		plt.colorbar()
		plt.title("outline one kidney, slice = " + str(i))

		# let user draw first ROI
		ROI1 = polydraw(roicolor='r') #let user draw first ROI

		# show the image with the first ROI
		plt.figure(figsize=(ROI1.figwidth,ROI1.figheight))
		plt.imshow(img,cmap='gray')
		plt.colorbar()
		ROI1.displayROI()
		plt.title("outline other kidney, slice = " + str(i))

		# let user draw second ROI
		ROI2 = polydraw(roicolor='b') #let user draw ROI

		initialSeg[:,:,i] = ROI1.getMask(img) + ROI2.getMask(img)


	#go from middle up...
	for i in xrange(np.round(z_si/2)-1,0,-3):

		img = (im_data[:,:,i])

		# show the image
		plt.figure(figsize=(ROI1.figwidth,ROI1.figheight))
		plt.imshow(img,cmap='gray')
		plt.colorbar()
		plt.title("outline one kidney, slice = " + str(i))

		# let user draw first ROI
		ROI1 = polydraw(roicolor='r') #let user draw first ROI

		# show the image with the first ROI
		plt.figure(figsize=(ROI1.figwidth,ROI1.figheight))
		plt.imshow(img,cmap='gray')
		plt.colorbar()
		ROI1.displayROI()
		plt.title("outline other kidney, slice = " + str(i))

		# let user draw second ROI
		ROI2 = polydraw(roicolor='b') #let user draw ROI

		initialSeg[:,:,i] = ROI1.getMask(img) + ROI2.getMask(img)

	toc = time.clock()


	#save out drawn polygon
	aff = selfaffine2
	outImage = deepcopy(initialSeg)#np.rot90(np.fliplr(self.segImg),-1)
	[x_si,y_si,z_si] = np.shape(outImage)
	#print np.shape(outImage)
	#This method works (for fastsegs)... but need more robust
	#for i in range(0,z_si):
	#    outImage[:,:,i] = np.rot90(self.segImg[:,:,z_si-1-i],-1)

	#try new method (more robust to header and affine mix-ups)
	ornt = orx.axcodes2ornt((selfOrx,selfOry,selfOrz))  
	refOrnt = orx.axcodes2ornt(('R','S','A'))
	newOrnt = orx.ornt_transform(refOrnt,ornt) #reversed these
	outImage= orx.apply_orientation(np.rot90(np.fliplr(outImage),-1),newOrnt)  
	#outImage = orx.apply_orientation(outImage,newOrnt)    
	#outImage = np.rot90(np.fliplr(outImage),-1)
	#print np.shape(outImage)
	#outImage = np.array(outImage,dtype=selfheaderdtype)
	new_image = nib.Nifti1Image(outImage,aff)

	nib.save(new_image,fileNAME[:-7]+'_polygon_MICOS.nii.gz')

	# Dilate and fill in missing slices
	initialSeg = dilation(initialSeg,iterations = 1)
	finalSeg = initialSeg.copy() * 0

	# now try convex hull method instead to better approximate missing slices (previous method is above)
	# This works but way too long. Also, would likely need to do object finding first, so compute
	# Convex hull for each kidney separately.
	while 0:
		xlist,ylist,zlist = find_3D_object_voxel_list(initialSeg)
		voxlist = np.zeros(shape=(np.shape(xlist)[0],3),dtype='int16')
		voxlist[:,0] = xlist
		voxlist[:,1] = ylist
		voxlist[:,2] = zlist
		tri = dtri(voxlist)

		# construct full voxel list
		xxlist,yylist,zzlist = find_3D_object_voxel_list((initialSeg+1)>0)

		fullvoxlist = np.zeros(shape=(np.shape(xxlist)[0],3),dtype='int16')
		fullvoxlist[:,0] = xxlist
		fullvoxlist[:,1] = yylist
		fullvoxlist[:,2] = zzlist

		finalSeg = np.array(in_hull(fullvoxlist,tri),dtype=float)
		finalSeg = np.reshape(finalSeg,(x_si,y_si,z_si))

	# Now do gaussian blur of polygon to smooth
	initialSeg = (filt.gaussian_filter(initialSeg.copy()*255,sigma=[3,3,1])) > 100

	#Begin optimized method...
	for i in xrange(0,z_si):
		img = (im_data[:,:,i])
		if np.max(initialSeg[:,:,i]>0):

			mgac = []
			gI = msnake.gborders(img,alpha=1E5,sigma=3.0) # increasing sigma allows more changes in contour
			mgac = msnake.MorphGAC(gI,smoothing=3,threshold=0.01,balloon=0.0) #was 2.5
			mgac.levelset = initialSeg[:,:,i]>0.5
			for ijk123 in xrange(100):
				mgac.step()
			finalSeg[:,:,i] = mgac.levelset
		#print i

	# Now do gaussian blur and threshold to finalize segmentation...
	finalSeg = (filt.gaussian_filter(finalSeg.copy()*255,sigma=[3,3,1])) > 100
	#using this helps with single slice errors of the active contour

	# Try adding now narrow band sobel/watershed technique.

	for i in xrange(0,z_si):
		img = (im_data[:,:,i])
		segslice = finalSeg[:,:,i]
		if np.max(finalSeg[:,:,i]>0):

			erodeimg = erosion(segslice.copy(),iterations=1)
			dilateimg = dilation(segslice.copy(),iterations=1)

			seeds = img * 0
			seeds[:] = 1
			seeds[dilateimg>0] = 0
			seeds[erodeimg>0] = 2
			sobelFilt = sobel(np.array(img.copy(),dtype='int16'))
			mgac = watershed(sobelFilt,seeds)>1

			finalSeg[:,:,i] = mgac>0

	#save out segmentation
	aff = selfaffine2
	outImage = deepcopy(finalSeg)#np.rot90(np.fliplr(self.segImg),-1)
	outImage = np.array(outImage,dtype='float')
	[x_si,y_si,z_si] = np.shape(outImage)

	#This method works (for fastsegs)... but need more robust
	#for i in range(0,z_si):
	#    outImage[:,:,i] = np.rot90(self.segImg[:,:,z_si-1-i],-1)

	#try new method (more robust to header and affine mix-ups)
	ornt = orx.axcodes2ornt((selfOrx,selfOry,selfOrz))  
	refOrnt = orx.axcodes2ornt(('R','S','A'))
	newOrnt = orx.ornt_transform(refOrnt,ornt) #reversed these
	outImage= orx.apply_orientation(np.rot90(np.fliplr(outImage),-1),newOrnt)  
	#outImage = orx.apply_orientation(outImage,newOrnt)    
	#outImage = np.rot90(np.fliplr(outImage),-1)
	new_image = nib.Nifti1Image(outImage,aff)
	nib.save(new_image,fileNAME[:-7]+'_FASTseg_MICOS.nii.gz')

	print 'time = '
	print toc - tic

	return (fileNAME[:-7]+'_FASTseg_MICOS.nii.gz')
Exemple #20
0
    def __init__(self, data, affine=None, axes=None, cmap='gray',
                 pcnt_range=(1., 99.), figsize=(8, 8), title=None):
        """
        Parameters
        ----------
        data : ndarray
            The data that will be displayed by the slicer. Should have 3+
            dimensions.
        affine : array-like | None
            Affine transform for the data. This is used to determine
            how the data should be sliced for plotting into the saggital,
            coronal, and axial view axes. If None, identity is assumed.
            The aspect ratio of the data are inferred from the affine
            transform.
        axes : tuple of mpl.Axes | None, optional
            3 or 4 axes instances for the 3 slices plus volumes,
            or None (default).
        cmap : str | instance of cmap, optional
            String or cmap instance specifying colormap.
        pcnt_range : array-like, optional
            Percentile range over which to scale image for display.
        figsize : tuple
            Figure size (in inches) to use if axes are None.
        """
        # Nest imports so that matplotlib.use() has the appropriate
        # effect in testing
        plt, _, _ = optional_package('matplotlib.pyplot')
        mpl_img, _, _ = optional_package('matplotlib.image')
        mpl_patch, _, _ = optional_package('matplotlib.patches')
        self._title = title
        self._closed = False

        data = np.asanyarray(data)
        if data.ndim < 3:
            raise ValueError('data must have at least 3 dimensions')
        affine = np.array(affine, float) if affine is not None else np.eye(4)
        if affine.ndim != 2 or affine.shape != (4, 4):
            raise ValueError('affine must be a 4x4 matrix')
        # determine our orientation
        self._affine = affine.copy()
        codes = axcodes2ornt(aff2axcodes(self._affine))
        self._order = np.argsort([c[0] for c in codes])
        self._flips = np.array([c[1] < 0 for c in codes])[self._order]
        self._flips = list(self._flips) + [False]  # add volume dim
        self._scalers = np.abs(self._affine).max(axis=0)[:3]
        self._inv_affine = np.linalg.inv(affine)
        # current volume info
        self._volume_dims = data.shape[3:]
        self._current_vol_data = data[:, :, :, 0] if data.ndim > 3 else data
        self._data = data
        vmin, vmax = np.percentile(data, pcnt_range)
        del data

        if axes is None:  # make the axes
            # ^ +---------+   ^ +---------+
            # | |         |   | |         |
            #   |   Sag   |     |   Cor   |
            # S |    0    |   S |    1    |
            #   |         |     |         |
            #   |         |     |         |
            #   +---------+     +---------+
            #        A  -->     <--  R
            # ^ +---------+     +---------+
            # | |         |     |         |
            #   |  Axial  |     |   Vol   |
            # A |    2    |     |    3    |
            #   |         |     |         |
            #   |         |     |         |
            #   +---------+     +---------+
            #   <--  R          <--  t  -->

            fig, axes = plt.subplots(2, 2)
            fig.set_size_inches(figsize, forward=True)
            self._axes = [axes[0, 0], axes[0, 1], axes[1, 0], axes[1, 1]]
            plt.tight_layout(pad=0.1)
            if self.n_volumes <= 1:
                fig.delaxes(self._axes[3])
                self._axes.pop(-1)
            if self._title is not None:
                fig.canvas.set_window_title(str(title))
        else:
            self._axes = [axes[0], axes[1], axes[2]]
            if len(axes) > 3:
                self._axes.append(axes[3])

        # Start midway through each axis, idx is current slice number
        self._ims, self._data_idx = list(), list()

        # set up axis crosshairs
        self._crosshairs = [None] * 3
        r = [self._scalers[self._order[2]] / self._scalers[self._order[1]],
             self._scalers[self._order[2]] / self._scalers[self._order[0]],
             self._scalers[self._order[1]] / self._scalers[self._order[0]]]
        self._sizes = [self._data.shape[o] for o in self._order]
        for ii, xax, yax, ratio, label in zip([0, 1, 2], [1, 0, 0], [2, 2, 1],
                                              r, ('SAIP', 'SLIR', 'ALPR')):
            ax = self._axes[ii]
            d = np.zeros((self._sizes[yax], self._sizes[xax]))
            im = self._axes[ii].imshow(d, vmin=vmin, vmax=vmax, aspect=1,
                                       cmap=cmap, interpolation='nearest',
                                       origin='lower')
            self._ims.append(im)
            vert = ax.plot([0] * 2, [-0.5, self._sizes[yax] - 0.5],
                           color=(0, 1, 0), linestyle='-')[0]
            horiz = ax.plot([-0.5, self._sizes[xax] - 0.5], [0] * 2,
                            color=(0, 1, 0), linestyle='-')[0]
            self._crosshairs[ii] = dict(vert=vert, horiz=horiz)
            # add text labels (top, right, bottom, left)
            lims = [0, self._sizes[xax], 0, self._sizes[yax]]
            bump = 0.01
            poss = [[lims[1] / 2., lims[3]],
                    [(1 + bump) * lims[1], lims[3] / 2.],
                    [lims[1] / 2., 0],
                    [lims[0] - bump * lims[1], lims[3] / 2.]]
            anchors = [['center', 'bottom'], ['left', 'center'],
                       ['center', 'top'], ['right', 'center']]
            for pos, anchor, lab in zip(poss, anchors, label):
                ax.text(pos[0], pos[1], lab,
                        horizontalalignment=anchor[0],
                        verticalalignment=anchor[1])
            ax.axis(lims)
            ax.set_aspect(ratio)
            ax.patch.set_visible(False)
            ax.set_frame_on(False)
            ax.axes.get_yaxis().set_visible(False)
            ax.axes.get_xaxis().set_visible(False)
            self._data_idx.append(0)
        self._data_idx.append(-1)  # volume

        # Set up volumes axis
        if self.n_volumes > 1 and len(self._axes) > 3:
            ax = self._axes[3]
            ax.set_axis_bgcolor('k')
            ax.set_title('Volumes')
            y = np.zeros(self.n_volumes + 1)
            x = np.arange(self.n_volumes + 1) - 0.5
            step = ax.step(x, y, where='post', color='y')[0]
            ax.set_xticks(np.unique(np.linspace(0, self.n_volumes - 1,
                                                5).astype(int)))
            ax.set_xlim(x[0], x[-1])
            yl = [self._data.min(), self._data.max()]
            yl = [l + s * np.diff(lims)[0] for l, s in zip(yl, [-1.01, 1.01])]
            patch = mpl_patch.Rectangle([-0.5, yl[0]], 1., np.diff(yl)[0],
                                        fill=True, facecolor=(0, 1, 0),
                                        edgecolor=(0, 1, 0), alpha=0.25)
            ax.add_patch(patch)
            ax.set_ylim(yl)
            self._volume_ax_objs = dict(step=step, patch=patch)

        self._figs = set([a.figure for a in self._axes])
        for fig in self._figs:
            fig.canvas.mpl_connect('scroll_event', self._on_scroll)
            fig.canvas.mpl_connect('motion_notify_event', self._on_mouse)
            fig.canvas.mpl_connect('button_press_event', self._on_mouse)
            fig.canvas.mpl_connect('key_press_event', self._on_keypress)
            fig.canvas.mpl_connect('close_event', self._cleanup)

        # actually set data meaningfully
        self._position = np.zeros(4)
        self._position[3] = 1.  # convenience for affine multn
        self._changing = False  # keep track of status to avoid loops
        self._links = []  # other viewers this one is linked to
        plt.draw()
        for fig in self._figs:
            fig.canvas.draw()
        self._set_volume_index(0, update_slices=False)
        self._set_position(0., 0., 0.)
        self._draw()
Exemple #21
0
    def __init__(self, data, affine=None, axes=None, title=None):
        """
        Parameters
        ----------
        data : array-like
            The data that will be displayed by the slicer. Should have 3+
            dimensions.
        affine : array-like or None, optional
            Affine transform for the data. This is used to determine
            how the data should be sliced for plotting into the sagittal,
            coronal, and axial view axes. If None, identity is assumed.
            The aspect ratio of the data are inferred from the affine
            transform.
        axes : tuple of mpl.Axes or None, optional
            3 or 4 axes instances for the 3 slices plus volumes,
            or None (default).
        title : str or None, optional
            The title to display. Can be None (default) to display no
            title.
        """
        # Use these late imports of matplotlib so that we have some hope that
        # the test functions are the first to set the matplotlib backend. The
        # tests set the backend to something that doesn't require a display.
        self._plt = plt = optional_package('matplotlib.pyplot')[0]
        mpl_patch = optional_package('matplotlib.patches')[0]
        self._title = title
        self._closed = False

        data = np.asanyarray(data)
        if data.ndim < 3:
            raise ValueError('data must have at least 3 dimensions')
        if np.iscomplexobj(data):
            raise TypeError("Complex data not supported")
        affine = np.array(affine, float) if affine is not None else np.eye(4)
        if affine.shape != (4, 4):
            raise ValueError('affine must be a 4x4 matrix')
        # determine our orientation
        self._affine = affine
        codes = axcodes2ornt(aff2axcodes(self._affine))
        self._order = np.argsort([c[0] for c in codes])
        self._flips = np.array([c[1] < 0 for c in codes])[self._order]
        self._flips = list(self._flips) + [False]  # add volume dim
        self._scalers = voxel_sizes(self._affine)
        self._inv_affine = np.linalg.inv(affine)
        # current volume info
        self._volume_dims = data.shape[3:]
        self._current_vol_data = data[:, :, :, 0] if data.ndim > 3 else data
        self._data = data
        self._clim = np.percentile(data, (1., 99.))
        del data

        if axes is None:  # make the axes
            # ^ +---------+   ^ +---------+
            # | |         |   | |         |
            #   |   Sag   |     |   Cor   |
            # S |    0    |   S |    1    |
            #   |         |     |         |
            #   |         |     |         |
            #   +---------+     +---------+
            #        A  -->     <--  R
            # ^ +---------+     +---------+
            # | |         |     |         |
            #   |  Axial  |     |   Vol   |
            # A |    2    |     |    3    |
            #   |         |     |         |
            #   |         |     |         |
            #   +---------+     +---------+
            #   <--  R          <--  t  -->

            fig, axes = plt.subplots(2, 2)
            fig.set_size_inches((8, 8), forward=True)
            self._axes = [axes[0, 0], axes[0, 1], axes[1, 0], axes[1, 1]]
            plt.tight_layout(pad=0.1)
            if self.n_volumes <= 1:
                fig.delaxes(self._axes[3])
                self._axes.pop(-1)
            if self._title is not None:
                fig.canvas.set_window_title(str(title))
        else:
            self._axes = [axes[0], axes[1], axes[2]]
            if len(axes) > 3:
                self._axes.append(axes[3])

        # Start midway through each axis, idx is current slice number
        self._ims, self._data_idx = list(), list()

        # set up axis crosshairs
        self._crosshairs = [None] * 3
        r = [self._scalers[self._order[2]] / self._scalers[self._order[1]],
             self._scalers[self._order[2]] / self._scalers[self._order[0]],
             self._scalers[self._order[1]] / self._scalers[self._order[0]]]
        self._sizes = [self._data.shape[order] for order in self._order]
        for ii, xax, yax, ratio, label in zip([0, 1, 2], [1, 0, 0], [2, 2, 1],
                                              r, ('SAIP', 'SLIR', 'ALPR')):
            ax = self._axes[ii]
            d = np.zeros((self._sizes[yax], self._sizes[xax]))
            im = self._axes[ii].imshow(
                d, vmin=self._clim[0], vmax=self._clim[1], aspect=1,
                cmap='gray', interpolation='nearest', origin='lower')
            self._ims.append(im)
            vert = ax.plot([0] * 2, [-0.5, self._sizes[yax] - 0.5],
                           color=(0, 1, 0), linestyle='-')[0]
            horiz = ax.plot([-0.5, self._sizes[xax] - 0.5], [0] * 2,
                            color=(0, 1, 0), linestyle='-')[0]
            self._crosshairs[ii] = dict(vert=vert, horiz=horiz)
            # add text labels (top, right, bottom, left)
            lims = [0, self._sizes[xax], 0, self._sizes[yax]]
            bump = 0.01
            poss = [[lims[1] / 2., lims[3]],
                    [(1 + bump) * lims[1], lims[3] / 2.],
                    [lims[1] / 2., 0],
                    [lims[0] - bump * lims[1], lims[3] / 2.]]
            anchors = [['center', 'bottom'], ['left', 'center'],
                       ['center', 'top'], ['right', 'center']]
            for pos, anchor, lab in zip(poss, anchors, label):
                ax.text(pos[0], pos[1], lab,
                        horizontalalignment=anchor[0],
                        verticalalignment=anchor[1])
            ax.axis(lims)
            ax.set_aspect(ratio)
            ax.patch.set_visible(False)
            ax.set_frame_on(False)
            ax.axes.get_yaxis().set_visible(False)
            ax.axes.get_xaxis().set_visible(False)
            self._data_idx.append(0)
        self._data_idx.append(-1)  # volume

        # Set up volumes axis
        if self.n_volumes > 1 and len(self._axes) > 3:
            ax = self._axes[3]
            try:
                ax.set_facecolor('k')
            except AttributeError:  # old mpl
                ax.set_axis_bgcolor('k')
            ax.set_title('Volumes')
            y = np.zeros(self.n_volumes + 1)
            x = np.arange(self.n_volumes + 1) - 0.5
            step = ax.step(x, y, where='post', color='y')[0]
            ax.set_xticks(np.unique(np.linspace(0, self.n_volumes - 1,
                                                5).astype(int)))
            ax.set_xlim(x[0], x[-1])
            yl = [self._data.min(), self._data.max()]
            yl = [l + s * np.diff(lims)[0] for l, s in zip(yl, [-1.01, 1.01])]
            patch = mpl_patch.Rectangle([-0.5, yl[0]], 1., np.diff(yl)[0],
                                        fill=True, facecolor=(0, 1, 0),
                                        edgecolor=(0, 1, 0), alpha=0.25)
            ax.add_patch(patch)
            ax.set_ylim(yl)
            self._volume_ax_objs = dict(step=step, patch=patch)

        self._figs = set([a.figure for a in self._axes])
        for fig in self._figs:
            fig.canvas.mpl_connect('scroll_event', self._on_scroll)
            fig.canvas.mpl_connect('motion_notify_event', self._on_mouse)
            fig.canvas.mpl_connect('button_press_event', self._on_mouse)
            fig.canvas.mpl_connect('key_press_event', self._on_keypress)
            fig.canvas.mpl_connect('close_event', self._cleanup)

        # actually set data meaningfully
        self._position = np.zeros(4)
        self._position[3] = 1.  # convenience for affine multiplication
        self._changing = False  # keep track of status to avoid loops
        self._links = []  # other viewers this one is linked to
        self._plt.draw()
        for fig in self._figs:
            fig.canvas.draw()
        self._set_volume_index(0, update_slices=False)
        self._set_position(0., 0., 0.)
        self._draw()
Exemple #22
0
        'Reorient to LIA and resample to 1mm iso-voxel resolution if required')

    parser.add_argument('source', type=str, help='Input volume')

    parser.add_argument('destination', type=str, help='Normalized volume')

    args = parser.parse_args()

    src_nib = nib_funcs.squeeze_image(nib.load(args.source))
    current_orientation = ''.join(nib.aff2axcodes(src_nib.affine))
    print('Input: {} [{}]'.format(src_nib.header.get_zooms(),
                                  current_orientation))

    # Avoid resampling if already 1mm iso-voxel
    # Note: Also in cases of tiny rounding error, e.g. (1.0000001, 1.0000001, 1.0)
    if not np.allclose(src_nib.header.get_zooms(), [1, 1, 1]):
        # requires re-sampling
        print('Resampling')
        dst_nib = nib_processing.conform(src_nib, orientation='LIA')
    elif current_orientation != 'LIA':
        # requires just reorient
        print('Reorientating {} to LIA'.format(current_orientation))
        start_ornt = nib_orientations.io_orientation(src_nib.affine)
        end_ornt = nib_orientations.axcodes2ornt('LIA')
        transform = nib_orientations.ornt_transform(start_ornt, end_ornt)
        dst_nib = src_nib.as_reoriented(transform)
    else:
        dst_nib = src_nib

    nib.save(dst_nib, args.destination)
Exemple #23
0
    def __init__(self, volume, affine=None, title=None, cmap='gray', clim=None, alpha=1.):
        """
        Parameters
        ----------
        volume : array-like
            The data that will be displayed by the slicer. Should have 3
            dimensions.
        affine : array-like or None, optional
            Affine transform for the data. This is used to determine
            how the data should be sliced for plotting into the sagittal,
            coronal, and axial view axes. If None, identity is assumed.
            The aspect ratio of the data are inferred from the affine
            transform.
        title : str or None, optional
            The title to display. Can be None (default) to display no
            title.
        cmap: matplotlib colormap, optional
            Colormap to use for ploting. Default: 'gray'
        clim: [min, max] or None
            Limits to use for plotting. Default: 1 and 99th percentiles
        alpha: float
            Transparency value
        """
        # Use these late imports of matplotlib so that we have some hope that
        # the test functions are the first to set the matplotlib backend. The
        # tests set the backend to something that doesn't require a display.
        self._title = title
        self._closed = False
        self._cross = True

        volume = np.asanyarray(volume)
        if volume.ndim < 3:
            raise ValueError('volume must have at least 3 dimensions')
        if np.iscomplexobj(volume):
            raise TypeError("Complex data not supported")
        affine = np.array(affine, float) if affine is not None else np.eye(4)
        if affine.shape != (4, 4):
            raise ValueError('affine must be a 4x4 matrix')
        # determine our orientation
        self._affine = affine
        codes = axcodes2ornt(aff2axcodes(self._affine))
        self._order = np.argsort([c[0] for c in codes])
        self._flips = np.array([c[1] < 0 for c in codes])[self._order]
        self._flips = list(self._flips) + [False]  # add volume dim
        self._scalers = voxel_sizes(self._affine)
        self._inv_affine = np.linalg.inv(affine)
        # current volume info
        self._volume_dims = volume.shape[3:]
        if len(self._volume_dims) > 0:
            raise NotImplementedError('Cannot handle 4-D Datasets')
        self._volumes = []

        # ^ +---------+   ^ +---------+
        # | |         |   | |         |
        #   |   Sag   |     |   Cor   |
        # S |    0    |   S |    1    |
        #   |         |     |         |
        #   |         |     |         |
        #   +---------+     +---------+
        #        A  -->
        # ^ +---------+
        # | |         |
        #   |  Axial  |
        # A |    2    |
        #   |         |
        #   |         |
        #   +---------+
        #   <--  R
        fig, axes = plt.subplots(2, 2)
        fig.set_size_inches((8, 8), forward=True)
        self._axes = [axes[0, 0], axes[0, 1], axes[1, 0]]
        plt.tight_layout(pad=0.1)
        fig.delaxes(axes[1, 1])
        if self._title is not None:
            fig.canvas.set_window_title(str(title))

        # Start midway through each axis, idx is current slice number
        self._ims, self._data_idx = list(), list()

        # set up axis crosshairs
        self._crosshairs = [None] * 3
        r = [self._scalers[self._order[2]] / self._scalers[self._order[1]],
             self._scalers[self._order[2]] / self._scalers[self._order[0]],
             self._scalers[self._order[1]] / self._scalers[self._order[0]]]
        self._sizes = [volume.shape[order] for order in self._order]
        for ii, xax, yax, ratio, label in zip([0, 1, 2], [1, 0, 0], [2, 2, 1],
                                              r, ('SAIP', 'SRIL', 'ARPL')):
            ax = self._axes[ii]
            vert = ax.plot([0] * 2, [-0.5, self._sizes[yax] - 0.5],
                           color=(0, 1, 0), linestyle='-')[0]
            horiz = ax.plot([-0.5, self._sizes[xax] - 0.5], [0] * 2,
                            color=(0, 1, 0), linestyle='-')[0]
            self._crosshairs[ii] = dict(vert=vert, horiz=horiz)
            # add text labels (top, right, bottom, left)
            lims = [0, self._sizes[xax], 0, self._sizes[yax]]
            bump = 0.01
            poss = [[lims[1] / 2., lims[3]],
                    [(1 + bump) * lims[1], lims[3] / 2.],
                    [lims[1] / 2., 0],
                    [lims[0] - bump * lims[1], lims[3] / 2.]]
            anchors = [['center', 'bottom'], ['left', 'center'],
                       ['center', 'top'], ['right', 'center']]
            for pos, anchor, lab in zip(poss, anchors, label):
                ax.text(pos[0], pos[1], lab,
                        horizontalalignment=anchor[0],
                        verticalalignment=anchor[1])
            ax.axis(lims)
            ax.set_aspect(ratio)
            ax.patch.set_visible(False)
            ax.set_frame_on(False)
            ax.axes.get_yaxis().set_visible(False)
            ax.axes.get_xaxis().set_visible(False)
            self._data_idx.append(0)
        self._data_idx.append(-1)  # volume

        self._figs = set([a.figure for a in self._axes])
        for fig in self._figs:
            fig.canvas.mpl_connect('scroll_event', self._on_scroll)
            fig.canvas.mpl_connect('motion_notify_event', self._on_mouse)
            fig.canvas.mpl_connect('button_press_event', self._on_mouse)

        # actually set data meaningfully
        self.add_overlay(volume, cmap=cmap, clim=clim, alpha=alpha, draw=False)
        self._position = np.zeros(4)
        self._position[3] = 1.  # convenience for affine multiplication
        self._changing = False  # keep track of status to avoid loops
        plt.draw()
        for fig in self._figs:
            fig.canvas.draw_idle()
            fig.canvas.draw()
        plt.pause(1e-3) # give a little bit of time for the renderer (needed on MacOS)
        self._set_position(0., 0., 0.)
        self._draw()