Beispiel #1
0
def test_label_vertebrae(t2_image, t2_seg_image, tmp_path):
    param = qc.Params(t2_image.absolutepath, 'sct_label_vertebrae', ['-a', '-b'], 'Sagittal', str(tmp_path))
    report = qc.QcReport(param, 'Test label vertebrae')

    @qc.QcImage(report, 'spline36', [qc.QcImage.label_vertebrae, ], process=param.command)
    def test(qslice):
        return qslice.single()

    test(qcslice.Sagittal([t2_image, t2_seg_image]))
    assert os.path.isfile(param.abs_bkg_img_path())
    assert os.path.isfile(param.abs_overlay_img_path())
def test_register_to_template(t2_image, t2_seg_image):
    param = qc.Params(t2_image, 'sct_register_to_template', ['-w', 'aaa'],
                      'SagittalTemplate2Anat', '/tmp')
    report = qc.QcReport(param, 'bla bla')

    @qc.QcImage(report, 'bicubic', [qc.QcImage.no_seg_seg])
    def test(qslice):
        return qslice.single()

    test(qcslice.SagittalTemplate2Anat(t2_image, t2_seg_image, t2_seg_image))
    assert os.path.isfile(param.abs_bkg_img_path())
    assert os.path.isfile(param.abs_overlay_img_path())
Beispiel #3
0
def test_propseg(t2_image, t2_seg_image, tmp_path):
    param = qc.Params(t2_image.absolutepath, 'sct_propseg', ['-a'], 'Axial', str(tmp_path))
    report = qc.QcReport(param, 'Test usage')

    @qc.QcImage(report, 'none', [qc.QcImage.listed_seg, ], process=param.command)
    def test(qslice):
        return qslice.mosaic()

    test(qcslice.Axial([t2_image, t2_seg_image]))
    assert os.path.isfile(param.abs_bkg_img_path())
    assert os.path.isfile(param.abs_overlay_img_path())
    assert os.path.isfile(param.qc_results)
def test_label_vertebrae(t2_image, t2_seg_image):
    param = qc.Params(t2_image, 'sct_label_vertebrae', ['-a', '-b'],
                      'Sagittal', '/tmp')
    report = qc.QcReport(param, 'Test label vertebrae')

    @qc.QcImage(report, 'spline36', [
        qc.QcImage.label_vertebrae,
    ])
    def test(qslice):
        return qslice.single()

    test(qcslice.Sagittal(t2_image, t2_seg_image))
    assert os.path.isfile(param.abs_bkg_img_path())
    assert os.path.isfile(param.abs_overlay_img_path())
def test_propseg(t2_image, t2_seg_image):
    param = qc.Params(t2_image, 'sct_propseg', ['-a'], 'Axial', '/tmp')
    report = qc.QcReport(param, 'Test usage')

    @qc.QcImage(report, 'none', [
        qc.QcImage.listed_seg,
    ])
    def test(qslice):
        return qslice.mosaic()

    test(qcslice.Axial(t2_image, t2_seg_image))
    assert os.path.isfile(param.abs_bkg_img_path())
    assert os.path.isfile(param.abs_overlay_img_path())
    assert os.path.isfile(param.qc_results)
def main():
    parser = get_parser()
    param = Param()

    args = sys.argv[1:]

    arguments = parser.parse(args)

    # get arguments
    fname_data = arguments['-i']
    fname_seg = arguments['-s']
    fname_landmarks = arguments['-l']
    if '-ofolder' in arguments:
        path_output = arguments['-ofolder']
    else:
        path_output = ''
    path_template = sct.slash_at_the_end(arguments['-t'], 1)
    contrast_template = arguments['-c']
    ref = arguments['-ref']
    remove_temp_files = int(arguments['-r'])
    verbose = int(arguments['-v'])
    param.verbose = verbose  # TODO: not clean, unify verbose or param.verbose in code, but not both
    if '-param-straighten' in arguments:
        param.param_straighten = arguments['-param-straighten']
    # if '-cpu-nb' in arguments:
    #     arg_cpu = ' -cpu-nb '+str(arguments['-cpu-nb'])
    # else:
    #     arg_cpu = ''
    # registration parameters
    if '-param' in arguments:
        # reset parameters but keep step=0 (might be overwritten if user specified step=0)
        paramreg = ParamregMultiStep([step0])
        if ref == 'subject':
            paramreg.steps['0'].dof = 'Tx_Ty_Tz_Rx_Ry_Rz_Sz'
        # add user parameters
        for paramStep in arguments['-param']:
            paramreg.addStep(paramStep)
    else:
        paramreg = ParamregMultiStep([step0, step1, step2])
        # if ref=subject, initialize registration using different affine parameters
        if ref == 'subject':
            paramreg.steps['0'].dof = 'Tx_Ty_Tz_Rx_Ry_Rz_Sz'

    # initialize other parameters
    # file_template_label = param.file_template_label
    zsubsample = param.zsubsample
    # smoothing_sigma = param.smoothing_sigma

    # retrieve template file names
    from sct_warp_template import get_file_label
    file_template_vertebral_labeling = get_file_label(path_template + 'template/', 'vertebral')
    file_template = get_file_label(path_template + 'template/', contrast_template.upper() + '-weighted')
    file_template_seg = get_file_label(path_template + 'template/', 'spinal cord')

    # start timer
    start_time = time.time()

    # get fname of the template + template objects
    fname_template = path_template + 'template/' + file_template
    fname_template_vertebral_labeling = path_template + 'template/' + file_template_vertebral_labeling
    fname_template_seg = path_template + 'template/' + file_template_seg

    # check file existence
    # TODO: no need to do that!
    sct.printv('\nCheck template files...')
    sct.check_file_exist(fname_template, verbose)
    sct.check_file_exist(fname_template_vertebral_labeling, verbose)
    sct.check_file_exist(fname_template_seg, verbose)
    path_data, file_data, ext_data = sct.extract_fname(fname_data)

    # print arguments
    sct.printv('\nCheck parameters:', verbose)
    sct.printv('  Data:                 ' + fname_data, verbose)
    sct.printv('  Landmarks:            ' + fname_landmarks, verbose)
    sct.printv('  Segmentation:         ' + fname_seg, verbose)
    sct.printv('  Path template:        ' + path_template, verbose)
    sct.printv('  Remove temp files:    ' + str(remove_temp_files), verbose)

    # create QC folder
    sct.create_folder(param.path_qc)

    # check if data, segmentation and landmarks are in the same space
    # JULIEN 2017-04-25: removed because of issue #1168
    # sct.printv('\nCheck if data, segmentation and landmarks are in the same space...')
    # if not sct.check_if_same_space(fname_data, fname_seg):
    #     sct.printv('ERROR: Data image and segmentation are not in the same space. Please check space and orientation of your files', verbose, 'error')
    # if not sct.check_if_same_space(fname_data, fname_landmarks):
    #     sct.printv('ERROR: Data image and landmarks are not in the same space. Please check space and orientation of your files', verbose, 'error')

    # check input labels
    labels = check_labels(fname_landmarks)

    # create temporary folder
    path_tmp = sct.tmp_create(verbose=verbose)

    # set temporary file names
    ftmp_data = 'data.nii'
    ftmp_seg = 'seg.nii.gz'
    ftmp_label = 'label.nii.gz'
    ftmp_template = 'template.nii'
    ftmp_template_seg = 'template_seg.nii.gz'
    ftmp_template_label = 'template_label.nii.gz'

    # copy files to temporary folder
    sct.printv('\nCopying input data to tmp folder and convert to nii...', verbose)
    sct.run('sct_convert -i ' + fname_data + ' -o ' + path_tmp + ftmp_data)
    sct.run('sct_convert -i ' + fname_seg + ' -o ' + path_tmp + ftmp_seg)
    sct.run('sct_convert -i ' + fname_landmarks + ' -o ' + path_tmp + ftmp_label)
    sct.run('sct_convert -i ' + fname_template + ' -o ' + path_tmp + ftmp_template)
    sct.run('sct_convert -i ' + fname_template_seg + ' -o ' + path_tmp + ftmp_template_seg)
    # sct.run('sct_convert -i '+fname_template_label+' -o '+path_tmp+ftmp_template_label)

    # go to tmp folder
    os.chdir(path_tmp)

    # copy header of anat to segmentation (issue #1168)
    # from sct_image import copy_header
    # im_data = Image(ftmp_data)
    # im_seg = Image(ftmp_seg)
    # copy_header(im_data, im_seg)
    # im_seg.save()
    # im_label = Image(ftmp_label)
    # copy_header(im_data, im_label)
    # im_label.save()

    # Generate labels from template vertebral labeling
    sct.printv('\nGenerate labels from template vertebral labeling', verbose)
    sct.run('sct_label_utils -i ' + fname_template_vertebral_labeling + ' -vert-body 0 -o ' + ftmp_template_label)

    # check if provided labels are available in the template
    sct.printv('\nCheck if provided labels are available in the template', verbose)
    image_label_template = Image(ftmp_template_label)
    labels_template = image_label_template.getNonZeroCoordinates(sorting='value')
    if labels[-1].value > labels_template[-1].value:
        sct.printv('ERROR: Wrong landmarks input. Labels must have correspondence in template space. \nLabel max '
                   'provided: ' + str(labels[-1].value) + '\nLabel max from template: ' +
                   str(labels_template[-1].value), verbose, 'error')

    # binarize segmentation (in case it has values below 0 caused by manual editing)
    sct.printv('\nBinarize segmentation', verbose)
    sct.run('sct_maths -i seg.nii.gz -bin 0.5 -o seg.nii.gz')

    # smooth segmentation (jcohenadad, issue #613)
    # sct.printv('\nSmooth segmentation...', verbose)
    # sct.run('sct_maths -i '+ftmp_seg+' -smooth 1.5 -o '+add_suffix(ftmp_seg, '_smooth'))
    # jcohenadad: updated 2016-06-16: DO NOT smooth the seg anymore. Issue #
    # sct.run('sct_maths -i '+ftmp_seg+' -smooth 0 -o '+add_suffix(ftmp_seg, '_smooth'))
    # ftmp_seg = add_suffix(ftmp_seg, '_smooth')

    # Switch between modes: subject->template or template->subject
    if ref == 'template':

        # resample data to 1mm isotropic
        sct.printv('\nResample data to 1mm isotropic...', verbose)
        sct.run('sct_resample -i ' + ftmp_data + ' -mm 1.0x1.0x1.0 -x linear -o ' + add_suffix(ftmp_data, '_1mm'))
        ftmp_data = add_suffix(ftmp_data, '_1mm')
        sct.run('sct_resample -i ' + ftmp_seg + ' -mm 1.0x1.0x1.0 -x linear -o ' + add_suffix(ftmp_seg, '_1mm'))
        ftmp_seg = add_suffix(ftmp_seg, '_1mm')
        # N.B. resampling of labels is more complicated, because they are single-point labels, therefore resampling with neighrest neighbour can make them disappear. Therefore a more clever approach is required.
        resample_labels(ftmp_label, ftmp_data, add_suffix(ftmp_label, '_1mm'))
        ftmp_label = add_suffix(ftmp_label, '_1mm')

        # Change orientation of input images to RPI
        sct.printv('\nChange orientation of input images to RPI...', verbose)
        sct.run('sct_image -i ' + ftmp_data + ' -setorient RPI -o ' + add_suffix(ftmp_data, '_rpi'))
        ftmp_data = add_suffix(ftmp_data, '_rpi')
        sct.run('sct_image -i ' + ftmp_seg + ' -setorient RPI -o ' + add_suffix(ftmp_seg, '_rpi'))
        ftmp_seg = add_suffix(ftmp_seg, '_rpi')
        sct.run('sct_image -i ' + ftmp_label + ' -setorient RPI -o ' + add_suffix(ftmp_label, '_rpi'))
        ftmp_label = add_suffix(ftmp_label, '_rpi')

        # get landmarks in native space
        # crop segmentation
        # output: segmentation_rpi_crop.nii.gz
        status_crop, output_crop = sct.run('sct_crop_image -i ' + ftmp_seg + ' -o ' + add_suffix(ftmp_seg, '_crop') + ' -dim 2 -bzmax', verbose)
        ftmp_seg = add_suffix(ftmp_seg, '_crop')
        cropping_slices = output_crop.split('Dimension 2: ')[1].split('\n')[0].split(' ')

        # straighten segmentation
        sct.printv('\nStraighten the spinal cord using centerline/segmentation...', verbose)
        # check if warp_curve2straight and warp_straight2curve already exist (i.e. no need to do it another time)
        if os.path.isfile('../warp_curve2straight.nii.gz') and os.path.isfile('../warp_straight2curve.nii.gz') and os.path.isfile('../straight_ref.nii.gz'):
            # if they exist, copy them into current folder
            sct.printv('WARNING: Straightening was already run previously. Copying warping fields...', verbose, 'warning')
            shutil.copy('../warp_curve2straight.nii.gz', 'warp_curve2straight.nii.gz')
            shutil.copy('../warp_straight2curve.nii.gz', 'warp_straight2curve.nii.gz')
            shutil.copy('../straight_ref.nii.gz', 'straight_ref.nii.gz')
            # apply straightening
            sct.run('sct_apply_transfo -i ' + ftmp_seg + ' -w warp_curve2straight.nii.gz -d straight_ref.nii.gz -o ' + add_suffix(ftmp_seg, '_straight'))
        else:
            sct.run('sct_straighten_spinalcord -i ' + ftmp_seg + ' -s ' + ftmp_seg + ' -o ' + add_suffix(ftmp_seg, '_straight') + ' -qc 0 -r 0 -v ' + str(verbose), verbose)
        # N.B. DO NOT UPDATE VARIABLE ftmp_seg BECAUSE TEMPORARY USED LATER
        # re-define warping field using non-cropped space (to avoid issue #367)
        sct.run('sct_concat_transfo -w warp_straight2curve.nii.gz -d ' + ftmp_data + ' -o warp_straight2curve.nii.gz')

        # Label preparation:
        # --------------------------------------------------------------------------------
        # Remove unused label on template. Keep only label present in the input label image
        sct.printv('\nRemove unused label on template. Keep only label present in the input label image...', verbose)
        sct.run('sct_label_utils -i ' + ftmp_template_label + ' -o ' + ftmp_template_label + ' -remove ' + ftmp_label)

        # Dilating the input label so they can be straighten without losing them
        sct.printv('\nDilating input labels using 3vox ball radius')
        sct.run('sct_maths -i ' + ftmp_label + ' -o ' + add_suffix(ftmp_label, '_dilate') + ' -dilate 3')
        ftmp_label = add_suffix(ftmp_label, '_dilate')

        # Apply straightening to labels
        sct.printv('\nApply straightening to labels...', verbose)
        sct.run('sct_apply_transfo -i ' + ftmp_label + ' -o ' + add_suffix(ftmp_label, '_straight') + ' -d ' + add_suffix(ftmp_seg, '_straight') + ' -w warp_curve2straight.nii.gz -x nn')
        ftmp_label = add_suffix(ftmp_label, '_straight')

        # Compute rigid transformation straight landmarks --> template landmarks
        sct.printv('\nEstimate transformation for step #0...', verbose)
        from msct_register_landmarks import register_landmarks
        try:
            register_landmarks(ftmp_label, ftmp_template_label, paramreg.steps['0'].dof, fname_affine='straight2templateAffine.txt', verbose=verbose)
        except Exception:
            sct.printv('ERROR: input labels do not seem to be at the right place. Please check the position of the labels. See documentation for more details: https://sourceforge.net/p/spinalcordtoolbox/wiki/create_labels/', verbose=verbose, type='error')

        # Concatenate transformations: curve --> straight --> affine
        sct.printv('\nConcatenate transformations: curve --> straight --> affine...', verbose)
        sct.run('sct_concat_transfo -w warp_curve2straight.nii.gz,straight2templateAffine.txt -d template.nii -o warp_curve2straightAffine.nii.gz')

        # Apply transformation
        sct.printv('\nApply transformation...', verbose)
        sct.run('sct_apply_transfo -i ' + ftmp_data + ' -o ' + add_suffix(ftmp_data, '_straightAffine') + ' -d ' + ftmp_template + ' -w warp_curve2straightAffine.nii.gz')
        ftmp_data = add_suffix(ftmp_data, '_straightAffine')
        sct.run('sct_apply_transfo -i ' + ftmp_seg + ' -o ' + add_suffix(ftmp_seg, '_straightAffine') + ' -d ' + ftmp_template + ' -w warp_curve2straightAffine.nii.gz -x linear')
        ftmp_seg = add_suffix(ftmp_seg, '_straightAffine')

        """
        # Benjamin: Issue from Allan Martin, about the z=0 slice that is screwed up, caused by the affine transform.
        # Solution found: remove slices below and above landmarks to avoid rotation effects
        points_straight = []
        for coord in landmark_template:
            points_straight.append(coord.z)
        min_point, max_point = int(round(np.min(points_straight))), int(round(np.max(points_straight)))
        sct.run('sct_crop_image -i ' + ftmp_seg + ' -start ' + str(min_point) + ' -end ' + str(max_point) + ' -dim 2 -b 0 -o ' + add_suffix(ftmp_seg, '_black'))
        ftmp_seg = add_suffix(ftmp_seg, '_black')
        """

        # binarize
        sct.printv('\nBinarize segmentation...', verbose)
        sct.run('sct_maths -i ' + ftmp_seg + ' -bin 0.5 -o ' + add_suffix(ftmp_seg, '_bin'))
        ftmp_seg = add_suffix(ftmp_seg, '_bin')

        # find min-max of anat2template (for subsequent cropping)
        zmin_template, zmax_template = find_zmin_zmax(ftmp_seg)

        # crop template in z-direction (for faster processing)
        sct.printv('\nCrop data in template space (for faster processing)...', verbose)
        sct.run('sct_crop_image -i ' + ftmp_template + ' -o ' + add_suffix(ftmp_template, '_crop') + ' -dim 2 -start ' + str(zmin_template) + ' -end ' + str(zmax_template))
        ftmp_template = add_suffix(ftmp_template, '_crop')
        sct.run('sct_crop_image -i ' + ftmp_template_seg + ' -o ' + add_suffix(ftmp_template_seg, '_crop') + ' -dim 2 -start ' + str(zmin_template) + ' -end ' + str(zmax_template))
        ftmp_template_seg = add_suffix(ftmp_template_seg, '_crop')
        sct.run('sct_crop_image -i ' + ftmp_data + ' -o ' + add_suffix(ftmp_data, '_crop') + ' -dim 2 -start ' + str(zmin_template) + ' -end ' + str(zmax_template))
        ftmp_data = add_suffix(ftmp_data, '_crop')
        sct.run('sct_crop_image -i ' + ftmp_seg + ' -o ' + add_suffix(ftmp_seg, '_crop') + ' -dim 2 -start ' + str(zmin_template) + ' -end ' + str(zmax_template))
        ftmp_seg = add_suffix(ftmp_seg, '_crop')

        # sub-sample in z-direction
        sct.printv('\nSub-sample in z-direction (for faster processing)...', verbose)
        sct.run('sct_resample -i ' + ftmp_template + ' -o ' + add_suffix(ftmp_template, '_sub') + ' -f 1x1x' + zsubsample, verbose)
        ftmp_template = add_suffix(ftmp_template, '_sub')
        sct.run('sct_resample -i ' + ftmp_template_seg + ' -o ' + add_suffix(ftmp_template_seg, '_sub') + ' -f 1x1x' + zsubsample, verbose)
        ftmp_template_seg = add_suffix(ftmp_template_seg, '_sub')
        sct.run('sct_resample -i ' + ftmp_data + ' -o ' + add_suffix(ftmp_data, '_sub') + ' -f 1x1x' + zsubsample, verbose)
        ftmp_data = add_suffix(ftmp_data, '_sub')
        sct.run('sct_resample -i ' + ftmp_seg + ' -o ' + add_suffix(ftmp_seg, '_sub') + ' -f 1x1x' + zsubsample, verbose)
        ftmp_seg = add_suffix(ftmp_seg, '_sub')

        # Registration straight spinal cord to template
        sct.printv('\nRegister straight spinal cord to template...', verbose)

        # loop across registration steps
        warp_forward = []
        warp_inverse = []
        for i_step in range(1, len(paramreg.steps)):
            sct.printv('\nEstimate transformation for step #' + str(i_step) + '...', verbose)
            # identify which is the src and dest
            if paramreg.steps[str(i_step)].type == 'im':
                src = ftmp_data
                dest = ftmp_template
                interp_step = 'linear'
            elif paramreg.steps[str(i_step)].type == 'seg':
                src = ftmp_seg
                dest = ftmp_template_seg
                interp_step = 'nn'
            else:
                sct.printv('ERROR: Wrong image type.', 1, 'error')
            # if step>1, apply warp_forward_concat to the src image to be used
            if i_step > 1:
                # sct.run('sct_apply_transfo -i '+src+' -d '+dest+' -w '+','.join(warp_forward)+' -o '+sct.add_suffix(src, '_reg')+' -x '+interp_step, verbose)
                # apply transformation from previous step, to use as new src for registration
                sct.run('sct_apply_transfo -i ' + src + ' -d ' + dest + ' -w ' + ','.join(warp_forward) + ' -o ' + add_suffix(src, '_regStep' + str(i_step - 1)) + ' -x ' + interp_step, verbose)
                src = add_suffix(src, '_regStep' + str(i_step - 1))
            # register src --> dest
            # TODO: display param for debugging
            warp_forward_out, warp_inverse_out = register(src, dest, paramreg, param, str(i_step))
            warp_forward.append(warp_forward_out)
            warp_inverse.append(warp_inverse_out)

        # Concatenate transformations:
        sct.printv('\nConcatenate transformations: anat --> template...', verbose)
        sct.run('sct_concat_transfo -w warp_curve2straightAffine.nii.gz,' + ','.join(warp_forward) + ' -d template.nii -o warp_anat2template.nii.gz', verbose)
        # sct.run('sct_concat_transfo -w warp_curve2straight.nii.gz,straight2templateAffine.txt,'+','.join(warp_forward)+' -d template.nii -o warp_anat2template.nii.gz', verbose)
        sct.printv('\nConcatenate transformations: template --> anat...', verbose)
        warp_inverse.reverse()
        sct.run('sct_concat_transfo -w ' + ','.join(warp_inverse) + ',-straight2templateAffine.txt,warp_straight2curve.nii.gz -d data.nii -o warp_template2anat.nii.gz', verbose)

    # register template->subject
    elif ref == 'subject':

        # Change orientation of input images to RPI
        sct.printv('\nChange orientation of input images to RPI...', verbose)
        sct.run('sct_image -i ' + ftmp_data + ' -setorient RPI -o ' + add_suffix(ftmp_data, '_rpi'))
        ftmp_data = add_suffix(ftmp_data, '_rpi')
        sct.run('sct_image -i ' + ftmp_seg + ' -setorient RPI -o ' + add_suffix(ftmp_seg, '_rpi'))
        ftmp_seg = add_suffix(ftmp_seg, '_rpi')
        sct.run('sct_image -i ' + ftmp_label + ' -setorient RPI -o ' + add_suffix(ftmp_label, '_rpi'))
        ftmp_label = add_suffix(ftmp_label, '_rpi')

        # Remove unused label on template. Keep only label present in the input label image
        sct.printv('\nRemove unused label on template. Keep only label present in the input label image...', verbose)
        sct.run('sct_label_utils -i ' + ftmp_template_label + ' -o ' + ftmp_template_label + ' -remove ' + ftmp_label)

        # Add one label because at least 3 orthogonal labels are required to estimate an affine transformation. This new label is added at the level of the upper most label (lowest value), at 1cm to the right.
        for i_file in [ftmp_label, ftmp_template_label]:
            im_label = Image(i_file)
            coord_label = im_label.getCoordinatesAveragedByValue()  # N.B. landmarks are sorted by value
            # Create new label
            from copy import deepcopy
            new_label = deepcopy(coord_label[0])
            # move it 5mm to the left (orientation is RAS)
            nx, ny, nz, nt, px, py, pz, pt = im_label.dim
            new_label.x = round(coord_label[0].x + 5.0 / px)
            # assign value 99
            new_label.value = 99
            # Add to existing image
            im_label.data[int(new_label.x), int(new_label.y), int(new_label.z)] = new_label.value
            # Overwrite label file
            # im_label.setFileName('label_rpi_modif.nii.gz')
            im_label.save()

        # Bring template to subject space using landmark-based transformation
        sct.printv('\nEstimate transformation for step #0...', verbose)
        from msct_register_landmarks import register_landmarks
        warp_forward = ['template2subjectAffine.txt']
        warp_inverse = ['-template2subjectAffine.txt']
        try:
            register_landmarks(ftmp_template_label, ftmp_label, paramreg.steps['0'].dof, fname_affine=warp_forward[0], verbose=verbose, path_qc=param.path_qc)
        except Exception:
            sct.printv('ERROR: input labels do not seem to be at the right place. Please check the position of the labels. See documentation for more details: https://sourceforge.net/p/spinalcordtoolbox/wiki/create_labels/', verbose=verbose, type='error')

        # loop across registration steps
        for i_step in range(1, len(paramreg.steps)):
            sct.printv('\nEstimate transformation for step #' + str(i_step) + '...', verbose)
            # identify which is the src and dest
            if paramreg.steps[str(i_step)].type == 'im':
                src = ftmp_template
                dest = ftmp_data
                interp_step = 'linear'
            elif paramreg.steps[str(i_step)].type == 'seg':
                src = ftmp_template_seg
                dest = ftmp_seg
                interp_step = 'nn'
            else:
                sct.printv('ERROR: Wrong image type.', 1, 'error')
            # apply transformation from previous step, to use as new src for registration
            sct.run('sct_apply_transfo -i ' + src + ' -d ' + dest + ' -w ' + ','.join(warp_forward) + ' -o ' + add_suffix(src, '_regStep' + str(i_step - 1)) + ' -x ' + interp_step, verbose)
            src = add_suffix(src, '_regStep' + str(i_step - 1))
            # register src --> dest
            # TODO: display param for debugging
            warp_forward_out, warp_inverse_out = register(src, dest, paramreg, param, str(i_step))
            warp_forward.append(warp_forward_out)
            warp_inverse.insert(0, warp_inverse_out)

        # Concatenate transformations:
        sct.printv('\nConcatenate transformations: template --> subject...', verbose)
        sct.run('sct_concat_transfo -w ' + ','.join(warp_forward) + ' -d data.nii -o warp_template2anat.nii.gz', verbose)
        sct.printv('\nConcatenate transformations: subject --> template...', verbose)
        sct.run('sct_concat_transfo -w ' + ','.join(warp_inverse) + ' -d template.nii -o warp_anat2template.nii.gz', verbose)

    # Apply warping fields to anat and template
    sct.run('sct_apply_transfo -i template.nii -o template2anat.nii.gz -d data.nii -w warp_template2anat.nii.gz -crop 1', verbose)
    sct.run('sct_apply_transfo -i data.nii -o anat2template.nii.gz -d template.nii -w warp_anat2template.nii.gz -crop 1', verbose)

    # come back to parent folder
    os.chdir('..')

    # Generate output files
    sct.printv('\nGenerate output files...', verbose)
    sct.generate_output_file(path_tmp + 'warp_template2anat.nii.gz', path_output + 'warp_template2anat.nii.gz', verbose)
    sct.generate_output_file(path_tmp + 'warp_anat2template.nii.gz', path_output + 'warp_anat2template.nii.gz', verbose)
    sct.generate_output_file(path_tmp + 'template2anat.nii.gz', path_output + 'template2anat' + ext_data, verbose)
    sct.generate_output_file(path_tmp + 'anat2template.nii.gz', path_output + 'anat2template' + ext_data, verbose)
    if ref == 'template':
        # copy straightening files in case subsequent SCT functions need them
        sct.generate_output_file(path_tmp + 'warp_curve2straight.nii.gz', path_output + 'warp_curve2straight.nii.gz', verbose)
        sct.generate_output_file(path_tmp + 'warp_straight2curve.nii.gz', path_output + 'warp_straight2curve.nii.gz', verbose)
        sct.generate_output_file(path_tmp + 'straight_ref.nii.gz', path_output + 'straight_ref.nii.gz', verbose)

    # Delete temporary files
    if remove_temp_files:
        sct.printv('\nDelete temporary files...', verbose)
        sct.run('rm -rf ' + path_tmp)

    # display elapsed time
    elapsed_time = time.time() - start_time
    sct.printv('\nFinished! Elapsed time: ' + str(int(round(elapsed_time))) + 's', verbose)

    if '-qc' in arguments and not arguments.get('-noqc', False):
        qc_path = arguments['-qc']

        import spinalcordtoolbox.reports.qc as qc
        import spinalcordtoolbox.reports.slice as qcslice

        qc_param = qc.Params(fname_data, 'sct_register_to_template', args, 'Sagittal', qc_path)
        report = qc.QcReport(qc_param, '')

        @qc.QcImage(report, 'none', [qc.QcImage.no_seg_seg])
        def test(qslice):
            return qslice.single()

        fname_template2anat = path_output + 'template2anat' + ext_data
        test(qcslice.SagittalTemplate2Anat(Image(fname_data), Image(fname_template2anat), Image(fname_seg)))
        sct.printv('Sucessfully generate the QC results in %s' % qc_param.qc_results)
        sct.printv('Use the following command to see the results in a browser')
        sct.printv('sct_qc -folder %s' % qc_path, type='info')

    # to view results
    sct.printv('\nTo view results, type:', verbose)
    sct.printv('fslview ' + fname_data + ' ' + path_output + 'template2anat -b 0,4000 &', verbose, 'info')
    sct.printv('fslview ' + fname_template + ' -b 0,5000 ' + path_output + 'anat2template &\n', verbose, 'info')
Beispiel #7
0
    im_seg = Image(fname_seg)
    im_seg = copy_header(image_input, im_seg)
    im_seg.save(type='int8')

    # remove temporary files
    if remove_temp_files and use_viewer:
        sct.log.info("Remove temporary files...")
        os.remove(tmp_output_file.absolutepath)

    if '-qc' in arguments and not arguments.get('-noqc', False):
        qc_path = arguments['-qc']

        import spinalcordtoolbox.reports.qc as qc
        import spinalcordtoolbox.reports.slice as qcslice

        param = qc.Params(fname_input_data, 'sct_propseg', args, 'Axial',
                          qc_path)
        report = qc.QcReport(param, '')

        @qc.QcImage(report, 'none', [
            qc.QcImage.listed_seg,
        ])
        def test(qslice):
            return qslice.mosaic()

        try:
            test(qcslice.Axial(Image(fname_input_data), Image(fname_seg)))
            sct.log.info('Sucessfully generated the QC results in %s' %
                         param.qc_results)
            sct.log.info(
                'Use the following command to see the results in a browser:')
            sct.log.info('sct_qc -folder %s' % qc_path)
def main(args=None):

    # initializations
    initz = ''
    initcenter = ''
    initc2 = 'auto'
    param = Param()

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

    # Get parser info
    parser = get_parser()
    arguments = parser.parse(args)
    fname_in = arguments["-i"]
    fname_seg = arguments['-s']
    contrast = arguments['-c']
    path_template = sct.slash_at_the_end(arguments['-t'], 1)
    # if '-o' in arguments:
    #     file_out = arguments["-o"]
    # else:
    #     file_out = ''
    if '-ofolder' in arguments:
        path_output = sct.slash_at_the_end(os.path.abspath(
            arguments['-ofolder']),
                                           slash=1)
    else:
        path_output = sct.slash_at_the_end(os.path.abspath(os.curdir), slash=1)
    if '-initz' in arguments:
        initz = arguments['-initz']
    if '-initcenter' in arguments:
        initcenter = arguments['-initcenter']
    # if user provided text file, parse and overwrite arguments
    if '-initfile' in arguments:
        # open file
        file = open(arguments['-initfile'], 'r')
        initfile = ' ' + file.read().replace('\n', '')
        arg_initfile = initfile.split(' ')
        for i in xrange(len(arg_initfile)):
            if arg_initfile[i] == '-initz':
                initz = [int(x) for x in arg_initfile[i + 1].split(',')]
            if arg_initfile[i] == '-initcenter':
                initcenter = int(arg_initfile[i + 1])
    if '-initc2' in arguments:
        initc2 = 'manual'
    if '-param' in arguments:
        param.update(arguments['-param'][0])
    verbose = int(arguments['-v'])
    remove_tmp_files = int(arguments['-r'])
    denoise = int(arguments['-denoise'])
    laplacian = int(arguments['-laplacian'])

    # create temporary folder
    sct.printv('\nCreate temporary folder...', verbose)
    path_tmp = sct.tmp_create(verbose=verbose)

    # Copying input data to tmp folder
    sct.printv('\nCopying input data to tmp folder...', verbose)
    sct.run('sct_convert -i ' + fname_in + ' -o ' + path_tmp + 'data.nii')
    sct.run('sct_convert -i ' + fname_seg + ' -o ' + path_tmp +
            'segmentation.nii.gz')

    # Go go temp folder
    os.chdir(path_tmp)

    # create label to identify disc
    sct.printv('\nCreate label to identify disc...', verbose)
    initauto = False
    if initz:
        create_label_z('segmentation.nii.gz', initz[0],
                       initz[1])  # create label located at z_center
    elif initcenter:
        # find z centered in FOV
        nii = Image('segmentation.nii.gz')
        nii.change_orientation('RPI')  # reorient to RPI
        nx, ny, nz, nt, px, py, pz, pt = nii.dim  # Get dimensions
        z_center = int(round(nz / 2))  # get z_center
        create_label_z('segmentation.nii.gz', z_center,
                       initcenter)  # create label located at z_center
    else:
        initauto = True
        # printv('\nERROR: You need to initialize the disc detection algorithm using one of these two options: -initz, -initcenter\n', 1, 'error')

    # Straighten spinal cord
    sct.printv('\nStraighten spinal cord...', verbose)
    # check if warp_curve2straight and warp_straight2curve already exist (i.e. no need to do it another time)
    if os.path.isfile('../warp_curve2straight.nii.gz') and os.path.isfile(
            '../warp_straight2curve.nii.gz') and os.path.isfile(
                '../straight_ref.nii.gz'):
        # if they exist, copy them into current folder
        sct.printv(
            'WARNING: Straightening was already run previously. Copying warping fields...',
            verbose, 'warning')
        shutil.copy('../warp_curve2straight.nii.gz',
                    'warp_curve2straight.nii.gz')
        shutil.copy('../warp_straight2curve.nii.gz',
                    'warp_straight2curve.nii.gz')
        shutil.copy('../straight_ref.nii.gz', 'straight_ref.nii.gz')
        # apply straightening
        sct.run(
            'sct_apply_transfo -i data.nii -w warp_curve2straight.nii.gz -d straight_ref.nii.gz -o data_straight.nii'
        )
    else:
        sct.run(
            'sct_straighten_spinalcord -i data.nii -s segmentation.nii.gz -r 0 -qc 0'
        )

    # resample to 0.5mm isotropic to match template resolution
    sct.printv('\nResample to 0.5mm isotropic...', verbose)
    sct.run(
        'sct_resample -i data_straight.nii -mm 0.5x0.5x0.5 -x linear -o data_straightr.nii',
        verbose)
    # sct.run('sct_resample -i segmentation.nii.gz -mm 0.5x0.5x0.5 -x linear -o segmentationr.nii.gz', verbose)
    # sct.run('sct_resample -i labelz.nii.gz -mm 0.5x0.5x0.5 -x linear -o labelzr.nii', verbose)

    # Apply straightening to segmentation
    # N.B. Output is RPI
    sct.printv('\nApply straightening to segmentation...', verbose)
    sct.run(
        'sct_apply_transfo -i segmentation.nii.gz -d data_straightr.nii -w warp_curve2straight.nii.gz -o segmentation_straight.nii.gz -x linear',
        verbose)
    # Threshold segmentation at 0.5
    sct.run(
        'sct_maths -i segmentation_straight.nii.gz -thr 0.5 -o segmentation_straight.nii.gz',
        verbose)

    if initauto:
        init_disc = []
    else:
        # Apply straightening to z-label
        sct.printv('\nDilate z-label and apply straightening...', verbose)
        sct.run(
            'sct_apply_transfo -i labelz.nii.gz -d data_straightr.nii -w warp_curve2straight.nii.gz -o labelz_straight.nii.gz -x nn',
            verbose)
        # get z value and disk value to initialize labeling
        sct.printv('\nGet z and disc values from straight label...', verbose)
        init_disc = get_z_and_disc_values_from_label('labelz_straight.nii.gz')
        sct.printv('.. ' + str(init_disc), verbose)

    # denoise data
    if denoise:
        sct.printv('\nDenoise data...', verbose)
        sct.run(
            'sct_maths -i data_straightr.nii -denoise h=0.05 -o data_straightr.nii',
            verbose)

    # apply laplacian filtering
    if laplacian:
        sct.printv('\nApply Laplacian filter...', verbose)
        sct.run(
            'sct_maths -i data_straightr.nii -laplacian 1 -o data_straightr.nii',
            verbose)

    # detect vertebral levels on straight spinal cord
    vertebral_detection('data_straightr.nii',
                        'segmentation_straight.nii.gz',
                        contrast,
                        param,
                        init_disc=init_disc,
                        verbose=verbose,
                        path_template=path_template,
                        initc2=initc2,
                        path_output=path_output)

    # un-straighten labeled spinal cord
    sct.printv('\nUn-straighten labeling...', verbose)
    sct.run(
        'sct_apply_transfo -i segmentation_straight_labeled.nii.gz -d segmentation.nii.gz -w warp_straight2curve.nii.gz -o segmentation_labeled.nii.gz -x nn',
        verbose)

    # Clean labeled segmentation
    sct.printv(
        '\nClean labeled segmentation (correct interpolation errors)...',
        verbose)
    clean_labeled_segmentation('segmentation_labeled.nii.gz',
                               'segmentation.nii.gz',
                               'segmentation_labeled.nii.gz')

    # label discs
    sct.printv('\nLabel discs...', verbose)
    label_discs('segmentation_labeled.nii.gz', verbose=verbose)

    # come back to parent folder
    os.chdir('..')

    # Generate output files
    path_seg, file_seg, ext_seg = sct.extract_fname(fname_seg)
    sct.printv('\nGenerate output files...', verbose)
    sct.generate_output_file(path_tmp + 'segmentation_labeled.nii.gz',
                             path_output + file_seg + '_labeled' + ext_seg)
    sct.generate_output_file(
        path_tmp + 'segmentation_labeled_disc.nii.gz',
        path_output + file_seg + '_labeled_discs' + ext_seg)
    # copy straightening files in case subsequent SCT functions need them
    sct.generate_output_file(path_tmp + 'warp_curve2straight.nii.gz',
                             path_output + 'warp_curve2straight.nii.gz',
                             verbose)
    sct.generate_output_file(path_tmp + 'warp_straight2curve.nii.gz',
                             path_output + 'warp_straight2curve.nii.gz',
                             verbose)
    sct.generate_output_file(path_tmp + 'straight_ref.nii.gz',
                             path_output + 'straight_ref.nii.gz', verbose)

    # Remove temporary files
    if remove_tmp_files == 1:
        sct.printv('\nRemove temporary files...', verbose)
        shutil.rmtree(path_tmp, ignore_errors=True)

    # Generate QC report
    try:
        if '-qc' in arguments and not arguments.get('-noqc', False):
            qc_path = arguments['-qc']

            import spinalcordtoolbox.reports.qc as qc
            import spinalcordtoolbox.reports.slice as qcslice

            qc_param = qc.Params(fname_in, 'sct_label_vertebrae', args,
                                 'Sagittal', qc_path)
            report = qc.QcReport(qc_param, '')

            @qc.QcImage(report, 'none', [
                qc.QcImage.label_vertebrae,
            ])
            def test(qslice):
                return qslice.single()

            labeled_seg_file = path_output + file_seg + '_labeled' + ext_seg
            test(qcslice.Sagittal(Image(fname_in), Image(labeled_seg_file)))
            sct.printv('Sucessfully generated the QC results in %s' %
                       qc_param.qc_results)
            sct.printv(
                'Use the following command to see the results in a browser:')
            sct.printv('sct_qc -folder %s' % qc_path, type='info')
    except Exception as err:
        sct.printv(err, verbose, 'warning')
        sct.printv('WARNING: Cannot generate report.', verbose, 'warning')

    # to view results
    sct.printv('\nDone! To view results, type:', verbose)
    sct.printv(
        'fslview ' + fname_in + ' ' + path_output + file_seg + '_labeled' +
        ' -l Random-Rainbow -t 0.5 &\n', verbose, 'info')