autods_pet.imaging#
Imaging subpackage: DICOM, normalization, registration, segmentation.
- autods_pet.imaging.compute_suvbw(pet_bqml, weight_kg, dose_bq)[source]#
Convert a PET image from Bq/mL to SUV body-weight.
- autods_pet.imaging.decay_dose(dose_bq, half_life_s, elapsed_s)[source]#
Apply radioactive decay:
dose * exp(-lambda * t).- Parameters:
- Returns:
Decayed dose in Bq.
- Return type:
Examples
>>> from autods_pet.imaging.normalization import decay_dose >>> round(decay_dose(370e6, 6586.2, 3600), 1) 253314180.2
- autods_pet.imaging.dicom_series_to_nifti(dicom_files, output_path)[source]#
Convert a DICOM series to a NIfTI file.
Uses SimpleITK’s
ImageSeriesReaderwith GDCM-based spatial ordering to ensure correct slice order.
- autods_pet.imaging.effective_dose(total_dose_bq, half_life_s, elapsed_s, decay_correction)[source]#
Determine the effective reference dose depending on the DICOM DecayCorrection tag.
- Parameters:
- Returns:
Dose in Bq to use as the SUV denominator.
- Return type:
Notes
The denominator must be the activity present in the patient at the same reference time the pixel values are corrected to:
ADMIN(and the non-standardYES/CORRECTED) means the pixels are decay corrected back to the injection time, so the raw injected dose is already the activity at that reference time.STARTmeans the pixels are decay corrected to the acquisition start time, the dominant Siemens and GE whole-body FDG convention. The reference activity is then the injected dose decayed from injection to acquisition.NONE(and unknown values, handled conservatively the same way) means the pixels hold the activity measured at acquisition, so the dose must likewise be decayed to that time.
- autods_pet.imaging.extract_ct_tags(dicom_path)[source]#
Extract CT metadata tags from a single DICOM file.
- autods_pet.imaging.extract_patient_weight(dicom_path)[source]#
Extract patient weight (kg) from a DICOM file.
- autods_pet.imaging.extract_pet_tags(dicom_path)[source]#
Extract PET metadata tags from a single DICOM file.
Handles nested
RadiopharmaceuticalInformationSequencewith top-level fallback for dose and half-life tags.- Returns:
Keys match the metadata expected by
normalize_pet():PatientID,StudyDate,AcquisitionTime,Units,DecayCorrection,RadiopharmaceuticalStartTime,RadiopharmaceuticalStartDateTime,RadionuclideTotalDose,RadionuclideHalfLife,SeriesInstanceUID,StudyInstanceUID. Missing tags are set to None.- Return type:
- Parameters:
Notes
RadiopharmaceuticalStartDateTime(0018,1078) carries the full date and time, so it survives multi-day protocols and is the only injection timestamp some Enhanced PET objects populate. It is read from the nested sequence first and from the top level as a fallback.
- autods_pet.imaging.find_dicom_files(patient_dir, size_threshold_kb=100)[source]#
Recursively find DICOM files above a size threshold.
Matching is case-insensitive on the
.dcmextension and also accepts extensionless (or oddly named) files that carry the Part 10DICMmagic, both of which are common in PACS exports.
- autods_pet.imaging.find_series_by_modality(patient_dir, size_threshold_kb=100)[source]#
Find the primary CT and PT DICOM series in a patient directory.
Groups
.dcmfiles by(Modality, SeriesInstanceUID), then picks the series with the most files for each modality.Note
This function reads DICOM headers for every
.dcmfile sequentially (O(n) disk reads, no parallelism). For directories with 1000+ files on network-attached storage this may be slow. Consider parallel header reads for high-throughput deployments.
- autods_pet.imaging.parse_dicom_date(dstr)[source]#
Parse a DICOM DA string (
YYYYMMDD) into adatetime.date.- Parameters:
dstr (
str) – DICOM DA-format string (e.g."20230415").- Return type:
- Raises:
ValueError – If dstr is too short or contains invalid month/day.
Examples
>>> from autods_pet.imaging.normalization import parse_dicom_date >>> parse_dicom_date("20230415") datetime.date(2023, 4, 15)
- autods_pet.imaging.parse_dicom_time(tstr)[source]#
Parse a DICOM TM string into a
datetime.time.Handles missing leading zeros, fractional seconds, and hours >= 24 (wrapped modulo 24). Out-of-range minutes and seconds are clamped to 59 with a warning, so a leap second (
ss == 60, permitted by the DICOM TM value representation) or a malformed field does not abort a run mid-cohort.- Parameters:
tstr (
str) – DICOM TM-format string (e.g."143012.123456").- Return type:
- Raises:
ValueError – If tstr is empty.
Examples
>>> from autods_pet.imaging.normalization import parse_dicom_time >>> parse_dicom_time("143012.000000") datetime.time(14, 30, 12) >>> parse_dicom_time("090000") datetime.time(9, 0) >>> parse_dicom_time("143060") # leap second datetime.time(14, 30, 59)
- autods_pet.imaging.resolve_patient_folder(basepath, patient_id)[source]#
Case-insensitive lookup for a patient subfolder.
Returns the resolved
Pathor None if no match is found.
- autods_pet.imaging.rigid_register_pet_to_ct(ct, pet, log_to_console=False, report_path=None)[source]#
Rigidly register pet onto the ct grid.
- Parameters:
ct (
Image) – CT image (fixed / reference frame).pet (
Image) – PET image (moving).log_to_console (
bool(default:False)) – If True, print Elastix iteration logs to stdout.report_path (
Path|None(default:None)) – If set, Elastix writesTransformParameters.0.txttoreport_path.parentand it is renamed to report_path.
- Returns:
PET resampled onto the CT grid (float64).
- Return type:
Image
- autods_pet.imaging.run_totalsegmentator(ct_path, output_dir, task='total', fast=False, output_filename=None)[source]#
Run TotalSegmentator on a CT image.
Uses the
--mlflag to produce a single multilabel NIfTI file namedTOTSEG_FILENAMEinside output_dir.Note
Paths are passed as subprocess arguments (list form, no shell). This mitigates OS command injection (CWE-78), but path traversal (CWE-22) is not validated. If this function is ever exposed via a network service, add explicit path validation.
- Parameters:
ct_path (
Path) – Path to the input CT NIfTI file.output_dir (
Path) – Directory where the segmentation output will be written.task (
str(default:'total')) – TotalSegmentator task name (default"total").fast (
bool(default:False)) – If True, use the--fastflag for lower resolution but faster inference.output_filename (
str|None(default:None)) – Custom filename for the output segmentation file. WhenNone(default), usesTOTSEG_FILENAME.
- Returns:
Path to the output segmentation file.
- Return type:
- autods_pet.imaging.seconds_between(injection, acquisition, max_uptake_hours=6.0)[source]#
Seconds elapsed from injection to acquisition, handling midnight wrap.
If the elapsed time is slightly negative (0 to
-max_uptake_hours), assumes the acquisition crossed midnight and adds 24 h. If more negative than-max_uptake_hours, still corrects but logs a warning.- Parameters:
injection (
datetime) – Radiopharmaceutical injection time.acquisition (
datetime) – PET acquisition time.max_uptake_hours (
float(default:6.0)) – Maximum expected injection-to-scan interval in hours. Negative elapsed times within this window are assumed to be midnight wraparounds. The default of 6 h is appropriate for standard 18F-FDG protocols (typical uptake ~60 min). Increase for tracers with longer uptake periods (e.g. 68Ga-DOTATATE).
- Returns:
Elapsed seconds (always >= 0 after midnight correction).
- Return type:
Examples
>>> from datetime import datetime >>> from autods_pet.imaging.normalization import seconds_between >>> seconds_between(datetime(2023, 1, 1, 9, 0), datetime(2023, 1, 1, 10, 0)) 3600.0