OSCR

Multi-BOUNTI: Multi-lobe Brain vOlUmetry and segmeNtation for feTal and neonatal MRI

Code ↔ Paper

4 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 4 matches
  1. [1] § Methods › Multi-lobe brain parcellation protocol ↔ scripts/auto-reporting-multi-bounti-brain-volumetry-fetal.py, lines 168–246 · score 0.89 · caudate nucleus, extracerebral CSF, Deep GM, lateral ventricles, vermis, cingulate
  2. [2] § Methods › Multi-lobe brain parcellation protocol ↔ scripts/auto-reporting-multi-bounti-brain-volumetry-neo.py, lines 173–251 · score 0.89 · caudate nucleus, extracerebral CSF, Deep GM, lateral ventricles, vermis, cingulate
  3. [3] § Results › Normative growth modelling ↔ scripts/auto-reporting-multi-bounti-brain-volumetry-fetal.py, lines 168–246 · score 0.83 · cavum volume, extracerebral CSF, deep GM, lateral ventricles, Cortical GM, vermis
  4. [4] § Results › Normative growth modelling ↔ scripts/auto-reporting-multi-bounti-brain-volumetry-neo.py, lines 173–251 · score 0.83 · cavum volume, extracerebral CSF, deep GM, lateral ventricles, Cortical GM, vermis

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 · 458 lines · 21 KB · GPL-3.0 · 2 matches

  1. import os
  2. import sys
  3. import base64
  4. from io import BytesIO
  5. import nibabel as nib
  6. import numpy as np
  7. import plotly.graph_objs as go
  8. import matplotlib.pyplot as plt
  9. from scipy.stats import norm
  10. from matplotlib.colors import ListedColormap
  11. REPORT_TITLE = "Multi-BOUNTI report for fetal MRI"
  12. GA_MIN = 20
  13. GA_MAX = 40
  14. LABEL_COLORS = {0: (0, 0, 0, 0.0), 1: (4, 51, 255, 1.0), 2: (21, 144, 156, 1.0), 3: (99, 22, 167, 1.0), 4: (103, 66, 230, 1.0), 5: (176, 51, 120, 1.0), 6: (190, 72, 8, 1.0), 7: (36, 131, 99, 1.0), 8: (23, 38, 95, 1.0), 9: (90, 40, 55, 1.0), 10: (131, 31, 44, 1.0), 11: (226, 121, 9, 1.0), 12: (212, 33, 20, 1.0), 13: (217, 75, 59, 1.0), 14: (188, 113, 217, 1.0), 15: (87, 224, 239, 1.0), 16: (171, 56, 91, 1.0), 17: (212, 122, 212, 1.0), 18: (233, 122, 174, 1.0), 19: (167, 90, 162, 1.0), 20: (171, 107, 130, 1.0), 21: (147, 112, 219, 1.0), 22: (55, 150, 190, 1.0), 23: (120, 34, 185, 1.0), 24: (29, 94, 199, 1.0), 25: (255, 191, 0, 1.0), 26: (255, 255, 255, 1.0), 27: (149, 132, 39, 1.0), 28: (153, 47, 33, 1.0), 29: (96, 0, 128, 1.0), 30: (134, 176, 92, 1.0), 31: (149, 6, 78, 1.0), 32: (131, 63, 24, 1.0), 33: (140, 35, 38, 1.0), 34: (141, 32, 158, 1.0), 35: (135, 47, 176, 1.0), 36: (162, 52, 104, 1.0), 37: (156, 255, 161, 1.0), 38: (174, 219, 255, 1.0), 39: (92, 167, 221, 1.0), 40: (115, 212, 175, 1.0), 41: (112, 139, 248, 1.0), 42: (171, 62, 25, 1.0), 43: (169, 82, 226, 1.0)}
  15. COEFFICIENTS = {'DGM_caudate_nucleus_volume': {'a50': 0.00396901070925127,
  16. 'astd': -5.86084682909637e-06,
  17. 'b50': -0.144544873360137,
  18. 'bstd': 0.00720446615292477,
  19. 'c50': 1.51498173637729,
  20. 'cstd': -0.11662908394105},
  21. 'DGM_lentiform_nucleus_volume': {'a50': 0.0061961627641139,
  22. 'astd': 0.000897673714326503,
  23. 'b50': -0.138715906260165,
  24. 'bstd': -0.0354996504407343,
  25. 'c50': 1.07514141158107,
  26. 'cstd': 0.447699389627272},
  27. 'DGM_thalamus_volume': {'a50': 0.00955522116813633,
  28. 'astd': 0.0003,
  29. 'b50': -0.235677179714089,
  30. 'bstd': -0.0015,
  31. 'c50': 1.9980690463482,
  32. 'cstd': 0.001},
  33. 'GM_cingulate_volume': {'a50': 0.00725241123289672,
  34. 'astd': 0.0,
  35. 'b50': -0.204525212101765,
  36. 'bstd': 0.0165,
  37. 'c50': 1.69647501148509,
  38. 'cstd': -0.3},
  39. 'GM_frontal_volume': {'a50': 0.0807,
  40. 'astd': 0.0069730214009038,
  41. 'b50': -3.1238,
  42. 'bstd': -0.274596736245797,
  43. 'c50': 33.0,
  44. 'cstd': 2.92539054001209},
  45. 'GM_insular_volume': {'a50': 0.00489876140350367,
  46. 'astd': 9.21597910923961e-05,
  47. 'b50': -0.166087051284211,
  48. 'bstd': 0.00235338930143109,
  49. 'c50': 1.70170537368668,
  50. 'cstd': -0.0640889669501304},
  51. 'GM_occipital_volume': {'a50': 0.0522,
  52. 'astd': 0.00522246567276285,
  53. 'b50': -2.1976,
  54. 'bstd': -0.23782423620518,
  55. 'c50': 25.0,
  56. 'cstd': 2.97201936200651},
  57. 'GM_parietal_volume': {'a50': 0.068,
  58. 'astd': 0.00721991229188154,
  59. 'b50': -2.8658,
  60. 'bstd': -0.328232894396965,
  61. 'c50': 32.0,
  62. 'cstd': 3.98920903828335},
  63. 'GM_temporal_volume': {'a50': 0.0533,
  64. 'astd': 0.00691489732001121,
  65. 'b50': -2.1688,
  66. 'bstd': -0.335237539622198,
  67. 'c50': 24.0,
  68. 'cstd': 4.34799834019574},
  69. 'WM_cingulate_volume': {'a50': 0.0075, 'astd': 0.0002, 'b50': 0.0033, 'bstd': 0.0285, 'c50': -2.0, 'cstd': -0.5},
  70. 'WM_frontal_volume': {'a50': 0.0375,
  71. 'astd': 0.016266611980808,
  72. 'b50': 0.9604,
  73. 'bstd': -0.63189332164781,
  74. 'c50': -30.0,
  75. 'cstd': 7.1073860580842},
  76. 'WM_insular_volume': {'a50': 0.00423156582442052,
  77. 'astd': 0.00165228115360945,
  78. 'b50': 0.0840136045572269,
  79. 'bstd': -0.0664590616154003,
  80. 'c50': -2.97419860973309,
  81. 'cstd': 0.812608727985254},
  82. 'WM_occipital_volume': {'a50': 0.002,
  83. 'astd': 0.00410861811688998,
  84. 'b50': 0.7953,
  85. 'bstd': -0.147399595291602,
  86. 'c50': -15.0,
  87. 'cstd': 1.8216795235438},
  88. 'WM_parietal_volume': {'a50': 0.0016,
  89. 'astd': 0.00915497532531195,
  90. 'b50': 1.5921,
  91. 'bstd': -0.362102769861644,
  92. 'c50': -30.0,
  93. 'cstd': 4.34624905746771},
  94. 'WM_temporal_volume': {'a50': 0.0003779264251499,
  95. 'astd': 0.00387492902328718,
  96. 'b50': 1.50633955759368,
  97. 'bstd': -0.10118723932875,
  98. 'c50': -28.8835869558016,
  99. 'cstd': 0.902406490021678},
  100. 'brainstem_volume': {'a50': 0.00325533324578462,
  101. 'astd': -0.000251263825187535,
  102. 'b50': 0.108431411226112,
  103. 'bstd': 0.0295439063464388,
  104. 'c50': -2.44103040073891,
  105. 'cstd': -0.435844321785417},
  106. 'cavum_volume': {'a50': -0.0059, 'astd': -0.0006, 'b50': 0.3724, 'bstd': 0.0425, 'c50': -5.0, 'cstd': -0.5},
  107. 'cerebellum_volume': {'a50': 0.0466480977799726,
  108. 'astd': 0.00360987762439721,
  109. 'b50': -1.87938070214712,
  110. 'bstd': -0.139930405061914,
  111. 'c50': 20.0650374338015,
  112. 'cstd': 1.45705276266902},
  113. 'eCSF_volume': {'a50': -0.1373,
  114. 'astd': -0.0163712639081,
  115. 'b50': 13.542,
  116. 'bstd': 1.59785166806484,
  117. 'c50': -200.0,
  118. 'cstd': -22.5734944518328},
  119. 'fourth_ventricle_volume': {'a50': 0.00054566572903546,
  120. 'astd': 8e-05,
  121. 'b50': -0.018992164615086,
  122. 'bstd': -0.0018,
  123. 'c50': 0.208952525904693,
  124. 'cstd': 0.01},
  125. 'lateral_ventricles_volume': {'a50': 0.0016, 'astd': 0.0, 'b50': 0.0209, 'bstd': 0.0692, 'c50': 2.0, 'cstd': -1.0},
  126. 'third_ventricle_volume': {'a50': 0.00107157558561917,
  127. 'astd': 0.000139373400159916,
  128. 'b50': -0.0363541901140626,
  129. 'bstd': -0.00276526640102309,
  130. 'c50': 0.340438967164873,
  131. 'cstd': 0.00491863412204744},
  132. 'total_DGM_volume': {'a50': 0.0197203946415015,
  133. 'astd': 0.000559296254541606,
  134. 'b50': -0.518937959334391,
  135. 'bstd': 0.000725552297728093,
  136. 'c50': 4.58819219430656,
  137. 'cstd': -0.110900894302876},
  138. 'total_WM_volume': {'a50': -0.0113602088278119,
  139. 'astd': 0.0380689771119069,
  140. 'b50': 8.79713006822208,
  141. 'bstd': -1.55198182922729,
  142. 'c50': -165.36273860942,
  143. 'cstd': 19.009669220147},
  144. 'total_brain_volume': {'a50': 0.0560772598864699,
  145. 'astd': -0.000714222351371512,
  146. 'b50': 18.384225646449,
  147. 'bstd': 1.1641566302025,
  148. 'c50': -360.048274167276,
  149. 'cstd': -16.6440446985629},
  150. 'total_cortical_GM_volume': {'a50': 0.2637,
  151. 'astd': 0.0263547371654088,
  152. 'b50': -10.563,
  153. 'bstd': -1.18408376936538,
  154. 'c50': 115.0,
  155. 'cstd': 14.4135618576711},
  156. 'total_parenchyma_volume': {'a50': 0.358001106623485,
  157. 'astd': 0.0446046125027615,
  158. 'b50': -5.21711385459465,
  159. 'bstd': -1.46460400627443,
  160. 'c50': -14.5840861004746,
  161. 'cstd': 14.2399945149215},
  162. 'vermis_volume': {'a50': 0.0039, 'astd': 0.0003, 'b50': -0.0909, 'bstd': -0.0056, 'c50': 0.5, 'cstd': 0.005}}
  163. ROI_LABELS = {
  164. "total_brain_volume": list(range(1, 44)),
  165. "total_parenchyma_volume": list(range(1, 37)),
  166. "total_cortical_GM_volume": list(range(1, 13)),
  167. "total_WM_volume": list(range(13, 25)),
  168. "total_DGM_volume": [31, 32, 33, 34, 35, 36],
  169. "GM_frontal_volume": [1, 2],
  170. "GM_parietal_volume": [3, 4],
  171. "GM_occipital_volume": [5, 6],
  172. "GM_insular_volume": [7, 8],
  173. "GM_temporal_volume": [9, 10],
  174. "GM_cingulate_volume": [11, 12],
  175. "WM_frontal_volume": [13, 14],
  176. "WM_parietal_volume": [15, 16],
  177. "WM_occipital_volume": [17, 18],
  178. "WM_insular_volume": [19, 20],
  179. "WM_temporal_volume": [21, 22],
  180. "WM_cingulate_volume": [23, 24],
  181. "brainstem_volume": [27],
  182. "cerebellum_volume": [28, 29],
  183. "vermis_volume": [30],
  184. "DGM_caudate_nucleus_volume": [31, 32],
  185. "DGM_lentiform_nucleus_volume": [33, 34],
  186. "DGM_thalamus_volume": [35, 36],
  187. "eCSF_volume": [37, 38],
  188. "lateral_ventricles_volume": [39, 40],
  189. "right_lateral_ventricle_volume": [39],
  190. "left_lateral_ventricle_volume": [40],
  191. "cavum_volume": [41],
  192. "third_ventricle_volume": [42],
  193. "fourth_ventricle_volume": [43],
  194. }
  195. DISPLAY_NAMES = {
  196. "total_brain_volume": "Total brain volume",
  197. "total_parenchyma_volume": "Total parenchyma volume",
  198. "total_cortical_GM_volume": "Total cortical GM volume",
  199. "total_WM_volume": "Total WM volume",
  200. "total_DGM_volume": "Total deep GM volume",
  201. "GM_frontal_volume": "GM frontal volume",
  202. "GM_parietal_volume": "GM parietal volume",
  203. "GM_occipital_volume": "GM occipital volume",
  204. "GM_insular_volume": "GM insular volume",
  205. "GM_temporal_volume": "GM temporal volume",
  206. "GM_cingulate_volume": "GM cingulate volume",
  207. "WM_frontal_volume": "WM frontal volume",
  208. "WM_parietal_volume": "WM parietal volume",
  209. "WM_occipital_volume": "WM occipital volume",
  210. "WM_insular_volume": "WM insular volume",
  211. "WM_temporal_volume": "WM temporal volume",
  212. "WM_cingulate_volume": "WM cingulate volume",
  213. "brainstem_volume": "Brainstem volume",
  214. "cerebellum_volume": "Cerebellum volume",
  215. "vermis_volume": "Vermis volume",
  216. "DGM_caudate_nucleus_volume": "Caudate nucleus volume",
  217. "DGM_lentiform_nucleus_volume": "Lentiform nucleus volume",
  218. "DGM_thalamus_volume": "Thalamus volume",
  219. "eCSF_volume": "Extracerebral CSF volume",
  220. "lateral_ventricles_volume": "Total lateral ventricles volume",
  221. "right_lateral_ventricle_volume": "Right lateral ventricle volume",
  222. "left_lateral_ventricle_volume": "Left lateral ventricle volume",
  223. "cavum_volume": "Cavum volume",
  224. "third_ventricle_volume": "Third ventricle volume",
  225. "fourth_ventricle_volume": "Fourth ventricle volume",
  226. }
  227. ORDERED_VARIABLES = [
  228. "total_brain_volume","total_parenchyma_volume","total_cortical_GM_volume","total_WM_volume","total_DGM_volume",
  229. "GM_frontal_volume","GM_parietal_volume","GM_occipital_volume","GM_insular_volume","GM_temporal_volume","GM_cingulate_volume",
  230. "WM_frontal_volume","WM_parietal_volume","WM_occipital_volume","WM_insular_volume","WM_temporal_volume","WM_cingulate_volume",
  231. "brainstem_volume","cerebellum_volume","vermis_volume","DGM_caudate_nucleus_volume","DGM_lentiform_nucleus_volume",
  232. "DGM_thalamus_volume","eCSF_volume","lateral_ventricles_volume","right_lateral_ventricle_volume",
  233. "left_lateral_ventricle_volume","cavum_volume","third_ventricle_volume","fourth_ventricle_volume"
  234. ]
  235. label_rgba = np.zeros((44, 4), dtype=float)
  236. for _idx, (r, g, b, a) in LABEL_COLORS.items():
  237. label_rgba[_idx] = [r/255.0, g/255.0, b/255.0, a]
  238. jet_transparent = ListedColormap(label_rgba)
  239. def compute_volume_cc(label_matrix, labels, voxel_dims):
  240. voxel_volume_mm3 = float(voxel_dims[0] * voxel_dims[1] * voxel_dims[2])
  241. n_vox = int(np.isin(label_matrix, labels).sum())
  242. return (n_vox * voxel_volume_mm3) / 1000.0
  243. def model_mean_std(variable, ga):
  244. c = COEFFICIENTS[variable]
  245. ga_arr = np.asarray(ga, dtype=float)
  246. mean = c["a50"] * ga_arr**2 + c["b50"] * ga_arr + c["c50"]
  247. std = c["astd"] * ga_arr**2 + c["bstd"] * ga_arr + c["cstd"]
  248. std = np.maximum(std, 1e-6)
  249. return mean, std
  250. def model_mean_std_side_lateral(ga):
  251. mean_total, std_total = model_mean_std("lateral_ventricles_volume", ga)
  252. return mean_total / 2.0, np.maximum(std_total / 2.0, 1e-6)
  253. def centile_graph(variable, ga, measured_cc):
  254. x = np.linspace(GA_MIN, GA_MAX, 200)
  255. if variable in ("right_lateral_ventricle_volume", "left_lateral_ventricle_volume"):
  256. m, s = model_mean_std_side_lateral(x)
  257. else:
  258. m, s = model_mean_std(variable, x)
  259. m = np.asarray(m, dtype=float)
  260. s = np.asarray(s, dtype=float)
  261. y5 = m - 1.645 * s
  262. y95 = m + 1.645 * s
  263. finite = np.isfinite(x) & np.isfinite(m) & np.isfinite(y5) & np.isfinite(y95)
  264. x = x[finite]
  265. m = m[finite]
  266. y5 = y5[finite]
  267. y95 = y95[finite]
  268. x_plot = x.astype(float).tolist()
  269. m_plot = m.astype(float).tolist()
  270. y5_plot = y5.astype(float).tolist()
  271. y95_plot = y95.astype(float).tolist()
  272. y_all = np.concatenate([m, y5, y95, np.array([measured_cc], dtype=float)])
  273. y_min = float(np.nanmin(y_all))
  274. y_max = float(np.nanmax(y_all))
  275. pad = max((y_max - y_min) * 0.08, 1e-3)
  276. fig = go.Figure()
  277. fig.add_trace(go.Scatter(x=x_plot, y=m_plot, mode="lines", line=dict(color="black", width=2), name="50th"))
  278. fig.add_trace(go.Scatter(x=x_plot, y=y5_plot, mode="lines", line=dict(color="grey", dash="dot"), name="5th"))
  279. fig.add_trace(go.Scatter(x=x_plot, y=y95_plot, mode="lines", line=dict(color="grey", dash="dot"), name="95th"))
  280. fig.add_trace(go.Scatter(x=[float(ga)], y=[float(measured_cc)], mode="markers",
  281. marker=dict(color="red", size=10, symbol="x"), name="Measured"))
  282. fig.update_layout(
  283. title={"text": DISPLAY_NAMES[variable], "x": 0.5, "xanchor": "center"},
  284. xaxis_title="GA [weeks]",
  285. yaxis_title="volume [cc]",
  286. xaxis=dict(range=[GA_MIN, GA_MAX], gridcolor="lightgrey"),
  287. yaxis=dict(range=[0, y_max + pad], gridcolor="lightgrey"),
  288. plot_bgcolor="white",
  289. paper_bgcolor="white",
  290. showlegend=False,
  291. margin=dict(l=40, r=20, t=50, b=40),
  292. )
  293. return fig.to_html(full_html=False, include_plotlyjs=False)
  294. def evaluate_measurements(label_matrix, voxel_dims, ga):
  295. results = []
  296. for variable in ORDERED_VARIABLES:
  297. measured_cc = compute_volume_cc(label_matrix, ROI_LABELS[variable], voxel_dims)
  298. if variable in ("right_lateral_ventricle_volume", "left_lateral_ventricle_volume"):
  299. mean_cc, std_cc = model_mean_std_side_lateral(ga)
  300. else:
  301. mean_cc, std_cc = model_mean_std(variable, ga)
  302. mean_cc = float(mean_cc)
  303. std_cc = float(std_cc)
  304. z = (measured_cc - mean_cc) / std_cc
  305. centile = norm.cdf(z) * 100.0
  306. results.append({
  307. "variable": variable,
  308. "name": DISPLAY_NAMES[variable].replace(" volume", "").replace("Volume", ""),
  309. "volume_cc": measured_cc,
  310. "oe_ratio": float(measured_cc / mean_cc) if mean_cc != 0 else float("nan"),
  311. "mean_cc": mean_cc,
  312. "std_cc": std_cc,
  313. "z": float(z),
  314. "centile": float(centile),
  315. "graph": centile_graph(variable, ga, measured_cc),
  316. })
  317. return results
  318. def _select_slice_indices(label_data, axis, n_slices=7):
  319. other_axes = [0, 1, 2]
  320. other_axes.remove(axis)
  321. presence = np.any(label_data > 0, axis=tuple(other_axes))
  322. idx = np.where(presence)[0]
  323. if len(idx) == 0:
  324. size = label_data.shape[axis]
  325. return np.linspace(int(size * 0.35), int(size * 0.65), n_slices).astype(int).tolist()
  326. if len(idx) == 1:
  327. return [int(idx[0])] * n_slices
  328. # Focus on the central brain and avoid edge-adjacent slices
  329. q = np.linspace(0.30, 0.70, n_slices)
  330. sel = np.quantile(idx, q)
  331. sel = np.clip(np.round(sel).astype(int), idx.min(), idx.max())
  332. return sel.tolist()
  333. def _show_slice(ax, img2d, lab2d=None, alpha=0.4):
  334. ax.imshow(img2d.T, cmap="gray", origin="lower")
  335. if lab2d is not None:
  336. ax.imshow(lab2d.T, cmap=jet_transparent, origin="lower", alpha=alpha, vmin=0, vmax=43)
  337. ax.axis("off")
  338. def plot_brain_image(t2w_data, label_data):
  339. n_slices = 7
  340. fig, axs = plt.subplots(6, n_slices, figsize=(24, 18))
  341. alpha = 0.4
  342. axial_idx = _select_slice_indices(label_data, axis=2, n_slices=n_slices)
  343. coronal_idx = _select_slice_indices(label_data, axis=1, n_slices=n_slices)
  344. sagittal_idx = _select_slice_indices(label_data, axis=0, n_slices=n_slices)
  345. for i, sl in enumerate(axial_idx):
  346. _show_slice(axs[0, i], t2w_data[:, :, sl], None, alpha)
  347. _show_slice(axs[1, i], t2w_data[:, :, sl], label_data[:, :, sl], alpha)
  348. for i, sl in enumerate(coronal_idx):
  349. _show_slice(axs[2, i], t2w_data[:, sl, :], None, alpha)
  350. _show_slice(axs[3, i], t2w_data[:, sl, :], label_data[:, sl, :], alpha)
  351. for i, sl in enumerate(sagittal_idx):
  352. _show_slice(axs[4, i], t2w_data[sl, :, :], None, alpha)
  353. _show_slice(axs[5, i], t2w_data[sl, :, :], label_data[sl, :, :], alpha)
  354. plt.tight_layout()
  355. buf = BytesIO()
  356. plt.savefig(buf, format="png", dpi=140)
  357. buf.seek(0)
  358. image_b64 = base64.b64encode(buf.read()).decode("utf-8")
  359. plt.close(fig)
  360. return image_b64
  361. def render_report(case_id, ga, scan_date, brain_image_b64, results):
  362. rows_html = "".join(
  363. (
  364. (f"<tr style='color:#c00000;font-weight:700;'><td>{r['name']}</td><td>{r['volume_cc']:.2f}</td><td>{r['oe_ratio']:.3f}</td>"
  365. f"<td>{r['centile']:.2f}</td><td>{r['z']:.2f}</td></tr>")
  366. if (r['centile'] < 5 or r['centile'] > 95)
  367. else
  368. (f"<tr><td>{r['name']}</td><td>{r['volume_cc']:.2f}</td><td>{r['oe_ratio']:.3f}</td>"
  369. f"<td>{r['centile']:.2f}</td><td>{r['z']:.2f}</td></tr>")
  370. )
  371. for r in results
  372. )
  373. graphs_html = "".join(f"<div class='graph'>{r['graph']}</div>" for r in results)
  374. return f"""<!DOCTYPE html>
  375. <html lang='en'>
  376. <head>
  377. <meta charset='UTF-8'>
  378. <meta name='viewport' content='width=device-width, initial-scale=1.0'>
  379. <title>{REPORT_TITLE}</title>
  380. <script src='https://cdn.plot.ly/plotly-latest.min.js'></script>
  381. <style>
  382. body {{ font-family: Arial, sans-serif; margin: 20px; }}
  383. .info-table {{ width: 100%; max-width: 1100px; border-collapse: collapse; }}
  384. .info-table td, .info-table th {{ border: 1px solid #bbb; padding: 6px 8px; text-align: left; font-size: 13px; }}
  385. .brain-image {{ width: 100%; max-width: 1100px; height: auto; }}
  386. .graph-container {{ display: grid; grid-template-columns: repeat(3, minmax(320px, 1fr)); gap: 12px; }}
  387. .graph {{ border: 1px solid #ddd; padding: 4px; }}
  388. </style>
  389. </head>
  390. <body>
  391. <h1>{REPORT_TITLE}</h1>
  392. <table class='info-table'>
  393. <tr><td>Case ID</td><td>{case_id}</td></tr>
  394. <tr><td>GA</td><td>{ga:.2f} weeks</td></tr>
  395. <tr><td>Scan date</td><td>{scan_date}</td></tr>
  396. </table>
  397. <br>
  398. <img src='data:image/png;base64,{brain_image_b64}' alt='Segmentation overlay' class='brain-image'>
  399. <br><br>
  400. <table class='info-table'>
  401. <tr><th>ROI</th><th>Volume [cc]</th><th>O/E</th><th>Centile</th><th>Z-score</th></tr>
  402. {rows_html}
  403. </table>
  404. <br><br>
  405. <div class='graph-container'>{graphs_html}</div>
  406. </body></html>"""
  407. def main():
  408. if len(sys.argv) != 7:
  409. raise SystemExit("Usage: python script.py <case_id> <ga_weeks> <scan_date> <input_img_nii> <input_lab_nii> <output_html>")
  410. case_id = sys.argv[1]
  411. ga = float(sys.argv[2])
  412. scan_date = sys.argv[3]
  413. img_path = sys.argv[4]
  414. lab_path = sys.argv[5]
  415. output_html = sys.argv[6]
  416. img = nib.load(img_path)
  417. lab = nib.load(lab_path)
  418. img_data = np.asarray(img.get_fdata())
  419. lab_data = np.rint(np.asarray(lab.get_fdata())).astype(np.int16)
  420. voxel_dims = img.header.get_zooms()[:3]
  421. results = evaluate_measurements(lab_data, voxel_dims, ga)
  422. brain_image_b64 = plot_brain_image(img_data, lab_data)
  423. html = render_report(case_id, ga, scan_date, brain_image_b64, results)
  424. with open(output_html, "w", encoding="utf-8") as f:
  425. f.write(html)
  426. print(output_html)
  427. if __name__ == "__main__":
  428. main()

auto-reporting-multi-bounti-brain-volumetry-fetal.py at commit 8091553, under GPL-3.0 · at the source

Overview

Authors: Alena Uus1, Abi Fukami-Gartner1,2, Vanessa Kyriakopoulou1, Daniel Cromb1, Taeona Morgan1, Sophie Arulkumaran1, Alexia Egloff Collado1, Aysha Luis1, Roos Bos3, Antonis Makropoulos4, Andreas Schuh4, Emma Robinson5, Helena Sousa5, Maria Deprez5, Lucilio Cordero-Grande1,6, Charline Bradshaw1,7, Kathleen Colford1, Jana Hutter1,8,7, Anthony Price1, Jonathan O’Muircheartaigh1,2
and 9 other authorsAlexander Hammers9, Daniel Rueckert4,10,8, Serena Counsell1, Grainne McAlonan2, Tomoki Arichi1,11, A. David Edwards1, Joseph V. Hajnal1,11, Mary A. Rutherford1, Lisa Story1,12,13
13 affiliations
  1. Research Department of Early Life Imaging, School of Biomedical Engineering and Imaging Sciences, King’s College London, UK
  2. Department of Forensic and Neurodevelopmental Science, School of Academic Psychiatry, Kings College London, London, UK
  3. Department of Neonatology, UMC Utrecht, Utrecht, The Netherlands
  4. Department of Computing, Imperial College London, London, UK
  5. Research Department of Biomedical Computing, School of Biomedical Engineering and Imaging Sciences, King’s College London, London, UK
  6. Biomedical Image Technologies, Universidad Politécnica de Madrid and CIBER-BBN, Madrid, Spain
  7. Institute for Information Processing, Leibniz University Hannover, Hannover, Germany
  8. Munich Center for Machine Learning (MCML), Munich, Germany
  9. PET Imaging Centre, School of Biomedical Engineering and Imaging Sciences, King’s College London, London, UK
  10. Chair for AI in Healthcare and Medicine, Technical University of Munich (TUM) and TUM University Hospital, Munich, Germany
  11. Research Department of Imaging Physics and Engineering, School of Biomedical Engineering and Imaging Sciences, King’s College London, London, UK
  12. Department of Women and Children’s Health, School of Life Course and Population Sciences, King’s College London, London, UK
  13. Fetal Medicine Unit, Guy’s and St Thomas’ NHS Foundation Trust, London, UK
Dates: published online 22 April 2026
Type: Preprint
License: CC BY
Identifiers: DOI 10.64898/2026.04.21.26351376 · OpenAlex W7155158764
Open access: green, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), human (organism), developmental (subfield)
Methods: Connectivity, Statistics, Preprocessing, fMRI & imaging
Keywords: Automated segmentation, Brain parcellation, Fetal brain MRI, Neonatal brain MRI, Normative growth modelling
Topic: Fetal and Pediatric Neurological Disorders (Pediatrics, Perinatology and Child Health, Medicine), according to OpenAlex
Funding: European Research Council (319456)
Citations: not cited yet (Europe PMC); 39 references in the paper

Abstract

Regional volumetric assessment of perinatal brain development is currently limited by the lack of consistent high quality multi-regional segmentation methods applicable to both fetal and neonatal MRI. We present Multi-BOUNTI, a deep learning pipeline for automated multi-lobe segmentation of fetal and neonatal T2w brain MRI. The method is based on a dedicated 43-label parcellation protocol and a 3D Attention U-Net trained on brain MRI datasets of subjects spanning 21–44 weeks gestational/postmenstrual age. The pipeline integrates preprocessing, segmentation and volumetric analysis, and was evaluated on independent datasets, demonstrating fast (< 10 min/case) and accurate performance with high agreement to manually refined labels.

We demonstrate the application of the framework with 267 fetal and 593 neonatal MRI datasets from the developing Human Connectome Project without reported clinically significant brain anomalies to derive normative volumetric growth models across 21–44 weeks GA/PMA. These models were used to characterise developmental trajectories, assess differences between fetal and preterm neonatal cohorts, and analyse longitudinal changes. The resulting normative models were integrated into an automated reporting framework enabling subject-specific volumetric assessment via centiles and z-scores.

Multi-BOUNTI provides a unified and scalable approach for perinatal brain segmentation and volumetry, supporting large-scale studies and facilitating future clinical translation. The full pipeline is publicly available at https://github.com/SVRTK/perinatal-brain-mri-analysis.

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 4 matches between paragraphs and lines of code.

SVRTK/perinatal-brain-mri-analysis

License: GPL-3.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: 809155349417acfcc4b2b0fa8cab5f29312091e4, 21 September 2026
Languages: Shell (9), Python (5)
Size: 40 files, 14 scripts
Software Heritage: not archived
Found in: the text, “Multi-lobe brain segmentation pipeline”
Holds: README, license file
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: ANTs (8 files), Matplotlib (5 files), NiBabel (5 files), NumPy (5 files), SciPy (5 files), MONAI (3 files), PyTorch (3 files), Plotly (2 files)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
16 files

biomedia/mirtk

License: Apache-2.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: ef71a176c120447b3f95291901af7af8b4f00544, 27 February 2025
Languages: C/C++ (372), C++ (308), Python (20), Shell (6)
Size: 1,296 files, 706 scripts
Software Heritage: not archived
Found in: the end of the paper
Holds: README, license file, environment (Dockerfile, Docker/Ubuntu/Dockerfile), tests, continuous integration, documentation
Not found: CITATION.cff
Tools: NumPy (2 files), FreeSurfer (1 file), NiBabel (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
708 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:

  • 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 720 scripts, each with its path and the digest of its content;
  • 4 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.

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, 29 September 2026: the first record

Recorded: type, journal, dates, 29 authors, 5 keywords, 1 funder, 35 references.

Cite

This paper

Uus, A., Fukami-Gartner, A., Kyriakopoulou, V., Cromb, D., Morgan, T., Arulkumaran, S., Collado, A. E., Luis, A., Bos, R., Makropoulos, A., Schuh, A., Robinson, E., Sousa, H., Deprez, M., Cordero-Grande, L., Bradshaw, C., Colford, K., Hutter, J., Price, A., . . . Story, L. (2026). Multi-BOUNTI: Multi-lobe Brain vOlUmetry and segmeNtation for feTal and neonatal MRI. medRxiv (preprint). https://doi.org/10.64898/2026.04.21.26351376

BibTeX

@article{uus2026multi,
author = {Uus, Alena and Fukami-Gartner, Abi and Kyriakopoulou, Vanessa and Cromb, Daniel and Morgan, Taeona and Arulkumaran, Sophie and Collado, Alexia Egloff and Luis, Aysha and Bos, Roos and Makropoulos, Antonis and Schuh, Andreas and Robinson, Emma and Sousa, Helena and Deprez, Maria and Cordero-Grande, Lucilio and Bradshaw, Charline and Colford, Kathleen and Hutter, Jana and Price, Anthony and O’Muircheartaigh, Jonathan and Hammers, Alexander and Rueckert, Daniel and Counsell, Serena and McAlonan, Grainne and Arichi, Tomoki and Edwards, A. David and Hajnal, Joseph V. and Rutherford, Mary A. and Story, Lisa},
title = {{Multi-BOUNTI: Multi-lobe Brain vOlUmetry and segmeNtation for feTal and neonatal MRI}},
journal = {medRxiv (preprint)},
year = {2026},
month = apr,
publisher = {medRxiv},
doi = {10.64898/2026.04.21.26351376},
url = {https://doi.org/10.64898/2026.04.21.26351376}
}

RIS

TY - JOUR
AU - Uus, Alena
AU - Fukami-Gartner, Abi
AU - Kyriakopoulou, Vanessa
AU - Cromb, Daniel
AU - Morgan, Taeona
AU - Arulkumaran, Sophie
AU - Collado, Alexia Egloff
AU - Luis, Aysha
AU - Bos, Roos
AU - Makropoulos, Antonis
AU - Schuh, Andreas
AU - Robinson, Emma
AU - Sousa, Helena
AU - Deprez, Maria
AU - Cordero-Grande, Lucilio
AU - Bradshaw, Charline
AU - Colford, Kathleen
AU - Hutter, Jana
AU - Price, Anthony
AU - O’Muircheartaigh, Jonathan
AU - Hammers, Alexander
AU - Rueckert, Daniel
AU - Counsell, Serena
AU - McAlonan, Grainne
AU - Arichi, Tomoki
AU - Edwards, A. David
AU - Hajnal, Joseph V.
AU - Rutherford, Mary A.
AU - Story, Lisa
TI - Multi-BOUNTI: Multi-lobe Brain vOlUmetry and segmeNtation for feTal and neonatal MRI
T2 - medRxiv (preprint)
J2 - medRxiv
PY - 2026
DA - 2026/04/22
PB - medRxiv
DO - 10.64898/2026.04.21.26351376
UR - https://doi.org/10.64898/2026.04.21.26351376
ER -

CSL-JSON

{
"id": "10.64898/2026.04.21.26351376",
"type": "article",
"title": "Multi-BOUNTI: Multi-lobe Brain vOlUmetry and segmeNtation for feTal and neonatal MRI",
"container-title": "medRxiv (preprint)",
"author": [
{
"family": "Uus",
"given": "Alena"
},
{
"family": "Fukami-Gartner",
"given": "Abi"
},
{
"family": "Kyriakopoulou",
"given": "Vanessa"
},
{
"family": "Cromb",
"given": "Daniel"
},
{
"family": "Morgan",
"given": "Taeona"
},
{
"family": "Arulkumaran",
"given": "Sophie"
},
{
"family": "Collado",
"given": "Alexia Egloff"
},
{
"family": "Luis",
"given": "Aysha"
},
{
"family": "Bos",
"given": "Roos"
},
{
"family": "Makropoulos",
"given": "Antonis"
},
{
"family": "Schuh",
"given": "Andreas"
},
{
"family": "Robinson",
"given": "Emma"
},
{
"family": "Sousa",
"given": "Helena"
},
{
"family": "Deprez",
"given": "Maria"
},
{
"family": "Cordero-Grande",
"given": "Lucilio"
},
{
"family": "Bradshaw",
"given": "Charline"
},
{
"family": "Colford",
"given": "Kathleen"
},
{
"family": "Hutter",
"given": "Jana"
},
{
"family": "Price",
"given": "Anthony"
},
{
"family": "O’Muircheartaigh",
"given": "Jonathan"
},
{
"family": "Hammers",
"given": "Alexander"
},
{
"family": "Rueckert",
"given": "Daniel"
},
{
"family": "Counsell",
"given": "Serena"
},
{
"family": "McAlonan",
"given": "Grainne"
},
{
"family": "Arichi",
"given": "Tomoki"
},
{
"family": "Edwards",
"given": "A. David"
},
{
"family": "Hajnal",
"given": "Joseph V."
},
{
"family": "Rutherford",
"given": "Mary A."
},
{
"family": "Story",
"given": "Lisa"
}
],
"container-title-short": "medRxiv",
"DOI": "10.64898/2026.04.21.26351376",
"publisher": "medRxiv",
"URL": "https://doi.org/10.64898/2026.04.21.26351376",
"issued": {
"date-parts": [
[
2026,
4,
22
]
]
}
}

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.1162/imag.a.1164 [code]
Bias and generalizability of brain age prediction models: A multi-cohort evaluation with anatomical and interpretability insights.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: MONAI, ANTs, FreeSurfer, 6 other tools, structural MRI / diffusion
[2] doi:10.3389/fnins.2026.1870124 [code]
An end-to-end pipeline for automated fetal brain segmentation and biometry from 3D SSFP MRI.
Journal: Frontiers in neuroscience
In common: MONAI, NiBabel, PyTorch, 3 other tools, structural MRI / diffusion, 3 references
[3] doi:10.1016/j.crmeth.2026.101473 [code]
AmygdalaGo-BOLT for boundary-aware segmentation of the human amygdala.
Journal: Cell reports methods
In common: MONAI, ANTs, FreeSurfer, 5 other tools, structural MRI / diffusion
[4] doi:10.1038/s41467-026-71555-0 [code]
A deep representation learning model to predict response to vagus nerve stimulation.
Journal: Nature communications
In common: MONAI, ANTs, FreeSurfer, 5 other tools, structural MRI / diffusion
[5] doi:10.1038/s41467-026-76011-7 [code]
Human cortex organizes dynamic co-fluctuations along the sensorimotor-association axis.
Journal: Nature communications
In common: MONAI, ANTs, FreeSurfer, 5 other tools
[6] doi:10.1162/imag.a.1352 [code]
Brain-age in ultra-low-field MRI: How well does it work?
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: MONAI, ANTs, FreeSurfer, 4 other tools, structural MRI / diffusion
[7] 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: ANTs, FreeSurfer, Plotly, 5 other tools, structural MRI / diffusion
[8] doi:10.1016/j.xcrm.2026.102943 [code]
Parent-of-origin effects in Alzheimer's liability dissociate neurocognitive and cardiovascular traits in at-risk individuals.
Journal: Cell reports. Medicine
In common: ANTs, FreeSurfer, Plotly, 5 other tools
[9] doi:10.21203/rs.3.rs-9326213/v1 [code]
Multi-task fMRI outperforms resting-state fMRI for revealing task-invariant organization of the human brain
Journal: Research Square (preprint)
In common: ANTs, FreeSurfer, Plotly, 5 other tools
[10] doi:10.64898/2026.03.09.710558 [code]
Multi-task fMRI outperforms resting-state fMRI for revealing task-invariant organization of the human brain
Journal: bioRxiv (preprint)
In common: ANTs, FreeSurfer, Plotly, 5 other tools

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.