An end-to-end clinical machine learning platform that automates fetal head circumference (HC) estimation from 2D ultrasound scans, performs spatial scale calibration, and maps findings to gestational-age normative growth curves for growth restriction screening.
π Technical Approach & Methodology: For clinical researchers, data scientists, and engineers interested in the statistical and algorithmic designβincluding the convolutional segmentation architectures, morphological boundary isolation, least-squares quadric fitting, and the error function (
$\text{erf}$ ) implementation of standard normal cumulative distributionsβplease refer directly to the detailed METHODOLOGY.md.
"Intrauterine growth restriction (IUGR) affects up to 10% of pregnancies worldwide and remains a leading cause of perinatal morbidity and mortality." β Clinical Obstetrics and Gynecology Research
Fetal head circumference (HC) measured at the trans-thalamic plane is a primary biomarker for assessing gestational age and screening for intrauterine growth restriction (IUGR) or microcephaly. In typical clinical workflows, this measurement is obtained manually by sonographers placing an interactive ellipse overlay on a two-dimensional (2D) ultrasound monitor.
This manual workflow suffers from three structural constraints:
- Operator Subjectivity: Manual caliper placement introduces an inter-observer variability of 5% to 10%, leading to inconsistent growth percentile mapping across operators.
- Acoustic Artifacts: Ultrasound propagation is inherently limited by bone attenuation, speckle noise, and acoustic shadowing. These factors create discontinuous boundaries, rendering automated gradient-based edge detection useless.
- Throughput Bottlenecks: Manual caliper tracing requires active operator time, limiting patient throughput in under-resourced public clinics.
FetalMetrics-AI addresses these challenges head-on.
By combining deep convolutional networks (YOLOv8-seg and U-Net) with least-squares ellipse fitting and parametric perimeter estimation, the platform isolates and measures the fetal skull from raw scans. The resulting perimeter is mapped to Hadlock (1984) composite growth curves via a zero-dependency normal cumulative distribution function (
The platform is designed to function as an objective, auditable clinical research console. It processes scans on a standard CPU workstation in under 200 milliseconds, bypassing GPU infrastructure requirements. This makes it suitable for edge deployments in resource-constrained environments.
The application is styled with a clinical-light "medical instrument" theme. It focuses on numeric readability and reserves saturated colors (crimson, amber, and emerald) exclusively for clinical risk signaling.
|
1 Β· Analysis Console Side-by-side display of original ultrasound and the cyan-fitted ellipse segmentation overlay. |
2 Β· Clinical Dashboard Calibrated metric cards detailing measured HC (mm), expected weekly mean, z-score deviation, and estimated growth percentile. |
3 Β· Statistical Reference Dynamic Hadlock normative table lookup showing standard deviations and reference percentiles (10th, 50th, 90th). |
The platform measures and calculates four core parameters to place a biometric scan in a population growth context:
| Metric Name | Mathematical Form | Clinical Utility | Target Range |
|---|---|---|---|
| Cranial Axes | Semi-major ( |
Establishes physical dimension mapping from coordinates | Inferred from gestational age |
| Head Circumference | Ellipse Perimeter ( |
Primary physical biomarker of cranial development |
|
| Standard score | z-score ( |
Standard deviation unit distance from mean reference |
|
| Growth Percentile | Cumulative Probability ( |
Places fetus in relative population growth distribution |
|
The measured metrics map directly to screening risk bands:
-
High Risk (
$< 10\text{th}$ percentile): Screening threshold for Intrauterine Growth Restriction (IUGR). Warrants Doppler velocimetry correlation. -
Medium Risk (
$10\text{th} \le \text{Percentile} < 25\text{th}$ ): Borderline growth. Suggests monitoring of growth velocity via serial scans. -
Normal (
$\ge 25\text{th}$ percentile): Biometric indicators lie within normal biological variance.
The system processes input scans through a sequential, modular pipeline. This architecture ensures that each phase performs a single transformation that is verifiable in isolation:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INPUT ULTRASOUND β
β Raw PNG/JPG Scan Gestational Age (weeks) Uploaded Name β
βββββββββββββββββββββββββββββββββ€ββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β pixel_size.py β SPATIAL CALIBRATION LAYER β
β 1. Check HC18 lookup table for filename β
β 2. If collision: Resolve training/test splits using pixel-level β
β Mean Absolute Difference (MAD) against local references β
β 3. Fall back to manual input slider scale (if user override active) β
β 4. Apply DEFAULT_PIXEL_SIZE_MM fallback (triggers uncalibrated UI) β
βββββββββββββββββββββββββββββββββ€ββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β inference/ β DEEP INFRASTRUCTURE INFRASTRUCTURE β
β β
β [Option A: YOLOv8s-seg] [Option B: U-Net ResNet34] β
β β’ Letterbox to 640x640 β’ Resize to 256x256 β
β β’ Normalise to [0,1] β’ Standardise (ImageNet stats) β
β β’ ONNX Runtime Inference β’ ONNX Runtime Inference β
β β’ Assemble prototype masks β’ Apply numerically stable β
β using predicted coefficients sigmoid to logits β
β β’ Bounding-box crop & upscale β’ Nearest-neighbour upscale β
βββββββββββββββββββββββββββββββββ€ββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β postprocess/ β GEOMETRIC CLEANUP & RECONSTRUCTION β
β β’ Morphological closing (5x5 elliptical structuring element) β
β β’ Suzuki-Abe topological retrieval to isolate largest contour β
β β’ Area validation (>1% image canvas) & point constraint (>=5 coordinates)β
β β’ Fit parametric conic coordinates via least-squares solver β
β β’ Scale semi-major/semi-minor axes to mm using calibration factor β
β β’ Compute perimeter using Ramanujan's second approximation β
βββββββββββββββββββββββββββββββββ€ββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β clinical/ β STATISTICAL EVALUATION & MAPPING β
β β’ Interpolate population mean HC from weekly Hadlock reference tablesβ
β β’ Compute gestational-age standard deviation: β
β SD(GA) = 0.3846 * GA - 0.3846 mm (floored at 3.0 mm) β
β β’ Calculate z-score: z = (measured_HC - mean) / SD β
β β’ Evaluate cumulative probability CDF natively via math.erf β
β β’ Clamp percentile to [0.1, 99.9] and bin into risk classifications β
βββββββββββββββββββββββββββββββββ€ββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PRESENTATION LAYER (Streamlit) β
β β’ Render side-by-side overlays (PIL + OpenCV drawing) β
β β’ Display clinical gauges and metric dashboard β
β β’ Log latency timing metrics (Inference, Post-processing, Calib) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The HC18 dataset contains file naming overlaps between its training and test splits. Because spatial calibration values (
To resolve this, the system implements an automated Mean Absolute Difference (MAD) check. When a filename collision occurs, the system computes the following value:
If MAD < 5.0, the system matches the uploaded file to the correct split. This method resolves the collision without requiring manual input.
The system supports dual inference models without requiring GPU runtimes or PyTorch/TensorFlow dependencies in production:
- YOLOv8s-seg (Instance Segmentation): Reconstructs the mask as a linear combination of 32 prototype masks weighted by predicted coefficients. The output is cropped to the bounding box to suppress background noise.
-
U-Net ResNet34 (Semantic Segmentation): Outputs a dense probability map, which is thresholded at
$0.5$ to isolate the skull structure.
Both models are compiled to .onnx and managed via onnxruntime-cpu with thread and optimization parameters set to maximize CPU execution speed. This configuration achieves average CPU latency times under
Ultrasound boundaries are often discontinuous due to acoustic attenuation. Traditional edge detection algorithms struggle to isolate boundaries under these conditions.
The post-processing pipeline uses least-squares ellipse fitting to apply a geometric prior (the human skull is ellipsoid) directly to the binary mask. The coordinates of the largest external contour are extracted using the Suzuki-Abe algorithm and fitted to a general quadratic curve:
flowchart LR
A[Raw Mask from ONNX] --> B["Morphological Closing\n(ellipse kernel 5x5)"]
B --> C["Suzuki-Abe Contour Retrieval"]
C --> D{"Area Constraint\n& coordinate count >= 5"}
D -->|Valid| E["Least-Squares Ellipse Fit\n( cv2.fitEllipse )"]
D -->|Invalid| F[Reject Mask & Trigger Warning]
E --> G["Ramanujan II Perimeter\n( Calibrated HC )"]
To map a measured HC to a growth percentile, the system calculates the standard normal cumulative distribution function math.erf):
scipy.stats.norm.cdf for all clinical inputs but runs without external dependencies.
All parameters that affect clinical or geometric evaluations are isolated in a centralized configuration module:
| Key | Type | Default | Clinical/Operational Purpose |
|---|---|---|---|
GA_MIN_WEEKS |
float |
14.0 |
Lower boundary of supported gestational age reference. |
GA_MAX_WEEKS |
float |
40.0 |
Upper boundary of supported gestational age reference. |
HIGH_RISK_MAX_PCT |
float |
10.0 |
Percentile threshold below which an IUGR alert is triggered. |
MEDIUM_RISK_MAX_PCT |
float |
25.0 |
Upper bound of the borderline growth range. |
DEFAULT_PIXEL_SIZE_MM |
float |
0.15 |
Default pixel scale used when calibration lookup fails. |
POSTPROCESS["mask_threshold"] |
float |
0.5 |
Threshold applied to probability maps to produce binary masks. |
POSTPROCESS["morph_kernel"] |
int |
5 |
Diameter (pixels) of the morph closing structuring element. |
POSTPROCESS["min_area_frac"] |
float |
0.01 |
Minimum area fraction required to reject background noise blobs. |
@dataclass(frozen=True)
class ModelSpec:
key: str # Registry lookup identifier
display_name: str # UI toggle label
family: str # "yolov8_seg" | "unet"
weights_path: Path # Path to the exported ONNX model weights
input_size: tuple[int, int] # (height, width) expected by the network
channels: int = 3 # Input channels (1 = grayscale, 3 = RGB)
normalize: str = "scale" # "scale" (/255) or "standard"
mean: tuple[float, ...] = (0.0,) # Per-channel mean (standard normalization only)
std: tuple[float, ...] = (1.0,) # Per-channel std (standard normalization only)
conf_threshold: float = 0.25 # YOLOv8 confidence limit
iou_threshold: float = 0.45 # YOLOv8 NMS intersection threshold
description: str = "" # UI help textThe Streamlit interface was designed to function like a physical medical instrument, prioritizing visual clarity and clinical utility.
- Palette: Built on a medical-teal primary base (
#0F766E) for interactive widgets, a clinical-paper canvas background (#F4F6F9), and a white card layout (#FFFFFF) with thin borders (#E4E9F0). Color is used sparingly to draw focus to clinical metrics. - Typography: Mapped across three font families:
- Inter: Applied to the interface, controls, and sidebar components for legibility.
- IBM Plex Mono: Applied to numeric readouts and timing markers to align characters.
- Source Serif 4: Applied to the documentation page to improve readability during extended review sessions.
- Contrast Ratios: Custom CSS elements in
src/assets/styles.cssstyle native Streamlit elements to meet contrast guidelines. Risk text uses saturated variants (crimson#DC2626and amber#D97706) against white panels to remain readable. - Semantic HTML: UI wrappers use semantic section labels and headers to ensure screen-reader compatibility. Key values are wrapped in container structures to prevent overlaps on small displays.
- Lazy Module Importing: heavy libraries (like
onnxruntime,cv2, andpandas) are imported lazily inside the classes or methods that execute them. This prevents loading unnecessary packages during test runs or simple geometric calculations. - ONNX Session Caching: The ONNX session creation step is cached via
@st.cache_resourceinapp.py. This ensures that the weights are loaded into memory only once. Multiple browser sessions share the same cached session, reducing memory requirements.
Every library and tool in the repository was selected to support edge execution and auditability:
- ONNX Runtime (CPU): Replaces PyTorch and TensorFlow for execution. ONNX Runtime uses built-in optimizations (like graph fusion and memory reuse) to run models quickly on CPU.
- OpenCV: Used for pre-processing (scaling and resizing) and geometric operations (contour extraction and ellipse fitting).
- NumPy: Handles array transformations, NMS calculations, and coordinate conversions.
- Pandas: Used to parse calibration CSV tables during database lookup.
- Streamlit: Selected to build the clinical dashboard without requiring frontend dependencies. It runs the interface directly from Python.
- Pillow (PIL): Decodes uploaded image bytes and manages PIL-to-NumPy coordinate conversions.
- Hadlock Formula Core: Implemented with standard Python math libraries to ensure long-term stability and compatibility.
- HC18 Grand Challenge Dataset: Contains 999 training images and 335 test images with manual annotations and spatial calibrations. This dataset provides the validation metrics used to benchmark the models.
The performance of the models was evaluated on the validation set using a CPU benchmark workspace (
quadrantChart
title FetalMetrics-AI Model Comparison
x-axis "Higher Latency" --> "Lower Latency"
y-axis "Lower Segmentation Overlap" --> "Higher Segmentation Overlap"
quadrant-1 "Target Zone (Fast & Accurate)"
quadrant-2 "High Overlap (Compute Heavy)"
quadrant-3 "Underperforming"
quadrant-4 "Fast but Inaccurate"
"YOLOv8s-seg (Inference 141.9ms, Dice 0.967)": [0.78, 0.85]
"U-Net ResNet34 (Inference 187.0ms, Dice 0.975)": [0.45, 0.93]
| Evaluation Metric | YOLOv8s-seg (Primary) | U-Net ResNet34 (Baseline) | Clinical Meaning |
|---|---|---|---|
| Mean CPU Latency | Time required to process a scan on standard hardware. | ||
| P95 CPU Latency | Worst-case latency. Shows performance consistency. | ||
| Mean IoU (Jaccard) | Spatial overlap of predicted mask and ground truth. | ||
| Mean Dice Coefficient | Overall accuracy of the skull boundary mask. | ||
| Pixel Accuracy | Percentage of pixels correctly classified. |
-
U-Net achieves slightly higher overlap performance (Dice:
$0.975$ ), making it a reliable baseline. -
YOLOv8s-seg operates faster (Mean Latency:
$141.9\text{ ms}$ ), leaving more compute headroom on lower-spec terminal hardware. - Both models satisfy the
$\le 200\text{ ms}$ execution budget on CPU.
- Python 3.12+
- An active shell terminal.
# Clone the repository and navigate to the project directory
git clone https://github.com/sadmanhsakib/fetalmetrics-ai.git
cd fetalmetrics-ai
# Set up the virtual environment
python -m venv .venv
# Activate the environment (Windows PowerShell)
.venv\Scripts\Activate.ps1
# Activate the environment (macOS/Linux)
# source .venv/bin/activate
# Install requirements
pip install -r pyproject.tomlYou can run benchmarks directly from the command line:
# Validate YOLOv8-seg model performance
python scripts/test/validate_yolov8_onnx.py
# Validate U-Net model performance
python scripts/test/validate_unet_onnx.py
# Validate geometric and measurement post-processing accuracy
python scripts/test/validate_postprocessing.pystreamlit run src/app.pyThis command starts the local web server. Open your browser and navigate to http://localhost:8501.
fetalmetrics-ai/
βββ src/
β βββ app.py # Streamlit application entry point
β βββ config.py # Centralised configuration parameters
β βββ assets/
β β βββ styles.css # Clinical-light medical instrument stylesheet
β βββ calibration/
β β βββ __init__.py
β β βββ pixel_size.py # Spatial calibration resolver (HC18 lookup & manual override)
β βββ clinical/
β β βββ __init__.py
β β βββ percentiles.py # Standard score z-score & percentile logic
β β βββ reference_hadlock.py # Hadlock 1984 composite reference lookups
β β βββ risk.py # Clinical screening risk-band stratification
β βββ inference/
β β βββ __init__.py
β β βββ base.py # Abstract segmenter class & shared NumPy functions
β β βββ registry.py # Model registration and loading factory
β β βββ unet_onnx.py # U-Net decoder & inference runtime
β β βββ yolov8_onnx.py # YOLOv8-seg instance mask decoder
β βββ pages/
β β βββ 1_Methodology.py # Methodology page content
β βββ ui/
β βββ __init__.py
β βββ components.py # Clinical component UI templates
β βββ theme.py # Shared styling & navigation setups
βββ data/
β βββ raw/ # Raw HC18 challenge datasets (gitignored)
β βββ preprocessed/ # Output of preprocessing script (yolo/ & fastai/)
βββ models/
β βββ yolov8_hc.onnx # Exported YOLOv8 instance segmentation weights
β βββ unet_hc.onnx # Exported U-Net semantic segmentation weights
βββ notebooks/
β βββ train_YOLOv8.ipynb # Model training notebooks
β βββ train_unet.ipynb
βββ scripts/
β βββ dataset.py # Dataset fetching & Kaggle hub utilities
β βββ preprocess.py # Preprocessing script (outline morph filling)
β βββ test/ # Validation and benchmarking scripts
β βββ validate_postprocessing.py
β βββ validate_preprocessing.py
β βββ validate_unet_onnx.py
β βββ validate_yolov8_onnx.py
βββ pyproject.toml # Pyproject metadata
βββ uv.lock # Lock file
βββ METHODOLOGY.md # Technical methodology documentation
βββ README.md # Academic case study readme
The standard YOLOv8-seg export uses split heads to generate instance masks. It combines output1) using the weight coefficients predicted for the selected bounding box (output0). The final mask coordinates are calculated using the following NumPy logic:
# Assemble instance mask from prototypes
protos = np.asarray(protos)[0] # (32, mh, mw)
ch, mh, mw = protos.shape
# Compute linear combination of coefficients and prototypes
mask_small = sigmoid(
coeffs[best] @ protos.reshape(ch, -1)
).reshape(mh, mw)
# Upscale back to the letterboxed input dimension
mask_pad = cv2.resize(mask_small, (in_w, in_h), interpolation=cv2.INTER_LINEAR)The perimeter of the fitted ellipse is computed using Ramanujan's second approximation. This method provides sub-millimeter precision for the eccentricity ranges typical of the human fetal skull:
def ramanujan_perimeter(semi_major: float, semi_minor: float) -> float:
a = float(semi_major)
b = float(semi_minor)
if a <= 0 or b <= 0:
return 0.0
h = ((a - b) / (a + b)) ** 2
return math.pi * (a + b) * (1.0 + (3.0 * h) / (10.0 + math.sqrt(4.0 - 3.0 * h)))When the same image filename is found in both the training and test dataset splits, the system computes the pixel-level Mean Absolute Difference to select the correct calibration profile:
# Resolve image collision across splits
for dataset_name, path in [("training", train_path), ("test", test_path)]:
if not path.exists():
continue
local_img = np.array(Image.open(path).convert("RGB"))
if local_img.shape == image_rgb.shape:
diff = np.mean(
np.abs(image_rgb.astype(float) - local_img.astype(float))
)
if diff < min_diff:
min_diff = diff
best_dataset = dataset_nameThis project is licensed under the MIT License β see LICENSE for details.
This project utilizes data and models developed for the HC18 Grand Challenge. If you use this software in research work, please cite the following original literature:
- Hadlock FP et al. (1984). Estimating fetal age: computer-assisted analysis of multiple fetal growth parameters. Radiology, 152(2): 497-501.
- van den Heuvel TLA et al. (2018). Automated measurement of fetal head circumference using 2D ultrasound images. PLoS ONE, 13(8): e0200448.
- Jocher G et al. (2023). Ultralytics YOLOv8. GitHub.
- Ronneberger O et al. (2015). U-Net: Convolutional Networks for Biomedical Image Segmentation. MICCAI, 234-241.
This repository provides an open implementation of cranial biometry segmentation and statistical analysis tools.
π©Ί Built for clinical research accuracy and reproducible fetal growth screening.