def generate_qc(fn_in, fn_seg, args, path_qc):
    """Generate a QC entry allowing to quickly review the segmentation process."""
    import spinalcordtoolbox.reports.qc as qc
    import spinalcordtoolbox.reports.slice as qcslice
    from spinalcordtoolbox.resample.nipy_resample import resample_file

    # Resample to fixed resolution (see #2063)
    tmp_folder = sct.TempFolder()
    fn_in_r = os.path.join(tmp_folder.path_tmp, 'img_r.nii.gz')
    # Orient to RPI and retrieve pixel size in IS direction (z)
    im_fn = Image(fn_in).change_orientation('RPI').save(fn_in_r)
    resample_file(fn_in_r, fn_in_r, '0.5x0.5x' + str(im_fn.dim[6]), 'mm', 'nn',
                  0)
    fn_seg_r = os.path.join(tmp_folder.path_tmp, 'seg_r.nii.gz')
    Image(fn_seg).change_orientation('RPI').save(fn_seg_r)
    resample_file(fn_seg_r, fn_seg_r, '0.5x0.5x' + str(im_fn.dim[6]), 'mm',
                  'nn', 0)

    # TODO: investigate the following issue further (Julien 2018-12-01):
    # fn_in_r and fn_seg_r should be in nii.gz format, otherwise qcslice.Axial outputs an memmap instead of
    # an array.
    qc.add_entry(
        src=fn_in,
        process="sct_deepseg_sc",
        args=args,
        path_qc=path_qc,
        plane='Axial',
        qcslice=qcslice.Axial([Image(fn_in_r), Image(fn_seg_r)]),
        qcslice_operations=[qc.QcImage.listed_seg],
        qcslice_layout=lambda x: x.mosaic(),
    )
示例#2
0
def generate_qc(fn_in, fn_seg, args, path_qc):
    """
    Generate a QC entry allowing to quickly review the segmentation process.
    """

    import spinalcordtoolbox.reports.qc as qc
    import spinalcordtoolbox.reports.slice as qcslice
    from spinalcordtoolbox.resample.nipy_resample import resample_file

    # Resample to fixed resolution (see #2063)
    tmp_folder = sct.TempFolder()
    fn_in_r = os.path.join(tmp_folder.path_tmp, 'img_r.nii.gz')
    # Orient to RPI and retrieve pixel size in IS direction (z)
    im_fn = Image(fn_in).change_orientation('RPI').save(fn_in_r)
    resample_file(fn_in_r, fn_in_r, '0.5x0.5x' + str(im_fn.dim[6]), 'mm', 'nn',
                  0)
    fn_seg_r = os.path.join(tmp_folder.path_tmp, 'seg_r.nii.gz')
    Image(fn_seg).change_orientation('RPI').save(fn_seg_r)
    resample_file(fn_seg_r, fn_seg_r, '0.5x0.5x' + str(im_fn.dim[6]), 'mm',
                  'nn', 0)

    qc.add_entry(
        src=fn_in,
        process="sct_propseg",
        args=args,
        path_qc=path_qc,
        plane='Axial',
        qcslice=qcslice.Axial([Image(fn_in_r), Image(fn_seg_r)]),
        qcslice_operations=[qc.QcImage.listed_seg],
        qcslice_layout=lambda x: x.mosaic(),
    )
示例#3
0
def detect_centerline(img, contrast):
    """Detect spinal cord centerline using OptiC.
    :param img: input Image() object.
    :param contrast: str: The type of contrast. Will define the path to Optic model.
    :returns: Image(): Output centerline
    """

    # Fetch path to Optic model based on contrast
    optic_models_path = os.path.join(sct.__sct_dir__, 'data', 'optic_models',
                                     '{}_model'.format(contrast))

    sct.log.debug('Detecting the spinal cord using OptiC')
    img_orientation = img.orientation

    temp_folder = sct.TempFolder()
    temp_folder.chdir()

    # convert image data type to int16, as required by opencv (backend in OptiC)
    img_int16 = img.copy()
    # Replace non-numeric values by zero
    img_data = img.data
    img_data[np.where(np.isnan(img_data))] = 0
    img_data[np.where(np.isinf(img_data))] = 0
    img_int16.data[np.where(np.isnan(img_int16.data))] = 0
    img_int16.data[np.where(np.isinf(img_int16.data))] = 0
    # rescale intensity
    min_out = np.iinfo('uint16').min
    max_out = np.iinfo('uint16').max
    min_in = np.nanmin(img_data)
    max_in = np.nanmax(img_data)
    data_rescaled = img_data.astype('float') * (max_out - min_out) / (max_in -
                                                                      min_in)
    img_int16.data = data_rescaled - (data_rescaled.min() - min_out)
    # change data type
    img_int16.change_type(np.uint16)
    # reorient the input image to RPI + convert to .nii
    img_int16.change_orientation('RPI')
    file_img = 'img_rpi_uint16'
    img_int16.save(file_img + '.nii')

    # call the OptiC method to generate the spinal cord centerline
    optic_input = file_img
    optic_filename = file_img + '_optic'
    os.environ["FSLOUTPUTTYPE"] = "NIFTI_PAIR"
    cmd_optic = 'isct_spine_detect -ctype=dpdt -lambda=1 "%s" "%s" "%s"' % \
                (optic_models_path, optic_input, optic_filename)
    # TODO: output coordinates, for each slice, in continuous (not discrete) values.

    sct.run(cmd_optic, verbose=0)

    # convert .img and .hdr files to .nii.gz
    img_ctl = Image(file_img + '_optic_ctr.hdr')
    img_ctl.change_orientation(img_orientation)

    # return to initial folder
    temp_folder.chdir_undo()

    return img_ctl
示例#4
0
def preprocess_image(image,
                     contrast_type='t1',
                     ctr_algo='svm',
                     ctr_file=None,
                     brain_bool=True,
                     kernel_size='2d',
                     remove_temp_files=1,
                     verbose=1):
    """ Resamples, reorients to RPI, and applies OptiC cropping to an Image and returns the result as an sct Image.
	Inputs:
		image - Image to be cropped
	Returns:
		im_nii - resampled Image
		im_norm_in - resampled, cropped, and normalized Imagect
		X_CROP_LST, Y_CROP_LST, Z_CROP_LST - coordinates for cropping original image
	"""

    im = image.copy()

    # create temporary folder with intermediate results
    tmp_folder = sct.TempFolder(verbose=verbose)
    tmp_folder_path = tmp_folder.get_path()
    if ctr_algo == 'file':  # 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()

    # re-orient image to RPI if necessary...
    original_orientation = im.orientation
    fname_orient = 'image_in_RPI.nii'
    im.change_orientation('RPI').save(fname_orient)

    input_resolution = im.dim[4:7]

    # resamples image to 0.5x0.5 resolution and finds the spinal cord centerline - execute OptiC binary
    fname_res, centerline_filename, im_labels = find_centerline(
        algo=ctr_algo,
        image_fname=fname_orient,
        contrast_type=contrast_type,
        brain_bool=brain_bool,
        folder_output=tmp_folder_path,
        remove_temp_files=remove_temp_files,
        centerline_fname=file_ctr)
    # could save the ctr_nii later if desired
    im_nii, ctr_nii = Image(fname_res), Image(centerline_filename)

    # crop image around the spinal cord centerline
    crop_size = 96 if (kernel_size == '3d' and contrast_type == 't2s') else 64
    X_CROP_LST, Y_CROP_LST, Z_CROP_LST, im_crop_nii = crop_image_around_centerline(
        im_in=im_nii, ctr_in=ctr_nii, crop_size=crop_size)
    # normalize the intensity of the images
    im_norm_in = apply_intensity_normalization(im_in=im_crop_nii)
    return im_nii, im_norm_in, X_CROP_LST, Y_CROP_LST, Z_CROP_LST
def _preprocess_segment(fname_t2, fname_t2_seg, contrast_test, dim_3=False):
    tmp_folder = sct.TempFolder()
    tmp_folder_path = tmp_folder.get_path()
    tmp_folder.chdir()

    img = Image(fname_t2)
    gt = Image(fname_t2_seg)

    fname_t2_RPI, fname_t2_seg_RPI = 'img_RPI.nii.gz', 'seg_RPI.nii.gz'
    img.change_orientation('RPI').save(fname_t2_RPI)
    gt.change_orientation('RPI').save(fname_t2_seg_RPI)
    input_resolution = gt.dim[4:7]
    del img, gt

    fname_res, fname_ctr, _ = deepseg_sc.find_centerline(algo='svm',
                                                            image_fname=fname_t2_RPI,
                                                            contrast_type=contrast_test,
                                                            brain_bool=False,
                                                            folder_output=tmp_folder_path,
                                                            remove_temp_files=1,
                                                            centerline_fname=None)

    fname_t2_seg_RPI_res = 'seg_RPI_res.nii.gz'
    new_resolution = 'x'.join(['0.5', '0.5', str(input_resolution[2])])
    resample_file(fname_t2_seg_RPI, fname_t2_seg_RPI_res, new_resolution, 'mm', 'linear', verbose=0)

    img, ctr, gt = Image(fname_res), Image(fname_ctr), Image(fname_t2_seg_RPI_res)
    _, _, _, img = deepseg_sc.crop_image_around_centerline(im_in=img,
                                                        ctr_in=ctr,
                                                        crop_size=64)
    _, _, _, gt = deepseg_sc.crop_image_around_centerline(im_in=gt,
                                                        ctr_in=ctr,
                                                        crop_size=64)
    del ctr

    img = deepseg_sc.apply_intensity_normalization(im_in=img)

    if dim_3:  # If 3D kernels
        fname_t2_RPI_res_crop, fname_t2_seg_RPI_res_crop = 'img_RPI_res_crop.nii.gz', 'seg_RPI_res_crop.nii.gz'
        img.save(fname_t2_RPI_res_crop)
        gt.save(fname_t2_seg_RPI_res_crop)
        del img, gt

        fname_t2_RPI_res_crop_res = 'img_RPI_res_crop_res.nii.gz'
        fname_t2_seg_RPI_res_crop_res = 'seg_RPI_res_crop_res.nii.gz'
        resample_file(fname_t2_RPI_res_crop, fname_t2_RPI_res_crop_res, new_resolution, 'mm', 'linear', verbose=0)
        resample_file(fname_t2_seg_RPI_res_crop, fname_t2_seg_RPI_res_crop_res, new_resolution, 'mm', 'linear', verbose=0)
        img, gt = Image(fname_t2_RPI_res_crop_res), Image(fname_t2_seg_RPI_res_crop_res)

    tmp_folder.chdir_undo()
    tmp_folder.cleanup()

    return img, gt
示例#6
0
def deep_segmentation_MSlesion(im_image,
                               contrast_type,
                               ctr_algo='svm',
                               ctr_file=None,
                               brain_bool=True,
                               remove_temp_files=1,
                               verbose=1):
    """
    Segment lesions from MRI data.

    :param im_image: Image() object containing the lesions to segment
    :param contrast_type: Constrast of the image. Need to use one supported by the CNN models.
    :param ctr_algo: Algo to find the centerline. See sct_get_centerline
    :param ctr_file: Centerline or segmentation (optional)
    :param brain_bool: If brain if present or not in the image.
    :param remove_temp_files:
    :return:
    """

    # create temporary folder with intermediate results
    tmp_folder = sct.TempFolder(verbose=verbose)
    tmp_folder_path = tmp_folder.get_path()
    if ctr_algo == 'file':  # 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()
    fname_in = im_image.absolutepath

    # re-orient image to RPI
    logger.info("Reorient the image to RPI, if necessary...")
    original_orientation = im_image.orientation
    # fname_orient = 'image_in_RPI.nii'
    im_image.change_orientation('RPI')

    input_resolution = im_image.dim[4:7]

    # Resample image to 0.5mm in plane
    im_image_res = \
        resampling.resample_nib(im_image, new_size=[0.5, 0.5, im_image.dim[6]], new_size_type='mm', interpolation='linear')

    fname_orient = 'image_in_RPI_res.nii'
    im_image_res.save(fname_orient)

    # find the spinal cord centerline - execute OptiC binary
    logger.info("\nFinding the spinal cord centerline...")
    contrast_type_ctr = contrast_type.split('_')[0]
    _, im_ctl, im_labels_viewer = find_centerline(
        algo=ctr_algo,
        image_fname=fname_orient,
        contrast_type=contrast_type_ctr,
        brain_bool=brain_bool,
        folder_output=tmp_folder_path,
        remove_temp_files=remove_temp_files,
        centerline_fname=file_ctr)
    if ctr_algo == 'file':
        im_ctl = \
            resampling.resample_nib(im_ctl, new_size=[0.5, 0.5, im_image.dim[6]], new_size_type='mm', interpolation='linear')

    # crop image around the spinal cord centerline
    logger.info("\nCropping the image around the spinal cord...")
    crop_size = 48
    X_CROP_LST, Y_CROP_LST, Z_CROP_LST, im_crop_nii = crop_image_around_centerline(
        im_in=im_image_res, ctr_in=im_ctl, crop_size=crop_size)
    del im_ctl

    # normalize the intensity of the images
    logger.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')
    resampling.resample_file(fname_norm,
                             fname_res3d,
                             '0.5x0.5x0.5',
                             'mm',
                             'linear',
                             verbose=0)

    # segment data using 3D convolutions
    logger.info(
        "\nSegmenting the MS lesions using deep learning on 3D patches...")
    segmentation_model_fname = sct_dir_local_path(
        'data', 'deepseg_lesion_models', '{}_lesion.h5'.format(contrast_type))
    fname_seg_crop_res = sct.add_suffix(fname_res3d, '_lesionseg')
    im_res3d = Image(fname_res3d)
    seg_im = segment_3d(model_fname=segmentation_model_fname,
                        contrast_type=contrast_type,
                        im=im_res3d.copy())
    seg_im.save(fname_seg_crop_res)
    del im_res3d, seg_im

    # 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])])
    resampling.resample_file(fname_seg_crop_res,
                             fname_seg_res2d,
                             initial_2d_resolution,
                             'mm',
                             'linear',
                             verbose=0)
    seg_crop = Image(fname_seg_res2d)

    # reconstruct the segmentation from the crop data
    logger.info("\nReassembling the image...")
    seg_uncrop_nii = uncrop_image(ref_in=im_image_res,
                                  data_crop=seg_crop.copy().data,
                                  x_crop_lst=X_CROP_LST,
                                  y_crop_lst=Y_CROP_LST,
                                  z_crop_lst=Z_CROP_LST)
    fname_seg_res_RPI = sct.add_suffix(fname_in, '_res_RPI_seg')
    seg_uncrop_nii.save(fname_seg_res_RPI)
    del seg_crop

    # resample to initial resolution
    logger.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(fname_in, '_RPI_seg')
    resampling.resample_file(fname_seg_res_RPI,
                             fname_seg_RPI,
                             initial_resolution,
                             'mm',
                             'linear',
                             verbose=0)
    seg_initres_nii = Image(fname_seg_RPI)

    if ctr_algo == 'viewer':  # resample and reorient the viewer labels
        im_labels_viewer_nib = nib.nifti1.Nifti1Image(
            im_labels_viewer.data, im_labels_viewer.hdr.get_best_affine())
        im_viewer_r_nib = resampling.resample_nib(im_labels_viewer_nib,
                                                  new_size=input_resolution,
                                                  new_size_type='mm',
                                                  interpolation='linear')
        im_viewer = Image(
            im_viewer_r_nib.get_data(),
            hdr=im_viewer_r_nib.header,
            orientation='RPI',
            dim=im_viewer_r_nib.header.get_data_shape()).change_orientation(
                original_orientation)

    else:
        im_viewer = None

    if verbose == 2:
        fname_res_ctr = sct.add_suffix(fname_orient, '_ctr')
        resampling.resample_file(fname_res_ctr,
                                 fname_res_ctr,
                                 initial_resolution,
                                 'mm',
                                 'linear',
                                 verbose=0)
        im_image_res_ctr_downsamp = Image(fname_res_ctr).change_orientation(
            original_orientation)
    else:
        im_image_res_ctr_downsamp = None

    # binarize the resampled image to remove interpolation effects
    logger.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

    # change data type
    seg_initres_nii.change_type(np.uint8)

    # reorient to initial orientation
    logger.info(
        "\nReorienting the segmentation to the original image orientation...")
    tmp_folder.chdir_undo()

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

    # reorient to initial orientation
    return seg_initres_nii.change_orientation(
        original_orientation), im_viewer, im_image_res_ctr_downsamp
示例#7
0
def run_main():
    sct.start_stream_logger()
    parser = get_parser()
    args = sys.argv[1:]
    arguments = parser.parse(args)

    # Input filename
    fname_input_data = arguments["-i"]
    fname_data = os.path.abspath(fname_input_data)

    # Method used
    method = 'optic'
    if "-method" in arguments:
        method = arguments["-method"]

    # Contrast type
    contrast_type = ''
    if "-c" in arguments:
        contrast_type = arguments["-c"]
    if method == 'optic' and not contrast_type:
        # Contrast must be
        error = 'ERROR: -c is a mandatory argument when using Optic method.'
        sct.printv(error, type='error')
        return

    # Ga between slices
    interslice_gap = 10.0
    if "-gap" in arguments:
        interslice_gap = float(arguments["-gap"])

    # Output folder
    if "-ofolder" in arguments:
        folder_output = sct.slash_at_the_end(arguments["-ofolder"], slash=1)
    else:
        folder_output = './'

    # Remove temporary files
    remove_temp_files = True
    if "-r" in arguments:
        remove_temp_files = bool(int(arguments["-r"]))

    # Outputs a ROI file
    output_roi = False
    if "-roi" in arguments:
        output_roi = bool(int(arguments["-roi"]))

    # Verbosity
    verbose = 0
    if "-v" in arguments:
        verbose = int(arguments["-v"])

    if method == 'viewer':
        path_data, file_data, ext_data = sct.extract_fname(fname_data)

        # create temporary folder
        temp_folder = sct.TempFolder()
        temp_folder.copy_from(fname_data)
        temp_folder.chdir()

        # make sure image is in SAL orientation, as it is the orientation used by the viewer
        image_input = Image(fname_data)
        image_input_orientation = orientation(image_input,
                                              get=True,
                                              verbose=False)
        reoriented_image_filename = sct.add_suffix(file_data + ext_data,
                                                   "_SAL")
        cmd_image = 'sct_image -i "%s" -o "%s" -setorient SAL -v 0' % (
            fname_data, reoriented_image_filename)
        sct.run(cmd_image, verbose=False)

        # extract points manually using the viewer
        fname_points = viewer_centerline(image_fname=reoriented_image_filename,
                                         interslice_gap=interslice_gap,
                                         verbose=verbose)

        if fname_points is not None:
            image_points_RPI = sct.add_suffix(fname_points, "_RPI")
            cmd_image = 'sct_image -i "%s" -o "%s" -setorient RPI -v 0' % (
                fname_points, image_points_RPI)
            sct.run(cmd_image, verbose=False)

            image_input_reoriented = Image(image_points_RPI)

            # fit centerline, smooth it and return the first derivative (in physical space)
            x_centerline_fit, y_centerline_fit, z_centerline, x_centerline_deriv, y_centerline_deriv, z_centerline_deriv = smooth_centerline(
                image_points_RPI,
                algo_fitting='nurbs',
                nurbs_pts_number=3000,
                phys_coordinates=True,
                verbose=verbose,
                all_slices=False)
            centerline = Centerline(x_centerline_fit, y_centerline_fit,
                                    z_centerline, x_centerline_deriv,
                                    y_centerline_deriv, z_centerline_deriv)

            # average centerline coordinates over slices of the image
            x_centerline_fit_rescorr, y_centerline_fit_rescorr, z_centerline_rescorr, x_centerline_deriv_rescorr, y_centerline_deriv_rescorr, z_centerline_deriv_rescorr = centerline.average_coordinates_over_slices(
                image_input_reoriented)

            # compute z_centerline in image coordinates for usage in vertebrae mapping
            voxel_coordinates = image_input_reoriented.transfo_phys2pix([[
                x_centerline_fit_rescorr[i], y_centerline_fit_rescorr[i],
                z_centerline_rescorr[i]
            ] for i in range(len(z_centerline_rescorr))])
            x_centerline_voxel = [coord[0] for coord in voxel_coordinates]
            y_centerline_voxel = [coord[1] for coord in voxel_coordinates]
            z_centerline_voxel = [coord[2] for coord in voxel_coordinates]

            # compute z_centerline in image coordinates with continuous precision
            voxel_coordinates = image_input_reoriented.transfo_phys2continuouspix(
                [[
                    x_centerline_fit_rescorr[i], y_centerline_fit_rescorr[i],
                    z_centerline_rescorr[i]
                ] for i in range(len(z_centerline_rescorr))])
            x_centerline_voxel_cont = [coord[0] for coord in voxel_coordinates]
            y_centerline_voxel_cont = [coord[1] for coord in voxel_coordinates]
            z_centerline_voxel_cont = [coord[2] for coord in voxel_coordinates]

            # Create an image with the centerline
            image_input_reoriented.data *= 0
            min_z_index, max_z_index = int(round(
                min(z_centerline_voxel))), int(round(max(z_centerline_voxel)))
            for iz in range(min_z_index, max_z_index + 1):
                image_input_reoriented.data[
                    int(round(x_centerline_voxel[iz - min_z_index])),
                    int(round(y_centerline_voxel[iz - min_z_index])),
                    int(
                        iz
                    )] = 1  # if index is out of bounds here for hanning: either the segmentation has holes or labels have been added to the file

            # Write the centerline image
            sct.printv('\nWrite NIFTI volumes...', verbose)
            fname_centerline_oriented = file_data + '_centerline' + ext_data
            image_input_reoriented.setFileName(fname_centerline_oriented)
            image_input_reoriented.changeType('uint8')
            image_input_reoriented.save()

            sct.printv('\nSet to original orientation...', verbose)
            sct.run('sct_image -i ' + fname_centerline_oriented +
                    ' -setorient ' + image_input_orientation + ' -o ' +
                    fname_centerline_oriented)

            # create a txt file with the centerline
            fname_centerline_oriented_txt = file_data + '_centerline.txt'
            file_results = open(fname_centerline_oriented_txt, 'w')
            for i in range(min_z_index, max_z_index + 1):
                file_results.write(
                    str(int(i)) + ' ' +
                    str(round(x_centerline_voxel_cont[i - min_z_index], 2)) +
                    ' ' +
                    str(round(y_centerline_voxel_cont[i - min_z_index], 2)) +
                    '\n')
            file_results.close()

            fname_centerline_oriented_roi = optic.centerline2roi(
                fname_image=fname_centerline_oriented,
                folder_output='./',
                verbose=verbose)

            # return to initial folder
            temp_folder.chdir_undo()

            # copy result to output folder
            shutil.copy(temp_folder.get_path() + fname_centerline_oriented,
                        folder_output)
            shutil.copy(temp_folder.get_path() + fname_centerline_oriented_txt,
                        folder_output)
            if output_roi:
                shutil.copy(
                    temp_folder.get_path() + fname_centerline_oriented_roi,
                    folder_output)
            centerline_filename = folder_output + fname_centerline_oriented

        else:
            centerline_filename = 'error'

        # delete temporary folder
        if remove_temp_files:
            temp_folder.cleanup()

    else:
        # condition on verbose when using OptiC
        if verbose == 1:
            verbose = 2

        # OptiC models
        path_script = os.path.dirname(__file__)
        path_sct = os.path.dirname(path_script)
        optic_models_path = os.path.join(path_sct, 'data/optic_models',
                                         '{}_model'.format(contrast_type))

        # Execute OptiC binary
        _, centerline_filename = optic.detect_centerline(
            image_fname=fname_data,
            contrast_type=contrast_type,
            optic_models_path=optic_models_path,
            folder_output=folder_output,
            remove_temp_files=remove_temp_files,
            output_roi=output_roi,
            verbose=verbose)

    sct.printv('\nDone! To view results, type:', verbose)
    sct.printv(
        "fslview " + fname_input_data + " " + centerline_filename +
        " -l Red -b 0,1 -t 0.7 &\n", verbose, 'info')
def detect_c2c3(nii_im, nii_seg, contrast, verbose=1):
    """
    Detect the posterior edge of C2-C3 disc.
    :param nii_im:
    :param nii_seg:
    :param contrast:
    :param verbose:
    :return:
    """
    # path to the pmj detector
    path_sct = os.environ.get("SCT_DIR",
                              os.path.dirname(os.path.dirname(__file__)))
    path_model = os.path.join(path_sct, 'data', 'c2c3_disc_models',
                              '{}_model'.format(contrast))

    orientation_init = nii_im.orientation

    # Flatten sagittal
    nii_im = flatten_sagittal(nii_im,
                              nii_seg,
                              centerline_fitting='hanning',
                              verbose=verbose)
    nii_seg_flat = flatten_sagittal(nii_seg,
                                    nii_seg,
                                    centerline_fitting='hanning',
                                    verbose=verbose)

    # create temporary folder with intermediate results
    sct.log.info("Creating temporary folder...")
    tmp_folder = sct.TempFolder()
    tmp_folder.chdir()

    # Extract mid-slice
    nii_im.change_orientation('PIR')
    nii_seg_flat.change_orientation('PIR')
    mid_RL = int(np.rint(nii_im.dim[2] * 1.0 / 2))
    midSlice = nii_im.data[:, :, mid_RL]
    midSlice_seg = nii_seg_flat.data[:, :, mid_RL]
    nii_midSlice = msct_image.zeros_like(nii_im)
    nii_midSlice.data = midSlice
    nii_midSlice.save('data_midSlice.nii')

    # Run detection
    sct.printv('Run C2-C3 detector...', verbose)
    os.environ["FSLOUTPUTTYPE"] = "NIFTI_PAIR"
    cmd_detection = 'isct_spine_detect -ctype=dpdt "%s" "%s" "%s"' % \
                    (path_model, 'data_midSlice', 'data_midSlice_pred')
    sct.run(cmd_detection, verbose=0, raise_exception=False)

    # sct.run(cmd_detection, verbose=0)
    pred = nib.load('data_midSlice_pred_svm.hdr').get_data()

    # Create mask along centerline
    midSlice_mask = np.zeros(midSlice_seg.shape)
    mask_halfSize = 25
    for z in range(midSlice_mask.shape[1]):
        row = midSlice_seg[:, z]
        if np.any(row):
            med_y = int(np.rint(np.median(np.where(row))))
            midSlice_mask[med_y - mask_halfSize:med_y + mask_halfSize] = 1

    # mask prediction
    pred[midSlice_mask == 0] = 0

    # assign label to voxel
    nii_c2c3 = zeros_like(nii_seg_flat)
    if np.any(pred > 0):
        sct.printv('C2-C3 detected...', verbose)
        coord_max = np.where(pred == np.max(pred))
        pa_c2c3, is_c2c3 = coord_max[0][0], coord_max[1][0]
        nii_seg.change_orientation('PIR')
        rl_c2c3 = int(np.rint(center_of_mass(nii_seg.data[:, is_c2c3, :])[1]))
        nii_c2c3.data[pa_c2c3, is_c2c3, rl_c2c3] = 3
    else:
        sct.printv('C2-C3 not detected...', verbose)

    # remove temporary files
    tmp_folder.chdir_undo()
    sct.log.info("Remove temporary files...")
    tmp_folder.cleanup()

    nii_c2c3.change_orientation(orientation_init)
    return nii_c2c3
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)
示例#10
0
def detect_c2c3(nii_im, nii_seg, contrast, nb_sag_avg=7.0, verbose=1):
    """
    Detect the posterior edge of C2-C3 disc.

    :param nii_im:
    :param nii_seg:
    :param contrast:
    :param verbose:
    :return:
    """
    # path to the pmj detector
    path_model = os.path.join(sct.__data_dir__, 'c2c3_disc_models',
                              '{}_model'.format(contrast))
    # check if model exists
    if not os.path.isfile(path_model + '.yml'):
        raise FileNotFoundError(
            "The model file {} does not exist. Please download it using sct_download_data"
            .format(path_model + '.yml'))

    orientation_init = nii_im.orientation
    z_seg_max = np.max(np.where(nii_seg.change_orientation('PIR').data)[1])

    # Flatten sagittal
    nii_im = flatten_sagittal(nii_im, nii_seg, verbose=verbose)
    nii_seg_flat = flatten_sagittal(nii_seg, nii_seg, verbose=verbose)

    # create temporary folder with intermediate results
    logger.info("Creating temporary folder...")
    tmp_folder = sct.TempFolder()
    tmp_folder.chdir()

    # Extract mid-slice
    nii_im.change_orientation('PIR')
    nii_seg_flat.change_orientation('PIR')
    mid_RL = int(np.rint(nii_im.dim[2] * 1.0 / 2))
    nb_sag_avg_half = int(nb_sag_avg / 2 / nii_im.dim[6])
    midSlice = np.mean(nii_im.data[:, :, mid_RL - nb_sag_avg_half:mid_RL +
                                   nb_sag_avg_half + 1], 2)  # average 7 slices
    midSlice_seg = nii_seg_flat.data[:, :, mid_RL]
    nii_midSlice = zeros_like(nii_im)
    nii_midSlice.data = midSlice
    nii_midSlice.save('data_midSlice.nii')

    # Run detection
    logger.info('Run C2-C3 detector...')
    os.environ["FSLOUTPUTTYPE"] = "NIFTI_PAIR"
    cmd_detection = 'isct_spine_detect -ctype=dpdt "%s" "%s" "%s"' % \
                    (path_model, 'data_midSlice', 'data_midSlice_pred')
    # The command below will fail, but we don't care because it will output an image (prediction), which we
    # will use later on.
    s, o = run_proc(cmd_detection,
                    verbose=0,
                    is_sct_binary=True,
                    raise_exception=False)
    pred = nib.load('data_midSlice_pred_svm.hdr').get_data()
    if verbose >= 2:
        # copy the "prediction data before post-processing" in an Image object
        nii_pred_before_postPro = nii_midSlice.copy()
        nii_pred_before_postPro.data = pred  # 2D data with orientation, mid sag slice of the original data
        nii_pred_before_postPro.save(
            "pred_midSlice_before_postPro.nii.gz")  # save it)
    # DEBUG trick: check if the detection succeed by running: fsleyes data_midSlice data_midSlice_pred_svm -cm red -dr 0 100
    # If a "red cluster" is observed in the neighbourhood of C2C3, then the model detected it.

    # Create mask along centerline
    midSlice_mask = np.zeros(midSlice_seg.shape)
    mask_halfSize = int(np.rint(25.0 / nii_midSlice.dim[4]))
    for z in range(midSlice_mask.shape[1]):
        row = midSlice_seg[:,
                           z]  # 2D data with PI orientation, mid sag slice of the original data
        if np.any(row > 0):
            med_y = int(np.rint(np.median(np.where(row > 0))))
            midSlice_mask[
                med_y - mask_halfSize:med_y + mask_halfSize,
                z] = 1  # 2D data with PI orientation, mid sag slice of the original data
    if verbose >= 2:
        # copy the created mask in an Image object
        nii_postPro_mask = nii_midSlice.copy()
        nii_postPro_mask.data = midSlice_mask  # 2D data with PI orientation, mid sag slice of the original data
        nii_postPro_mask.save("mask_midSlice.nii.gz")  # save it

    # mask prediction
    pred[midSlice_mask == 0] = 0
    pred[:, z_seg_max:] = 0  # Mask above SC segmentation
    if verbose >= 2:
        # copy the "prediction data after post-processing" in an Image object
        nii_pred_after_postPro = nii_midSlice.copy()
        nii_pred_after_postPro.data = pred
        nii_pred_after_postPro.save(
            "pred_midSlice_after_postPro.nii.gz")  # save it

    # assign label to voxel
    nii_c2c3 = zeros_like(nii_seg_flat)  # 3D data with PIR orientaion
    if np.any(pred > 0):
        logger.info('C2-C3 detected...')

        pred_bin = (pred > 0).astype(np.int_)
        coord_max = np.where(pred == np.max(pred))
        pa_c2c3, is_c2c3 = coord_max[0][0], coord_max[1][0]
        nii_seg.change_orientation('PIR')
        rl_c2c3 = int(
            np.rint(center_of_mass(np.array(nii_seg.data[:, is_c2c3, :]))[1]))
        nii_c2c3.data[pa_c2c3, is_c2c3, rl_c2c3] = 3
    else:
        logger.warning('C2-C3 not detected...')

    # remove temporary files
    tmp_folder.chdir_undo()
    if verbose < 2:
        logger.info("Remove temporary files...")
        tmp_folder.cleanup()
    else:
        logger.info("Temporary files saved to " + tmp_folder.get_path())

    nii_c2c3.change_orientation(orientation_init)
    return nii_c2c3
示例#11
0
def deep_segmentation_spinalcord(im_image, contrast_type, ctr_algo='cnn', ctr_file=None, brain_bool=True,
                                 kernel_size='2d', threshold_seg=None, remove_temp_files=1, verbose=1):
    """
    Main pipeline for CNN-based segmentation of the spinal cord.

    :param im_image:
    :param contrast_type: {'t1', 't2', t2s', 'dwi'}
    :param ctr_algo:
    :param ctr_file:
    :param brain_bool:
    :param kernel_size:
    :param threshold_seg: Binarization threshold (between 0 and 1) to apply to the segmentation prediction. Set to -1
        for no binarization (i.e. soft segmentation output)
    :param remove_temp_files:
    :param verbose:
    :return:
    """
    if threshold_seg is None:
        threshold_seg = THR_DEEPSEG[contrast_type]

    # Display stuff
    logger.info("Config deepseg_sc:")
    logger.info("  Centerline algorithm: {}".format(ctr_algo))
    logger.info("  Brain in image: {}".format(brain_bool))
    logger.info("  Kernel dimension: {}".format(kernel_size))
    logger.info("  Contrast: {}".format(contrast_type))
    logger.info("  Threshold: {}".format(threshold_seg))

    # create temporary folder with intermediate results
    tmp_folder = sct.TempFolder(verbose=verbose)
    tmp_folder_path = tmp_folder.get_path()
    if ctr_algo == 'file':  # 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()

    # re-orient image to RPI
    logger.info("Reorient the image to RPI, if necessary...")
    original_orientation = im_image.orientation
    # fname_orient = 'image_in_RPI.nii'
    im_image.change_orientation('RPI')

    # Resample image to 0.5mm in plane
    im_image_res = \
        resampling.resample_nib(im_image, new_size=[0.5, 0.5, im_image.dim[6]], new_size_type='mm', interpolation='linear')

    fname_orient = 'image_in_RPI_res.nii'
    im_image_res.save(fname_orient)

    # find the spinal cord centerline - execute OptiC binary
    logger.info("Finding the spinal cord centerline...")
    _, im_ctl, im_labels_viewer = find_centerline(algo=ctr_algo,
                                                    image_fname=fname_orient,
                                                    contrast_type=contrast_type,
                                                    brain_bool=brain_bool,
                                                    folder_output=tmp_folder_path,
                                                    remove_temp_files=remove_temp_files,
                                                    centerline_fname=file_ctr)

    if ctr_algo == 'file':
        im_ctl = \
            resampling.resample_nib(im_ctl, new_size=[0.5, 0.5, im_image.dim[6]], new_size_type='mm', interpolation='linear')

    # crop image around the spinal cord centerline
    logger.info("Cropping the image around the spinal cord...")
    crop_size = 96 if (kernel_size == '3d' and contrast_type == 't2s') else 64
    X_CROP_LST, Y_CROP_LST, Z_CROP_LST, im_crop_nii = crop_image_around_centerline(im_in=im_image_res,
                                                                                   ctr_in=im_ctl,
                                                                                   crop_size=crop_size)

    # normalize the intensity of the images
    logger.info("Normalizing the intensity...")
    im_norm_in = apply_intensity_normalization(im_in=im_crop_nii)
    del im_crop_nii

    if kernel_size == '2d':
        # segment data using 2D convolutions
        logger.info("Segmenting the spinal cord using deep learning on 2D patches...")
        segmentation_model_fname = \
            os.path.join(sct.__sct_dir__, 'data', 'deepseg_sc_models', '{}_sc.h5'.format(contrast_type))
        seg_crop = segment_2d(model_fname=segmentation_model_fname,
                              contrast_type=contrast_type,
                              input_size=(crop_size, crop_size),
                              im_in=im_norm_in)
    elif kernel_size == '3d':
        # segment data using 3D convolutions
        logger.info("Segmenting the spinal cord using deep learning on 3D patches...")
        segmentation_model_fname = \
            os.path.join(sct.__sct_dir__, 'data', 'deepseg_sc_models', '{}_sc_3D.h5'.format(contrast_type))
        seg_crop = segment_3d(model_fname=segmentation_model_fname,
                              contrast_type=contrast_type,
                              im_in=im_norm_in)

    # Postprocessing
    seg_crop_postproc = np.zeros_like(seg_crop)
    x_cOm, y_cOm = None, None
    for zz in range(im_norm_in.dim[2]):
        # Fill holes (only for binary segmentations)
        if threshold_seg >= 0:
            pred_seg_th = fill_holes_2d((seg_crop[:, :, zz] > threshold_seg).astype(int))
            pred_seg_pp = keep_largest_object(pred_seg_th, x_cOm, y_cOm)
            # Update center of mass for slice i+1
            if 1 in pred_seg_pp:
                x_cOm, y_cOm = center_of_mass(pred_seg_pp)
                x_cOm, y_cOm = np.round(x_cOm), np.round(y_cOm)
        else:
            # If soft segmentation, do nothing
            pred_seg_pp = seg_crop[:, :, zz]

        seg_crop_postproc[:, :, zz] = pred_seg_pp  # dtype is float32

    # reconstruct the segmentation from the crop data
    logger.info("Reassembling the image...")
    im_seg = uncrop_image(ref_in=im_image_res,
                          data_crop=seg_crop_postproc,
                          x_crop_lst=X_CROP_LST,
                          y_crop_lst=Y_CROP_LST,
                          z_crop_lst=Z_CROP_LST)
    # seg_uncrop_nii.save(sct.add_suffix(fname_res, '_seg'))  # for debugging
    del seg_crop, seg_crop_postproc, im_norm_in

    # resample to initial resolution
    logger.info("Resampling the segmentation to the native image resolution using linear interpolation...")
    im_seg_r = resampling.resample_nib(im_seg, image_dest=im_image, interpolation='linear')

    if ctr_algo == 'viewer':  # for debugging
        im_labels_viewer.save(sct.add_suffix(fname_orient, '_labels-viewer'))

    # Binarize the resampled image (except for soft segmentation, defined by threshold_seg=-1)
    if threshold_seg >= 0:
        logger.info("Binarizing the resampled segmentation...")
        im_seg_r.data = (im_seg_r.data > 0.5).astype(np.uint8)

    # post processing step to z_regularized
    im_seg_r_postproc = post_processing_volume_wise(im_seg_r)

    # Change data type. By default, dtype is float32
    if threshold_seg >= 0:
        im_seg_r_postproc.change_type(np.uint8)

    tmp_folder.chdir_undo()

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

    # reorient to initial orientation
    im_seg_r_postproc.change_orientation(original_orientation)

    # copy q/sform from input image to output segmentation
    im_seg.copy_qform_from_ref(im_image)

    return im_seg_r_postproc, im_image_res, im_seg.change_orientation('RPI')
示例#12
0
def deep_segmentation_spinalcord(im_image,
                                 contrast_type,
                                 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_in = im_image.absolutepath
    original_orientation = im_image.orientation
    fname_orient = 'image_in_RPI.nii'
    im_image.change_orientation('RPI').save(fname_orient)

    input_resolution = im_image.dim[4:7]

    # find the spinal cord centerline - execute OptiC binary
    sct.log.info("Finding the spinal cord centerline...")
    fname_res, centerline_filename = find_centerline(
        algo=ctr_algo,
        image_fname=fname_orient,
        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)

    im_nii, ctr_nii = Image(fname_res), Image(centerline_filename)

    # crop image around the spinal cord centerline
    sct.log.info("Cropping the image around the spinal cord...")
    crop_size = 96 if (kernel_size == '3d' and contrast_type == 't2s') else 64
    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(im_in=im_crop_nii)
    del im_crop_nii

    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))
        seg_crop_data = segment_2d(model_fname=segmentation_model_fname,
                                   contrast_type=contrast_type,
                                   input_size=(crop_size, crop_size),
                                   im_in=im_norm_in)
        del im_norm_in

    elif kernel_size == '3d':
        # resample to 0.5mm isotropic
        fname_norm = sct.add_suffix(fname_orient, '_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(
            "Segmenting the spinal cord using deep learning on 3D patches...")
        fname_seg_crop_res = sct.add_suffix(fname_res3d, '_seg')
        segmentation_model_fname = os.path.join(
            path_sct, 'data', 'deepseg_sc_models',
            '{}_sc_3D.h5'.format(contrast_type))
        seg_crop_nii = segment_3d(model_fname=segmentation_model_fname,
                                  contrast_type=contrast_type,
                                  im_in=Image(fname_res3d))
        seg_crop_nii.save(fname_seg_crop_res)
        del seg_crop_nii

        # resample to the initial pz resolution
        # TODO: does this need to be done (if already done below)?
        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_image(
            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...")
    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_res_seg = sct.add_suffix(fname_res, '_seg')
    seg_uncrop_nii.save(fname_res_seg)
    del 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_res_seg_downsamp = sct.add_suffix(fname_res_seg, '_downsamp')

    spinalcordtoolbox.resample.nipy_resample.resample_file(
        fname_res_seg,
        fname_res_seg_downsamp,
        initial_resolution,
        'mm',
        'linear',
        verbose=0)
    im_image_res_seg_downsamp = Image(fname_res_seg_downsamp)

    # 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
    # TODO: optimize speed --> np.where is slow
    im_image_res_seg_downsamp.data[np.where(
        im_image_res_seg_downsamp.data >= thr)] = 1
    im_image_res_seg_downsamp.data[np.where(
        im_image_res_seg_downsamp.data < thr)] = 0

    # post processing step to z_regularized
    im_image_res_seg_downsamp_postproc = post_processing_volume_wise(
        im_in=im_image_res_seg_downsamp)

    tmp_folder.chdir_undo()

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

    # reorient to initial orientation
    return im_image_res_seg_downsamp_postproc.change_orientation(
        original_orientation), im_nii, seg_uncrop_nii.change_orientation(
            'RPI').save('image_in_RPI_resampled_seg.nii.gz')
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)
示例#14
0
def deep_segmentation_spinalcord(fname_image,
                                 contrast_type,
                                 output_folder,
                                 ctr_algo='cnn',
                                 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)
    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 = set_orientation(im_2orient, 'RPI')
        im_orient.setFileName(fname_orient)
        im_orient.save()
    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...")
    if ctr_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=fname_res,
            contrast_type=contrast_type,
            optic_models_path=optic_models_fname,
            folder_output=tmp_folder_path,
            remove_temp_files=remove_temp_files,
            output_roi=False,
            verbose=0)
    elif ctr_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)

        # compute the heatmap
        fname_heatmap = sct.add_suffix(fname_res, "_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)

    # 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 = 64 if kernel_size == '2d' else 96
    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 = set_orientation(Image(fname_seg_RPI),
                                        original_orientation)
        im_seg_orient.setFileName(fname_seg)
        im_seg_orient.save()
    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)
def detect_c2c3(nii_im, nii_seg, contrast, nb_sag_avg=7.0, verbose=1):
    """
    Detect the posterior edge of C2-C3 disc.
    :param nii_im:
    :param nii_seg:
    :param contrast:
    :param verbose:
    :return:
    """
    # path to the pmj detector
    path_sct = os.environ.get("SCT_DIR",
                              os.path.dirname(os.path.dirname(__file__)))
    path_model = os.path.join(path_sct, 'data', 'c2c3_disc_models',
                              '{}_model'.format(contrast))

    orientation_init = nii_im.orientation
    z_seg_max = np.max(np.where(nii_seg.change_orientation('PIR').data)[1])

    # Flatten sagittal
    nii_im = flatten_sagittal(nii_im,
                              nii_seg,
                              centerline_fitting='hanning',
                              verbose=verbose)
    nii_seg_flat = flatten_sagittal(nii_seg,
                                    nii_seg,
                                    centerline_fitting='hanning',
                                    verbose=verbose)

    # create temporary folder with intermediate results
    sct.log.info("Creating temporary folder...")
    tmp_folder = sct.TempFolder()
    # print tmp_folder.path_tmp
    tmp_folder.chdir()

    # Extract mid-slice
    nii_im.change_orientation('PIR')
    nii_seg_flat.change_orientation('PIR')
    mid_RL = int(np.rint(nii_im.dim[2] * 1.0 / 2))
    nb_sag_avg_half = int(nb_sag_avg / 2 / nii_im.dim[6])
    midSlice = np.mean(nii_im.data[:, :, mid_RL - nb_sag_avg_half:mid_RL +
                                   nb_sag_avg_half + 1], 2)  # average 7 slices
    midSlice_seg = nii_seg_flat.data[:, :, mid_RL]
    nii_midSlice = msct_image.zeros_like(nii_im)
    nii_midSlice.data = midSlice
    nii_midSlice.save('data_midSlice.nii')

    # Run detection
    sct.printv('Run C2-C3 detector...', verbose)
    os.environ["FSLOUTPUTTYPE"] = "NIFTI_PAIR"
    cmd_detection = 'isct_spine_detect -ctype=dpdt "%s" "%s" "%s"' % \
                    (path_model, 'data_midSlice', 'data_midSlice_pred')
    sct.run(cmd_detection, verbose=0, raise_exception=False)

    pred = nib.load('data_midSlice_pred_svm.hdr').get_data()

    # Create mask along centerline
    midSlice_mask = np.zeros(midSlice_seg.shape)
    mask_halfSize = int(np.rint(25.0 / nii_midSlice.dim[4]))
    for z in range(midSlice_mask.shape[1]):
        row = midSlice_seg[:, z]
        if np.any(row):
            med_y = int(np.rint(np.median(np.where(row))))
            midSlice_mask[med_y - mask_halfSize:med_y + mask_halfSize] = 1

    # mask prediction
    pred[midSlice_mask == 0] = 0
    # dist_medulla = 30.0 if contrast == 't1' else 40.0  # Observation: segmentation ends higher on t2 images than t1
    # z_seg_max -= int(np.rint(dist_medulla / nii_midSlice.dim[5])) # TODO: take into account the curvature
    pred[:, z_seg_max:] = 0  # Mask above SC segmentation

    # assign label to voxel
    nii_c2c3 = zeros_like(nii_seg_flat)
    if np.any(pred > 0):
        sct.printv('C2-C3 detected...', verbose)

        pred_bin = (pred > 0).astype(np.int_)
        # labeled_pred, nb_regions = label_regions(pred_bin, return_num=True)
        # if nb_regions > 1:  # if there are several clusters of voxels detected
        #     region_idx_top, region_z_top = 0, 0
        #     for region_idx in range(1, nb_regions+1):
        #         pred_idx = (labeled_pred == region_idx).astype(np.int_)
        #         pa_com, is_com = center_of_mass(pred_idx)
        #         if is_com >= region_z_top:
        #             region_idx_top = region_idx
        #             region_z_top = is_com
        #     pred[labeled_pred != region_idx_top] = 0  # then keep the one located at the top (IS direction)

        coord_max = np.where(pred == np.max(pred))
        pa_c2c3, is_c2c3 = coord_max[0][0], coord_max[1][0]
        nii_seg.change_orientation('PIR')
        rl_c2c3 = int(np.rint(center_of_mass(nii_seg.data[:, is_c2c3, :])[1]))
        nii_c2c3.data[pa_c2c3, is_c2c3, rl_c2c3] = 3
    else:
        sct.printv('C2-C3 not detected...', verbose)

    # remove temporary files
    tmp_folder.chdir_undo()
    sct.log.info("Remove temporary files...")
    tmp_folder.cleanup()

    nii_c2c3.change_orientation(orientation_init)
    return nii_c2c3
示例#16
0
def deep_segmentation_spinalcord(im_image,
                                 contrast_type,
                                 ctr_algo='cnn',
                                 ctr_file=None,
                                 brain_bool=True,
                                 kernel_size='2d',
                                 remove_temp_files=1,
                                 verbose=1):
    """Pipeline"""
    # create temporary folder with intermediate results
    tmp_folder = sct.TempFolder(verbose=verbose)
    tmp_folder_path = tmp_folder.get_path()
    if ctr_algo == 'file':  # 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()

    # re-orient image to RPI
    logger.info("Reorient the image to RPI, if necessary...")
    original_orientation = im_image.orientation
    fname_orient = 'image_in_RPI.nii'
    im_image.change_orientation('RPI').save(fname_orient)

    input_resolution = im_image.dim[4:7]

    # find the spinal cord centerline - execute OptiC binary
    logger.info("Finding the spinal cord centerline...")
    fname_res, centerline_filename = find_centerline(
        algo=ctr_algo,
        image_fname=fname_orient,
        contrast_type=contrast_type,
        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
    logger.info("Cropping the image around the spinal cord...")
    crop_size = 96 if (kernel_size == '3d' and contrast_type == 't2s') else 64
    X_CROP_LST, Y_CROP_LST, Z_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
    logger.info("Normalizing the intensity...")
    im_norm_in = apply_intensity_normalization(im_in=im_crop_nii)
    del im_crop_nii

    if kernel_size == '2d':
        # segment data using 2D convolutions
        logger.info(
            "Segmenting the spinal cord using deep learning on 2D patches...")
        segmentation_model_fname = \
            os.path.join(sct.__sct_dir__, 'data', 'deepseg_sc_models', '{}_sc.h5'.format(contrast_type))
        seg_crop_data = segment_2d(model_fname=segmentation_model_fname,
                                   contrast_type=contrast_type,
                                   input_size=(crop_size, crop_size),
                                   im_in=im_norm_in)
    elif kernel_size == '3d':
        # segment data using 3D convolutions
        logger.info(
            "Segmenting the spinal cord using deep learning on 3D patches...")
        segmentation_model_fname = \
            os.path.join(sct.__sct_dir__, 'data', 'deepseg_sc_models', '{}_sc_3D.h5'.format(contrast_type))
        seg_crop_data = segment_3d(model_fname=segmentation_model_fname,
                                   contrast_type=contrast_type,
                                   im_in=im_norm_in)
    del im_norm_in

    # reconstruct the segmentation from the crop data
    logger.info("Reassembling 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,
                                  z_crop_lst=Z_CROP_LST)
    fname_res_seg = sct.add_suffix(fname_res, '_seg')
    seg_uncrop_nii.save(fname_res_seg)
    del seg_crop_data

    # resample to initial resolution
    logger.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_res_seg_downsamp = sct.add_suffix(fname_res_seg, '_downsamp')

    resampling.resample_file(fname_res_seg,
                             fname_res_seg_downsamp,
                             initial_resolution,
                             'mm',
                             'linear',
                             verbose=0)
    im_image_res_seg_downsamp = Image(fname_res_seg_downsamp)

    if ctr_algo == 'viewer':  # resample and reorient the viewer labels
        fname_res_labels = sct.add_suffix(fname_orient, '_labels-centerline')
        resampling.resample_file(fname_res_labels,
                                 fname_res_labels,
                                 initial_resolution,
                                 'mm',
                                 'linear',
                                 verbose=0)
        im_image_res_labels_downsamp = Image(
            fname_res_labels).change_orientation(original_orientation)
    else:
        im_image_res_labels_downsamp = None

    if verbose == 2:
        fname_res_ctr = sct.add_suffix(fname_orient, '_ctr')
        resampling.resample_file(fname_res_ctr,
                                 fname_res_ctr,
                                 initial_resolution,
                                 'mm',
                                 'linear',
                                 verbose=0)
        im_image_res_ctr_downsamp = Image(fname_res_ctr).change_orientation(
            original_orientation)
    else:
        im_image_res_ctr_downsamp = None

    # binarize the resampled image to remove interpolation effects
    logger.info(
        "Binarizing the segmentation to avoid interpolation effects...")
    thr = 0.0001 if contrast_type in ['t1', 'dwi'] else 0.5
    # TODO: optimize speed --> np.where is slow
    im_image_res_seg_downsamp.data[np.where(
        im_image_res_seg_downsamp.data >= thr)] = 1
    im_image_res_seg_downsamp.data[np.where(
        im_image_res_seg_downsamp.data < thr)] = 0

    # post processing step to z_regularized
    im_image_res_seg_downsamp_postproc = post_processing_volume_wise(
        im_in=im_image_res_seg_downsamp)

    tmp_folder.chdir_undo()

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

    # reorient to initial orientation
    return im_image_res_seg_downsamp_postproc.change_orientation(original_orientation), \
           im_nii, \
           seg_uncrop_nii.change_orientation('RPI'), \
           im_image_res_labels_downsamp, \
           im_image_res_ctr_downsamp
示例#17
0
def deep_segmentation_spinalcord(im_image, contrast_type, ctr_algo='cnn', ctr_file=None, brain_bool=True,
                                 kernel_size='2d', remove_temp_files=1, verbose=1):
    """Pipeline"""
    # create temporary folder with intermediate results
    tmp_folder = sct.TempFolder(verbose=verbose)
    tmp_folder_path = tmp_folder.get_path()
    if ctr_algo == 'file':  # 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()

    # re-orient image to RPI
    logger.info("Reorient the image to RPI, if necessary...")
    original_orientation = im_image.orientation
    fname_orient = 'image_in_RPI.nii'
    im_image.change_orientation('RPI').save(fname_orient)

    input_resolution = im_image.dim[4:7]

    # find the spinal cord centerline - execute OptiC binary
    logger.info("Finding the spinal cord centerline...")
    fname_res, centerline_filename, im_labels_viewer = find_centerline(algo=ctr_algo,
                                                                        image_fname=fname_orient,
                                                                        contrast_type=contrast_type,
                                                                        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
    logger.info("Cropping the image around the spinal cord...")
    crop_size = 96 if (kernel_size == '3d' and contrast_type == 't2s') else 64
    X_CROP_LST, Y_CROP_LST, Z_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
    logger.info("Normalizing the intensity...")
    im_norm_in = apply_intensity_normalization(im_in=im_crop_nii)
    del im_crop_nii

    if kernel_size == '2d':
        # segment data using 2D convolutions
        logger.info("Segmenting the spinal cord using deep learning on 2D patches...")
        segmentation_model_fname = \
            os.path.join(sct.__sct_dir__, 'data', 'deepseg_sc_models', '{}_sc.h5'.format(contrast_type))
        seg_crop = segment_2d(model_fname=segmentation_model_fname,
                                 contrast_type=contrast_type,
                                 input_size=(crop_size, crop_size),
                                 im_in=im_norm_in)
    elif kernel_size == '3d':
        # segment data using 3D convolutions
        logger.info("Segmenting the spinal cord using deep learning on 3D patches...")
        segmentation_model_fname = \
            os.path.join(sct.__sct_dir__, 'data', 'deepseg_sc_models', '{}_sc_3D.h5'.format(contrast_type))
        seg_crop = segment_3d(model_fname=segmentation_model_fname,
                                 contrast_type=contrast_type,
                                 im_in=im_norm_in)
    del im_norm_in

    # reconstruct the segmentation from the crop data
    logger.info("Reassembling the image...")
    im_seg = uncrop_image(ref_in=im_nii,
                          data_crop=seg_crop,
                          x_crop_lst=X_CROP_LST,
                          y_crop_lst=Y_CROP_LST,
                          z_crop_lst=Z_CROP_LST)
    # fname_res_seg = sct.add_suffix(fname_res, '_seg')
    # seg_uncrop_nii.save(fname_res_seg)  # for debugging
    del seg_crop

    # resample to initial resolution
    logger.info("Resampling the segmentation to the native image resolution using linear interpolation...")
    # create nibabel object
    seg_uncrop_nii_nib = nib.nifti1.Nifti1Image(im_seg.data, im_seg.hdr.get_best_affine())
    seg_uncrop_nii_nibr = resampling.resample_nib(seg_uncrop_nii_nib, new_size=input_resolution, new_size_type='mm',
                                                  interpolation='linear')
    # Convert back to Image type
    im_seg_r = Image(seg_uncrop_nii_nibr.get_data(), hdr=seg_uncrop_nii_nibr.header, orientation='RPI',
                     dim=seg_uncrop_nii_nibr.header.get_data_shape())

    if ctr_algo == 'viewer':  # resample and reorient the viewer labels
        im_labels_viewer_nib = nib.nifti1.Nifti1Image(im_labels_viewer.data, im_labels_viewer.hdr.get_best_affine())
        im_viewer_r_nib = resampling.resample_nib(im_labels_viewer_nib, new_size=input_resolution, new_size_type='mm',
                                                    interpolation='linear')
        im_viewer = Image(im_viewer_r_nib.get_data(), hdr=im_viewer_r_nib.header, orientation='RPI',
                            dim=im_viewer_r_nib.header.get_data_shape()).change_orientation(original_orientation)
    else:
        im_viewer = None

    # TODO: Deal with that later-- ideally this file should be written when debugging, not with verbose=2
    # if verbose == 2:
    #     fname_res_ctr = sct.add_suffix(fname_orient, '_ctr')
    #     resampling.resample_file(fname_res_ctr, fname_res_ctr, initial_resolution, 'mm', 'linear', verbose=0)
    #     im_image_res_ctr_downsamp = Image(fname_res_ctr).change_orientation(original_orientation)
    # else:
    im_image_res_ctr_downsamp = None

    # Binarize the resampled image to remove interpolation effects
    logger.info("Binarizing the resampled segmentation...")
    thr = 0.0001 if contrast_type in ['t1', 'dwi'] else 0.5
    # TODO: optimize speed --> np.where is slow
    im_seg_r.data[np.where(im_seg_r.data >= thr)] = 1
    im_seg_r.data[np.where(im_seg_r.data < thr)] = 0

    # post processing step to z_regularized
    im_seg_r_postproc = post_processing_volume_wise(im_seg_r)

    # change data type
    im_seg_r_postproc.change_type(np.uint8)

    tmp_folder.chdir_undo()

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

    # reorient to initial orientation
    return im_seg_r_postproc.change_orientation(original_orientation), \
           im_nii, \
           im_seg.change_orientation('RPI'), \
           im_viewer, \
           im_image_res_ctr_downsamp
示例#18
0
def detect_centerline(image_fname,
                      contrast_type,
                      optic_models_path,
                      folder_output,
                      remove_temp_files=False,
                      init_option=None,
                      output_roi=False,
                      verbose=0):
    """This method will use the OptiC to detect the centerline.

    :param image_fname: The input image filename.
    :param init_option: Axial slice where the propagation starts.
    :param contrast_type: The contrast type.
    :param optic_models_path: The path with the Optic model files.
    :param folder_output: The OptiC output folder.
    :param remove_temp_files: Remove the temporary created files.
    :param verbose: Adjusts the verbosity of the logging.

    :returns: The OptiC output filename.
    """

    image_input = Image(image_fname)
    path_data, file_data, ext_data = sct.extract_fname(image_fname)

    sct.printv('Detecting the spinal cord using OptiC', verbose=verbose)
    image_input_orientation = image_input.orientation

    temp_folder = sct.TempFolder()
    temp_folder.copy_from(image_fname)
    curdir = os.getcwd()
    temp_folder.chdir()

    # convert image data type to int16, as required by opencv (backend in OptiC)
    image_int_filename = sct.add_suffix(file_data + ext_data, "_int16")
    img = Image(image_fname)
    img_int16 = img.copy()

    # rescale intensity
    min_out = np.iinfo('uint16').min
    max_out = np.iinfo('uint16').max
    min_in = np.nanmin(img.data)
    max_in = np.nanmax(img.data)
    data_rescaled = img.data.astype('float') * (max_out - min_out) / (max_in -
                                                                      min_in)
    img_int16.data = data_rescaled - (data_rescaled.min() - min_out)

    # change data type
    img_int16.save(image_int_filename, dtype=np.uint16)
    del img, img_int16

    # reorient the input image to RPI + convert to .nii
    reoriented_image_filename = sct.add_suffix(image_int_filename, "_RPI")
    img_filename = ''.join(sct.extract_fname(reoriented_image_filename)[:2])
    reoriented_image_filename_nii = img_filename + '.nii'
    cmd_reorient = 'sct_image -i "%s" -o "%s" -setorient RPI -v 0' % \
                (image_int_filename, reoriented_image_filename_nii)
    sct.run(cmd_reorient, verbose=0)

    image_rpi_init = Image(reoriented_image_filename_nii)
    nxr, nyr, nzr, ntr, pxr, pyr, pzr, ptr = image_rpi_init.dim
    if init_option is not None:
        if init_option > 1:
            init_option /= (nzr - 1)

    # call the OptiC method to generate the spinal cord centerline
    optic_input = img_filename
    optic_filename = img_filename + '_optic'

    os.environ["FSLOUTPUTTYPE"] = "NIFTI_PAIR"
    cmd_optic = 'isct_spine_detect -ctype=dpdt -lambda=1 "%s" "%s" "%s"' % \
                (optic_models_path, optic_input, optic_filename)
    sct.run(cmd_optic, verbose=0)

    # convert .img and .hdr files to .nii.gz
    optic_hdr_filename = img_filename + '_optic_ctr.hdr'
    centerline_optic_RPI_filename = sct.add_suffix(file_data + ext_data,
                                                   "_centerline_optic_RPI")
    img = nib.load(optic_hdr_filename)
    nib.save(img, centerline_optic_RPI_filename)

    # reorient the output image to initial orientation
    centerline_optic_filename = sct.add_suffix(file_data + ext_data,
                                               "_centerline_optic")
    cmd_reorient = 'sct_image -i "%s" -o "%s" -setorient "%s" -v 0' % \
                   (centerline_optic_RPI_filename,
                    centerline_optic_filename,
                    image_input_orientation)
    sct.run(cmd_reorient, verbose=0)

    # copy centerline to parent folder
    folder_output_from_temp = folder_output
    if not os.path.isabs(folder_output):
        folder_output_from_temp = os.path.join(curdir, folder_output)

    sct.printv('Copy output to ' + folder_output, verbose=0)
    sct.copy(centerline_optic_filename, folder_output_from_temp)

    if output_roi:
        fname_roi_centerline = centerline2roi(
            fname_image=centerline_optic_RPI_filename,
            folder_output=folder_output_from_temp,
            verbose=verbose)

        # Note: the .roi file is defined in RPI orientation. To be used, it must be applied on the original image with
        # a RPI orientation. For this reason, this script also outputs the input image in RPI orientation
        sct.copy(reoriented_image_filename_nii, folder_output_from_temp)

    # return to initial folder
    temp_folder.chdir_undo()

    # delete temporary folder
    if remove_temp_files:
        temp_folder.cleanup()

    return init_option, os.path.join(folder_output, centerline_optic_filename)
示例#19
0
def deep_segmentation_MSlesion(im_image,
                               contrast_type,
                               ctr_algo='svm',
                               ctr_file=None,
                               brain_bool=True,
                               remove_temp_files=1):
    """
    Segment lesions from MRI data.
    :param im_image: Image() object containing the lesions to segment
    :param contrast_type: Constrast of the image. Need to use one supported by the CNN models.
    :param ctr_algo: Algo to find the centerline. See sct_get_centerline
    :param ctr_file: Centerline or segmentation (optional)
    :param brain_bool: If brain if present or not in the image.
    :param remove_temp_files:
    :return:
    """

    # create temporary folder with intermediate results
    sct.log.info("\nCreating temporary folder...")
    tmp_folder = sct.TempFolder()
    tmp_folder_path = tmp_folder.get_path()
    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_in = im_image.absolutepath
    original_orientation = im_image.orientation
    fname_orient = 'image_in_RPI.nii'
    im_image.change_orientation('RPI').save(fname_orient)

    input_resolution = im_image.dim[4:7]

    # 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,
        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...")
    crop_size = 48
    X_CROP_LST, Y_CROP_LST, Z_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')
    resampling.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(
        sct.__sct_dir__, 'data', 'deepseg_lesion_models',
        '{}_lesion.h5'.format(contrast_type))
    fname_seg_crop_res = sct.add_suffix(fname_res3d, '_lesionseg')
    im_res3d = Image(fname_res3d)
    seg_im = segment_3d(model_fname=segmentation_model_fname,
                        contrast_type=contrast_type,
                        im=im_res3d.copy())
    seg_im.save(fname_seg_crop_res)
    del im_res3d, seg_im

    # 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])])
    resampling.resample_file(fname_seg_crop_res,
                             fname_seg_res2d,
                             initial_2d_resolution,
                             'mm',
                             'linear',
                             verbose=0)
    seg_crop = Image(fname_seg_res2d)

    # 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.copy().data,
                                  x_crop_lst=X_CROP_LST,
                                  y_crop_lst=Y_CROP_LST,
                                  z_crop_lst=Z_CROP_LST)
    fname_seg_res_RPI = sct.add_suffix(fname_in, '_res_RPI_seg')
    seg_uncrop_nii.save(fname_seg_res_RPI)
    del seg_crop

    # 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(fname_in, '_RPI_seg')
    resampling.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...")
    tmp_folder.chdir_undo()

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

    # reorient to initial orientation
    return seg_initres_nii.change_orientation(original_orientation)
示例#20
0
def detect_c2c3(nii_im, nii_seg, contrast, nb_sag_avg=7.0, verbose=1):
    """
    Detect the posterior edge of C2-C3 disc.
    :param nii_im:
    :param nii_seg:
    :param contrast:
    :param verbose:
    :return:
    """
    # path to the pmj detector
    path_model = os.path.join(sct.__data_dir__, 'c2c3_disc_models',
                              '{}_model'.format(contrast))

    orientation_init = nii_im.orientation
    z_seg_max = np.max(np.where(nii_seg.change_orientation('PIR').data)[1])

    # Flatten sagittal
    nii_im = flatten_sagittal(nii_im, nii_seg, verbose=verbose)
    nii_seg_flat = flatten_sagittal(nii_seg, nii_seg, verbose=verbose)

    # create temporary folder with intermediate results
    sct.log.info("Creating temporary folder...")
    tmp_folder = sct.TempFolder()
    tmp_folder.chdir()

    # Extract mid-slice
    nii_im.change_orientation('PIR')
    nii_seg_flat.change_orientation('PIR')
    mid_RL = int(np.rint(nii_im.dim[2] * 1.0 / 2))
    nb_sag_avg_half = int(nb_sag_avg / 2 / nii_im.dim[6])
    midSlice = np.mean(nii_im.data[:, :, mid_RL - nb_sag_avg_half:mid_RL +
                                   nb_sag_avg_half + 1], 2)  # average 7 slices
    midSlice_seg = nii_seg_flat.data[:, :, mid_RL]
    nii_midSlice = msct_image.zeros_like(nii_im)
    nii_midSlice.data = midSlice
    nii_midSlice.save('data_midSlice.nii')

    # Run detection
    sct.printv('Run C2-C3 detector...', verbose)
    os.environ["FSLOUTPUTTYPE"] = "NIFTI_PAIR"
    cmd_detection = 'isct_spine_detect -ctype=dpdt "%s" "%s" "%s"' % \
                    (path_model, 'data_midSlice', 'data_midSlice_pred')
    sct.run(cmd_detection, verbose=0, raise_exception=False)

    pred = nib.load('data_midSlice_pred_svm.hdr').get_data()
    if verbose >= 2:
        # copy the "prediction data before post-processing" in an Image object
        nii_pred_before_postPro = nii_midSlice.copy()
        nii_pred_before_postPro.data = pred  # 2D data with orientation, mid sag slice of the original data
        nii_pred_before_postPro.save(
            "pred_midSlice_before_postPro.nii.gz")  # save it)

    # Create mask along centerline
    midSlice_mask = np.zeros(midSlice_seg.shape)
    mask_halfSize = int(np.rint(25.0 / nii_midSlice.dim[4]))
    for z in range(midSlice_mask.shape[1]):
        row = midSlice_seg[:,
                           z]  # 2D data with PI orientation, mid sag slice of the original data
        if np.any(row > 0):
            med_y = int(np.rint(np.median(np.where(row > 0))))
            midSlice_mask[
                med_y - mask_halfSize:med_y + mask_halfSize,
                z] = 1  # 2D data with PI orientation, mid sag slice of the original data
    if verbose >= 2:
        # copy the created mask in an Image object
        nii_postPro_mask = nii_midSlice.copy()
        nii_postPro_mask.data = midSlice_mask  # 2D data with PI orientation, mid sag slice of the original data
        nii_postPro_mask.save("mask_midSlice.nii.gz")  # save it

    # mask prediction
    pred[midSlice_mask == 0] = 0
    pred[:, z_seg_max:] = 0  # Mask above SC segmentation
    if verbose >= 2:
        # copy the "prediction data after post-processing" in an Image object
        nii_pred_after_postPro = nii_midSlice.copy()
        nii_pred_after_postPro.data = pred
        nii_pred_after_postPro.save(
            "pred_midSlice_after_postPro.nii.gz")  # save it

    # assign label to voxel
    nii_c2c3 = zeros_like(nii_seg_flat)  # 3D data with PIR orientaion
    if np.any(pred > 0):
        sct.printv('C2-C3 detected...', verbose)

        pred_bin = (pred > 0).astype(np.int_)
        coord_max = np.where(pred == np.max(pred))
        pa_c2c3, is_c2c3 = coord_max[0][0], coord_max[1][0]
        nii_seg.change_orientation('PIR')
        rl_c2c3 = int(
            np.rint(center_of_mass(np.array(nii_seg.data[:, is_c2c3, :]))[1]))
        nii_c2c3.data[pa_c2c3, is_c2c3, rl_c2c3] = 3
    else:
        sct.printv('C2-C3 not detected...', verbose)

    # remove temporary files
    tmp_folder.chdir_undo()
    if verbose < 2:
        sct.log.info("Remove temporary files...")
        tmp_folder.cleanup()

    nii_c2c3.change_orientation(orientation_init)
    return nii_c2c3
示例#21
0
def deep_segmentation_spinalcord(im_image,
                                 contrast_type,
                                 ctr_algo='cnn',
                                 ctr_file=None,
                                 brain_bool=True,
                                 kernel_size='2d',
                                 remove_temp_files=1,
                                 verbose=1):
    """Pipeline"""
    # create temporary folder with intermediate results
    tmp_folder = sct.TempFolder(verbose=verbose)
    tmp_folder_path = tmp_folder.get_path()
    if ctr_algo == 'file':  # 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()

    # re-orient image to RPI
    logger.info("Reorient the image to RPI, if necessary...")
    original_orientation = im_image.orientation
    # fname_orient = 'image_in_RPI.nii'
    im_image.change_orientation('RPI')

    # Resample image to 0.5mm in plane
    im_image_res = \
        resampling.resample_nib(im_image, new_size=[0.5, 0.5, im_image.dim[6]], new_size_type='mm', interpolation='linear')

    fname_orient = 'image_in_RPI_res.nii'
    im_image_res.save(fname_orient)

    # find the spinal cord centerline - execute OptiC binary
    logger.info("Finding the spinal cord centerline...")
    _, im_ctl, im_labels_viewer = find_centerline(
        algo=ctr_algo,
        image_fname=fname_orient,
        contrast_type=contrast_type,
        brain_bool=brain_bool,
        folder_output=tmp_folder_path,
        remove_temp_files=remove_temp_files,
        centerline_fname=file_ctr)

    if ctr_algo == 'file':
        im_ctl = \
            resampling.resample_nib(im_ctl, new_size=[0.5, 0.5, im_image.dim[6]], new_size_type='mm', interpolation='linear')

    # crop image around the spinal cord centerline
    logger.info("Cropping the image around the spinal cord...")
    crop_size = 96 if (kernel_size == '3d' and contrast_type == 't2s') else 64
    X_CROP_LST, Y_CROP_LST, Z_CROP_LST, im_crop_nii = crop_image_around_centerline(
        im_in=im_image_res, ctr_in=im_ctl, crop_size=crop_size)

    # normalize the intensity of the images
    logger.info("Normalizing the intensity...")
    im_norm_in = apply_intensity_normalization(im_in=im_crop_nii)
    del im_crop_nii

    if kernel_size == '2d':
        # segment data using 2D convolutions
        logger.info(
            "Segmenting the spinal cord using deep learning on 2D patches...")
        segmentation_model_fname = \
            os.path.join(sct.__sct_dir__, 'data', 'deepseg_sc_models', '{}_sc.h5'.format(contrast_type))
        seg_crop = segment_2d(model_fname=segmentation_model_fname,
                              contrast_type=contrast_type,
                              input_size=(crop_size, crop_size),
                              im_in=im_norm_in)
    elif kernel_size == '3d':
        # segment data using 3D convolutions
        logger.info(
            "Segmenting the spinal cord using deep learning on 3D patches...")
        segmentation_model_fname = \
            os.path.join(sct.__sct_dir__, 'data', 'deepseg_sc_models', '{}_sc_3D.h5'.format(contrast_type))
        seg_crop = segment_3d(model_fname=segmentation_model_fname,
                              contrast_type=contrast_type,
                              im_in=im_norm_in)
    del im_norm_in

    # reconstruct the segmentation from the crop data
    logger.info("Reassembling the image...")
    im_seg = uncrop_image(ref_in=im_image_res,
                          data_crop=seg_crop,
                          x_crop_lst=X_CROP_LST,
                          y_crop_lst=Y_CROP_LST,
                          z_crop_lst=Z_CROP_LST)
    # seg_uncrop_nii.save(sct.add_suffix(fname_res, '_seg'))  # for debugging
    del seg_crop

    # Change type uint8 --> float32 otherwise resampling will produce binary output (even with linear interpolation)
    im_seg.change_type(np.float32)
    # resample to initial resolution
    logger.info(
        "Resampling the segmentation to the native image resolution using linear interpolation..."
    )
    im_seg_r = resampling.resample_nib(im_seg,
                                       image_dest=im_image,
                                       interpolation='linear')

    if ctr_algo == 'viewer':  # for debugging
        im_labels_viewer.save(sct.add_suffix(fname_orient, '_labels-viewer'))

    # Binarize the resampled image to remove interpolation effects
    logger.info("Binarizing the resampled segmentation...")
    # thr = 0.0001 if contrast_type in ['t1', 'dwi'] else 0.5
    thr = 0.5
    # TODO: optimize speed --> np.where is slow
    im_seg_r.data[np.where(im_seg_r.data > thr)] = 1
    im_seg_r.data[np.where(im_seg_r.data <= thr)] = 0

    # post processing step to z_regularized
    im_seg_r_postproc = post_processing_volume_wise(im_seg_r)

    # change data type
    im_seg_r_postproc.change_type(np.uint8)

    tmp_folder.chdir_undo()

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

    # reorient to initial orientation
    return im_seg_r_postproc.change_orientation(original_orientation), \
           im_image_res, \
           im_seg.change_orientation('RPI')