OSCR

Resources are associated with functional outcome and brain morphometry in childhood cancer survivors.

Code ↔ Paper

2 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 2 matches
  1. [1] § Materials and methods › Outcome measures › Neuroimaging › Preprocessing and data analysis ↔ src/DeepSCAN_Anatomy_Newnet_apply.py, lines 417–487 · score 0.75 · Anatomy Segmentation, Deep Learning, Cortex Parcellation, tissue, classes, scans
  2. [2] § Materials and methods › Outcome measures › Neuroimaging › Preprocessing and data analysis ↔ dl+direct.sh, lines 80–155 · score 0.62 · DiReCT, Anatomy, Deep, scans, boundary, DL

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 · 488 lines · 20 KB · BSD-3-Clause · 1 match

  1. import numpy as np
  2. import sys
  3. import os
  4. import argparse
  5. import csv
  6. import pandas as pd
  7. import nibabel as nib
  8. from collections import OrderedDict
  9. import torch
  10. import torch.nn as nn
  11. import torch.nn.functional as F
  12. from torch.nn import ModuleList, ReplicationPad2d, Dropout
  13. from torch.utils.data.sampler import Sampler, SequentialSampler
  14. from torch.utils.data.dataset import Dataset
  15. from torch.utils.data import DataLoader
  16. from numpy import require
  17. # Save logits of each class
  18. # Set to None to save all:
  19. # SAVE_LOGITS_FILTER = None
  20. # Set to empty list to disable save of logits:
  21. # SAVE_LOGITS_FILTER = []
  22. # Set to list of selected labels otherwise (e.g. for DL+DiReCT):
  23. # SAVE_LOGITS_FILTER = ['Left-Cerebral-White-Matter', 'Right-Cerebral-White-Matter', 'WM-hypointensities',
  24. # 'Left-Cerebral-Cortex', 'Right-Cerebral-Cortex',
  25. # 'Left-Amygdala', 'Right-Amygdala', 'Left-Hippocampus', 'Right-Hippocampus']
  26. SAVE_LOGITS_FILTER = ['Left-Cerebral-White-Matter', 'Right-Cerebral-White-Matter', 'WM-hypointensities',
  27. 'Left-Cerebral-Cortex', 'Right-Cerebral-Cortex',
  28. 'Left-Amygdala', 'Right-Amygdala', 'Left-Hippocampus', 'Right-Hippocampus']
  29. stack_depth = 7
  30. BATCH_SIZE = 10
  31. VERBOSE = True
  32. DIM = 216
  33. SCRIPT_DIR = os.path.dirname(os.path.realpath(sys.argv[0]))
  34. def get_label_def(label_names):
  35. # To generate the hard segmentations, we use the FS labels where we have a 1:1 correspondence,
  36. # otherwise a label above 100 (not used in FS)
  37. LUT = dict()
  38. with open('{}/fs_lut.csv'.format(SCRIPT_DIR), 'r') as file:
  39. csv_reader = csv.reader(file, delimiter=',')
  40. next(csv_reader, None) # skip the headers
  41. for row in csv_reader:
  42. LUT[row[1]] = int(row[0])
  43. LABELS = dict()
  44. for idx, label in enumerate(label_names):
  45. if label in LUT:
  46. l = LUT[label]
  47. else:
  48. l = idx + 100
  49. LABELS[label] = l
  50. return LABELS
  51. def get_stack(axis, volume, central_slice, first_slice=None, last_slice=None,
  52. stack_depth=5, size = (DIM,DIM), lower_threshold = None, upper_threshold= None, return_nonzero= True):
  53. image_data = np.array(np.swapaxes(volume, 0, axis), copy = True)
  54. mean = np.mean(image_data[image_data>0])
  55. sd = np.sqrt(np.var(image_data[image_data>0]))
  56. if lower_threshold is None:
  57. lower_threshold = 0
  58. if upper_threshold is None:
  59. upper_threshold = np.percentile(image_data[image_data>0], 99.9)
  60. image_data[image_data<lower_threshold] = lower_threshold
  61. image_data[image_data>upper_threshold] = upper_threshold
  62. if first_slice is None:
  63. if central_slice is not None:
  64. first_slice = central_slice - stack_depth//2
  65. last_slice = central_slice + stack_depth//2 + 1
  66. elif last_slice is not None:
  67. first_slice = last_slice - stack_depth
  68. elif last_slice is None:
  69. last_slice = min(first_slice + stack_depth, len(image_data))
  70. pad_up = max(0, -first_slice)
  71. pad_down = -min(0, len(image_data)-last_slice)
  72. first_slice = max(first_slice,0)
  73. last_slice = min(last_slice, len(image_data))
  74. initial_stack = image_data[first_slice:last_slice]
  75. initial_shape = initial_stack.shape[1:]
  76. shape_difference = (size[0] - initial_shape[0],size[1] - initial_shape[1])
  77. pad_size = ((pad_up,pad_down),
  78. (max(0, shape_difference[0]//2), max(0, shape_difference[0] - shape_difference[0]//2)),
  79. (max(0, shape_difference[1]//2), max(0, shape_difference[1] - shape_difference[1]//2))
  80. )
  81. initial_stack = np.pad(initial_stack, pad_size, mode = 'constant', constant_values = lower_threshold)
  82. if return_nonzero :
  83. nonzero_mask = (initial_stack>lower_threshold).astype(np.uint8)
  84. else:
  85. nonzero_mask = None
  86. return (initial_stack - mean)/sd, nonzero_mask
  87. def get_stack_no_augment(axis, volume, first_slice, last_slice, size=(DIM, DIM)):
  88. return get_stack(axis = axis, volume = volume, central_slice=None, stack_depth=None, first_slice = first_slice, last_slice = last_slice, size=size)
  89. def reduce_3d_depth (in_channel, out_channel, kernel_size, padding):
  90. layer = nn.Sequential(OrderedDict([
  91. ("pad1", nn.ReplicationPad3d((1,1,1,1,0,0))),
  92. ("conv1", nn.Conv3d(in_channel, out_channel, kernel_size=kernel_size, padding=padding)),
  93. ("bn1", nn.InstanceNorm3d(out_channel, affine = False)),
  94. ("relu1", nn.ReLU()),
  95. #("dropout", nn.Dropout(p=0.2))
  96. ]))
  97. return layer
  98. def down_layer(in_channel, out_channel, kernel_size, padding):
  99. layer = nn.Sequential(OrderedDict([
  100. ("pad1", nn.ReplicationPad2d(1)),
  101. ("conv1", nn.Conv2d(in_channel, out_channel, kernel_size=kernel_size, padding=padding)),
  102. ("bn1", nn.InstanceNorm2d(out_channel, affine = False)),
  103. ("relu1", nn.ReLU()),
  104. ("dropout1", nn.Dropout(p=0.0)),
  105. ("pad2", nn.ReplicationPad2d(1)),
  106. ("conv2", nn.Conv2d(out_channel, out_channel, kernel_size=kernel_size, padding=padding)),
  107. ("bn2", nn.InstanceNorm2d(out_channel, affine = False)),
  108. ("relu2", nn.ReLU()),
  109. ("dropout2", nn.Dropout(p=0.0))]))
  110. return layer
  111. def up_layer(in_channel, out_channel, kernel_size, padding):
  112. layer = nn.Sequential(OrderedDict([
  113. ("pad1", nn.ReplicationPad2d(1)),
  114. ("conv1", nn.Conv2d(in_channel, out_channel, kernel_size=kernel_size, padding=padding)),
  115. ("bn1", nn.InstanceNorm2d(out_channel, affine = False)),
  116. ("relu1", nn.ReLU()),
  117. ("dropout1", nn.Dropout(p=0.0)),
  118. ("pad2", nn.ReplicationPad2d(1)),
  119. ("conv2", nn.Conv2d(out_channel, out_channel, kernel_size=kernel_size, padding=padding)),
  120. ("bn2", nn.InstanceNorm2d(out_channel, affine = False)),
  121. ("relu2", nn.ReLU()),
  122. ("dropout2", nn.Dropout(p=0.0))]))
  123. return layer
  124. class DilatedDenseUnit(nn.Module):
  125. def __init__(self, in_channel, growth_rate , kernel_size, dilation):
  126. super(DilatedDenseUnit,self).__init__()
  127. self.layer = nn.Sequential(OrderedDict([
  128. ("bn1", nn.InstanceNorm2d(in_channel, affine = False)),
  129. ("relu1", nn.ReLU()),
  130. ("pad1", nn.ReplicationPad2d(dilation)),
  131. ("conv1", nn.Conv2d(in_channel, growth_rate, kernel_size=kernel_size, dilation = dilation,padding=0)),
  132. ("dropout", nn.Dropout(p=0.0))]))
  133. def forward(self, x):
  134. out = x
  135. out = self.layer(out)
  136. out = concatenate(x, out)
  137. return out
  138. class AttentionModule(nn.Module):
  139. def __init__(self, in_channel , intermediate_channel, out_channel, kernel_size=3):
  140. super(AttentionModule,self).__init__()
  141. self.layer = nn.Sequential(OrderedDict([
  142. ("bn1", nn.InstanceNorm2d(in_channel, affine = False)),
  143. ("relu1", nn.ReLU()),
  144. ("pad1", nn.ReplicationPad2d(1)),
  145. ("conv1", nn.Conv2d(in_channel, intermediate_channel, kernel_size=kernel_size,padding=0)),
  146. ("bn2", nn.InstanceNorm2d(intermediate_channel, affine = False)),
  147. ("relu2", nn.ReLU()),
  148. ("pad2", nn.ReplicationPad2d(1)),
  149. ("conv2", nn.Conv2d(intermediate_channel, out_channel, kernel_size=kernel_size,padding=0)),
  150. ("sigmoid", nn.Sigmoid())]))
  151. def forward(self, x):
  152. out = x
  153. out = self.layer(out)
  154. out = x * out
  155. return out
  156. def center_crop(layer, target_size):
  157. _, _, layer_width, layer_height = layer.size()
  158. start = (layer_width - target_size) // 2
  159. crop = layer[:, :, start:(start + target_size), start:(start + target_size)]
  160. return crop
  161. def concatenate(link, layer):
  162. concat = torch.cat([link, layer], 1)
  163. return concat
  164. def dense_atrous_bottleneck(in_channel, growth_rate = 12, depth = [4,4,4,4]):
  165. layer_dict = OrderedDict()
  166. for idx, growth_steps in enumerate(depth):
  167. dilation_rate = 2**idx
  168. for y in range(growth_steps):
  169. layer_dict["dilated_{}_{}".format(dilation_rate,y)] = DilatedDenseUnit(in_channel,
  170. growth_rate,
  171. kernel_size=3,
  172. dilation = dilation_rate)
  173. in_channel = in_channel + growth_rate
  174. layer_dict["attention_{}".format(dilation_rate)] = AttentionModule(in_channel, in_channel//4, in_channel)
  175. return nn.Sequential(layer_dict), in_channel
  176. class UNET_3D_to_2D(nn.Module):
  177. def __init__(self, depth, channels_in = 1,
  178. channels_2d_to_3d = 32, channels = 32, output_channels = 1, slices=stack_depth,
  179. dilated_layers = [4,4,4,4],
  180. growth_rate = 12):
  181. super(UNET_3D_to_2D, self).__init__()
  182. self.main_modules = []
  183. self.depth = depth
  184. self.slices = slices
  185. self.depth_reducing_layers = ModuleList([reduce_3d_depth(in_channel, channels_2d_to_3d, kernel_size=3, padding=0)
  186. for in_channel in [channels_in]+[channels_2d_to_3d]*(slices//2 - 1)])
  187. self.down1 = down_layer(in_channel=channels_2d_to_3d, out_channel=channels, kernel_size=3, padding=0)
  188. self.main_modules.append(self.down1)
  189. self.max1 = nn.MaxPool2d(2)
  190. self.down_layers = ModuleList([down_layer(in_channel = channels*(2**i),
  191. out_channel = channels * (2**(i+1)),
  192. kernel_size = 3,
  193. padding=0
  194. ) for i in range(self.depth)])
  195. self.main_modules.append(self.down_layers)
  196. self.max_layers = ModuleList([nn.MaxPool2d(2) for i in range(self.depth)])
  197. self.bottleneck, bottleneck_features = dense_atrous_bottleneck(channels*2**self.depth, growth_rate = growth_rate,
  198. depth = dilated_layers)
  199. self.main_modules.append(self.bottleneck)
  200. self.upsampling_layers = ModuleList([nn.Sequential(OrderedDict([
  201. ("upsampling",nn.Upsample(scale_factor=2, mode = 'bilinear', align_corners=True)),
  202. ("pad", nn.ReplicationPad2d(1)),
  203. ("conv", nn.Conv2d(in_channels= bottleneck_features,
  204. out_channels=bottleneck_features,
  205. kernel_size=3,
  206. padding=0))])) for i in range(self.depth, -1, -1)])
  207. self.main_modules.append(self.upsampling_layers)
  208. self.up_layers = ModuleList([up_layer(in_channel= bottleneck_features+ channels*(2**(i)),
  209. out_channel=bottleneck_features,
  210. kernel_size=3,
  211. padding=0) for i in range(self.depth, -1, -1)])
  212. self.main_modules.append(self.up_layers)
  213. self.last = nn.Conv2d(in_channels=bottleneck_features, out_channels=output_channels, kernel_size=1)
  214. self.main_modules.append(self.last)
  215. self.logvar = nn.Conv2d(in_channels=bottleneck_features, out_channels=output_channels, kernel_size=1)
  216. def forward(self, x):
  217. # down
  218. out = x
  219. for i in range(self.slices//2):
  220. out = self.depth_reducing_layers[i](out)
  221. out.transpose_(1, 2).contiguous()
  222. size = out.size()
  223. out = out.view((-1, size[2], size[3], size[4]))
  224. links = []
  225. out = self.down1(out)
  226. links.append(out)
  227. out = self.max1(out)
  228. for i in range(self.depth):
  229. out = self.down_layers[i](out)
  230. links.append(out)
  231. out = self.max_layers[i](out)
  232. out = self.bottleneck(out)
  233. links.reverse()
  234. # up
  235. for i in range(self.depth+1):
  236. out = self.upsampling_layers[i](out)
  237. out = concatenate(links[i], out)
  238. out = self.up_layers[i](out)
  239. pred = self.last(out)
  240. logvar = self.logvar(out)
  241. logvar = -torch.exp(logvar)
  242. return pred, logvar
  243. def apply_to_case(model, volumes, batch_size, stack_depth = stack_depth, axes=[0], size=(DIM,DIM), mask_bg = True, lowmem=False):
  244. volume_0 = volumes[0]
  245. ensemble_logits = None
  246. for axis in axes:
  247. print('Axis {}'.format(axis), end='', flush=True) if VERBOSE else False
  248. logit_total = []
  249. num_batches = volume_0.shape[axis]//(batch_size)
  250. if volume_0.shape[axis]%batch_size > 0:
  251. num_batches = num_batches + 1
  252. padding = stack_depth//2
  253. class BrainDataTest(Dataset):
  254. def __init__(self):
  255. self.length = num_batches
  256. def __getitem__(self, batch):
  257. first_slice = batch*batch_size - padding
  258. last_slice = np.min([(batch+1)*batch_size+padding, volume_0.shape[axis]+padding])
  259. extra_upper_slices = np.max([0, stack_depth - (last_slice - first_slice)])
  260. last_slice = last_slice + extra_upper_slices
  261. images_t1, nonzero_masks = get_stack_no_augment(axis = axis,
  262. volume = volume_0,
  263. first_slice=first_slice,
  264. last_slice=last_slice,
  265. size=size)
  266. images = np.stack([images_t1])
  267. if padding >0:
  268. nonzero_masks = nonzero_masks[padding:-(padding+extra_upper_slices)]
  269. return images.astype(np.float32), nonzero_masks.astype(np.float32)
  270. def __len__(self):
  271. return self.length
  272. test_generator = DataLoader(BrainDataTest(), sampler = SequentialSampler(BrainDataTest()),
  273. num_workers=0,pin_memory=True)
  274. for images, nonzero_masks in test_generator:
  275. print('.', end='', flush=True) if VERBOSE else False
  276. images = images.to(device)
  277. nonzero_mask = nonzero_masks.to(device)
  278. outputs, logit_flip = model(images)
  279. if mask_bg:
  280. outputs = outputs * torch.unsqueeze(nonzero_mask[0],1)
  281. out_cpu = outputs.cpu().data.numpy()
  282. if lowmem:
  283. out_cpu = out_cpu.astype(np.float16)
  284. logit_total.append(out_cpu)
  285. print('') if VERBOSE else False
  286. full_logit = np.concatenate(logit_total)
  287. logit_total = None
  288. new_shape = full_logit[:, 0, :, :].shape
  289. shape_difference = (new_shape[0] - np.swapaxes(volume_0,0, axis).shape[0],
  290. new_shape[1]-np.swapaxes(volume_0,0, axis).shape[1],
  291. new_shape[2]-np.swapaxes(volume_0,0, axis).shape[2])
  292. full_logit = np.swapaxes(full_logit, 1, 0)
  293. full_logit = full_logit[:, shape_difference[0]//2:new_shape[0]- (shape_difference[0] - shape_difference[0]//2),
  294. shape_difference[1]//2: new_shape[1]- (shape_difference[1] - shape_difference[1]//2),
  295. shape_difference[2]//2: new_shape[2]- (shape_difference[2] - shape_difference[2]//2)]
  296. full_logit = np.swapaxes(full_logit, 1, axis+1)
  297. if ensemble_logits is None:
  298. ensemble_logits = np.zeros((3,) + full_logit.shape, dtype=np.float16 if lowmem else np.float32)
  299. ensemble_logits[axis, ] = full_logit
  300. return np.mean(ensemble_logits, axis=0)
  301. def locate_model(model_file):
  302. if os.path.exists(model_file):
  303. return model_file
  304. for prefix in ['', '{}/../model/'.format(SCRIPT_DIR)]:
  305. for suffix in ['.pth', '_f1.pth']:
  306. file = '{}{}{}'.format(prefix, model_file, suffix)
  307. if os.path.exists(file):
  308. return file
  309. def load_checkpoint(checkpoint_file, device):
  310. if not os.path.exists(checkpoint_file):
  311. print('Error: model {} not found'.format(checkpoint_file))
  312. sys.exit(1)
  313. print('loading checkpoint {}'.format(checkpoint_file)) if VERBOSE else False
  314. return torch.load(checkpoint_file, weights_only=True, map_location=device)
  315. def validate_input(t1, t1_data):
  316. # input sanity check: we expect images in LIA orientation (FS space)!
  317. orientation = ''.join(nib.aff2axcodes(t1.affine))
  318. if orientation != 'LIA':
  319. print('\nWARNING: Invalid orientation found for {}: {}\n'.format(subject_id, orientation))
  320. # check for non-zero corners (background)
  321. corner_idx = np.ix_((0,-1),(0,-1),(0,-1))
  322. if not np.allclose(t1_data[corner_idx].flatten(), 0):
  323. print('\nWARNING: Non-zero voxels detected in background (corners). Make sure input is brain extracted (use --bet) and background intensities are exactly 0\n')
  324. if __name__ == '__main__':
  325. parser = argparse.ArgumentParser(description='DeepSCAN: Deep learning based anatomy segmentation and cortex parcellation')
  326. parser.add_argument("--model", required=False, default='v0_f1')
  327. parser.add_argument("--lowmem", required=False, default=False)
  328. parser.add_argument("T1w")
  329. parser.add_argument("destination_dir")
  330. parser.add_argument("subject_id")
  331. args = parser.parse_args()
  332. t1_file = args.T1w
  333. output_dir = args.destination_dir
  334. model_file = locate_model(args.model)
  335. subject_id = args.subject_id
  336. if not os.path.exists(t1_file):
  337. print('T1w file {} not found'.format(t1_file))
  338. sys.exit(1)
  339. if not os.path.exists(output_dir):
  340. os.makedirs(output_dir)
  341. device = torch.device('cuda' if torch.cuda.is_available() else ('mps' if hasattr(torch.backends, 'mps') and torch.backends.mps.is_available() else 'cpu'))
  342. checkpoint = load_checkpoint(model_file, device)
  343. target_label_names = checkpoint['label_names']
  344. # number of last labels to ignore for hard segmentation (argmax), e.g. left-hemi, right-hemi, brain
  345. NUM_IGNORE_LABELS = checkpoint['label_num_ignore']
  346. LABELS = get_label_def(target_label_names)
  347. unet = UNET_3D_to_2D(0,channels_in=1,channels=64, growth_rate=16, dilated_layers=[4,4,4,4], output_channels=len(target_label_names)).to(device)
  348. unet.load_state_dict(checkpoint['state_dict'])
  349. unet.eval()
  350. t1 = nib.load(t1_file)
  351. t1_data = t1.get_fdata(dtype=np.float32)
  352. validate_input(t1, t1_data)
  353. # apply model
  354. with torch.set_grad_enabled(False):
  355. logit = apply_to_case(unet, volumes = [t1_data], batch_size=BATCH_SIZE, stack_depth = stack_depth, axes=[0,1,2], lowmem=args.lowmem)
  356. print('DONE predicting') if VERBOSE else False
  357. brain_tissue = logit[-1] > 0
  358. logit_sm = np.concatenate([logit[:-NUM_IGNORE_LABELS]], axis = 0)
  359. segmentation_sm = np.argmax(logit_sm, axis=0) + 1
  360. segmentation_sm_masked = segmentation_sm * brain_tissue
  361. segmentation_stacked = np.stack([segmentation_sm_masked == x for x in range(1, len(target_label_names)-NUM_IGNORE_LABELS+1)], axis=0)
  362. volumes = np.sum(segmentation_stacked, axis=(1,2,3))
  363. # re-label with FS labels
  364. segmentation_sm_fslabels = np.zeros_like(segmentation_sm_masked)
  365. for idx in range(1, len(target_label_names)):
  366. segmentation_sm_fslabels[segmentation_sm_masked == idx] = LABELS[target_label_names[idx-1]]
  367. affine = t1.affine
  368. nib.save(nib.Nifti1Image(segmentation_sm_fslabels.astype(np.int32), affine), '{}/softmax_seg.nii.gz'.format(output_dir))
  369. # save individual logits for each class
  370. for idx, x in enumerate(target_label_names):
  371. lbl_name = target_label_names[idx]
  372. if not SAVE_LOGITS_FILTER or lbl_name in SAVE_LOGITS_FILTER:
  373. nib.save(nib.Nifti1Image(logit[idx, :, :, :].astype(np.float32), affine), '{}/seg_{}.nii.gz'.format(output_dir, lbl_name))
  374. with open('{}/result-vol.csv'.format(output_dir), 'w') as file:
  375. writer = csv.writer(file, delimiter=',')
  376. writer.writerow(['SUBJECT'] + ['{}'.format(target_label_names[idx]) for idx in range(0, len(target_label_names)-NUM_IGNORE_LABELS)])
  377. writer.writerow([subject_id] + ['{}'.format(i) for i in volumes])
  378. # write label definitions
  379. pd.DataFrame([[LABELS[lbl], lbl] for lbl in LABELS], columns=['ID', 'LABEL']).to_csv('{}/label_def.csv'.format(output_dir), sep=',', index=False)

DeepSCAN_Anatomy_Newnet_apply.py at commit c750348, under BSD-3-Clause · at the source

Overview

Authors: Saskia Salzmann1,2, Valentin Benzing3, David Romascano4, Regula Everts1,5
  1. Division of Neuropaediatrics, Development and Rehabilitation, Department of Paediatrics, Inselspital, Bern University Hospital, University of Bern, Bern, Switzerland
  2. Graduate School for Health Sciences, University of Bern, Bern, Switzerland
  3. Institute of Sport Science, University of Bern, Bern, Switzerland
  4. Support Center for Advanced Neuroimaging (SCAN), University Institute of Diagnostic and Interventional Neuroradiology, Inselspital, Bern University Hospital and University of Bern, Bern, Switzerland
  5. Division of Paediatric Hematology and Oncology, Department of Paediatrics, Inselspital, Bern University Hospital, University of Bern, Bern, Switzerland
Institutions: University of Bern (Switzerland); University Hospital of Bern (Switzerland)
Journal: Frontiers in oncology, volume 16, article 1886395
Dates: received 20 May 2026; accepted 21 July 2026; published online 6 August 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.3389/fonc.2026.1886395 · PMID 42625627 · PMCID PMC13489876 · OpenAlex W7197052626
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), human (organism), other condition (population), developmental (subfield)
Methods: Statistics, Smoothing, state filtering, decompositions, Machine learning, Connectivity, fMRI & imaging, Preprocessing
Keywords: brain morphometry, childhood cancer, cognition, contextual resources, individual resources, motor functions, multifactorial
Topic: Cancer-related cognitive impairment studies (Pulmonary and Respiratory Medicine, Medicine), according to OpenAlex
Funding: Dietmar Hopp Stiftung; Fondation Gaydoul; Swiss Cancer Research Foundation (KFS-3705-08-2015, KFS-4708-02-2019)
Citations: not cited yet (Europe PMC); 50 references in the paper

Abstract

Background: Childhood cancer survivors exhibit a high prevalence of long-term cognitive and motor impairments as well as structural brain alterations. Examining late effects from a multimodal perspective is essential as individual and contextual resources (e.g. self-efficacy, optimism; parental support, socioeconomic status) as well as risk factors (e.g. disease and treatment related factors) likely impact neurodevelopment such as functional outcome (cognition, motor function) and brain structure in childhood cancer survivors. It is purely understood how individual and contextual resources are associated with functional outcome and brain structure and whether resources can moderate the relationship between functional outcome and brain structure. A deeper understanding of these interrelations can help to identify components for multimodal interventions to strengthen neurodevelopment after childhood cancer in the long-term. This exploratory study investigates associations between resources (individual and contextual) and neurodevelopmental outcomes and how resources moderate functional outcome, and brain morphometry in childhood cancer survivors.

Methods: 56 childhood cancer survivors (N = 45 non central nervous system cancer survivors (non-CNS), N = 11 CNS cancer survivors (CNS)) and 45 typically developing children all aged 7–16 years; M = 10.85, SD = 2.52)) underwent structural MRI, cognitive and motor assessments and filled out questionnaires on individual and contextual resources at least one year after the end of cancer treatment. Correlations were computed, followed by principal components analysis to minimize factors (given the small sample and number of variables), and subsequent moderation analyses were conducted.

Results: More and stronger correlations occurred between resources and functional outcome as well as resources and brain morphometry in survivors (non-CNS: N correlations = 16, r = 0.32-0.61; CNS: N correlation = 9, r = 0.78-0.97) compared with typically developing children (N correlation = 2, r = 0.34-0.37), with the strongest effects in CNS cancer survivors. Interaction effects suggest that resources may moderate the associations between cognition and motor function (β=-0.834-0.894, puncorr=0.003-0.047), as well as between cognition and brain morphometry (β=-1.185 to -1.109, puncorr=0.034-0.046). The associations across resources, cognition, motor function, and brain morphometry were more pronounced in CNS and non-CNS cancer survivors (non-CNS: N = 34, r=0.33-0.61; CNS: N = 29, r=0.72-1.00) compared to typically developing children (N = 17, r=0.31-0.47).

Conclusion: These exploratory findings propose that individual and contextual resources are associated with functional outcome and brain morphometry following childhood cancer, suggesting that resource-oriented, multimodal interventions should be considered for neurodevelopmental rehabilitation.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above, with 2 matches between paragraphs and lines of code.

SCAN-NRAD/DL-DiReCT

License: BSD-3-Clause
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: c750348c569f9dc1c8321048c1ab374b2daca61d, 15 October 2024
Languages: Python (10), Shell (3)
Size: 27 files, 13 scripts
Software Heritage: archived
Found in: the text, “Preprocessing and data analysis”
Holds: README, license file, environment (pyproject.toml), documentation
Not found: CITATION.cff, tests, continuous integration
Tools: NumPy (7 files), NiBabel (6 files), pandas (5 files), PyTorch (2 files), SciPy (2 files), ANTs (1 file), PyRadiomics (1 file), scikit-image (1 file), SimpleITK (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
15 files

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:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 13 scripts, each with its path and the digest of its content;
  • 2 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 availability statement

All anonymized data are available from the last author on reasonable request. Requests to access these datasets should be directed to RE, .

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 3, 28 September 2026

  • Funding: added Dietmar Hopp Stiftung; Fondation Gaydoul; Swiss Cancer Research Foundation: KFS-3705-08-2015, KFS-4708-02-2019

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, pages, dates, 4 authors, 7 keywords, 45 references.

Cite

This paper

Salzmann, S., Benzing, V., Romascano, D., & Everts, R. (2026). Resources are associated with functional outcome and brain morphometry in childhood cancer survivors. Frontiers in oncology, 16, 1886395. https://doi.org/10.3389/fonc.2026.1886395

BibTeX

@article{salzmann2026resources,
author = {Salzmann, Saskia and Benzing, Valentin and Romascano, David and Everts, Regula},
title = {{Resources are associated with functional outcome and brain morphometry in childhood cancer survivors}},
journal = {Frontiers in oncology},
year = {2026},
month = aug,
volume = {16},
pages = {1886395},
publisher = {Frontiers Media SA},
issn = {2234-943X},
doi = {10.3389/fonc.2026.1886395},
url = {https://doi.org/10.3389/fonc.2026.1886395},
pmid = {42625627},
pmcid = {PMC13489876}
}

RIS

TY - JOUR
AU - Salzmann, Saskia
AU - Benzing, Valentin
AU - Romascano, David
AU - Everts, Regula
TI - Resources are associated with functional outcome and brain morphometry in childhood cancer survivors
T2 - Frontiers in oncology
J2 - Front Oncol
PY - 2026
DA - 2026/08/06
VL - 16
SP - 1886395
SN - 2234-943X
PB - Frontiers Media SA
DO - 10.3389/fonc.2026.1886395
UR - https://doi.org/10.3389/fonc.2026.1886395
LA - en
ER -

CSL-JSON

{
"id": "10.3389/fonc.2026.1886395",
"type": "article-journal",
"title": "Resources are associated with functional outcome and brain morphometry in childhood cancer survivors",
"container-title": "Frontiers in oncology",
"author": [
{
"family": "Salzmann",
"given": "Saskia"
},
{
"family": "Benzing",
"given": "Valentin"
},
{
"family": "Romascano",
"given": "David"
},
{
"family": "Everts",
"given": "Regula"
}
],
"container-title-short": "Front Oncol",
"volume": "16",
"page": "1886395",
"DOI": "10.3389/fonc.2026.1886395",
"PMID": "42625627",
"PMCID": "PMC13489876",
"ISSN": "2234-943X",
"publisher": "Frontiers Media SA",
"URL": "https://doi.org/10.3389/fonc.2026.1886395",
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
6
]
]
}
}

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-55397-w [code]
Fast surface reconstruction of human brain MRI: benchmarking deep-learning based morphometry tools.
Journal: Scientific reports
In common: PyRadiomics, SimpleITK, ANTs, 6 other tools, structural MRI / diffusion, 3 references
[2] doi:10.1038/s41598-026-56778-x [code]
Chiari malformation type 1 is associated with a smaller fourth ventricle volume - a multi-cohort replication study.
Journal: Scientific reports
In common: PyRadiomics, SimpleITK, ANTs, 6 other tools, structural MRI / diffusion, 1 reference
[3] doi:10.1371/journal.pcbi.1014555 [code]
Body surface potential driven personalisation of electrophysiological digital twins in hypertrophic cardiomyopathy.
Journal: PLoS computational biology
In common: PyRadiomics, SimpleITK, ANTs, 6 other tools, structural MRI / diffusion
[4] doi:10.1002/alz.71649 [code]
Postmortem brain MRI reveals differential associations of subcortical and limbic volumes with cortical thinning and neurodegenerative pathologies.
Journal: Alzheimer's & dementia : the journal of the Alzheimer's Association
In common: SimpleITK, ANTs, scikit-image, 5 other tools, structural MRI / diffusion, other condition, 1 reference
[5] doi:10.3390/jimaging12070276 [code]
Hyperelastic Regularization for Near-Diffeomorphic Transformer-Based Brain MRI Registration.
Journal: Journal of imaging
In common: SimpleITK, ANTs, scikit-image, 5 other tools, structural MRI / diffusion, 1 reference
[6] doi:10.1038/s41467-026-73373-w [code]
Mapping neuro-vascular unit communications reveals distinct angiogenic programs across developing mouse brain regions.
Journal: Nature communications
In common: SimpleITK, ANTs, scikit-image, 5 other tools
[7] doi:10.1016/j.crmeth.2026.101473 [code]
AmygdalaGo-BOLT for boundary-aware segmentation of the human amygdala.
Journal: Cell reports methods
In common: SimpleITK, ANTs, scikit-image, 4 other tools, structural MRI / diffusion
[8] 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: SimpleITK, ANTs, NiBabel, 4 other tools, structural MRI / diffusion, 1 reference
[9] doi:10.3389/frai.2026.1771088 [code]
Few-shot deployment of pretrained MRI transformers in brain imaging tasks.
Journal: Frontiers in artificial intelligence
In common: SimpleITK, scikit-image, NiBabel, 4 other tools, structural MRI / diffusion, 1 reference
[10] doi:10.1186/s12880-026-02335-x [code]
Automatic lateral ventricle and choroid plexus segmentation method in infant brain MR images.
Journal: BMC medical imaging
In common: SimpleITK, scikit-image, NiBabel, 4 other tools, developmental, 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.

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.