Learning-based segmentation of diffusion-weighted MR images with arbitrary <i>q</i>-space samplings.
The 11 matches · 2 of them tie a paragraph to a whole file, not to given lines: weak matches, whose lines are not tinted
- [1] § Materials and Methods › Data › Preprocessing › Reference segmentations ↔ DISCUSseg/data_loader/dkt_labels.py, lines 1–23 · score 0.69 · Desikan Killiany Tourville, DKT, FreeSurfer, mapping
- [2] § Materials and Methods › Evaluation › Labels ↔ data_loader/load_neuroimaging_data.py, lines 405–520 · score 0.69 · corpus callosum, cortical region, hemisphere, hypointensities, lateral, ventricles
- [3] § Materials and Methods › Method › Architecture › Details ↔ DISCUSseg/run_prediction.py, lines 178–297 · score 0.63 · brain mask, DISCUS encoder, sagittal, axial, memory, inference
- [4] § Materials and Methods › Method › Architecture › Details ↔ DISCUSseg/data_loader/discus_preprocessing.py, the whole file · a weak match · score 0.63 · brain mask, DISCUS encoder, inside, width, inference, volume
- [5] § Materials and Methods › Method › Training › Phase 1: DISCUS pre-training ↔ DISCUSseg/train.py, lines 171–242 · score 0.62 · DISCUS reconstructs, train DISCUS, DISCUS encoder, decoder, loss, signals
- [6] § Materials and Methods › Method › Training › Phase 1: DISCUS pre-training ↔ DISCUSseg/data_loader/discus_preprocessing.py, the whole file · a weak match · score 0.59 · DISCUS reconstructs, DISCUS encoder, subsets, decoder, loss, signals
- [7] § Materials and Methods › Reference methods › SynthSeg ↔ process.sh, lines 1–59 · score 0.54 · fractional anisotropy, diffusion tensor, FA, fitted, brain, mask
- [8] § Materials and Methods › Data › Preprocessing › Masks ↔ DISCUSseg/run_prediction.py, lines 319–407 · score 0.54 · brain mask, FSL, binary, probability, inference, maps
- [9] § Materials and Methods › Reference methods › DDParcel ↔ process.sh, lines 1–59 · score 0.52 · fractional anisotropy, diffusion tensor, eigenvalues, brain, masking, .2
- [10] § Materials and Methods › Method › Training › Alternative training schemes › Multi-task training for segmentation and reconstruction ↔ DISCUSseg/train.py, lines 171–242 · score 0.52 · DISCUS encoder, rotation, embeddings, reconstruction, decoder, augmented
- [11] § Materials and Methods › Data › Preprocessing › Reference segmentations ↔ data_loader/load_neuroimaging_data.py, lines 405–520 · score 0.51 · corpus callosum, vessels, DKT, cortical, mapping, segmentations
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 987 lines · 36 KB · Unlicense · 2 matches
- # Copyright 2019 Image Analysis Lab, German Center for Neurodegenerative Diseases (DZNE), Bonn
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- # IMPORTS
- import nibabel as nib
- import numpy as np
- import h5py
- import scipy.ndimage.morphology as morphology
- import scipy.ndimage as ndimage
- import scipy.ndimage.filters as filters
- import sys
- import glob, os
- from skimage.measure import label
- from torch.utils.data.dataset import Dataset
- from .conform import is_conform, conform, check_affine_in_nifti
- ##
- # Helper Functions
- ##
- # Conform an MRI brain image to UCHAR, RAS orientation, and 1mm isotropic voxels
- def load_and_conform_image(img_filename, interpol=1, logger=None, imagetype='image'):
- """
- Function to load MRI image and conform it to UCHAR, RAS orientation and 1mm isotropic voxels size
- (if it does not already have this format)
- :param str img_filename: path and name of volume to read
- :param int interpol: interpolation order for image conformation (0=nearest,1=linear(default),2=quadratic,3=cubic)
- :return:
- """
- orig = nib.load(img_filename)
- if not is_conform(orig):
- if logger is not None:
- logger.info('Conforming image to UCHAR, RAS orientation, and 1mm isotropic voxels')
- else:
- print('Conforming image to RAS orientation, and 1mm isotropic voxels')
- if len(orig.shape) > 3 and orig.shape[3] != 1:
- sys.exit('ERROR: Multiple input frames (' + format(orig.shape[3]) + ') not supported!')
- # Check affine if image is nifti image
- if img_filename[-7:] == ".nii.gz" or img_filename[-4:] == ".nii":
- if not check_affine_in_nifti(orig, logger=logger):
- sys.exit("ERROR: inconsistency in nifti-header. Exiting now.\n")
- # conform
- orig = conform(orig, interpol, imagetype=imagetype)
- # Collect header and affine information
- header_info = orig.header
- affine_info = orig.affine
- orig = np.asarray(orig.get_fdata(), dtype=np.float32)
- return header_info, affine_info, orig
- def cropparameters(orig_, img_filename):
- data = orig_.get_fdata()
- # Transformation for mapping
- def transform_axial(vol, coronal2axial=True):
- """
- Function to transform volume into Axial axis and back
- :param np.ndarray vol: image volume to transform
- :param bool coronal2axial: transform from coronal to axial = True (default),
- transform from axial to coronal = False
- :return:
- """
- if coronal2axial:
- return np.moveaxis(vol, [0, 1, 2], [1, 2, 0])
- else:
- return np.moveaxis(vol, [0, 1, 2], [2, 0, 1])
- def transform_sagittal(vol, coronal2sagittal=True):
- """
- Function to transform volume into Sagittal axis and back
- :param np.ndarray vol: image volume to transform
- :param bool coronal2sagittal: transform from coronal to sagittal = True (default),
- transform from sagittal to coronal = False
- :return:
- """
- if coronal2sagittal:
- return np.moveaxis(vol, [0, 1, 2], [2, 1, 0])
- else:
- return np.moveaxis(vol, [0, 1, 2], [2, 1, 0])
- # Thick slice generator (for eval) and blank slices filter (for training)
- def get_thick_slices(img_data, slice_thickness=3):
- """
- Function to extract thick slices from the image
- (feed slice_thickness preceeding and suceeding slices to network,
- label only middle one)
- :param np.ndarray img_data: 3D MRI image read in with nibabel
- :param int slice_thickness: number of slices to stack on top and below slice of interest (default=3)
- :return:
- """
- h, w, d = img_data.shape
- img_data_pad = np.expand_dims(np.pad(img_data, ((0, 0), (0, 0), (slice_thickness, slice_thickness)), mode='edge'),
- axis=3)
- img_data_thick = np.ndarray((h, w, d, 0), dtype=np.uint8)
- for slice_idx in range(2 * slice_thickness + 1):
- img_data_thick = np.append(img_data_thick, img_data_pad[:, :, slice_idx:d + slice_idx, :], axis=3)
- return img_data_thick
- def filter_blank_slices_thick(img_vol, label_vol, weight_vol, threshold=50):
- """
- Function to filter blank slices from the volume using the label volume
- :param np.ndarray img_vol: orig image volume
- :param np.ndarray label_vol: label images (ground truth)
- :param np.ndarray weight_vol: weight corresponding to labels
- :param int threshold: threshold for number of pixels needed to keep slice (below = dropped)
- :return:
- """
- # Get indices of all slices with more than threshold labels/pixels
- select_slices = (np.sum(label_vol, axis=(0, 1)) > threshold)
- # Retain only slices with more than threshold labels/pixels
- img_vol = img_vol[:, :, select_slices, :]
- label_vol = label_vol[:, :, select_slices]
- weight_vol = weight_vol[:, :, select_slices]
- return img_vol, label_vol, weight_vol
- # weight map generator
- def create_weight_mask(mapped_aseg, max_weight=5, max_edge_weight=5):
- """
- Function to create weighted mask - with median frequency balancing and edge-weighting
- :param mapped_aseg:
- :param max_weight:
- :param max_edge_weight:
- :return:
- """
- unique, counts = np.unique(mapped_aseg, return_counts=True)
- # Median Frequency Balancing
- class_wise_weights = np.median(counts) / counts
- class_wise_weights[class_wise_weights > max_weight] = max_weight
- (h, w, d) = mapped_aseg.shape
- weights_mask = np.reshape(class_wise_weights[mapped_aseg.ravel()], (h, w, d))
- # Gradient Weighting
- (gx, gy, gz) = np.gradient(mapped_aseg)
- grad_weight = max_edge_weight * np.asarray(np.power(np.power(gx, 2) + np.power(gy, 2) + np.power(gz, 2), 0.5) > 0,
- dtype=np.float32)
- weights_mask += grad_weight
- return weights_mask
- # class unknown filler (cortex)
- def fill_unknown_labels_per_hemi(gt, unknown_label, cortex_stop):
- """
- Function to replace label 1000 (lh unknown) and 2000 (rh unknown) with closest class for each voxel.
- :param np.ndarray gt: ground truth segmentation with class unknown
- :param int unknown_label: class label for unknown (lh: 1000, rh: 2000)
- :param int cortex_stop: class label at which cortical labels of this hemi stop (lh: 2000, rh: 3000)
- :return:
- """
- # Define shape of image and dilation element
- h, w, d = gt.shape
- struct1 = ndimage.generate_binary_structure(3, 2)
- # Get indices of unknown labels, dilate them to get closest sorrounding parcels
- unknown = gt == unknown_label
- unknown = (morphology.binary_dilation(unknown, struct1) ^ unknown)
- list_parcels = np.unique(gt[unknown])
- # Mask all subcortical structures (fill unknown with closest cortical parcels only)
- mask = (list_parcels > unknown_label) & (list_parcels < cortex_stop)
- list_parcels = list_parcels[mask]
- # For each closest parcel, blur label with gaussian filter (spread), append resulting blurred images
- blur_vals = np.ndarray((h, w, d, 0), dtype=np.float32)
- for idx in range(len(list_parcels)):
- aseg_blur = filters.gaussian_filter(1000 * np.asarray(gt == list_parcels[idx], dtype=np.float32), sigma=5)
- blur_vals = np.append(blur_vals, np.expand_dims(aseg_blur, axis=3), axis=3)
- # Get for each position parcel with maximum value after blurring (= closest parcel)
- unknown = np.argmax(blur_vals, axis=3)
- unknown = np.reshape(list_parcels[unknown.ravel()], (h, w, d))
- # Assign the determined closest parcel to the unknown class (case-by-case basis)
- mask = gt == unknown_label
- gt[mask] = unknown[mask]
- return gt
- # class unknown filler (cortex)
- def fill_WMhyper_per_hemi(gt, WMhyper_label=77, replace_labels=[2, 41]):
- """
- Function to replace label 1000 (lh unknown) and 2000 (rh unknown) with closest class for each voxel.
- :param np.ndarray gt: ground truth segmentation with class unknown
- :param int WMhyper_label: class label for unknown: 77
- :param int cortex_stop: class label at which cortical labels of this hemi stop (lh: 2000, rh: 3000)
- :return:
- """
- # Define shape of image and dilation element
- h, w, d = gt.shape
- struct1 = ndimage.generate_binary_structure(3, 2)
- # Get indices of unknown labels, dilate them to get closest sorrounding parcels
- unknown = gt == WMhyper_label
- if np.sum(unknown) == 0:
- return gt
- unknown = (morphology.binary_dilation(unknown, struct1) ^ unknown)
- list_parcels = np.unique(gt[unknown])
- if np.intersect1d(list_parcels, replace_labels).shape[0] > 0:
- list_parcels = np.intersect1d(list_parcels, replace_labels)
- # For each closest parcel, blur label with gaussian filter (spread), append resulting blurred images
- blur_vals = np.ndarray((h, w, d, 0), dtype=np.float32)
- for idx in range(len(list_parcels)):
- aseg_blur = filters.gaussian_filter(1000 * np.asarray(gt == list_parcels[idx], dtype=np.float32), sigma=5)
- blur_vals = np.append(blur_vals, np.expand_dims(aseg_blur, axis=3), axis=3)
- # Get for each position parcel with maximum value after blurring (= closest parcel)
- unknown = np.argmax(blur_vals, axis=3)
- unknown = np.reshape(list_parcels[unknown.ravel()], (h, w, d))
- # Assign the determined closest parcel to the unknown class (case-by-case basis)
- mask = gt == WMhyper_label
- gt[mask] = unknown[mask]
- return gt
- # Label mapping functions (to aparc (eval) and to label (train))
- def map_label2aparc_aseg(mapped_aseg):
- """
- Function to perform look-up table mapping from label space to aparc.DKTatlas+aseg space
- :param np.ndarray mapped_aseg: label space segmentation (aparc.DKTatlas + aseg)
- :return:
- """
- aseg = np.zeros_like(mapped_aseg)
- labels = np.array([0, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 24, 26, 28, 31, 41, 43, 44,
- 46, 47, 49, 50, 51, 52, 53, 54, 58, 60, 63,
- 192, 1001, 1002, 1003, 1005, 1006, 1007, 1008, 1009, 1010, 1011,
- 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022,
- 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035,
- 2002, 2005, 2010, 2012, 2013, 2014, 2016, 2017, 2021, 2022, 2023,
- 2024, 2025, 2028])
- h, w, d = aseg.shape
- aseg = labels[mapped_aseg.ravel()]
- aseg = aseg.reshape((h, w, d))
- return aseg
- def map_aparc_aseg2label(aseg, aseg_nocc=None):
- """
- Function to perform look-up table mapping of aparc.DKTatlas+aseg.mgz data to label space
- :param np.ndarray aseg: ground truth aparc+aseg
- :param None/np.ndarray aseg_nocc: ground truth aseg without corpus callosum segmentation
- :return:
- """
- aseg = aseg.astype(np.int16)
- aseg_temp = aseg.copy()
- aseg[aseg == 80] = 77 # Hypointensities Class
- aseg[aseg == 85] = 0 # Optic Chiasma to BKG
- aseg[aseg == 62] = 41 # Right Vessel to Right WM
- aseg[aseg == 30] = 2 # Left Vessel to Left MW
- aseg[aseg == 72] = 24 # 5th Ventricle to CSF
- # Fan: change wm-lh wm-rh to cerebral WM
- aseg[(aseg_temp >= 3000) & (aseg_temp < 3999)] = 2
- aseg[(aseg_temp >= 4000) & (aseg_temp < 4999)] = 41
- aseg[aseg_temp == 5001] = 2
- aseg[aseg_temp == 5002] = 41
- # Fan: add CC
- aseg[(aseg >= 251) & (aseg <= 255)] = 251
- # If corpus callosum is not removed yet, do it now
- if aseg_nocc is not None:
- cc_mask = (aseg >= 251) & (aseg <= 255)
- aseg[cc_mask] = aseg_nocc[cc_mask]
- aseg[aseg == 3] = 0 # Map Remaining Cortical labels to background
- aseg[aseg == 42] = 0
- # If ctx-unknowns are not filled yet, do it now
- if np.any(np.in1d([1000, 2000], aseg.ravel())):
- aseg = fill_unknown_labels_per_hemi(aseg, 1000, 2000)
- aseg = fill_unknown_labels_per_hemi(aseg, 2000, 3000)
- # Fan: Make all right to be left:
- cortical_label_mask = (aseg >= 2000) & (aseg <= 2999)
- aseg[cortical_label_mask] = aseg[cortical_label_mask] - 1000
- # Preserve Cortical Labels: The ones not touching:
- # "cortical regions touching each other across the hemispheres, are lateralized
- # while all others are com- bined thus reducing the total number of labels from 95
- # (DKT without corpus callosum segmentations which are added later) to 78 during network training."
- aseg[aseg_temp == 2014] = 2014
- aseg[aseg_temp == 2028] = 2028
- aseg[aseg_temp == 2012] = 2012
- aseg[aseg_temp == 2016] = 2016
- aseg[aseg_temp == 2002] = 2002
- aseg[aseg_temp == 2023] = 2023
- aseg[aseg_temp == 2017] = 2017
- aseg[aseg_temp == 2024] = 2024
- aseg[aseg_temp == 2010] = 2010
- aseg[aseg_temp == 2013] = 2013
- aseg[aseg_temp == 2025] = 2025
- aseg[aseg_temp == 2022] = 2022
- aseg[aseg_temp == 2021] = 2021
- aseg[aseg_temp == 2005] = 2005
- # Here 251, 1001, 1032, 1033 are added.
- labels = np.array([0, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 24, 26, 28, 31, 41, 43, 44,
- 46, 47, 49, 50, 51, 52, 53, 54, 58, 60, 63,
- 77, 251, 1001, 1002, 1003, 1005, 1006, 1007, 1008, 1009, 1010, 1011,
- 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022,
- 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035,
- 2002, 2005, 2010, 2012, 2013, 2014, 2016, 2017, 2021, 2022, 2023,
- 2024, 2025, 2028])
- h, w, d = aseg.shape
- lut_aseg = np.zeros(max(labels) + 1, dtype='int')
- for idx, value in enumerate(labels):
- lut_aseg[value] = idx
- # Remap Label Classes - Perform LUT Mapping - Coronal, Axial
- mapped_aseg = lut_aseg.ravel()[aseg.ravel()]
- mapped_aseg = mapped_aseg.reshape((h, w, d))
- # Map Sagittal Labels
- aseg[aseg == 2] = 41
- aseg[aseg == 3] = 42
- aseg[aseg == 4] = 43
- aseg[aseg == 5] = 44
- aseg[aseg == 7] = 46
- aseg[aseg == 8] = 47
- aseg[aseg == 10] = 49
- aseg[aseg == 11] = 50
- aseg[aseg == 12] = 51
- aseg[aseg == 13] = 52
- aseg[aseg == 17] = 53
- aseg[aseg == 18] = 54
- aseg[aseg == 26] = 58
- aseg[aseg == 28] = 60
- aseg[aseg == 31] = 63
- cortical_label_mask = (aseg >= 2000) & (aseg <= 2999)
- aseg[cortical_label_mask] = aseg[cortical_label_mask] - 1000
- labels_sag = np.array([0, 14, 15, 16, 24, 41, 43, 44, 46, 47, 49,
- 50, 51, 52, 53, 54, 58, 60, 63, 77, 251, 1001, 1002,
- 1003, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014,
- 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025,
- 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035])
- h, w, d = aseg.shape
- lut_aseg = np.zeros(max(labels_sag) + 1, dtype='int')
- for idx, value in enumerate(labels_sag):
- lut_aseg[value] = idx
- # Remap Label Classes - Perform LUT Mapping - Coronal, Axial
- mapped_aseg_sag = lut_aseg.ravel()[aseg.ravel()]
- mapped_aseg_sag = mapped_aseg_sag.reshape((h, w, d))
- return mapped_aseg, mapped_aseg_sag
- def map_wmparc2label(aseg):
- """
- Function to perform look-up table mapping of aparc.DKTatlas+aseg.mgz data to label space
- :param np.ndarray aseg: ground truth aparc+aseg
- :param None/np.ndarray aseg_nocc: ground truth aseg without corpus callosum segmentation
- :return:
- """
- aseg = aseg.astype(np.int16)
- aseg_temp = aseg.copy()
- aseg[aseg == 80] = 77 # Hypointensities Class
- aseg[aseg == 85] = 0 # Optic Chiasma to BKG
- aseg[aseg == 62] = 41 # Right Vessel to Right WM
- aseg[aseg == 30] = 2 # Left Vessel to Left MW
- aseg[aseg == 72] = 24 # 5th Ventricle to CSF
- # Fan: change wm-lh wm-rh to cerebral WM
- aseg[(aseg_temp >= 3000) & (aseg_temp < 3999)] = 2
- aseg[(aseg_temp >= 4000) & (aseg_temp < 4999)] = 41
- aseg[aseg_temp == 5001] = 2
- aseg[aseg_temp == 5002] = 41
- # Fan: combine CC to Corpus_Callosum
- aseg[(aseg >= 251) & (aseg <= 255)] = 192
- aseg[aseg == 3] = 0 # Map Remaining Cortical labels to background
- aseg[aseg == 42] = 0
- # If ctx-unknowns are not filled yet, do it now
- if np.any(np.in1d([1000, 2000], aseg.ravel())):
- aseg = fill_unknown_labels_per_hemi(aseg, 1000, 2000)
- aseg = fill_unknown_labels_per_hemi(aseg, 2000, 3000)
- aseg = fill_WMhyper_per_hemi(aseg) # Remove hyperinstensity
- # Fan: Make all right to be left:
- cortical_label_mask = (aseg >= 2000) & (aseg <= 2999)
- aseg[cortical_label_mask] = aseg[cortical_label_mask] - 1000
- # Preserve Cortical Labels: The ones not touching:
- # "cortical regions touching each other across the hemispheres, are lateralized
- # while all others are com- bined thus reducing the total number of labels from 95
- # (DKT without corpus callosum segmentations which are added later) to 78 during network training."
- aseg[aseg_temp == 2014] = 2014
- aseg[aseg_temp == 2028] = 2028
- aseg[aseg_temp == 2012] = 2012
- aseg[aseg_temp == 2016] = 2016
- aseg[aseg_temp == 2002] = 2002
- aseg[aseg_temp == 2023] = 2023
- aseg[aseg_temp == 2017] = 2017
- aseg[aseg_temp == 2024] = 2024
- aseg[aseg_temp == 2010] = 2010
- aseg[aseg_temp == 2013] = 2013
- aseg[aseg_temp == 2025] = 2025
- aseg[aseg_temp == 2022] = 2022
- aseg[aseg_temp == 2021] = 2021
- aseg[aseg_temp == 2005] = 2005
- # Here 192, 1001, 1032, 1033 are added.
- labels = np.array([0, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 24, 26, 28, 31, 41, 43, 44, 46, 47,
- 49, 50, 51, 52, 53, 54, 58, 60, 63, 192,
- 1001, 1002, 1003, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012,
- 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023,
- 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035,
- 2002, 2005, 2010, 2012, 2013, 2014, 2016, 2017, 2021, 2022, 2023,
- 2024, 2025, 2028])
- h, w, d = aseg.shape
- lut_aseg = np.zeros(max(labels) + 1, dtype='int')
- for idx, value in enumerate(labels):
- lut_aseg[value] = idx
- # Remap Label Classes - Perform LUT Mapping - Coronal, Axial
- mapped_aseg = lut_aseg.ravel()[aseg.ravel()]
- mapped_aseg = mapped_aseg.reshape((h, w, d))
- # Map Sagittal Labels
- aseg[aseg == 2] = 41
- aseg[aseg == 3] = 42
- aseg[aseg == 4] = 43
- aseg[aseg == 5] = 44
- aseg[aseg == 7] = 46
- aseg[aseg == 8] = 47
- aseg[aseg == 10] = 49
- aseg[aseg == 11] = 50
- aseg[aseg == 12] = 51
- aseg[aseg == 13] = 52
- aseg[aseg == 17] = 53
- aseg[aseg == 18] = 54
- aseg[aseg == 26] = 58
- aseg[aseg == 28] = 60
- aseg[aseg == 31] = 63
- cortical_label_mask = (aseg >= 2000) & (aseg <= 2999)
- aseg[cortical_label_mask] = aseg[cortical_label_mask] - 1000
- labels_sag = np.array([0, 14, 15, 16, 24, 41, 43, 44, 46, 47, 49,
- 50, 51, 52, 53, 54, 58, 60, 63, 192,
- 1001, 1002, 1003, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013,
- 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025,
- 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035])
- h, w, d = aseg.shape
- lut_aseg = np.zeros(max(labels_sag) + 1, dtype='int')
- for idx, value in enumerate(labels_sag):
- lut_aseg[value] = idx
- # Remap Label Classes - Perform LUT Mapping - Coronal, Axial
- mapped_aseg_sag = lut_aseg.ravel()[aseg.ravel()]
- mapped_aseg_sag = mapped_aseg_sag.reshape((h, w, d))
- return mapped_aseg, mapped_aseg_sag
- def map_wmparc2gtseg(aseg):
- """
- Function to perform look-up table mapping of aparc.DKTatlas+aseg.mgz data to label space
- :param np.ndarray aseg: ground truth aparc+aseg
- :param None/np.ndarray aseg_nocc: ground truth aseg without corpus callosum segmentation
- :return:
- """
- aseg = aseg.astype(np.int16)
- aseg_temp = aseg.copy()
- aseg[aseg == 80] = 77 # Hypointensities Class
- aseg[aseg == 85] = 0 # Optic Chiasma to BKG
- aseg[aseg == 62] = 41 # Right Vessel to Right WM
- aseg[aseg == 30] = 2 # Left Vessel to Left MW
- aseg[aseg == 72] = 24 # 5th Ventricle to CSF
- # Fan: change wm-lh wm-rh to cerebral WM
- aseg[(aseg_temp >= 3000) & (aseg_temp < 3999)] = 2
- aseg[(aseg_temp >= 4000) & (aseg_temp < 4999)] = 41
- aseg[aseg_temp == 5001] = 2
- aseg[aseg_temp == 5002] = 41
- # Fan: combine CC to Corpus_Callosum
- aseg[(aseg >= 251) & (aseg <= 255)] = 192
- aseg[aseg == 3] = 0 # Map Remaining Cortical labels to background
- aseg[aseg == 42] = 0
- # If ctx-unknowns are not filled yet, do it now
- if np.any(np.in1d([1000, 2000], aseg.ravel())):
- aseg = fill_unknown_labels_per_hemi(aseg, 1000, 2000)
- aseg = fill_unknown_labels_per_hemi(aseg, 2000, 3000)
- aseg = fill_WMhyper_per_hemi(aseg) # Remove hyperinstensity
- return aseg
- def sagittal_coronal_remap_lookup(x):
- """
- Dictionary mapping to convert left labels to corresponding right labels for aseg
- :param int x: label to look up
- :return:
- """
- return {
- 2: 41,
- 3: 42,
- 4: 43,
- 5: 44,
- 7: 46,
- 8: 47,
- 10: 49,
- 11: 50,
- 12: 51,
- 13: 52,
- 17: 53,
- 18: 54,
- 26: 58,
- 28: 60,
- 31: 63,
- }[x]
- def map_prediction_sagittal2full(prediction_sag, num_classes=85):
- """
- Function to remap the prediction on the sagittal network to full label space used by coronal and axial networks
- (full aparc.DKTatlas+aseg.mgz)
- :param prediction_sag: sagittal prediction (labels)
- :param int num_classes: number of classes (96 for full classes, 79 for hemi split)
- :return: Remapped prediction
- """
- if num_classes == 96:
- idx_list = np.asarray([0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 2, 3, 14, 15, 4, 16,
- 17, 18, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 20, 21, 22,
- 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50], dtype=np.int16)
- else:
- # idx_list = np.asarray([0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 2, 3, 14, 15, 4, 16,
- # 17, 18, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
- # 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- # 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 20, 22, 27,
- # 29, 30, 31, 33, 34, 38, 39, 40, 41, 42, 45], dtype=np.int16)
- labels = np.array([0, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 24, 26, 28, 31, 41, 43, 44,
- 46, 47, 49, 50, 51, 52, 53, 54, 58, 60, 63,
- 192, 1001, 1002, 1003, 1005, 1006, 1007, 1008, 1009, 1010, 1011,
- 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022,
- 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035,
- 2002, 2005, 2010, 2012, 2013, 2014, 2016, 2017, 2021, 2022, 2023,
- 2024, 2025, 2028])
- labels_full_to_sag = np.array([0, 41, 43, 44, 46, 47, 49, 50, 51, 52, 14, 15, 16, 53, 54, 24, 58, 60, 63, 41, 43, 44, 46, 47, 49, 50, 51, 52, 53,
- 54, 58, 60, 63, 192, 1001, 1002, 1003, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016,
- 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035,
- 1002, 1005, 1010, 1012, 1013, 1014, 1016, 1017, 1021, 1022, 1023, 1024, 1025, 1028])
- labels_sag = np.array([0, 14, 15, 16, 24, 41, 43, 44, 46, 47, 49,
- 50, 51, 52, 53, 54, 58, 60, 63, 192, 1001, 1002,
- 1003, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014,
- 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025,
- 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035])
- idx = []
- for l in labels_full_to_sag:
- idx.append(np.where(labels_sag==l)[0][0])
- idx_list = np.array(idx)
- prediction_full = prediction_sag[:, idx_list, :, :]
- return prediction_full
- # Clean up and class separation
- def bbox_3d(img):
- """
- Function to extract the three-dimensional bounding box coordinates.
- :param np.ndarray img: mri image
- :return:
- """
- r = np.any(img, axis=(1, 2))
- c = np.any(img, axis=(0, 2))
- z = np.any(img, axis=(0, 1))
- rmin, rmax = np.where(r)[0][[0, -1]]
- cmin, cmax = np.where(c)[0][[0, -1]]
- zmin, zmax = np.where(z)[0][[0, -1]]
- return rmin, rmax, cmin, cmax, zmin, zmax
- def get_largest_cc(segmentation):
- """
- Function to find largest connected component of segmentation.
- :param np.ndarray segmentation: segmentation
- :return:
- """
- labels = label(segmentation, connectivity=3, background=0)
- bincount = np.bincount(labels.flat)
- background = np.argmax(bincount)
- bincount[background] = -1
- largest_cc = labels == np.argmax(bincount)
- return largest_cc
- # Class Operator for image loading (orig only)
- class OrigDataThickSlices(Dataset):
- """
- Class to load a given image and segmentation and prepare it
- for network training.
- """
- def __init__(self, img_filename, orig, plane='Axial', slice_thickness=3, transforms=None):
- try:
- self.img_filename = img_filename
- self.plane = plane
- self.slice_thickness = slice_thickness
- # Transform Data as needed
- if plane == 'Sagittal':
- orig = transform_sagittal(orig)
- print('Loading Sagittal')
- elif plane == 'Axial':
- orig = transform_axial(orig)
- print('Loading Axial')
- else:
- print('Loading Coronal.')
- # Create Thick Slices
- orig_thick = get_thick_slices(orig, self.slice_thickness)
- # Make 4D
- orig_thick = np.transpose(orig_thick, (2, 0, 1, 3))
- self.images = orig_thick
- self.count = self.images.shape[0]
- self.transforms = transforms
- print("Successfully loaded Image from {}".format(img_filename))
- except Exception as e:
- print("Loading failed. {}".format(e))
- def __getitem__(self, index):
- img = self.images[index]
- if self.transforms is not None:
- img = self.transforms(img)
- return {'image': img}
- def __len__(self):
- return self.count
- # Class Operator for image loading (orig only)
- class OrigDataThickSlices_Fused_Input(Dataset):
- """
- Class to load a given image and segmentation and prepare it
- for network training.
- """
- def __init__(self, img_filename, orig, plane='Axial', slice_thickness=3, transforms=None):
- try:
- self.img_filename = img_filename
- self.plane = plane
- self.slice_thickness = slice_thickness
- orig_thick_list = []
- for idx, orig_ in enumerate(orig):
- # Transform Data as needed
- if plane == 'Sagittal':
- orig_ = transform_sagittal(orig_)
- print('Loading Sagittal %d' % idx)
- elif plane == 'Axial':
- orig_ = transform_axial(orig_)
- print('Loading Axial %d' % idx)
- else:
- print('Loading Coronal %d' % idx)
- # Create Thick Slices
- orig_thick = get_thick_slices(orig_, self.slice_thickness)
- # Make 4D
- orig_thick = np.transpose(orig_thick, (2, 0, 1, 3))
- orig_thick_list.append(orig_thick)
- self.images = np.concatenate(orig_thick_list, axis=3)
- self.count = self.images.shape[0]
- self.transforms = transforms
- print("Successfully loaded Image from {}".format(img_filename))
- except Exception as e:
- print("Loading failed. {}".format(e))
- def __getitem__(self, index):
- img = self.images[index]
- if self.transforms is not None:
- img = self.transforms(img)
- return {'image': img}
- def __len__(self):
- return self.count
- ##
- # Dataset loading (for training)
- ##
- # Operator to load hdf5-file for training
- class AsegDatasetWithAugmentation(Dataset):
- """
- Class for loading aseg file with augmentations (transforms)
- """
- def __init__(self, params, transforms=None):
- # Load the h5 file and save it to the dataset
- try:
- self.params = params
- # Open file in reading mode
- with h5py.File(self.params['dataset_name'], "r") as hf:
- self.images = np.array(hf.get('orig_dataset'))
- self.labels = np.array(hf.get('aseg_dataset'))
- self.weights = np.array(hf.get('weight_dataset'))
- self.subjects = np.array(hf.get("subject"))
- self.count = self.images.shape[0]
- self.transforms = transforms
- print("Successfully loaded {} with plane: {}".format(params["dataset_name"], params["plane"]))
- except Exception as e:
- print("Loading failed: {}".format(e))
- def get_subject_names(self):
- return self.subjects
- def __getitem__(self, index):
- img = self.images[index]
- label = self.labels[index]
- weight = self.weights[index]
- if self.transforms is not None:
- tx_sample = self.transforms({'img': img, 'label': label, 'weight': weight})
- img = tx_sample['img']
- label = tx_sample['label']
- weight = tx_sample['weight']
- return {'image': img, 'label': label, 'weight': weight}
- def __len__(self):
- return self.count
- # Operator to load hdf5-file for training
- class AsegDatasetWithAugmentation_Fused_Input(Dataset):
- """
- Class for loading aseg file with augmentations (transforms)
- """
- def __init__(self, params, transforms=None):
- # Load the h5 file and save it to the dataset
- try:
- self.params = params
- self.images = []
- # Open file in reading mode
- for idx in range(len(self.params['dataset_name'])):
- with h5py.File(self.params['dataset_name'][idx], "r") as hf:
- self.images.append(np.array(hf.get('orig_dataset')))
- if idx == 0:
- self.labels = np.array(hf.get('aseg_dataset'))
- self.weights = np.array(hf.get('weight_dataset'))
- self.subjects = np.array(hf.get("subject"))
- self.images = np.concatenate(self.images, axis=3)
- self.count = self.images.shape[0]
- self.transforms = transforms
- print("Successfully loaded {} with plane: {}".format(params["dataset_name"], params["plane"]))
- except Exception as e:
- print("Loading failed: {}".format(e))
- def get_subject_names(self):
- return self.subjects
- def __getitem__(self, index):
- img = self.images[index]
- label = self.labels[index]
- weight = self.weights[index]
- if self.transforms is not None:
- tx_sample = self.transforms({'img': img, 'label': label, 'weight': weight})
- img = tx_sample['img']
- label = tx_sample['label']
- weight = tx_sample['weight']
- return {'image': img, 'label': label, 'weight': weight}
- def __len__(self):
- return self.count
- class AsegDatasetWithAugmentation_Slice(Dataset):
- """
- Class for loading aseg file with augmentations (transforms)
- """
- def __init__(self, params, transforms=None):
- # Load the h5 file and save it to the dataset
- try:
- self.params = params
- self.hdf5_files = sorted(glob.glob(os.path.join(params['dataset_name'], '*hdf5')))
- self.count = len(self.hdf5_files)
- self.transforms = transforms
- print("Successfully loaded {} with plane: {}".format(params["dataset_name"], params["plane"]))
- except Exception as e:
- print("Loading failed: {}".format(e))
- def get_subject_names(self):
- return self.subjects
- def __getitem__(self, index):
- hdf5 = self.hdf5_files[index]
- with h5py.File(hdf5, "r") as hf:
- img = np.array(hf.get('orig_dataset')).squeeze()
- label = np.array(hf.get('aseg_dataset')).squeeze()
- weight = np.array(hf.get('weight_dataset')).squeeze()
- if self.transforms is not None:
- tx_sample = self.transforms({'img': img, 'label': label, 'weight': weight})
- img = tx_sample['img']
- label = tx_sample['label']
- weight = tx_sample['weight']
- return {'image': img, 'label': label, 'weight': weight}
- def __len__(self):
- return self.count
- class AsegDatasetWithAugmentation_Slice_Fused_Input(Dataset):
- """
- Class for loading aseg file with augmentations (transforms)
- """
- def __init__(self, params, transforms=None):
- # Load the h5 file and save it to the dataset
- try:
- self.params = params
- self.params['dataset_name'] = sorted(self.params['dataset_name'])
- self.hdf5_files = []
- tmp_len = []
- for dataset in self.params['dataset_name']:
- filelist = sorted(glob.glob(os.path.join(dataset, '*hdf5')))
- self.hdf5_files.append(filelist)
- tmp_len.append(len(filelist))
- if np.unique(tmp_len).shape[0] != 1:
- print("Error: Input data should have the same number of hdf5 files!")
- exit()
- self.hdf5_files = np.array(self.hdf5_files)
- self.count = np.unique(tmp_len)[0]
- self.transforms = transforms
- print("Successfully loaded {} with plane: {}".format(params["dataset_name"], params["plane"]))
- except Exception as e:
- print("Loading failed: {}".format(e))
- def get_subject_names(self):
- return self.subjects
- def __getitem__(self, index):
- hdf5s = self.hdf5_files[:, index]
- if np.unique([os.path.split(n)[1] for n in hdf5s]).shape[0] != 1:
- print("Error: Must have the same file name!")
- print(hdf5s)
- exit()
- img = []
- for idx, hdf5 in enumerate(hdf5s):
- with h5py.File(hdf5, "r") as hf:
- img.append(np.array(hf.get('orig_dataset')).squeeze())
- if idx == 0:
- label = np.array(hf.get('aseg_dataset')).squeeze()
- weight = np.array(hf.get('weight_dataset')).squeeze()
- img = np.concatenate(img, axis=2)
- if self.transforms is not None:
- tx_sample = self.transforms({'img': img, 'label': label, 'weight': weight})
- img = tx_sample['img']
- label = tx_sample['label']
- weight = tx_sample['weight']
- return {'image': img, 'label': label, 'weight': weight}
- def __len__(self):
- return self.count
load_neuroimaging_data.py at commit 257ec7c, under Unlicense · at the source
Overview
- German Center for Neurodegenerative Diseases (DZNE), Bonn, Germany
- A. A. Martinos Center for Biomedical Imaging, Massachusetts General Hospital, Boston, MA, United States
- Department of Radiology, Harvard Medical School, Boston, MA, United States
Abstract
Segmenting anatomical regions is a crucial step in many diffusion-weighted MRI (dMRI) workflows, such as region-of-interest analysis or anatomically-constrained
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 11 matches between paragraphs and lines of code.
liziyu0929/DeepAnat
365f8e4529faa4cce3470450e6aaef4f395b51e4, 9 February 2023Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
9 files
- DeepAnat.ipynb, Jupyter, 292 lines
- SpectralNormalizationKer
as.py , Python, 673 lines - aini_utils.py, Python, 169 lines
- cnn_models.py, Python, 186 lines
- s_DeepAnat_applyCNN.py, Python, 122 lines
- s_DeepAnat_trainGAN.py, Python, 357 lines
- s_DeepAnat_trainUNet.py, Python, 165 lines
- LICENSE.md, License, 21 lines
- README.md, Text, 50 lines
zhangfanmark/DDParcel
257ec7c2a02209f86365dc5c0b39755458a3f776, 9 December 2024Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
15 files
- DDSurfer_Pred.py, Python, 333 lines
- data_loader/
__init__.py , Python, 1 line - data_loader/
augmentation.py , Python, 163 lines - data_loader/
conform.py , Python, 383 lines - data_loader/
load_neuroimaging_data.p , Python, 987 lines, 2 matchesy - models/
__init__.py , Python, 1 line - models/
losses.py , Python, 141 lines - models/
networks.py , Python, 1,487 lines - models/
organize_weights.sh , Shell, 28 lines - models/
solver.py , Python, 431 lines - models/
sub_module.py , Python, 327 lines - normalize.py, Python, 76 lines
- process.sh, Shell, 112 lines, 2 matches
- LICENSE, License, 24 lines
- README.md, Text, 30 lines
Deep-MI/DISCUSseg
c45ed3b5ba88c09c163074d5e08b3d6c521bdb9c, 1 June 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
39 files
- DISCUSseg/
__init__.py , Python, 24 lines - DISCUSseg/
config/ , Python, 247 linesdefaults.py - DISCUSseg/
data_loader/ , Python, 20 lines__init__.py - DISCUSseg/
data_loader/ , Python, 206 linesaugmentation.py - DISCUSseg/
data_loader/ , Python, 346 linesdata_utils.py - DISCUSseg/
data_loader/ , Python, 343 linesdataset.py - DISCUSseg/
data_loader/ , Python, 94 linesdiscus_augmentation_help ers.py - DISCUSseg/
data_loader/ , Python, 150 lines, 2 matchesdiscus_preprocessing.py - DISCUSseg/
data_loader/ , Python, 55 lines, 1 matchdkt_labels.py - DISCUSseg/
data_loader/ , Python, 18 linesevaluation_sampling_look up.py - DISCUSseg/
data_loader/ , Python, 81 linesloader.py - DISCUSseg/
inference.py , Python, 435 lines - DISCUSseg/
models/ , Python, 1 line__init__.py - DISCUSseg/
models/ , Python, 246 linesdiscus.py - DISCUSseg/
models/ , Python, 650 linesinterpolation_layer.py - DISCUSseg/
models/ , Python, 248 lineslosses.py - DISCUSseg/
models/ , Python, 401 linesnetworks.py - DISCUSseg/
models/ , Python, 73 linesoptimizer.py - DISCUSseg/
models/ , Python, 820 linessub_module.py - DISCUSseg/
run_model.py , Python, 104 lines - DISCUSseg/
run_prediction.py , Python, 753 lines, 2 matches - DISCUSseg/
train.py , Python, 696 lines, 2 matches - DISCUSseg/
utils/ , Python, 40 lines__init__.py - DISCUSseg/
utils/ , Python, 191 linesarg_types.py - DISCUSseg/
utils/ , Python, 235 linescheckpoint.py - DISCUSseg/
utils/ , Python, 1,141 linescommon.py - DISCUSseg/
utils/ , Python, 160 linesdataclasses.py - DISCUSseg/
utils/ , Python, 78 linesload_config.py - DISCUSseg/
utils/ , Python, 44 lineslogging.py - DISCUSseg/
utils/ , Python, 61 lineslr_scheduler.py - DISCUSseg/
utils/ , Python, 1,072 linesmapper.py - DISCUSseg/
utils/ , Python, 243 linesmeters.py - DISCUSseg/
utils/ , Python, 279 linesmetrics.py - DISCUSseg/
utils/ , Python, 206 linesmisc.py - DISCUSseg/
utils/ , Python, 373 linesparser_defaults.py - DISCUSseg/
utils/ , Python, 199 linesquick_qc.py - DISCUSseg/
utils/ , Python, 35 linesthreads.py - LICENSE, License, 174 lines
- README.md, Text, 90 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 3 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 57 scripts, each with its path and the digest of its content;
- 11 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data and Code Availability
In this paper, we use MRI data of two public datasets, the Young Adult dataset of the Human Connectome Project (HCP), available at https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, pages, dates, 3 authors, 5 keywords, 6 funders, 59 references.
Cite
This paper
Ewert, C., Kügler, D., & Reuter, M. (2026). Learning-based segmentation of diffusion-weighted MR images with arbitrary &
BibTeX
@article{ewert2026learni
author = {Ewert, Christian and Kügler, David and Reuter, Martin},
title = {{Learning-based segmentation of diffusion-weighted MR images with arbitrary \&
journal = {Imaging neuroscience (Cambridge, Mass.)},
year = {2026},
month = jun,
volume = {4},
pages = {IMAG.a.1183},
publisher = {MIT Press},
issn = {2837-6056},
doi = {10.1162/
url = {https://
pmid = {42245204},
pmcid = {PMC13231284}
}
RIS
TY - JOUR
AU - Ewert, Christian
AU - Kügler, David
AU - Reuter, Martin
TI - Learning-based segmentation of diffusion-weighted MR images with arbitrary &
T2 - Imaging neuroscience (Cambridge, Mass.)
J2 - Imaging Neurosci (Camb)
PY - 2026
DA - 2026/
VL - 4
SP - IMAG.a.1183
SN - 2837-6056
PB - MIT Press
DO - 10.1162/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1162/
"type": "article-journal",
"title": "Learning-based segmentation of diffusion-weighted MR images with arbitrary &
"container-title": "Imaging neuroscience (Cambridge, Mass.)",
"author": [
{
"family": "Ewert",
"given": "Christian"
},
{
"family": "Kügler",
"given": "David"
},
{
"family": "Reuter",
"given": "Martin"
}
],
"container-title-short":
"volume": "4",
"page": "IMAG.a.1183",
"DOI": "10.1162/
"PMID": "42245204",
"PMCID": "PMC13231284",
"ISSN": "2837-6056",
"publisher": "MIT Press",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
2
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41598-026-54446-8 [code]
- Deep learning-based Desikan-Killiany parcellation of the brain using diffusion MRI.Journal: Scientific reportsIn common: scikit-image, h5py, NiBabel, 3 other tools, methods / tools, structural MRI / diffusion, 12 references
- [2] doi:10.1002/advs.76596 [code]
- DDSurfer: A Weakly-Supervised Dual-Stream Deep Learning Framework for Cortical Surface Reconstruction From Diffusion MRI.Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)In common: NiBabel, PyTorch, pandas, 2 other tools, methods / tools, structural MRI / diffusion, 10 references
- [3] doi:10.1002/nbm.70353 [code]
- Automated Surface-Based Segmentation of Deep Gray Matter Regions Based on Diffusion Tensor Images Reveals Unique Age Trajectories Over the Healthy Lifespan.Journal: NMR in biomedicineIn common: scikit-image, NiBabel, SciPy, 1 other tool, structural MRI / diffusion, 9 references
- [4] doi:10.1038/s41597-026-07184-5 [code]
- A Multiple Sclerosis MRI Dataset with Tri-Mask Annotations for Lesion Segmentation.Journal: Scientific dataIn common: Keras, TensorFlow, scikit-image, 5 other tools, methods / tools, structural MRI / diffusion, 3 references
- [5] doi:10.1162/imag.a.1198 [code]
- MEPrep: A robust pipeline for multi-echo fMRI denoising and preprocessing.Journal: Imaging neuroscience (Cambridge, Mass.)In common: scikit-image, h5py, NiBabel, 4 other tools, methods / tools, 5 references
- [6] doi:10.1038/s41598-026-55397-w [code]
- Fast surface reconstruction of human brain MRI: benchmarking deep-learning based morphometry tools.Journal: Scientific reportsIn common: scikit-image, NiBabel, PyTorch, 3 other tools, methods / tools, structural MRI / diffusion, 6 references
- [7] doi:10.1162/imag.a.1366 [code]
- MICAFlow: Fast and robust MRI preprocessing bridging research neuroimaging and clinical practice.Journal: Imaging neuroscience (Cambridge, Mass.)In common: Keras, TensorFlow, NiBabel, 4 other tools, methods / tools, structural MRI / diffusion, 4 references
- [8] doi:10.1038/s41586-026-10631-3 [code]
- A prognostic human brain network for diffuse midline glioma.Journal: NatureIn common: Keras, TensorFlow, h5py, 5 other tools, 4 references
- [9] doi:10.1002/alz.71530 [code]
- Differential associations of plasma biomarkers with Alzheimer's disease and small vessel disease: A multimodal imaging study.Journal: Alzheimer's & dementia : the journal of the Alzheimer's AssociationIn common: NiBabel, PyTorch, pandas, 3 other tools, structural MRI / diffusion, 6 references
- [10] doi:10.1080/07853890.2026.2685416 [code]
- Pulmonary and cerebral damage in COVID-19 survivors: is there any association?Journal: Annals of medicineIn common: Keras, TensorFlow, scikit-image, 7 other tools, structural MRI / diffusion
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 3 repositories of the authors' code, each at its verified commit and with its license, 57 scripts, and 11 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:ed136f1525cd2801…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
