def run_cardiac_segmentation(img, guide_structure=None, settings=CARDIAC_SETTINGS_DEFAULTS):
    'Runs the atlas-based cardiac segmentation\n\n    Args:\n        img (sitk.Image):\n        settings (dict, optional): Dictionary containing settings for algorithm.\n                                   Defaults to default_settings.\n\n    Returns:\n        dict: Dictionary containing output of segmentation\n    '
    results = {}
    results_prob = {}
    return_as_cropped = settings['return_as_cropped']
    "\n    Initialisation - Read in atlases\n    - image files\n    - structure files\n\n        Atlas structure:\n        'ID': 'Original': 'CT Image'    : sitk.Image\n                            'Struct A'    : sitk.Image\n                            'Struct B'    : sitk.Image\n                'RIR'     : 'CT Image'    : sitk.Image\n                            'Transform'   : transform parameter map\n                            'Struct A'    : sitk.Image\n                            'Struct B'    : sitk.Image\n                'DIR'     : 'CT Image'    : sitk.Image\n                            'Transform'   : displacement field transform\n                            'Weight Map'  : sitk.Image\n                            'Struct A'    : sitk.Image\n                            'Struct B'    : sitk.Image\n\n\n    "
    logger.info('')
    atlas_path = settings['atlas_settings']['atlas_path']
    atlas_id_list = settings['atlas_settings']['atlas_id_list']
    atlas_structure_list = settings['atlas_settings']['atlas_structure_list']
    atlas_image_format = settings['atlas_settings']['atlas_image_format']
    atlas_label_format = settings['atlas_settings']['atlas_label_format']
    crop_atlas_to_structures = settings['atlas_settings']['crop_atlas_to_structures']
    crop_atlas_expansion_mm = settings['atlas_settings']['crop_atlas_expansion_mm']
    atlas_set = {}
    for atlas_id in atlas_id_list:
        atlas_set[atlas_id] = {}
        atlas_set[atlas_id]['Original'] = {}
        image = sitk.ReadImage(f'{atlas_path}/{atlas_image_format.format(atlas_id)}')
        structures = {struct: sitk.ReadImage(f'{atlas_path}/{atlas_label_format.format(atlas_id, struct)}') for struct in atlas_structure_list}
        if crop_atlas_to_structures:
            logger.info(f'Automatically cropping atlas: {atlas_id}')
            original_volume = np.product(image.GetSize())
            (crop_box_size, crop_box_index) = label_to_roi(structures.values(), expansion_mm=crop_atlas_expansion_mm)
            image = crop_to_roi(image, size=crop_box_size, index=crop_box_index)
            final_volume = np.product(image.GetSize())
            logger.info(f'  > Volume reduced by factor {(original_volume / final_volume):.2f}')
            for struct in atlas_structure_list:
                structures[struct] = crop_to_roi(structures[struct], size=crop_box_size, index=crop_box_index)
        atlas_set[atlas_id]['Original']['CT Image'] = image
        for struct in atlas_structure_list:
            atlas_set[atlas_id]['Original'][struct] = structures[struct]
    '\n    Step 1 - Automatic cropping\n    If we have a guide structure:\n        - use structure to crop target image\n\n    Otherwise:\n        - using a quick registration to register each atlas\n        - expansion of the bounding box to ensure entire volume of interest is enclosed\n        - target image is cropped\n    '
    expansion_mm = settings['auto_crop_target_image_settings']['expansion_mm']
    if guide_structure:
        (crop_box_size, crop_box_index) = label_to_roi(guide_structure, expansion_mm=expansion_mm)
        img_crop = crop_to_roi(img, crop_box_size, crop_box_index)
        guide_structure = crop_to_roi(guide_structure, crop_box_size, crop_box_index)
        target_reg_structure = convert_mask_to_reg_structure(guide_structure, expansion=2)
    else:
        quick_reg_settings = {'reg_method': 'similarity', 'shrink_factors': [8], 'smooth_sigmas': [0], 'sampling_rate': 0.75, 'default_value': (- 1000), 'number_of_iterations': 25, 'final_interp': sitk.sitkLinear, 'metric': 'mean_squares', 'optimiser': 'gradient_descent_line_search'}
        registered_crop_images = []
        logger.info('Running initial Translation tranform to crop image volume')
        for atlas_id in atlas_id_list[:min([8, len(atlas_id_list)])]:
            logger.info(f'  > atlas {atlas_id}')
            atlas_set[atlas_id]['RIR'] = {}
            atlas_image = atlas_set[atlas_id]['Original']['CT Image']
            (reg_image, _) = linear_registration(img, atlas_image, **quick_reg_settings)
            registered_crop_images.append(sitk.Cast(reg_image, sitk.sitkFloat32))
            del reg_image
        combined_image = ((sum(registered_crop_images) / len(registered_crop_images)) > (- 1000))
        (crop_box_size, crop_box_index) = label_to_roi(combined_image, expansion_mm=expansion_mm)
        img_crop = crop_to_roi(img, crop_box_size, crop_box_index)
    logger.info('Calculated crop box:')
    logger.info(f'  > {crop_box_index}')
    logger.info(f'  > {crop_box_size}')
    logger.info(f'  > Vol reduction = {(np.product(img.GetSize()) / np.product(crop_box_size)):.2f}')
    '\n    Step 2 - Rigid registration of target images\n    - Individual atlas images are registered to the target\n    - The transformation is used to propagate the labels onto the target\n    '
    linear_registration_settings = settings['linear_registration_settings']
    logger.info(f"Running {linear_registration_settings['reg_method']} tranform to align atlas images")
    for atlas_id in atlas_id_list:
        logger.info(f'  > atlas {atlas_id}')
        atlas_set[atlas_id]['RIR'] = {}
        if guide_structure:
            guide_structure_name = settings['atlas_settings']['guide_structure_name']
            target_reg_image = target_reg_structure
            atlas_reg_image = convert_mask_to_reg_structure(atlas_set[atlas_id]['Original'][guide_structure_name], expansion=2)
        else:
            target_reg_image = img_crop
            atlas_reg_image = atlas_set[atlas_id]['Original']['CT Image']
        (_, initial_tfm) = linear_registration(target_reg_image, atlas_reg_image, **linear_registration_settings)
        atlas_set[atlas_id]['RIR']['Transform'] = initial_tfm
        if guide_structure:
            atlas_set[atlas_id]['RIR']['Reg Mask'] = apply_transform(input_image=atlas_reg_image, reference_image=img_crop, transform=initial_tfm, default_value=0, interpolator=sitk.sitkLinear)
            expanded_atlas_guide_structure = extend_mask(atlas_set[atlas_id]['Original'][guide_structure_name], direction=('ax', 'sup'), extension_mm=settings['atlas_settings']['superior_extension'], interior_mm_shape=(settings['atlas_settings']['superior_extension'] / 2))
            atlas_set[atlas_id]['RIR'][(guide_structure_name + 'EXPANDED')] = apply_transform(input_image=expanded_atlas_guide_structure, reference_image=img_crop, transform=initial_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
        atlas_set[atlas_id]['RIR']['CT Image'] = apply_transform(input_image=atlas_set[atlas_id]['Original']['CT Image'], reference_image=img_crop, transform=initial_tfm, default_value=(- 1000), interpolator=sitk.sitkLinear)
        for struct in atlas_structure_list:
            input_struct = atlas_set[atlas_id]['Original'][struct]
            atlas_set[atlas_id]['RIR'][struct] = apply_transform(input_image=input_struct, reference_image=img_crop, transform=initial_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
        atlas_set[atlas_id]['Original'] = None
    '\n    Step 3 - Deformable image registration\n    - Using Fast Symmetric Diffeomorphic Demons\n    '
    if guide_structure:
        structure_guided_registration_settings = settings['structure_guided_registration_settings']
        logger.info('Running structure-guided deformable registration on atlas labels')
        for atlas_id in atlas_id_list:
            logger.info(f'  > atlas {atlas_id}')
            atlas_set[atlas_id]['DIR_STRUCT'] = {}
            (deform_image, struct_guided_tfm, _) = fast_symmetric_forces_demons_registration(target_reg_structure, atlas_set[atlas_id]['RIR']['Reg Mask'], **structure_guided_registration_settings)
            atlas_set[atlas_id]['DIR_STRUCT']['Reg Mask'] = deform_image
            atlas_set[atlas_id]['DIR_STRUCT']['Transform'] = struct_guided_tfm
            atlas_set[atlas_id]['DIR_STRUCT']['CT Image'] = apply_transform(input_image=atlas_set[atlas_id]['RIR']['CT Image'], transform=struct_guided_tfm, default_value=(- 1000), interpolator=sitk.sitkLinear)
            atlas_set[atlas_id]['DIR_STRUCT'][(guide_structure_name + 'EXPANDED')] = apply_transform(input_image=atlas_set[atlas_id]['RIR'][(guide_structure_name + 'EXPANDED')], reference_image=img_crop, transform=struct_guided_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
            for struct in atlas_structure_list:
                input_struct = atlas_set[atlas_id]['RIR'][struct]
                atlas_set[atlas_id]['DIR_STRUCT'][struct] = apply_transform(input_image=input_struct, transform=struct_guided_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
            atlas_set[atlas_id]['RIR'] = None
    deformable_registration_settings = settings['deformable_registration_settings']
    logger.info('Running DIR to refine atlas image registration')
    for atlas_id in atlas_id_list:
        logger.info(f'  > atlas {atlas_id}')
        atlas_set[atlas_id]['DIR'] = {}
        if guide_structure:
            label = 'DIR_STRUCT'
        else:
            label = 'RIR'
        atlas_reg_image = atlas_set[atlas_id][label]['CT Image']
        target_reg_image = img_crop
        if guide_structure:
            expanded_atlas_mask = atlas_set[atlas_id]['DIR_STRUCT'][(guide_structure_name + 'EXPANDED')]
            expanded_target_mask = extend_mask(guide_structure, direction=('ax', 'sup'), extension_mm=settings['atlas_settings']['superior_extension'], interior_mm_shape=(settings['atlas_settings']['superior_extension'] / 2))
            combined_mask = sitk.Maximum(expanded_atlas_mask, expanded_target_mask)
            atlas_reg_image = sitk.Mask(atlas_reg_image, combined_mask, outsideValue=(- 1000))
            atlas_reg_image = sitk.Mask(atlas_reg_image, (atlas_reg_image > (- 400)), outsideValue=(- 1000))
            target_reg_image = sitk.Mask(target_reg_image, combined_mask, outsideValue=(- 1000))
            target_reg_image = sitk.Mask(target_reg_image, (atlas_reg_image > (- 400)), outsideValue=(- 1000))
        (deform_image, dir_tfm, _) = fast_symmetric_forces_demons_registration(target_reg_image, atlas_reg_image, **deformable_registration_settings)
        atlas_set[atlas_id]['DIR']['Transform'] = dir_tfm
        atlas_set[atlas_id]['DIR']['CT Image'] = apply_transform(input_image=atlas_set[atlas_id][label]['CT Image'], transform=dir_tfm, default_value=(- 1000), interpolator=sitk.sitkLinear)
        for struct in atlas_structure_list:
            input_struct = atlas_set[atlas_id][label][struct]
            atlas_set[atlas_id]['DIR'][struct] = apply_transform(input_image=input_struct, transform=dir_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
        atlas_set[atlas_id][label] = None
    '\n    Step 4 - Iterative atlas removal\n    - This is an automatic process that will attempt to remove inconsistent atlases from the entire set\n\n    '
    iar_settings = settings['iar_settings']
    if iar_settings['reference_structure']:
        for atlas_id in atlas_id_list:
            atlas_image = atlas_set[atlas_id]['DIR']['CT Image']
            weight_map = compute_weight_map(img_crop, atlas_image, vote_type='global')
            atlas_set[atlas_id]['DIR']['Weight Map'] = weight_map
        atlas_set = run_iar(atlas_set=atlas_set, **iar_settings)
    else:
        logger.info('IAR: No reference structure, skipping iterative atlas removal.')
    '\n    Step 4 - Vessel Splining\n\n    '
    vessel_spline_settings = settings['vessel_spline_settings']
    if (len(vessel_spline_settings['vessel_name_list']) > 0):
        segmented_vessel_dict = vessel_spline_generation(img_crop, atlas_set, **vessel_spline_settings)
    else:
        logger.info('No vessel splining required, continue.')
    '\n    Step 5 - Label Fusion\n    '
    vote_type = settings['label_fusion_settings']['vote_type']
    vote_params = settings['label_fusion_settings']['vote_params']
    for atlas_id in list(atlas_set.keys()):
        atlas_image = atlas_set[atlas_id]['DIR']['CT Image']
        weight_map = compute_weight_map(img_crop, atlas_image, vote_type=vote_type, vote_params=vote_params)
        atlas_set[atlas_id]['DIR']['Weight Map'] = weight_map
    combined_label_dict = combine_labels(atlas_set, atlas_structure_list)
    '\n    Step 6 - Paste the cropped structure into the original image space\n    '
    logger.info('Generating binary segmentations.')
    template_img_binary = sitk.Cast((img * 0), sitk.sitkUInt8)
    template_img_prob = sitk.Cast((img * 0), sitk.sitkFloat64)
    vote_structures = settings['label_fusion_settings']['optimal_threshold'].keys()
    vote_structures = [i for i in vote_structures if (i in atlas_structure_list)]
    for structure_name in vote_structures:
        probability_map = combined_label_dict[structure_name]
        optimal_threshold = settings['label_fusion_settings']['optimal_threshold'][structure_name]
        binary_struct = process_probability_image(probability_map, optimal_threshold)
        if return_as_cropped:
            results[structure_name] = binary_struct
            if settings['return_proba_as_contours']:
                atlas_contours = [(atlas_set[atlas_id]['DIR'][structure_name] >= 2) for atlas_id in atlas_id_list]
                results_prob[structure_name] = binary_encode_structure_list(atlas_contours)
            else:
                results_prob[structure_name] = probability_map
            if ((not settings['return_atlas_guide_structure']) and (guide_structure is not None)):
                results[guide_structure_name] = guide_structure
                results_prob[guide_structure_name] = guide_structure
        else:
            if settings['return_proba_as_contours']:
                atlas_contours = [(atlas_set[atlas_id]['DIR'][structure_name] >= 2) for atlas_id in atlas_id_list]
                probability_img = binary_encode_structure_list(atlas_contours)
                template_img_prob = sitk.Cast((img * 0), sitk.sitkUInt32)
            else:
                probability_img = probability_map
            paste_img_binary = sitk.Paste(template_img_binary, binary_struct, binary_struct.GetSize(), (0, 0, 0), crop_box_index)
            results[structure_name] = paste_img_binary
            paste_prob_img = sitk.Paste(template_img_prob, probability_img, probability_img.GetSize(), (0, 0, 0), crop_box_index)
            results_prob[structure_name] = paste_prob_img
            if ((not settings['return_atlas_guide_structure']) and (guide_structure is not None)):
                new_guide_structure = sitk.Paste(template_img_binary, guide_structure, guide_structure.GetSize(), (0, 0, 0), crop_box_index)
                results[guide_structure_name] = new_guide_structure
                results_prob[guide_structure_name] = new_guide_structure
    for structure_name in vessel_spline_settings['vessel_name_list']:
        binary_struct = segmented_vessel_dict[structure_name]
        if return_as_cropped:
            results[structure_name] = binary_struct
            vessel_list = [atlas_set[atlas_id]['DIR'][structure_name] for atlas_id in list(atlas_set.keys())]
        else:
            paste_img_binary = sitk.Paste(template_img_binary, binary_struct, binary_struct.GetSize(), (0, 0, 0), crop_box_index)
            results[structure_name] = paste_img_binary
            vessel_list = []
            for atlas_id in list(atlas_set.keys()):
                paste_img_binary = sitk.Paste(template_img_binary, atlas_set[atlas_id]['DIR'][structure_name], atlas_set[atlas_id]['DIR'][structure_name].GetSize(), (0, 0, 0), crop_box_index)
                vessel_list.append(paste_img_binary)
        encoded_vessels = binary_encode_structure_list(vessel_list)
        results_prob[structure_name] = encoded_vessels
    '\n    Step 7 - Geometric definitions of cardiac valves and conduction system nodes\n    '
    geometric_segmentation_settings = settings['geometric_segmentation_settings']
    if geometric_segmentation_settings['run_geometric_algorithms']:
        logger.info('Computing geometric definitions for valves and conduction system.')
        geom_atlas_names = geometric_segmentation_settings['atlas_structure_names']
        geom_valve_defs = geometric_segmentation_settings['valve_definitions']
        geom_conduction_defs = geometric_segmentation_settings['conduction_system_definitions']
        mv_name = ('MITRALVALVE' + geometric_segmentation_settings['geometric_name_suffix'])
        results[mv_name] = generate_valve_using_cylinder(label_atrium=results[geom_atlas_names['atlas_left_atrium']], label_ventricle=results[geom_atlas_names['atlas_left_ventricle']], radius_mm=geom_valve_defs['mitral_valve_radius_mm'], height_mm=geom_valve_defs['mitral_valve_thickness_mm'])
        tv_name = ('TRICUSPIDVALVE' + geometric_segmentation_settings['geometric_name_suffix'])
        results[tv_name] = generate_valve_using_cylinder(label_atrium=results[geom_atlas_names['atlas_right_atrium']], label_ventricle=results[geom_atlas_names['atlas_right_ventricle']], radius_mm=geom_valve_defs['tricuspid_valve_radius_mm'], height_mm=geom_valve_defs['tricuspid_valve_thickness_mm'])
        av_name = ('AORTICVALVE' + geometric_segmentation_settings['geometric_name_suffix'])
        results[av_name] = generate_valve_from_great_vessel(label_great_vessel=results[geom_atlas_names['atlas_ascending_aorta']], label_ventricle=results[geom_atlas_names['atlas_left_ventricle']], valve_thickness_mm=geom_valve_defs['aortic_valve_thickness_mm'])
        pv_name = ('PULMONICVALVE' + geometric_segmentation_settings['geometric_name_suffix'])
        results[pv_name] = generate_valve_from_great_vessel(label_great_vessel=results[geom_atlas_names['atlas_pulmonary_artery']], label_ventricle=results[geom_atlas_names['atlas_right_ventricle']], valve_thickness_mm=geom_valve_defs['pulmonic_valve_thickness_mm'])
        san_name = ('SAN' + geometric_segmentation_settings['geometric_name_suffix'])
        results[san_name] = geometric_sinoatrialnode(label_svc=results[geom_atlas_names['atlas_superior_vena_cava']], label_ra=results[geom_atlas_names['atlas_right_atrium']], label_wholeheart=results[geom_atlas_names['atlas_whole_heart']], radius_mm=geom_conduction_defs['sinoatrial_node_radius_mm'])
        avn_name = ('AVN' + geometric_segmentation_settings['geometric_name_suffix'])
        results[avn_name] = geometric_atrioventricularnode(label_la=results[geom_atlas_names['atlas_left_atrium']], label_lv=results[geom_atlas_names['atlas_left_ventricle']], label_ra=results[geom_atlas_names['atlas_right_atrium']], label_rv=results[geom_atlas_names['atlas_right_ventricle']], radius_mm=geom_conduction_defs['atrioventricular_node_radius_mm'])
    '\n    Step 8 - Post-processing\n    '
    postprocessing_settings = settings['postprocessing_settings']
    if postprocessing_settings['run_postprocessing']:
        logger.info('Running post-processing.')
        binaryfillhole_img = [int((postprocessing_settings['binaryfillhole_mm'] / sp)) for sp in img.GetSpacing()]
        for structure_name in postprocessing_settings['structures_for_binaryfillhole']:
            if (structure_name not in results.keys()):
                continue
            contour_s = results[structure_name]
            contour_s = (sitk.RelabelComponent(sitk.ConnectedComponent(contour_s)) == 1)
            contour_s = sitk.BinaryMorphologicalClosing(contour_s, binaryfillhole_img)
            results[structure_name] = contour_s
        input_overlap = {s: results[s] for s in postprocessing_settings['structures_for_overlap_correction']}
        output_overlap = correct_volume_overlap(input_overlap)
        for s in postprocessing_settings['structures_for_overlap_correction']:
            results[s] = output_overlap[s]
    if return_as_cropped:
        results['CROP_IMAGE'] = img_crop
    logger.info('Done!')
    return (results, results_prob)
Runs the atlas-based cardiac segmentation

Args:
    img (sitk.Image):
    settings (dict, optional): Dictionary containing settings for algorithm.
                               Defaults to default_settings.

Returns:
    dict: Dictionary containing output of segmentation
def run_cardiac_segmentation(img, guide_structure=None, settings=CARDIAC_SETTINGS_DEFAULTS):
    'Runs the atlas-based cardiac segmentation\n\n    Args:\n        img (sitk.Image):\n        settings (dict, optional): Dictionary containing settings for algorithm.\n                                   Defaults to default_settings.\n\n    Returns:\n        dict: Dictionary containing output of segmentation\n    '
    results = {}
    results_prob = {}
    return_as_cropped = settings['return_as_cropped']
    "\n    Initialisation - Read in atlases\n    - image files\n    - structure files\n\n        Atlas structure:\n        'ID': 'Original': 'CT Image'    : sitk.Image\n                            'Struct A'    : sitk.Image\n                            'Struct B'    : sitk.Image\n                'RIR'     : 'CT Image'    : sitk.Image\n                            'Transform'   : transform parameter map\n                            'Struct A'    : sitk.Image\n                            'Struct B'    : sitk.Image\n                'DIR'     : 'CT Image'    : sitk.Image\n                            'Transform'   : displacement field transform\n                            'Weight Map'  : sitk.Image\n                            'Struct A'    : sitk.Image\n                            'Struct B'    : sitk.Image\n\n\n    "
    logger.info()
    atlas_path = settings['atlas_settings']['atlas_path']
    atlas_id_list = settings['atlas_settings']['atlas_id_list']
    atlas_structure_list = settings['atlas_settings']['atlas_structure_list']
    atlas_image_format = settings['atlas_settings']['atlas_image_format']
    atlas_label_format = settings['atlas_settings']['atlas_label_format']
    crop_atlas_to_structures = settings['atlas_settings']['crop_atlas_to_structures']
    crop_atlas_expansion_mm = settings['atlas_settings']['crop_atlas_expansion_mm']
    atlas_set = {}
    for atlas_id in atlas_id_list:
        atlas_set[atlas_id] = {}
        atlas_set[atlas_id]['Original'] = {}
        image = sitk.ReadImage(f'{atlas_path}/{atlas_image_format.format(atlas_id)}')
        structures = {struct: sitk.ReadImage(f'{atlas_path}/{atlas_label_format.format(atlas_id, struct)}') for struct in atlas_structure_list}
        if crop_atlas_to_structures:
            logger.info(f'Automatically cropping atlas: {atlas_id}')
            original_volume = np.product(image.GetSize())
            (crop_box_size, crop_box_index) = label_to_roi(structures.values(), expansion_mm=crop_atlas_expansion_mm)
            image = crop_to_roi(image, size=crop_box_size, index=crop_box_index)
            final_volume = np.product(image.GetSize())
            logger.info(f'  > Volume reduced by factor {(original_volume / final_volume):.2f}')
            for struct in atlas_structure_list:
                structures[struct] = crop_to_roi(structures[struct], size=crop_box_size, index=crop_box_index)
        atlas_set[atlas_id]['Original']['CT Image'] = image
        for struct in atlas_structure_list:
            atlas_set[atlas_id]['Original'][struct] = structures[struct]
    '\n    Step 1 - Automatic cropping\n    If we have a guide structure:\n        - use structure to crop target image\n\n    Otherwise:\n        - using a quick registration to register each atlas\n        - expansion of the bounding box to ensure entire volume of interest is enclosed\n        - target image is cropped\n    '
    expansion_mm = settings['auto_crop_target_image_settings']['expansion_mm']
    if guide_structure:
        (crop_box_size, crop_box_index) = label_to_roi(guide_structure, expansion_mm=expansion_mm)
        img_crop = crop_to_roi(img, crop_box_size, crop_box_index)
        guide_structure = crop_to_roi(guide_structure, crop_box_size, crop_box_index)
        target_reg_structure = convert_mask_to_reg_structure(guide_structure, expansion=2)
    else:
        quick_reg_settings = {'reg_method': 'similarity', 'shrink_factors': [8], 'smooth_sigmas': [0], 'sampling_rate': 0.75, 'default_value': (- 1000), 'number_of_iterations': 25, 'final_interp': sitk.sitkLinear, 'metric': 'mean_squares', 'optimiser': 'gradient_descent_line_search'}
        registered_crop_images = []
        logger.info('Running initial Translation tranform to crop image volume')
        for atlas_id in atlas_id_list[:min([8, len(atlas_id_list)])]:
            logger.info(f'  > atlas {atlas_id}')
            atlas_set[atlas_id]['RIR'] = {}
            atlas_image = atlas_set[atlas_id]['Original']['CT Image']
            (reg_image, _) = linear_registration(img, atlas_image, **quick_reg_settings)
            registered_crop_images.append(sitk.Cast(reg_image, sitk.sitkFloat32))
            del reg_image
        combined_image = ((sum(registered_crop_images) / len(registered_crop_images)) > (- 1000))
        (crop_box_size, crop_box_index) = label_to_roi(combined_image, expansion_mm=expansion_mm)
        img_crop = crop_to_roi(img, crop_box_size, crop_box_index)
    logger.info('Calculated crop box:')
    logger.info(f'  > {crop_box_index}')
    logger.info(f'  > {crop_box_size}')
    logger.info(f'  > Vol reduction = {(np.product(img.GetSize()) / np.product(crop_box_size)):.2f}')
    '\n    Step 2 - Rigid registration of target images\n    - Individual atlas images are registered to the target\n    - The transformation is used to propagate the labels onto the target\n    '
    linear_registration_settings = settings['linear_registration_settings']
    logger.info(f"Running {linear_registration_settings['reg_method']} tranform to align atlas images")
    for atlas_id in atlas_id_list:
        logger.info(f'  > atlas {atlas_id}')
        atlas_set[atlas_id]['RIR'] = {}
        if guide_structure:
            guide_structure_name = settings['atlas_settings']['guide_structure_name']
            target_reg_image = target_reg_structure
            atlas_reg_image = convert_mask_to_reg_structure(atlas_set[atlas_id]['Original'][guide_structure_name], expansion=2)
        else:
            target_reg_image = img_crop
            atlas_reg_image = atlas_set[atlas_id]['Original']['CT Image']
        (_, initial_tfm) = linear_registration(target_reg_image, atlas_reg_image, **linear_registration_settings)
        atlas_set[atlas_id]['RIR']['Transform'] = initial_tfm
        if guide_structure:
            atlas_set[atlas_id]['RIR']['Reg Mask'] = apply_transform(input_image=atlas_reg_image, reference_image=img_crop, transform=initial_tfm, default_value=0, interpolator=sitk.sitkLinear)
            expanded_atlas_guide_structure = extend_mask(atlas_set[atlas_id]['Original'][guide_structure_name], direction=('ax', 'sup'), extension_mm=settings['atlas_settings']['superior_extension'], interior_mm_shape=(settings['atlas_settings']['superior_extension'] / 2))
            atlas_set[atlas_id]['RIR'][(guide_structure_name + 'EXPANDED')] = apply_transform(input_image=expanded_atlas_guide_structure, reference_image=img_crop, transform=initial_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
        atlas_set[atlas_id]['RIR']['CT Image'] = apply_transform(input_image=atlas_set[atlas_id]['Original']['CT Image'], reference_image=img_crop, transform=initial_tfm, default_value=(- 1000), interpolator=sitk.sitkLinear)
        for struct in atlas_structure_list:
            input_struct = atlas_set[atlas_id]['Original'][struct]
            atlas_set[atlas_id]['RIR'][struct] = apply_transform(input_image=input_struct, reference_image=img_crop, transform=initial_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
        atlas_set[atlas_id]['Original'] = None
    '\n    Step 3 - Deformable image registration\n    - Using Fast Symmetric Diffeomorphic Demons\n    '
    if guide_structure:
        structure_guided_registration_settings = settings['structure_guided_registration_settings']
        logger.info('Running structure-guided deformable registration on atlas labels')
        for atlas_id in atlas_id_list:
            logger.info(f'  > atlas {atlas_id}')
            atlas_set[atlas_id]['DIR_STRUCT'] = {}
            (deform_image, struct_guided_tfm, _) = fast_symmetric_forces_demons_registration(target_reg_structure, atlas_set[atlas_id]['RIR']['Reg Mask'], **structure_guided_registration_settings)
            atlas_set[atlas_id]['DIR_STRUCT']['Reg Mask'] = deform_image
            atlas_set[atlas_id]['DIR_STRUCT']['Transform'] = struct_guided_tfm
            atlas_set[atlas_id]['DIR_STRUCT']['CT Image'] = apply_transform(input_image=atlas_set[atlas_id]['RIR']['CT Image'], transform=struct_guided_tfm, default_value=(- 1000), interpolator=sitk.sitkLinear)
            atlas_set[atlas_id]['DIR_STRUCT'][(guide_structure_name + 'EXPANDED')] = apply_transform(input_image=atlas_set[atlas_id]['RIR'][(guide_structure_name + 'EXPANDED')], reference_image=img_crop, transform=struct_guided_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
            for struct in atlas_structure_list:
                input_struct = atlas_set[atlas_id]['RIR'][struct]
                atlas_set[atlas_id]['DIR_STRUCT'][struct] = apply_transform(input_image=input_struct, transform=struct_guided_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
            atlas_set[atlas_id]['RIR'] = None
    deformable_registration_settings = settings['deformable_registration_settings']
    logger.info('Running DIR to refine atlas image registration')
    for atlas_id in atlas_id_list:
        logger.info(f'  > atlas {atlas_id}')
        atlas_set[atlas_id]['DIR'] = {}
        if guide_structure:
            label = 'DIR_STRUCT'
        else:
            label = 'RIR'
        atlas_reg_image = atlas_set[atlas_id][label]['CT Image']
        target_reg_image = img_crop
        if guide_structure:
            expanded_atlas_mask = atlas_set[atlas_id]['DIR_STRUCT'][(guide_structure_name + 'EXPANDED')]
            expanded_target_mask = extend_mask(guide_structure, direction=('ax', 'sup'), extension_mm=settings['atlas_settings']['superior_extension'], interior_mm_shape=(settings['atlas_settings']['superior_extension'] / 2))
            combined_mask = sitk.Maximum(expanded_atlas_mask, expanded_target_mask)
            atlas_reg_image = sitk.Mask(atlas_reg_image, combined_mask, outsideValue=(- 1000))
            atlas_reg_image = sitk.Mask(atlas_reg_image, (atlas_reg_image > (- 400)), outsideValue=(- 1000))
            target_reg_image = sitk.Mask(target_reg_image, combined_mask, outsideValue=(- 1000))
            target_reg_image = sitk.Mask(target_reg_image, (atlas_reg_image > (- 400)), outsideValue=(- 1000))
        (deform_image, dir_tfm, _) = fast_symmetric_forces_demons_registration(target_reg_image, atlas_reg_image, **deformable_registration_settings)
        atlas_set[atlas_id]['DIR']['Transform'] = dir_tfm
        atlas_set[atlas_id]['DIR']['CT Image'] = apply_transform(input_image=atlas_set[atlas_id][label]['CT Image'], transform=dir_tfm, default_value=(- 1000), interpolator=sitk.sitkLinear)
        for struct in atlas_structure_list:
            input_struct = atlas_set[atlas_id][label][struct]
            atlas_set[atlas_id]['DIR'][struct] = apply_transform(input_image=input_struct, transform=dir_tfm, default_value=0, interpolator=sitk.sitkNearestNeighbor)
        atlas_set[atlas_id][label] = None
    '\n    Step 4 - Iterative atlas removal\n    - This is an automatic process that will attempt to remove inconsistent atlases from the entire set\n\n    '
    iar_settings = settings['iar_settings']
    if iar_settings['reference_structure']:
        for atlas_id in atlas_id_list:
            atlas_image = atlas_set[atlas_id]['DIR']['CT Image']
            weight_map = compute_weight_map(img_crop, atlas_image, vote_type='global')
            atlas_set[atlas_id]['DIR']['Weight Map'] = weight_map
        atlas_set = run_iar(atlas_set=atlas_set, **iar_settings)
    else:
        logger.info('IAR: No reference structure, skipping iterative atlas removal.')
    '\n    Step 4 - Vessel Splining\n\n    '
    vessel_spline_settings = settings['vessel_spline_settings']
    if (len(vessel_spline_settings['vessel_name_list']) > 0):
        segmented_vessel_dict = vessel_spline_generation(img_crop, atlas_set, **vessel_spline_settings)
    else:
        logger.info('No vessel splining required, continue.')
    '\n    Step 5 - Label Fusion\n    '
    vote_type = settings['label_fusion_settings']['vote_type']
    vote_params = settings['label_fusion_settings']['vote_params']
    for atlas_id in list(atlas_set.keys()):
        atlas_image = atlas_set[atlas_id]['DIR']['CT Image']
        weight_map = compute_weight_map(img_crop, atlas_image, vote_type=vote_type, vote_params=vote_params)
        atlas_set[atlas_id]['DIR']['Weight Map'] = weight_map
    combined_label_dict = combine_labels(atlas_set, atlas_structure_list)
    '\n    Step 6 - Paste the cropped structure into the original image space\n    '
    logger.info('Generating binary segmentations.')
    template_img_binary = sitk.Cast((img * 0), sitk.sitkUInt8)
    template_img_prob = sitk.Cast((img * 0), sitk.sitkFloat64)
    vote_structures = settings['label_fusion_settings']['optimal_threshold'].keys()
    vote_structures = [i for i in vote_structures if (i in atlas_structure_list)]
    for structure_name in vote_structures:
        probability_map = combined_label_dict[structure_name]
        optimal_threshold = settings['label_fusion_settings']['optimal_threshold'][structure_name]
        binary_struct = process_probability_image(probability_map, optimal_threshold)
        if return_as_cropped:
            results[structure_name] = binary_struct
            if settings['return_proba_as_contours']:
                atlas_contours = [(atlas_set[atlas_id]['DIR'][structure_name] >= 2) for atlas_id in atlas_id_list]
                results_prob[structure_name] = binary_encode_structure_list(atlas_contours)
            else:
                results_prob[structure_name] = probability_map
            if ((not settings['return_atlas_guide_structure']) and (guide_structure is not None)):
                results[guide_structure_name] = guide_structure
                results_prob[guide_structure_name] = guide_structure
        else:
            if settings['return_proba_as_contours']:
                atlas_contours = [(atlas_set[atlas_id]['DIR'][structure_name] >= 2) for atlas_id in atlas_id_list]
                probability_img = binary_encode_structure_list(atlas_contours)
                template_img_prob = sitk.Cast((img * 0), sitk.sitkUInt32)
            else:
                probability_img = probability_map
            paste_img_binary = sitk.Paste(template_img_binary, binary_struct, binary_struct.GetSize(), (0, 0, 0), crop_box_index)
            results[structure_name] = paste_img_binary
            paste_prob_img = sitk.Paste(template_img_prob, probability_img, probability_img.GetSize(), (0, 0, 0), crop_box_index)
            results_prob[structure_name] = paste_prob_img
            if ((not settings['return_atlas_guide_structure']) and (guide_structure is not None)):
                new_guide_structure = sitk.Paste(template_img_binary, guide_structure, guide_structure.GetSize(), (0, 0, 0), crop_box_index)
                results[guide_structure_name] = new_guide_structure
                results_prob[guide_structure_name] = new_guide_structure
    for structure_name in vessel_spline_settings['vessel_name_list']:
        binary_struct = segmented_vessel_dict[structure_name]
        if return_as_cropped:
            results[structure_name] = binary_struct
            vessel_list = [atlas_set[atlas_id]['DIR'][structure_name] for atlas_id in list(atlas_set.keys())]
        else:
            paste_img_binary = sitk.Paste(template_img_binary, binary_struct, binary_struct.GetSize(), (0, 0, 0), crop_box_index)
            results[structure_name] = paste_img_binary
            vessel_list = []
            for atlas_id in list(atlas_set.keys()):
                paste_img_binary = sitk.Paste(template_img_binary, atlas_set[atlas_id]['DIR'][structure_name], atlas_set[atlas_id]['DIR'][structure_name].GetSize(), (0, 0, 0), crop_box_index)
                vessel_list.append(paste_img_binary)
        encoded_vessels = binary_encode_structure_list(vessel_list)
        results_prob[structure_name] = encoded_vessels
    '\n    Step 7 - Geometric definitions of cardiac valves and conduction system nodes\n    '
    geometric_segmentation_settings = settings['geometric_segmentation_settings']
    if geometric_segmentation_settings['run_geometric_algorithms']:
        logger.info('Computing geometric definitions for valves and conduction system.')
        geom_atlas_names = geometric_segmentation_settings['atlas_structure_names']
        geom_valve_defs = geometric_segmentation_settings['valve_definitions']
        geom_conduction_defs = geometric_segmentation_settings['conduction_system_definitions']
        mv_name = ('MITRALVALVE' + geometric_segmentation_settings['geometric_name_suffix'])
        results[mv_name] = generate_valve_using_cylinder(label_atrium=results[geom_atlas_names['atlas_left_atrium']], label_ventricle=results[geom_atlas_names['atlas_left_ventricle']], radius_mm=geom_valve_defs['mitral_valve_radius_mm'], height_mm=geom_valve_defs['mitral_valve_thickness_mm'])
        tv_name = ('TRICUSPIDVALVE' + geometric_segmentation_settings['geometric_name_suffix'])
        results[tv_name] = generate_valve_using_cylinder(label_atrium=results[geom_atlas_names['atlas_right_atrium']], label_ventricle=results[geom_atlas_names['atlas_right_ventricle']], radius_mm=geom_valve_defs['tricuspid_valve_radius_mm'], height_mm=geom_valve_defs['tricuspid_valve_thickness_mm'])
        av_name = ('AORTICVALVE' + geometric_segmentation_settings['geometric_name_suffix'])
        results[av_name] = generate_valve_from_great_vessel(label_great_vessel=results[geom_atlas_names['atlas_ascending_aorta']], label_ventricle=results[geom_atlas_names['atlas_left_ventricle']], valve_thickness_mm=geom_valve_defs['aortic_valve_thickness_mm'])
        pv_name = ('PULMONICVALVE' + geometric_segmentation_settings['geometric_name_suffix'])
        results[pv_name] = generate_valve_from_great_vessel(label_great_vessel=results[geom_atlas_names['atlas_pulmonary_artery']], label_ventricle=results[geom_atlas_names['atlas_right_ventricle']], valve_thickness_mm=geom_valve_defs['pulmonic_valve_thickness_mm'])
        san_name = ('SAN' + geometric_segmentation_settings['geometric_name_suffix'])
        results[san_name] = geometric_sinoatrialnode(label_svc=results[geom_atlas_names['atlas_superior_vena_cava']], label_ra=results[geom_atlas_names['atlas_right_atrium']], label_wholeheart=results[geom_atlas_names['atlas_whole_heart']], radius_mm=geom_conduction_defs['sinoatrial_node_radius_mm'])
        avn_name = ('AVN' + geometric_segmentation_settings['geometric_name_suffix'])
        results[avn_name] = geometric_atrioventricularnode(label_la=results[geom_atlas_names['atlas_left_atrium']], label_lv=results[geom_atlas_names['atlas_left_ventricle']], label_ra=results[geom_atlas_names['atlas_right_atrium']], label_rv=results[geom_atlas_names['atlas_right_ventricle']], radius_mm=geom_conduction_defs['atrioventricular_node_radius_mm'])
    '\n    Step 8 - Post-processing\n    '
    postprocessing_settings = settings['postprocessing_settings']
    if postprocessing_settings['run_postprocessing']:
        logger.info('Running post-processing.')
        binaryfillhole_img = [int((postprocessing_settings['binaryfillhole_mm'] / sp)) for sp in img.GetSpacing()]
        for structure_name in postprocessing_settings['structures_for_binaryfillhole']:
            if (structure_name not in results.keys()):
                continue
            contour_s = results[structure_name]
            contour_s = (sitk.RelabelComponent(sitk.ConnectedComponent(contour_s)) == 1)
            contour_s = sitk.BinaryMorphologicalClosing(contour_s, binaryfillhole_img)
            results[structure_name] = contour_s
        input_overlap = {s: results[s] for s in postprocessing_settings['structures_for_overlap_correction']}
        output_overlap = correct_volume_overlap(input_overlap)
        for s in postprocessing_settings['structures_for_overlap_correction']:
            results[s] = output_overlap[s]
    if return_as_cropped:
        results['CROP_IMAGE'] = img_crop
    logger.info('Done!')
    return (results, results_prob)