OSCR

Revisiting intensity normalization in brain [<sup>18</sup>F]FDG PET: What is reliable in autoimmune encephalitis?

Code ↔ Paper

The paper beside its authors' code: matches between them have not been computed for this paper yet.

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 · 190 lines · 6.5 KB · MIT

  1. import os
  2. import nibabel as nib
  3. import json
  4. import pydicom
  5. import pandas as pd
  6. import argparse
  7. import math
  8. def time_to_seconds(tstr):
  9. # DICOM time format HHMMSS.frac
  10. if '.' in tstr:
  11. tstr, frac = tstr.split('.')
  12. else:
  13. frac = '0'
  14. h = int(tstr[0:2])
  15. m = int(tstr[2:4])
  16. s = int(tstr[4:6])
  17. return h*3600 + m*60 + s + float("0."+frac)
  18. def find_first_dcmslice(dicom_dir, nifti_path):
  19. if nifti_path.endswith(".nii.gz"):
  20. series_uid = os.path.basename(nifti_path[:-7])
  21. elif nifti_path.endswith(".nii"):
  22. series_uid = os.path.basename(nifti_path[:-4])
  23. else:
  24. raise ValueError("Unsupported file extension. Only .nii and .nii.gz are supported.")
  25. for dirpath, dirnames, filenames in os.walk(dicom_dir):
  26. for filename in filenames:
  27. filepath = os.path.join(dirpath, filename)
  28. try:
  29. ds = pydicom.dcmread(filepath, stop_before_pixels=True)
  30. if ds.get("SeriesInstanceUID") == series_uid:
  31. return ds
  32. except Exception:
  33. continue
  34. return None
  35. def suv_conversion_parameters(ds):
  36. patient_weight_kg = ds.get("PatientWeight", None)
  37. if patient_weight_kg is None:
  38. raise ValueError("PatientWeight missing")
  39. patient_weight_g = patient_weight_kg * 1000
  40. # Radiopharmaceutical info sequence (usually only one)
  41. radsq = ds.RadiopharmaceuticalInformationSequence[0]
  42. injected_dose_Bq = radsq.get("RadionuclideTotalDose", None)
  43. if injected_dose_Bq is None:
  44. raise ValueError("Injected dose missing")
  45. half_life_s = radsq.get("RadionuclideHalfLife", None)
  46. if half_life_s is None:
  47. raise ValueError("Half-life missing")
  48. injection_time_str = radsq.get("RadiopharmaceuticalStartTime", None)
  49. acq_time_str = ds.get("AcquisitionTime", None)
  50. inj_sec = time_to_seconds(injection_time_str)
  51. acq_sec = time_to_seconds(acq_time_str)
  52. delta_t = acq_sec - inj_sec
  53. if delta_t < 0: # If acquisition is after midnight, adjust accordingly
  54. delta_t += 24*3600
  55. decay_factor = math.exp(-math.log(2) / half_life_s * delta_t)
  56. return patient_weight_g, injected_dose_Bq, decay_factor
  57. def identification(ds, info_dict):
  58. series_uid = ds.get("SeriesInstanceUID", None)
  59. name = ds.get("PatientName", None)
  60. patient_id = ds.get("PatientID", None)
  61. modality = ds.get("Modality", None)
  62. dob = ds.get("PatientBirthDate", None)
  63. sex = ds.get("PatientSex", None)
  64. dos = ds.get("StudyDate", None)
  65. weight = ds.get("PatientWeight", None)
  66. size = ds.get("PatientSize", None)
  67. injected_dose_Bq = None
  68. if "RadiopharmaceuticalInformationSequence" in ds:
  69. radsq = ds.RadiopharmaceuticalInformationSequence[0]
  70. injected_dose_Bq = radsq.get("RadionuclideTotalDose", None)
  71. recon_element = ds.get((0x0054, 0x1103), None)
  72. recon_method = recon_element.value if recon_element else None
  73. series_description = ds.get("SeriesDescription", None)
  74. # Update the passed dict with these key-value pairs
  75. info_dict.update({
  76. "SeriesUID": str(series_uid),
  77. "PatientName": str(name) if name else None,
  78. "PatientID": patient_id,
  79. "Modality": modality,
  80. "DateOfBirth": dob,
  81. "Sex": sex,
  82. "StudyDate": dos,
  83. "PatientWeight": weight,
  84. "PatientSize": size,
  85. "InjectedDose_Bq": injected_dose_Bq,
  86. "ReconstructionMethod": str(recon_method) if recon_method else None,
  87. "SeriesDescription": series_description
  88. })
  89. def compute_age(row):
  90. try:
  91. dob = pd.to_datetime(row['DateOfBirth'], format='%Y%m%d')
  92. study_date = pd.to_datetime(row['StudyDate'], format='%Y%m%d')
  93. age = (study_date - dob).days / 365.25
  94. return round(age, 1)
  95. except Exception:
  96. return None
  97. def convert_bqml_to_suv(bqml_dir, suv_dir, dicom_dir):
  98. parent_folder = os.path.abspath(bqml_dir).split(os.sep)[-2]
  99. info_list = []
  100. for filename in os.listdir(bqml_dir):
  101. if filename.endswith(".nii.gz"):
  102. source_path = os.path.join(bqml_dir, filename)
  103. json_path = source_path[:-7] + ".json"
  104. target_filename = filename[:-7] + ".nii"
  105. target_path = os.path.join(suv_dir, target_filename)
  106. elif filename.endswith(".nii"):
  107. source_path = os.path.join(bqml_dir, filename)
  108. json_path = source_path[:-4] + ".json"
  109. target_path = os.path.join(suv_dir, filename)
  110. else:
  111. continue
  112. try:
  113. with open(json_path, 'r') as f:
  114. meta = json.load(f)
  115. except FileNotFoundError:
  116. print(f" ⚠️ JSON metadata not found for {source_path}. Skipping.")
  117. continue
  118. units = meta.get("Units", "")
  119. if units != "BQML":
  120. print(f"⚠️ Skipping {source_path}: Data is not in BQML units — cannot apply SUV formula.")
  121. continue
  122. print(f"⚙️ Processing {source_path}...")
  123. img = nib.load(source_path)
  124. bqml_data = img.get_fdata()
  125. dcm_file = find_first_dcmslice(dicom_dir, source_path)
  126. if dcm_file is None:
  127. print(f" ⚠️ No matching DICOM slice found for {source_path}. Skipping.")
  128. continue
  129. try:
  130. weight, dose, decay = suv_conversion_parameters(dcm_file)
  131. suv_data = (bqml_data * weight) / (dose * decay)
  132. suv_img = nib.Nifti1Image(suv_data, img.affine, img.header)
  133. nib.save(suv_img, target_path)
  134. print(f" ✅ SUV conversion")
  135. info_dict = {}
  136. identification(dcm_file, info_dict=info_dict)
  137. info_list.append(info_dict)
  138. except ValueError as e:
  139. print(f" ❌ Skipping {source_path}: {e}")
  140. # Save the info as Excel
  141. if info_list:
  142. df = pd.DataFrame(info_list)
  143. df['Sex_binary'] = df['Sex'].map({'M': 0, 'F': 1})
  144. df['Age'] = df.apply(compute_age, axis=1)
  145. dfpath = os.path.join(parent_folder, "infos.xlsx")
  146. df.to_excel(dfpath, index=False)
  147. print(f"📄 Info saved to {dfpath}")
  148. def main():
  149. parser = argparse.ArgumentParser(description="Convert BQML NIfTI files to SUV using DICOM metadata.")
  150. parser.add_argument("bqml_dir", help="Directory containing BQML .nii.gz files")
  151. parser.add_argument("suv_dir", help="Output directory for SUV .nii files")
  152. parser.add_argument("dicom_dir", help="Directory containing DICOM files")
  153. args = parser.parse_args()
  154. convert_bqml_to_suv(args.bqml_dir, args.suv_dir, args.dicom_dir)
  155. if __name__ == "__main__":
  156. main()

bqml2suv.py at commit 984cc08, under MIT · at the source

Overview

Authors: Fiene Marie Kuijper1,2, Antoine Rogeau1,3, Hélène Rostand1,4, Alberto Picca5, Cristina Birzu6, Vincent Navarro7, Louis Cousyn7, Vincent Davy8, Dimitri Psimaras5, Aurélie Kas1,3
  1. Department of Nuclear Medicine, Pitié-Salpêtrière Hospital, Assistance Publique-Hôpitaux de Paris (AP-HP), Sorbonne Université, Paris, France
  2. Department of Nuclear Medicine, Institut Curie, 92210, Saint-Cloud, France
  3. Laboratoire d'Imagerie Biomédicale, Sorbonne Université, INSERM, CNRS, Paris, France
  4. Department of Nuclear Medicine, Saint-Louis Hospital, Assistance Publique-Hôpitaux de Paris (AP-HP), Sorbonne Université, Paris, France
  5. Department of Neuro-Oncology, DMU Neurosciences, Pitié-Salpêtrière Hospital, AP-HP, Sorbonne Université. Paris Reference Centre on Paraneoplastic Neurological Syndromes and Autoimmune Encephalitis (Sorbonne Université, UMR S 1127, Inserm U 1127, CNRS UMR 7225, ICM-Paris Brain Institute, Paris, France
  6. FranceMeLiS Institute -UCBL-CNRS UMR 5284 - INSERM U1314, Université Claude Bernard Lyon 1 (French Reference Centre on Paraneoplastic Neurological Syndromes and Autoimmune Encephalitis, Hospices Civils de Lyon, Hôpital Neurologique, Bron, France
  7. AP-HP, Department of Neurology, Epilepsy Unit, Reference Center of rare epilepsies, ERN EPicare, Pitié-Salpêtrière University Hospital, and Paris Brain Institute (Inserm, CNRS, Sorbonne Université), Paris, France
  8. Department of Neurology, Pitié-Salpêtrière Hospital, AP-HP, Sorbonne Université, Paris, France
Journal: NeuroImage. Clinical, volume 51, article 104037
Dates: received 11 May 2026; accepted 18 July 2026; published online 19 July 2026; in print 2026
Type: Research article · Language: English
License: CC BY-NC
Identifiers: DOI 10.1016/j.nicl.2026.104037 · PMID 42485846 · PMCID PMC13396930 · OpenAlex W7169792341
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: PET / SPECT (modality), human (organism), other condition (population), cellular / molecular (subfield)
Methods: Statistics, fMRI & imaging
Keywords: Intensity normalization, Brain [18F]FDG PET, Autoimmune encephalitis, SPM12, Neuroinflammation
MeSH: Autoimmune Diseases of the Nervous System*, Brain*, Encephalitis*, Hashimoto Disease*, Positron-Emission Tomography*, Adult, Aged, Female, Fluorodeoxyglucose F18, Humans, Male, Middle Aged, Radiopharmaceuticals (* major topic)
Topic: Autoimmune Neurological Disorders and Treatments (Neurology, Medicine), according to OpenAlex
Citations: not cited yet (Europe PMC); 35 references in the paper

Abstract

Purpose: Data-driven intensity normalization has emerged as an alternative to proportional scaling (PS) and reference-region methods in brain [18F]FDG PET. However, no consensus exists for autoimmune encephalitis (AE), whose variable metabolic patterns and lack of a reliable disease-free reference region complicate normalization. We compared three methods; PS, iterative PS (iPS), and pons-based reference-region (RR) normalization, in patients with definite AE (n = 29, 42 ± 20 years) and healthy controls (HC; n = 53, 46 ± 15 y/o) examined with brain [18F]FDG PET at diagnosis.

Methods: Three sets of normalized [18F]FDG PET images (2 MBq/kg, Biograph mCT Flow PET/CT system, Siemens Healthcare) were generated using: (1) PS with an eroded AAL grey-matter mask; (2) iPS, applying PS then excluding voxels deviating from controls (SPM12, F-contrast p < 0.01 uncorrected) to create a subject-specific mask; and (3) RR, normalizing to mean pons uptake. Effects were assessed through voxel-based AE vs. HC comparisons in SPM12. Two limbic AE cases were analyzed longitudinally.

Results: PS and iPS revealed basal ganglia and mesiotemporal hypermetabolism in AE vs. HC that RR failed to detect (p < 0.05 FWE corrected). All methods identified cortical hypometabolism, slightly more extensive with RR. PS and iPS yielded broadly similar results. Follow-up showed that iPS and PS better captured initial abnormalities than RR.

Conclusion: PS and iterative PS may provide more robust normalization than RR in AE. As interest in neuroinflammatory disorders grows, standardized normalization protocols are needed to ensure consistency across studies.

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

Repository

Its files are read in the Code ↔ Paper reader above.

rogeau/fdg-pet-intensitynorm-ae

License: MIT
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 984cc083dd369cf23a3917696e69f2906ddca4d5, 30 June 2026
Languages: MATLAB (7), Shell (5), Python (4)
Size: 29 files, 16 scripts
Software Heritage: not archived
Found in: “Data availability”
Holds: README, license file, environment (environment.yml)
Not found: CITATION.cff, tests, continuous integration, documentation
Tools: SPM (7 files), pandas (4 files), NiBabel (3 files), NumPy (2 files), dcm2niix (1 file), Image Processing Toolbox (1 file), Matplotlib (1 file), pydicom (1 file), SciPy (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
18 files

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:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 16 scripts, each with its path and the digest of its content;
  • no match between paragraphs and code yet;
  • 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

The full processing pipeline is available as a unified workflow in a publicly accessible repository (https://github.com/rogeau/fdg-pet-intensitynorm-ae). The datasets generated during and/or analyzed during the current study are available from the corresponding author on reasonable request.

Reproduced under the paper's license (CC BY-NC), 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, 10 authors, 5 keywords, 13 MeSH terms, 35 references.

Cite

This paper

Kuijper, F. M., Rogeau, A., Rostand, H., Picca, A., Birzu, C., Navarro, V., Cousyn, L., Davy, V., Psimaras, D., & Kas, A. (2026). Revisiting intensity normalization in brain [&lt;sup&gt;18&lt;/sup&gt;F]FDG PET: What is reliable in autoimmune encephalitis? NeuroImage. Clinical, 51, 104037. https://doi.org/10.1016/j.nicl.2026.104037

BibTeX

@article{kuijper2026revisiting,
author = {Kuijper, Fiene Marie and Rogeau, Antoine and Rostand, Hélène and Picca, Alberto and Birzu, Cristina and Navarro, Vincent and Cousyn, Louis and Davy, Vincent and Psimaras, Dimitri and Kas, Aurélie},
title = {{Revisiting intensity normalization in brain [\&lt;sup\&gt;18\&lt;/sup\&gt;F]FDG PET: What is reliable in autoimmune encephalitis?}},
journal = {NeuroImage. Clinical},
year = {2026},
month = jul,
volume = {51},
pages = {104037},
publisher = {Elsevier},
issn = {2213-1582},
doi = {10.1016/j.nicl.2026.104037},
url = {https://doi.org/10.1016/j.nicl.2026.104037},
pmid = {42485846},
pmcid = {PMC13396930}
}

RIS

TY - JOUR
AU - Kuijper, Fiene Marie
AU - Rogeau, Antoine
AU - Rostand, Hélène
AU - Picca, Alberto
AU - Birzu, Cristina
AU - Navarro, Vincent
AU - Cousyn, Louis
AU - Davy, Vincent
AU - Psimaras, Dimitri
AU - Kas, Aurélie
TI - Revisiting intensity normalization in brain [&lt;sup&gt;18&lt;/sup&gt;F]FDG PET: What is reliable in autoimmune encephalitis?
T2 - NeuroImage. Clinical
J2 - Neuroimage Clin
PY - 2026
DA - 2026/07/19
VL - 51
SP - 104037
SN - 2213-1582
PB - Elsevier
DO - 10.1016/j.nicl.2026.104037
UR - https://doi.org/10.1016/j.nicl.2026.104037
LA - en
ER -

CSL-JSON

{
"id": "10.1016/j.nicl.2026.104037",
"type": "article-journal",
"title": "Revisiting intensity normalization in brain [&lt;sup&gt;18&lt;/sup&gt;F]FDG PET: What is reliable in autoimmune encephalitis?",
"container-title": "NeuroImage. Clinical",
"author": [
{
"family": "Kuijper",
"given": "Fiene Marie"
},
{
"family": "Rogeau",
"given": "Antoine"
},
{
"family": "Rostand",
"given": "Hélène"
},
{
"family": "Picca",
"given": "Alberto"
},
{
"family": "Birzu",
"given": "Cristina"
},
{
"family": "Navarro",
"given": "Vincent"
},
{
"family": "Cousyn",
"given": "Louis"
},
{
"family": "Davy",
"given": "Vincent"
},
{
"family": "Psimaras",
"given": "Dimitri"
},
{
"family": "Kas",
"given": "Aurélie"
}
],
"container-title-short": "Neuroimage Clin",
"volume": "51",
"page": "104037",
"DOI": "10.1016/j.nicl.2026.104037",
"PMID": "42485846",
"PMCID": "PMC13396930",
"ISSN": "2213-1582",
"publisher": "Elsevier",
"URL": "https://doi.org/10.1016/j.nicl.2026.104037",
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
19
]
]
}
}

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.1002/hbm.70602 [code]
Neuroimaging Correlates of Post-Stroke Pain After Ischemic Stroke: Secondary Analysis of the INSPiRE-TMS Trial.
Journal: Human brain mapping
In common: pydicom, SPM, Image Processing Toolbox, 5 other tools, other condition
[2] doi:10.1038/s41586-026-10631-3 [code]
A prognostic human brain network for diffuse midline glioma.
Journal: Nature
In common: pydicom, SPM, Image Processing Toolbox, 5 other tools, other condition
[3] doi:10.1111/ene.70678 [code]
Who Falls After a Stroke? Evidence From a Prospective Stroke Cohort.
Journal: European journal of neurology
In common: pydicom, SPM, Image Processing Toolbox, 5 other tools
[4] doi:10.1016/j.celrep.2026.117404 [code]
Action and rest tremor map to distinct networks within the primary motor cortex.
Journal: Cell reports
In common: pydicom, SPM, Image Processing Toolbox, 5 other tools
[5] doi:10.1002/ana.78206 [code]
Multimodal Image Guidance in Subthalamic Deep Brain Stimulation for Parkinson's Disease.
Journal: Annals of neurology
In common: pydicom, SPM, Image Processing Toolbox, 5 other tools
[6] doi:10.1162/imag.a.1262 [code]
Frame-wise multi-echo distortion correction for superior functional MRI.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: pydicom, SPM, Image Processing Toolbox, 5 other tools
[7] doi:10.1038/s41597-026-07184-5 [code]
A Multiple Sclerosis MRI Dataset with Tri-Mask Annotations for Lesion Segmentation.
Journal: Scientific data
In common: dcm2niix, pydicom, NiBabel, 4 other tools
[8] doi:10.1038/s41598-026-54528-7 [code]
Enhanced sensorimotor cortex responsiveness to nonplegic hand stimulation and motor network assembly during recovery after spinal cord injury in primates.
Journal: Scientific reports
In common: pydicom, SPM, Image Processing Toolbox, 4 other tools, other condition
[9] doi:10.1038/s41597-026-07676-4 [code]
A neuroimaging dataset combining movie-watching, eye-tracking, sensorimotor mapping, and cognitive tasks.
Journal: Scientific data
In common: dcm2niix, SPM, NiBabel, 4 other tools
[10] doi:10.1038/s41467-026-71918-7 [code]
Developmental disinhibition gates language lateralization in childhood.
Journal: Nature communications
In common: dcm2niix, SPM, NiBabel, 4 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.